diff --git a/.gitignore b/.gitignore index e9f55da..9d47849 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,6 @@ /conf/* !/conf/dist -/modules/* -!/modules/*.md -!/modules/*.sh -!/modules/CMakeLists.txt -!/modules/*.h -!/modules/*.cmake /build*/ /var/* !/var/build/.gitkeep diff --git a/modules/DungeonRespawn/.editorconfig b/modules/DungeonRespawn/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/DungeonRespawn/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/DungeonRespawn/.git_commit_template.txt b/modules/DungeonRespawn/.git_commit_template.txt new file mode 100644 index 0000000..5c5d933 --- /dev/null +++ b/modules/DungeonRespawn/.git_commit_template.txt @@ -0,0 +1,45 @@ +### TITLE +## Type(Scope/Subscope): Commit ultra short explanation +## |---- Write below the examples with a maximum of 50 characters ----| +## Example 1: fix(DB/SAI): Missing spell to NPC Hogger +## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros +## Example 3: feat(CORE/Commands): New GM command to do something + +### DESCRIPTION +## Explain why this change is being made, what does it fix etc... +## |---- Write below the examples with a maximum of 72 characters per lines ----| +## Example: Hogger (id: 492) was not charging player when being engaged. + +## Provide links to any issue, commit, pull request or other resource +## Example 1: Closes issue #23 +## Example 2: Ported from other project's commit (link) +## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ + +## ======================================================= +## EXTRA INFOS +## ======================================================= +## "Type" can be: +## feat (new feature) +## fix (bug fix) +## refactor (refactoring production code) +## style (formatting, missing semi colons, etc; no code change) +## docs (changes to documentation) +## test (adding or refactoring tests; no production code change) +## chore (updating bash scripts, git files etc; no production code change) +## -------------------- +## Remember to +## Capitalize the subject line +## Use the imperative mood in the subject line +## Do not end the subject line with a period +## Separate subject from body with a blank line +## Use the body to explain what and why rather than how +## Can use multiple lines with "-" for bullet points in body +## -------------------- +## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ +## ======================================================= +## "Scope" can be: +## CORE (core related, c++) +## DB (database related, sql) +## ======================================================= +## "Subscope" is optional and depends on the nature of the commit. +## ======================================================= diff --git a/modules/DungeonRespawn/.gitattributes b/modules/DungeonRespawn/.gitattributes new file mode 100644 index 0000000..7ef9001 --- /dev/null +++ b/modules/DungeonRespawn/.gitattributes @@ -0,0 +1,105 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto eol=lf + +# Text +*.conf text +*.conf.dist text +*.cmake text + +## Scripts +*.sh text +*.fish text +*.lua text + +## SQL +*.sql text + +## C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + + +## ARCHIVES +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +## EXECUTABLES +*.exe binary +*.pyc binary diff --git a/modules/DungeonRespawn/.github/workflows/core-build.yml b/modules/DungeonRespawn/.github/workflows/core-build.yml new file mode 100644 index 0000000..a178aed --- /dev/null +++ b/modules/DungeonRespawn/.github/workflows/core-build.yml @@ -0,0 +1,11 @@ +name: core-build +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/DungeonRespawn/.gitignore b/modules/DungeonRespawn/.gitignore new file mode 100644 index 0000000..c6e1299 --- /dev/null +++ b/modules/DungeonRespawn/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*.*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/DungeonRespawn/LICENSE b/modules/DungeonRespawn/LICENSE new file mode 100644 index 0000000..9031171 --- /dev/null +++ b/modules/DungeonRespawn/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 AzerothCore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/modules/DungeonRespawn/README.md b/modules/DungeonRespawn/README.md new file mode 100644 index 0000000..3270df6 --- /dev/null +++ b/modules/DungeonRespawn/README.md @@ -0,0 +1,19 @@ +# ![logo](https://camo.githubusercontent.com/e4f036844d45424178f34d39dc3b0d52fdb82c07c5ef3c2aeb7e3da22c1538b3/68747470733a2f2f692e696d6775722e636f6d2f66517762386d332e706e67)Dungeon Respawn + +## About + +This module will teleport the player to the start of the dungeon on death. + +## Install + +Just clone the module into your modules directory for your server, re-run cmake and compile. + +Then enable the module in the module config. + +## Contact + +If you need any help you can join my [Discord Server](https://discord.gg/xdVPGcpJ8C). + +## Credits + +Thanks to Артём Борисов_99 from the AzerothCore Discord for the module suggestion. diff --git a/modules/DungeonRespawn/README_ES.md b/modules/DungeonRespawn/README_ES.md new file mode 100644 index 0000000..d7d6ddc --- /dev/null +++ b/modules/DungeonRespawn/README_ES.md @@ -0,0 +1,66 @@ + [English](README.md) | [Español](README_ES.md) + +# PARTE 1 - Cómo crear su propio módulo + +Puede utilizar estos scripts para iniciar su proyecto: + +[Ejemplos de scripts](https://github.com/azerothcore/azerothcore-boilerplates) + +### ¿Cómo probar su módulo? + +Desactivar PCH (cabeceras pre-compiladas) e intentar compilar. Si ha olvidado algunas cabeceras, es hora de añadirlas. Para desactivar PCH, siga este [link](https://github.com/azerothcore/azerothcore-wotlk/wiki/CMake-options) y ponga `USE_COREPCH ` a 0 con Cmake. + +------------------------------------------------------- + +# PARTE 2 - EJEMPLO DE UN README.md +Recuerde que el README.md le explica al resto de las personas que es lo que hace su módulo. Recomendamos escribirlo en ingles quizás, aunque puede ser traducido luego a otros idiomas. + +# MI NUEVO MÓDULO (título) + +## Descripción + +Este módulo permite hacer esto y esto. +(Debe explicar para que se va a utilizar el modulo, cuál es su utilidad) + +## Cómo utilizar + +Haz esto y aquello. + +Puedes agregar una carpeta de pantalla: + +[screenshot](/screenshots/my_module.png?raw=true "screenshot") + +O incluso un video donde expliques su uso: + +[Youtube](https://www.youtube.com/watch?v=T6UEX47mPeE) + + +## Requisitos + +Se debe especificar que versión de azerothcore requiere, porque podría ser incompatible con alguna más adelante. Entonces aclarar por las dudas su compatibilidad no está de más. + +Mi nuevo módulo requiere: + +- AzerothCore v4.0.0+ + + +## Instalación + +``` +1) Simplemente coloque el módulo dentro del directorio `modules` de AzerothCore (repositorio), no la compilación. +2) Importe el SQL manualmente a la base de datos correcta (auth, mundo o caracteres) o con el `db_assembler.sh` (si se proporciona `include.sh`). +3) Vuelva a ejecutar el Cmake y genere la compilación necesaria. (Revise la guía) +``` + +## Editar la configuración del módulo (opcional) + +Si necesita cambiar la configuración del módulo, vaya a la carpeta de configuración de su servidor (donde está su `worldserver` o `worldserver.exe`), copie `my_module.conf.dist` a `my_module.conf` y edite ese nuevo archivo. + + +## Créditos + +* [Yo](https://github.com/YOUR_GITHUB_NAME) (autor del módulo) Edite el enlace para que apunte a su github si lo desea. +* [BarbzYHOOL](https://github.com/barbzyhool) +* [Talamortis](https://github.com/talamortis) + +AzerothCore: [repository](https://github.com/azerothcore) - [website](http://azerothcore.org/) - [discord chat community](https://discord.gg/PaqQRkd) diff --git a/modules/DungeonRespawn/README_example.md b/modules/DungeonRespawn/README_example.md new file mode 100644 index 0000000..f31dca8 --- /dev/null +++ b/modules/DungeonRespawn/README_example.md @@ -0,0 +1,41 @@ +# MY_NEW_MODULE + +## Description + +This module allows to do this and this. + + +## How to use ingame + +Do this and that. + +![my_new_module screenshot](/screenshots/my_module.png?raw=true "my_new_module screenshot") + + +[![Youtube Link](https://i.imgur.com/Jhrdgv6.png)](https://www.youtube.com/watch?v=T6UEX47mPeE) + + +## Requirements + +My_new_module requires: + +- AzerothCore v4.0.0+ + + +## Installation + +``` +1) Simply `git clone` the module under the `modules` directory of your AzerothCore source or copy paste it manually. +2) Import the SQL manually to the right Database (auth, world or characters) or with the `db_assembler.sh` (if `include.sh` provided). +3) Re-run cmake and launch a clean build of AzerothCore. +``` + +## Edit the module's configuration (optional) + +If you need to change the module configuration, go to your server configuration directory (where your `worldserver` or `worldserver.exe` is), copy `my_module.conf.dist` to `my_module.conf` and edit that new file. + + +## Credits + +* [Me](https://github.com/YOUR_GITHUB_NAME) (author of the module): Check out my soundcloud - Join my discord +* AzerothCore: [repository](https://github.com/azerothcore) - [website](http://azerothcore.org/) - [discord chat community](https://discord.gg/PaqQRkd) diff --git a/modules/DungeonRespawn/conf/conf.sh.dist b/modules/DungeonRespawn/conf/conf.sh.dist new file mode 100644 index 0000000..0e78e8a --- /dev/null +++ b/modules/DungeonRespawn/conf/conf.sh.dist @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +## CUSTOM SQL - Important file used by the db_assembler.sh +## Keep only the required variables (base sql files or updates, depending on the DB) + +## BASE SQL + +DB_AUTH_CUSTOM_PATHS+=( + "$MOD_SKELETON_ROOT/sql/auth/base/" +) + +DB_CHARACTERS_CUSTOM_PATHS+=( + "$MOD_SKELETON_ROOT/sql/characters/base/" +) + +DB_WORLD_CUSTOM_PATHS+=( + "$MOD_SKELETON_ROOT/sql/world/base/" +) + +## UPDATES + +DB_AUTH_UPDATES_PATHS+=( + "$MOD_SKELETON_ROOT/sql/auth/updates/" +) + +DB_CHARACTERS_UPDATES_PATHS+=( + "$MOD_SKELETON_ROOT/sql/characters/updates/" +) + +DB_WORLD_UPDATES_PATHS+=( + "$MOD_SKELETON_ROOT/sql/world/updates/" +) diff --git a/modules/DungeonRespawn/conf/dungeonrespawn.conf.dist b/modules/DungeonRespawn/conf/dungeonrespawn.conf.dist new file mode 100644 index 0000000..9180b23 --- /dev/null +++ b/modules/DungeonRespawn/conf/dungeonrespawn.conf.dist @@ -0,0 +1,26 @@ +# +# Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 +# + +[worldserver] + +######################################## +# Dungeon Respawn configuration +######################################## +# +# DungeonRespawn.Enable +# Description: Enables the Dungeon Respawn module. +# Default: 0 - Disabled +# 1 - Enabled +# + +DungeonRespawn.Enable = 0 + +# +# DungeonRespawn.RespawnHealthPct +# Description: The amount of health in % to respawn with. +# Range: 0.0 - 100.0 +# Default: 100.0 +# + +DungeonRespawn.RespawnHealthPct = 50.0 diff --git a/modules/DungeonRespawn/data/sql/db-characters/base/dungeonrespawn_char_0000_00_00_00.sql b/modules/DungeonRespawn/data/sql/db-characters/base/dungeonrespawn_char_0000_00_00_00.sql new file mode 100644 index 0000000..6a8e249 --- /dev/null +++ b/modules/DungeonRespawn/data/sql/db-characters/base/dungeonrespawn_char_0000_00_00_00.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `dungeonrespawn_playerinfo` ( + `guid` bigint(20) unsigned DEFAULT NULL, + `map` int(11) DEFAULT NULL, + `x` float DEFAULT NULL, + `y` float DEFAULT NULL, + `z` float DEFAULT NULL, + `o` float DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/modules/DungeonRespawn/data/sql/db-characters/updates/dungeonrespawn_char_2023_01_12_01.sql b/modules/DungeonRespawn/data/sql/db-characters/updates/dungeonrespawn_char_2023_01_12_01.sql new file mode 100644 index 0000000..0cc8c69 --- /dev/null +++ b/modules/DungeonRespawn/data/sql/db-characters/updates/dungeonrespawn_char_2023_01_12_01.sql @@ -0,0 +1,4 @@ +DELETE FROM dungeonrespawn_playerinfo; + +ALTER TABLE dungeonrespawn_playerinfo +MODIFY guid BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY; \ No newline at end of file diff --git a/modules/DungeonRespawn/icon.png b/modules/DungeonRespawn/icon.png new file mode 100644 index 0000000..38bc640 Binary files /dev/null and b/modules/DungeonRespawn/icon.png differ diff --git a/modules/DungeonRespawn/include.sh b/modules/DungeonRespawn/include.sh new file mode 100644 index 0000000..a241572 --- /dev/null +++ b/modules/DungeonRespawn/include.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +## GETS THE CURRENT MODULE ROOT DIRECTORY +MOD_SKELETON_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" + +source $MOD_SKELETON_ROOT"/conf/conf.sh.dist" + +if [ -f $MOD_SKELETON_ROOT"/conf/conf.sh" ]; then + source $MOD_SKELETON_ROOT"/conf/conf.sh" +fi diff --git a/modules/DungeonRespawn/setup_git_commit_template.sh b/modules/DungeonRespawn/setup_git_commit_template.sh new file mode 100644 index 0000000..7b52062 --- /dev/null +++ b/modules/DungeonRespawn/setup_git_commit_template.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +## Set a local git commit template +git config --local commit.template ".git_commit_template.txt" ; diff --git a/modules/DungeonRespawn/src/DungeonRespawn.cpp b/modules/DungeonRespawn/src/DungeonRespawn.cpp new file mode 100644 index 0000000..97bab9f --- /dev/null +++ b/modules/DungeonRespawn/src/DungeonRespawn.cpp @@ -0,0 +1,294 @@ +#include "DungeonRespawn.h" + +bool DSPlayerScript::IsInsideDungeonRaid(Player* player) +{ + if (!player) + { + return false; + } + + Map* map = player->GetMap(); + if (!map) + { + return false; + } + + if (!map->IsDungeon() && !map->IsRaid()) + { + return false; + } + + return true; +} +void DSPlayerScript::OnPlayerReleasedGhost(Player* player) +{ + if (!drEnabled) + { + return; + } + + if (!IsInsideDungeonRaid(player)) + { + return; + } + + playersToTeleport.push_back(player->GetGUID()); +} + +void DSPlayerScript::ResurrectPlayer(Player* player) +{ + player->ResurrectPlayer(respawnHpPct / 100.0f, false); + player->SpawnCorpseBones(); +} + +bool DSPlayerScript::OnBeforeTeleport(Player* player, uint32 mapid, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) +{ + if (!drEnabled) + { + return true; + } + + if (!player) + { + return true; + } + + if (player->GetMapId() != mapid) + { + auto prData = GetOrCreateRespawnData(player); + prData->isTeleportingNewMap = true; + } + + if (!IsInsideDungeonRaid(player)) + { + return true; + } + + if (!player->isDead()) + { + return true; + } + + GuidVector::iterator itToRemove; + bool canRestore = false; + + for (auto it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it) + { + if (*it == player->GetGUID()) + { + itToRemove = it; + canRestore = true; + break; + } + } + + if (!canRestore) + { + return true; + } + + playersToTeleport.erase(itToRemove); + + auto prData = GetOrCreateRespawnData(player); + if (prData) + { + //Invalid Player Restore data, use default behaviour. + if (prData->dungeon.map == -1) + { + return true; + } + + if (prData->dungeon.map != int32(player->GetMapId())) + { + return true; + } + + player->TeleportTo(prData->dungeon.map, prData->dungeon.x, prData->dungeon.y, prData->dungeon.z, prData->dungeon.o); + ResurrectPlayer(player); + return false; + } + + return true; +} + +void DSWorldScript::OnAfterConfigLoad(bool reload) +{ + if (reload) + { + SaveRespawnData(); + respawnData.clear(); + } + + drEnabled = sConfigMgr->GetOption("DungeonRespawn.Enable", false); + respawnHpPct = sConfigMgr->GetOption("DungeonRespawn.RespawnHealthPct", 50.0f); + + QueryResult qResult = CharacterDatabase.Query("SELECT `guid`, `map`, `x`, `y`, `z`, `o` FROM `dungeonrespawn_playerinfo`"); + + if (qResult) + { + uint32 dataCount = 0; + + do + { + Field* fields = qResult->Fetch(); + + PlayerRespawnData prData; + DungeonData dData; + prData.guid = ObjectGuid(fields[0].Get()); + dData.map = fields[1].Get(); + dData.x = fields[2].Get(); + dData.y = fields[3].Get(); + dData.z = fields[4].Get(); + dData.o = fields[5].Get(); + prData.dungeon = dData; + prData.isTeleportingNewMap = false; + prData.inDungeon = false; + + respawnData.push_back(prData); + + dataCount++; + } while (qResult->NextRow()); + + LOG_INFO("module", "Loaded '{}' rows from 'dungeonrespawn_playerinfo' table.", dataCount); + } + else + { + LOG_INFO("module", "Loaded '0' rows from 'dungeonrespawn_playerinfo' table."); + return; + } +} + +void DSWorldScript::OnShutdown() +{ + SaveRespawnData(); +} + +void DSWorldScript::SaveRespawnData() +{ + for (const auto& prData : respawnData) + { + if (prData.inDungeon) + { + CharacterDatabase.Execute("INSERT INTO `dungeonrespawn_playerinfo` (guid, map, x, y, z, o) VALUES ({}, {}, {}, {}, {}, {}) ON DUPLICATE KEY UPDATE map={}, x={}, y={}, z={}, o={}", + prData.guid.GetRawValue(), + prData.dungeon.map, + prData.dungeon.x, + prData.dungeon.y, + prData.dungeon.z, + prData.dungeon.o, + prData.dungeon.map, + prData.dungeon.x, + prData.dungeon.y, + prData.dungeon.z, + prData.dungeon.o); + } + else + { + CharacterDatabase.Execute("DELETE FROM `dungeonrespawn_playerinfo` WHERE guid = {}", prData.guid.GetRawValue()); + } + } +} + +PlayerRespawnData* DSPlayerScript::GetOrCreateRespawnData(Player* player) +{ + for (auto it = respawnData.begin(); it != respawnData.end(); ++it) + { + if (it != respawnData.end()) + { + if (player->GetGUID() == it->guid) + { + return &(*it); + } + } + } + + CreateRespawnData(player); + + return GetOrCreateRespawnData(player); +} + +void DSPlayerScript::OnMapChanged(Player* player) +{ + if (!player) + { + return; + } + + auto prData = GetOrCreateRespawnData(player); + + if (!prData) + { + return; + } + + bool inDungeon = IsInsideDungeonRaid(player); + prData->inDungeon = inDungeon; + + if (!inDungeon) + { + return; + } + + if (!prData->isTeleportingNewMap) + { + return; + } + + prData->dungeon.map = player->GetMapId(); + prData->dungeon.x = player->GetPositionX(); + prData->dungeon.y = player->GetPositionY(); + prData->dungeon.z = player->GetPositionZ(); + prData->dungeon.o = player->GetOrientation(); + + prData->isTeleportingNewMap = false; +} + +void DSPlayerScript::CreateRespawnData(Player* player) +{ + DungeonData newDData; + newDData.map = -1; + newDData.x = 0; + newDData.y = 0; + newDData.z = 0; + newDData.o = 0; + + PlayerRespawnData newPrData; + newPrData.dungeon = newDData; + newPrData.guid = player->GetGUID(); + newPrData.isTeleportingNewMap = false; + newPrData.inDungeon = false; + + respawnData.push_back(newPrData); +} + +void DSPlayerScript::OnLogin(Player* player) +{ + if (!player) + { + return; + } + + GetOrCreateRespawnData(player); +} + +void DSPlayerScript::OnLogout(Player* player) +{ + if (!player) + { + return; + } + + for (auto it = playersToTeleport.begin(); it < playersToTeleport.end(); ++it) + { + if (player->GetGUID() == (*it)) + { + playersToTeleport.erase(it); + } + } +} + +void SC_AddDungeonRespawnScripts() +{ + new DSWorldScript(); + new DSPlayerScript(); +} diff --git a/modules/DungeonRespawn/src/DungeonRespawn.h b/modules/DungeonRespawn/src/DungeonRespawn.h new file mode 100644 index 0000000..9597675 --- /dev/null +++ b/modules/DungeonRespawn/src/DungeonRespawn.h @@ -0,0 +1,62 @@ +#ifndef MODULE_DUNGEONRESPAWN_H +#define MODULE_DUNGEONRESPAWN_H + +#include "ScriptMgr.h" +#include "LFGMgr.h" +#include "Player.h" +#include "Config.h" +#include "Chat.h" +#include + +struct DungeonData +{ + int32 map; + float x; + float y; + float z; + float o; +}; + +struct PlayerRespawnData +{ + ObjectGuid guid; + DungeonData dungeon; + bool isTeleportingNewMap; + bool inDungeon; +}; + +std::vector respawnData; + +bool drEnabled; +float respawnHpPct; + +class DSPlayerScript : public PlayerScript +{ +public: + DSPlayerScript() : PlayerScript("DSPlayerScript") { } + +private: + std::vector playersToTeleport; + bool IsInsideDungeonRaid(Player* /*player*/); + void ResurrectPlayer(Player* /*player*/); + PlayerRespawnData* GetOrCreateRespawnData(Player* /*player*/); + void CreateRespawnData(Player* /*player*/); + void OnPlayerReleasedGhost(Player* /*player*/) override; + bool OnBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override; + void OnMapChanged(Player* /*player*/) override; + void OnLogin(Player* /*player*/) override; + void OnLogout(Player* /*player*/) override; +}; + +class DSWorldScript : public WorldScript +{ +public: + DSWorldScript() : WorldScript("DSWorldScript") { } + +private: + void OnAfterConfigLoad(bool /*reload*/) override; + void OnShutdown() override; + void SaveRespawnData(); +}; + +#endif //MODULE_DUNGEONRESPAWN_H diff --git a/modules/DungeonRespawn/src/MP_loader.cpp b/modules/DungeonRespawn/src/MP_loader.cpp new file mode 100644 index 0000000..5d0e9fc --- /dev/null +++ b/modules/DungeonRespawn/src/MP_loader.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + +// From SC +void SC_AddDungeonRespawnScripts(); + +// Add all +// cf. the naming convention https://github.com/azerothcore/azerothcore-wotlk/blob/master/doc/changelog/master.md#how-to-upgrade-4 +// additionally replace all '-' in the module folder name with '_' here +void AddDungeonRespawnScripts() +{ + SC_AddDungeonRespawnScripts(); +} + diff --git a/modules/mod-accountbound/.github/README.md b/modules/mod-accountbound/.github/README.md new file mode 100644 index 0000000..64b9758 --- /dev/null +++ b/modules/mod-accountbound/.github/README.md @@ -0,0 +1,11 @@ +# Account Bound +[![core-build](https://github.com/tkn963/mod-accountbound/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/tkn963/mod-accountbound/actions?query=workflow%3Acore-build+branch%3Amaster+event%3Apush) + +# Features +This module aims to make mounts, companions and heirlooms shared across all characters of an account. + +Companions and mounts that are specific to Alliance or Horde will be converted to the correct version of the companion or mount whenever a character receives them. + +There is no way to see all mounts that the account has unless the character has the required skill, unfortunately there is no way to handle this yet. The character will automatically receive the mounts linked to their account whenever they learn the riding skills. + +An addon that helps the user see all their mounts may be developed in the future. diff --git a/modules/mod-accountbound/.github/workflows/core-build.yml b/modules/mod-accountbound/.github/workflows/core-build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-accountbound/.github/workflows/core-build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-accountbound/LICENSE b/modules/mod-accountbound/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/modules/mod-accountbound/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/modules/mod-accountbound/README.md b/modules/mod-accountbound/README.md new file mode 100644 index 0000000..dbf5167 --- /dev/null +++ b/modules/mod-accountbound/README.md @@ -0,0 +1,8 @@ +# Features +This module aims to make mounts, companions and heirlooms shared across all characters of an account. + +Companions and mounts that are specific to Alliance or Horde will be converted to the correct version of the companion or mount whenever a character receives them. + +There is no way to see all mounts that the account has unless the character has the required skill, unfortunately there is no way to handle this yet. The character will automatically receive the mounts linked to their account whenever they learn the riding skills. + +An addon that helps the user see all their mounts may be developed in the future. diff --git a/modules/mod-accountbound/conf/conf.sh.dist b/modules/mod-accountbound/conf/conf.sh.dist new file mode 100644 index 0000000..f1f641a --- /dev/null +++ b/modules/mod-accountbound/conf/conf.sh.dist @@ -0,0 +1 @@ +#!/usr/bin/env bash diff --git a/modules/mod-accountbound/conf/mod_accountbound.conf.dist b/modules/mod-accountbound/conf/mod_accountbound.conf.dist new file mode 100644 index 0000000..35c5687 --- /dev/null +++ b/modules/mod-accountbound/conf/mod_accountbound.conf.dist @@ -0,0 +1,22 @@ +[worldserver] + +### +# Allow gamemasters to save and load companions and mounts +AccountBound.Gamemasters = 0 +### + +### +# Make companions shared across all characters of an account +AccountBound.Companions = 1 +### + +### +# Make heirlooms shared across all characters of an account +# This requires the included creature to be spawned +AccountBound.Heirlooms = 0 +### + +### +# Make mounts shared shared across all characters of an account +AccountBound.Mounts = 1 +### diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companion_template.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companion_template.sql new file mode 100644 index 0000000..114a4a3 --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companion_template.sql @@ -0,0 +1,214 @@ +DROP TABLE IF EXISTS `account_bound_companion_template`; +CREATE TABLE `account_bound_companion_template` ( + `spell_id` INT(10) UNSIGNED NOT NULL, + `allowable_race` INT(11) NOT NULL, + `comment` VARCHAR(255) NOT NULL, + PRIMARY KEY (`spell_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `account_bound_companion_template` (`spell_id`, `allowable_race`, `comment`) VALUES +(4055, 1791, 'Mechanical Squirrel'), +(10673, 1791, 'Bombay Cat'), +(10674, 1791, 'Cornish Rex Cat'), +(10675, 1791, 'Black Tabby Cat'), +(10676, 1791, 'Orange Tabby Cat'), +(10677, 1791, 'Siamese Cat'), +(10678, 1791, 'Silver Tabby Cat'), +(10679, 1791, 'White Kitten'), +(10680, 1791, 'Cockatiel'), +(10681, 1791, 'Summon Cockatoo'), +(10682, 1791, 'Hyacinth Macaw'), +(10683, 1791, 'Green Wing Macaw'), +(10684, 1791, 'Senegal'), +(10685, 1791, 'Ancona Chicken'), +(10686, 1791, 'Summon Prairie Chicken'), +(10687, 1791, 'Summon White Plymouth Rock'), +(10688, 1791, 'Cockroach'), +(10695, 1791, 'Dark Whelpling'), +(10696, 1791, 'Azure Whelpling'), +(10697, 1791, 'Crimson Whelpling'), +(10698, 1791, 'Emerald Whelpling'), +(10699, 1791, 'Summon Bronze Whelpling'), +(10700, 1791, 'Summon Faeling'), +(10701, 1791, 'Summon Dart Frog'), +(10702, 1791, 'Summon Island Frog'), +(10703, 1791, 'Wood Frog'), +(10704, 1791, 'Tree Frog'), +(10705, 1791, 'Summon Eagle Owl'), +(10706, 1791, 'Hawk Owl'), +(10707, 1791, 'Great Horned Owl'), +(10708, 1791, 'Summon Snowy Owl'), +(10709, 1791, 'Brown Prairie Dog'), +(10710, 1791, 'Summon Cottontail Rabbit'), +(10711, 1791, 'Snowshoe Rabbit'), +(10712, 1791, 'Summon Spotted Rabbit'), +(10713, 1791, 'Albino Snake'), +(10714, 1791, 'Black Kingsnake'), +(10715, 1791, 'Summon Blue Racer'), +(10716, 1791, 'Brown Snake'), +(10717, 1791, 'Crimson Snake'), +(10718, 1791, 'Green Water Snake'), +(10719, 1791, 'Ribbon Snake'), +(10720, 1791, 'Scarlet Snake'), +(10721, 1791, 'Summon Elven Wisp'), +(12243, 1791, 'Mechanical Chicken'), +(13548, 1791, 'Westfall Chicken'), +(15048, 1791, 'Pet Bombling'), +(15049, 1791, 'Lil\' Smoky'), +(15067, 1791, 'Sprite Darter Hatchling'), +(15648, 1791, 'Corrupted Kitten'), +(15999, 1791, 'Worg Pup'), +(16450, 1791, 'Smolderweb Hatchling'), +(17468, 1791, 'Pet Fish'), +(17469, 1791, 'Pet Stone'), +(17567, 1791, 'Summon Blood Parrot'), +(17707, 1791, 'Panda Cub'), +(17708, 1791, 'Mini Diablo'), +(17709, 1791, 'Zergling'), +(19363, 1791, 'Summon Mechanical Yeti'), +(19772, 1791, 'Lifelike Toad'), +(23428, 1791, 'Albino Snapjaw'), +(23429, 1791, 'Loggerhead Snapjaw'), +(23430, 1791, 'Olive Snapjaw'), +(23431, 1791, 'Leatherback Snapjaw'), +(23432, 1791, 'Hawksbill Snapjaw'), +(23530, 1791, 'Tiny Red Dragon'), +(23531, 1791, 'Tiny Green Dragon'), +(23811, 1791, 'Jubling'), +(24696, 1791, 'Murky'), +(24985, 1791, 'Summon Baby Murloc (Blue)'), +(24986, 1791, 'Summon Baby Murloc (Green)'), +(24987, 1791, 'Summon Baby Murloc (Orange)'), +(24988, 1791, 'Lurky'), +(24989, 1791, 'Summon Baby Murloc (Pink)'), +(24990, 1791, 'Summon Baby Murloc (Purple)'), +(25018, 1791, 'Murki'), +(25162, 1791, 'Disgusting Oozeling'), +(25849, 1791, 'Baby Shark'), +(26010, 1791, 'Tranquil Mechanical Yeti'), +(26045, 1791, 'Tiny Snowman'), +(26067, 1791, 'Summon Mechanical Greench'), +(26391, 1791, 'Tentacle Call'), +(26529, 1791, 'Winter Reindeer'), +(26533, 1791, 'Father Winter\'s Helper'), +(26541, 1791, 'Winter\'s Little Helper'), +(27241, 1791, 'Gurky'), +(27570, 1791, 'Peddlefeet'), +(28487, 1791, 'Terky'), +(28505, 1791, 'Poley'), +(28738, 1791, 'Speedy'), +(28739, 1791, 'Mr. Wiggles'), +(28740, 1791, 'Whiskers the Rat'), +(28871, 1791, 'Spirit of Summer'), +(30152, 1791, 'White Tiger Cub'), +(30156, 1791, 'Hippogryph Hatchling'), +(32298, 1791, 'Netherwhelp'), +(33050, 1791, 'Magical Crawdad'), +(33057, 1791, 'Summon Mighty Mr. Pinchy'), +(35156, 1791, 'Mana Wyrmling'), +(35157, 1791, 'Summon Spotted Rabbit'), +(35239, 1791, 'Brown Rabbit'), +(35907, 1791, 'Blue Moth'), +(35909, 1791, 'Red Moth'), +(35910, 1791, 'Yellow Moth'), +(35911, 1791, 'White Moth'), +(36027, 1791, 'Golden Dragonhawk Hatchling'), +(36028, 1791, 'Red Dragonhawk Hatchling'), +(36029, 1791, 'Silver Dragonhawk Hatchling'), +(36031, 1791, 'Blue Dragonhawk Hatchling'), +(36034, 1791, 'Firefly'), +(39181, 1791, 'Miniwing'), +(39709, 1791, 'Wolpertinger'), +(40319, 1791, 'Lucky'), +(40405, 1791, 'Lucky'), +(40549, 1791, 'Bananas'), +(40613, 1791, 'Willy'), +(40614, 1791, 'Egbert'), +(40634, 1791, 'Peanut'), +(40990, 1791, 'Stinker'), +(42609, 1791, 'Sinister Squashling'), +(43697, 1791, 'Toothy'), +(43698, 1791, 'Muckbreath'), +(43918, 1791, 'Mojo'), +(44369, 1791, 'Pint-Sized Pink Pachyderm'), +(45082, 1791, 'Tiny Sporebat'), +(45125, 1791, 'Rocket Chicken'), +(45127, 1791, 'Dragon Kite'), +(45174, 1791, 'Golden Pig'), +(45175, 1791, 'Silver Pig'), +(45890, 1791, 'Scorchling'), +(46425, 1791, 'Snarly'), +(46426, 1791, 'Chuck'), +(46599, 1791, 'Phoenix Hatchling'), +(48406, 1791, 'Spirit of Competition'), +(48408, 1791, 'Essence of Competition'), +(49964, 1791, 'Ethereal Soul-Trader'), +(51716, 1791, 'Nether Ray Fry'), +(51851, 1791, 'Vampiric Batling'), +(52615, 1791, 'Frosty'), +(53082, 1791, 'Mini Tyrael'), +(53316, 1791, 'Ghostly Skull'), +(53768, 1791, 'Haunted'), +(54187, 1791, 'Clockwork Rocket Bot'), +(55068, 1791, 'Mr. Chilly'), +(59250, 1791, 'Giant Sewer Rat'), +(61348, 1791, 'Tickbird Hatchling'), +(61349, 1791, 'White Tickbird Hatchling'), +(61350, 1791, 'Proto-Drake Whelp'), +(61351, 1791, 'Cobra Hatchling'), +(61357, 1791, 'Pengu'), +(61472, 1791, 'Kirin Tor Familiar'), +(61725, 1791, 'Spring Rabbit'), +(61773, 1791, 'Plump Turkey'), +(61855, 1791, 'Baby Blizzard Bear'), +(61991, 1791, 'Little Fawn'), +(62491, 1791, 'Teldrassil Sproutling'), +(62508, 1791, 'Dun Morogh Cub'), +(62510, 1791, 'Tirisfal Batling'), +(62513, 1791, 'Durotar Scorpion'), +(62514, 1791, 'Alarming Clockbot'), +(62516, 1791, 'Elwynn Lamb'), +(62542, 1791, 'Mulgore Hatchling'), +(62561, 1791, 'Strand Crawler'), +(62562, 1791, 'Ammen Vale Lashling'), +(62564, 1791, 'Enchanted Broom'), +(62609, 1101, 'Argent Squire'), +(62674, 1791, 'Mechanopeep'), +(62746, 690, 'Argent Gruntling'), +(63318, 1791, 'Murkimus the Gladiator'), +(63712, 1791, 'Sen\'jin Fetish'), +(64351, 1791, 'XS-001 Constructor Bot'), +(65358, 1791, 'Calico Cat'), +(65381, 1791, 'Curious Oracle Hatchling'), +(65382, 1791, 'Curious Wolvar Pup'), +(65682, 1791, 'Warbot'), +(66030, 1791, 'Grunty'), +(66096, 1791, 'Shimmering Wyrmling'), +(66175, 1791, 'Macabre Marionette'), +(66520, 1791, 'Jade Tiger'), +(67413, 1791, 'Darting Hatchling'), +(67414, 1791, 'Deviate Hatchling'), +(67415, 1791, 'Gundrak Hatchling'), +(67416, 1791, 'Leaping Hatchling'), +(67417, 1791, 'Obsidian Hatchling'), +(67418, 1791, 'Ravasaur Hatchling'), +(67419, 1791, 'Razormaw Hatchling'), +(67420, 1791, 'Razzashi Hatchling'), +(67527, 1791, 'Onyx Panther'), +(68767, 1791, 'Tuskarr Kite'), +(68810, 1791, 'Spectral Tiger Cub'), +(69002, 1791, 'Onyxian Whelpling'), +(69452, 1791, 'Core Hound Pup'), +(69535, 1791, 'Gryphon Hatchling'), +(69536, 1791, 'Wind Rider Cub'), +(69539, 1791, 'Zipao Tiger'), +(69541, 1791, 'Pandaren Monk'), +(69677, 1791, 'Lil\' K.T.'), +(70613, 1791, 'Perky Pug'), +(71840, 1791, 'Toxic Wasteling'), +(74932, 1791, 'Frigid Frostling'), +(75134, 1791, 'Blue Clockwork Rocket Bot'), +(75613, 1791, 'Celestial Dragon'), +(75906, 1791, 'Lil\' XT'), +(75936, 1791, 'Murkimus the Gladiator'), +(78381, 1791, 'Mini Thor'); diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companions.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companions.sql new file mode 100644 index 0000000..b9dda72 --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_companions.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `account_bound_companions` ( + `account_id` INT(10) UNSIGNED NOT NULL, + `spell_id` MEDIUMINT(8) UNSIGNED NOT NULL, + `allowable_race` INT(11) UNSIGNED NOT NULL, + PRIMARY KEY (`account_id`, `spell_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_factionchange_spells.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_factionchange_spells.sql new file mode 100644 index 0000000..728adc9 --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_factionchange_spells.sql @@ -0,0 +1,92 @@ +DROP TABLE IF EXISTS `account_bound_factionchange_spells`; +CREATE TABLE `account_bound_factionchange_spells` ( + `alliance_id` INT(10) UNSIGNED NOT NULL, + `alliance_comment` TEXT NOT NULL COLLATE 'utf8mb4_general_ci', + `horde_id` INT(10) UNSIGNED NOT NULL, + `horde_comment` TEXT NOT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`alliance_id`, `horde_id`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=MyISAM +; + +-- Companions +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (62609, 'Argent Squire', 62746, 'Argent Gruntling'); + +-- Mounts +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (458, 'Brown Horse', 6654, 'Brown Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (470, 'Black Stallion', 64658, 'Black Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (472, 'Pinto', 580, 'Timber Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (6648, 'Chestnut Mare', 6653, 'Dire Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (6777, 'Gray Ram', 8395, 'Emerald Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (6898, 'White Ram', 10796, 'Turquoise Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (6899, 'Brown Ram', 10799, 'Violet Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (8394, 'Striped Frostsaber', 64977, 'Black Skeletal Horse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (10789, 'Spotted Frostsaber', 17464, 'Brown Skeletal Horse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (10793, 'Striped Nightsaber', 17463, 'Blue Skeletal Horse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (10873, 'Red Mechanostrider', 64657, 'White Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (10969, 'Blue Mechanostrider', 35020, 'Blue Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (15779, 'White Mechanostrider Mod B', 18992, 'Teal Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (16082, 'Palomino', 16080, 'Red Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (16083, 'White Stallion', 16081, 'Winter Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (17229, 'Winterspring Frostsaber', 64659, 'Venomhide Ravasaur'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (17453, 'Green Mechanostrider', 18989, 'Gray Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (17459, 'Icy Blue Mechanostrider Mod A', 18991, 'Green Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (17460, 'Frost Ram', 17450, 'Ivory Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (17461, 'Black Ram', 16084, 'Mottled Red Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (22717, 'Black War Steed', 22724, 'Black War Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (22719, 'Black Battlestrider', 22718, 'Black War Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (22720, 'Black War Ram', 22721, 'Black War Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (22723, 'Black War Tiger', 22722, 'Red Skeletal Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23219, 'Swift Mistsaber', 23246, 'Purple Skeletal Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23221, 'Swift Frostsaber', 66846, 'Ochre Skeletal Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23222, 'Swift Yellow Mechanostrider', 23247, 'Great White Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23223, 'Swift White Mechanostrider', 23248, 'Great Gray Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23225, 'Swift Green Mechanostrider', 23249, 'Great Brown Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23227, 'Swift Palomino', 23251, 'Swift Timber Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23228, 'Swift White Steed', 23252, 'Swift Gray Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23229, 'Swift Brown Steed', 23250, 'Swift Brown Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23238, 'Swift Brown Ram', 23243, 'Swift Orange Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23239, 'Swift Gray Ram', 23241, 'Swift Blue Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23240, 'Swift White Ram', 23242, 'Swift Olive Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23338, 'Swift Stormsaber', 17465, 'Green Skeletal Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (23510, 'Stormpike Battle Charger', 23509, 'Frostwolf Howler'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32235, 'Golden Gryphon', 32245, 'Green Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32239, 'Ebon Gryphon', 32243, 'Tawny Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32240, 'Snowy Gryphon', 32244, 'Blue Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32242, 'Swift Blue Gryphon', 32296, 'Swift Yellow Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32289, 'Swift Red Gryphon', 32246, 'Swift Red Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32290, 'Swift Green Gryphon', 32295, 'Swift Green Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (32292, 'Swift Purple Gryphon', 32297, 'Swift Purple Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (34406, 'Brown Elekk', 35022, 'Black Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (35710, 'Gray Elekk', 34795, 'Red Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (35711, 'Purple Elekk', 35018, 'Purple Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (35712, 'Great Green Elekk', 35027, 'Swift Purple Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (35713, 'Great Blue Elekk', 35025, 'Swift Green Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (35714, 'Great Purple Elekk', 33660, 'Swift Pink Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (48027, 'Black War Elekk', 35028, 'Swift Warstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (59785, 'Black War Mammoth', 59788, 'Black War Mammoth'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (59791, 'Wooly Mammoth', 59793, 'Wooly Mammoth'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (59799, 'Ice Mammoth', 59797, 'Ice Mammoth'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (60114, 'Armored Brown Bear', 60116, 'Armored Brown Bear'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (60118, 'Black War Bear', 60119, 'Black War Bear'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (60424, 'Mekgineer\'s Chopper', 55531, 'Mechano-hog'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (61229, 'Armored Snowy Gryphon', 61230, 'Armored Blue Wind Rider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (61425, 'Traveler\'s Tundra Mammoth', 61447, 'Traveler\'s Tundra Mammoth'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (61470, 'Grand Ice Mammoth', 61469, 'Grand Ice Mammoth'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (61996, 'Blue Dragonhawk', 61997, 'Red Dragonhawk'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (63232, 'Stormwind Steed', 63640, 'Orgrimmar Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (63636, 'Ironforge Ram', 63635, 'Darkspear Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (63637, 'Darnassian Nightsaber', 63643, 'Forsaken Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (63638, 'Gnomeregan Mechanostrider', 63641, 'Thunder Bluff Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (63639, 'Exodar Elekk', 63642, 'Silvermoon Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (65637, 'Great Red Elekk', 65639, 'Swift Red Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (65638, 'Swift Moonsaber', 65645, 'White Skeletal Warhorse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (65640, 'Swift Gray Steed', 65646, 'Swift Burgundy Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (65642, 'Turbostrider', 65641, 'Great Golden Kodo'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (65643, 'Swift Violet Ram', 65644, 'Swift Purple Raptor'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (66087, 'Silver Covenant Hippogryph', 66088, 'Sunreaver Dragonhawk'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (66090, 'Quel\'dorei Steed', 66091, 'Sunreaver Hawkstrider'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (66847, 'Striped Dawnsaber', 17462, 'Red Skeletal Horse'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (68057, 'Swift Alliance Steed', 68056, 'Swift Horde Wolf'); +INSERT INTO `account_bound_factionchange_spells` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES (68187, 'Crusader\'s White Warhorse', 68188, 'Crusader\'s Black Warhorse'); diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_heirlooms.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_heirlooms.sql new file mode 100644 index 0000000..fe684e1 --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_heirlooms.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `account_bound_heirlooms` ( + `account_id` INT(10) UNSIGNED NOT NULL, + `item_id` MEDIUMINT(8) UNSIGNED NOT NULL, + PRIMARY KEY (`account_id`, `item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mount_template.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mount_template.sql new file mode 100644 index 0000000..46ffc1b --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mount_template.sql @@ -0,0 +1,259 @@ +DROP TABLE IF EXISTS `account_bound_mount_template`; +CREATE TABLE `account_bound_mount_template` ( + `spell_id` INT(10) UNSIGNED NOT NULL, + `allowable_race` INT(11) NOT NULL, + `allowable_class` INT(11) NOT NULL, + `required_level` TINYINT(3) UNSIGNED NOT NULL, + `required_skill` SMALLINT(3) UNSIGNED NOT NULL, + `required_skill_rank` SMALLINT(3) UNSIGNED NOT NULL, + `comment` VARCHAR(255) NOT NULL, + PRIMARY KEY (`spell_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `account_bound_mount_template` (`spell_id`, `allowable_race`, `allowable_class`, `required_level`, `required_skill`, `required_skill_rank`, `comment`) VALUES +(458, 1101, 1535, 20, 762, 75, 'Brown Horse'), +(470, 1101, 1535, 20, 762, 75, 'Black Stallion'), +(472, 1101, 1535, 20, 762, 75, 'Pinto'), +(580, 690, 1535, 20, 762, 75, 'Timber Wolf'), +(6648, 1101, 1535, 20, 762, 75, 'Chestnut Mare'), +(6653, 690, 1535, 20, 762, 75, 'Dire Wolf'), +(6654, 690, 1535, 20, 762, 75, 'Brown Wolf'), +(6777, 1101, 1535, 20, 762, 75, 'Gray Ram'), +(6898, 1101, 1535, 20, 762, 75, 'White Ram'), +(6899, 1101, 1535, 20, 762, 75, 'Brown Ram'), +(8394, 1101, 1535, 20, 762, 75, 'Striped Frostsaber'), +(8395, 690, 1535, 20, 762, 75, 'Emerald Raptor'), +(10789, 1101, 1535, 20, 762, 75, 'Spotted Frostsaber'), +(10793, 1101, 1535, 20, 762, 75, 'Striped Nightsaber'), +(10796, 690, 1535, 20, 762, 75, 'Turquoise Raptor'), +(10799, 690, 1535, 20, 762, 75, 'Violet Raptor'), +(10873, 1101, 1535, 20, 762, 75, 'Red Mechanostrider'), +(10969, 1101, 1535, 20, 762, 75, 'Blue Mechanostrider'), +(15779, 1101, 1535, 40, 762, 150, 'White Mechanostrider Mod B'), +(16055, 1101, 1535, 40, 762, 150, 'Nightsaber'), +(16056, 1101, 1535, 40, 762, 150, 'Ancient Frostsaber'), +(16080, 690, 1535, 40, 762, 150, 'Red Wolf'), +(16081, 690, 1535, 40, 762, 150, 'Arctic Wolf'), +(16082, 1101, 1535, 40, 762, 150, 'Palomino'), +(16083, 1101, 1535, 40, 762, 150, 'White Stallion'), +(16084, 690, 1535, 40, 762, 150, 'Mottled Red Raptor'), +(17229, 1101, 1535, 40, 762, 75, 'Winterspring Frostsaber'), +(17450, 690, 1535, 40, 762, 150, 'Ivory Raptor'), +(17453, 1101, 1535, 20, 762, 75, 'Green Mechanostrider'), +(17454, 1101, 1535, 20, 762, 75, 'Unpainted Mechanostrider'), +(17459, 1101, 1535, 40, 762, 150, 'Icy Blue Mechanostrider Mod A'), +(17460, 1101, 1535, 40, 762, 150, 'Frost Ram'), +(17461, 1101, 1535, 40, 762, 150, 'Black Ram'), +(17462, 690, 1535, 20, 762, 75, 'Red Skeletal Horse'), +(17463, 690, 1535, 20, 762, 75, 'Blue Skeletal Horse'), +(17464, 690, 1535, 20, 762, 75, 'Brown Skeletal Horse'), +(17465, 690, 1535, 40, 762, 150, 'Green Skeletal Warhorse'), +(17481, 1791, 1535, 40, 762, 150, 'Rivendare\'s Deathcharger'), +(18989, 690, 1535, 20, 762, 75, 'Gray Kodo'), +(18990, 690, 1535, 20, 762, 75, 'Brown Kodo'), +(18991, 690, 1535, 40, 762, 150, 'Green Kodo'), +(18992, 690, 1535, 40, 762, 150, 'Teal Kodo'), +(22717, 1101, 1535, 40, 762, 150, 'Black War Steed'), +(22718, 690, 1535, 40, 762, 150, 'Black War Kodo'), +(22719, 1101, 1535, 40, 762, 150, 'Black Battlestrider'), +(22720, 1101, 1535, 40, 762, 150, 'Black War Ram'), +(22721, 690, 1535, 40, 762, 150, 'Black War Raptor'), +(22722, 690, 1535, 40, 762, 150, 'Red Skeletal Warhorse'), +(22723, 1101, 1535, 40, 762, 150, 'Black War Tiger'), +(22724, 690, 1535, 40, 762, 150, 'Black War Wolf'), +(23219, 1101, 1535, 40, 762, 150, 'Swift Mistsaber'), +(23221, 1101, 1535, 40, 762, 150, 'Swift Frostsaber'), +(23222, 1101, 1535, 40, 762, 150, 'Swift Yellow Mechanostrider'), +(23223, 1101, 1535, 40, 762, 150, 'Swift White Mechanostrider'), +(23225, 1101, 1535, 40, 762, 150, 'Swift Green Mechanostrider'), +(23227, 1101, 1535, 40, 762, 150, 'Swift Palomino'), +(23228, 1101, 1535, 40, 762, 150, 'Swift White Steed'), +(23229, 1101, 1535, 40, 762, 150, 'Swift Brown Steed'), +(23238, 1101, 1535, 40, 762, 150, 'Swift Brown Ram'), +(23239, 1101, 1535, 40, 762, 150, 'Swift Gray Ram'), +(23240, 1101, 1535, 40, 762, 150, 'Swift White Ram'), +(23241, 690, 1535, 40, 762, 150, 'Swift Blue Raptor'), +(23242, 690, 1535, 40, 762, 150, 'Swift Olive Raptor'), +(23243, 690, 1535, 40, 762, 150, 'Swift Orange Raptor'), +(23246, 690, 1535, 40, 762, 150, 'Purple Skeletal Warhorse'), +(23247, 690, 1535, 40, 762, 150, 'Great White Kodo'), +(23248, 690, 1535, 40, 762, 150, 'Great Gray Kodo'), +(23249, 690, 1535, 40, 762, 150, 'Great Brown Kodo'), +(23250, 690, 1535, 40, 762, 150, 'Swift Brown Wolf'), +(23251, 690, 1535, 40, 762, 150, 'Swift Timber Wolf'), +(23252, 690, 1535, 40, 762, 150, 'Swift Gray Wolf'), +(23338, 1101, 1535, 40, 762, 150, 'Swift Stormsaber'), +(23509, 1791, 1535, 40, 762, 150, 'Frostwolf Howler'), +(23510, 1791, 1535, 40, 762, 150, 'Stormpike Battle Charger'), +(24242, 1791, 1535, 40, 762, 150, 'Swift Razzashi Raptor'), +(24252, 1791, 1535, 40, 762, 150, 'Swift Zulian Tiger'), +(25953, 1791, 1535, 40, 762, 75, 'Blue Qiraji Battle Tank'), +(26054, 1791, 1535, 40, 762, 75, 'Red Qiraji Battle Tank'), +(26055, 1791, 1535, 40, 762, 75, 'Yellow Qiraji Battle Tank'), +(26056, 1791, 1535, 40, 762, 75, 'Green Qiraji Battle Tank'), +(26656, 1791, 1535, 40, 762, 150, 'Black Qiraji Battle Tank'), +(32235, 1101, 1535, 60, 762, 225, 'Golden Gryphon'), +(32239, 1101, 1535, 60, 762, 225, 'Ebon Gryphon'), +(32240, 1101, 1535, 60, 762, 225, 'Snowy Gryphon'), +(32242, 1101, 1535, 70, 762, 300, 'Swift Blue Gryphon'), +(32243, 690, 1535, 60, 762, 225, 'Tawny Wind Rider'), +(32244, 690, 1535, 60, 762, 225, 'Blue Wind Rider'), +(32245, 690, 1535, 60, 762, 225, 'Green Wind Rider'), +(32246, 690, 1535, 70, 762, 300, 'Swift Red Wind Rider'), +(32289, 1101, 1535, 70, 762, 300, 'Swift Red Gryphon'), +(32290, 1101, 1535, 70, 762, 300, 'Swift Green Gryphon'), +(32292, 1101, 1535, 70, 762, 300, 'Swift Purple Gryphon'), +(32295, 690, 1535, 70, 762, 300, 'Swift Green Wind Rider'), +(32296, 690, 1535, 70, 762, 300, 'Swift Yellow Wind Rider'), +(32297, 690, 1535, 70, 762, 300, 'Swift Purple Wind Rider'), +(33660, 690, 1535, 40, 762, 150, 'Swift Pink Hawkstrider'), +(34406, 1101, 1535, 20, 762, 75, 'Brown Elekk'), +(34790, 1791, 1535, 40, 762, 150, 'Dark War Talbuk'), +(34795, 690, 1535, 20, 762, 75, 'Red Hawkstrider'), +(34896, 1791, 1535, 40, 762, 150, 'Cobalt War Talbuk'), +(34897, 1791, 1535, 40, 762, 150, 'White War Talbuk'), +(34898, 1791, 1535, 40, 762, 150, 'Silver War Talbuk'), +(34899, 1791, 1535, 40, 762, 150, 'Tan War Talbuk'), +(35018, 690, 1535, 20, 762, 75, 'Purple Hawkstrider'), +(35020, 690, 1535, 20, 762, 75, 'Blue Hawkstrider'), +(35022, 690, 1535, 20, 762, 75, 'Black Hawkstrider'), +(35025, 690, 1535, 40, 762, 150, 'Swift Green Hawkstrider'), +(35027, 690, 1535, 40, 762, 150, 'Swift Purple Hawkstrider'), +(35028, 690, 1535, 40, 762, 150, 'Swift Warstrider'), +(35710, 1101, 1535, 20, 762, 75, 'Gray Elekk'), +(35711, 1101, 1535, 20, 762, 75, 'Purple Elekk'), +(35712, 1101, 1535, 40, 762, 150, 'Great Green Elekk'), +(35713, 1101, 1535, 40, 762, 150, 'Great Blue Elekk'), +(35714, 1101, 1535, 40, 762, 150, 'Great Purple Elekk'), +(36702, 1791, 1535, 40, 762, 150, 'Fiery Warhorse'), +(37015, 1791, 1535, 70, 762, 300, 'Swift Nether Drake'), +(39315, 1791, 1535, 40, 762, 150, 'Cobalt Riding Talbuk'), +(39316, 1791, 1535, 40, 762, 150, 'Dark Riding Talbuk'), +(39317, 1791, 1535, 40, 762, 150, 'Silver Riding Talbuk'), +(39318, 1791, 1535, 40, 762, 150, 'Tan Riding Talbuk'), +(39319, 1791, 1535, 40, 762, 150, 'White Riding Talbuk'), +(39798, 1791, 1535, 70, 762, 300, 'Green Riding Nether Ray'), +(39800, 1791, 1535, 70, 762, 300, 'Red Riding Nether Ray'), +(39801, 1791, 1535, 70, 762, 300, 'Purple Riding Nether Ray'), +(39802, 1791, 1535, 70, 762, 300, 'Silver Riding Nether Ray'), +(39803, 1791, 1535, 70, 762, 300, 'Blue Riding Nether Ray'), +(40192, 1791, 1535, 70, 762, 300, 'Ashes of Al\'ar'), +(41252, 1791, 1535, 40, 762, 150, 'Raven Lord'), +(41513, 1791, 1535, 70, 762, 300, 'Onyx Netherwing Drake'), +(41514, 1791, 1535, 70, 762, 300, 'Azure Netherwing Drake'), +(41515, 1791, 1535, 70, 762, 300, 'Cobalt Netherwing Drake'), +(41516, 1791, 1535, 70, 762, 300, 'Purple Netherwing Drake'), +(41517, 1791, 1535, 70, 762, 300, 'Veridian Netherwing Drake'), +(41518, 1791, 1535, 70, 762, 300, 'Violet Netherwing Drake'), +(42776, 1791, 1535, 20, 762, 75, 'Spectral Tiger'), +(42777, 1791, 1535, 40, 762, 150, 'Swift Spectral Tiger'), +(43688, 1791, 1535, 70, 762, 150, 'Amani War Bear'), +(43899, 1791, 1535, 20, 762, 75, 'Brewfest Ram'), +(43900, 1791, 1535, 40, 762, 150, 'Swift Brewfest Ram'), +(43927, 1791, 1535, 70, 762, 300, 'Cenarion War Hippogryph'), +(44744, 1791, 1535, 70, 762, 300, 'Merciless Nether Drake'), +(46197, 1791, 1535, 60, 762, 225, 'X-51 Nether-Rocket'), +(46199, 1791, 1535, 70, 762, 300, 'X-51 Nether-Rocket X-TREME'), +(46628, 1791, 1535, 40, 762, 150, 'Swift White Hawkstrider'), +(48025, 1791, 1535, 20, 762, 75, 'Headless Horseman\'s Mount'), +(48027, 1101, 1535, 40, 762, 150, 'Black War Elekk'), +(49193, 1791, 1535, 70, 762, 300, 'Vengeful Nether Drake'), +(49322, 1791, 1535, 40, 762, 150, 'Swift Zhevra'), +(49379, 1791, 1535, 40, 762, 150, 'Great Brewfest Kodo'), +(51412, 1791, 1535, 40, 762, 150, 'Big Battle Bear'), +(54729, 1791, 32, 60, 762, 225, 'Winged Steed of the Ebon Blade'), +(54753, 1791, 1535, 40, 762, 150, 'White Polar Bear'), +(55531, 690, 1535, 40, 762, 150, 'Mechano-hog'), +(58615, 1791, 1535, 70, 762, 300, 'Brutal Nether Drake'), +(58983, 1791, 1535, 20, 762, 75, 'Big Blizzard Bear'), +(59567, 1791, 1535, 70, 762, 300, 'Azure Drake'), +(59568, 1791, 1535, 70, 762, 300, 'Blue Drake'), +(59569, 1791, 1535, 70, 762, 300, 'Bronze Drake'), +(59570, 1791, 1535, 70, 762, 300, 'Red Drake'), +(59571, 1791, 1535, 70, 762, 300, 'Twilight Drake'), +(59650, 1791, 1535, 70, 762, 300, 'Black Drake'), +(59785, 1101, 1535, 40, 762, 150, 'Black War Mammoth'), +(59788, 690, 1535, 40, 762, 150, 'Black War Mammoth'), +(59791, 1101, 1535, 40, 762, 150, 'Wooly Mammoth'), +(59793, 690, 1535, 40, 762, 150, 'Wooly Mammoth'), +(59797, 690, 1535, 40, 762, 150, 'Ice Mammoth'), +(59799, 1101, 1535, 40, 762, 150, 'Ice Mammoth'), +(59961, 1791, 1535, 70, 762, 300, 'Red Proto-Drake'), +(59976, 1791, 1535, 70, 762, 300, 'Black Proto-Drake'), +(59996, 1791, 1535, 70, 762, 300, 'Blue Proto-Drake'), +(60002, 1791, 1535, 70, 762, 300, 'Time-Lost Proto-Drake'), +(60021, 1791, 1535, 70, 762, 300, 'Plagued Proto-Drake'), +(60024, 1791, 1535, 70, 762, 300, 'Violet Proto-Drake'), +(60025, 1791, 1535, 70, 762, 300, 'Albino Drake'), +(60114, 1101, 1535, 40, 762, 150, 'Armored Brown Bear'), +(60116, 690, 1535, 40, 762, 150, 'Armored Brown Bear'), +(60118, 1101, 1535, 40, 762, 150, 'Black War Bear'), +(60119, 690, 1535, 40, 762, 150, 'Black War Bear'), +(60424, 1101, 1535, 40, 762, 150, 'Mekgineer\'s Chopper'), +(61229, 1101, 1535, 70, 762, 300, 'Armored Snowy Gryphon'), +(61230, 690, 1535, 70, 762, 300, 'Armored Blue Wind Rider'), +(61294, 1791, 1535, 70, 762, 300, 'Green Proto-Drake'), +(61425, 1101, 1535, 40, 762, 150, 'Traveler\'s Tundra Mammoth'), +(61447, 690, 1535, 40, 762, 150, 'Traveler\'s Tundra Mammoth'), +(61465, 1101, 1535, 40, 762, 150, 'Grand Black War Mammoth'), +(61467, 690, 1535, 40, 762, 150, 'Grand Black War Mammoth'), +(61469, 690, 1535, 40, 762, 150, 'Grand Ice Mammoth'), +(61470, 1101, 1535, 40, 762, 150, 'Grand Ice Mammoth'), +(61996, 1791, 1535, 70, 762, 300, 'Blue Dragonhawk'), +(61997, 1791, 1535, 70, 762, 300, 'Red Dragonhawk'), +(63232, 1101, 1535, 40, 762, 150, 'Stormwind Steed'), +(63635, 690, 1535, 40, 762, 150, 'Darkspear Raptor'), +(63636, 1101, 1535, 40, 762, 150, 'Ironforge Ram'), +(63637, 1101, 1535, 40, 762, 150, 'Darnassian Nightsaber'), +(63638, 1101, 1535, 40, 762, 150, 'Gnomeregan Mechanostrider'), +(63639, 1101, 1535, 40, 762, 150, 'Exodar Elekk'), +(63640, 690, 1535, 40, 762, 150, 'Orgrimmar Wolf'), +(63641, 690, 1535, 40, 762, 150, 'Thunder Bluff Kodo'), +(63642, 690, 1535, 40, 762, 150, 'Silvermoon Hawkstrider'), +(63643, 690, 1535, 40, 762, 150, 'Forsaken Warhorse'), +(63796, 1791, 1535, 70, 762, 300, 'Mimiron\'s Head'), +(63844, 1791, 1535, 70, 762, 300, 'Argent Hippogryph'), +(63956, 1791, 1535, 70, 762, 300, 'Ironbound Proto-Drake'), +(63963, 1791, 1535, 70, 762, 300, 'Rusted Proto-Drake'), +(64657, 690, 1535, 20, 762, 75, 'White Kodo'), +(64658, 690, 1535, 20, 762, 75, 'Black Wolf'), +(64659, 690, 1535, 40, 762, 75, 'Venomhide Ravasaur'), +(64731, 1791, 1535, 0, 762, 75, 'Sea Turtle'), +(64927, 1791, 1535, 70, 762, 300, 'Deadly Gladiator\'s Frost Wyrm'), +(64977, 690, 1535, 20, 762, 75, 'Black Skeletal Horse'), +(65439, 1791, 1535, 70, 762, 300, 'Furious Gladiator\'s Frost Wyrm'), +(65637, 1101, 1535, 40, 762, 150, 'Great Red Elekk'), +(65638, 1101, 1535, 40, 762, 150, 'Swift Moonsaber'), +(65639, 690, 1535, 40, 762, 150, 'Swift Red Hawkstrider'), +(65640, 1101, 1535, 40, 762, 150, 'Swift Gray Steed'), +(65641, 690, 1535, 40, 762, 150, 'Great Golden Kodo'), +(65642, 1101, 1535, 40, 762, 150, 'Turbostrider'), +(65643, 1101, 1535, 40, 762, 150, 'Swift Violet Ram'), +(65644, 690, 1535, 40, 762, 150, 'Swift Purple Raptor'), +(65645, 690, 1535, 40, 762, 150, 'White Skeletal Warhorse'), +(65646, 690, 1535, 40, 762, 150, 'Swift Burgundy Wolf'), +(65917, 1791, 1535, 40, 762, 150, 'Magic Rooster'), +(66087, 1791, 1535, 70, 762, 300, 'Silver Covenant Hippogryph'), +(66088, 1791, 1535, 70, 762, 300, 'Sunreaver Dragonhawk'), +(66090, 1101, 1535, 40, 762, 150, 'Quel\'dorei Steed'), +(66091, 690, 1535, 40, 762, 150, 'Sunreaver Hawkstrider'), +(66846, 690, 1535, 40, 762, 150, 'Ochre Skeletal Warhorse'), +(66847, 1101, 1535, 20, 762, 75, 'Striped Dawnsaber'), +(66906, 1791, 2, 40, 762, 150, 'Argent Charger'), +(67336, 1791, 1535, 70, 762, 300, 'Relentless Gladiator\'s Frost Wyrm'), +(67466, 1791, 1535, 40, 762, 150, 'Argent Warhorse'), +(68056, 690, 1535, 40, 762, 150, 'Swift Horde Wolf'), +(68057, 1101, 1535, 40, 762, 150, 'Swift Alliance Steed'), +(68187, 1101, 1535, 40, 762, 150, 'Crusader\'s White Warhorse'), +(68188, 690, 1535, 40, 762, 150, 'Crusader\'s Black Warhorse'), +(69395, 1791, 1535, 70, 762, 300, 'Onyxian Drake'), +(71342, 1791, 1535, 80, 762, 150, 'Big Love Rocket'), +(71810, 1791, 1535, 70, 762, 300, 'Wrathful Gladiator\'s Frost Wyrm'), +(72286, 1791, 1535, 20, 762, 75, 'Invincible'), +(72807, 1791, 1535, 70, 762, 300, 'Icebound Frostbrood Vanquisher'), +(72808, 1791, 1535, 70, 762, 300, 'Bloodbathed Frostbrood Vanquisher'), +(73313, 1791, 1535, 20, 762, 75, 'Crimson Deathcharger'), +(74856, 1791, 1535, 60, 762, 225, 'Blazing Hippogryph'), +(74918, 1791, 1535, 40, 762, 150, 'Wooly White Rhino'), +(75614, 1791, 1535, 20, 762, 75, 'Celestial Steed'), +(75973, 1791, 1535, 60, 762, 225, 'X-53 Touring Rocket'); diff --git a/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mounts.sql b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mounts.sql new file mode 100644 index 0000000..dadee8d --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-auth/base/account_bound_mounts.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `account_bound_mounts` ( + `account_id` INT(10) UNSIGNED NOT NULL, + `spell_id` MEDIUMINT(8) UNSIGNED NOT NULL, + `allowable_race` INT(11) NOT NULL, + `allowable_class` INT(11) NOT NULL, + `required_level` TINYINT(3) UNSIGNED NOT NULL, + `required_skill` SMALLINT(3) UNSIGNED NOT NULL, + `required_skill_rank` SMALLINT(3) UNSIGNED NOT NULL, + PRIMARY KEY (`account_id`,`spell_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/modules/mod-accountbound/data/sql/db-world/base/account_bound_creature_template.sql b/modules/mod-accountbound/data/sql/db-world/base/account_bound_creature_template.sql new file mode 100644 index 0000000..a6d3490 --- /dev/null +++ b/modules/mod-accountbound/data/sql/db-world/base/account_bound_creature_template.sql @@ -0,0 +1,18 @@ +SET +@Entry := 7500000, +@Model := 25609, +@Name := "Edward Findle", +@Title := "Heirloom Hoarder", +@Icon := "Speak", +@MinLevel := 25, +@MaxLevel := 25, +@Faction := 35, +@NPCFlag := 129, +@Rank := 0, +@Type := 7, +@Script := "npc_account_bound_heirlooms"; + +-- Creature template +DELETE FROM `creature_template` WHERE `entry`=@Entry; +INSERT INTO `creature_template` (`entry`, `modelid1`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `faction`, `npcflag`, `unit_class`, `unit_flags`, `type`, `ScriptName`) VALUES +(@Entry, @Model, @Name, @Title, @Icon, @MinLevel, @MaxLevel, @Faction, @NPCFlag, 1, 2, @Type, @Script); diff --git a/modules/mod-accountbound/include.sh b/modules/mod-accountbound/include.sh new file mode 100644 index 0000000..375c149 --- /dev/null +++ b/modules/mod-accountbound/include.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +MOD_ACCOUNTBOUND_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" + +source $MOD_ACCOUNTBOUND_ROOT"/conf/conf.sh.dist" + +if [ -f $MOD_ACCOUNTBOUND_ROOT"/conf/conf.sh" ]; then + source $MOD_ACCOUNTBOUND_ROOT"/conf/conf.sh" +fi diff --git a/modules/mod-accountbound/src/loader.cpp b/modules/mod-accountbound/src/loader.cpp new file mode 100644 index 0000000..98e3aba --- /dev/null +++ b/modules/mod-accountbound/src/loader.cpp @@ -0,0 +1,6 @@ +void AddSC_mod_accountbound(); + +void Addmod_accountboundScripts() +{ + AddSC_mod_accountbound(); +} diff --git a/modules/mod-accountbound/src/mod_accountbound.cpp b/modules/mod-accountbound/src/mod_accountbound.cpp new file mode 100644 index 0000000..ceb280f --- /dev/null +++ b/modules/mod-accountbound/src/mod_accountbound.cpp @@ -0,0 +1,470 @@ +#include "Chat.h" +#include "Config.h" +#include "Player.h" +#include "ScriptedGossip.h" +#include "ScriptMgr.h" + +bool abEnableGamemasters; +bool abEnableAccountCompanions; +bool abEnableAccountHeirlooms; +bool abEnableAccountMounts; + +struct AccountCompanions +{ + uint32 SpellId; + uint32 AllowableRace; +}; + +struct FactionSpecificAccountCompanions +{ + uint32 AllianceId; + uint32 HordeId; +}; + +struct AccountMounts +{ + uint32 SpellId; + uint32 AllowableRace; + uint32 AllowableClass; + uint32 RequiredLevel; + uint32 RequiredSkill; + uint32 RequiredSkillRank; +}; + +struct FactionSpecificAccountMounts +{ + uint32 AllianceId; + uint32 HordeId; +}; + +std::vector accountCompanions; +std::vector factionSpecificAccountCompanions; +std::vector accountMounts; +std::vector factionSpecificAccountMounts; + +class AccountBoundCompanions : public PlayerScript +{ +public: + AccountBoundCompanions() : PlayerScript("AccountBoundCompanions") {} + + void OnLearnSpell(Player* player, uint32 spellID) override + { + if (abEnableAccountCompanions) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + SaveCompanions(player, spellID); + } + + void OnLogin(Player* player) override + { + if (abEnableAccountCompanions) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + LoadCompanions(player); + } + +private: + int FindFactionSpecificCompanion(uint32 spellId) + { + for (size_t i = 0; i != factionSpecificAccountCompanions.size(); ++i) + { + if (factionSpecificAccountCompanions[i].AllianceId == spellId || factionSpecificAccountCompanions[i].HordeId == spellId) + return i; + } + + return -1; + } + + void LoadCompanions(Player* player) + { + QueryResult result = LoginDatabase.Query("SELECT spell_id FROM account_bound_companions WHERE account_id={} AND allowable_race & {}", + player->GetSession()->GetAccountId(), + player->getRaceMask()); + + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + uint32 spellId = fields[0].Get(); + + if (!player->HasSpell(spellId)) + player->learnSpell(spellId); + + } while (result->NextRow()); + } + + void SaveCompanions(Player* player, uint32 spellID) + { + for (auto& accountCompanion : accountCompanions) + { + if (accountCompanion.SpellId != spellID) + continue; + + int factionCompanionSpellId = FindFactionSpecificCompanion(accountCompanion.SpellId); + if (factionCompanionSpellId == -1) + { + LoginDatabase.DirectExecute("REPLACE INTO account_bound_companions (account_id, spell_id, allowable_race)" + "VALUES ({}, {}, {})", + player->GetSession()->GetAccountId(), + spellID, + accountCompanion.AllowableRace); + continue; + } + + LoginDatabase.DirectExecute("REPLACE INTO account_bound_companions (account_id, spell_id, allowable_race) " + "VALUES ({}, {}, {}), ({}, {}, {})", + player->GetSession()->GetAccountId(), + factionSpecificAccountCompanions[factionCompanionSpellId].AllianceId, + RACEMASK_ALLIANCE, + player->GetSession()->GetAccountId(), + factionSpecificAccountCompanions[factionCompanionSpellId].HordeId, + RACEMASK_HORDE); + } + } +}; + +class AccountBoundData : public WorldScript +{ +public: + AccountBoundData() : WorldScript("AccountBoundData") {} + + void OnAfterConfigLoad(bool /*reload*/) override + { + abEnableGamemasters = sConfigMgr->GetOption("AccountBound.Gamemasters", 0); + abEnableAccountCompanions = sConfigMgr->GetOption("AccountBound.Companions", 1); + abEnableAccountHeirlooms = sConfigMgr->GetOption("AccountBound.Heirlooms", 0); + abEnableAccountMounts = sConfigMgr->GetOption("AccountBound.Mounts", 1); + } + + void OnStartup() override + { + LOG_INFO("server.loading", "Loading account bound templates..."); + + if (abEnableAccountCompanions) + { + LoadCompanions(); + LoadFactionSpecificCompanions(); + } + + if (abEnableAccountMounts) + { + LoadMounts(); + LoadFactionSpecificMounts(); + } + } + +private: + void LoadCompanions() + { + QueryResult result = LoginDatabase.Query("SELECT spell_id, allowable_race FROM account_bound_companion_template"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 companion templates"); + return; + } + + accountCompanions.clear(); + + int i = 0; + do + { + accountCompanions.push_back(AccountCompanions()); + Field* fields = result->Fetch(); + accountCompanions[i].SpellId = fields[0].Get(); + accountCompanions[i].AllowableRace = fields[1].Get(); + + i++; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} companion templates", i); + } + + void LoadFactionSpecificCompanions() + { + QueryResult result = LoginDatabase.Query("SELECT alliance_id, horde_id FROM account_bound_factionchange_spells pfs LEFT OUTER JOIN " + "account_bound_companion_template abt ON pfs.alliance_id = abt.spell_id WHERE abt.allowable_race = 1101"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 faction-specific companion templates"); + return; + } + + factionSpecificAccountCompanions.clear(); + + int i = 0; + do + { + factionSpecificAccountCompanions.push_back(FactionSpecificAccountCompanions()); + Field* fields = result->Fetch(); + factionSpecificAccountCompanions[i].AllianceId = fields[0].Get(); + factionSpecificAccountCompanions[i].HordeId = fields[1].Get(); + + i++; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} faction-specific companion templates", i); + } + + void LoadMounts() + { + QueryResult result = LoginDatabase.Query("SELECT spell_id, allowable_race, allowable_class, required_level, " + "required_skill, required_skill_rank FROM account_bound_mount_template"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 mount spells"); + return; + } + + accountMounts.clear(); + + int i = 0; + do + { + accountMounts.push_back(AccountMounts()); + Field* fields = result->Fetch(); + accountMounts[i].SpellId = fields[0].Get(); + accountMounts[i].AllowableRace = fields[1].Get(); + accountMounts[i].AllowableClass = fields[2].Get(); + accountMounts[i].RequiredLevel = fields[3].Get(); + accountMounts[i].RequiredSkill = fields[4].Get(); + accountMounts[i].RequiredSkillRank = fields[5].Get(); + + i++; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} mount templates", i); + } + + void LoadFactionSpecificMounts() + { + QueryResult result = LoginDatabase.Query("SELECT alliance_id, horde_id FROM account_bound_factionchange_spells pfs LEFT OUTER JOIN " + "account_bound_mount_template abt ON pfs.alliance_id = abt.spell_id WHERE abt.allowable_race = 1101"); + + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 faction-specific mount templates"); + return; + } + + factionSpecificAccountMounts.clear(); + + int i = 0; + do + { + factionSpecificAccountMounts.push_back(FactionSpecificAccountMounts()); + Field* fields = result->Fetch(); + factionSpecificAccountMounts[i].AllianceId = fields[0].Get(); + factionSpecificAccountMounts[i].HordeId = fields[1].Get(); + + i++; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} faction-specific mount templates", i); + } +}; + +class AccountBoundHeirlooms : public PlayerScript +{ +public: + AccountBoundHeirlooms() : PlayerScript("AccountBoundHeirlooms") {} + + void OnAfterStoreOrEquipNewItem(Player* player, uint32 /*vendorslot*/, Item* item, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/, ItemTemplate const* /*pProto*/, Creature* /*pVendor*/, VendorItem const* /*crItem*/, bool /*bStore*/) override + { + if (!item || !item->GetTemplate() || !abEnableAccountHeirlooms) + return; + + if (item->GetTemplate()->Quality == ITEM_QUALITY_HEIRLOOM && item->GetEntry() != 49177) + { + SaveHeirlooms(player, item->GetEntry()); + item->SetNotRefundable(player); + } + } + +private: + void SaveHeirlooms(Player* player, uint32 itemId) + { + LoginDatabase.DirectExecute("REPLACE INTO account_bound_heirlooms (account_id, item_id) " + "VALUES ({}, {})", + player->GetSession()->GetAccountId(), + itemId); + } +}; + +class AccountBoundHeirloomHoarder : CreatureScript +{ +public: + AccountBoundHeirloomHoarder() : CreatureScript("npc_account_bound_heirlooms") {} + + bool OnGossipHello(Player* player, Creature* creature) + { + if (!abEnableAccountHeirlooms) + { + ChatHandler(player->GetSession()).PSendSysMessage("This feature is currently disabled."); + CloseGossipMenuFor(player); + return true; + } + + QueryResult result = LoginDatabase.Query("SELECT item_id FROM account_bound_heirlooms WHERE account_id = {}", + player->GetSession()->GetAccountId()); + + if (!result) + { + ChatHandler(player->GetSession()).PSendSysMessage("You don't have any stored heirlooms."); + CloseGossipMenuFor(player); + return true; + } + + uint32 vendorId = 7500000 + player->GetSession()->GetAccountId(); + + if (const VendorItemData* vendorData = sObjectMgr->GetNpcVendorItemList(vendorId)) + { + uint8 vendorItemCount = vendorData->GetItemCount(); + for (int i = 0; i < vendorItemCount; i++) + { + sObjectMgr->RemoveVendorItem(vendorId, vendorData->GetItem(i)->item); + } + } + + do + { + Field* fields = result->Fetch(); + sObjectMgr->AddVendorItem(vendorId, fields[0].Get(), 0, 0, 0, false); + } while (result->NextRow()); + + player->GetSession()->SendListInventory(creature->GetGUID(), vendorId); + + return true; + } +}; + +enum RidingAchievement +{ + ACHIEVEMENT_APPRENTICE = 891, + ACHIEVEMENT_JOURNEYMAN = 889, + ACHIEVEMENT_EXPERT = 890, + ACHIEVEMENT_ARTISAN = 892 +}; + +class AccountBoundMounts : public PlayerScript +{ +public: + AccountBoundMounts() : PlayerScript("AccountBoundMounts") {} + + void OnAchiComplete(Player* player, AchievementEntry const* achievement) override + { + if (abEnableAccountMounts) + if (achievement->ID == ACHIEVEMENT_APPRENTICE || achievement->ID == ACHIEVEMENT_JOURNEYMAN || achievement->ID == ACHIEVEMENT_EXPERT || achievement->ID == ACHIEVEMENT_ARTISAN) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + LearnMounts(player); + } + + void OnLearnSpell(Player* player, uint32 spellID) override + { + if (abEnableAccountMounts) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + SaveMounts(player, spellID); + } + + void OnLevelChanged(Player* player, uint8 /*oldlevel*/) override + { + if (abEnableAccountMounts) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + LearnMounts(player); + } + + void OnLogin(Player* player) override + { + if (abEnableAccountMounts) + if (player->GetSession()->GetSecurity() == SEC_PLAYER || abEnableGamemasters) + LearnMounts(player); + } + +private: + int FindFactionSpecificMount(uint32 spellId) + { + for (size_t i = 0; i != factionSpecificAccountMounts.size(); ++i) + { + if (factionSpecificAccountMounts[i].AllianceId == spellId || factionSpecificAccountMounts[i].HordeId == spellId) + return i; + } + + return -1; + } + + void LearnMounts(Player* player) + { + QueryResult result = LoginDatabase.Query("SELECT spell_id FROM account_bound_mounts WHERE account_id={} AND allowable_race & {} " + "AND allowable_class & {} AND required_level <= {} AND (required_skill = 0 OR required_skill_rank <= {})", + player->GetSession()->GetAccountId(), + player->getRaceMask(), + player->getClassMask(), + player->getLevel(), + player->GetSkillValue(SKILL_RIDING)); + + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + uint32 spellId = fields[0].Get(); + + if (!player->HasSpell(spellId)) + player->learnSpell(spellId); + + } while (result->NextRow()); + } + + void SaveMounts(Player* player, uint32 spellID) + { + for (auto& mount : accountMounts) + { + if (mount.SpellId != spellID) + continue; + + int factionSpecificMountSpellId = FindFactionSpecificMount(mount.SpellId); + if (factionSpecificMountSpellId == -1) + { + LoginDatabase.DirectExecute("REPLACE INTO account_bound_mounts (account_id, spell_id, allowable_race, allowable_class, required_level, " + "required_skill, required_skill_rank) VALUES ({}, {}, {}, {}, {}, {}, {})", + player->GetSession()->GetAccountId(), + spellID, + mount.AllowableRace, + mount.AllowableClass, + mount.RequiredLevel, + mount.RequiredSkill, + mount.RequiredSkillRank); + continue; + } + + LoginDatabase.DirectExecute("REPLACE INTO account_bound_mounts (account_id, spell_id, allowable_race, allowable_class, required_level, required_skill, " + "required_skill_rank) VALUES ({}, {}, {}, {}, {}, {}, {}), ({}, {}, {}, {}, {}, {}, {})", + player->GetSession()->GetAccountId(), + factionSpecificAccountMounts[factionSpecificMountSpellId].AllianceId, + RACEMASK_ALLIANCE, + mount.AllowableClass, + mount.RequiredLevel, + mount.RequiredSkill, + mount.RequiredSkillRank, + player->GetSession()->GetAccountId(), + factionSpecificAccountMounts[factionSpecificMountSpellId].HordeId, + RACEMASK_HORDE, + mount.AllowableClass, + mount.RequiredLevel, + mount.RequiredSkill, + mount.RequiredSkillRank); + } + } +}; + +void AddSC_mod_accountbound() +{ + new AccountBoundCompanions(); + new AccountBoundData(); + new AccountBoundHeirlooms(); + new AccountBoundHeirloomHoarder(); + new AccountBoundMounts(); +} diff --git a/modules/mod-ah-bot/.editorconfig b/modules/mod-ah-bot/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/mod-ah-bot/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/mod-ah-bot/.gitattributes b/modules/mod-ah-bot/.gitattributes new file mode 100644 index 0000000..823b0b0 --- /dev/null +++ b/modules/mod-ah-bot/.gitattributes @@ -0,0 +1,62 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto eol=lf + +# Text +*.conf +*.conf.dist +*.txt +*.md +*.cmake + +# Bash +*.sh text + +# Lua if lua module? +*.lua + +# SQL +*.sql + +# C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as an asset (binary) by default. If you want to treat it as text, +# comment-out the following line and uncomment the line after. +*.svg binary +#*.svg text +*.eps binary diff --git a/modules/mod-ah-bot/.github/workflows/core-build.yml b/modules/mod-ah-bot/.github/workflows/core-build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-ah-bot/.github/workflows/core-build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-ah-bot/.gitignore b/modules/mod-ah-bot/.gitignore new file mode 100644 index 0000000..d011fdd --- /dev/null +++ b/modules/mod-ah-bot/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-ah-bot/README.md b/modules/mod-ah-bot/README.md new file mode 100644 index 0000000..db90434 --- /dev/null +++ b/modules/mod-ah-bot/README.md @@ -0,0 +1,46 @@ +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore +## Mod-AHBOT +- Latest build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-ah-bot/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-ah-bot) + + +## Important notes + +You have to use at least AzerothCore commit [9adba48](https://github.com/azerothcore/azerothcore-wotlk/commit/9adba482c236f1087d66a672e97a99f763ba74b3). + +If you use an old version of this module please update the table structure using this SQL statement: + +```sql +ALTER TABLE `auctionhousebot` RENAME TO `mod_auctionhousebot`; +``` + +## Description + +An auction house bot for the best core: AzerothCore. + +## Installation + +``` +1. Simply place the module under the `modules` directory of your AzerothCore source. +1. Import the SQL manually to the right Database (auth, world or characters) or with the `db_assembler.sh` (if `include.sh` provided). +1. Re-run cmake and launch a clean build of AzerothCore. +``` + +## Edit module configuration (optional) + +If you need to change the module configuration, go to your server configuration folder (where your `worldserver` or `worldserver.exe` is) +rename the file mod_ahbot.conf.dist to mod_ahbot.conf and edit it. + +## Usage + +Edit the module configuration and add a player account ID and a character ID. +This character will sell and buy items in the auction house so give him a good name. + +Notes: +- The account used does not need any security level and can be a player account. +- The character used by the ahbot is not meant to be used ingame. If you use it to browse the auction house, you might have issues like "Searching for items..." displaying forever. + +## Credits + +- Ayase: ported the bot to AzerothCore +- Other contributors (check the contributors list) + diff --git a/modules/mod-ah-bot/conf/conf.sh.dist b/modules/mod-ah-bot/conf/conf.sh.dist new file mode 100644 index 0000000..937a7bc --- /dev/null +++ b/modules/mod-ah-bot/conf/conf.sh.dist @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# +# CUSTOM +# + +DB_WORLD_CUSTOM_PATHS+=( + $MOD_AH_BOT_ROOT"/sql/world/base/" +) diff --git a/modules/mod-ah-bot/conf/mod_ahbot.conf.dist b/modules/mod-ah-bot/conf/mod_ahbot.conf.dist new file mode 100644 index 0000000..26d8fdf --- /dev/null +++ b/modules/mod-ah-bot/conf/mod_ahbot.conf.dist @@ -0,0 +1,266 @@ +[worldserver] + +############################################################################### +# AUCTION HOUSE BOT SETTINGS +# +# AuctionHouseBot.DEBUG +# Enable/Disable Debugging output +# Default 0 (disabled) +# +# AuctionHouseBot.DEBUG_FILTERS +# Enable/Disable Debugging output from Filters +# Default 0 (disabled) +# +# AuctionHouseBot.EnableSeller +# Enable/Disable the part of AHBot that puts items up for auction +# Default 0 (disabled) +# +# AuctionHouseBot.EnableBuyer +# Enable/Disable the part of AHBot that buys items from players +# Default 0 (disabled) +# +# AuctionHouseBot.UseBuyPriceForSeller +# Should the Seller use BuyPrice or SellPrice to determine Bid Prices +# Default 0 (use SellPrice) +# +# AuctionHouseBot.UseBuyPriceForBuyer +# Should the Buyer use BuyPrice or SellPrice to determine Bid Prices +# Default 0 (use SellPrice) +# +# Auction House Bot character data +# AuctionHouseBot.Account is the account number +# (in realmd->account table) of the player you want to run +# as the auction bot. +# AuctionHouseBot.GUID is the GUID (in characters->characters table) +# of the player you want to run as the auction bot. +# Default: 0 (Auction House Bot disabled) +# +# AuctionHouseBot.ItemsPerCycle +# Number of Items to Add/Remove from the AH during mass operations +# Default 200 +# +############################################################################### + +AuctionHouseBot.DEBUG = 0 +AuctionHouseBot.DEBUG_FILTERS = 0 +AuctionHouseBot.EnableSeller = 0 +AuctionHouseBot.EnableBuyer = 0 +AuctionHouseBot.UseBuyPriceForSeller = 0 +AuctionHouseBot.UseBuyPriceForBuyer = 0 +AuctionHouseBot.Account = 0 +AuctionHouseBot.GUID = 0 +AuctionHouseBot.ItemsPerCycle = 200 + +############################################################################### +# AUCTION HOUSE BOT FILTERS PART 1 +# +# AuctionHouseBot.VendorItems +# Include items that can be bought from vendors. +# Default 0 (False) +# +# AuctionHouseBot.VendorTradeGoods +# Include Trade Goods that can be bought from vendors. +# Default 0 (False) +# +# AuctionHouseBot.LootItems +# Include items that can be looted or fished for. +# Default 1 (True) +# +# AuctionHouseBot.LootTradeGoods +# Include Trade Goods that can be looted or fished for. +# Default 1 (True) +# +# AuctionHouseBot.OtherItems +# Include misc. items. +# Default 0 (False) +# +# AuctionHouseBot.OtherTradeGoods +# Include misc. Trade Goods. +# Default 0 (False) +# +# AuctionHouseBot.Bonding_types +# Indicates which bonding types to allow seller to put up for auction +# No_Bind +# Default 1 (True) +# Bind_When_Picked_Up +# Default 0 (False) +# Bind_When_Equipped +# Default 1 (True) +# Bind_When_Use +# Default 1 (True) +# Bind_Quest_Item +# Default 0 (False) +# +# AuctionHouseBot.DisablePermEnchant +# Disable Items with a Permanent Enchantment +# Default 0 (False) +# +# AuctionHouseBot.DisableConjured +# Disable Conjured Items +# Default 0 (False) +# +# AuctionHouseBot.DisableGems +# Disable Gems +# Default 0 (False) +# +# AuctionHouseBot.DisableMoney +# Disable Items that are used as money +# Default 0 (False) +# +# AuctionHouseBot.DisableMoneyLoot +# Disable Items that have Money as a loot +# Default 0 (False) +# +# AuctionHouseBot.DisableLootable +# Disable Items that have other items as loot +# Default 0 (False) +# +# AuctionHouseBot.DisableKeys +# Disable Items that are keys +# Default 0 (False) +# +# AuctionHouseBot.DisableDuration +# Disable Items with a duration +# Default 0 (False) +# +# AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel +# Disable items that are BOP or Quest Item +# with a Required level that is less than the Item Level +# (This prevents a level 10 with a level 60 weapon or armor) +# (May need further refinement) +# Default 0 (False) +# +############################################################################### + +AuctionHouseBot.VendorItems = 0 +AuctionHouseBot.VendorTradeGoods = 0 +AuctionHouseBot.LootItems = 1 +AuctionHouseBot.LootTradeGoods = 1 +AuctionHouseBot.OtherItems = 0 +AuctionHouseBot.OtherTradeGoods = 0 +AuctionHouseBot.No_Bind = 1 +AuctionHouseBot.Bind_When_Picked_Up = 0 +AuctionHouseBot.Bind_When_Equipped = 1 +AuctionHouseBot.Bind_When_Use = 1 +AuctionHouseBot.Bind_Quest_Item = 0 +AuctionHouseBot.DisablePermEnchant = 0 +AuctionHouseBot.DisableConjured = 0 +AuctionHouseBot.DisableGems = 0 +AuctionHouseBot.DisableMoney = 0 +AuctionHouseBot.DisableMoneyLoot = 0 +AuctionHouseBot.DisableLootable = 0 +AuctionHouseBot.DisableKeys = 0 +AuctionHouseBot.DisableDuration = 0 +AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel = 0 + +############################################################################### +# AUCTION HOUSE BOT FILTERS PART 2 +# +# These Filters are boolean (0 or 1) and will disable items that are +# specifically meant for the Class named. +# (UnusedClass is Class 10, which was skipped for some reason) +# Default 0 (allowed) +# +############################################################################### + +AuctionHouseBot.DisableWarriorItems = 0 +AuctionHouseBot.DisablePaladinItems = 0 +AuctionHouseBot.DisableHunterItems = 0 +AuctionHouseBot.DisableRogueItems = 0 +AuctionHouseBot.DisablePriestItems = 0 +AuctionHouseBot.DisableDKItems = 0 +AuctionHouseBot.DisableShamanItems = 0 +AuctionHouseBot.DisableMageItems = 0 +AuctionHouseBot.DisableWarlockItems = 0 +AuctionHouseBot.DisableUnusedClassItems = 0 +AuctionHouseBot.DisableDruidItems = 0 + +############################################################################### +# AUCTION HOUSE BOT FILTERS PART 3 +# +# AuctionHouseBot.DisabledItems +# Prevent Seller from listing specific item(s) +# (not used anymore, see table "mod_auctionhousebot_disabled_items") +# +# AuctionHouseBot.DisableItemsBelowLevel +# Prevent Seller from listing Items below this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveLevel +# Prevent Seller from listing Items above this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowLevel +# Prevent Seller from listing Trade Goods below this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveLevel +# Prevent Seller from listing Trade Goods above this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowGUID +# Prevent Seller from listing Items below this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveGUID +# Prevent Seller from listing Items above this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowGUID +# Prevent Seller from listing Trade Goods below this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveGUID +# Prevent Seller from listing Trade Goods above this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowReqLevel +# Prevent Seller from listing Items below this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveReqLevel +# Prevent Seller from listing Items above this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowReqLevel +# Prevent Seller from listing Trade Goods below this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveReqLevel +# Prevent Seller from listing Trade Goods above this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowReqSkillRank +# Prevent Seller from listing Items below this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveReqSkillRank +# Prevent Seller from listing Items above this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowReqSkillRank +# Prevent Seller from listing Trade Goods below this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveReqSkillRank +# Prevent Seller from listing Trade Goods above this Required Skill Rank +# Default 0 (Off) +# +############################################################################### + +AuctionHouseBot.DisableItemsBelowLevel = 0 +AuctionHouseBot.DisableItemsAboveLevel = 0 +AuctionHouseBot.DisableTGsBelowLevel = 0 +AuctionHouseBot.DisableTGsAboveLevel = 0 +AuctionHouseBot.DisableItemsBelowGUID = 0 +AuctionHouseBot.DisableItemsAboveGUID = 0 +AuctionHouseBot.DisableTGsBelowGUID = 0 +AuctionHouseBot.DisableTGsAboveGUID = 0 +AuctionHouseBot.DisableItemsBelowReqLevel = 0 +AuctionHouseBot.DisableItemsAboveReqLevel = 0 +AuctionHouseBot.DisableTGsBelowReqLevel = 0 +AuctionHouseBot.DisableTGsAboveReqLevel = 0 +AuctionHouseBot.DisableItemsBelowReqSkillRank = 0 +AuctionHouseBot.DisableItemsAboveReqSkillRank = 0 +AuctionHouseBot.DisableTGsBelowReqSkillRank = 0 +AuctionHouseBot.DisableTGsAboveReqSkillRank = 0 diff --git a/modules/mod-ah-bot/include.sh b/modules/mod-ah-bot/include.sh new file mode 100644 index 0000000..038ece6 --- /dev/null +++ b/modules/mod-ah-bot/include.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +MOD_AH_BOT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" + +source $MOD_AH_BOT_ROOT"/conf/conf.sh.dist" + +if [ -f $MOD_AH_BOT_ROOT"/conf/conf.sh" ]; then + source $MOD_AH_BOT_ROOT"/conf/conf.sh" +fi diff --git a/modules/mod-ah-bot/sql/world/base/mod_auctionhousebot.sql b/modules/mod-ah-bot/sql/world/base/mod_auctionhousebot.sql new file mode 100644 index 0000000..12aaa00 --- /dev/null +++ b/modules/mod-ah-bot/sql/world/base/mod_auctionhousebot.sql @@ -0,0 +1,368 @@ +DROP TABLE IF EXISTS `mod_auctionhousebot`; +CREATE TABLE `mod_auctionhousebot` ( + `auctionhouse` int(11) NOT NULL DEFAULT '0' COMMENT 'mapID of the auctionhouse.', + `name` char(25) DEFAULT NULL COMMENT 'Text name of the auctionhouse.', + `minitems` int(11) DEFAULT '0' COMMENT 'This is the minimum number of items you want to keep in the auction house. a 0 here will make it the same as the maximum.', + `maxitems` int(11) DEFAULT '0' COMMENT 'This is the number of items you want to keep in the auction house.', + `percentgreytradegoods` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the Grey Trade Goods auction items', + `percentwhitetradegoods` int(11) DEFAULT '27' COMMENT 'Sets the percentage of the White Trade Goods auction items', + `percentgreentradegoods` int(11) DEFAULT '12' COMMENT 'Sets the percentage of the Green Trade Goods auction items', + `percentbluetradegoods` int(11) DEFAULT '10' COMMENT 'Sets the percentage of the Blue Trade Goods auction items', + `percentpurpletradegoods` int(11) DEFAULT '1' COMMENT 'Sets the percentage of the Purple Trade Goods auction items', + `percentorangetradegoods` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the Orange Trade Goods auction items', + `percentyellowtradegoods` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the Yellow Trade Goods auction items', + `percentgreyitems` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the non trade Grey auction items', + `percentwhiteitems` int(11) DEFAULT '10' COMMENT 'Sets the percentage of the non trade White auction items', + `percentgreenitems` int(11) DEFAULT '30' COMMENT 'Sets the percentage of the non trade Green auction items', + `percentblueitems` int(11) DEFAULT '8' COMMENT 'Sets the percentage of the non trade Blue auction items', + `percentpurpleitems` int(11) DEFAULT '2' COMMENT 'Sets the percentage of the non trade Purple auction items', + `percentorangeitems` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the non trade Orange auction items', + `percentyellowitems` int(11) DEFAULT '0' COMMENT 'Sets the percentage of the non trade Yellow auction items', + `minpricegrey` int(11) DEFAULT '100' COMMENT 'Minimum price of Grey items (percentage).', + `maxpricegrey` int(11) DEFAULT '150' COMMENT 'Maximum price of Grey items (percentage).', + `minpricewhite` int(11) DEFAULT '150' COMMENT 'Minimum price of White items (percentage).', + `maxpricewhite` int(11) DEFAULT '250' COMMENT 'Maximum price of White items (percentage).', + `minpricegreen` int(11) DEFAULT '800' COMMENT 'Minimum price of Green items (percentage).', + `maxpricegreen` int(11) DEFAULT '1400' COMMENT 'Maximum price of Green items (percentage).', + `minpriceblue` int(11) DEFAULT '1250' COMMENT 'Minimum price of Blue items (percentage).', + `maxpriceblue` int(11) DEFAULT '1750' COMMENT 'Maximum price of Blue items (percentage).', + `minpricepurple` int(11) DEFAULT '2250' COMMENT 'Minimum price of Purple items (percentage).', + `maxpricepurple` int(11) DEFAULT '4550' COMMENT 'Maximum price of Purple items (percentage).', + `minpriceorange` int(11) DEFAULT '3250' COMMENT 'Minimum price of Orange items (percentage).', + `maxpriceorange` int(11) DEFAULT '5550' COMMENT 'Maximum price of Orange items (percentage).', + `minpriceyellow` int(11) DEFAULT '5250' COMMENT 'Minimum price of Yellow items (percentage).', + `maxpriceyellow` int(11) DEFAULT '6550' COMMENT 'Maximum price of Yellow items (percentage).', + `minbidpricegrey` int(11) DEFAULT '70' COMMENT 'Starting bid price of Grey items as a percentage of the randomly chosen buyout price. Default: 70', + `maxbidpricegrey` int(11) DEFAULT '100' COMMENT 'Starting bid price of Grey items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpricewhite` int(11) DEFAULT '70' COMMENT 'Starting bid price of White items as a percentage of the randomly chosen buyout price. Default: 70', + `maxbidpricewhite` int(11) DEFAULT '100' COMMENT 'Starting bid price of White items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpricegreen` int(11) DEFAULT '80' COMMENT 'Starting bid price of Green items as a percentage of the randomly chosen buyout price. Default: 80', + `maxbidpricegreen` int(11) DEFAULT '100' COMMENT 'Starting bid price of Green items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpriceblue` int(11) DEFAULT '75' COMMENT 'Starting bid price of Blue items as a percentage of the randomly chosen buyout price. Default: 75', + `maxbidpriceblue` int(11) DEFAULT '100' COMMENT 'Starting bid price of Blue items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpricepurple` int(11) DEFAULT '80' COMMENT 'Starting bid price of Purple items as a percentage of the randomly chosen buyout price. Default: 80', + `maxbidpricepurple` int(11) DEFAULT '100' COMMENT 'Starting bid price of Purple items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpriceorange` int(11) DEFAULT '80' COMMENT 'Starting bid price of Orange items as a percentage of the randomly chosen buyout price. Default: 80', + `maxbidpriceorange` int(11) DEFAULT '100' COMMENT 'Starting bid price of Orange items as a percentage of the randomly chosen buyout price. Default: 100', + `minbidpriceyellow` int(11) DEFAULT '80' COMMENT 'Starting bid price of Yellow items as a percentage of the randomly chosen buyout price. Default: 80', + `maxbidpriceyellow` int(11) DEFAULT '100' COMMENT 'Starting bid price of Yellow items as a percentage of the randomly chosen buyout price. Default: 100', + `maxstackgrey` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackwhite` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackgreen` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackblue` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackpurple` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackorange` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `maxstackyellow` int(11) DEFAULT '0' COMMENT 'Stack size limits for item qualities - a value of 0 will disable a maximum stack size for that quality, which will allow the bot to create items in stack as large as the item allows.', + `buyerpricegrey` int(11) DEFAULT '1' COMMENT 'Multiplier to vendorprice when buying grey items from auctionhouse', + `buyerpricewhite` int(11) DEFAULT '3' COMMENT 'Multiplier to vendorprice when buying white items from auctionhouse', + `buyerpricegreen` int(11) DEFAULT '5' COMMENT 'Multiplier to vendorprice when buying green items from auctionhouse', + `buyerpriceblue` int(11) DEFAULT '12' COMMENT 'Multiplier to vendorprice when buying blue items from auctionhouse', + `buyerpricepurple` int(11) DEFAULT '15' COMMENT 'Multiplier to vendorprice when buying purple items from auctionhouse', + `buyerpriceorange` int(11) DEFAULT '20' COMMENT 'Multiplier to vendorprice when buying orange items from auctionhouse', + `buyerpriceyellow` int(11) DEFAULT '22' COMMENT 'Multiplier to vendorprice when buying yellow items from auctionhouse', + `buyerbiddinginterval` int(11) DEFAULT '1' COMMENT 'Interval how frequently AHB bids on each AH. Time in minutes', + `buyerbidsperinterval` int(11) DEFAULT '1' COMMENT 'number of bids to put in per bidding interval', + PRIMARY KEY (`auctionhouse`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `mod_auctionhousebot_disabled_items`; +CREATE TABLE `mod_auctionhousebot_disabled_items` ( + `item` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`item`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- AHBot auctionhouse configuration +INSERT INTO `mod_auctionhousebot` (`auctionhouse`, `name`, `minitems`, `maxitems`, `percentgreytradegoods`, `percentwhitetradegoods`, `percentgreentradegoods`, `percentbluetradegoods`, `percentpurpletradegoods`, `percentorangetradegoods`, `percentyellowtradegoods`, `percentgreyitems`, `percentwhiteitems`, `percentgreenitems`, `percentblueitems`, `percentpurpleitems`, `percentorangeitems`, `percentyellowitems`, `minpricegrey`, `maxpricegrey`, `minpricewhite`, `maxpricewhite`, `minpricegreen`, `maxpricegreen`, `minpriceblue`, `maxpriceblue`, `minpricepurple`, `maxpricepurple`, `minpriceorange`, `maxpriceorange`, `minpriceyellow`, `maxpriceyellow`, `minbidpricegrey`, `maxbidpricegrey`, `minbidpricewhite`, `maxbidpricewhite`, `minbidpricegreen`, `maxbidpricegreen`, `minbidpriceblue`, `maxbidpriceblue`, `minbidpricepurple`, `maxbidpricepurple`, `minbidpriceorange`, `maxbidpriceorange`, `minbidpriceyellow`, `maxbidpriceyellow`, `maxstackgrey`, `maxstackwhite`, `maxstackgreen`, `maxstackblue`, `maxstackpurple`, `maxstackorange`, `maxstackyellow`, `buyerpricegrey`, `buyerpricewhite`, `buyerpricegreen`, `buyerpriceblue`, `buyerpricepurple`, `buyerpriceorange`, `buyerpriceyellow`, `buyerbiddinginterval`, `buyerbidsperinterval`) +VALUES +(2,'Alliance',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1), +(6,'Horde',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1), +(7,'Neutral',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1); + +-- Items unavailable to players +INSERT INTO `mod_auctionhousebot_disabled_items` +VALUES +(17), (3895), (1700), (862), (4196), (3934), (2275), (4213), (4988), (4989), (4990), (4110), (4111), (4116), (3463), (3068), +(913), (2016), (3738), (1189), (3222), (2664), (2273), (4763), (2444), (1041), (1133), (1134), (2413), (2415), (2927), (2932), +(2443), (1487), (1623), (3031), (3034), (3762), (3772), (4981), (2693), (2808), (1254), (2442), (3137), (4191), (4193), (931), +(1114), (1450), (2136), (1352), (2441), (3884), (4200), (2588), (2922), (3005), (3122), (1193), (1057), (3107), (3135), (3144), +(4273), (1113), (2288), (2556), (2921), (3004), (763), (1146), (1255), (2929), (4143), (2064), (3648), (1162), (1167), (2377), +(2920), (3003), (4965), (2497), (2499), (2501), (2599), (3320), (964), (2496), (2498), (2503), (2946), (3131), (1389), (2500), +(2502), (4959), (1166), (1386), (2133), (4930), (1029), (2055), (2128), (2481), (2484), (2487), (3260), (2482), (2483), (2485), +(2486), (2947), (3111), (37), (996), (119), (138), (734), (876), (895), (896), (900), (956), (958), (960), (997), +(1014), (1020), (1021), (1024), (1025), (1027), (1324), (1356), (1672), (1923), (1977), (2410), (2477), (2586), (2638), (2668), +(2755), (2891), (3316), (3513), (3516), (3536), (3584), (3686), (3707), (3744), (4278), (4524), (4703), (4704), (4749), (4851), +(4868), (192), (3958), (3978), (4014), (3952), (3981), (3991), (4011), (3957), (3979), (4012), (3959), (3982), (4010), (3954), +(3983), (3988), (4009), (3953), (3984), (4013), (3956), (3977), (4008), (3955), (3980), (4015), (2931), (3776), (1914), (4858), +(3713), (3777), (3063), (2918), (3046), (3052), (3062), (4912), (2995), (1028), (1192), (2692), (1298), (1363), (4688), (4774), +(4773), (4761), (2305), (2306), (4471), (88), (91), (100), (128), (143), (156), (813), (1222), (1259), (1902), (1911), +(2081), (2184), (2550), (2705), (2715), (2810), (3148), (3168), (3245), (3368), (3675), (3774), (5828), (9372), (8708), (8586), +(9240), (9380), (9484), (9417), (10579), (9718), (7187), (10978), (9685), (9214), (9653), (7987), (7988), (7986), (7550), (7547), +(7548), (7994), (7748), (7953), (9888), (5010), (7497), (7466), (5008), (8840), (5004), (5005), (7467), (7427), (7426), (7948), +(7949), (7950), (7951), (7952), (6589), (6360), (6376), (10049), (5821), (5822), (7188), (6478), (10998), (6345), (5748), (5255), +(5968), (8350), (10939), (6343), (9602), (10595), (8079), (8008), (9421), (8076), (8078), (10683), (8171), (8546), (10662), (10818), +(8007), (5510), (8075), (8077), (10664), (8147), (8993), (5663), (5874), (5875), (8583), (8589), (8590), (8627), (8628), (8630), +(8633), (9254), (10620), (5513), (5522), (6357), (8365), (8366), (5509), (6715), (5108), (5518), (6355), (5632), (5845), (6352), +(6359), (6363), (6364), (6647), (6766), (5654), (5657), (5511), (5105), (6354), (6366), (6374), (6650), (8964), (5232), (5517), +(5660), (5013), (5024), (5603), (5823), (6292), (6294), (6295), (6309), (6310), (6311), (6351), (6353), (6358), (6645), (6754), +(7678), (5150), (6651), (5512), (6182), (6183), (6619), (6649), (5229), (6356), (5235), (5043), (5044), (5349), (5350), (6216), +(6291), (6643), (6891), (7807), (7808), (6648), (5056), (5184), (5220), (5330), (5333), (5353), (5389), (5400), (5410), (5417), +(5418), (5455), (5515), (5531), (5562), (5563), (5639), (5645), (5646), (5681), (5768), (5769), (5833), (5859), (5878), (6130), +(6276), (6277), (6278), (6279), (6280), (6435), (6490), (6491), (6492), (6495), (6496), (6497), (6498), (6500), (6501), (6516), +(6544), (6623), (6717), (6718), (6834), (6927), (6988), (7134), (7206), (7208), (7268), (7271), (7286), (7287), (7333), (7392), +(7679), (7680), (7681), (7716), (7725), (7733), (7737), (7867), (7923), (7970), (8072), (8426), (9280), (9281), (9282), (9284), +(9316), (9319), (9325), (9330), (9365), (9593), (9594), (9595), (9596), (9597), (10464), (10691), (10692), (10693), (10694), (5495), +(5863), (6307), (7769), (7770), (7771), (8164), (8383), (8585), (9311), (9438), (9440), (9441), (9443), (10790), (5550), (5549), +(5555), (8368), (8688), (6951), (5560), (7428), (7190), (5625), (6174), (7170), (5106), (8427), (5379), (5259), (5283), (5362), +(5363), (5364), (5367), (5370), (5371), (5377), (5435), (5600), (6131), (6150), (6225), (6227), (6232), (6297), (6301), (6455), +(7135), (8425), (9700), (9701), (10457), (10450), (10791), (11264), (12947), (15780), (14550), (12302), (12303), (12330), (12351), (12353), +(12354), (13317), (13326), (13327), (13328), (13329), (15292), (15293), (12731), (12588), (12970), (13080), (13090), (13092), (13936), (13950), +(14543), (13148), (13164), (13173), (15410), (15769), (11768), (12105), (11743), (14344), (11671), (11672), (14343), (12469), (11178), (11177), +(13325), (11139), (11138), (11084), (12325), (12326), (12327), (13323), (13324), (12616), (12617), (12615), (12904), (12104), (12106), (12107), +(13175), (13242), (13247), (12866), (11175), (12258), (11174), (11135), (11134), (11082), (13727), (13728), (13730), (13731), (13736), (13737), +(13738), (13739), (13740), (13741), (13742), (13743), (13744), (13745), (13746), (13747), (13748), (13749), (13762), (13763), (13764), (13765), +(13766), (13767), (13768), (13769), (13770), (13771), (13772), (13773), (13775), (13776), (13777), (13778), (13779), (13780), (13781), (13782), +(13783), (13784), (13785), (13788), (13791), (13794), (13797), (13798), (13801), (13802), (13803), (13804), (13805), (13806), (13807), (13808), +(13809), (13603), (15756), (13701), (14488), (11950), (11951), (11952), (13480), (13888), (13889), (13890), (13891), (13893), (13901), (13902), +(13903), (13904), (13905), (13906), (13907), (13908), (13910), (13911), (13912), (13914), (13915), (13916), (13917), (13918), (14481), (13477), +(14894), (15409), (15415), (15417), (15419), (15886), (13602), (13700), (11176), (13422), (13754), (13755), (13756), (13758), (13759), (13760), +(13875), (13876), (13877), (13878), (13879), (13880), (13881), (13882), (13883), (13884), (13885), (13886), (13887), (11903), (14062), (15326), +(15327), (11111), (13699), (11137), (11083), (12238), (12446), (12447), (12448), (12449), (14891), (14083), (11024), (11131), (11149), (11170), +(11222), (11230), (11282), (11364), (11413), (11470), (11507), (11508), (11512), (11513), (11582), (11602), (11609), (11613), (11616), (11947), +(11949), (11954), (12064), (12241), (12263), (12347), (12349), (12563), (12567), (12648), (12649), (12723), (12847), (12885), (13155), (13159), +(13370), (13673), (13726), (13732), (13733), (13734), (13787), (13790), (13793), (13796), (14339), (14390), (14392), (14645), (15448), (15843), +(15845), (11270), (11283), (11511), (11514), (12468), (15422), (15423), (12348), (12787), (12943), (12991), (13316), (13337), (13612), (14586), +(18582), (18583), (18584), (17182), (17782), (18881), (17142), (17067), (17068), (18608), (18609), (18713), (18715), (17075), (18813), (17078), +(17064), (18205), (17223), (18538), (18970), (18241), (18242), (18243), (18244), (18245), (18246), (18247), (18248), (18768), (17886), (17982), +(16369), (16391), (16392), (16393), (16396), (16397), (16401), (16403), (16405), (16406), (16409), (16410), (16413), (16414), (16415), (16416), +(16417), (16418), (16419), (16420), (16421), (16422), (16423), (16424), (16425), (16426), (16427), (16428), (16429), (16430), (16431), (16432), +(16433), (16434), (16435), (16436), (16485), (16487), (16489), (16490), (16491), (16492), (16494), (16496), (16498), (16499), (16501), (16502), +(16503), (16504), (16505), (16506), (16507), (16508), (16509), (16510), (16513), (16514), (16515), (16516), (16518), (16519), (16521), (16522), +(16523), (16524), (16525), (16526), (16527), (16528), (16530), (16531), (17562), (17564), (17566), (17567), (17568), (17569), (17570), (17571), +(17572), (17573), (17576), (17577), (17594), (17596), (17598), (17599), (17600), (17601), (17610), (17611), (17612), (17613), (17616), (17617), +(16337), (17967), (17968), (16999), (17733), (16334), (16336), (16340), (18303), (18304), (18320), (18341), (18342), (16315), (16203), (17966), +(16664), (16202), (17769), (16792), (16165), (17224), (17364), (16026), (16339), (16350), (16366), (16374), (16896), (17012), (18142), (16320), +(16362), (16378), (16356), (16387), (16047), (16171), (16330), (16383), (18636), (16041), (16042), (16373), (16389), (18651), (16325), (16349), +(16361), (16895), (17024), (16319), (16355), (16365), (16386), (16377), (16382), (16082), (16085), (16971), (16329), (16372), (16360), (16390), +(17019), (16348), (16354), (16385), (16893), (16967), (16318), (16324), (16381), (16364), (16371), (16388), (17027), (16057), (16328), (16359), +(16376), (16353), (16380), (16384), (16347), (16892), (16317), (16368), (16323), (16358), (16379), (16327), (16352), (16363), (16375), (16346), +(18964), (16316), (16357), (16351), (16322), (16326), (16331), (16302), (17195), (17302), (17305), (17308), (18002), (16321), (16180), (16642), +(16643), (16644), (16968), (16969), (16970), (16973), (17126), (17242), (17262), (17323), (17324), (17325), (17333), (17353), (17362), (17363), +(17442), (17505), (17506), (17507), (17696), (17758), (17882), (17887), (18151), (18153), (18492), (18540), (18566), (18643), (18799), (18154), +(18642), (20880), (19158), (20142), (20329), (21584), (21587), (21588), (21594), (21612), (21613), (21614), (21339), (20487), (20488), (21124), +(21125), (21127), (21890), (19879), (19951), (19952), (19953), (19954), (19955), (19956), (19957), (19958), (19959), (20698), (20725), (20887), +(19875), (20720), (20721), (20722), (19105), (19110), (20696), (20706), (20368), (21281), (21282), (21283), (21293), (21302), (19986), (20003), +(20005), (20502), (20522), (20524), (21044), (20381), (21785), (21786), (21878), (21772), (21773), (20086), (20965), (19803), (19805), (19806), +(19808), (20591), (20596), (20962), (20957), (20953), (20829), (20952), (20825), (20822), (20819), (19213), (19322), (20256), (20560), (21992), +(21159), (21175), (19012), (19013), (19696), (20498), (20500), (20501), (19010), (19011), (19807), (20065), (21228), (21243), (21153), (19450), +(20067), (21150), (21164), (19008), (19009), (21113), (19006), (19007), (19054), (19055), (21071), (21168), (21212), (21043), (20708), (21162), +(19004), (19005), (20913), (20979), (20981), (19160), (19422), (19642), (19725), (19775), (19880), (19882), (20018), (20020), (20021), (20364), +(20393), (20416), (20418), (20419), (20420), (20432), (20433), (20435), (20436), (20447), (20448), (20449), (20450), (20454), (20455), (20456), +(20709), (20902), (20903), (20904), (20977), (20984), (21106), (21107), (21109), (21111), (21114), (21131), (21152), (21158), (21160), (21161), +(21171), (21442), (21519), (21536), (21560), (21577), (21578), (21591), (21815), (21816), (21817), (21818), (21819), (21820), (21821), (21822), +(21823), (21831), (21975), (21979), (21980), (21981), (19960), (21140), (19924), (20030), (21141), (22736), (22726), (22819), (22821), (22798), +(22799), (22802), (22812), (22691), (22947), (22954), (22800), (22801), (22804), (22807), (22808), (22809), (22811), (22816), (22818), (22820), +(22935), (22936), (22937), (22938), (22939), (22940), (22941), (22943), (22960), (22961), (22967), (22968), (22981), (22983), (22988), (22994), +(22803), (22806), (22810), (22813), (22814), (22815), (22942), (22805), (22817), (22450), (22349), (22350), (22351), (22352), (22353), (22354), +(22355), (22356), (22357), (22358), (22359), (22360), (22361), (22362), (22363), (22364), (22365), (22366), (22367), (22368), (22369), (22370), +(22371), (22372), (22373), (22374), (22375), (22376), (22891), (22230), (22273), (22446), (22447), (22782), (22018), (22019), (22103), (22104), +(22105), (22116), (22182), (22187), (22189), (22797), (22044), (22179), (22186), (22788), (22128), (22184), (22646), (22795), (22895), (22181), +(22185), (22190), (22183), (22180), (22188), (22972), (22710), (22020), (22042), (22045), (22140), (22141), (22142), (22143), (22144), (22145), +(22154), (22155), (22156), (22157), (22158), (22159), (22160), (22161), (22162), (22163), (22164), (22165), (22166), (22167), (22168), (22169), +(22170), (22171), (22172), (22178), (22202), (22260), (22262), (22263), (22283), (22284), (22285), (22286), (22287), (22288), (22289), (22290), +(22291), (22292), (22293), (22294), (22295), (22296), (22297), (22298), (22299), (22300), (22386), (22387), (22584), (22733), (22754), (22822), +(22896), (22899), (22058), (22059), (22709), (23051), (25596), (24526), (24561), (24567), (27965), (24550), (24557), (24265), (23053), (23057), +(23058), (23040), (23041), (23043), (23045), (23046), (23047), (23048), (23049), (23050), (23072), (23362), (23363), (23054), (23056), (23577), +(23242), (23000), (23001), (23025), (23027), (23037), (23038), (23042), (23069), (23070), (23219), (23220), (23663), (23664), (23665), (23666), +(23667), (23668), (23004), (23005), (23006), (23009), (23017), (23018), (23019), (23020), (23021), (23023), (23028), (23029), (23030), (23031), +(23032), (23033), (23034), (23035), (23036), (23039), (23044), (23068), (23071), (23073), (23075), (23221), (23226), (23237), (23238), (23014), +(23457), (23458), (23459), (23461), (23462), (23193), (23545), (23547), (23548), (23549), (23714), (23705), (23709), (23716), (23773), (24412), +(25641), (24137), (25667), (23854), (23855), (24288), (27388), (27446), (24071), (23885), (23882), (23364), (23366), (27774), (27811), (27002), +(27007), (26368), (26372), (26655), (26738), (26128), (26129), (26130), (26131), (26132), (26133), (26134), (26135), (26464), (26465), (26513), +(26527), (26541), (26569), (26765), (26779), (25573), (25574), (25575), (25576), (25580), (25581), (25582), (26235), (26792), (25627), (27196), +(27718), (27719), (27720), (26324), (25145), (25159), (25173), (25285), (26843), (26548), (26180), (26173), (26174), (26175), (27218), (23147), +(23151), (23153), (23229), (23076), (23157), (26015), (26029), (26041), (23420), (23421), (23422), (23432), (23433), (23434), (23233), (23234), +(23235), (27864), (26045), (27863), (24243), (23731), (23755), (23840), (24315), (25877), (23137), (23131), (23141), (23730), (23130), (23135), +(23140), (23144), (23148), (23152), (23162), (23194), (23195), (23196), (23684), (23745), (25469), (25699), (25700), (27422), (27437), (27481), +(27511), (27513), (23578), (25900), (23579), (23683), (23711), (23734), (23846), (23365), (23368), (24227), (24100), (23003), (23008), (23010), +(23011), (23012), (23013), (23016), (23024), (23055), (23214), (23227), (23248), (23340), (23341), (23342), (23350), (23352), (23360), (23378), +(23471), (23486), (23552), (23567), (23584), (23586), (23670), (23686), (23726), (23754), (23878), (23879), (23880), (24156), (24226), (24317), +(24494), (24538), (24573), (25635), (25677), (25747), (25748), (25749), (25750), (25754), (25755), (25756), (25757), (25850), (27317), (27419), +(27590), (23560), (23561), (23562), (23750), (23858), (23866), (23867), (23868), (25814), (27443), (25407), (24242), (27441), (24235), (24190), +(24234), (24188), (23330), (23355), (23952), (23980), (24283), (24506), (24509), (25813), (24140), (28294), (28295), (28297), (28298), (28299), +(28300), (28302), (28305), (28307), (28308), (28309), (28310), (28312), (28313), (28314), (28319), (28320), (28346), (28358), (28383), (28385), +(28402), (28404), (28409), (28410), (28422), (28423), (28443), (28444), (28446), (28447), (28449), (28450), (28476), (28629), (28630), (28639), +(28640), (28641), (28642), (28644), (28645), (28974), (28975), (28976), (28977), (28980), (28982), (28983), (28985), (28986), (28987), (28990), +(28991), (28993), (28994), (28995), (28997), (28998), (28355), (28356), (28357), (28244), (28245), (28381), (28405), (28411), (28424), (28445), +(28448), (28451), (28605), (28638), (28643), (28646), (28973), (28978), (28981), (28984), (28988), (28989), (28992), (28996), (28999), (28117), +(28122), (28388), (28389), (28482), (28293), (28613), (28614), (28615), (28616), (28617), (28618), (28619), (28620), (28622), (28623), (28624), +(28625), (28626), (28627), (28628), (28679), (28680), (28681), (28683), (28684), (28685), (28686), (28687), (28688), (28689), (28690), (28691), +(28692), (28693), (28694), (28695), (28696), (28697), (28698), (28699), (28700), (28701), (28702), (28703), (28704), (28705), (28706), (28707), +(28708), (28709), (28710), (28711), (28712), (28713), (28714), (28715), (28716), (28717), (28718), (28719), (28720), (28721), (28722), (28723), +(28724), (28805), (28806), (28807), (28808), (28809), (28811), (28812), (28813), (28814), (28815), (28817), (28818), (28819), (28820), (28821), +(28831), (28832), (28833), (28834), (28835), (28836), (28837), (28838), (28839), (28840), (28841), (28842), (28843), (28844), (28845), (28846), +(28847), (28848), (28849), (28850), (28851), (28852), (28853), (28854), (28855), (28856), (28857), (28858), (28859), (28860), (28861), (28862), +(28863), (28864), (28865), (28866), (28867), (28868), (28869), (28870), (28871), (28872), (28873), (28874), (28875), (28917), (28918), (28919), +(28920), (28921), (28922), (28923), (28924), (28925), (28926), (28928), (28929), (28930), (28931), (28933), (28935), (28937), (28938), (28939), +(28940), (28941), (28942), (28943), (28944), (28945), (28946), (28947), (28948), (28949), (28950), (28951), (28952), (28953), (28954), (28955), +(28956), (28957), (28959), (28960), (28043), (28044), (28045), (28291), (28408), (28145), (28073), (28112), (28068), (28596), (28072), (28110), +(28131), (28071), (28047), (28099), (28500), (28676), (28738), (28739), (28784), (28039), (28023), (28489), (28905), (30320), (29828), (31958), +(31959), (31965), (31966), (31978), (31984), (31985), (31986), (30448), (29000), (29001), (29003), (29004), (29005), (30491), (31594), (31595), +(31596), (31597), (29885), (29002), (29006), (31598), (31599), (29237), (30559), (29120), (29225), (31584), (31585), (31586), (31587), (31588), +(31589), (31590), (31591), (31592), (31593), (31620), (31621), (31622), (31623), (31624), (31625), (31626), (31627), (31628), (31629), (31630), +(31631), (31632), (31633), (31634), (31635), (31636), (31637), (31638), (31639), (31640), (31641), (31642), (31643), (31644), (31646), (31647), +(31648), (31649), (31650), (31942), (31490), (31491), (31802), (31492), (31493), (31494), (31246), (29210), (30418), (30287), (30288), (30289), +(31730), (30845), (29024), (30427), (30703), (30760), (29539), (29547), (29548), (29569), (30309), (30499), (29041), (29311), (29749), (29751), +(29769), (29839), (29840), (29841), (29842), (29852), (29856), (29857), (29860), (29861), (29863), (29868), (29871), (29872), (29874), (29887), +(29961), (29963), (30193), (30197), (30430), (30438), (30524), (30525), (30526), (30539), (30567), (30595), (30613), (30630), (30658), (30659), +(30717), (31122), (31123), (31130), (31252), (31266), (31346), (31365), (31518), (31607), (31665), (31813), (31843), (31845), (31849), (29790), +(29805), (30632), (30805), (31530), (29410), (29419), (29565), (29571), (29575), (29576), (29645), (29712), (30414), (31824), (32824), (32466), +(32419), (32760), (32761), (32956), (32959), (32416), (32003), (32014), (32025), (32026), (32027), (32028), (32044), (32045), (32046), (32052), +(32053), (32054), (32055), (32961), (32962), (32963), (32964), (32944), (32418), (32422), (32482), (32955), (32958), (32450), (32451), (32452), +(32974), (32975), (32976), (32978), (32982), (32984), (32985), (32987), (32992), (32993), (32995), (32996), (32415), (32417), (32954), (32957), +(32973), (32977), (32983), (32986), (32991), (32994), (32093), (32094), (32095), (32096), (32097), (32098), (32099), (32100), (32101), (32102), +(32103), (32104), (32105), (32106), (32107), (32108), (32109), (32110), (32111), (32112), (32113), (32114), (32115), (32116), (32117), (32118), +(32119), (32120), (32121), (32122), (32123), (32124), (32125), (32126), (32127), (32128), (32129), (32130), (32131), (32132), (32133), (32134), +(32135), (32136), (32137), (32138), (32139), (32140), (32141), (32142), (32143), (32144), (32145), (32146), (32147), (32148), (32149), (32150), +(32151), (32152), (32153), (32154), (32155), (32156), (32157), (32158), (32159), (32160), (32161), (32162), (32163), (32164), (32165), (32166), +(32167), (32168), (32169), (32170), (32171), (32172), (32173), (32174), (32175), (32176), (32177), (32178), (32179), (32180), (32181), (32182), +(32183), (32184), (32185), (32186), (32187), (32188), (32189), (32190), (32192), (32414), (32421), (32655), (32656), (32914), (32735), (32895), +(32896), (32407), (32658), (32659), (32660), (32661), (32662), (32663), (32664), (32665), (32949), (32950), (32412), (32915), (32917), (32918), +(32919), (32920), (32465), (32542), (32566), (32594), (32773), (32764), (32765), (32766), (32618), (32642), (32543), (32544), (32545), (32546), +(32547), (32548), (32549), (32550), (32551), (32552), (32553), (32554), (32555), (32556), (32557), (32558), (32559), (32560), (32561), (32595), +(32598), (32601), (32840), (32844), (32845), (32846), (32847), (32762), (32763), (32767), (32972), (32320), (32364), (32408), (32626), (32627), +(32628), (32629), (32630), (32631), (32688), (32689), (32690), (32691), (32692), (32693), (32700), (32701), (32702), (32703), (32704), (32705), +(32706), (32707), (32708), (32709), (32710), (32711), (32712), (32713), (32734), (32911), (32971), (32578), (32906), (32725), (32615), (32633), +(32841), (33475), (34146), (34149), (34145), (34148), (34144), (34147), (34219), (34335), (34209), (34212), (33668), (33671), (33674), (33676), +(33679), (33682), (33684), (33690), (33693), (33699), (33700), (33703), (33717), (33720), (33726), (33729), (33732), (33744), (33747), (33753), +(33767), (33770), (33920), (33921), (33922), (33923), (33076), (33077), (33078), (33309), (33313), (33937), (33940), (33943), (33946), (33949), +(33952), (34576), (34577), (34578), (34579), (34580), (33987), (33997), (33054), (33065), (33066), (33067), (33068), (33482), (33964), (33936), +(33939), (33942), (33945), (33948), (33951), (33957), (33959), (34073), (34074), (34075), (34622), (34057), (33132), (33137), (33138), (33139), +(33141), (33142), (33809), (34544), (33080), (33225), (33182), (33184), (34835), (33350), (34138), (34139), (33803), (34143), (34142), (34221), +(33060), (33147), (34627), (34967), (34415), (34107), (33224), (33993), (34955), (33017), (33018), (33019), (33020), (33021), (33176), (33183), +(33219), (33223), (34492), (34499), (34518), (34519), (33197), (34484), (34486), (33455), (34025), (34030), (33312), (34062), (34024), (34126), +(34469), (34735), (34737), (34738), (34739), (34740), (34741), (34742), (34743), (34744), (34745), (34746), (34864), (34865), (34867), (34868), +(33823), (33824), (34467), (34663), (33096), (33218), (33041), (33081), (33087), (33105), (33111), (33121), (33315), (33336), (33341), (33477), +(33558), (33599), (33604), (33610), (33614), (33615), (33616), (33617), (33634), (33781), (33784), (33839), (33848), (33850), (33929), (34044), +(34077), (34112), (34115), (34116), (34117), (34120), (34123), (34135), (34158), (34187), (34191), (34494), (34497), (34501), (34623), (34645), +(34647), (34716), (34718), (34842), (33051), (33063), (33797), (34171), (33316), (34476), (33089), (34589), (34590), (34591), (34694), (34784), +(34880), (34907), (36942), (35290), (35291), (35292), (35317), (35319), (35327), (35494), (35495), (35496), (35497), (35507), (35508), (35509), +(35511), (35514), (35213), (35539), (35541), (35545), (35546), (35549), (35550), (35202), (35209), (35226), (35517), (35518), (35519), (35520), +(35521), (35522), (35523), (35524), (35525), (35526), (35527), (35528), (35529), (35530), (35531), (35532), (35533), (35535), (35537), (35538), +(35544), (35548), (35551), (35553), (35555), (35664), (35665), (35666), (36866), (36867), (35728), (35729), (35730), (35731), (35225), (36941), +(36454), (36477), (36491), (36505), (36519), (36533), (36547), (36561), (36575), (36589), (36603), (36617), (36631), (36645), (36659), (36673), +(36687), (36701), (36715), (35876), (36910), (36915), (35626), (36899), (36900), (36970), (36892), (36893), (36894), (36965), (36897), (36955), +(36967), (36895), (36960), (36912), (36914), (36968), (36959), (36889), (36890), (36891), (36966), (36896), (36964), (35285), (35286), (35396), +(35397), (35398), (35399), (35400), (35417), (35418), (35419), (35420), (35421), (35422), (35423), (35424), (35425), (35426), (35427), (35428), +(35429), (35430), (35431), (35432), (35433), (35434), (35435), (35436), (35437), (35438), (35439), (35440), (35441), (35442), (35443), (35444), +(35445), (35446), (35447), (35448), (35449), (35450), (35451), (35452), (35453), (35454), (35455), (35456), (35457), (35458), (35459), (35460), +(35461), (35462), (35313), (35946), (35126), (35229), (35289), (35692), (35701), (35718), (35722), (35738), (35777), (35803), (35840), (35854), +(36733), (36748), (36765), (36768), (36772), (36799), (36828), (36836), (36846), (36848), (35512), (35792), (35806), (36862), (36863), (35757), +(36794), (36795), (36829), (36830), (38691), (37739), (37740), (37611), (37127), (37128), (37597), (38287), (38288), (38289), (38290), (38282), +(38307), (38377), (38378), (38265), (37598), (37719), (38576), (38484), (38309), (38310), (38311), (38312), (38313), (38314), (37174), (37175), +(37176), (37196), (37197), (37243), (37244), (37245), (37290), (37364), (37365), (37366), (37410), (37587), (37590), (37624), (37625), (37646), +(37647), (37648), (37649), (37671), (37672), (37673), (37697), (37698), (37699), (37799), (37800), (37801), (37856), (37857), (37858), (37109), +(38442), (38443), (38444), (38445), (38387), (38388), (38389), (38390), (38572), (38468), (38243), (38244), (38245), (38246), (38247), (38248), +(38471), (38480), (38481), (38469), (37430), (37311), (37313), (38292), (38538), (38658), (38683), (37164), (37827), (37893), (37894), (37895), +(37896), (37897), (37297), (37298), (38301), (38578), (38916), (37955), (37967), (37976), (38052), (38140), (38204), (38383), (38524), (38525), +(38527), (37210), (37225), (37273), (37278), (37279), (37281), (37284), (37285), (37286), (37295), (37296), (37315), (37316), (37317), (37318), +(37321), (37323), (37324), (37385), (37386), (37400), (37420), (37433), (37444), (37448), (37450), (37451), (37453), (37454), (37455), (37457), +(37466), (37468), (37469), (37470), (37472), (37473), (37474), (37477), (37485), (37510), (37511), (37534), (37536), (37544), (38164), (38254), +(38255), (38256), (37343), (37345), (37346), (37338), (37326), (37329), (37335), (37336), (37337), (37710), (37312), (37163), (37154), (37126), +(37348), (38640), (38970), (38994), (38996), (38983), (37706), (38958), (37452), (38270), (38271), (38272), (38561), (38597), (38643), (38625), +(38957), (38567), (37161), (37157), (37158), (37489), (37898), (37900), (37901), (37902), (37903), (37904), (37905), (37906), (37907), (37908), +(37909), (37100), (37250), (37303), (37372), (37501), (37815), (37837), (37859), (37860), (37925), (38089), (38186), (38233), (38266), (38324), +(38380), (38382), (38483), (38498), (38512), (38577), (38600), (38606), (38619), (38621), (38622), (38623), (38624), (38629), (38630), (38631), +(37063), (37089), (37090), (37148), (37301), (37711), (37742), (37878), (38333), (38587), (38644), (38687), (38448), (37839), (38497), (38496), +(38626), (37467), (37579), (38261), (38263), (38264), (38268), (38269), (38273), (38274), (38605), (40481), (41900), (41911), (41995), (40549), +(39715), (40406), (40407), (40408), (40409), (40410), (40412), (40414), (40650), (39263), (39427), (39467), (39468), (39470), (39472), (39473), +(40307), (40553), (40440), (40441), (40442), (40443), (40444), (39769), (41749), (41342), (39303), (40480), (41605), (41606), (40762), (40777), +(40599), (40727), (40754), (40832), (40839), (40725), (41403), (41404), (41405), (41406), (41407), (41408), (41409), (41410), (41411), (41412), +(41413), (41414), (41415), (41416), (41417), (41418), (41419), (41420), (41421), (41422), (41423), (41796), (41125), (39370), (40232), (41133), +(39364), (39410), (39440), (39460), (39819), (39828), (41756), (41757), (41758), (41759), (39707), (39708), (39709), (39710), (39711), (41178), +(41750), (41753), (39685), (41147), (41166), (41174), (41196), (39644), (39687), (39738), (39969), (40199), (40776), (41091), (41093), (41111), +(41118), (41173), (39526), (39527), (41195), (39148), (39213), (39343), (39692), (41741), (41800), (41801), (41802), (41803), (41804), (41805), +(41806), (41807), (41808), (41809), (41810), (41811), (41812), (41813), (41814), (40773), (41194), (39342), (40484), (40948), (41193), (41172), +(39341), (41192), (41171), (39340), (41169), (41191), (39339), (41170), (39338), (39302), (39334), (39151), (39162), (39163), (39314), (39575), +(39576), (39614), (39739), (39748), (39903), (39904), (40110), (40218), (40219), (40220), (40221), (40222), (40223), (40224), (40225), (40226), +(40227), (40228), (40229), (40230), (40231), (40389), (40686), (41132), (41585), (39506), (39883), (39153), (39743), (39754), (42000), (42007), +(42013), (42019), (42083), (42238), (42207), (42226), (42231), (42236), (42241), (42254), (42259), (42264), (42269), (42274), (42279), (42284), +(42289), (42316), (42321), (42326), (42331), (42345), (42351), (42359), (42383), (42389), (42449), (42484), (42489), (42494), (42501), (42512), +(42518), (42524), (42530), (42536), (42558), (42563), (42569), (42577), (42582), (42587), (42596), (42601), (42606), (42613), (42619), (42654), +(42655), (42656), (42657), (42658), (42851), (42664), (42665), (42666), (42667), (42668), (42625), (42626), (42627), (42628), (42629), (42659), +(42660), (42661), (42662), (42663), (42690), (42691), (42692), (42693), (42694), (42695), (42696), (42697), (42698), (42699), (42630), (42631), +(42632), (42633), (42634), (42635), (42636), (42637), (42638), (42639), (42669), (42670), (42671), (42672), (42673), (42674), (42675), (42676), +(42677), (42678), (42680), (42681), (42682), (42683), (42684), (42685), (42686), (42687), (42688), (42689), (42703), (42704), (42705), (42706), +(42707), (42708), (42709), (42710), (42711), (42712), (42713), (42714), (42715), (42716), (42717), (42718), (42719), (42720), (42721), (42722), +(42197), (42198), (42199), (42200), (42201), (42202), (42976), (42206), (42212), (42213), (42214), (42215), (42216), (42217), (42218), (42219), +(42220), (42221), (42222), (42223), (42224), (42294), (42295), (42296), (42297), (42343), (42344), (42356), (42382), (42388), (42444), (42445), +(42446), (42447), (42448), (42511), (42517), (42523), (42529), (42535), (42556), (42557), (42568), (42574), (42575), (42576), (42593), (42594), +(42595), (42611), (42612), (42618), (42755), (42953), (42975), (42977), (42978), (42979), (42980), (42981), (42982), (42983), (42875), (42885), +(42886), (42174), (42179), (42425), (42147), (42434), (42171), (42545), (42180), (42181), (42182), (42186), (42189), (42190), (42191), (42192), +(42193), (42194), (42195), (42196), (42432), (42433), (42170), (42986), (42590), (42474), (42440), (42894), (42733), (42342), (42350), (42381), +(42776), (42940), (43651), (43727), (43728), (43729), (43730), (43731), (43460), (43611), (43612), (43613), (43732), (43733), (43734), (43735), +(43736), (43737), (43738), (43739), (43740), (43741), (43742), (43743), (43744), (43745), (43746), (43747), (43748), (43749), (43750), (43751), +(43752), (43753), (43754), (43755), (43756), (43757), (43758), (43759), (43760), (43761), (43762), (43763), (43764), (43765), (43766), (43767), +(43768), (43769), (43770), (43771), (43772), (43773), (43774), (43775), (43776), (43777), (43778), (43779), (43780), (43781), (43782), (43783), +(43784), (43785), (43786), (43787), (43788), (43789), (43790), (43791), (43792), (43793), (43794), (43795), (43796), (43797), (43798), (43799), +(43800), (43801), (43802), (43803), (43804), (43805), (43806), (43807), (43808), (43809), (43810), (43811), (43812), (43813), (43814), (43815), +(43816), (43817), (43818), (43819), (43820), (43822), (43069), (43071), (43072), (43075), (43076), (43079), (43080), (43083), (43267), (43963), +(43964), (43475), (43476), (43302), (43303), (43304), (43949), (43517), (43698), (43648), (43848), (43878), (43895), (43922), (43936), (43938), +(43109), (43563), (43108), (43298), (43562), (43107), (43561), (43106), (43560), (43105), (43559), (43104), (43558), (43103), (43557), (43150), +(43523), (43087), (43097), (43518), (43468), (43571), (43572), (43614), (43620), (43621), (43647), (43652), (43038), (43646), (43002), (43099), +(43136), (43144), (43149), (43269), (43270), (43272), (43274), (43275), (43276), (43308), (43336), (43337), (43384), (43362), (43006), (43093), +(43288), (43307), (43471), (43486), (43489), (43617), (43618), (43619), (43627), (43628), (43629), (43630), (43631), (43632), (43633), (43634), +(43635), (43636), (43637), (43638), (43639), (43640), (43641), (43650), (43695), (43215), (43493), (43659), (43003), (43321), (43325), (43326), +(43328), (43329), (43330), (43333), (43341), (43576), (43577), (43643), (43644), (43645), (43653), (43658), (43675), (43676), (43677), (43678), +(43679), (43680), (43681), (43682), (43683), (43684), (43685), (43686), (43687), (43694), (43701), (43702), (43703), (43704), (43705), (43706), +(43707), (43708), (43709), (43710), (43711), (43712), (43713), (43714), (43715), (43716), (43717), (43718), (43719), (43720), (43721), (43722), +(43723), (44090), (44807), (45457), (45459), (45460), (45461), (45462), (45605), (45455), (45538), (45539), (45540), (45541), (45542), (45543), +(45544), (45547), (45548), (45549), (45350), (45464), (44310), (44311), (44333), (44417), (44418), (44869), (44870), (44926), (44948), (45924), +(44924), (44555), (44556), (44557), (44871), (44872), (44873), (44874), (44164), (44175), (45280), (45024), (45037), (45173), (44191), (44415), +(44416), (45172), (44505), (45174), (45175), (44391), (44392), (45850), (45851), (45852), (45853), (44945), (44563), (44875), (44876), (44877), +(44878), (44879), (44880), (44881), (44882), (44883), (44884), (45705), (44451), (44619), (44627), (44629), (44600), (44811), (44158), (44148), +(45180), (44260), (44261), (44262), (44263), (44264), (44265), (44266), (44267), (44268), (44269), (44270), (44271), (44272), (44273), (44274), +(44275), (44277), (44278), (44279), (44280), (44281), (44282), (44284), (44285), (44286), (44287), (44288), (44289), (44290), (44291), (44292), +(44293), (44866), (44972), (45063), (44703), (45575), (45126), (44428), (45052), (45050), (45629), (44849), (45127), (45229), (45230), (45231), +(45500), (44817), (44607), (45006), (45007), (45008), (45009), (44506), (44507), (45279), (45863), (45901), (45909), (44221), (44229), (44598), +(44608), (44609), (44475), (45276), (45277), (44432), (45908), (44743), (44604), (45942), (44462), (44480), (44508), (44620), (44646), (44680), +(44832), (44851), (44852), (44856), (44915), (44981), (44988), (44989), (44991), (44992), (44993), (44994), (44996), (44997), (45003), (45026), +(45028), (45029), (45030), (45031), (45032), (45033), (45036), (45045), (45049), (45082), (45120), (45278), (45328), (45569), (45728), (45729), +(45730), (45748), (45749), (45750), (45751), (45752), (45754), (45759), (45765), (45860), (45899), (45902), (45903), (45904), (45905), (44304), +(44434), (44656), (44718), (45034), (45035), (45568), (44299), (45630), (44728), (44236), (44298), (44300), (44578), (44580), (44705), (44755), +(44760), (44761), (44833), (45061), (45176), (45177), (45178), (45179), (45188), (45189), (45190), (45191), (45194), (45195), (45196), (45197), +(45198), (45199), (45200), (45201), (45202), (45900), (45907), (46105), (46104), (46214), (46215), (46217), (46218), (46219), (46220), (46222), +(46225), (46227), (46228), (46230), (46232), (46233), (46234), (46235), (46236), (46237), (46238), (46239), (46240), (46241), (46242), (46243), +(46244), (46245), (46246), (46248), (46255), (46256), (46257), (46273), (46274), (46275), (46276), (46277), (46288), (46289), (46290), (46291), +(46292), (46293), (46294), (46295), (46296), (46297), (46298), (46299), (46300), (46301), (46302), (46303), (46304), (46305), (46306), (46307), +(46103), (46213), (46216), (46221), (46223), (46224), (46226), (46231), (46247), (46249), (46250), (46251), (46252), (46253), (46254), (46258), +(46259), (46260), (46261), (46262), (46263), (46264), (46265), (46266), (46267), (46268), (46269), (46270), (46271), (46272), (46278), (46279), +(46280), (46281), (46282), (46283), (46284), (46285), (46286), (46287), (46309), (46339), (46340), (46341), (46342), (46343), (46344), (46345), +(46346), (46347), (46350), (46351), (47497), (47229), (46101), (46778), (46331), (47246), (46709), (46767), (46802), (46892), (46780), (46765), +(46766), (46849), (47507), (47395), (46399), (46400), (46401), (46402), (46403), (46055), (46847), (47030), (46887), (46054), (46735), (46069), +(46070), (46106), (46319), (46395), (46783), (46830), (46978), (47036), (46852), (46957), (49686), (48435), (48438), (48440), (48442), (48444), +(48507), (48509), (48511), (48513), (48515), (48517), (48519), (48521), (48523), (49191), (49497), (48725), (48726), (48727), (48728), (48729), +(48730), (48731), (48732), (48733), (48734), (48735), (48736), (48737), (48738), (48739), (48740), (48741), (48742), (48743), (48744), (48745), +(48746), (48747), (48748), (48749), (48750), (48751), (48752), (48753), (48754), (48755), (48756), (48757), (48758), (48759), (48760), (48761), +(48762), (48763), (48764), (48769), (48770), (48771), (48772), (48773), (48774), (48775), (48776), (48777), (48778), (48781), (48782), (48783), +(48784), (48785), (48786), (48787), (48788), (48789), (48790), (48794), (48795), (48796), (48797), (48798), (48799), (48800), (48801), (48802), +(48803), (48804), (48805), (48806), (48807), (48808), (48809), (48810), (48811), (48812), (48813), (48814), (48815), (48816), (48817), (48818), +(48819), (48820), (48821), (48822), (48823), (48824), (48825), (48826), (48827), (48828), (48829), (48830), (48831), (48832), (48833), (48836), +(48837), (48838), (48839), (48840), (48841), (48842), (48843), (48844), (48845), (48846), (48847), (48848), (48849), (48850), (48851), (48852), +(48853), (48854), (48855), (48860), (48861), (48862), (48863), (48864), (48865), (48866), (48867), (48868), (48869), (48870), (48871), (48872), +(48873), (48874), (48875), (48876), (48877), (48878), (48879), (48880), (48881), (48882), (48883), (48884), (48885), (48886), (48887), (48888), +(48889), (48890), (48891), (48892), (48893), (48894), (48895), (48896), (48897), (48898), (48899), (48900), (48901), (48902), (48903), (48904), +(48905), (48906), (48907), (48908), (48909), (48910), (48911), (48912), (48913), (48914), (48915), (48916), (48917), (48918), (48919), (48922), +(48923), (48924), (48925), (48926), (48927), (48928), (48929), (48930), (48931), (49301), (49312), (49313), (49314), (49852), (49853), (49854), +(49855), (49334), (49703), (49704), (49706), (48945), (49050), (48527), (49662), (49663), (49665), (49693), (49343), (49640), (49917), (48601), +(49288), (49289), (48679), (49362), (49223), (49278), (49340), (49373), (49655), (49680), (49739), (49750), (49915), (49916), (49209), (49645), +(49689), (49708), (49733), (49873), (49984), (50442), (50204), (51682), (51683), (51684), (51685), (51686), (51687), (51688), (51689), (51690), +(51691), (51692), (51693), (51694), (51695), (51696), (51697), (51698), (51699), (51700), (51701), (51702), (51703), (51704), (51705), (51706), +(51707), (51708), (51709), (51710), (51711), (51712), (51713), (51714), (51715), (51716), (51717), (51718), (51719), (51720), (51721), (51722), +(51723), (51724), (51725), (51726), (51727), (51728), (51729), (51730), (51731), (51732), (51733), (51734), (51735), (51736), (51737), (51738), +(51739), (51740), (51741), (51742), (51743), (51744), (51745), (51746), (51747), (51748), (51749), (51750), (51751), (51752), (51753), (51754), +(51755), (51756), (51757), (51758), (51759), (51760), (51761), (51762), (51763), (51764), (51765), (51766), (51767), (51768), (51769), (51770), +(51771), (51772), (51773), (51774), (51775), (51776), (53491), (53492), (53493), (53494), (53495), (53496), (53497), (53498), (53499), (53500), +(53501), (53502), (53503), (53504), (53505), (53506), (53507), (53508), (53509), (54592), (50315), (50318), (50319), (52567), (50815), (53889), +(53890), (54069), (54860), (50840), (53891), (53924), (51997), (51998), (54847), (54857), (56806), (54212), (54452), (54810), (50093), (54822), +(50289), (50301), (50307), (52189), (52202), (52272), (52275), (52276), (52345), (52562), (52563), (52565), (52729), (53510), (54218), (54455), +(54467), (50248), (50431), (52011), (52062), (54291), (54470); diff --git a/modules/mod-ah-bot/src/AuctionHouseBot.cpp b/modules/mod-ah-bot/src/AuctionHouseBot.cpp new file mode 100644 index 0000000..9ceb204 --- /dev/null +++ b/modules/mod-ah-bot/src/AuctionHouseBot.cpp @@ -0,0 +1,1942 @@ +/* + * Copyright (C) 2008-2010 Trinity + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectMgr.h" +#include "AuctionHouseMgr.h" +#include "AuctionHouseBot.h" +#include "Config.h" +#include "Player.h" +#include "WorldSession.h" +#include "GameTime.h" +#include + +using namespace std; +vector npcItems; +vector lootItems; +vector greyTradeGoodsBin; +vector whiteTradeGoodsBin; +vector greenTradeGoodsBin; +vector blueTradeGoodsBin; +vector purpleTradeGoodsBin; +vector orangeTradeGoodsBin; +vector yellowTradeGoodsBin; +vector greyItemsBin; +vector whiteItemsBin; +vector greenItemsBin; +vector blueItemsBin; +vector purpleItemsBin; +vector orangeItemsBin; +vector yellowItemsBin; + +AuctionHouseBot::AuctionHouseBot() +{ + debug_Out = false; + debug_Out_Filters = false; + AHBSeller = false; + AHBBuyer = false; + + //Begin Filters + + Vendor_Items = false; + Loot_Items = false; + Other_Items = false; + Vendor_TGs = false; + Loot_TGs = false; + Other_TGs = false; + + No_Bind = false; + Bind_When_Picked_Up = false; + Bind_When_Equipped = false; + Bind_When_Use = false; + Bind_Quest_Item = false; + + DisablePermEnchant = false; + DisableConjured = false; + DisableGems = false; + DisableMoney = false; + DisableMoneyLoot = false; + DisableLootable = false; + DisableKeys = false; + DisableDuration = false; + DisableBOP_Or_Quest_NoReqLevel = false; + + DisableWarriorItems = false; + DisablePaladinItems = false; + DisableHunterItems = false; + DisableRogueItems = false; + DisablePriestItems = false; + DisableDKItems = false; + DisableShamanItems = false; + DisableMageItems = false; + DisableWarlockItems = false; + DisableUnusedClassItems = false; + DisableDruidItems = false; + + DisableItemsBelowLevel = 0; + DisableItemsAboveLevel = 0; + DisableTGsBelowLevel = 0; + DisableTGsAboveLevel = 0; + DisableItemsBelowGUID = 0; + DisableItemsAboveGUID = 0; + DisableTGsBelowGUID = 0; + DisableTGsAboveGUID = 0; + DisableItemsBelowReqLevel = 0; + DisableItemsAboveReqLevel = 0; + DisableTGsBelowReqLevel = 0; + DisableTGsAboveReqLevel = 0; + DisableItemsBelowReqSkillRank = 0; + DisableItemsAboveReqSkillRank = 0; + DisableTGsBelowReqSkillRank = 0; + DisableTGsAboveReqSkillRank = 0; + + //End Filters + + _lastrun_a = time(NULL); + _lastrun_h = time(NULL); + _lastrun_n = time(NULL); + + AllianceConfig = AHBConfig(2); + HordeConfig = AHBConfig(6); + NeutralConfig = AHBConfig(7); +} + +AuctionHouseBot::~AuctionHouseBot() +{ +} + +void AuctionHouseBot::addNewAuctions(Player *AHBplayer, AHBConfig *config) +{ + if (!AHBSeller) + { + if (debug_Out) + LOG_INFO("module", "AHSeller: Disabled"); + return; + } + + uint32 minItems = config->GetMinItems(); + uint32 maxItems = config->GetMaxItems(); + + if (maxItems == 0) + { + //if (debug_Out) sLog->outString( "AHSeller: Auctions disabled"); + return; + } + + AuctionHouseEntry const* ahEntry = sAuctionMgr->GetAuctionHouseEntry(config->GetAHFID()); + if (!ahEntry) + { + return; + } + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); + if (!auctionHouse) + { + return; + } + + uint32 auctions = auctionHouse->Getcount(); + + uint32 items = 0; + + if (auctions >= minItems) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: Auctions above minimum"); + return; + } + + if (auctions >= maxItems) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: Auctions at or above maximum"); + return; + } + + if ((maxItems - auctions) >= ItemsPerCycle) + items = ItemsPerCycle; + else + items = (maxItems - auctions); + + if (debug_Out) + LOG_INFO("module", "AHSeller: Adding {} Auctions", items); + + if (debug_Out) + LOG_ERROR("module", "AHSeller: Current house id is {}", config->GetAHID()); + + uint32 greyTGcount = config->GetPercents(AHB_GREY_TG); + uint32 whiteTGcount = config->GetPercents(AHB_WHITE_TG); + uint32 greenTGcount = config->GetPercents(AHB_GREEN_TG); + uint32 blueTGcount = config->GetPercents(AHB_BLUE_TG); + uint32 purpleTGcount = config->GetPercents(AHB_PURPLE_TG); + uint32 orangeTGcount = config->GetPercents(AHB_ORANGE_TG); + uint32 yellowTGcount = config->GetPercents(AHB_YELLOW_TG); + uint32 greyIcount = config->GetPercents(AHB_GREY_I); + uint32 whiteIcount = config->GetPercents(AHB_WHITE_I); + uint32 greenIcount = config->GetPercents(AHB_GREEN_I); + uint32 blueIcount = config->GetPercents(AHB_BLUE_I); + uint32 purpleIcount = config->GetPercents(AHB_PURPLE_I); + uint32 orangeIcount = config->GetPercents(AHB_ORANGE_I); + uint32 yellowIcount = config->GetPercents(AHB_YELLOW_I); +/* uint32 total = greyTGcount + whiteTGcount + greenTGcount + blueTGcount + + purpleTGcount + orangeTGcount + yellowTGcount + + whiteIcount + greenIcount + blueIcount + purpleIcount + + orangeIcount + yellowIcount; +*/ + uint32 greyTGoods = config->GetItemCounts(AHB_GREY_TG); + uint32 whiteTGoods = config->GetItemCounts(AHB_WHITE_TG); + uint32 greenTGoods = config->GetItemCounts(AHB_GREEN_TG); + uint32 blueTGoods = config->GetItemCounts(AHB_BLUE_TG); + uint32 purpleTGoods = config->GetItemCounts(AHB_PURPLE_TG); + uint32 orangeTGoods = config->GetItemCounts(AHB_ORANGE_TG); + uint32 yellowTGoods = config->GetItemCounts(AHB_YELLOW_TG); + + uint32 greyItems = config->GetItemCounts(AHB_GREY_I); + uint32 whiteItems = config->GetItemCounts(AHB_WHITE_I); + uint32 greenItems = config->GetItemCounts(AHB_GREEN_I); + uint32 blueItems = config->GetItemCounts(AHB_BLUE_I); + uint32 purpleItems = config->GetItemCounts(AHB_PURPLE_I); + uint32 orangeItems = config->GetItemCounts(AHB_ORANGE_I); + uint32 yellowItems = config->GetItemCounts(AHB_YELLOW_I); + + if (debug_Out) + LOG_ERROR("module", "AHSeller: {} items", items); + + // only insert a few at a time, so as not to peg the processor + for (uint32 cnt = 1; cnt <= items; cnt++) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: {} count", cnt); + + uint32 itemID = 0; + uint32 itemColor = 99; + uint32 loopbreaker = 0; + while (itemID == 0 && loopbreaker <= 50) + { + ++loopbreaker; + uint32 choice = urand(0, 13); + itemColor = choice; + switch (choice) + { + case 0: + { + if ((greyItemsBin.size() > 0) && (greyItems < greyIcount)) + itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)]; + else continue; + break; + } + case 1: + { + if ((whiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) + itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)]; + else continue; + break; + } + case 2: + { + if ((greenItemsBin.size() > 0) && (greenItems < greenIcount)) + itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)]; + else continue; + break; + } + case 3: + { + if ((blueItemsBin.size() > 0) && (blueItems < blueIcount)) + itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)]; + else continue; + break; + } + case 4: + { + if ((purpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) + itemID = purpleItemsBin[urand(0, purpleItemsBin.size() - 1)]; + else continue; + break; + } + case 5: + { + if ((orangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) + itemID = orangeItemsBin[urand(0, orangeItemsBin.size() - 1)]; + else continue; + break; + } + case 6: + { + if ((yellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) + itemID = yellowItemsBin[urand(0, yellowItemsBin.size() - 1)]; + else continue; + break; + } + case 7: + { + if ((greyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) + itemID = greyTradeGoodsBin[urand(0, greyTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 8: + { + if ((whiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) + itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 9: + { + if ((greenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) + itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 10: + { + if ((blueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) + itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 11: + { + if ((purpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) + itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 12: + { + if ((orangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) + itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 13: + { + if ((yellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) + itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)]; + else continue; + break; + } + default: + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: itemID Switch - Default Reached"); + break; + } + } + + if (itemID == 0) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: Item::CreateItem() - ItemID is 0"); + continue; + } + + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemID); + if (prototype == NULL) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: Huh?!?! prototype == NULL"); + continue; + } + + Item* item = Item::CreateItem(itemID, 1, AHBplayer); + if (item == NULL) + { + if (debug_Out) + LOG_ERROR("module", "AHSeller: Item::CreateItem() returned NULL"); + break; + } + item->AddToUpdateQueueOf(AHBplayer); + + uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); + if (randomPropertyId != 0) + item->SetItemRandomProperties(randomPropertyId); + + uint64 buyoutPrice = 0; + uint64 bidPrice = 0; + uint32 stackCount = 1; + + if (SellMethod) + buyoutPrice = prototype->BuyPrice; + else + buyoutPrice = prototype->SellPrice; + + if (prototype->Quality <= AHB_MAX_QUALITY) + { + if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(prototype->Quality))); + else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) + stackCount = urand(1, item->GetMaxStackCount()); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); + bidPrice /= 100; + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) + LOG_ERROR("module", "AHBuyer: Quality {} not Supported", prototype->Quality); + item->RemoveFromUpdateQueueOf(AHBplayer); + continue; + } + + uint32 etime = urand(1,3); + switch(etime) + { + case 1: + etime = 43200; + break; + case 2: + etime = 86400; + break; + case 3: + etime = 172800; + break; + default: + etime = 86400; + break; + } + item->SetCount(stackCount); + + uint32 dep = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount); + + auto trans = CharacterDatabase.BeginTransaction(); + AuctionEntry* auctionEntry = new AuctionEntry(); + auctionEntry->Id = sObjectMgr->GenerateAuctionID(); + auctionEntry->houseId = config->GetAHID(); + auctionEntry->item_guid = item->GetGUID(); + auctionEntry->item_template = item->GetEntry(); + auctionEntry->itemCount = item->GetCount(); + auctionEntry->owner = AHBplayer->GetGUID(); + auctionEntry->startbid = bidPrice * stackCount; + auctionEntry->buyout = buyoutPrice * stackCount; + auctionEntry->bid = 0; + auctionEntry->deposit = dep; + auctionEntry->expire_time = (time_t) etime + time(NULL); + auctionEntry->auctionHouseEntry = ahEntry; + item->SaveToDB(trans); + item->RemoveFromUpdateQueueOf(AHBplayer); + sAuctionMgr->AddAItem(item); + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(trans); + CharacterDatabase.CommitTransaction(trans); + + switch(itemColor) + { + case 0: + ++greyItems; + break; + case 1: + ++whiteItems; + break; + case 2: + ++greenItems; + break; + case 3: + ++blueItems; + break; + case 4: + ++purpleItems; + break; + case 5: + ++orangeItems; + break; + case 6: + ++yellowItems; + break; + case 7: + ++greyTGoods; + break; + case 8: + ++whiteTGoods; + break; + case 9: + ++greenTGoods; + break; + case 10: + ++blueTGoods; + break; + case 11: + ++purpleTGoods; + break; + case 12: + ++orangeTGoods; + break; + case 13: + ++yellowTGoods; + break; + default: + break; + } + } + } +} +void AuctionHouseBot::addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session) +{ + if (!AHBBuyer) + { + if (debug_Out) + LOG_ERROR("module", "AHBuyer: Disabled"); + return; + } + + QueryResult result = CharacterDatabase.Query("SELECT id FROM auctionhouse WHERE itemowner<>{} AND buyguid<>{}", AHBplayerGUID, AHBplayerGUID); + + if (!result) + return; + + if (result->GetRowCount() == 0) + return; + + // Fetches content of selected AH + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); + vector possibleBids; + + do + { + uint32 tmpdata = result->Fetch()->Get(); + possibleBids.push_back(tmpdata); + }while (result->NextRow()); + + for (uint32 count = 1; count <= config->GetBidsPerInterval(); ++count) + { + // Do we have anything to bid? If not, stop here. + if (possibleBids.empty()) + { + //if (debug_Out) sLog->outError( "AHBuyer: I have no items to bid on."); + count = config->GetBidsPerInterval(); + continue; + } + + // Choose random auction from possible auctions + uint32 vectorPos = urand(0, possibleBids.size() - 1); + vector::iterator iter = possibleBids.begin(); + advance(iter, vectorPos); + + // from auctionhousehandler.cpp, creates auction pointer & player pointer + AuctionEntry* auction = auctionHouse->GetAuction(*iter); + + // Erase the auction from the vector to prevent bidding on item in next iteration. + possibleBids.erase(iter); + + if (!auction) + continue; + + // get exact item information + Item *pItem = sAuctionMgr->GetAItem(auction->item_guid); + if (!pItem) + { + if (debug_Out) + LOG_ERROR("module", "AHBuyer: Item {} doesn't exist, perhaps bought already?", auction->item_guid.ToString()); + continue; + } + + // get item prototype + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(auction->item_template); + + // check which price we have to use, startbid or if it is bidded already + uint32 currentprice; + if (auction->bid) + currentprice = auction->bid; + else + currentprice = auction->startbid; + + // Prepare portion from maximum bid + double bidrate = static_cast(urand(1, 100)) / 100; + long double bidMax = 0; + + // check that bid has acceptable value and take bid based on vendorprice, stacksize and quality + if (BuyMethod) + { + if (prototype->Quality <= AHB_MAX_QUALITY) + { + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) + LOG_ERROR("module", "AHBuyer: Quality {} not Supported", prototype->Quality); + continue; + } + } + else + { + if (prototype->Quality <= AHB_MAX_QUALITY) + { + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) + LOG_ERROR("module", "AHBuyer: Quality {} not Supported", prototype->Quality); + continue; + } + } + + // check some special items, and do recalculating to their prices + switch (prototype->Class) + { + // ammo + case 6: + bidMax = 0; + break; + default: + break; + } + + if (bidMax == 0) + { + // quality check failed to get bidmax, let's get out of here + continue; + } + + // Calculate our bid + long double bidvalue = currentprice + ((bidMax - currentprice) * bidrate); + // Convert to uint32 + uint32 bidprice = static_cast(bidvalue); + + // Check our bid is high enough to be valid. If not, correct it to minimum. + if ((currentprice + auction->GetAuctionOutBid()) > bidprice) + bidprice = currentprice + auction->GetAuctionOutBid(); + + + if (debug_Out) + { + LOG_INFO("module", "-------------------------------------------------"); + LOG_INFO("module", "AHBuyer: Info for Auction #{}:", auction->Id); + LOG_INFO("module", "AHBuyer: AuctionHouse: {}", auction->GetHouseId()); + LOG_INFO("module", "AHBuyer: Owner: {}", auction->owner.ToString()); + LOG_INFO("module", "AHBuyer: Bidder: {}", auction->bidder.ToString()); + LOG_INFO("module", "AHBuyer: Starting Bid: {}", auction->startbid); + LOG_INFO("module", "AHBuyer: Current Bid: {}", currentprice); + LOG_INFO("module", "AHBuyer: Buyout: {}", auction->buyout); + LOG_INFO("module", "AHBuyer: Deposit: {}", auction->deposit); + LOG_INFO("module", "AHBuyer: Expire Time: {}", uint32(auction->expire_time)); + LOG_INFO("module", "AHBuyer: Bid Rate: {}", bidrate); + LOG_INFO("module", "AHBuyer: Bid Max: {}", bidMax); + LOG_INFO("module", "AHBuyer: Bid Value: {}", bidvalue); + LOG_INFO("module", "AHBuyer: Bid Price: {}", bidprice); + LOG_INFO("module", "AHBuyer: Item GUID: {}", auction->item_guid.ToString()); + LOG_INFO("module", "AHBuyer: Item Template: {}", auction->item_template); + LOG_INFO("module", "AHBuyer: Item Info:"); + LOG_INFO("module", "AHBuyer: Item ID: {}", prototype->ItemId); + LOG_INFO("module", "AHBuyer: Buy Price: {}", prototype->BuyPrice); + LOG_INFO("module", "AHBuyer: Sell Price: {}", prototype->SellPrice); + LOG_INFO("module", "AHBuyer: Bonding: {}", prototype->Bonding); + LOG_INFO("module", "AHBuyer: Quality: {}", prototype->Quality); + LOG_INFO("module", "AHBuyer: Item Level: {}", prototype->ItemLevel); + LOG_INFO("module", "AHBuyer: Ammo Type: {}", prototype->AmmoType); + LOG_INFO("module", "-------------------------------------------------"); + } + + // Check whether we do normal bid, or buyout + if ((bidprice < auction->buyout) || (auction->buyout == 0)) + { + if (auction->bidder) + { + if (auction->bidder == AHBplayer->GetGUID()) + { + //pl->ModifyMoney(-int32(price - auction->bid)); + } + else + { + // mail to last bidder and return money + auto trans = CharacterDatabase.BeginTransaction(); + sAuctionMgr->SendAuctionOutbiddedMail(auction, bidprice, session->GetPlayer(), trans); + CharacterDatabase.CommitTransaction(trans); + //pl->ModifyMoney(-int32(price)); + } + } + + auction->bidder = AHBplayer->GetGUID(); + auction->bid = bidprice; + + // Saving auction into database + CharacterDatabase.Execute("UPDATE auctionhouse SET buyguid = '{}',lastbid = '{}' WHERE id = '{}'", auction->bidder.GetCounter(), auction->bid, auction->Id); + } + else + { + auto trans = CharacterDatabase.BeginTransaction(); + //buyout + if ((auction->bidder) && (AHBplayer->GetGUID() != auction->bidder)) + { + sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, session->GetPlayer(), trans); + } + auction->bidder = AHBplayer->GetGUID(); + auction->bid = auction->buyout; + + // Send mails to buyer & seller + //sAuctionMgr->SendAuctionSalePendingMail(auction, trans); + sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); + sAuctionMgr->SendAuctionWonMail(auction, trans); + auction->DeleteFromDB(trans); + + sAuctionMgr->RemoveAItem(auction->item_guid); + auctionHouse->RemoveAuction(auction); + CharacterDatabase.CommitTransaction(trans); + } + } +} + +void AuctionHouseBot::Update() +{ + time_t _newrun = time(NULL); + if ((!AHBSeller) && (!AHBBuyer)) + return; + + std::string accountName = "AuctionHouseBot" + std::to_string(AHBplayerAccount); + + WorldSession _session(AHBplayerAccount, std::move(accountName), nullptr, SEC_PLAYER, sWorld->getIntConfig(CONFIG_EXPANSION), 0, LOCALE_enUS, 0, false, false, 0); + Player _AHBplayer(&_session); + _AHBplayer.Initialize(AHBplayerGUID); + ObjectAccessor::AddObject(&_AHBplayer); + + // Add New Bids + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + { + addNewAuctions(&_AHBplayer, &AllianceConfig); + if (((_newrun - _lastrun_a) >= (AllianceConfig.GetBiddingInterval() * MINUTE)) && (AllianceConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog->outError( "AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_a)); + //if (debug_Out) sLog->outError( "AHBuyer: Bidding on Alliance Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig, &_session); + _lastrun_a = _newrun; + } + + addNewAuctions(&_AHBplayer, &HordeConfig); + if (((_newrun - _lastrun_h) >= (HordeConfig.GetBiddingInterval() * MINUTE)) && (HordeConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog->outError( "AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_h)); + //if (debug_Out) sLog->outError( "AHBuyer: Bidding on Horde Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &HordeConfig, &_session); + _lastrun_h = _newrun; + } + } + + addNewAuctions(&_AHBplayer, &NeutralConfig); + if (((_newrun - _lastrun_n) >= (NeutralConfig.GetBiddingInterval() * MINUTE)) && (NeutralConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog->outError( "AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_n)); + //if (debug_Out) sLog->outError( "AHBuyer: Bidding on Neutral Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &NeutralConfig, &_session); + _lastrun_n = _newrun; + } + ObjectAccessor::RemoveObject(&_AHBplayer); +} + +void AuctionHouseBot::Initialize() +{ + DisableItemStore.clear(); + QueryResult result = WorldDatabase.Query("SELECT item FROM mod_auctionhousebot_disabled_items"); + + if (result) + { + do + { + Field* fields = result->Fetch(); + DisableItemStore.insert(fields[0].Get()); + } while (result->NextRow()); + } + + //End Filters + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + { + LoadValues(&AllianceConfig); + LoadValues(&HordeConfig); + } + LoadValues(&NeutralConfig); + + // + // check if the AHBot account/GUID in the config actually exists + // + + if ((AHBplayerAccount != 0) || (AHBplayerGUID != 0)) + { + QueryResult result = CharacterDatabase.Query("SELECT 1 FROM characters WHERE account = {} AND guid = {}", AHBplayerAccount, AHBplayerGUID); + if (!result) + { + LOG_ERROR("module", "AuctionHouseBot: The account/GUID-information set for your AHBot is incorrect (account: {} guid: {})", AHBplayerAccount, AHBplayerGUID); + return; + } + } + + if (AHBSeller) + { + QueryResult results = QueryResult(NULL); + char npcQuery[] = "SELECT distinct item FROM npc_vendor"; + results = WorldDatabase.Query(npcQuery); + if (results) + { + do + { + Field* fields = results->Fetch(); + npcItems.push_back(fields[0].Get()); + + } while (results->NextRow()); + } + else + { + if (debug_Out) + LOG_ERROR("module", "AuctionHouseBot: \"{}\" failed", npcQuery); + } + + char lootQuery[] = "SELECT item FROM creature_loot_template UNION " + "SELECT item FROM reference_loot_template UNION " + "SELECT item FROM disenchant_loot_template UNION " + "SELECT item FROM fishing_loot_template UNION " + "SELECT item FROM gameobject_loot_template UNION " + "SELECT item FROM item_loot_template UNION " + "SELECT item FROM milling_loot_template UNION " + "SELECT item FROM pickpocketing_loot_template UNION " + "SELECT item FROM prospecting_loot_template UNION " + "SELECT item FROM skinning_loot_template"; + + results = WorldDatabase.Query(lootQuery); + if (results) + { + do + { + Field* fields = results->Fetch(); + lootItems.push_back(fields[0].Get()); + + } while (results->NextRow()); + } + else + { + if (debug_Out) + LOG_ERROR("module", "AuctionHouseBot: \"{}\" failed", lootQuery); + } + + ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); + for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) + { + switch (itr->second.Bonding) + { + case NO_BIND: + if (!No_Bind) + continue; + break; + case BIND_WHEN_PICKED_UP: + if (!Bind_When_Picked_Up) + continue; + break; + case BIND_WHEN_EQUIPED: + if (!Bind_When_Equipped) + continue; + break; + case BIND_WHEN_USE: + if (!Bind_When_Use) + continue; + break; + case BIND_QUEST_ITEM: + if (!Bind_Quest_Item) + continue; + break; + default: + continue; + break; + } + + if (SellMethod) + { + if (itr->second.BuyPrice == 0) + continue; + } + else + { + if (itr->second.SellPrice == 0) + continue; + } + + if (itr->second.Quality > 6) + continue; + + if ((Vendor_Items == 0) && !(itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorItem = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) + { + if (itr->second.ItemId == npcItems[i]) + isVendorItem = true; + } + + if (isVendorItem) + continue; + } + + if ((Vendor_TGs == 0) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorTG = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) + { + if (itr->second.ItemId == npcItems[i]) + isVendorTG = true; + } + + if (isVendorTG) + continue; + } + + if ((Loot_Items == 0) && !(itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isLootItem = false; + + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) + { + if (itr->second.ItemId == lootItems[i]) + isLootItem = true; + } + + if (isLootItem) + continue; + } + + if ((Loot_TGs == 0) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isLootTG = false; + + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) + { + if (itr->second.ItemId == lootItems[i]) + isLootTG = true; + } + + if (isLootTG) + continue; + } + + if ((Other_Items == 0) && !(itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorItem = false; + bool isLootItem = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) + { + if (itr->second.ItemId == npcItems[i]) + isVendorItem = true; + } + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) + { + if (itr->second.ItemId == lootItems[i]) + isLootItem = true; + } + if ((!isLootItem) && (!isVendorItem)) + continue; + } + + if ((Other_TGs == 0) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorTG = false; + bool isLootTG = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) + { + if (itr->second.ItemId == npcItems[i]) + isVendorTG = true; + } + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) + { + if (itr->second.ItemId == lootItems[i]) + isLootTG = true; + } + if ((!isLootTG) && (!isVendorTG)) + continue; + } + + // Disable items by Id + if (DisableItemStore.find(itr->second.ItemId) != DisableItemStore.end()) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (PTR/Beta/Unused Item)", itr->second.ItemId); + continue; + } + + // Disable permanent enchants items + if ((DisablePermEnchant) && (itr->second.Class == ITEM_CLASS_PERMANENT)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Permanent Enchant Item)", itr->second.ItemId); + continue; + } + + // Disable conjured items + if ((DisableConjured) && (itr->second.IsConjuredConsumable())) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Conjured Consumable)", itr->second.ItemId); + continue; + } + + // Disable gems + if ((DisableGems) && (itr->second.Class == ITEM_CLASS_GEM)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Gem)", itr->second.ItemId); + continue; + } + + // Disable money + if ((DisableMoney) && (itr->second.Class == ITEM_CLASS_MONEY)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Money)", itr->second.ItemId); + continue; + } + + // Disable moneyloot + if ((DisableMoneyLoot) && (itr->second.MinMoneyLoot > 0)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (MoneyLoot)", itr->second.ItemId); + continue; + } + + // Disable lootable items + if ((DisableLootable) && (itr->second.Flags & 4)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Lootable Item)", itr->second.ItemId); + continue; + } + + // Disable Keys + if ((DisableKeys) && (itr->second.Class == ITEM_CLASS_KEY)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Quest Item)", itr->second.ItemId); + continue; + } + + // Disable items with duration + if ((DisableDuration) && (itr->second.Duration > 0)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Has a Duration)", itr->second.ItemId); + continue; + } + + // Disable items which are BOP or Quest Items and have a required level lower than the item level + if ((DisableBOP_Or_Quest_NoReqLevel) && ((itr->second.Bonding == BIND_WHEN_PICKED_UP || itr->second.Bonding == BIND_QUEST_ITEM) && (itr->second.RequiredLevel < itr->second.ItemLevel))) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (BOP or BQI and Required Level is less than Item Level)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Warrior + if ((DisableWarriorItems) && (itr->second.AllowableClass == 1)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Warrior Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Paladin + if ((DisablePaladinItems) && (itr->second.AllowableClass == 2)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Paladin Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Hunter + if ((DisableHunterItems) && (itr->second.AllowableClass == 4)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Hunter Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Rogue + if ((DisableRogueItems) && (itr->second.AllowableClass == 8)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Rogue Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Priest + if ((DisablePriestItems) && (itr->second.AllowableClass == 16)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Priest Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for DK + if ((DisableDKItems) && (itr->second.AllowableClass == 32)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (DK Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Shaman + if ((DisableShamanItems) && (itr->second.AllowableClass == 64)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Shaman Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Mage + if ((DisableMageItems) && (itr->second.AllowableClass == 128)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Mage Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Warlock + if ((DisableWarlockItems) && (itr->second.AllowableClass == 256)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Warlock Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Unused Class + if ((DisableUnusedClassItems) && (itr->second.AllowableClass == 512)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Unused Item)", itr->second.ItemId); + continue; + } + + // Disable items specifically for Druid + if ((DisableDruidItems) && (itr->second.AllowableClass == 1024)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Druid Item)", itr->second.ItemId); + continue; + } + + // Disable Items below level X + if ((DisableItemsBelowLevel) && (itr->second.Class != ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemLevel < DisableItemsBelowLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Item Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Items above level X + if ((DisableItemsAboveLevel) && (itr->second.Class != ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemLevel > DisableItemsAboveLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Item Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Trade Goods below level X + if ((DisableTGsBelowLevel) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemLevel < DisableTGsBelowLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Trade Good {} disabled (Trade Good Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Trade Goods above level X + if ((DisableTGsAboveLevel) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemLevel > DisableTGsAboveLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Trade Good {} disabled (Trade Good Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Items below GUID X + if ((DisableItemsBelowGUID) && (itr->second.Class != ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemId < DisableItemsBelowGUID)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Item Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Items above GUID X + if ((DisableItemsAboveGUID) && (itr->second.Class != ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemId > DisableItemsAboveGUID)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Item Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Trade Goods below GUID X + if ((DisableTGsBelowGUID) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemId < DisableTGsBelowGUID)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Trade Good Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Trade Goods above GUID X + if ((DisableTGsAboveGUID) && (itr->second.Class == ITEM_CLASS_TRADE_GOODS) && (itr->second.ItemId > DisableTGsAboveGUID)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (Trade Good Level = {})", itr->second.ItemId, itr->second.ItemLevel); + continue; + } + + // Disable Items for level lower than X + if ((DisableItemsBelowReqLevel) && (itr->second.RequiredLevel < DisableItemsBelowReqLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredLevel = {})", itr->second.ItemId, itr->second.RequiredLevel); + continue; + } + + // Disable Items for level higher than X + if ((DisableItemsAboveReqLevel) && (itr->second.RequiredLevel > DisableItemsAboveReqLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredLevel = {})", itr->second.ItemId, itr->second.RequiredLevel); + continue; + } + + // Disable Trade Goods for level lower than X + if ((DisableTGsBelowReqLevel) && (itr->second.RequiredLevel < DisableTGsBelowReqLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Trade Good {} disabled (RequiredLevel = {})", itr->second.ItemId, itr->second.RequiredLevel); + continue; + } + + // Disable Trade Goods for level higher than X + if ((DisableTGsAboveReqLevel) && (itr->second.RequiredLevel > DisableTGsAboveReqLevel)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Trade Good {} disabled (RequiredLevel = {})", itr->second.ItemId, itr->second.RequiredLevel); + continue; + } + + // Disable Items that require skill lower than X + if ((DisableItemsBelowReqSkillRank) && (itr->second.RequiredSkillRank < DisableItemsBelowReqSkillRank)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredSkillRank = {})", itr->second.ItemId, itr->second.RequiredSkillRank); + continue; + } + + // Disable Items that require skill higher than X + if ((DisableItemsAboveReqSkillRank) && (itr->second.RequiredSkillRank > DisableItemsAboveReqSkillRank)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredSkillRank = {})", itr->second.ItemId, itr->second.RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill lower than X + if ((DisableTGsBelowReqSkillRank) && (itr->second.RequiredSkillRank < DisableTGsBelowReqSkillRank)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredSkillRank = {})", itr->second.ItemId, itr->second.RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill higher than X + if ((DisableTGsAboveReqSkillRank) && (itr->second.RequiredSkillRank > DisableTGsAboveReqSkillRank)) + { + if (debug_Out_Filters) + LOG_ERROR("module", "AuctionHouseBot: Item {} disabled (RequiredSkillRank = {})", itr->second.ItemId, itr->second.RequiredSkillRank); + continue; + } + + switch (itr->second.Quality) + { + case AHB_GREY: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + greyTradeGoodsBin.push_back(itr->second.ItemId); + else + greyItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_WHITE: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + whiteTradeGoodsBin.push_back(itr->second.ItemId); + else + whiteItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_GREEN: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + greenTradeGoodsBin.push_back(itr->second.ItemId); + else + greenItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_BLUE: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + blueTradeGoodsBin.push_back(itr->second.ItemId); + else + blueItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_PURPLE: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + purpleTradeGoodsBin.push_back(itr->second.ItemId); + else + purpleItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_ORANGE: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + orangeTradeGoodsBin.push_back(itr->second.ItemId); + else + orangeItemsBin.push_back(itr->second.ItemId); + break; + + case AHB_YELLOW: + if (itr->second.Class == ITEM_CLASS_TRADE_GOODS) + yellowTradeGoodsBin.push_back(itr->second.ItemId); + else + yellowItemsBin.push_back(itr->second.ItemId); + break; + } + } + + if ((greyTradeGoodsBin.size() == 0) && + (whiteTradeGoodsBin.size() == 0) && + (greenTradeGoodsBin.size() == 0) && + (blueTradeGoodsBin.size() == 0) && + (purpleTradeGoodsBin.size() == 0) && + (orangeTradeGoodsBin.size() == 0) && + (yellowTradeGoodsBin.size() == 0) && + (greyItemsBin.size() == 0) && + (whiteItemsBin.size() == 0) && + (greenItemsBin.size() == 0) && + (blueItemsBin.size() == 0) && + (purpleItemsBin.size() == 0) && + (orangeItemsBin.size() == 0) && + (yellowItemsBin.size() == 0)) + { + LOG_ERROR("module", "AuctionHouseBot: No items"); + AHBSeller = 0; + } + + LOG_INFO("module", "AuctionHouseBot:"); + LOG_INFO("module", "{} disabled items", uint32(DisableItemStore.size())); + LOG_INFO("module", "loaded {} grey trade goods", uint32(greyTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} white trade goods", uint32(whiteTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} green trade goods", uint32(greenTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} blue trade goods", uint32(blueTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} purple trade goods", uint32(purpleTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} orange trade goods", uint32(orangeTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} yellow trade goods", uint32(yellowTradeGoodsBin.size())); + LOG_INFO("module", "loaded {} grey items", uint32(greyItemsBin.size())); + LOG_INFO("module", "loaded {} white items", uint32(whiteItemsBin.size())); + LOG_INFO("module", "loaded {} green items", uint32(greenItemsBin.size())); + LOG_INFO("module", "loaded {} blue items", uint32(blueItemsBin.size())); + LOG_INFO("module", "loaded {} purple items", uint32(purpleItemsBin.size())); + LOG_INFO("module", "loaded {} orange items", uint32(orangeItemsBin.size())); + LOG_INFO("module", "loaded {} yellow items", uint32(yellowItemsBin.size())); + } + + LOG_INFO("module", "AuctionHouseBot and AuctionHouseBuyer have been loaded."); +} + +void AuctionHouseBot::InitializeConfiguration() +{ + debug_Out = sConfigMgr->GetOption("AuctionHouseBot.DEBUG", false); + debug_Out_Filters = sConfigMgr->GetOption("AuctionHouseBot.DEBUG_FILTERS", false); + + AHBSeller = sConfigMgr->GetOption("AuctionHouseBot.EnableSeller", false); + AHBBuyer = sConfigMgr->GetOption("AuctionHouseBot.EnableBuyer", false); + SellMethod = sConfigMgr->GetOption("AuctionHouseBot.UseBuyPriceForSeller", false); + BuyMethod = sConfigMgr->GetOption("AuctionHouseBot.UseBuyPriceForBuyer", false); + + AHBplayerAccount = sConfigMgr->GetOption("AuctionHouseBot.Account", 0); + AHBplayerGUID = sConfigMgr->GetOption("AuctionHouseBot.GUID", 0); + ItemsPerCycle = sConfigMgr->GetOption("AuctionHouseBot.ItemsPerCycle", 200); + + //Begin Filters + + Vendor_Items = sConfigMgr->GetOption("AuctionHouseBot.VendorItems", false); + Loot_Items = sConfigMgr->GetOption("AuctionHouseBot.LootItems", true); + Other_Items = sConfigMgr->GetOption("AuctionHouseBot.OtherItems", false); + Vendor_TGs = sConfigMgr->GetOption("AuctionHouseBot.VendorTradeGoods", false); + Loot_TGs = sConfigMgr->GetOption("AuctionHouseBot.LootTradeGoods", true); + Other_TGs = sConfigMgr->GetOption("AuctionHouseBot.OtherTradeGoods", false); + + No_Bind = sConfigMgr->GetOption("AuctionHouseBot.No_Bind", true); + Bind_When_Picked_Up = sConfigMgr->GetOption("AuctionHouseBot.Bind_When_Picked_Up", false); + Bind_When_Equipped = sConfigMgr->GetOption("AuctionHouseBot.Bind_When_Equipped", true); + Bind_When_Use = sConfigMgr->GetOption("AuctionHouseBot.Bind_When_Use", true); + Bind_Quest_Item = sConfigMgr->GetOption("AuctionHouseBot.Bind_Quest_Item", false); + + DisablePermEnchant = sConfigMgr->GetOption("AuctionHouseBot.DisablePermEnchant", false); + DisableConjured = sConfigMgr->GetOption("AuctionHouseBot.DisableConjured", false); + DisableGems = sConfigMgr->GetOption("AuctionHouseBot.DisableGems", false); + DisableMoney = sConfigMgr->GetOption("AuctionHouseBot.DisableMoney", false); + DisableMoneyLoot = sConfigMgr->GetOption("AuctionHouseBot.DisableMoneyLoot", false); + DisableLootable = sConfigMgr->GetOption("AuctionHouseBot.DisableLootable", false); + DisableKeys = sConfigMgr->GetOption("AuctionHouseBot.DisableKeys", false); + DisableDuration = sConfigMgr->GetOption("AuctionHouseBot.DisableDuration", false); + DisableBOP_Or_Quest_NoReqLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel", false); + + DisableWarriorItems = sConfigMgr->GetOption("AuctionHouseBot.DisableWarriorItems", false); + DisablePaladinItems = sConfigMgr->GetOption("AuctionHouseBot.DisablePaladinItems", false); + DisableHunterItems = sConfigMgr->GetOption("AuctionHouseBot.DisableHunterItems", false); + DisableRogueItems = sConfigMgr->GetOption("AuctionHouseBot.DisableRogueItems", false); + DisablePriestItems = sConfigMgr->GetOption("AuctionHouseBot.DisablePriestItems", false); + DisableDKItems = sConfigMgr->GetOption("AuctionHouseBot.DisableDKItems", false); + DisableShamanItems = sConfigMgr->GetOption("AuctionHouseBot.DisableShamanItems", false); + DisableMageItems = sConfigMgr->GetOption("AuctionHouseBot.DisableMageItems", false); + DisableWarlockItems = sConfigMgr->GetOption("AuctionHouseBot.DisableWarlockItems", false); + DisableUnusedClassItems = sConfigMgr->GetOption("AuctionHouseBot.DisableUnusedClassItems", false); + DisableDruidItems = sConfigMgr->GetOption("AuctionHouseBot.DisableDruidItems", false); + + DisableItemsBelowLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsBelowLevel", 0); + DisableItemsAboveLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsAboveLevel", 0); + DisableTGsBelowLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsBelowLevel", 0); + DisableTGsAboveLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsAboveLevel", 0); + DisableItemsBelowGUID = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsBelowGUID", 0); + DisableItemsAboveGUID = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsAboveGUID", 0); + DisableTGsBelowGUID = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsBelowGUID", 0); + DisableTGsAboveGUID = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsAboveGUID", 0); + DisableItemsBelowReqLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsBelowReqLevel", 0); + DisableItemsAboveReqLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsAboveReqLevel", 0); + DisableTGsBelowReqLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsBelowReqLevel", 0); + DisableTGsAboveReqLevel = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsAboveReqLevel", 0); + DisableItemsBelowReqSkillRank = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsBelowReqSkillRank", 0); + DisableItemsAboveReqSkillRank = sConfigMgr->GetOption("AuctionHouseBot.DisableItemsAboveReqSkillRank", 0); + DisableTGsBelowReqSkillRank = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsBelowReqSkillRank", 0); + DisableTGsAboveReqSkillRank = sConfigMgr->GetOption("AuctionHouseBot.DisableTGsAboveReqSkillRank", 0); +} + +void AuctionHouseBot::IncrementItemCounts(AuctionEntry* ah) +{ + // from auctionhousehandler.cpp, creates auction pointer & player pointer + + // get exact item information + Item *pItem = sAuctionMgr->GetAItem(ah->item_guid); + if (!pItem) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: Item {} doesn't exist, perhaps bought already?", ah->item_guid.ToString()); + return; + } + + // get item prototype + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(ah->item_template); + + AHBConfig *config; + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(ah->GetHouseId()); + if (!ahEntry) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Neutral", ah->GetHouseId()); + config = &NeutralConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_ALLIANCE) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Alliance", ah->GetHouseId()); + config = &AllianceConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_HORDE) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Horde", ah->GetHouseId()); + config = &HordeConfig; + } + else + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Neutral", ah->GetHouseId()); + config = &NeutralConfig; + } + + config->IncItemCounts(prototype->Class, prototype->Quality); +} + +void AuctionHouseBot::DecrementItemCounts(AuctionEntry* ah, uint32 itemEntry) +{ + // get item prototype + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemEntry); + + AHBConfig *config; + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(ah->GetHouseId()); + if (!ahEntry) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Neutral", ah->GetHouseId()); + config = &NeutralConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_ALLIANCE) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Alliance", ah->GetHouseId()); + config = &AllianceConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_HORDE) + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Horde", ah->GetHouseId()); + config = &HordeConfig; + } + else + { + if (debug_Out) + LOG_ERROR("module", "AHBot: {} returned as House Faction. Neutral", ah->GetHouseId()); + config = &NeutralConfig; + } + + config->DecItemCounts(prototype->Class, prototype->Quality); +} + +void AuctionHouseBot::Commands(uint32 command, uint32 ahMapID, uint32 col, char* args) +{ + AHBConfig *config = NULL; + switch (ahMapID) + { + case 2: + config = &AllianceConfig; + break; + case 6: + config = &HordeConfig; + break; + case 7: + config = &NeutralConfig; + break; + } + std::string color; + switch (col) + { + case AHB_GREY: + color = "grey"; + break; + case AHB_WHITE: + color = "white"; + break; + case AHB_GREEN: + color = "green"; + break; + case AHB_BLUE: + color = "blue"; + break; + case AHB_PURPLE: + color = "purple"; + break; + case AHB_ORANGE: + color = "orange"; + break; + case AHB_YELLOW: + color = "yellow"; + break; + default: + break; + } + switch (command) + { + case 0: //ahexpire + { + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); + + AuctionHouseObject::AuctionEntryMap::iterator itr; + itr = auctionHouse->GetAuctionsBegin(); + + while (itr != auctionHouse->GetAuctionsEnd()) + { + if (itr->second->owner.GetCounter() == AHBplayerGUID) + { + itr->second->expire_time = GameTime::GetGameTime().count(); + uint32 id = itr->second->Id; + uint32 expire_time = itr->second->expire_time; + CharacterDatabase.Execute("UPDATE auctionhouse SET time = '{}' WHERE id = '{}'", expire_time, id); + } + ++itr; + } + } + break; + case 1: //min items + { + char * param1 = strtok(args, " "); + uint32 minItems = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET minitems = '{}' WHERE auctionhouse = '{}'", minItems, ahMapID); + config->SetMinItems(minItems); + } + break; + case 2: //max items + { + char * param1 = strtok(args, " "); + uint32 maxItems = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET maxitems = '{}' WHERE auctionhouse = '{}'", maxItems, ahMapID); + config->SetMaxItems(maxItems); + config->CalculatePercents(); + } + break; + case 3: //min time Deprecated (Place holder for future commands) + break; + case 4: //max time Deprecated (Place holder for future commands) + break; + case 5: //percentages + { + char * param1 = strtok(args, " "); + char * param2 = strtok(NULL, " "); + char * param3 = strtok(NULL, " "); + char * param4 = strtok(NULL, " "); + char * param5 = strtok(NULL, " "); + char * param6 = strtok(NULL, " "); + char * param7 = strtok(NULL, " "); + char * param8 = strtok(NULL, " "); + char * param9 = strtok(NULL, " "); + char * param10 = strtok(NULL, " "); + char * param11 = strtok(NULL, " "); + char * param12 = strtok(NULL, " "); + char * param13 = strtok(NULL, " "); + char * param14 = strtok(NULL, " "); + uint32 greytg = (uint32) strtoul(param1, NULL, 0); + uint32 whitetg = (uint32) strtoul(param2, NULL, 0); + uint32 greentg = (uint32) strtoul(param3, NULL, 0); + uint32 bluetg = (uint32) strtoul(param4, NULL, 0); + uint32 purpletg = (uint32) strtoul(param5, NULL, 0); + uint32 orangetg = (uint32) strtoul(param6, NULL, 0); + uint32 yellowtg = (uint32) strtoul(param7, NULL, 0); + uint32 greyi = (uint32) strtoul(param8, NULL, 0); + uint32 whitei = (uint32) strtoul(param9, NULL, 0); + uint32 greeni = (uint32) strtoul(param10, NULL, 0); + uint32 bluei = (uint32) strtoul(param11, NULL, 0); + uint32 purplei = (uint32) strtoul(param12, NULL, 0); + uint32 orangei = (uint32) strtoul(param13, NULL, 0); + uint32 yellowi = (uint32) strtoul(param14, NULL, 0); + + auto trans = WorldDatabase.BeginTransaction(); + trans->Append("UPDATE mod_auctionhousebot SET percentgreytradegoods = '{}' WHERE auctionhouse = '{}'", greytg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentwhitetradegoods = '{}' WHERE auctionhouse = '{}'", whitetg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreentradegoods = '{}' WHERE auctionhouse = '{}'", greentg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentbluetradegoods = '{}' WHERE auctionhouse = '{}'", bluetg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentpurpletradegoods = '{}' WHERE auctionhouse = '{}'", purpletg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentorangetradegoods = '{}' WHERE auctionhouse = '{}'", orangetg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentyellowtradegoods = '{}' WHERE auctionhouse = '{}'", yellowtg, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreyitems = '{}' WHERE auctionhouse = '{}'", greyi, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentwhiteitems = '{}' WHERE auctionhouse = '{}'", whitei, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreenitems = '{}' WHERE auctionhouse = '{}'", greeni, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentblueitems = '{}' WHERE auctionhouse = '{}'", bluei, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentpurpleitems = '{}' WHERE auctionhouse = '{}'", purplei, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentorangeitems = '{}' WHERE auctionhouse = '{}'", orangei, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentyellowitems = '{}' WHERE auctionhouse = '{}'", yellowi, ahMapID); + WorldDatabase.CommitTransaction(trans); + config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); + } + break; + case 6: //min prices + { + char * param1 = strtok(args, " "); + uint32 minPrice = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET minprice{} = '{}' WHERE auctionhouse = '{}'", color, minPrice, ahMapID); + config->SetMinPrice(col, minPrice); + } + break; + case 7: //max prices + { + char * param1 = strtok(args, " "); + uint32 maxPrice = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET maxprice{} = '{}' WHERE auctionhouse = '{}'", color, maxPrice, ahMapID); + config->SetMaxPrice(col, maxPrice); + } + break; + case 8: //min bid price + { + char * param1 = strtok(args, " "); + uint32 minBidPrice = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET minbidprice{} = '{}' WHERE auctionhouse = '{}'", color, minBidPrice, ahMapID); + config->SetMinBidPrice(col, minBidPrice); + } + break; + case 9: //max bid price + { + char * param1 = strtok(args, " "); + uint32 maxBidPrice = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET maxbidprice{} = '{}' WHERE auctionhouse = '{}'", color, maxBidPrice, ahMapID); + config->SetMaxBidPrice(col, maxBidPrice); + } + break; + case 10: //max stacks + { + char * param1 = strtok(args, " "); + uint32 maxStack = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET maxstack{} = '{}' WHERE auctionhouse = '{}'", color, maxStack, ahMapID); + config->SetMaxStack(col, maxStack); + } + break; + case 11: //buyer bid prices + { + char * param1 = strtok(args, " "); + uint32 buyerPrice = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET buyerprice{} = '{}' WHERE auctionhouse = '{}'", color, buyerPrice, ahMapID); + config->SetBuyerPrice(col, buyerPrice); + } + break; + case 12: //buyer bidding interval + { + char * param1 = strtok(args, " "); + uint32 bidInterval = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET buyerbiddinginterval = '{}' WHERE auctionhouse = '{}'", bidInterval, ahMapID); + config->SetBiddingInterval(bidInterval); + } + break; + case 13: //buyer bids per interval + { + char * param1 = strtok(args, " "); + uint32 bidsPerInterval = (uint32) strtoul(param1, NULL, 0); + WorldDatabase.Execute("UPDATE mod_auctionhousebot SET buyerbidsperinterval = '{}' WHERE auctionhouse = '{}'", bidsPerInterval, ahMapID); + config->SetBidsPerInterval(bidsPerInterval); + } + break; + default: + break; + } +} + +void AuctionHouseBot::LoadValues(AHBConfig *config) +{ + if (debug_Out) + LOG_ERROR("module", "Start Settings for {} Auctionhouses:", WorldDatabase.Query("SELECT name FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + + if (AHBSeller) + { + //load min and max items + config->SetMinItems(WorldDatabase.Query("SELECT minitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxItems(WorldDatabase.Query("SELECT maxitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + //load percentages + uint32 greytg = WorldDatabase.Query("SELECT percentgreytradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 whitetg = WorldDatabase.Query("SELECT percentwhitetradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 greentg = WorldDatabase.Query("SELECT percentgreentradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 bluetg = WorldDatabase.Query("SELECT percentbluetradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 purpletg = WorldDatabase.Query("SELECT percentpurpletradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 orangetg = WorldDatabase.Query("SELECT percentorangetradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 yellowtg = WorldDatabase.Query("SELECT percentyellowtradegoods FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 greyi = WorldDatabase.Query("SELECT percentgreyitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 whitei = WorldDatabase.Query("SELECT percentwhiteitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 greeni = WorldDatabase.Query("SELECT percentgreenitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 bluei = WorldDatabase.Query("SELECT percentblueitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 purplei = WorldDatabase.Query("SELECT percentpurpleitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 orangei = WorldDatabase.Query("SELECT percentorangeitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + uint32 yellowi = WorldDatabase.Query("SELECT percentyellowitems FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get(); + config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); + //load min and max prices + config->SetMinPrice(AHB_GREY, WorldDatabase.Query("SELECT minpricegrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_GREY, WorldDatabase.Query("SELECT maxpricegrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_WHITE, WorldDatabase.Query("SELECT minpricewhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_WHITE, WorldDatabase.Query("SELECT maxpricewhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_GREEN, WorldDatabase.Query("SELECT minpricegreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_GREEN, WorldDatabase.Query("SELECT maxpricegreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_BLUE, WorldDatabase.Query("SELECT minpriceblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_BLUE, WorldDatabase.Query("SELECT maxpriceblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_PURPLE, WorldDatabase.Query("SELECT minpricepurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_PURPLE, WorldDatabase.Query("SELECT maxpricepurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_ORANGE, WorldDatabase.Query("SELECT minpriceorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_ORANGE, WorldDatabase.Query("SELECT maxpriceorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinPrice(AHB_YELLOW, WorldDatabase.Query("SELECT minpriceyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxPrice(AHB_YELLOW, WorldDatabase.Query("SELECT maxpriceyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + //load min and max bid prices + config->SetMinBidPrice(AHB_GREY, WorldDatabase.Query("SELECT minbidpricegrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_GREY, WorldDatabase.Query("SELECT maxbidpricegrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_WHITE, WorldDatabase.Query("SELECT minbidpricewhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_WHITE, WorldDatabase.Query("SELECT maxbidpricewhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_GREEN, WorldDatabase.Query("SELECT minbidpricegreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_GREEN, WorldDatabase.Query("SELECT maxbidpricegreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_BLUE, WorldDatabase.Query("SELECT minbidpriceblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_BLUE, WorldDatabase.Query("SELECT maxbidpriceblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_PURPLE, WorldDatabase.Query("SELECT minbidpricepurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_PURPLE, WorldDatabase.Query("SELECT maxbidpricepurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_ORANGE, WorldDatabase.Query("SELECT minbidpriceorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_ORANGE, WorldDatabase.Query("SELECT maxbidpriceorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMinBidPrice(AHB_YELLOW, WorldDatabase.Query("SELECT minbidpriceyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxBidPrice(AHB_YELLOW, WorldDatabase.Query("SELECT maxbidpriceyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + //load max stacks + config->SetMaxStack(AHB_GREY, WorldDatabase.Query("SELECT maxstackgrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_WHITE, WorldDatabase.Query("SELECT maxstackwhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_GREEN, WorldDatabase.Query("SELECT maxstackgreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_BLUE, WorldDatabase.Query("SELECT maxstackblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_PURPLE, WorldDatabase.Query("SELECT maxstackpurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_ORANGE, WorldDatabase.Query("SELECT maxstackorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetMaxStack(AHB_YELLOW, WorldDatabase.Query("SELECT maxstackyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + if (debug_Out) + { + LOG_ERROR("module", "minItems = {}", config->GetMinItems()); + LOG_ERROR("module", "maxItems = {}", config->GetMaxItems()); + LOG_ERROR("module", "percentGreyTradeGoods = {}", config->GetPercentages(AHB_GREY_TG)); + LOG_ERROR("module", "percentWhiteTradeGoods = {}", config->GetPercentages(AHB_WHITE_TG)); + LOG_ERROR("module", "percentGreenTradeGoods = {}", config->GetPercentages(AHB_GREEN_TG)); + LOG_ERROR("module", "percentBlueTradeGoods = {}", config->GetPercentages(AHB_BLUE_TG)); + LOG_ERROR("module", "percentPurpleTradeGoods = {}", config->GetPercentages(AHB_PURPLE_TG)); + LOG_ERROR("module", "percentOrangeTradeGoods = {}", config->GetPercentages(AHB_ORANGE_TG)); + LOG_ERROR("module", "percentYellowTradeGoods = {}", config->GetPercentages(AHB_YELLOW_TG)); + LOG_ERROR("module", "percentGreyItems = {}", config->GetPercentages(AHB_GREY_I)); + LOG_ERROR("module", "percentWhiteItems = {}", config->GetPercentages(AHB_WHITE_I)); + LOG_ERROR("module", "percentGreenItems = {}", config->GetPercentages(AHB_GREEN_I)); + LOG_ERROR("module", "percentBlueItems = {}", config->GetPercentages(AHB_BLUE_I)); + LOG_ERROR("module", "percentPurpleItems = {}", config->GetPercentages(AHB_PURPLE_I)); + LOG_ERROR("module", "percentOrangeItems = {}", config->GetPercentages(AHB_ORANGE_I)); + LOG_ERROR("module", "percentYellowItems = {}", config->GetPercentages(AHB_YELLOW_I)); + LOG_ERROR("module", "minPriceGrey = {}", config->GetMinPrice(AHB_GREY)); + LOG_ERROR("module", "maxPriceGrey = {}", config->GetMaxPrice(AHB_GREY)); + LOG_ERROR("module", "minPriceWhite = {}", config->GetMinPrice(AHB_WHITE)); + LOG_ERROR("module", "maxPriceWhite = {}", config->GetMaxPrice(AHB_WHITE)); + LOG_ERROR("module", "minPriceGreen = {}", config->GetMinPrice(AHB_GREEN)); + LOG_ERROR("module", "maxPriceGreen = {}", config->GetMaxPrice(AHB_GREEN)); + LOG_ERROR("module", "minPriceBlue = {}", config->GetMinPrice(AHB_BLUE)); + LOG_ERROR("module", "maxPriceBlue = {}", config->GetMaxPrice(AHB_BLUE)); + LOG_ERROR("module", "minPricePurple = {}", config->GetMinPrice(AHB_PURPLE)); + LOG_ERROR("module", "maxPricePurple = {}", config->GetMaxPrice(AHB_PURPLE)); + LOG_ERROR("module", "minPriceOrange = {}", config->GetMinPrice(AHB_ORANGE)); + LOG_ERROR("module", "maxPriceOrange = {}", config->GetMaxPrice(AHB_ORANGE)); + LOG_ERROR("module", "minPriceYellow = {}", config->GetMinPrice(AHB_YELLOW)); + LOG_ERROR("module", "maxPriceYellow = {}", config->GetMaxPrice(AHB_YELLOW)); + LOG_ERROR("module", "minBidPriceGrey = {}", config->GetMinBidPrice(AHB_GREY)); + LOG_ERROR("module", "maxBidPriceGrey = {}", config->GetMaxBidPrice(AHB_GREY)); + LOG_ERROR("module", "minBidPriceWhite = {}", config->GetMinBidPrice(AHB_WHITE)); + LOG_ERROR("module", "maxBidPriceWhite = {}", config->GetMaxBidPrice(AHB_WHITE)); + LOG_ERROR("module", "minBidPriceGreen = {}", config->GetMinBidPrice(AHB_GREEN)); + LOG_ERROR("module", "maxBidPriceGreen = {}", config->GetMaxBidPrice(AHB_GREEN)); + LOG_ERROR("module", "minBidPriceBlue = {}", config->GetMinBidPrice(AHB_BLUE)); + LOG_ERROR("module", "maxBidPriceBlue = {}", config->GetMinBidPrice(AHB_BLUE)); + LOG_ERROR("module", "minBidPricePurple = {}", config->GetMinBidPrice(AHB_PURPLE)); + LOG_ERROR("module", "maxBidPricePurple = {}", config->GetMaxBidPrice(AHB_PURPLE)); + LOG_ERROR("module", "minBidPriceOrange = {}", config->GetMinBidPrice(AHB_ORANGE)); + LOG_ERROR("module", "maxBidPriceOrange = {}", config->GetMaxBidPrice(AHB_ORANGE)); + LOG_ERROR("module", "minBidPriceYellow = {}", config->GetMinBidPrice(AHB_YELLOW)); + LOG_ERROR("module", "maxBidPriceYellow = {}", config->GetMaxBidPrice(AHB_YELLOW)); + LOG_ERROR("module", "maxStackGrey = {}", config->GetMaxStack(AHB_GREY)); + LOG_ERROR("module", "maxStackWhite = {}", config->GetMaxStack(AHB_WHITE)); + LOG_ERROR("module", "maxStackGreen = {}", config->GetMaxStack(AHB_GREEN)); + LOG_ERROR("module", "maxStackBlue = {}", config->GetMaxStack(AHB_BLUE)); + LOG_ERROR("module", "maxStackPurple = {}", config->GetMaxStack(AHB_PURPLE)); + LOG_ERROR("module", "maxStackOrange = {}", config->GetMaxStack(AHB_ORANGE)); + LOG_ERROR("module", "maxStackYellow = {}", config->GetMaxStack(AHB_YELLOW)); + } + + //AuctionHouseEntry const* ahEntry = sAuctionMgr->GetAuctionHouseEntry(config->GetAHFID()); + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config->GetAHFID()); + + config->ResetItemCounts(); + uint32 auctions = auctionHouse->Getcount(); + + if (auctions) + { + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + { + AuctionEntry *Aentry = itr->second; + Item *item = sAuctionMgr->GetAItem(Aentry->item_guid); + if (item) + { + ItemTemplate const *prototype = item->GetTemplate(); + if (prototype) + { + switch (prototype->Quality) + { + case 0: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_GREY_TG); + else + config->IncItemCounts(AHB_GREY_I); + break; + case 1: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_WHITE_TG); + else + config->IncItemCounts(AHB_WHITE_I); + break; + case 2: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_GREEN_TG); + else + config->IncItemCounts(AHB_GREEN_I); + break; + case 3: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_BLUE_TG); + else + config->IncItemCounts(AHB_BLUE_I); + break; + case 4: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_PURPLE_TG); + else + config->IncItemCounts(AHB_PURPLE_I); + break; + case 5: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_ORANGE_TG); + else + config->IncItemCounts(AHB_ORANGE_I); + break; + case 6: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_YELLOW_TG); + else + config->IncItemCounts(AHB_YELLOW_I); + break; + } + } + } + } + } + + if (debug_Out) + { + LOG_ERROR("module", "Current Settings for {} Auctionhouses:", WorldDatabase.Query("SELECT name FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + LOG_ERROR("module", "Grey Trade Goods\t{}\tGrey Items\t{}", config->GetItemCounts(AHB_GREY_TG), config->GetItemCounts(AHB_GREY_I)); + LOG_ERROR("module", "White Trade Goods\t{}\tWhite Items\t{}", config->GetItemCounts(AHB_WHITE_TG), config->GetItemCounts(AHB_WHITE_I)); + LOG_ERROR("module", "Green Trade Goods\t{}\tGreen Items\t{}", config->GetItemCounts(AHB_GREEN_TG), config->GetItemCounts(AHB_GREEN_I)); + LOG_ERROR("module", "Blue Trade Goods\t{}\tBlue Items\t{}", config->GetItemCounts(AHB_BLUE_TG), config->GetItemCounts(AHB_BLUE_I)); + LOG_ERROR("module", "Purple Trade Goods\t{}\tPurple Items\t{}", config->GetItemCounts(AHB_PURPLE_TG), config->GetItemCounts(AHB_PURPLE_I)); + LOG_ERROR("module", "Orange Trade Goods\t{}\tOrange Items\t{}", config->GetItemCounts(AHB_ORANGE_TG), config->GetItemCounts(AHB_ORANGE_I)); + LOG_ERROR("module", "Yellow Trade Goods\t{}\tYellow Items\t{}", config->GetItemCounts(AHB_YELLOW_TG), config->GetItemCounts(AHB_YELLOW_I)); + } + } + if (AHBBuyer) + { + //load buyer bid prices + config->SetBuyerPrice(AHB_GREY, WorldDatabase.Query("SELECT buyerpricegrey FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_WHITE, WorldDatabase.Query("SELECT buyerpricewhite FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_GREEN, WorldDatabase.Query("SELECT buyerpricegreen FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_BLUE, WorldDatabase.Query("SELECT buyerpriceblue FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_PURPLE, WorldDatabase.Query("SELECT buyerpricepurple FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_ORANGE, WorldDatabase.Query("SELECT buyerpriceorange FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + config->SetBuyerPrice(AHB_YELLOW, WorldDatabase.Query("SELECT buyerpriceyellow FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + //load bidding interval + config->SetBiddingInterval(WorldDatabase.Query("SELECT buyerbiddinginterval FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + //load bids per interval + config->SetBidsPerInterval(WorldDatabase.Query("SELECT buyerbidsperinterval FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); + if (debug_Out) + { + LOG_ERROR("module", "buyerPriceGrey = {}", config->GetBuyerPrice(AHB_GREY)); + LOG_ERROR("module", "buyerPriceWhite = {}", config->GetBuyerPrice(AHB_WHITE)); + LOG_ERROR("module", "buyerPriceGreen = {}", config->GetBuyerPrice(AHB_GREEN)); + LOG_ERROR("module", "buyerPriceBlue = {}", config->GetBuyerPrice(AHB_BLUE)); + LOG_ERROR("module", "buyerPricePurple = {}", config->GetBuyerPrice(AHB_PURPLE)); + LOG_ERROR("module", "buyerPriceOrange = {}", config->GetBuyerPrice(AHB_ORANGE)); + LOG_ERROR("module", "buyerPriceYellow = {}", config->GetBuyerPrice(AHB_YELLOW)); + LOG_ERROR("module", "buyerBiddingInterval = {}", config->GetBiddingInterval()); + LOG_ERROR("module", "buyerBidsPerInterval = {}", config->GetBidsPerInterval()); + } + } + + if (debug_Out) + LOG_ERROR("module", "End Settings for {} Auctionhouses:", WorldDatabase.Query("SELECT name FROM mod_auctionhousebot WHERE auctionhouse = {}", config->GetAHID())->Fetch()->Get()); +} diff --git a/modules/mod-ah-bot/src/AuctionHouseBot.h b/modules/mod-ah-bot/src/AuctionHouseBot.h new file mode 100644 index 0000000..a091f7d --- /dev/null +++ b/modules/mod-ah-bot/src/AuctionHouseBot.h @@ -0,0 +1,1260 @@ +/* + * Copyright (C) 2008-2010 Trinity + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AUCTION_HOUSE_BOT_H +#define AUCTION_HOUSE_BOT_H + +#include "Common.h" +#include "ObjectGuid.h" + +struct AuctionEntry; +class Player; +class WorldSession; + +#include "ItemTemplate.h" + +#define AHB_GREY 0 +#define AHB_WHITE 1 +#define AHB_GREEN 2 +#define AHB_BLUE 3 +#define AHB_PURPLE 4 +#define AHB_ORANGE 5 +#define AHB_YELLOW 6 +#define AHB_MAX_QUALITY 6 +#define AHB_GREY_TG 0 +#define AHB_WHITE_TG 1 +#define AHB_GREEN_TG 2 +#define AHB_BLUE_TG 3 +#define AHB_PURPLE_TG 4 +#define AHB_ORANGE_TG 5 +#define AHB_YELLOW_TG 6 +#define AHB_GREY_I 7 +#define AHB_WHITE_I 8 +#define AHB_GREEN_I 9 +#define AHB_BLUE_I 10 +#define AHB_PURPLE_I 11 +#define AHB_ORANGE_I 12 +#define AHB_YELLOW_I 13 + +class AHBConfig +{ +private: + uint32 AHID; + uint32 AHFID; + uint32 minItems; + uint32 maxItems; + uint32 percentGreyTradeGoods; + uint32 percentWhiteTradeGoods; + uint32 percentGreenTradeGoods; + uint32 percentBlueTradeGoods; + uint32 percentPurpleTradeGoods; + uint32 percentOrangeTradeGoods; + uint32 percentYellowTradeGoods; + uint32 percentGreyItems; + uint32 percentWhiteItems; + uint32 percentGreenItems; + uint32 percentBlueItems; + uint32 percentPurpleItems; + uint32 percentOrangeItems; + uint32 percentYellowItems; + uint32 minPriceGrey; + uint32 maxPriceGrey; + uint32 minBidPriceGrey; + uint32 maxBidPriceGrey; + uint32 maxStackGrey; + uint32 minPriceWhite; + uint32 maxPriceWhite; + uint32 minBidPriceWhite; + uint32 maxBidPriceWhite; + uint32 maxStackWhite; + uint32 minPriceGreen; + uint32 maxPriceGreen; + uint32 minBidPriceGreen; + uint32 maxBidPriceGreen; + uint32 maxStackGreen; + uint32 minPriceBlue; + uint32 maxPriceBlue; + uint32 minBidPriceBlue; + uint32 maxBidPriceBlue; + uint32 maxStackBlue; + uint32 minPricePurple; + uint32 maxPricePurple; + uint32 minBidPricePurple; + uint32 maxBidPricePurple; + uint32 maxStackPurple; + uint32 minPriceOrange; + uint32 maxPriceOrange; + uint32 minBidPriceOrange; + uint32 maxBidPriceOrange; + uint32 maxStackOrange; + uint32 minPriceYellow; + uint32 maxPriceYellow; + uint32 minBidPriceYellow; + uint32 maxBidPriceYellow; + uint32 maxStackYellow; + + uint32 buyerPriceGrey; + uint32 buyerPriceWhite; + uint32 buyerPriceGreen; + uint32 buyerPriceBlue; + uint32 buyerPricePurple; + uint32 buyerPriceOrange; + uint32 buyerPriceYellow; + uint32 buyerBiddingInterval; + uint32 buyerBidsPerInterval; + + uint32 greytgp; + uint32 whitetgp; + uint32 greentgp; + uint32 bluetgp; + uint32 purpletgp; + uint32 orangetgp; + uint32 yellowtgp; + uint32 greyip; + uint32 whiteip; + uint32 greenip; + uint32 blueip; + uint32 purpleip; + uint32 orangeip; + uint32 yellowip; + + uint32 greyTGoods; + uint32 whiteTGoods; + uint32 greenTGoods; + uint32 blueTGoods; + uint32 purpleTGoods; + uint32 orangeTGoods; + uint32 yellowTGoods; + + uint32 greyItems; + uint32 whiteItems; + uint32 greenItems; + uint32 blueItems; + uint32 purpleItems; + uint32 orangeItems; + uint32 yellowItems; + +public: + AHBConfig(uint32 ahid) + { + AHID = ahid; + switch(ahid) + { + case 2: + AHFID = 55; + break; + case 6: + AHFID = 29; + break; + case 7: + AHFID = 120; + break; + default: + AHFID = 120; + break; + } + } + AHBConfig() + { + } + uint32 GetAHID() + { + return AHID; + } + uint32 GetAHFID() + { + return AHFID; + } + void SetMinItems(uint32 value) + { + minItems = value; + } + uint32 GetMinItems() + { + if ((minItems == 0) && (maxItems)) + return maxItems; + else if ((maxItems) && (minItems > maxItems)) + return maxItems; + else + return minItems; + } + void SetMaxItems(uint32 value) + { + maxItems = value; + // CalculatePercents() needs to be called, but only if + // SetPercentages() has been called at least once already. + } + uint32 GetMaxItems() + { + return maxItems; + } + void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi) + { + uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; + + if (totalPercent == 0) + { + maxItems = 0; + } + else if (totalPercent != 100) + { + greytg = 0; + whitetg = 27; + greentg = 12; + bluetg = 10; + purpletg = 1; + orangetg = 0; + yellowtg = 0; + greyi = 0; + whitei = 10; + greeni = 30; + bluei = 8; + purplei = 2; + orangei = 0; + yellowi = 0; + } + percentGreyTradeGoods = greytg; + percentWhiteTradeGoods = whitetg; + percentGreenTradeGoods = greentg; + percentBlueTradeGoods = bluetg; + percentPurpleTradeGoods = purpletg; + percentOrangeTradeGoods = orangetg; + percentYellowTradeGoods = yellowtg; + percentGreyItems = greyi; + percentWhiteItems = whitei; + percentGreenItems = greeni; + percentBlueItems = bluei; + percentPurpleItems = purplei; + percentOrangeItems = orangei; + percentYellowItems = yellowi; + CalculatePercents(); + } + uint32 GetPercentages(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return percentGreyTradeGoods; + break; + case AHB_WHITE_TG: + return percentWhiteTradeGoods; + break; + case AHB_GREEN_TG: + return percentGreenTradeGoods; + break; + case AHB_BLUE_TG: + return percentBlueTradeGoods; + break; + case AHB_PURPLE_TG: + return percentPurpleTradeGoods; + break; + case AHB_ORANGE_TG: + return percentOrangeTradeGoods; + break; + case AHB_YELLOW_TG: + return percentYellowTradeGoods; + break; + case AHB_GREY_I: + return percentGreyItems; + break; + case AHB_WHITE_I: + return percentWhiteItems; + break; + case AHB_GREEN_I: + return percentGreenItems; + break; + case AHB_BLUE_I: + return percentBlueItems; + break; + case AHB_PURPLE_I: + return percentPurpleItems; + break; + case AHB_ORANGE_I: + return percentOrangeItems; + break; + case AHB_YELLOW_I: + return percentYellowItems; + break; + default: + return 0; + break; + } + } + void SetMinPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + minPriceGrey = value; + break; + case AHB_WHITE: + minPriceWhite = value; + break; + case AHB_GREEN: + minPriceGreen = value; + break; + case AHB_BLUE: + minPriceBlue = value; + break; + case AHB_PURPLE: + minPricePurple = value; + break; + case AHB_ORANGE: + minPriceOrange = value; + break; + case AHB_YELLOW: + minPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMinPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (minPriceGrey == 0) + return 100; + else if (minPriceGrey > maxPriceGrey) + return maxPriceGrey; + else + return minPriceGrey; + break; + } + case AHB_WHITE: + { + if (minPriceWhite == 0) + return 150; + else if (minPriceWhite > maxPriceWhite) + return maxPriceWhite; + else + return minPriceWhite; + break; + } + case AHB_GREEN: + { + if (minPriceGreen == 0) + return 200; + else if (minPriceGreen > maxPriceGreen) + return maxPriceGreen; + else + return minPriceGreen; + break; + } + case AHB_BLUE: + { + if (minPriceBlue == 0) + return 250; + else if (minPriceBlue > maxPriceBlue) + return maxPriceBlue; + else + return minPriceBlue; + break; + } + case AHB_PURPLE: + { + if (minPricePurple == 0) + return 300; + else if (minPricePurple > maxPricePurple) + return maxPricePurple; + else + return minPricePurple; + break; + } + case AHB_ORANGE: + { + if (minPriceOrange == 0) + return 400; + else if (minPriceOrange > maxPriceOrange) + return maxPriceOrange; + else + return minPriceOrange; + break; + } + case AHB_YELLOW: + { + if (minPriceYellow == 0) + return 500; + else if (minPriceYellow > maxPriceYellow) + return maxPriceYellow; + else + return minPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxPriceGrey = value; + break; + case AHB_WHITE: + maxPriceWhite = value; + break; + case AHB_GREEN: + maxPriceGreen = value; + break; + case AHB_BLUE: + maxPriceBlue = value; + break; + case AHB_PURPLE: + maxPricePurple = value; + break; + case AHB_ORANGE: + maxPriceOrange = value; + break; + case AHB_YELLOW: + maxPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMaxPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (maxPriceGrey == 0) + return 150; + else + return maxPriceGrey; + break; + } + case AHB_WHITE: + { + if (maxPriceWhite == 0) + return 250; + else + return maxPriceWhite; + break; + } + case AHB_GREEN: + { + if (maxPriceGreen == 0) + return 300; + else + return maxPriceGreen; + break; + } + case AHB_BLUE: + { + if (maxPriceBlue == 0) + return 350; + else + return maxPriceBlue; + break; + } + case AHB_PURPLE: + { + if (maxPricePurple == 0) + return 450; + else + return maxPricePurple; + break; + } + case AHB_ORANGE: + { + if (maxPriceOrange == 0) + return 550; + else + return maxPriceOrange; + break; + } + case AHB_YELLOW: + { + if (maxPriceYellow == 0) + return 650; + else + return maxPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMinBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + minBidPriceGrey = value; + break; + case AHB_WHITE: + minBidPriceWhite = value; + break; + case AHB_GREEN: + minBidPriceGreen = value; + break; + case AHB_BLUE: + minBidPriceBlue = value; + break; + case AHB_PURPLE: + minBidPricePurple = value; + break; + case AHB_ORANGE: + minBidPriceOrange = value; + break; + case AHB_YELLOW: + minBidPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMinBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (minBidPriceGrey > 100) + return 100; + else + return minBidPriceGrey; + break; + } + case AHB_WHITE: + { + if (minBidPriceWhite > 100) + return 100; + else + return minBidPriceWhite; + break; + } + case AHB_GREEN: + { + if (minBidPriceGreen > 100) + return 100; + else + return minBidPriceGreen; + break; + } + case AHB_BLUE: + { + if (minBidPriceBlue > 100) + return 100; + else + return minBidPriceBlue; + break; + } + case AHB_PURPLE: + { + if (minBidPricePurple > 100) + return 100; + else + return minBidPricePurple; + break; + } + case AHB_ORANGE: + { + if (minBidPriceOrange > 100) + return 100; + else + return minBidPriceOrange; + break; + } + case AHB_YELLOW: + { + if (minBidPriceYellow > 100) + return 100; + else + return minBidPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxBidPriceGrey = value; + break; + case AHB_WHITE: + maxBidPriceWhite = value; + break; + case AHB_GREEN: + maxBidPriceGreen = value; + break; + case AHB_BLUE: + maxBidPriceBlue = value; + break; + case AHB_PURPLE: + maxBidPricePurple = value; + break; + case AHB_ORANGE: + maxBidPriceOrange = value; + break; + case AHB_YELLOW: + maxBidPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMaxBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (maxBidPriceGrey > 100) + return 100; + else + return maxBidPriceGrey; + break; + } + case AHB_WHITE: + { + if (maxBidPriceWhite > 100) + return 100; + else + return maxBidPriceWhite; + break; + } + case AHB_GREEN: + { + if (maxBidPriceGreen > 100) + return 100; + else + return maxBidPriceGreen; + break; + } + case AHB_BLUE: + { + if (maxBidPriceBlue > 100) + return 100; + else + return maxBidPriceBlue; + break; + } + case AHB_PURPLE: + { + if (maxBidPricePurple > 100) + return 100; + else + return maxBidPricePurple; + break; + } + case AHB_ORANGE: + { + if (maxBidPriceOrange > 100) + return 100; + else + return maxBidPriceOrange; + break; + } + case AHB_YELLOW: + { + if (maxBidPriceYellow > 100) + return 100; + else + return maxBidPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxStack(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxStackGrey = value; + break; + case AHB_WHITE: + maxStackWhite = value; + break; + case AHB_GREEN: + maxStackGreen = value; + break; + case AHB_BLUE: + maxStackBlue = value; + break; + case AHB_PURPLE: + maxStackPurple = value; + break; + case AHB_ORANGE: + maxStackOrange = value; + break; + case AHB_YELLOW: + maxStackYellow = value; + break; + default: + break; + } + } + uint32 GetMaxStack(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + return maxStackGrey; + break; + } + case AHB_WHITE: + { + return maxStackWhite; + break; + } + case AHB_GREEN: + { + return maxStackGreen; + break; + } + case AHB_BLUE: + { + return maxStackBlue; + break; + } + case AHB_PURPLE: + { + return maxStackPurple; + break; + } + case AHB_ORANGE: + { + return maxStackOrange; + break; + } + case AHB_YELLOW: + { + return maxStackYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetBuyerPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + buyerPriceGrey = value; + break; + case AHB_WHITE: + buyerPriceWhite = value; + break; + case AHB_GREEN: + buyerPriceGreen = value; + break; + case AHB_BLUE: + buyerPriceBlue = value; + break; + case AHB_PURPLE: + buyerPricePurple = value; + break; + case AHB_ORANGE: + buyerPriceOrange = value; + break; + case AHB_YELLOW: + buyerPriceYellow = value; + break; + default: + break; + } + } + uint32 GetBuyerPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + return buyerPriceGrey; + break; + case AHB_WHITE: + return buyerPriceWhite; + break; + case AHB_GREEN: + return buyerPriceGreen; + break; + case AHB_BLUE: + return buyerPriceBlue; + break; + case AHB_PURPLE: + return buyerPricePurple; + break; + case AHB_ORANGE: + return buyerPriceOrange; + break; + case AHB_YELLOW: + return buyerPriceYellow; + break; + default: + return 0; + break; + } + } + void SetBiddingInterval(uint32 value) + { + buyerBiddingInterval = value; + } + uint32 GetBiddingInterval() + { + return buyerBiddingInterval; + } + void CalculatePercents() + { + greytgp = (uint32) (((double)percentGreyTradeGoods / 100.0) * maxItems); + whitetgp = (uint32) (((double)percentWhiteTradeGoods / 100.0) * maxItems); + greentgp = (uint32) (((double)percentGreenTradeGoods / 100.0) * maxItems); + bluetgp = (uint32) (((double)percentBlueTradeGoods / 100.0) * maxItems); + purpletgp = (uint32) (((double)percentPurpleTradeGoods / 100.0) * maxItems); + orangetgp = (uint32) (((double)percentOrangeTradeGoods / 100.0) * maxItems); + yellowtgp = (uint32) (((double)percentYellowTradeGoods / 100.0) * maxItems); + greyip = (uint32) (((double)percentGreyItems / 100.0) * maxItems); + whiteip = (uint32) (((double)percentWhiteItems / 100.0) * maxItems); + greenip = (uint32) (((double)percentGreenItems / 100.0) * maxItems); + blueip = (uint32) (((double)percentBlueItems / 100.0) * maxItems); + purpleip = (uint32) (((double)percentPurpleItems / 100.0) * maxItems); + orangeip = (uint32) (((double)percentOrangeItems / 100.0) * maxItems); + yellowip = (uint32) (((double)percentYellowItems / 100.0) * maxItems); + uint32 total = greytgp + whitetgp + greentgp + bluetgp + purpletgp + orangetgp + yellowtgp + greyip + whiteip + greenip + blueip + purpleip + orangeip + yellowip; + int32 diff = (maxItems - total); + if (diff < 0) + { + if ((whiteip - diff) > 0) + whiteip -= diff; + else if ((greenip - diff) > 0) + greenip -= diff; + } + else if (diff < 0) + { + whiteip += diff; + } + } + uint32 GetPercents(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return greytgp; + break; + case AHB_WHITE_TG: + return whitetgp; + break; + case AHB_GREEN_TG: + return greentgp; + break; + case AHB_BLUE_TG: + return bluetgp; + break; + case AHB_PURPLE_TG: + return purpletgp; + break; + case AHB_ORANGE_TG: + return orangetgp; + break; + case AHB_YELLOW_TG: + return yellowtgp; + break; + case AHB_GREY_I: + return greyip; + break; + case AHB_WHITE_I: + return whiteip; + break; + case AHB_GREEN_I: + return greenip; + break; + case AHB_BLUE_I: + return blueip; + break; + case AHB_PURPLE_I: + return purpleip; + break; + case AHB_ORANGE_I: + return orangeip; + break; + case AHB_YELLOW_I: + return yellowip; + break; + default: + return 0; + break; + } + } + + void DecItemCounts(uint32 Class, uint32 Quality) + { + switch(Class) + { + case ITEM_CLASS_TRADE_GOODS: + DecItemCounts(Quality); + break; + default: + DecItemCounts(Quality + 7); + break; + } + } + + void DecItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + --greyTGoods; + break; + case AHB_WHITE_TG: + --whiteTGoods; + break; + case AHB_GREEN_TG: + --greenTGoods; + break; + case AHB_BLUE_TG: + --blueTGoods; + break; + case AHB_PURPLE_TG: + --purpleTGoods; + break; + case AHB_ORANGE_TG: + --orangeTGoods; + break; + case AHB_YELLOW_TG: + --yellowTGoods; + break; + case AHB_GREY_I: + --greyItems; + break; + case AHB_WHITE_I: + --whiteItems; + break; + case AHB_GREEN_I: + --greenItems; + break; + case AHB_BLUE_I: + --blueItems; + break; + case AHB_PURPLE_I: + --purpleItems; + break; + case AHB_ORANGE_I: + --orangeItems; + break; + case AHB_YELLOW_I: + --yellowItems; + break; + default: + break; + } + } + + void IncItemCounts(uint32 Class, uint32 Quality) + { + switch(Class) + { + case ITEM_CLASS_TRADE_GOODS: + IncItemCounts(Quality); + break; + default: + IncItemCounts(Quality + 7); + break; + } + } + + void IncItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + ++greyTGoods; + break; + case AHB_WHITE_TG: + ++whiteTGoods; + break; + case AHB_GREEN_TG: + ++greenTGoods; + break; + case AHB_BLUE_TG: + ++blueTGoods; + break; + case AHB_PURPLE_TG: + ++purpleTGoods; + break; + case AHB_ORANGE_TG: + ++orangeTGoods; + break; + case AHB_YELLOW_TG: + ++yellowTGoods; + break; + case AHB_GREY_I: + ++greyItems; + break; + case AHB_WHITE_I: + ++whiteItems; + break; + case AHB_GREEN_I: + ++greenItems; + break; + case AHB_BLUE_I: + ++blueItems; + break; + case AHB_PURPLE_I: + ++purpleItems; + break; + case AHB_ORANGE_I: + ++orangeItems; + break; + case AHB_YELLOW_I: + ++yellowItems; + break; + default: + break; + } + } + + void ResetItemCounts() + { + greyTGoods = 0; + whiteTGoods = 0; + greenTGoods = 0; + blueTGoods = 0; + purpleTGoods = 0; + orangeTGoods = 0; + yellowTGoods = 0; + + greyItems = 0; + whiteItems = 0; + greenItems = 0; + blueItems = 0; + purpleItems = 0; + orangeItems = 0; + yellowItems = 0; + } + + uint32 TotalItemCounts() + { + return( + greyTGoods + + whiteTGoods + + greenTGoods + + blueTGoods + + purpleTGoods + + orangeTGoods + + yellowTGoods + + + greyItems + + whiteItems + + greenItems + + blueItems + + purpleItems + + orangeItems + + yellowItems); + } + + uint32 GetItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return greyTGoods; + break; + case AHB_WHITE_TG: + return whiteTGoods; + break; + case AHB_GREEN_TG: + return greenTGoods; + break; + case AHB_BLUE_TG: + return blueTGoods; + break; + case AHB_PURPLE_TG: + return purpleTGoods; + break; + case AHB_ORANGE_TG: + return orangeTGoods; + break; + case AHB_YELLOW_TG: + return yellowTGoods; + break; + case AHB_GREY_I: + return greyItems; + break; + case AHB_WHITE_I: + return whiteItems; + break; + case AHB_GREEN_I: + return greenItems; + break; + case AHB_BLUE_I: + return blueItems; + break; + case AHB_PURPLE_I: + return purpleItems; + break; + case AHB_ORANGE_I: + return orangeItems; + break; + case AHB_YELLOW_I: + return yellowItems; + break; + default: + return 0; + break; + } + } + void SetBidsPerInterval(uint32 value) + { + buyerBidsPerInterval = value; + } + uint32 GetBidsPerInterval() + { + return buyerBidsPerInterval; + } + ~AHBConfig() + { + } +}; +class AuctionHouseBot +{ +private: + + bool debug_Out; + bool debug_Out_Filters; + + bool AHBSeller; + bool AHBBuyer; + bool BuyMethod; + bool SellMethod; + + uint32 AHBplayerAccount; + ObjectGuid::LowType AHBplayerGUID; + uint32 ItemsPerCycle; + + //Begin Filters + + bool Vendor_Items; + bool Loot_Items; + bool Other_Items; + bool Vendor_TGs; + bool Loot_TGs; + bool Other_TGs; + + bool No_Bind; + bool Bind_When_Picked_Up; + bool Bind_When_Equipped; + bool Bind_When_Use; + bool Bind_Quest_Item; + + bool DisablePermEnchant; + bool DisableConjured; + bool DisableGems; + bool DisableMoney; + bool DisableMoneyLoot; + bool DisableLootable; + bool DisableKeys; + bool DisableDuration; + bool DisableBOP_Or_Quest_NoReqLevel; + + bool DisableWarriorItems; + bool DisablePaladinItems; + bool DisableHunterItems; + bool DisableRogueItems; + bool DisablePriestItems; + bool DisableDKItems; + bool DisableShamanItems; + bool DisableMageItems; + bool DisableWarlockItems; + bool DisableUnusedClassItems; + bool DisableDruidItems; + + uint32 DisableItemsBelowLevel; + uint32 DisableItemsAboveLevel; + uint32 DisableTGsBelowLevel; + uint32 DisableTGsAboveLevel; + uint32 DisableItemsBelowGUID; + uint32 DisableItemsAboveGUID; + uint32 DisableTGsBelowGUID; + uint32 DisableTGsAboveGUID; + uint32 DisableItemsBelowReqLevel; + uint32 DisableItemsAboveReqLevel; + uint32 DisableTGsBelowReqLevel; + uint32 DisableTGsAboveReqLevel; + uint32 DisableItemsBelowReqSkillRank; + uint32 DisableItemsAboveReqSkillRank; + uint32 DisableTGsBelowReqSkillRank; + uint32 DisableTGsAboveReqSkillRank; + + std::set DisableItemStore; + + //End Filters + + AHBConfig AllianceConfig; + AHBConfig HordeConfig; + AHBConfig NeutralConfig; + + time_t _lastrun_a; + time_t _lastrun_h; + time_t _lastrun_n; + + inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; }; + void addNewAuctions(Player *AHBplayer, AHBConfig *config); + void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session); + +// friend class ACE_Singleton; + AuctionHouseBot(); + +public: + static AuctionHouseBot* instance() + { + static AuctionHouseBot instance; + return &instance; + } + + ~AuctionHouseBot(); + void Update(); + void Initialize(); + void InitializeConfiguration(); + void LoadValues(AHBConfig*); + void DecrementItemCounts(AuctionEntry* ah, uint32 itemEntry); + void IncrementItemCounts(AuctionEntry* ah); + void Commands(uint32, uint32, uint32, char*); + ObjectGuid::LowType GetAHBplayerGUID() { return AHBplayerGUID; }; +}; + +#define auctionbot AuctionHouseBot::instance() + +#endif diff --git a/modules/mod-ah-bot/src/AuctionHouseBotScript.cpp b/modules/mod-ah-bot/src/AuctionHouseBotScript.cpp new file mode 100644 index 0000000..19ef7c8 --- /dev/null +++ b/modules/mod-ah-bot/src/AuctionHouseBotScript.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 +*/ + +#include "ScriptMgr.h" +#include "AuctionHouseBot.h" +#include "Log.h" +#include "Mail.h" +#include "Player.h" +#include "WorldSession.h" + +class AHBot_WorldScript : public WorldScript +{ +public: + AHBot_WorldScript() : WorldScript("AHBot_WorldScript") { } + + void OnBeforeConfigLoad(bool /*reload*/) override + { + auctionbot->InitializeConfiguration(); + } + + void OnStartup() override + { + LOG_INFO("server.loading", "Initialize AuctionHouseBot..."); + auctionbot->Initialize(); + } +}; + +class AHBot_AuctionHouseScript : public AuctionHouseScript +{ +public: + AHBot_AuctionHouseScript() : AuctionHouseScript("AHBot_AuctionHouseScript") { } + + void OnBeforeAuctionHouseMgrSendAuctionSuccessfulMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* /*auction*/, Player* owner, uint32& /*owner_accId*/, uint32& /*profit*/, bool& sendNotification, bool& updateAchievementCriteria, bool& /*sendMail*/) override + { + if (owner && owner->GetGUID().GetCounter() == auctionbot->GetAHBplayerGUID()) + { + sendNotification = false; + updateAchievementCriteria = false; + } + } + + void OnBeforeAuctionHouseMgrSendAuctionExpiredMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* /*auction*/, Player* owner, uint32& /*owner_accId*/, bool& sendNotification, bool& /*sendMail*/) override + { + if (owner && owner->GetGUID().GetCounter() == auctionbot->GetAHBplayerGUID()) + sendNotification = false; + } + + void OnBeforeAuctionHouseMgrSendAuctionOutbiddedMail(AuctionHouseMgr* /*auctionHouseMgr*/, AuctionEntry* auction, Player* oldBidder, uint32& /*oldBidder_accId*/, Player* newBidder, uint32& newPrice, bool& /*sendNotification*/, bool& /*sendMail*/) override + { + if (oldBidder && !newBidder) + oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, ObjectGuid::Create(auctionbot->GetAHBplayerGUID()), newPrice, auction->GetAuctionOutBid(), auction->item_template); + } + + void OnAuctionAdd(AuctionHouseObject* /*ah*/, AuctionEntry* auction) override + { + auctionbot->IncrementItemCounts(auction); + } + + void OnAuctionRemove(AuctionHouseObject* /*ah*/, AuctionEntry* auction) override + { + auctionbot->DecrementItemCounts(auction, auction->item_template); + } + + void OnBeforeAuctionHouseMgrUpdate() override + { + auctionbot->Update(); + } +}; + +class AHBot_MailScript : public MailScript +{ +public: + AHBot_MailScript() : MailScript("AHBot_MailScript") { } + + void OnBeforeMailDraftSendMailTo(MailDraft* /*mailDraft*/, MailReceiver const& receiver, MailSender const& sender, MailCheckMask& /*checked*/, uint32& /*deliver_delay*/, uint32& /*custom_expiration*/, bool& deleteMailItemsFromDB, bool& sendMail) override + { + if (receiver.GetPlayerGUIDLow() == auctionbot->GetAHBplayerGUID()) + { + if (sender.GetMailMessageType() == MAIL_AUCTION) // auction mail with items + deleteMailItemsFromDB = true; + sendMail = false; + } + } +}; + +void AddAHBotScripts() +{ + new AHBot_WorldScript(); + new AHBot_AuctionHouseScript(); + new AHBot_MailScript(); +} diff --git a/modules/mod-ah-bot/src/ah_bot_loader.cpp b/modules/mod-ah-bot/src/ah_bot_loader.cpp new file mode 100644 index 0000000..1344243 --- /dev/null +++ b/modules/mod-ah-bot/src/ah_bot_loader.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2021+ WarheadCore + */ + +// From SC +void AddAHBotCommandScripts(); +void AddAHBotScripts(); + +// Add all +void Addmod_ah_botScripts() +{ + AddAHBotCommandScripts(); + AddAHBotScripts(); +} diff --git a/modules/mod-ah-bot/src/cs_ah_bot.cpp b/modules/mod-ah-bot/src/cs_ah_bot.cpp new file mode 100644 index 0000000..469f7b5 --- /dev/null +++ b/modules/mod-ah-bot/src/cs_ah_bot.cpp @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/* ScriptData +Name: ah_bot_commandscript +%Complete: 100 +Comment: All ah_bot related commands +Category: commandscripts +EndScriptData */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "AuctionHouseBot.h" +#include "Config.h" + +#if AC_COMPILER == AC_COMPILER_GNU +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +using namespace Acore::ChatCommands; + +class ah_bot_commandscript : public CommandScript +{ +public: + ah_bot_commandscript() : CommandScript("ah_bot_commandscript") { } + + std::vector GetCommands() const override + { + static std::vector commandTable = + { + { "ahbotoptions", SEC_GAMEMASTER, true, &HandleAHBotOptionsCommand, "" }, + }; + return commandTable; + } + + static bool HandleAHBotOptionsCommand(ChatHandler* handler, const char*args) + { + uint32 ahMapID = 0; + char* opt = strtok((char*)args, " "); + char* ahMapIdStr = strtok(NULL, " "); + + if (ahMapIdStr) + { + ahMapID = uint32(strtoul(ahMapIdStr, NULL, 0)); + switch (ahMapID) + { + case 2: + case 6: + case 7: + break; + default: + opt = NULL; + break; + } + } + + if (!opt) + { + handler->PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); + handler->PSendSysMessage("Try ahbotoptions help to see a list of options."); + return false; + } + + int l = strlen(opt); + + if (strncmp(opt, "help", l) == 0) + { + handler->PSendSysMessage("AHBot commands:"); + handler->PSendSysMessage("ahexpire"); + handler->PSendSysMessage("minitems"); + handler->PSendSysMessage("maxitems"); + //handler->PSendSysMessage(""); + //handler->PSendSysMessage(""); + handler->PSendSysMessage("percentages"); + handler->PSendSysMessage("minprice"); + handler->PSendSysMessage("maxprice"); + handler->PSendSysMessage("minbidprice"); + handler->PSendSysMessage("maxbidprice"); + handler->PSendSysMessage("maxstack"); + handler->PSendSysMessage("buyerprice"); + handler->PSendSysMessage("bidinterval"); + handler->PSendSysMessage("bidsperinterval"); + return true; + } + else if (strncmp(opt, "ahexpire", l) == 0) + { + if (!ahMapIdStr) + { + handler->PSendSysMessage("Syntax is: ahbotoptions ahexpire $ahMapID (2, 6 or 7)"); + return false; + } + + auctionbot->Commands(0, ahMapID, 0, NULL); + } + else if (strncmp(opt, "minitems", l) == 0) + { + char* param1 = strtok(NULL, " "); + if (!ahMapIdStr || !param1) + { + handler->PSendSysMessage("Syntax is: ahbotoptions minitems $ahMapID (2, 6 or 7) $minItems"); + return false; + } + + auctionbot->Commands(1, ahMapID, 0, param1); + } + else if (strncmp(opt, "maxitems", l) == 0) + { + char* param1 = strtok(NULL, " "); + if (!ahMapIdStr || !param1) + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxitems $ahMapID (2, 6 or 7) $maxItems"); + return false; + } + + auctionbot->Commands(2, ahMapID, 0, param1); + } + else if (strncmp(opt, "mintime", l) == 0) + { + handler->PSendSysMessage("ahbotoptions mintime has been deprecated"); + return false; + /* + char* param1 = strtok(NULL, " "); + if (!ahMapIdStr || !param1) + { + PSendSysMessage("Syntax is: ahbotoptions mintime $ahMapID (2, 6 or 7) $mintime"); + return false; + } + + auctionbot.Commands(3, ahMapID, 0, param1); + */ + } + else if (strncmp(opt, "maxtime", l) == 0) + { + handler->PSendSysMessage("ahbotoptions maxtime has been deprecated"); + return false; + /* + char* param1 = strtok(NULL, " "); + if (!ahMapIdStr || !param1) + { + PSendSysMessage("Syntax is: ahbotoptions maxtime $ahMapID (2, 6 or 7) $maxtime"); + return false; + } + + auctionbot.Commands(4, ahMapID, 0, param1); + */ + } + else if (strncmp(opt, "percentages", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + char* param3 = strtok(NULL, " "); + char* param4 = strtok(NULL, " "); + char* param5 = strtok(NULL, " "); + char* param6 = strtok(NULL, " "); + char* param7 = strtok(NULL, " "); + char* param8 = strtok(NULL, " "); + char* param9 = strtok(NULL, " "); + char* param10 = strtok(NULL, " "); + char* param11 = strtok(NULL, " "); + char* param12 = strtok(NULL, " "); + char* param13 = strtok(NULL, " "); + char* param14 = strtok(NULL, " "); + + if (!ahMapIdStr || !param14) + { + handler->PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); + handler->PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); + handler->PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); + handler->PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); + handler->PSendSysMessage("The total must add up to 100%%"); + return false; + } + + uint32 greytg = uint32(strtoul(param1, NULL, 0)); + uint32 whitetg = uint32(strtoul(param2, NULL, 0)); + uint32 greentg = uint32(strtoul(param3, NULL, 0)); + uint32 bluetg = uint32(strtoul(param4, NULL, 0)); + uint32 purpletg = uint32(strtoul(param5, NULL, 0)); + uint32 orangetg = uint32(strtoul(param6, NULL, 0)); + uint32 yellowtg = uint32(strtoul(param7, NULL, 0)); + uint32 greyi = uint32(strtoul(param8, NULL, 0)); + uint32 whitei = uint32(strtoul(param9, NULL, 0)); + uint32 greeni = uint32(strtoul(param10, NULL, 0)); + uint32 bluei = uint32(strtoul(param11, NULL, 0)); + uint32 purplei = uint32(strtoul(param12, NULL, 0)); + uint32 orangei = uint32(strtoul(param13, NULL, 0)); + uint32 yellowi = uint32(strtoul(param14, NULL, 0)); + uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; + + if (totalPercent == 0 || totalPercent != 100) + { + handler->PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); + handler->PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); + handler->PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); + handler->PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); + handler->PSendSysMessage("The total must add up to 100%%"); + return false; + } + + char param[100]; + param[0] = '\0'; + strcat(param, param1); + strcat(param, " "); + strcat(param, param2); + strcat(param, " "); + strcat(param, param3); + strcat(param, " "); + strcat(param, param4); + strcat(param, " "); + strcat(param, param5); + strcat(param, " "); + strcat(param, param6); + strcat(param, " "); + strcat(param, param7); + strcat(param, " "); + strcat(param, param8); + strcat(param, " "); + strcat(param, param9); + strcat(param, " "); + strcat(param, param10); + strcat(param, " "); + strcat(param, param11); + strcat(param, " "); + strcat(param, param12); + strcat(param, " "); + strcat(param, param13); + strcat(param, " "); + strcat(param, param14); + auctionbot->Commands(5, ahMapID, 0, param); + } + else if (strncmp(opt, "minprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + + if (strncmp(param1, "grey", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, "orange", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(6, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt, "maxprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + if (!ahMapIdStr || !param1 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + if (strncmp(param1, "grey", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, "orange",l) == 0) + auctionbot->Commands(7, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(7, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt, "minbidprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + + if (!ahMapIdStr || !param2 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + + uint32 minBidPrice = uint32(strtoul(param2, NULL, 0)); + if (minBidPrice < 1 || minBidPrice > 100) + { + handler->PSendSysMessage("The min bid price multiplier must be between 1 and 100"); + return false; + } + + if (strncmp(param1, "grey", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, "orange", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(8, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt, "maxbidprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + + uint32 maxBidPrice = uint32(strtoul(param2, NULL, 0)); + if (maxBidPrice < 1 || maxBidPrice > 100) + { + handler->PSendSysMessage("The max bid price multiplier must be between 1 and 100"); + return false; + } + + if (strncmp(param1, "grey", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, " orange", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(9, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions max bidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt, "maxstack",l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); + return false; + } + + // uint32 maxStack = uint32(strtoul(param2, NULL, 0)); + // if (maxStack < 0) + // { + // handler->PSendSysMessage("maxstack can't be a negative number."); + // return false; + // } + + if (strncmp(param1, "grey",l) == 0) + auctionbot->Commands(10, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, "orange", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(10, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); + return false; + } + } + else if (strncmp(opt, "buyerprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + char* param2 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1 || !param2) + { + handler->PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); + return false; + } + + if (strncmp(param1, "grey", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_GREY, param2); + else if (strncmp(param1, "white", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_WHITE, param2); + else if (strncmp(param1, "green", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_GREEN, param2); + else if (strncmp(param1, "blue", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_BLUE, param2); + else if (strncmp(param1, "purple", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_PURPLE, param2); + else if (strncmp(param1, "orange", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_ORANGE, param2); + else if (strncmp(param1, "yellow", l) == 0) + auctionbot->Commands(11, ahMapID, AHB_YELLOW, param2); + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); + return false; + } + } + else if (strncmp(opt, "bidinterval", l) == 0) + { + char* param1 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1) + { + handler->PSendSysMessage("Syntax is: ahbotoptions bidinterval $ahMapID (2, 6 or 7) $interval(in minutes)"); + return false; + } + + auctionbot->Commands(12, ahMapID, 0, param1); + } + else if (strncmp(opt, "bidsperinterval", l) == 0) + { + char* param1 = strtok(NULL, " "); + + if (!ahMapIdStr || !param1) + { + handler->PSendSysMessage("Syntax is: ahbotoptions bidsperinterval $ahMapID (2, 6 or 7) $bids"); + return false; + } + + auctionbot->Commands(13, ahMapID, 0, param1); + } + else + { + handler->PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); + handler->PSendSysMessage("Try ahbotoptions help to see a list of options."); + return false; + } + + return true; + } +}; + +void AddAHBotCommandScripts() +{ + new ah_bot_commandscript(); +} diff --git a/modules/mod-aoe-loot/.editorconfig b/modules/mod-aoe-loot/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/mod-aoe-loot/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/mod-aoe-loot/.gitattributes b/modules/mod-aoe-loot/.gitattributes new file mode 100644 index 0000000..6667b6a --- /dev/null +++ b/modules/mod-aoe-loot/.gitattributes @@ -0,0 +1,104 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text eol=lf + +# Text +*.conf text +*.conf.dist text +*.cmake text + +## Scripts +*.sh text +*.fish text +*.lua text + +## SQL +*.sql text + +## C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +COPYRIGHT text +INSTALL text +license text +LICENSE text +NEWS text +readme text +README text +TODO text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + + +## ARCHIVES +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +## EXECUTABLES +*.exe binary +*.pyc binary diff --git a/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/bug_report.yml b/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..5610d2b --- /dev/null +++ b/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,72 @@ +name: Bug report +description: Create a bug report to help us improve. +title: "Bug: " +body: + - type: textarea + id: current + attributes: + label: Current Behaviour + description: | + Description of the problem or issue here. + Include entries of affected creatures / items / quests / spells etc. + If this is a crash, post the crashlog (upload to https://gist.github.com/) and include the link here. + Never upload files! Use GIST for text and YouTube for videos! + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behaviour + description: | + Tell us what should happen instead. + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce the problem + description: | + What does someone else need to do to encounter the same bug? + placeholder: | + 1. Step 1 + 2. Step 2 + 3. Step 3 + validations: + required: true + - type: textarea + id: extra + attributes: + label: Extra Notes + description: | + Do you have any extra notes that can help solve the issue that does not fit any other field? + placeholder: | + None + validations: + required: false + - type: textarea + id: commit + attributes: + label: AC rev. hash/commit + description: | + Copy the result of the `.server debug` command (if you need to run it from the client get a prat addon) + validations: + required: true + - type: input + id: os + attributes: + label: Operating system + description: | + The Operating System the Server is running on. + i.e. Windows 11 x64, Debian 10 x64, macOS 12, Ubuntu 20.04 + validations: + required: true + - type: textarea + id: custom + attributes: + label: Custom changes or Modules + description: | + List which custom changes or modules you have applied, i.e. Eluna module, etc. + placeholder: | + None + validations: + required: false diff --git a/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/feature_request.yml b/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..58f79dd --- /dev/null +++ b/modules/mod-aoe-loot/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,33 @@ +name: Feature request +description: Suggest an idea for this project +title: "Feature: " +body: + - type: markdown + attributes: + value: | + Thank you for taking your time to fill out a feature request. Remember to fill out all fields including the title above. + An issue that is not properly filled out will be closed. + - type: textarea + id: description + attributes: + label: Describe your feature request or suggestion in detail + description: | + A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Describe a possible solution to your feature or suggestion in detail + description: | + A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + - type: textarea + id: additional + attributes: + label: Additional context + description: | + Add any other context or screenshots about the feature request here. + validations: + required: false diff --git a/modules/mod-aoe-loot/.github/README.md b/modules/mod-aoe-loot/.github/README.md new file mode 100644 index 0000000..3683617 --- /dev/null +++ b/modules/mod-aoe-loot/.github/README.md @@ -0,0 +1,28 @@ +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore + +## # mod-aoe-loot + +[English](README.md) | [Español](README_ES.md) + +- Latest build status with azerothcore: + +[![Build Status](https://github.com/azerothcore/mod-aoe-loot/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-aoe-loot) + +## Important notes + +There may still be some improvements to be made to the module, but you could say that it is pretty good. However, we are still going to continue working and trying to revise what is needed, as long as tests are performed and it can be determined that the reports are valid. + +For the module to work, 4 things are needed. +- [x] Create the `CanSendErrorAlreadyLooted` hook. (created) +- [x] Create the hook `CanSendCreatureLoot` (created) +- [x] Create the hook `OnBeforeCreatureLootMoney` (created) +- [x] The module works, if the player takes an object from the loot. If the player selects gold, it does not run. So we want to check that and also correct to be able to add up the total amount of gold obtained. +- [x] If the creature can be skinned, the body remains for a while, and when it is skinned, it automatically disappears to avoid being skinned again. + +This module requires the following pull request + +https://github.com/azerothcore/azerothcore-wotlk/pull/16589 + +## Description + +The objective of this module is to allow players to obtain all items from various npc's within a certain distance range. diff --git a/modules/mod-aoe-loot/.github/README_ES.md b/modules/mod-aoe-loot/.github/README_ES.md new file mode 100644 index 0000000..6d80059 --- /dev/null +++ b/modules/mod-aoe-loot/.github/README_ES.md @@ -0,0 +1,28 @@ +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore + +## # mod-aoe-loot + +[English](README.md) | [Español](README_ES.md) + +- Último estado de compilación con azerothcore: + +[![Build Status](https://github.com/azerothcore/mod-aoe-loot/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-aoe-loot) + +## Notas importantes + +Puede que todavia, haya que hacerle alguna mejora al modulo, pero se podria decir que esta bastante bien. Sin embargo, aun se va a seguir trabajando y tratando de revisar lo que haga falta, en la medida, en la que se realicen pruebas y se pueda determinar, que los reportes son validos. + +Para que el módulo funcione, se necesitan 4 cosas. +- [x] Crear el hook `CanSendErrorAlreadyLooted`. (creado) +- [x] Crear el hook `CanSendCreatureLoot` (creado) +- [x] Crear el hook `OnBeforeCreatureLootMoney` (creado) +- [x] El módulo funciona, si el jugador toma un objeto del botín. Si el jugador selecciona oro, no funciona. Así que queremos comprobar que funcione y también poder sumar la cantidad total de oro obtenida. +- [x] Si la criatura, puede ser desollada, el cuerpo, permanece por un tiempo, y cuando el mismo es desollado, automáticamente desaparece, para evitar ser desollado nuevamente. + +Este módulo requiere el siguiente pull request + +https://github.com/azerothcore/azerothcore-wotlk/pull/16589 + +## Descripción + +El objetivo de este módulo es permitir a los jugadores obtener todos los objetos de varios npc's dentro de un cierto rango de distancia. diff --git a/modules/mod-aoe-loot/.github/workflows/core-build.yml b/modules/mod-aoe-loot/.github/workflows/core-build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-aoe-loot/.github/workflows/core-build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-aoe-loot/.gitignore b/modules/mod-aoe-loot/.gitignore new file mode 100644 index 0000000..4ba5dd3 --- /dev/null +++ b/modules/mod-aoe-loot/.gitignore @@ -0,0 +1,47 @@ +!.gitignore + +# +#Generic +# +.directory +.mailmap +* .orig +* .rej +* .*~ +.hg / +*.kdev * +.DS_Store +CMakeLists.txt.user +* .bak +* .patch +* .diff +* .REMOTE.* +* .BACKUP.* +* .BASE.* +* .LOCAL.* + +# +# IDE & other softwares +# +/ .settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-aoe-loot/conf/mod_aoe_loot.conf.dist b/modules/mod-aoe-loot/conf/mod_aoe_loot.conf.dist new file mode 100644 index 0000000..8718059 --- /dev/null +++ b/modules/mod-aoe-loot/conf/mod_aoe_loot.conf.dist @@ -0,0 +1,26 @@ +# +# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# User has manually chosen to ignore the git-tests, so throw them a warning. +# This is done EACH compile so they can be alerted about the consequences. +# + +######################################## +# AoeLoot module configuration +######################################## +# +# AOELoot.Enable +# Description: Enables Module +# Default: 0 - (Disabled) +# 1 - (Enabled) +# + +AOELoot.Enable = 1 diff --git a/modules/mod-aoe-loot/data/.gitkeep b/modules/mod-aoe-loot/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-auth/base/.gitkeep b/modules/mod-aoe-loot/data/sql/db-auth/base/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-auth/updates/.gitkeep b/modules/mod-aoe-loot/data/sql/db-auth/updates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-characters/base/.gitkeep b/modules/mod-aoe-loot/data/sql/db-characters/base/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-characters/updates/.gitkeep b/modules/mod-aoe-loot/data/sql/db-characters/updates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-world/base/.gitkeep b/modules/mod-aoe-loot/data/sql/db-world/base/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/data/sql/db-world/base/aoe_loot_acore_string.sql b/modules/mod-aoe-loot/data/sql/db-world/base/aoe_loot_acore_string.sql new file mode 100644 index 0000000..f8fb507 --- /dev/null +++ b/modules/mod-aoe-loot/data/sql/db-world/base/aoe_loot_acore_string.sql @@ -0,0 +1,5 @@ +SET @ENTRY:=50000; +DELETE FROM `acore_string` WHERE `entry` IN (@ENTRY+0, @ENTRY+1); +INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES +(@ENTRY+0, 'This server is running the |cff4CFF00Loot aoe|r module.', '', '', '', '', '', 'Este servidor está ejecutando el módulo |cff4CFF00Loot aoe|r.', 'Este servidor está ejecutando el módulo |cff4CFF00Loot aoe|r.', ''), +(@ENTRY+1, '|cff4CFF00[Loot aoe]|r Your items has been mailed to you.', '', '', '', '', '', '|cff4CFF00[Loot aoe]|r Sus artículos le han sido enviados por correo.', '|cff4CFF00[Loot aoe]|r Sus artículos le han sido enviados por correo.', ''); diff --git a/modules/mod-aoe-loot/data/sql/db-world/updates/.gitkeep b/modules/mod-aoe-loot/data/sql/db-world/updates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/include.sh b/modules/mod-aoe-loot/include.sh new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-aoe-loot/pull_request_template.md b/modules/mod-aoe-loot/pull_request_template.md new file mode 100644 index 0000000..21c9245 --- /dev/null +++ b/modules/mod-aoe-loot/pull_request_template.md @@ -0,0 +1,25 @@ + + +## Changes Proposed: +- +- + +## Issues Addressed: + +- Closes + +## SOURCE: + + +## Tests Performed: + +- +- + + +## How to Test the Changes: + + +1. +2. +3. diff --git a/modules/mod-aoe-loot/src/AoeLoot_SC.cpp b/modules/mod-aoe-loot/src/AoeLoot_SC.cpp new file mode 100644 index 0000000..0cea4d2 --- /dev/null +++ b/modules/mod-aoe-loot/src/AoeLoot_SC.cpp @@ -0,0 +1,130 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Log.h" +#include "ScriptMgr.h" +#include "Config.h" +#include "Chat.h" +#include "Player.h" +#include "ScriptedGossip.h" + +enum AoeLootString +{ + AOE_ACORE_STRING_MESSAGE = 50000, + AOE_ITEM_IN_THE_MAIL +}; + +class AoeLoot_Player : public PlayerScript +{ +public: + AoeLoot_Player() : PlayerScript("AoeLoot_Player") { } + + void OnLogin(Player* player) override + { + if (sConfigMgr->GetOption("AOELoot.Enable", true)) + { + ChatHandler(player->GetSession()).PSendSysMessage(AOE_ACORE_STRING_MESSAGE); + } + } + + bool CanSendErrorAlreadyLooted(Player* /*player*/) override + { + return true; + } + + void OnCreatureLootAOE(Player* player) + { + bool _enable = sConfigMgr->GetOption("AOELoot.Enable", true); + + if (player->GetGroup() || !_enable) + return; + + float range = 30.0f; + uint32 gold = 0; + + std::list creaturedie; + player->GetDeadCreatureListInGrid(creaturedie, range); + + for (auto const& _creature : creaturedie) + { + Loot* loot = &_creature->loot; + gold += loot->gold; + loot->gold = 0; + uint8 lootSlot = 0; + uint32 maxSlot = loot->GetMaxSlotInLootFor(player); + + for (uint32 i = 0; i < maxSlot; ++i) + { + if (LootItem* item = loot->LootItemInSlot(i, player)) + { + if (player->AddItem(item->itemid, item->count)) + { + player->SendNotifyLootItemRemoved(lootSlot); + player->SendLootRelease(player->GetLootGUID()); + } + else + { + player->SendItemRetrievalMail(item->itemid, item->count); + ChatHandler(player->GetSession()).SendSysMessage(AOE_ITEM_IN_THE_MAIL); + } + } + } + + if (!loot->empty()) + { + if (!_creature->IsAlive()) + { + _creature->AllLootRemovedFromCorpse(); + _creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + loot->clear(); + + if (_creature->HasUnitFlag(UNIT_FLAG_SKINNABLE)) + { + _creature->RemoveUnitFlag(UNIT_FLAG_SKINNABLE); + } + } + } + else + { + _creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + _creature->AllLootRemovedFromCorpse(); + } + } + + player->ModifyMoney(gold); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, gold); + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); + data << uint32(gold); + data << uint8(1); + player->GetSession()->SendPacket(&data); + } + + void OnAfterCreatureLoot(Player* player) override + { + OnCreatureLootAOE(player); + } + + void OnAfterCreatureLootMoney(Player* player) override + { + OnCreatureLootAOE(player); + } +}; + +void AddSC_AoeLoot() +{ + new AoeLoot_Player(); +} diff --git a/modules/mod-aoe-loot/src/aoe_loot_loader.cpp b/modules/mod-aoe-loot/src/aoe_loot_loader.cpp new file mode 100644 index 0000000..8d760fa --- /dev/null +++ b/modules/mod-aoe-loot/src/aoe_loot_loader.cpp @@ -0,0 +1,25 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +// From SC +void AddSC_AoeLoot(); + +// Add all +void Addmod_aoe_lootScripts() +{ + AddSC_AoeLoot(); +} diff --git a/modules/mod-arac/.github/workflows/core-build.yml b/modules/mod-arac/.github/workflows/core-build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-arac/.github/workflows/core-build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-arac/LICENSE b/modules/mod-arac/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/modules/mod-arac/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/modules/mod-arac/Patch-A.MPQ b/modules/mod-arac/Patch-A.MPQ new file mode 100644 index 0000000..21fc1ee Binary files /dev/null and b/modules/mod-arac/Patch-A.MPQ differ diff --git a/modules/mod-arac/README.md b/modules/mod-arac/README.md new file mode 100644 index 0000000..705d541 --- /dev/null +++ b/modules/mod-arac/README.md @@ -0,0 +1,28 @@ +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore +## ARAC - All Class All Races +# ![ARAC icon](https://raw.githubusercontent.com/azerothcore/mod-arac/master/icon.png) +- Latest build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-arac/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-arac) + +## Screenshot + +![All Races All Classes](https://raw.githubusercontent.com/azerothcore/mod-arac/master/images/screen1.png) + +![All Races All Classes](https://raw.githubusercontent.com/azerothcore/mod-arac/master/images/screen2.png) + + +# Usage + +- Make a backup of your database before using this module. +- Apply the SQL query. +- Update your DBC files (client and server) contained in the release, so add **Patch-A.MPQ** to your WoW/Data/ directory and update the DBC files in your server/data/dbc/ directory. + +# Need help? + +If you encounter a bug please [open a issue](https://github.com/azerothcore/mod-arac/issues/new). + + +## Credits + +* [iThorgrim](https://github.com/iThorgrim) + +AzerothCore: [repository](https://github.com/azerothcore) - [website](http://azerothcore.org/) - [discord chat community](https://discord.gg/PaqQRkd) diff --git a/modules/mod-arac/icon.png b/modules/mod-arac/icon.png new file mode 100644 index 0000000..9545c9f Binary files /dev/null and b/modules/mod-arac/icon.png differ diff --git a/modules/mod-arac/icons.png b/modules/mod-arac/icons.png new file mode 100644 index 0000000..80e154b Binary files /dev/null and b/modules/mod-arac/icons.png differ diff --git a/modules/mod-arac/images/screen1.png b/modules/mod-arac/images/screen1.png new file mode 100644 index 0000000..b4ebbc1 Binary files /dev/null and b/modules/mod-arac/images/screen1.png differ diff --git a/modules/mod-arac/images/screen2.png b/modules/mod-arac/images/screen2.png new file mode 100644 index 0000000..330ec4e Binary files /dev/null and b/modules/mod-arac/images/screen2.png differ diff --git a/modules/mod-arac/patch-contents/DBFilesContent/CharBaseInfo.dbc b/modules/mod-arac/patch-contents/DBFilesContent/CharBaseInfo.dbc new file mode 100644 index 0000000..3e1320c Binary files /dev/null and b/modules/mod-arac/patch-contents/DBFilesContent/CharBaseInfo.dbc differ diff --git a/modules/mod-arac/patch-contents/DBFilesContent/CharStartOutfit.dbc b/modules/mod-arac/patch-contents/DBFilesContent/CharStartOutfit.dbc new file mode 100644 index 0000000..aee4a2c Binary files /dev/null and b/modules/mod-arac/patch-contents/DBFilesContent/CharStartOutfit.dbc differ diff --git a/modules/mod-arac/sql/world/(Optionnal)/1 - Copy for Custom Race.SQL b/modules/mod-arac/sql/world/(Optionnal)/1 - Copy for Custom Race.SQL new file mode 100644 index 0000000..7b69440 --- /dev/null +++ b/modules/mod-arac/sql/world/(Optionnal)/1 - Copy for Custom Race.SQL @@ -0,0 +1,30 @@ +/* + +This query allows you to copy information from a specific breed to add new information. +In this example, the code copies the information from RACE 1 (Human) to add it to race 12 (Fel'Orc). + +*/ + +-- PlayerCreateInfo +REPLACE INTO `playercreateinfo` + SELECT race+11, class, map, zone, position_x, position_y, position_z, orientation FROM `playercreateinfo` WHERE race = 1; + +-- PlayerLevelStats +REPLACE INTO `player_levelstats` + SELECT race+11, class, `level`, str, agi, sta, inte, spi FROM `player_levelstats` WHERE race = 1; + +-- PlayerCreateInfo_Action +REPLACE INTO `playercreateinfo_action` + SELECT race+11, class, button, `action`, `type` FROM `playercreateinfo_action` WHERE race = 1; + +-- PlayerCreateInfo_Item +REPLACE INTO `playercreateinfo_item` + SELECT race+11, class, itemid, amount FROM `playercreateinfo_item` WHERE race = 1; + +-- PlayerCreateInfo_Spell +REPLACE INTO `playercreateinfo_spell` + SELECT racemask+2047, classmask, Spell, Note FROM `playercreateinfo_spell` WHERE racemask = 1; + +-- PlayerCreateInfo_Spell +REPLACE INTO `playercreateinfo_spell_custom` + SELECT racemask+2047, classmask, Spell, Note FROM `playercreateinfo_spell_custom` WHERE racemask = 1; diff --git a/modules/mod-arac/sql/world/arac.sql b/modules/mod-arac/sql/world/arac.sql new file mode 100644 index 0000000..2ba8693 --- /dev/null +++ b/modules/mod-arac/sql/world/arac.sql @@ -0,0 +1,16822 @@ +-- player_classlevelstats + +INSERT IGNORE INTO `player_classlevelstats` VALUES +('1', '1', '20', '0'), +('1', '2', '29', '0'), +('1', '3', '38', '0'), +('1', '4', '47', '0'), +('1', '5', '56', '0'), +('1', '6', '65', '0'), +('1', '7', '74', '0'), +('1', '8', '83', '0'), +('1', '9', '92', '0'), +('1', '10', '101', '0'), +('1', '11', '100', '0'), +('1', '12', '109', '0'), +('1', '13', '118', '0'), +('1', '14', '128', '0'), +('1', '15', '139', '0'), +('1', '16', '151', '0'), +('1', '17', '154', '0'), +('1', '18', '168', '0'), +('1', '19', '183', '0'), +('1', '20', '199', '0'), +('1', '21', '206', '0'), +('1', '22', '224', '0'), +('1', '23', '243', '0'), +('1', '24', '253', '0'), +('1', '25', '274', '0'), +('1', '26', '296', '0'), +('1', '27', '309', '0'), +('1', '28', '333', '0'), +('1', '29', '348', '0'), +('1', '30', '374', '0'), +('1', '31', '401', '0'), +('1', '32', '419', '0'), +('1', '33', '448', '0'), +('1', '34', '468', '0'), +('1', '35', '499', '0'), +('1', '36', '521', '0'), +('1', '37', '545', '0'), +('1', '38', '581', '0'), +('1', '39', '609', '0'), +('1', '40', '649', '0'), +('1', '41', '681', '0'), +('1', '42', '715', '0'), +('1', '43', '761', '0'), +('1', '44', '799', '0'), +('1', '45', '839', '0'), +('1', '46', '881', '0'), +('1', '47', '935', '0'), +('1', '48', '981', '0'), +('1', '49', '1029', '0'), +('1', '50', '1079', '0'), +('1', '51', '1131', '0'), +('1', '52', '1185', '0'), +('1', '53', '1241', '0'), +('1', '54', '1299', '0'), +('1', '55', '1359', '0'), +('1', '56', '1421', '0'), +('1', '57', '1485', '0'), +('1', '58', '1551', '0'), +('1', '59', '1619', '0'), +('1', '60', '1689', '0'), +('1', '61', '1902', '0'), +('1', '62', '2129', '0'), +('1', '63', '2357', '0'), +('1', '64', '2612', '0'), +('1', '65', '2883', '0'), +('1', '66', '3169', '0'), +('1', '67', '3455', '0'), +('1', '68', '3774', '0'), +('1', '69', '4109', '0'), +('1', '70', '4444', '0'), +('2', '1', '28', '60'), +('2', '2', '36', '78'), +('2', '3', '44', '98'), +('2', '4', '52', '104'), +('2', '5', '60', '111'), +('2', '6', '68', '134'), +('2', '7', '76', '143'), +('2', '8', '84', '153'), +('2', '9', '92', '179'), +('2', '10', '100', '192'), +('2', '11', '108', '205'), +('2', '12', '116', '219'), +('2', '13', '124', '249'), +('2', '14', '132', '265'), +('2', '15', '131', '282'), +('2', '16', '141', '315'), +('2', '17', '152', '334'), +('2', '18', '164', '354'), +('2', '19', '177', '390'), +('2', '20', '191', '412'), +('2', '21', '206', '435'), +('2', '22', '222', '459'), +('2', '23', '239', '499'), +('2', '24', '247', '525'), +('2', '25', '266', '552'), +('2', '26', '286', '579'), +('2', '27', '307', '621'), +('2', '28', '329', '648'), +('2', '29', '342', '675'), +('2', '30', '366', '702'), +('2', '31', '391', '729'), +('2', '32', '407', '756'), +('2', '33', '434', '798'), +('2', '34', '462', '825'), +('2', '35', '481', '852'), +('2', '36', '511', '879'), +('2', '37', '542', '906'), +('2', '38', '564', '933'), +('2', '39', '597', '960'), +('2', '40', '621', '987'), +('2', '41', '656', '1014'), +('2', '42', '682', '1041'), +('2', '43', '719', '1068'), +('2', '44', '747', '1110'), +('2', '45', '786', '1137'), +('2', '46', '816', '1164'), +('2', '47', '857', '1176'), +('2', '48', '889', '1203'), +('2', '49', '922', '1230'), +('2', '50', '966', '1257'), +('2', '51', '1001', '1284'), +('2', '52', '1037', '1311'), +('2', '53', '1084', '1338'), +('2', '54', '1122', '1365'), +('2', '55', '1161', '1392'), +('2', '56', '1201', '1419'), +('2', '57', '1252', '1446'), +('2', '58', '1294', '1458'), +('2', '59', '1337', '1485'), +('2', '60', '1381', '1512'), +('2', '61', '1540', '1656'), +('2', '62', '1708', '1800'), +('2', '63', '1884', '1944'), +('2', '64', '2068', '2088'), +('2', '65', '2262', '2232'), +('2', '66', '2466', '2377'), +('2', '67', '2679', '2521'), +('2', '68', '2901', '2665'), +('2', '69', '3134', '2809'), +('2', '70', '3377', '2953'), +('3', '1', '46', '65'), +('3', '2', '53', '70'), +('3', '3', '60', '76'), +('3', '4', '67', '98'), +('3', '5', '74', '106'), +('3', '6', '81', '130'), +('3', '7', '88', '140'), +('3', '8', '95', '166'), +('3', '9', '102', '193'), +('3', '10', '109', '206'), +('3', '11', '116', '235'), +('3', '12', '123', '250'), +('3', '13', '130', '266'), +('3', '14', '138', '298'), +('3', '15', '147', '316'), +('3', '16', '157', '350'), +('3', '17', '168', '370'), +('3', '18', '180', '391'), +('3', '19', '193', '428'), +('3', '20', '207', '451'), +('3', '21', '222', '475'), +('3', '22', '238', '515'), +('3', '23', '255', '541'), +('3', '24', '273', '568'), +('3', '25', '292', '611'), +('3', '26', '312', '640'), +('3', '27', '333', '670'), +('3', '28', '355', '715'), +('3', '29', '378', '745'), +('3', '30', '402', '775'), +('3', '31', '417', '805'), +('3', '32', '443', '850'), +('3', '33', '470', '880'), +('3', '34', '498', '910'), +('3', '35', '527', '940'), +('3', '36', '547', '970'), +('3', '37', '578', '1015'), +('3', '38', '610', '1045'), +('3', '39', '643', '1075'), +('3', '40', '667', '1105'), +('3', '41', '702', '1135'), +('3', '42', '738', '1180'), +('3', '43', '775', '1210'), +('3', '44', '803', '1240'), +('3', '45', '842', '1270'), +('3', '46', '872', '1300'), +('3', '47', '913', '1330'), +('3', '48', '955', '1360'), +('3', '49', '994', '1390'), +('3', '50', '1047', '1420'), +('3', '51', '1067', '1450'), +('3', '52', '1113', '1480'), +('3', '53', '1150', '1510'), +('3', '54', '1198', '1540'), +('3', '55', '1237', '1570'), +('3', '56', '1287', '1600'), +('3', '57', '1328', '1630'), +('3', '58', '1370', '1660'), +('3', '59', '1423', '1690'), +('3', '60', '1467', '1720'), +('3', '61', '1633', '1886'), +('3', '62', '1819', '2053'), +('3', '63', '2003', '2219'), +('3', '64', '2195', '2385'), +('3', '65', '2397', '2552'), +('3', '66', '2623', '2718'), +('3', '67', '2844', '2884'), +('3', '68', '3075', '3050'), +('3', '69', '3316', '3217'), +('3', '70', '3568', '3383'), +('4', '1', '25', '0'), +('4', '2', '32', '0'), +('4', '3', '49', '0'), +('4', '4', '56', '0'), +('4', '5', '63', '0'), +('4', '6', '70', '0'), +('4', '7', '87', '0'), +('4', '8', '94', '0'), +('4', '9', '101', '0'), +('4', '10', '118', '0'), +('4', '11', '125', '0'), +('4', '12', '142', '0'), +('4', '13', '149', '0'), +('4', '14', '156', '0'), +('4', '15', '173', '0'), +('4', '16', '181', '0'), +('4', '17', '190', '0'), +('4', '18', '200', '0'), +('4', '19', '221', '0'), +('4', '20', '233', '0'), +('4', '21', '246', '0'), +('4', '22', '260', '0'), +('4', '23', '275', '0'), +('4', '24', '301', '0'), +('4', '25', '318', '0'), +('4', '26', '336', '0'), +('4', '27', '355', '0'), +('4', '28', '375', '0'), +('4', '29', '396', '0'), +('4', '30', '428', '0'), +('4', '31', '451', '0'), +('4', '32', '475', '0'), +('4', '33', '500', '0'), +('4', '34', '526', '0'), +('4', '35', '553', '0'), +('4', '36', '581', '0'), +('4', '37', '610', '0'), +('4', '38', '640', '0'), +('4', '39', '671', '0'), +('4', '40', '703', '0'), +('4', '41', '736', '0'), +('4', '42', '770', '0'), +('4', '43', '805', '0'), +('4', '44', '841', '0'), +('4', '45', '878', '0'), +('4', '46', '916', '0'), +('4', '47', '955', '0'), +('4', '48', '995', '0'), +('4', '49', '1026', '0'), +('4', '50', '1068', '0'), +('4', '51', '1111', '0'), +('4', '52', '1155', '0'), +('4', '53', '1200', '0'), +('4', '54', '1246', '0'), +('4', '55', '1283', '0'), +('4', '56', '1331', '0'), +('4', '57', '1380', '0'), +('4', '58', '1430', '0'), +('4', '59', '1471', '0'), +('4', '60', '1523', '0'), +('4', '61', '1702', '0'), +('4', '62', '1879', '0'), +('4', '63', '2077', '0'), +('4', '64', '2285', '0'), +('4', '65', '2489', '0'), +('4', '66', '2717', '0'), +('4', '67', '2941', '0'), +('4', '68', '3190', '0'), +('4', '69', '3450', '0'), +('4', '70', '3704', '0'), +('5', '1', '52', '73'), +('5', '2', '57', '76'), +('5', '3', '72', '95'), +('5', '4', '77', '114'), +('5', '5', '92', '133'), +('5', '6', '97', '152'), +('5', '7', '112', '171'), +('5', '8', '117', '190'), +('5', '9', '132', '209'), +('5', '10', '137', '212'), +('5', '11', '142', '215'), +('5', '12', '157', '234'), +('5', '13', '172', '254'), +('5', '14', '177', '260'), +('5', '15', '192', '282'), +('5', '16', '197', '305'), +('5', '17', '212', '329'), +('5', '18', '227', '339'), +('5', '19', '232', '365'), +('5', '20', '247', '377'), +('5', '21', '252', '405'), +('5', '22', '268', '434'), +('5', '23', '275', '449'), +('5', '24', '293', '480'), +('5', '25', '302', '497'), +('5', '26', '322', '530'), +('5', '27', '343', '549'), +('5', '28', '355', '584'), +('5', '29', '378', '605'), +('5', '30', '392', '627'), +('5', '31', '417', '665'), +('5', '32', '433', '689'), +('5', '33', '460', '728'), +('5', '34', '478', '752'), +('5', '35', '507', '776'), +('5', '36', '527', '800'), +('5', '37', '548', '839'), +('5', '38', '580', '863'), +('5', '39', '603', '887'), +('5', '40', '637', '911'), +('5', '41', '662', '950'), +('5', '42', '698', '974'), +('5', '43', '725', '998'), +('5', '44', '763', '1022'), +('5', '45', '792', '1046'), +('5', '46', '822', '1070'), +('5', '47', '863', '1094'), +('5', '48', '895', '1118'), +('5', '49', '928', '1142'), +('5', '50', '972', '1166'), +('5', '51', '1007', '1190'), +('5', '52', '1053', '1214'), +('5', '53', '1090', '1238'), +('5', '54', '1128', '1262'), +('5', '55', '1177', '1271'), +('5', '56', '1217', '1295'), +('5', '57', '1258', '1319'), +('5', '58', '1300', '1343'), +('5', '59', '1353', '1352'), +('5', '60', '1397', '1376'), +('5', '61', '1557', '1500'), +('5', '62', '1738', '1625'), +('5', '63', '1916', '1749'), +('5', '64', '2101', '1873'), +('5', '65', '2295', '1998'), +('5', '66', '2495', '2122'), +('5', '67', '2719', '2247'), +('5', '68', '2936', '2371'), +('5', '69', '3160', '2495'), +('5', '70', '3391', '2620'), +('7', '80', '6939', '4396'), +('7', '79', '6457', '4252'), +('7', '78', '6009', '4108'), +('7', '77', '5592', '3965'), +('7', '76', '5203', '3821'), +('7', '75', '4843', '3677'), +('7', '74', '4507', '3533'), +('7', '73', '4194', '3389'), +('7', '72', '3903', '3246'), +('7', '71', '3633', '3102'), +('7', '70', '3380', '2958'), +('7', '69', '3136', '2814'), +('7', '68', '2903', '2670'), +('7', '67', '2679', '2527'), +('7', '66', '2465', '2383'), +('7', '65', '2262', '2239'), +('7', '64', '2067', '2095'), +('7', '63', '1883', '1951'), +('7', '62', '1694', '1808'), +('7', '61', '1528', '1664'), +('7', '60', '1423', '1520'), +('7', '59', '1326', '1501'), +('7', '58', '1283', '1467'), +('7', '57', '1231', '1448'), +('7', '56', '1190', '1414'), +('7', '55', '1150', '1395'), +('7', '54', '1101', '1376'), +('7', '53', '1064', '1342'), +('7', '52', '1027', '1323'), +('7', '51', '981', '1289'), +('7', '50', '947', '1255'), +('7', '49', '903', '1236'), +('7', '48', '871', '1202'), +('7', '47', '829', '1183'), +('7', '46', '799', '1149'), +('7', '45', '760', '1115'), +('7', '44', '732', '1096'), +('7', '43', '694', '1062'), +('7', '42', '669', '1028'), +('7', '41', '633', '1009'), +('7', '40', '610', '975'), +('7', '39', '577', '941'), +('7', '38', '545', '922'), +('7', '37', '524', '888'), +('7', '36', '494', '854'), +('7', '35', '465', '820'), +('7', '34', '448', '786'), +('7', '33', '422', '767'), +('7', '32', '396', '733'), +('7', '31', '371', '699'), +('7', '30', '358', '665'), +('7', '29', '336', '631'), +('7', '28', '315', '598'), +('7', '27', '294', '566'), +('7', '26', '275', '535'), +('7', '25', '257', '505'), +('7', '24', '250', '476'), +('7', '23', '234', '448'), +('7', '22', '219', '421'), +('7', '21', '205', '395'), +('7', '20', '193', '370'), +('7', '19', '181', '346'), +('7', '18', '170', '323'), +('7', '17', '161', '301'), +('7', '16', '152', '280'), +('7', '15', '144', '260'), +('7', '14', '137', '241'), +('7', '13', '129', '223'), +('7', '12', '122', '206'), +('7', '11', '114', '190'), +('8', '1', '32', '100'), +('8', '2', '47', '110'), +('8', '3', '52', '106'), +('8', '4', '67', '118'), +('8', '5', '82', '131'), +('8', '6', '97', '130'), +('8', '7', '102', '145'), +('8', '8', '117', '146'), +('8', '9', '132', '163'), +('8', '10', '137', '196'), +('8', '11', '152', '215'), +('8', '12', '167', '220'), +('8', '13', '172', '241'), +('8', '14', '187', '263'), +('8', '15', '202', '271'), +('8', '16', '207', '295'), +('8', '17', '222', '305'), +('8', '18', '237', '331'), +('8', '19', '242', '343'), +('8', '20', '257', '371'), +('8', '21', '272', '385'), +('8', '22', '277', '415'), +('8', '23', '292', '431'), +('8', '24', '298', '463'), +('8', '25', '315', '481'), +('8', '26', '333', '515'), +('8', '27', '342', '535'), +('8', '28', '362', '556'), +('8', '29', '373', '592'), +('8', '30', '395', '613'), +('8', '31', '418', '634'), +('8', '32', '432', '670'), +('8', '33', '457', '691'), +('8', '34', '473', '712'), +('8', '35', '500', '733'), +('8', '36', '518', '754'), +('8', '37', '547', '790'), +('8', '38', '577', '811'), +('8', '39', '598', '832'), +('8', '40', '630', '853'), +('8', '41', '653', '874'), +('8', '42', '687', '895'), +('8', '43', '712', '916'), +('8', '44', '748', '937'), +('8', '45', '775', '958'), +('8', '46', '813', '979'), +('8', '47', '842', '1000'), +('8', '48', '882', '1021'), +('8', '49', '913', '1042'), +('8', '50', '955', '1048'), +('8', '51', '988', '1069'), +('8', '52', '1032', '1090'), +('8', '53', '1067', '1111'), +('8', '54', '1103', '1117'), +('8', '55', '1150', '1138'), +('8', '56', '1188', '1159'), +('8', '57', '1237', '1165'), +('8', '58', '1277', '1186'), +('8', '59', '1328', '1192'), +('8', '60', '1370', '1213'), +('8', '61', '1526', '1316'), +('8', '62', '1702', '1419'), +('8', '63', '1875', '1521'), +('8', '64', '2070', '1624'), +('8', '65', '2261', '1727'), +('8', '66', '2461', '1830'), +('8', '67', '2686', '1932'), +('8', '68', '2906', '2035'), +('8', '69', '3136', '2138'), +('8', '70', '3393', '2241'), +('9', '1', '23', '90'), +('9', '2', '28', '98'), +('9', '3', '43', '107'), +('9', '4', '48', '102'), +('9', '5', '63', '113'), +('9', '6', '68', '126'), +('9', '7', '83', '144'), +('9', '8', '88', '162'), +('9', '9', '93', '180'), +('9', '10', '108', '198'), +('9', '11', '123', '200'), +('9', '12', '128', '218'), +('9', '13', '143', '237'), +('9', '14', '148', '257'), +('9', '15', '153', '278'), +('9', '16', '168', '300'), +('9', '17', '173', '308'), +('9', '18', '189', '332'), +('9', '19', '196', '357'), +('9', '20', '204', '383'), +('9', '21', '223', '395'), +('9', '22', '233', '423'), +('9', '23', '244', '452'), +('9', '24', '266', '467'), +('9', '25', '279', '498'), +('9', '26', '293', '530'), +('9', '27', '318', '548'), +('9', '28', '334', '582'), +('9', '29', '351', '602'), +('9', '30', '379', '638'), +('9', '31', '398', '674'), +('9', '32', '418', '695'), +('9', '33', '439', '731'), +('9', '34', '471', '752'), +('9', '35', '494', '788'), +('9', '36', '518', '809'), +('9', '37', '543', '830'), +('9', '38', '569', '866'), +('9', '39', '606', '887'), +('9', '40', '634', '923'), +('9', '41', '663', '944'), +('9', '42', '693', '965'), +('9', '43', '724', '1001'), +('9', '44', '756', '1022'), +('9', '45', '799', '1043'), +('9', '46', '832', '1064'), +('9', '47', '868', '1100'), +('9', '48', '904', '1121'), +('9', '49', '941', '1142'), +('9', '50', '979', '1163'), +('9', '51', '1018', '1184'), +('9', '52', '1058', '1205'), +('9', '53', '1099', '1226'), +('9', '54', '1141', '1247'), +('9', '55', '1184', '1268'), +('9', '56', '1228', '1289'), +('9', '57', '1273', '1310'), +('9', '58', '1319', '1331'), +('9', '59', '1366', '1352'), +('9', '60', '1414', '1373'), +('9', '61', '1580', '1497'), +('9', '62', '1755', '1621'), +('9', '63', '1939', '1745'), +('9', '64', '2133', '1870'), +('9', '65', '2323', '1994'), +('9', '66', '2535', '2118'), +('9', '67', '2758', '2242'), +('9', '68', '2991', '2366'), +('9', '69', '3235', '2490'), +('9', '70', '3490', '2615'), +('11', '1', '44', '60'), +('11', '2', '51', '66'), +('11', '3', '58', '73'), +('11', '4', '75', '81'), +('11', '5', '82', '90'), +('11', '6', '89', '100'), +('11', '7', '106', '111'), +('11', '8', '113', '123'), +('11', '9', '120', '136'), +('11', '10', '137', '150'), +('11', '11', '144', '165'), +('11', '12', '151', '182'), +('11', '13', '168', '200'), +('11', '14', '175', '219'), +('11', '15', '182', '239'), +('11', '16', '199', '260'), +('11', '17', '206', '282'), +('11', '18', '214', '305'), +('11', '19', '233', '329'), +('11', '20', '243', '354'), +('11', '21', '254', '380'), +('11', '22', '266', '392'), +('11', '23', '289', '420'), +('11', '24', '303', '449'), +('11', '25', '318', '479'), +('11', '26', '334', '509'), +('11', '27', '361', '524'), +('11', '28', '379', '554'), +('11', '29', '398', '584'), +('11', '30', '418', '614'), +('11', '31', '439', '629'), +('11', '32', '461', '659'), +('11', '33', '494', '689'), +('11', '34', '518', '704'), +('11', '35', '543', '734'), +('11', '36', '569', '749'), +('11', '37', '596', '779'), +('11', '38', '624', '809'), +('11', '39', '653', '824'), +('11', '40', '683', '854'), +('11', '41', '714', '869'), +('11', '42', '746', '899'), +('11', '43', '779', '914'), +('11', '44', '823', '944'), +('11', '45', '858', '959'), +('11', '46', '894', '989'), +('11', '47', '921', '1004'), +('11', '48', '959', '1019'), +('11', '49', '998', '1049'), +('11', '50', '1038', '1064'), +('11', '51', '1079', '1079'), +('11', '52', '1121', '1109'), +('11', '53', '1164', '1124'), +('11', '54', '1208', '1139'), +('11', '55', '1253', '1154'), +('11', '56', '1299', '1169'), +('11', '57', '1346', '1199'), +('11', '58', '1384', '1214'), +('11', '59', '1433', '1229'), +('11', '60', '1483', '1244'), +('11', '61', '1657', '1357'), +('11', '62', '1840', '1469'), +('11', '63', '2020', '1582'), +('11', '64', '2222', '1694'), +('11', '65', '2433', '1807'), +('11', '66', '2640', '1919'), +('11', '67', '2872', '2032'), +('11', '68', '3114', '2145'), +('11', '69', '3351', '2257'), +('11', '70', '3614', '2370'), +('1', '71', '4720', '0'), +('1', '72', '5013', '0'), +('1', '73', '5325', '0'), +('1', '74', '5656', '0'), +('1', '75', '6008', '0'), +('1', '76', '6381', '0'), +('1', '77', '6778', '0'), +('1', '78', '7198', '0'), +('1', '79', '7646', '0'), +('1', '80', '8121', '0'), +('2', '71', '3629', '3097'), +('2', '72', '3900', '3241'), +('2', '73', '4191', '3385'), +('2', '74', '4503', '3529'), +('2', '75', '4839', '3673'), +('2', '76', '5200', '3817'), +('2', '77', '5588', '3962'), +('2', '78', '6005', '4106'), +('2', '79', '6453', '4250'), +('2', '80', '6934', '4394'), +('3', '71', '3834', '3549'), +('3', '72', '4120', '3716'), +('3', '73', '4427', '3882'), +('3', '74', '4757', '4048'), +('3', '75', '5112', '4215'), +('3', '76', '5493', '4381'), +('3', '77', '5903', '4547'), +('3', '78', '6343', '4713'), +('3', '79', '6816', '4880'), +('3', '80', '7324', '5046'), +('4', '71', '3980', '0'), +('4', '72', '4277', '0'), +('4', '73', '4596', '0'), +('4', '74', '4939', '0'), +('4', '75', '5307', '0'), +('4', '76', '5703', '0'), +('4', '77', '6128', '0'), +('4', '78', '6585', '0'), +('4', '79', '7076', '0'), +('4', '80', '7604', '0'), +('5', '71', '3644', '2744'), +('5', '72', '3916', '2868'), +('5', '73', '4208', '2993'), +('5', '74', '4522', '3117'), +('5', '75', '4859', '3242'), +('5', '76', '5221', '3366'), +('5', '77', '5610', '3490'), +('5', '78', '6028', '3615'), +('5', '79', '6477', '3739'), +('5', '80', '6960', '3863'), +('6', '1', '22', '0'), +('6', '2', '27', '0'), +('6', '3', '32', '0'), +('6', '4', '37', '0'), +('6', '5', '42', '0'), +('6', '6', '47', '0'), +('6', '7', '52', '0'), +('6', '8', '58', '0'), +('6', '9', '64', '0'), +('6', '10', '70', '0'), +('6', '11', '77', '0'), +('6', '12', '84', '0'), +('6', '13', '92', '0'), +('6', '14', '100', '0'), +('6', '15', '117', '0'), +('6', '16', '127', '0'), +('6', '17', '138', '0'), +('6', '18', '150', '0'), +('6', '19', '163', '0'), +('6', '20', '177', '0'), +('6', '21', '192', '0'), +('6', '22', '208', '0'), +('6', '23', '225', '0'), +('6', '24', '239', '0'), +('6', '25', '258', '0'), +('6', '26', '278', '0'), +('6', '27', '299', '0'), +('6', '28', '321', '0'), +('6', '29', '344', '0'), +('6', '30', '368', '0'), +('6', '31', '393', '0'), +('6', '32', '419', '0'), +('6', '33', '446', '0'), +('6', '34', '474', '0'), +('6', '35', '503', '0'), +('6', '36', '533', '0'), +('6', '37', '564', '0'), +('6', '38', '596', '0'), +('6', '39', '629', '0'), +('6', '40', '698', '0'), +('6', '41', '698', '0'), +('6', '42', '734', '0'), +('6', '43', '771', '0'), +('6', '44', '809', '0'), +('6', '45', '849', '0'), +('6', '46', '891', '0'), +('6', '47', '935', '0'), +('6', '48', '981', '0'), +('6', '49', '1029', '0'), +('6', '50', '1079', '0'), +('6', '51', '1131', '0'), +('6', '52', '1185', '0'), +('6', '53', '1241', '0'), +('6', '54', '1299', '0'), +('6', '55', '1359', '0'), +('6', '56', '1421', '0'), +('6', '57', '1485', '0'), +('6', '58', '1551', '0'), +('6', '59', '1619', '0'), +('6', '60', '1689', '0'), +('6', '61', '1902', '0'), +('6', '62', '2129', '0'), +('6', '63', '2357', '0'), +('6', '64', '2612', '0'), +('6', '65', '2883', '0'), +('6', '66', '3169', '0'), +('6', '67', '3455', '0'), +('6', '68', '3774', '0'), +('6', '69', '4109', '0'), +('6', '70', '4444', '0'), +('6', '71', '4720', '0'), +('6', '72', '5013', '0'), +('6', '73', '5325', '0'), +('6', '74', '5656', '0'), +('6', '75', '6008', '0'), +('6', '76', '6381', '0'), +('6', '77', '6778', '0'), +('6', '78', '7199', '0'), +('6', '79', '7646', '0'), +('6', '80', '8121', '0'), +('7', '10', '107', '175'), +('7', '9', '100', '161'), +('7', '8', '92', '148'), +('7', '7', '85', '136'), +('7', '6', '77', '125'), +('7', '5', '70', '115'), +('7', '4', '62', '106'), +('7', '3', '55', '98'), +('7', '2', '47', '91'), +('7', '1', '40', '85'), +('8', '71', '3646', '2343'), +('8', '72', '3918', '2446'), +('8', '73', '4210', '2549'), +('8', '74', '4524', '2652'), +('8', '75', '4861', '2754'), +('8', '76', '5223', '2857'), +('8', '77', '5612', '2960'), +('8', '78', '6030', '3063'), +('8', '79', '6480', '3165'), +('8', '80', '6963', '3268'), +('9', '71', '3750', '2739'), +('9', '72', '4025', '2863'), +('9', '73', '4330', '2987'), +('9', '74', '4646', '3111'), +('9', '75', '4997', '3235'), +('9', '76', '5373', '3360'), +('9', '77', '5774', '3483'), +('9', '78', '6207', '3608'), +('9', '79', '6667', '3732'), +('9', '80', '7136', '3856'), +('11', '71', '3883', '2482'), +('11', '72', '4172', '2595'), +('11', '73', '4483', '2708'), +('11', '74', '4817', '2820'), +('11', '75', '5176', '2933'), +('11', '76', '5562', '3045'), +('11', '77', '5977', '3158'), +('11', '78', '6423', '3270'), +('11', '79', '6902', '3383'), +('11', '80', '7417', '3496'); + +-- player_levelstats + +INSERT IGNORE INTO `player_levelstats` VALUES +('1', '1', '1', '23', '20', '22', '20', '20'), +('1', '1', '2', '24', '21', '23', '20', '20'), +('1', '1', '3', '26', '22', '24', '20', '21'), +('1', '1', '4', '27', '22', '26', '20', '21'), +('1', '1', '5', '28', '23', '27', '20', '21'), +('1', '1', '6', '30', '24', '28', '20', '21'), +('1', '1', '7', '31', '25', '29', '21', '22'), +('1', '1', '8', '32', '26', '30', '21', '22'), +('1', '1', '9', '34', '26', '32', '21', '22'), +('1', '1', '10', '35', '27', '33', '21', '23'), +('1', '1', '11', '36', '28', '34', '21', '23'), +('1', '1', '12', '38', '29', '35', '21', '23'), +('1', '1', '13', '39', '30', '37', '21', '24'), +('1', '1', '14', '41', '31', '38', '21', '24'), +('1', '1', '15', '42', '32', '39', '21', '24'), +('1', '1', '16', '44', '33', '41', '21', '25'), +('1', '1', '17', '45', '34', '42', '22', '25'), +('1', '1', '18', '47', '34', '43', '22', '25'), +('1', '1', '19', '48', '35', '45', '22', '26'), +('1', '1', '20', '50', '36', '46', '22', '26'), +('1', '1', '21', '51', '37', '48', '22', '26'), +('1', '1', '22', '53', '38', '49', '22', '27'), +('1', '1', '23', '54', '39', '51', '22', '27'), +('1', '1', '24', '56', '40', '52', '23', '28'), +('1', '1', '25', '58', '41', '53', '23', '28'), +('1', '1', '26', '59', '42', '55', '23', '28'), +('1', '1', '27', '61', '43', '56', '23', '29'), +('1', '1', '28', '63', '44', '58', '23', '29'), +('1', '1', '29', '64', '45', '59', '23', '30'), +('1', '1', '30', '66', '46', '61', '24', '30'), +('1', '1', '31', '68', '47', '62', '24', '30'), +('1', '1', '32', '69', '48', '64', '24', '31'), +('1', '1', '33', '71', '50', '66', '24', '31'), +('1', '1', '34', '73', '51', '67', '24', '32'), +('1', '1', '35', '74', '52', '69', '24', '32'), +('1', '1', '36', '76', '53', '70', '25', '33'), +('1', '1', '37', '78', '54', '72', '25', '33'), +('1', '1', '38', '80', '55', '74', '25', '34'), +('1', '1', '39', '82', '56', '75', '25', '34'), +('1', '1', '40', '83', '57', '77', '25', '35'), +('1', '1', '41', '85', '58', '79', '26', '35'), +('1', '1', '42', '87', '60', '80', '26', '35'), +('1', '1', '43', '89', '61', '82', '26', '36'), +('1', '1', '44', '91', '62', '84', '26', '36'), +('1', '1', '45', '93', '63', '85', '26', '37'), +('1', '1', '46', '95', '64', '87', '27', '37'), +('1', '1', '47', '97', '66', '89', '27', '38'), +('1', '1', '48', '99', '67', '91', '27', '38'), +('1', '1', '49', '101', '68', '93', '27', '39'), +('1', '1', '50', '103', '69', '94', '28', '40'), +('1', '1', '51', '105', '71', '96', '28', '40'), +('1', '1', '52', '107', '72', '98', '28', '41'), +('1', '1', '53', '109', '73', '100', '28', '41'), +('1', '1', '54', '111', '74', '102', '29', '42'), +('1', '1', '55', '113', '76', '103', '29', '42'), +('1', '1', '56', '115', '77', '105', '29', '43'), +('1', '1', '57', '117', '78', '107', '29', '43'), +('1', '1', '58', '119', '79', '109', '30', '44'), +('1', '1', '59', '121', '81', '111', '30', '44'), +('1', '1', '60', '123', '82', '113', '30', '45'), +('1', '1', '61', '125', '83', '115', '30', '46'), +('1', '1', '62', '127', '85', '117', '31', '46'), +('1', '1', '63', '129', '86', '119', '31', '47'), +('1', '1', '64', '132', '88', '121', '31', '47'), +('1', '1', '65', '134', '89', '123', '32', '48'), +('1', '1', '66', '136', '90', '125', '32', '49'), +('1', '1', '67', '138', '92', '127', '32', '49'), +('1', '1', '68', '140', '93', '129', '32', '50'), +('1', '1', '69', '143', '95', '131', '33', '50'), +('1', '1', '70', '145', '96', '133', '33', '51'), +('1', '1', '71', '148', '97', '140', '33', '53'), +('1', '1', '72', '156', '99', '143', '33', '54'), +('1', '1', '73', '162', '101', '148', '33', '55'), +('1', '1', '74', '162', '102', '148', '34', '55'), +('1', '1', '75', '165', '104', '150', '34', '56'), +('1', '1', '76', '171', '106', '156', '34', '57'), +('1', '1', '77', '171', '108', '157', '35', '58'), +('1', '1', '78', '174', '109', '159', '35', '58'), +('1', '1', '79', '181', '111', '165', '35', '59'), +('1', '1', '80', '184', '113', '168', '36', '60'), +('1', '2', '1', '22', '20', '22', '20', '21'), +('1', '2', '2', '23', '21', '23', '21', '22'), +('1', '2', '3', '24', '21', '24', '21', '22'), +('1', '2', '4', '25', '22', '25', '22', '23'), +('1', '2', '5', '26', '22', '26', '23', '24'), +('1', '2', '6', '28', '23', '27', '23', '25'), +('1', '2', '7', '29', '24', '28', '24', '25'), +('1', '2', '8', '30', '24', '29', '25', '26'), +('1', '2', '9', '31', '25', '30', '25', '27'), +('1', '2', '10', '32', '25', '32', '26', '27'), +('1', '2', '11', '33', '26', '33', '27', '28'), +('1', '2', '12', '35', '27', '34', '27', '29'), +('1', '2', '13', '36', '27', '35', '28', '30'), +('1', '2', '14', '37', '28', '36', '29', '31'), +('1', '2', '15', '38', '29', '37', '30', '31'), +('1', '2', '16', '40', '29', '38', '30', '32'), +('1', '2', '17', '41', '30', '40', '31', '33'), +('1', '2', '18', '42', '31', '41', '32', '34'), +('1', '2', '19', '43', '31', '42', '33', '35'), +('1', '2', '20', '45', '32', '43', '33', '35'), +('1', '2', '21', '46', '33', '45', '34', '36'), +('1', '2', '22', '47', '33', '46', '35', '37'), +('1', '2', '23', '49', '34', '47', '36', '38'), +('1', '2', '24', '50', '35', '48', '37', '39'), +('1', '2', '25', '51', '36', '50', '37', '40'), +('1', '2', '26', '53', '36', '51', '38', '41'), +('1', '2', '27', '54', '37', '52', '39', '42'), +('1', '2', '28', '56', '38', '54', '40', '43'), +('1', '2', '29', '57', '39', '55', '41', '43'), +('1', '2', '30', '58', '39', '56', '42', '44'), +('1', '2', '31', '60', '40', '58', '43', '45'), +('1', '2', '32', '61', '41', '59', '43', '46'), +('1', '2', '33', '63', '42', '60', '44', '47'), +('1', '2', '34', '64', '43', '62', '45', '48'), +('1', '2', '35', '66', '44', '63', '46', '49'), +('1', '2', '36', '67', '44', '65', '47', '50'), +('1', '2', '37', '69', '45', '66', '48', '51'), +('1', '2', '38', '70', '46', '67', '49', '52'), +('1', '2', '39', '72', '47', '69', '50', '53'), +('1', '2', '40', '73', '48', '70', '51', '54'), +('1', '2', '41', '75', '49', '72', '52', '55'), +('1', '2', '42', '77', '49', '73', '53', '56'), +('1', '2', '43', '78', '50', '75', '54', '57'), +('1', '2', '44', '80', '51', '76', '55', '58'), +('1', '2', '45', '81', '52', '78', '56', '59'), +('1', '2', '46', '83', '53', '79', '57', '61'), +('1', '2', '47', '85', '54', '81', '58', '62'), +('1', '2', '48', '86', '55', '83', '59', '63'), +('1', '2', '49', '88', '56', '84', '60', '64'), +('1', '2', '50', '90', '57', '86', '61', '65'), +('1', '2', '51', '91', '58', '87', '62', '66'), +('1', '2', '52', '93', '59', '89', '63', '67'), +('1', '2', '53', '95', '60', '91', '64', '68'), +('1', '2', '54', '97', '61', '92', '65', '69'), +('1', '2', '55', '98', '61', '94', '66', '71'), +('1', '2', '56', '100', '62', '95', '67', '72'), +('1', '2', '57', '102', '63', '97', '68', '73'), +('1', '2', '58', '104', '64', '99', '69', '74'), +('1', '2', '59', '105', '65', '101', '70', '75'), +('1', '2', '60', '107', '66', '102', '71', '77'), +('1', '2', '61', '109', '67', '104', '73', '78'), +('1', '2', '62', '111', '69', '106', '74', '79'), +('1', '2', '63', '113', '70', '107', '75', '80'), +('1', '2', '64', '115', '71', '109', '76', '81'), +('1', '2', '65', '116', '72', '111', '77', '83'), +('1', '2', '66', '118', '73', '113', '78', '84'), +('1', '2', '67', '120', '74', '115', '79', '85'), +('1', '2', '68', '122', '75', '116', '81', '86'), +('1', '2', '69', '124', '76', '118', '82', '88'), +('1', '2', '70', '126', '77', '120', '83', '89'), +('1', '2', '71', '148', '78', '122', '84', '92'), +('1', '2', '72', '150', '79', '125', '86', '94'), +('1', '2', '73', '152', '80', '127', '87', '96'), +('1', '2', '74', '156', '82', '129', '89', '97'), +('1', '2', '75', '158', '83', '131', '90', '99'), +('1', '2', '76', '162', '84', '134', '92', '100'), +('1', '2', '77', '164', '86', '136', '93', '103'), +('1', '2', '78', '167', '87', '138', '95', '105'), +('1', '2', '79', '170', '88', '153', '96', '106'), +('1', '2', '80', '173', '90', '160', '98', '108'), +('1', '4', '1', '21', '23', '21', '20', '20'), +('1', '4', '2', '22', '24', '22', '20', '20'), +('1', '4', '3', '23', '26', '22', '20', '21'), +('1', '4', '4', '23', '27', '23', '20', '21'), +('1', '4', '5', '24', '29', '24', '21', '21'), +('1', '4', '6', '25', '30', '25', '21', '22'), +('1', '4', '7', '26', '32', '25', '21', '22'), +('1', '4', '8', '26', '33', '26', '21', '23'), +('1', '4', '9', '27', '35', '27', '21', '23'), +('1', '4', '10', '28', '36', '27', '21', '23'), +('1', '4', '11', '29', '38', '28', '22', '24'), +('1', '4', '12', '30', '39', '29', '22', '24'), +('1', '4', '13', '31', '41', '30', '22', '25'), +('1', '4', '14', '31', '43', '31', '22', '25'), +('1', '4', '15', '32', '44', '31', '22', '25'), +('1', '4', '16', '33', '46', '32', '23', '26'), +('1', '4', '17', '34', '48', '33', '23', '26'), +('1', '4', '18', '35', '49', '34', '23', '27'), +('1', '4', '19', '36', '51', '35', '23', '27'), +('1', '4', '20', '37', '53', '35', '23', '28'), +('1', '4', '21', '38', '54', '36', '24', '28'), +('1', '4', '22', '39', '56', '37', '24', '29'), +('1', '4', '23', '40', '58', '38', '24', '29'), +('1', '4', '24', '41', '60', '39', '24', '30'), +('1', '4', '25', '42', '61', '40', '25', '30'), +('1', '4', '26', '43', '63', '41', '25', '31'), +('1', '4', '27', '44', '65', '42', '25', '31'), +('1', '4', '28', '45', '67', '43', '25', '32'), +('1', '4', '29', '46', '69', '43', '25', '32'), +('1', '4', '30', '47', '71', '44', '26', '33'), +('1', '4', '31', '48', '72', '45', '26', '33'), +('1', '4', '32', '49', '74', '46', '26', '34'), +('1', '4', '33', '50', '76', '47', '27', '34'), +('1', '4', '34', '51', '78', '48', '27', '35'), +('1', '4', '35', '52', '80', '49', '27', '35'), +('1', '4', '36', '53', '82', '50', '27', '36'), +('1', '4', '37', '54', '84', '51', '28', '36'), +('1', '4', '38', '55', '86', '52', '28', '37'), +('1', '4', '39', '56', '88', '53', '28', '38'), +('1', '4', '40', '57', '90', '54', '28', '38'), +('1', '4', '41', '58', '92', '55', '29', '39'), +('1', '4', '42', '60', '94', '56', '29', '39'), +('1', '4', '43', '61', '96', '57', '29', '40'), +('1', '4', '44', '62', '98', '58', '30', '40'), +('1', '4', '45', '63', '100', '59', '30', '41'), +('1', '4', '46', '64', '103', '61', '30', '42'), +('1', '4', '47', '65', '105', '62', '31', '42'), +('1', '4', '48', '66', '107', '63', '31', '43'), +('1', '4', '49', '68', '109', '64', '31', '44'), +('1', '4', '50', '69', '111', '65', '32', '44'), +('1', '4', '51', '70', '113', '66', '32', '45'), +('1', '4', '52', '71', '116', '67', '32', '45'), +('1', '4', '53', '73', '118', '68', '33', '46'), +('1', '4', '54', '74', '120', '69', '33', '47'), +('1', '4', '55', '75', '122', '71', '33', '47'), +('1', '4', '56', '76', '125', '72', '34', '48'), +('1', '4', '57', '78', '127', '73', '34', '49'), +('1', '4', '58', '79', '129', '74', '34', '49'), +('1', '4', '59', '80', '131', '75', '35', '50'), +('1', '4', '60', '81', '134', '77', '35', '51'), +('1', '4', '61', '83', '136', '78', '35', '51'), +('1', '4', '62', '84', '138', '79', '36', '52'), +('1', '4', '63', '85', '141', '80', '36', '53'), +('1', '4', '64', '87', '143', '81', '37', '54'), +('1', '4', '65', '88', '146', '83', '37', '54'), +('1', '4', '66', '89', '148', '84', '37', '55'), +('1', '4', '67', '91', '151', '85', '38', '56'), +('1', '4', '68', '92', '153', '86', '38', '57'), +('1', '4', '69', '94', '156', '88', '39', '57'), +('1', '4', '70', '95', '158', '89', '39', '58'), +('1', '4', '71', '97', '161', '90', '39', '60'), +('1', '4', '72', '99', '164', '92', '40', '60'), +('1', '4', '73', '100', '167', '94', '40', '61'), +('1', '4', '74', '102', '170', '95', '41', '62'), +('1', '4', '75', '104', '173', '97', '41', '63'), +('1', '4', '76', '105', '176', '98', '41', '64'), +('1', '4', '77', '107', '179', '100', '42', '65'), +('1', '4', '78', '109', '183', '106', '42', '66'), +('1', '4', '79', '111', '186', '107', '43', '67'), +('1', '4', '80', '113', '189', '109', '43', '69'), +('1', '5', '1', '20', '20', '20', '22', '23'), +('1', '5', '2', '20', '20', '20', '23', '24'), +('1', '5', '3', '20', '20', '21', '25', '26'), +('1', '5', '4', '20', '21', '21', '26', '27'), +('1', '5', '5', '21', '21', '21', '27', '28'), +('1', '5', '6', '21', '21', '22', '29', '30'), +('1', '5', '7', '21', '21', '22', '30', '31'), +('1', '5', '8', '21', '22', '23', '31', '33'), +('1', '5', '9', '21', '22', '23', '33', '34'), +('1', '5', '10', '21', '22', '23', '34', '36'), +('1', '5', '11', '22', '22', '24', '36', '37'), +('1', '5', '12', '22', '23', '24', '37', '39'), +('1', '5', '13', '22', '23', '25', '38', '40'), +('1', '5', '14', '22', '23', '25', '40', '42'), +('1', '5', '15', '22', '23', '25', '41', '43'), +('1', '5', '16', '23', '24', '26', '43', '45'), +('1', '5', '17', '23', '24', '26', '44', '46'), +('1', '5', '18', '23', '24', '27', '46', '48'), +('1', '5', '19', '23', '24', '27', '47', '49'), +('1', '5', '20', '23', '25', '28', '49', '51'), +('1', '5', '21', '24', '25', '28', '51', '53'), +('1', '5', '22', '24', '25', '29', '52', '54'), +('1', '5', '23', '24', '26', '29', '54', '56'), +('1', '5', '24', '24', '26', '30', '55', '58'), +('1', '5', '25', '25', '26', '30', '57', '59'), +('1', '5', '26', '25', '27', '31', '59', '61'), +('1', '5', '27', '25', '27', '31', '60', '63'), +('1', '5', '28', '25', '27', '32', '62', '65'), +('1', '5', '29', '25', '28', '32', '64', '66'), +('1', '5', '30', '26', '28', '33', '65', '68'), +('1', '5', '31', '26', '28', '33', '67', '70'), +('1', '5', '32', '26', '29', '34', '69', '72'), +('1', '5', '33', '27', '29', '34', '70', '73'), +('1', '5', '34', '27', '29', '35', '72', '75'), +('1', '5', '35', '27', '30', '35', '74', '77'), +('1', '5', '36', '27', '30', '36', '76', '79'), +('1', '5', '37', '28', '30', '36', '78', '81'), +('1', '5', '38', '28', '31', '37', '79', '83'), +('1', '5', '39', '28', '31', '38', '81', '85'), +('1', '5', '40', '28', '31', '38', '83', '87'), +('1', '5', '41', '29', '32', '39', '85', '88'), +('1', '5', '42', '29', '32', '39', '87', '90'), +('1', '5', '43', '29', '33', '40', '89', '92'), +('1', '5', '44', '30', '33', '40', '91', '94'), +('1', '5', '45', '30', '33', '41', '92', '96'), +('1', '5', '46', '30', '34', '42', '94', '98'), +('1', '5', '47', '31', '34', '42', '96', '100'), +('1', '5', '48', '31', '35', '43', '98', '102'), +('1', '5', '49', '31', '35', '44', '100', '104'), +('1', '5', '50', '32', '36', '44', '102', '106'), +('1', '5', '51', '32', '36', '45', '104', '109'), +('1', '5', '52', '32', '36', '45', '106', '111'), +('1', '5', '53', '33', '37', '46', '108', '113'), +('1', '5', '54', '33', '37', '47', '110', '115'), +('1', '5', '55', '33', '38', '47', '112', '117'), +('1', '5', '56', '34', '38', '48', '114', '119'), +('1', '5', '57', '34', '39', '49', '117', '121'), +('1', '5', '58', '34', '39', '49', '119', '124'), +('1', '5', '59', '35', '40', '50', '121', '126'), +('1', '5', '60', '35', '40', '51', '123', '128'), +('1', '5', '61', '35', '41', '51', '125', '130'), +('1', '5', '62', '36', '41', '52', '127', '132'), +('1', '5', '63', '36', '41', '53', '129', '135'), +('1', '5', '64', '37', '42', '54', '132', '137'), +('1', '5', '65', '37', '42', '54', '134', '139'), +('1', '5', '66', '37', '43', '55', '136', '142'), +('1', '5', '67', '38', '43', '56', '138', '144'), +('1', '5', '68', '38', '44', '57', '140', '146'), +('1', '5', '69', '39', '44', '57', '143', '149'), +('1', '5', '70', '39', '45', '58', '145', '151'), +('1', '5', '71', '39', '46', '59', '148', '158'), +('1', '5', '72', '40', '46', '59', '151', '161'), +('1', '5', '73', '40', '47', '60', '154', '164'), +('1', '5', '74', '41', '47', '61', '156', '167'), +('1', '5', '75', '41', '48', '62', '159', '170'), +('1', '5', '76', '41', '49', '63', '162', '174'), +('1', '5', '77', '42', '49', '64', '165', '177'), +('1', '5', '78', '42', '50', '65', '168', '180'), +('1', '5', '79', '43', '50', '66', '171', '183'), +('1', '5', '80', '43', '51', '67', '174', '186'), +('1', '6', '1', '23', '20', '22', '20', '20'), +('1', '6', '2', '24', '21', '23', '20', '20'), +('1', '6', '3', '26', '22', '24', '20', '21'), +('1', '6', '4', '27', '22', '26', '20', '21'), +('1', '6', '5', '28', '23', '27', '20', '21'), +('1', '6', '6', '30', '24', '28', '20', '21'), +('1', '6', '7', '31', '25', '29', '21', '22'), +('1', '6', '8', '32', '26', '30', '21', '22'), +('1', '6', '9', '34', '26', '32', '21', '22'), +('1', '6', '10', '35', '27', '33', '21', '23'), +('1', '6', '11', '36', '28', '34', '21', '23'), +('1', '6', '12', '38', '29', '35', '21', '23'), +('1', '6', '13', '39', '30', '37', '21', '24'), +('1', '6', '14', '41', '31', '38', '21', '24'), +('1', '6', '15', '42', '32', '39', '21', '24'), +('1', '6', '16', '44', '33', '41', '21', '25'), +('1', '6', '17', '45', '34', '42', '22', '25'), +('1', '6', '18', '47', '34', '43', '22', '25'), +('1', '6', '19', '48', '35', '45', '22', '26'), +('1', '6', '20', '50', '36', '46', '22', '26'), +('1', '6', '21', '51', '37', '48', '22', '26'), +('1', '6', '22', '53', '38', '49', '22', '27'), +('1', '6', '23', '54', '39', '51', '22', '27'), +('1', '6', '24', '56', '40', '52', '23', '28'), +('1', '6', '25', '58', '41', '53', '23', '28'), +('1', '6', '26', '59', '42', '55', '23', '28'), +('1', '6', '27', '61', '43', '56', '23', '29'), +('1', '6', '28', '63', '44', '58', '23', '29'), +('1', '6', '29', '64', '45', '59', '23', '30'), +('1', '6', '30', '66', '46', '61', '24', '30'), +('1', '6', '31', '68', '47', '62', '24', '30'), +('1', '6', '32', '69', '48', '64', '24', '31'), +('1', '6', '33', '71', '50', '66', '24', '31'), +('1', '6', '34', '73', '51', '67', '24', '32'), +('1', '6', '35', '74', '52', '69', '24', '32'), +('1', '6', '36', '76', '53', '70', '25', '33'), +('1', '6', '37', '78', '54', '72', '25', '33'), +('1', '6', '38', '80', '55', '74', '25', '34'), +('1', '6', '39', '82', '56', '75', '25', '34'), +('1', '6', '40', '83', '57', '77', '25', '35'), +('1', '6', '41', '85', '58', '79', '26', '35'), +('1', '6', '42', '87', '60', '80', '26', '35'), +('1', '6', '43', '89', '61', '82', '26', '36'), +('1', '6', '44', '91', '62', '84', '26', '36'), +('1', '6', '45', '93', '63', '85', '26', '37'), +('1', '6', '46', '95', '64', '87', '27', '37'), +('1', '6', '47', '97', '66', '89', '27', '38'), +('1', '6', '48', '99', '67', '91', '27', '38'), +('1', '6', '49', '101', '68', '93', '27', '39'), +('1', '6', '50', '103', '69', '94', '28', '40'), +('1', '6', '51', '105', '71', '96', '28', '40'), +('1', '6', '52', '106', '72', '97', '28', '41'), +('1', '6', '53', '107', '72', '98', '28', '41'), +('1', '6', '54', '107', '73', '98', '29', '42'), +('1', '6', '55', '108', '73', '99', '29', '43'), +('1', '6', '56', '111', '75', '102', '29', '44'), +('1', '6', '57', '113', '76', '104', '29', '44'), +('1', '6', '58', '118', '77', '106', '30', '45'), +('1', '6', '59', '118', '79', '108', '30', '45'), +('1', '6', '60', '123', '80', '110', '30', '46'), +('1', '6', '61', '125', '81', '112', '30', '47'), +('1', '6', '62', '128', '83', '114', '30', '47'), +('1', '6', '63', '130', '84', '117', '31', '48'), +('1', '6', '64', '130', '86', '119', '31', '48'), +('1', '6', '65', '140', '87', '128', '31', '49'), +('1', '6', '66', '143', '89', '131', '31', '50'), +('1', '6', '67', '146', '90', '133', '32', '50'), +('1', '6', '68', '148', '92', '135', '32', '51'), +('1', '6', '69', '151', '93', '138', '32', '52'), +('1', '6', '70', '154', '95', '140', '32', '52'), +('1', '6', '71', '162', '97', '144', '33', '53'), +('1', '6', '72', '164', '98', '146', '33', '54'), +('1', '6', '73', '165', '100', '148', '33', '55'), +('1', '6', '74', '166', '102', '151', '33', '55'), +('1', '6', '75', '169', '103', '154', '34', '56'), +('1', '6', '76', '172', '105', '157', '34', '57'), +('1', '6', '77', '175', '107', '157', '34', '58'), +('1', '6', '78', '176', '108', '157', '34', '58'), +('1', '6', '79', '177', '110', '157', '35', '59'), +('1', '6', '80', '180', '112', '160', '35', '60'), +('1', '8', '1', '20', '20', '20', '23', '22'), +('1', '8', '2', '20', '20', '20', '24', '23'), +('1', '8', '3', '20', '20', '21', '26', '25'), +('1', '8', '4', '20', '20', '21', '27', '26'), +('1', '8', '5', '20', '21', '21', '28', '27'), +('1', '8', '6', '20', '21', '21', '30', '29'), +('1', '8', '7', '21', '21', '22', '31', '30'), +('1', '8', '8', '21', '21', '22', '33', '31'), +('1', '8', '9', '21', '21', '22', '34', '33'), +('1', '8', '10', '21', '21', '23', '36', '34'), +('1', '8', '11', '21', '22', '23', '37', '36'), +('1', '8', '12', '21', '22', '23', '39', '37'), +('1', '8', '13', '21', '22', '24', '40', '38'), +('1', '8', '14', '21', '22', '24', '42', '40'), +('1', '8', '15', '21', '22', '24', '43', '41'), +('1', '8', '16', '21', '23', '25', '45', '43'), +('1', '8', '17', '22', '23', '25', '46', '44'), +('1', '8', '18', '22', '23', '25', '48', '46'), +('1', '8', '19', '22', '23', '26', '49', '47'), +('1', '8', '20', '22', '23', '26', '51', '49'), +('1', '8', '21', '22', '24', '26', '53', '51'), +('1', '8', '22', '22', '24', '27', '54', '52'), +('1', '8', '23', '22', '24', '27', '56', '54'), +('1', '8', '24', '23', '24', '28', '58', '55'), +('1', '8', '25', '23', '25', '28', '59', '57'), +('1', '8', '26', '23', '25', '28', '61', '59'), +('1', '8', '27', '23', '25', '29', '63', '60'), +('1', '8', '28', '23', '25', '29', '65', '62'), +('1', '8', '29', '23', '25', '30', '66', '64'), +('1', '8', '30', '24', '26', '30', '68', '65'), +('1', '8', '31', '24', '26', '30', '70', '67'), +('1', '8', '32', '24', '26', '31', '72', '69'), +('1', '8', '33', '24', '27', '31', '73', '70'), +('1', '8', '34', '24', '27', '32', '75', '72'), +('1', '8', '35', '24', '27', '32', '77', '74'), +('1', '8', '36', '25', '27', '33', '79', '76'), +('1', '8', '37', '25', '28', '33', '81', '78'), +('1', '8', '38', '25', '28', '34', '83', '79'), +('1', '8', '39', '25', '28', '34', '85', '81'), +('1', '8', '40', '25', '28', '35', '87', '83'), +('1', '8', '41', '26', '29', '35', '88', '85'), +('1', '8', '42', '26', '29', '35', '90', '87'), +('1', '8', '43', '26', '29', '36', '92', '89'), +('1', '8', '44', '26', '30', '36', '94', '91'), +('1', '8', '45', '26', '30', '37', '96', '92'), +('1', '8', '46', '27', '30', '37', '98', '94'), +('1', '8', '47', '27', '31', '38', '100', '96'), +('1', '8', '48', '27', '31', '38', '102', '98'), +('1', '8', '49', '27', '31', '39', '104', '100'), +('1', '8', '50', '28', '32', '40', '106', '102'), +('1', '8', '51', '28', '32', '40', '109', '104'), +('1', '8', '52', '28', '32', '41', '111', '106'), +('1', '8', '53', '28', '33', '41', '113', '108'), +('1', '8', '54', '29', '33', '42', '115', '110'), +('1', '8', '55', '29', '33', '42', '117', '112'), +('1', '8', '56', '29', '34', '43', '119', '114'), +('1', '8', '57', '29', '34', '43', '121', '117'), +('1', '8', '58', '30', '34', '44', '124', '119'), +('1', '8', '59', '30', '35', '44', '126', '121'), +('1', '8', '60', '30', '35', '45', '128', '123'), +('1', '8', '61', '30', '35', '46', '130', '125'), +('1', '8', '62', '31', '36', '46', '132', '127'), +('1', '8', '63', '31', '36', '47', '135', '129'), +('1', '8', '64', '31', '37', '47', '137', '132'), +('1', '8', '65', '32', '37', '48', '139', '134'), +('1', '8', '66', '32', '37', '49', '142', '136'), +('1', '8', '67', '32', '38', '49', '144', '138'), +('1', '8', '68', '32', '38', '50', '146', '140'), +('1', '8', '69', '33', '39', '50', '149', '143'), +('1', '8', '70', '33', '39', '51', '151', '145'), +('1', '8', '71', '33', '39', '52', '154', '152'), +('1', '8', '72', '33', '40', '53', '160', '155'), +('1', '8', '73', '33', '40', '54', '160', '158'), +('1', '8', '74', '34', '41', '54', '163', '160'), +('1', '8', '75', '34', '41', '55', '166', '163'), +('1', '8', '76', '34', '41', '56', '169', '166'), +('1', '8', '77', '35', '42', '57', '172', '169'), +('1', '8', '78', '35', '42', '57', '175', '173'), +('1', '8', '79', '35', '43', '58', '178', '176'), +('1', '8', '80', '36', '43', '59', '181', '179'), +('1', '9', '1', '20', '20', '21', '22', '22'), +('1', '9', '2', '20', '20', '22', '23', '23'), +('1', '9', '3', '21', '21', '22', '24', '24'), +('1', '9', '4', '21', '21', '23', '26', '25'), +('1', '9', '5', '21', '21', '23', '27', '27'), +('1', '9', '6', '21', '22', '24', '28', '28'), +('1', '9', '7', '22', '22', '24', '29', '29'), +('1', '9', '8', '22', '23', '25', '30', '30'), +('1', '9', '9', '22', '23', '26', '32', '31'), +('1', '9', '10', '23', '23', '26', '33', '33'), +('1', '9', '11', '23', '24', '27', '34', '34'), +('1', '9', '12', '23', '24', '27', '35', '35'), +('1', '9', '13', '24', '25', '28', '37', '36'), +('1', '9', '14', '24', '25', '29', '38', '38'), +('1', '9', '15', '24', '25', '29', '39', '39'), +('1', '9', '16', '25', '26', '30', '41', '40'), +('1', '9', '17', '25', '26', '31', '42', '42'), +('1', '9', '18', '25', '27', '31', '43', '43'), +('1', '9', '19', '26', '27', '32', '45', '44'), +('1', '9', '20', '26', '28', '33', '46', '46'), +('1', '9', '21', '26', '28', '33', '48', '47'), +('1', '9', '22', '27', '29', '34', '49', '49'), +('1', '9', '23', '27', '29', '35', '51', '50'), +('1', '9', '24', '28', '30', '35', '52', '51'), +('1', '9', '25', '28', '30', '36', '53', '53'), +('1', '9', '26', '28', '31', '37', '55', '54'), +('1', '9', '27', '29', '31', '37', '56', '56'), +('1', '9', '28', '29', '32', '38', '58', '57'), +('1', '9', '29', '30', '32', '39', '59', '59'), +('1', '9', '30', '30', '33', '40', '61', '60'), +('1', '9', '31', '30', '33', '40', '62', '62'), +('1', '9', '32', '31', '34', '41', '64', '63'), +('1', '9', '33', '31', '34', '42', '66', '65'), +('1', '9', '34', '32', '35', '43', '67', '66'), +('1', '9', '35', '32', '35', '44', '69', '68'), +('1', '9', '36', '33', '36', '44', '70', '69'), +('1', '9', '37', '33', '36', '45', '72', '71'), +('1', '9', '38', '34', '37', '46', '74', '73'), +('1', '9', '39', '34', '38', '47', '75', '74'), +('1', '9', '40', '35', '38', '48', '77', '76'), +('1', '9', '41', '35', '39', '48', '79', '78'), +('1', '9', '42', '35', '39', '49', '80', '79'), +('1', '9', '43', '36', '40', '50', '82', '81'), +('1', '9', '44', '36', '40', '51', '84', '83'), +('1', '9', '45', '37', '41', '52', '85', '84'), +('1', '9', '46', '37', '42', '53', '87', '86'), +('1', '9', '47', '38', '42', '54', '89', '88'), +('1', '9', '48', '38', '43', '55', '91', '89'), +('1', '9', '49', '39', '44', '55', '93', '91'), +('1', '9', '50', '40', '44', '56', '94', '93'), +('1', '9', '51', '40', '45', '57', '96', '95'), +('1', '9', '52', '41', '45', '58', '98', '97'), +('1', '9', '53', '41', '46', '59', '100', '98'), +('1', '9', '54', '42', '47', '60', '102', '100'), +('1', '9', '55', '42', '47', '61', '103', '102'), +('1', '9', '56', '43', '48', '62', '105', '104'), +('1', '9', '57', '43', '49', '63', '107', '106'), +('1', '9', '58', '44', '49', '64', '109', '108'), +('1', '9', '59', '44', '50', '65', '111', '109'), +('1', '9', '60', '45', '51', '66', '113', '111'), +('1', '9', '61', '46', '51', '67', '115', '113'), +('1', '9', '62', '46', '52', '68', '117', '115'), +('1', '9', '63', '47', '53', '69', '119', '117'), +('1', '9', '64', '47', '54', '70', '121', '119'), +('1', '9', '65', '48', '54', '71', '123', '121'), +('1', '9', '66', '49', '55', '72', '125', '123'), +('1', '9', '67', '49', '56', '73', '127', '125'), +('1', '9', '68', '50', '57', '74', '129', '127'), +('1', '9', '69', '50', '57', '75', '131', '129'), +('1', '9', '70', '51', '58', '76', '133', '131'), +('1', '9', '71', '52', '59', '78', '135', '146'), +('1', '9', '72', '53', '59', '79', '138', '148'), +('1', '9', '73', '54', '60', '80', '140', '151'), +('1', '9', '74', '54', '61', '89', '143', '154'), +('1', '9', '75', '55', '62', '91', '145', '156'), +('1', '9', '76', '56', '63', '92', '148', '159'), +('1', '9', '77', '57', '64', '93', '151', '162'), +('1', '9', '78', '57', '65', '95', '153', '165'), +('1', '9', '79', '58', '66', '96', '156', '168'), +('1', '9', '80', '59', '67', '97', '159', '170'), +('2', '1', '1', '26', '17', '24', '17', '23'), +('2', '1', '2', '27', '18', '25', '17', '23'), +('2', '1', '3', '29', '19', '26', '17', '24'), +('2', '1', '4', '30', '19', '27', '17', '24'), +('2', '1', '5', '31', '20', '29', '17', '24'), +('2', '1', '6', '32', '21', '30', '17', '24'), +('2', '1', '7', '34', '22', '31', '18', '25'), +('2', '1', '8', '35', '23', '32', '18', '25'), +('2', '1', '9', '37', '24', '34', '18', '25'), +('2', '1', '10', '38', '24', '35', '18', '26'), +('2', '1', '11', '39', '25', '36', '18', '26'), +('2', '1', '12', '41', '26', '37', '18', '26'), +('2', '1', '13', '42', '27', '39', '18', '27'), +('2', '1', '14', '44', '28', '40', '18', '27'), +('2', '1', '15', '45', '29', '41', '18', '27'), +('2', '1', '16', '47', '30', '43', '19', '28'), +('2', '1', '17', '48', '31', '44', '19', '28'), +('2', '1', '18', '50', '32', '45', '19', '28'), +('2', '1', '19', '51', '33', '47', '19', '29'), +('2', '1', '20', '53', '34', '48', '19', '29'), +('2', '1', '21', '54', '34', '50', '19', '29'), +('2', '1', '22', '56', '35', '51', '19', '30'), +('2', '1', '23', '57', '36', '52', '20', '30'), +('2', '1', '24', '59', '37', '54', '20', '30'), +('2', '1', '25', '60', '38', '55', '20', '31'), +('2', '1', '26', '62', '39', '57', '20', '31'), +('2', '1', '27', '64', '40', '58', '20', '32'), +('2', '1', '28', '65', '41', '60', '20', '32'), +('2', '1', '29', '67', '43', '61', '21', '32'), +('2', '1', '30', '69', '44', '63', '21', '33'), +('2', '1', '31', '70', '45', '64', '21', '33'), +('2', '1', '32', '72', '46', '66', '21', '34'), +('2', '1', '33', '74', '47', '67', '21', '34'), +('2', '1', '34', '76', '48', '69', '21', '35'), +('2', '1', '35', '77', '49', '71', '22', '35'), +('2', '1', '36', '79', '50', '72', '22', '36'), +('2', '1', '37', '81', '51', '74', '22', '36'), +('2', '1', '38', '83', '52', '76', '22', '36'), +('2', '1', '39', '84', '53', '77', '22', '37'), +('2', '1', '40', '86', '55', '79', '23', '37'), +('2', '1', '41', '88', '56', '81', '23', '38'), +('2', '1', '42', '90', '57', '82', '23', '38'), +('2', '1', '43', '92', '58', '84', '23', '39'), +('2', '1', '44', '94', '59', '86', '23', '39'), +('2', '1', '45', '96', '60', '87', '24', '40'), +('2', '1', '46', '98', '62', '89', '24', '40'), +('2', '1', '47', '100', '63', '91', '24', '41'), +('2', '1', '48', '101', '64', '93', '24', '41'), +('2', '1', '49', '103', '65', '94', '25', '42'), +('2', '1', '50', '105', '66', '96', '25', '42'), +('2', '1', '51', '107', '68', '98', '25', '43'), +('2', '1', '52', '109', '69', '100', '25', '43'), +('2', '1', '53', '111', '70', '102', '25', '44'), +('2', '1', '54', '113', '71', '104', '26', '45'), +('2', '1', '55', '115', '73', '105', '26', '45'), +('2', '1', '56', '118', '74', '107', '26', '46'), +('2', '1', '57', '120', '75', '109', '26', '46'), +('2', '1', '58', '122', '77', '111', '27', '47'), +('2', '1', '59', '124', '78', '113', '27', '47'), +('2', '1', '60', '126', '79', '115', '27', '48'), +('2', '1', '61', '128', '81', '117', '27', '48'), +('2', '1', '62', '130', '82', '119', '28', '49'), +('2', '1', '63', '132', '83', '121', '28', '50'), +('2', '1', '64', '135', '85', '123', '28', '50'), +('2', '1', '65', '137', '86', '125', '29', '51'), +('2', '1', '66', '139', '87', '127', '29', '52'), +('2', '1', '67', '141', '89', '129', '29', '52'), +('2', '1', '68', '143', '90', '131', '29', '53'), +('2', '1', '69', '146', '92', '133', '30', '53'), +('2', '1', '70', '148', '93', '135', '30', '54'), +('2', '1', '71', '157', '94', '142', '30', '55'), +('2', '1', '72', '162', '96', '148', '30', '56'), +('2', '1', '73', '165', '98', '150', '30', '57'), +('2', '1', '74', '168', '99', '153', '31', '57'), +('2', '1', '75', '170', '101', '154', '31', '58'), +('2', '1', '76', '172', '103', '156', '31', '59'), +('2', '1', '77', '174', '105', '159', '32', '60'), +('2', '1', '78', '179', '106', '162', '32', '60'), +('2', '1', '79', '184', '108', '167', '32', '61'), +('2', '1', '80', '187', '110', '170', '33', '62'), +('2', '3', '1', '23', '20', '23', '17', '24'), +('2', '3', '2', '23', '21', '24', '18', '25'), +('2', '3', '3', '24', '23', '25', '18', '25'), +('2', '3', '4', '24', '24', '26', '19', '26'), +('2', '3', '5', '25', '25', '27', '19', '26'), +('2', '3', '6', '25', '27', '28', '20', '27'), +('2', '3', '7', '26', '28', '28', '21', '28'), +('2', '3', '8', '26', '30', '29', '21', '28'), +('2', '3', '9', '26', '31', '30', '22', '29'), +('2', '3', '10', '27', '33', '31', '22', '30'), +('2', '3', '11', '27', '34', '32', '23', '30'), +('2', '3', '12', '28', '36', '33', '24', '31'), +('2', '3', '13', '28', '37', '34', '24', '32'), +('2', '3', '14', '29', '39', '35', '25', '33'), +('2', '3', '15', '29', '40', '36', '26', '33'), +('2', '3', '16', '30', '42', '37', '26', '34'), +('2', '3', '17', '30', '43', '39', '27', '35'), +('2', '3', '18', '31', '45', '40', '28', '35'), +('2', '3', '19', '31', '47', '41', '28', '36'), +('2', '3', '20', '32', '48', '42', '29', '37'), +('2', '3', '21', '32', '50', '43', '30', '38'), +('2', '3', '22', '33', '51', '44', '31', '39'), +('2', '3', '23', '34', '53', '45', '31', '39'), +('2', '3', '24', '34', '55', '46', '32', '40'), +('2', '3', '25', '35', '57', '47', '33', '41'), +('2', '3', '26', '35', '58', '48', '34', '42'), +('2', '3', '27', '36', '60', '50', '34', '43'), +('2', '3', '28', '36', '62', '51', '35', '43'), +('2', '3', '29', '37', '63', '52', '36', '44'), +('2', '3', '30', '38', '65', '53', '37', '45'), +('2', '3', '31', '38', '67', '54', '37', '46'), +('2', '3', '32', '39', '69', '56', '38', '47'), +('2', '3', '33', '39', '71', '57', '39', '48'), +('2', '3', '34', '40', '72', '58', '40', '49'), +('2', '3', '35', '41', '74', '59', '41', '49'), +('2', '3', '36', '41', '76', '61', '42', '50'), +('2', '3', '37', '42', '78', '62', '42', '51'), +('2', '3', '38', '43', '80', '63', '43', '52'), +('2', '3', '39', '43', '82', '64', '44', '53'), +('2', '3', '40', '44', '84', '66', '45', '54'), +('2', '3', '41', '45', '86', '67', '46', '55'), +('2', '3', '42', '45', '88', '68', '47', '56'), +('2', '3', '43', '46', '90', '70', '47', '57'), +('2', '3', '44', '47', '91', '71', '48', '58'), +('2', '3', '45', '47', '93', '72', '49', '59'), +('2', '3', '46', '48', '95', '74', '50', '60'), +('2', '3', '47', '49', '98', '75', '51', '61'), +('2', '3', '48', '50', '100', '77', '52', '62'), +('2', '3', '49', '50', '102', '78', '53', '63'), +('2', '3', '50', '51', '104', '79', '54', '64'), +('2', '3', '51', '52', '106', '81', '55', '65'), +('2', '3', '52', '52', '108', '82', '56', '66'), +('2', '3', '53', '53', '110', '84', '57', '67'), +('2', '3', '54', '54', '112', '85', '58', '68'), +('2', '3', '55', '55', '114', '87', '59', '69'), +('2', '3', '56', '55', '116', '88', '60', '70'), +('2', '3', '57', '56', '118', '90', '61', '71'), +('2', '3', '58', '57', '121', '91', '62', '72'), +('2', '3', '59', '58', '123', '93', '63', '73'), +('2', '3', '60', '59', '125', '94', '64', '74'), +('2', '3', '61', '59', '127', '96', '65', '76'), +('2', '3', '62', '60', '130', '97', '66', '77'), +('2', '3', '63', '61', '132', '99', '67', '78'), +('2', '3', '64', '62', '134', '100', '68', '79'), +('2', '3', '65', '63', '136', '102', '69', '80'), +('2', '3', '66', '64', '139', '104', '70', '81'), +('2', '3', '67', '64', '141', '105', '71', '82'), +('2', '3', '68', '65', '143', '107', '72', '84'), +('2', '3', '69', '66', '146', '108', '73', '85'), +('2', '3', '70', '67', '148', '110', '74', '86'), +('2', '3', '71', '68', '151', '112', '75', '87'), +('2', '3', '72', '69', '154', '114', '76', '88'), +('2', '3', '73', '70', '157', '116', '77', '90'), +('2', '3', '74', '71', '160', '118', '79', '91'), +('2', '3', '75', '72', '163', '120', '80', '93'), +('2', '3', '76', '73', '166', '122', '81', '94'), +('2', '3', '77', '74', '169', '124', '83', '96'), +('2', '3', '78', '75', '172', '126', '84', '97'), +('2', '3', '79', '76', '175', '128', '85', '99'), +('2', '3', '80', '77', '178', '130', '87', '100'), +('2', '4', '1', '24', '20', '23', '17', '23'), +('2', '4', '2', '25', '21', '24', '17', '23'), +('2', '4', '3', '25', '23', '24', '17', '24'), +('2', '4', '4', '26', '24', '25', '17', '24'), +('2', '4', '5', '27', '26', '26', '18', '24'), +('2', '4', '6', '28', '27', '26', '18', '25'), +('2', '4', '7', '29', '29', '27', '18', '25'), +('2', '4', '8', '29', '30', '28', '18', '26'), +('2', '4', '9', '30', '32', '29', '18', '26'), +('2', '4', '10', '31', '33', '29', '19', '26'), +('2', '4', '11', '32', '35', '30', '19', '27'), +('2', '4', '12', '33', '37', '31', '19', '27'), +('2', '4', '13', '34', '38', '32', '19', '28'), +('2', '4', '14', '34', '40', '32', '19', '28'), +('2', '4', '15', '35', '41', '33', '19', '28'), +('2', '4', '16', '36', '43', '34', '20', '29'), +('2', '4', '17', '37', '45', '35', '20', '29'), +('2', '4', '18', '38', '46', '36', '20', '30'), +('2', '4', '19', '39', '48', '37', '20', '30'), +('2', '4', '20', '40', '50', '37', '21', '31'), +('2', '4', '21', '41', '52', '38', '21', '31'), +('2', '4', '22', '42', '53', '39', '21', '31'), +('2', '4', '23', '43', '55', '40', '21', '32'), +('2', '4', '24', '43', '57', '41', '21', '32'), +('2', '4', '25', '44', '59', '42', '22', '33'), +('2', '4', '26', '45', '60', '43', '22', '33'), +('2', '4', '27', '46', '62', '44', '22', '34'), +('2', '4', '28', '47', '64', '44', '22', '34'), +('2', '4', '29', '48', '66', '45', '23', '35'), +('2', '4', '30', '49', '68', '46', '23', '35'), +('2', '4', '31', '50', '70', '47', '23', '36'), +('2', '4', '32', '51', '72', '48', '23', '36'), +('2', '4', '33', '53', '73', '49', '24', '37'), +('2', '4', '34', '54', '75', '50', '24', '38'), +('2', '4', '35', '55', '77', '51', '24', '38'), +('2', '4', '36', '56', '79', '52', '24', '39'), +('2', '4', '37', '57', '81', '53', '25', '39'), +('2', '4', '38', '58', '83', '54', '25', '40'), +('2', '4', '39', '59', '85', '55', '25', '40'), +('2', '4', '40', '60', '87', '56', '26', '41'), +('2', '4', '41', '61', '89', '57', '26', '41'), +('2', '4', '42', '62', '91', '58', '26', '42'), +('2', '4', '43', '63', '93', '59', '27', '43'), +('2', '4', '44', '65', '95', '60', '27', '43'), +('2', '4', '45', '66', '98', '61', '27', '44'), +('2', '4', '46', '67', '100', '62', '27', '44'), +('2', '4', '47', '68', '102', '64', '28', '45'), +('2', '4', '48', '69', '104', '65', '28', '46'), +('2', '4', '49', '71', '106', '66', '28', '46'), +('2', '4', '50', '72', '108', '67', '29', '47'), +('2', '4', '51', '73', '110', '68', '29', '48'), +('2', '4', '52', '74', '113', '69', '29', '48'), +('2', '4', '53', '75', '115', '70', '30', '49'), +('2', '4', '54', '77', '117', '71', '30', '50'), +('2', '4', '55', '78', '119', '73', '30', '50'), +('2', '4', '56', '79', '122', '74', '31', '51'), +('2', '4', '57', '80', '124', '75', '31', '52'), +('2', '4', '58', '82', '126', '76', '31', '52'), +('2', '4', '59', '83', '129', '77', '32', '53'), +('2', '4', '60', '84', '131', '78', '32', '54'), +('2', '4', '61', '86', '133', '80', '33', '54'), +('2', '4', '62', '87', '136', '81', '33', '55'), +('2', '4', '63', '88', '138', '82', '33', '56'), +('2', '4', '64', '90', '140', '83', '34', '57'), +('2', '4', '65', '91', '143', '85', '34', '57'), +('2', '4', '66', '92', '145', '86', '34', '58'), +('2', '4', '67', '94', '148', '87', '35', '59'), +('2', '4', '68', '95', '150', '88', '35', '59'), +('2', '4', '69', '97', '153', '90', '36', '60'), +('2', '4', '70', '98', '155', '91', '36', '61'), +('2', '4', '71', '100', '158', '92', '36', '62'), +('2', '4', '72', '102', '161', '94', '37', '62'), +('2', '4', '73', '103', '164', '99', '37', '63'), +('2', '4', '74', '105', '167', '100', '38', '64'), +('2', '4', '75', '107', '170', '102', '38', '65'), +('2', '4', '76', '108', '173', '102', '38', '66'), +('2', '4', '77', '110', '176', '102', '39', '67'), +('2', '4', '78', '112', '180', '103', '39', '68'), +('2', '4', '79', '114', '183', '105', '40', '69'), +('2', '4', '80', '116', '186', '107', '40', '70'), +('2', '6', '1', '26', '17', '24', '17', '23'), +('2', '6', '2', '27', '18', '25', '17', '23'), +('2', '6', '3', '29', '19', '26', '17', '24'), +('2', '6', '4', '30', '19', '27', '17', '24'), +('2', '6', '5', '31', '20', '29', '17', '24'), +('2', '6', '6', '32', '21', '30', '17', '24'), +('2', '6', '7', '34', '22', '31', '18', '25'), +('2', '6', '8', '35', '23', '32', '18', '25'), +('2', '6', '9', '37', '24', '34', '18', '25'), +('2', '6', '10', '38', '24', '35', '18', '26'), +('2', '6', '11', '39', '25', '36', '18', '26'), +('2', '6', '12', '41', '26', '37', '18', '26'), +('2', '6', '13', '42', '27', '39', '18', '27'), +('2', '6', '14', '44', '28', '40', '18', '27'), +('2', '6', '15', '45', '29', '41', '18', '27'), +('2', '6', '16', '47', '30', '43', '19', '28'), +('2', '6', '17', '48', '31', '44', '19', '28'), +('2', '6', '18', '50', '32', '45', '19', '28'), +('2', '6', '19', '51', '33', '47', '19', '29'), +('2', '6', '20', '53', '34', '48', '19', '29'), +('2', '6', '21', '54', '34', '50', '19', '29'), +('2', '6', '22', '56', '35', '51', '19', '30'), +('2', '6', '23', '57', '36', '52', '20', '30'), +('2', '6', '24', '59', '37', '54', '20', '30'), +('2', '6', '25', '60', '38', '55', '20', '31'), +('2', '6', '26', '62', '39', '57', '20', '31'), +('2', '6', '27', '64', '40', '58', '20', '32'), +('2', '6', '28', '65', '41', '60', '20', '32'), +('2', '6', '29', '67', '43', '61', '21', '32'), +('2', '6', '30', '69', '44', '63', '21', '33'), +('2', '6', '31', '70', '45', '64', '21', '33'), +('2', '6', '32', '72', '46', '66', '21', '34'), +('2', '6', '33', '74', '47', '67', '21', '34'), +('2', '6', '34', '76', '48', '69', '21', '35'), +('2', '6', '35', '77', '49', '71', '22', '35'), +('2', '6', '36', '79', '50', '72', '22', '36'), +('2', '6', '37', '81', '51', '74', '22', '36'), +('2', '6', '38', '83', '52', '76', '22', '36'), +('2', '6', '39', '84', '53', '77', '22', '37'), +('2', '6', '40', '86', '55', '79', '23', '37'), +('2', '6', '41', '88', '56', '81', '23', '38'), +('2', '6', '42', '90', '57', '82', '23', '38'), +('2', '6', '43', '92', '58', '84', '23', '39'), +('2', '6', '44', '94', '59', '86', '23', '39'), +('2', '6', '45', '96', '60', '87', '24', '40'), +('2', '6', '46', '98', '62', '89', '24', '40'), +('2', '6', '47', '100', '63', '91', '24', '41'), +('2', '6', '48', '101', '64', '93', '24', '41'), +('2', '6', '49', '103', '65', '94', '25', '42'), +('2', '6', '50', '105', '66', '96', '25', '42'), +('2', '6', '51', '107', '68', '98', '25', '43'), +('2', '6', '52', '109', '69', '100', '25', '43'), +('2', '6', '53', '110', '69', '100', '25', '44'), +('2', '6', '54', '111', '70', '101', '26', '45'), +('2', '6', '55', '111', '70', '101', '26', '45'), +('2', '6', '56', '114', '72', '104', '26', '46'), +('2', '6', '57', '116', '73', '106', '26', '46'), +('2', '6', '58', '118', '74', '108', '27', '47'), +('2', '6', '59', '124', '76', '110', '27', '47'), +('2', '6', '60', '126', '77', '112', '27', '48'), +('2', '6', '61', '128', '78', '114', '27', '49'), +('2', '6', '62', '131', '80', '116', '27', '49'), +('2', '6', '63', '133', '81', '119', '28', '50'), +('2', '6', '64', '136', '83', '121', '28', '50'), +('2', '6', '65', '136', '84', '123', '28', '51'), +('2', '6', '66', '142', '86', '126', '28', '52'), +('2', '6', '67', '145', '87', '128', '29', '52'), +('2', '6', '68', '147', '89', '130', '29', '53'), +('2', '6', '69', '150', '90', '133', '29', '54'), +('2', '6', '70', '157', '92', '135', '29', '54'), +('2', '6', '71', '160', '94', '138', '30', '55'), +('2', '6', '72', '163', '95', '140', '30', '56'), +('2', '6', '73', '166', '97', '151', '30', '57'), +('2', '6', '74', '169', '99', '154', '30', '57'), +('2', '6', '75', '172', '100', '156', '31', '58'), +('2', '6', '76', '175', '102', '160', '31', '59'), +('2', '6', '77', '179', '104', '162', '31', '60'), +('2', '6', '78', '182', '105', '165', '31', '60'), +('2', '6', '79', '191', '107', '168', '32', '61'), +('2', '6', '80', '194', '109', '171', '32', '62'), +('2', '7', '1', '24', '17', '23', '18', '25'), +('2', '7', '2', '25', '17', '24', '19', '26'), +('2', '7', '3', '26', '18', '25', '20', '27'), +('2', '7', '4', '26', '18', '26', '21', '28'), +('2', '7', '5', '27', '19', '27', '22', '29'), +('2', '7', '6', '28', '19', '28', '23', '30'), +('2', '7', '7', '29', '20', '29', '24', '31'), +('2', '7', '8', '30', '20', '30', '25', '32'), +('2', '7', '9', '31', '21', '31', '26', '33'), +('2', '7', '10', '32', '21', '32', '27', '34'), +('2', '7', '11', '33', '22', '33', '28', '36'), +('2', '7', '12', '34', '22', '34', '29', '37'), +('2', '7', '13', '34', '23', '35', '30', '38'), +('2', '7', '14', '35', '23', '36', '31', '39'), +('2', '7', '15', '36', '24', '37', '32', '40'), +('2', '7', '16', '37', '24', '39', '33', '41'), +('2', '7', '17', '38', '25', '40', '34', '43'), +('2', '7', '18', '39', '25', '41', '35', '44'), +('2', '7', '19', '40', '26', '42', '36', '45'), +('2', '7', '20', '41', '26', '43', '37', '46'), +('2', '7', '21', '42', '27', '44', '38', '47'), +('2', '7', '22', '43', '27', '45', '39', '49'), +('2', '7', '23', '44', '28', '47', '40', '50'), +('2', '7', '24', '45', '28', '48', '41', '51'), +('2', '7', '25', '47', '29', '49', '43', '52'), +('2', '7', '26', '48', '30', '50', '44', '54'), +('2', '7', '27', '49', '30', '52', '45', '55'), +('2', '7', '28', '50', '31', '53', '46', '56'), +('2', '7', '29', '51', '31', '54', '47', '58'), +('2', '7', '30', '52', '32', '55', '48', '59'), +('2', '7', '31', '53', '33', '57', '50', '60'), +('2', '7', '32', '54', '33', '58', '51', '62'), +('2', '7', '33', '55', '34', '59', '52', '63'), +('2', '7', '34', '57', '34', '61', '53', '65'), +('2', '7', '35', '58', '35', '62', '55', '66'), +('2', '7', '36', '59', '36', '63', '56', '67'), +('2', '7', '37', '60', '36', '65', '57', '69'), +('2', '7', '38', '61', '37', '66', '58', '70'), +('2', '7', '39', '62', '38', '67', '60', '72'), +('2', '7', '40', '64', '38', '69', '61', '73'), +('2', '7', '41', '65', '39', '70', '62', '75'), +('2', '7', '42', '66', '40', '72', '64', '76'), +('2', '7', '43', '67', '40', '73', '65', '78'), +('2', '7', '44', '69', '41', '74', '66', '79'), +('2', '7', '45', '70', '42', '76', '68', '81'), +('2', '7', '46', '71', '42', '77', '69', '82'), +('2', '7', '47', '72', '43', '79', '70', '84'), +('2', '7', '48', '74', '44', '80', '72', '85'), +('2', '7', '49', '75', '45', '82', '73', '87'), +('2', '7', '50', '76', '45', '83', '75', '89'), +('2', '7', '51', '78', '46', '85', '76', '90'), +('2', '7', '52', '79', '47', '86', '77', '92'), +('2', '7', '53', '80', '47', '88', '79', '93'), +('2', '7', '54', '82', '48', '90', '80', '95'), +('2', '7', '55', '83', '49', '91', '82', '97'), +('2', '7', '56', '85', '50', '93', '83', '98'), +('2', '7', '57', '86', '50', '94', '85', '100'), +('2', '7', '58', '87', '51', '96', '86', '102'), +('2', '7', '59', '89', '52', '97', '88', '103'), +('2', '7', '60', '90', '53', '99', '89', '105'), +('2', '7', '61', '92', '54', '101', '91', '107'), +('2', '7', '62', '93', '54', '102', '92', '109'), +('2', '7', '63', '95', '55', '104', '94', '110'), +('2', '7', '64', '96', '56', '106', '95', '112'), +('2', '7', '65', '97', '57', '107', '97', '114'), +('2', '7', '66', '99', '58', '109', '99', '116'), +('2', '7', '67', '100', '58', '111', '100', '118'), +('2', '7', '68', '102', '59', '113', '102', '119'), +('2', '7', '69', '103', '60', '114', '103', '121'), +('2', '7', '70', '105', '61', '116', '105', '123'), +('2', '7', '71', '106', '62', '118', '117', '125'), +('2', '7', '72', '108', '63', '120', '119', '128'), +('2', '7', '73', '110', '64', '122', '122', '130'), +('2', '7', '74', '112', '65', '125', '124', '132'), +('2', '7', '75', '114', '66', '127', '126', '134'), +('2', '7', '76', '116', '67', '129', '128', '137'), +('2', '7', '77', '117', '68', '131', '128', '139'), +('2', '7', '78', '119', '69', '133', '133', '141'), +('2', '7', '79', '121', '70', '136', '135', '144'), +('2', '7', '80', '123', '71', '138', '137', '146'), +('2', '9', '1', '23', '17', '23', '19', '25'), +('2', '9', '2', '23', '17', '24', '20', '26'), +('2', '9', '3', '24', '18', '24', '21', '27'), +('2', '9', '4', '24', '18', '25', '23', '28'), +('2', '9', '5', '24', '18', '25', '24', '30'), +('2', '9', '6', '24', '19', '26', '25', '31'), +('2', '9', '7', '25', '19', '26', '26', '32'), +('2', '9', '8', '25', '20', '27', '27', '33'), +('2', '9', '9', '25', '20', '27', '29', '34'), +('2', '9', '10', '26', '20', '28', '30', '36'), +('2', '9', '11', '26', '21', '29', '31', '37'), +('2', '9', '12', '26', '21', '29', '33', '38'), +('2', '9', '13', '27', '22', '30', '34', '39'), +('2', '9', '14', '27', '22', '31', '35', '41'), +('2', '9', '15', '27', '23', '31', '37', '42'), +('2', '9', '16', '28', '23', '32', '38', '43'), +('2', '9', '17', '28', '23', '32', '39', '45'), +('2', '9', '18', '28', '24', '33', '41', '46'), +('2', '9', '19', '29', '24', '34', '42', '47'), +('2', '9', '20', '29', '25', '34', '43', '49'), +('2', '9', '21', '29', '25', '35', '45', '50'), +('2', '9', '22', '30', '26', '36', '46', '51'), +('2', '9', '23', '30', '26', '37', '48', '53'), +('2', '9', '24', '30', '27', '37', '49', '54'), +('2', '9', '25', '31', '27', '38', '51', '56'), +('2', '9', '26', '31', '28', '39', '52', '57'), +('2', '9', '27', '32', '28', '39', '54', '59'), +('2', '9', '28', '32', '29', '40', '55', '60'), +('2', '9', '29', '32', '29', '41', '57', '62'), +('2', '9', '30', '33', '30', '42', '58', '63'), +('2', '9', '31', '33', '30', '42', '60', '65'), +('2', '9', '32', '34', '31', '43', '61', '66'), +('2', '9', '33', '34', '31', '44', '63', '68'), +('2', '9', '34', '35', '32', '45', '64', '69'), +('2', '9', '35', '35', '32', '45', '66', '71'), +('2', '9', '36', '36', '33', '46', '68', '72'), +('2', '9', '37', '36', '34', '47', '69', '74'), +('2', '9', '38', '36', '34', '48', '71', '76'), +('2', '9', '39', '37', '35', '49', '72', '77'), +('2', '9', '40', '37', '35', '50', '74', '79'), +('2', '9', '41', '38', '36', '50', '76', '80'), +('2', '9', '42', '38', '36', '51', '77', '82'), +('2', '9', '43', '39', '37', '52', '79', '84'), +('2', '9', '44', '39', '38', '53', '81', '85'), +('2', '9', '45', '40', '38', '54', '83', '87'), +('2', '9', '46', '40', '39', '55', '84', '89'), +('2', '9', '47', '41', '39', '56', '86', '91'), +('2', '9', '48', '41', '40', '56', '88', '92'), +('2', '9', '49', '42', '41', '57', '90', '94'), +('2', '9', '50', '42', '41', '58', '91', '96'), +('2', '9', '51', '43', '42', '59', '93', '98'), +('2', '9', '52', '43', '43', '60', '95', '99'), +('2', '9', '53', '44', '43', '61', '97', '101'), +('2', '9', '54', '45', '44', '62', '99', '103'), +('2', '9', '55', '45', '45', '63', '101', '105'), +('2', '9', '56', '46', '45', '64', '102', '107'), +('2', '9', '57', '46', '46', '65', '104', '109'), +('2', '9', '58', '47', '47', '66', '106', '110'), +('2', '9', '59', '47', '47', '67', '108', '112'), +('2', '9', '60', '48', '48', '68', '110', '114'), +('2', '9', '61', '48', '49', '69', '112', '116'), +('2', '9', '62', '49', '49', '70', '114', '118'), +('2', '9', '63', '50', '50', '71', '116', '120'), +('2', '9', '64', '50', '51', '72', '118', '122'), +('2', '9', '65', '51', '51', '73', '120', '124'), +('2', '9', '66', '52', '52', '74', '122', '126'), +('2', '9', '67', '52', '53', '75', '124', '128'), +('2', '9', '68', '53', '54', '76', '126', '130'), +('2', '9', '69', '53', '54', '77', '128', '132'), +('2', '9', '70', '54', '55', '78', '130', '134'), +('2', '9', '71', '55', '56', '88', '134', '145'), +('2', '9', '72', '56', '56', '89', '135', '147'), +('2', '9', '73', '57', '57', '90', '137', '150'), +('2', '9', '74', '57', '58', '91', '142', '153'), +('2', '9', '75', '58', '59', '93', '142', '155'), +('2', '9', '76', '59', '60', '94', '145', '158'), +('2', '9', '77', '60', '61', '95', '148', '161'), +('2', '9', '78', '60', '62', '97', '150', '164'), +('2', '9', '79', '61', '63', '98', '153', '167'), +('2', '9', '80', '62', '64', '99', '156', '169'), +('3', '1', '1', '25', '16', '25', '19', '19'), +('3', '1', '2', '26', '17', '26', '19', '19'), +('3', '1', '3', '28', '18', '27', '19', '20'), +('3', '1', '4', '29', '18', '28', '19', '20'), +('3', '1', '5', '30', '19', '30', '19', '20'), +('3', '1', '6', '31', '20', '31', '19', '20'), +('3', '1', '7', '33', '21', '32', '20', '21'), +('3', '1', '8', '34', '22', '33', '20', '21'), +('3', '1', '9', '36', '23', '35', '20', '21'), +('3', '1', '10', '37', '23', '36', '20', '22'), +('3', '1', '11', '38', '24', '37', '20', '22'), +('3', '1', '12', '40', '25', '38', '20', '22'), +('3', '1', '13', '41', '26', '40', '20', '23'), +('3', '1', '14', '43', '27', '41', '20', '23'), +('3', '1', '15', '44', '28', '42', '20', '23'), +('3', '1', '16', '46', '29', '44', '21', '24'), +('3', '1', '17', '47', '30', '45', '21', '24'), +('3', '1', '18', '49', '31', '46', '21', '24'), +('3', '1', '19', '50', '32', '48', '21', '25'), +('3', '1', '20', '52', '33', '49', '21', '25'), +('3', '1', '21', '53', '34', '51', '21', '26'), +('3', '1', '22', '55', '34', '52', '21', '26'), +('3', '1', '23', '56', '35', '53', '21', '26'), +('3', '1', '24', '58', '36', '55', '22', '27'), +('3', '1', '25', '59', '37', '56', '22', '27'), +('3', '1', '26', '61', '38', '58', '22', '27'), +('3', '1', '27', '63', '39', '59', '22', '28'), +('3', '1', '28', '64', '41', '61', '22', '28'), +('3', '1', '29', '66', '42', '62', '22', '29'), +('3', '1', '30', '68', '43', '64', '23', '29'), +('3', '1', '31', '69', '44', '65', '23', '30'), +('3', '1', '32', '71', '45', '67', '23', '30'), +('3', '1', '33', '73', '46', '68', '23', '30'), +('3', '1', '34', '75', '47', '70', '23', '31'), +('3', '1', '35', '76', '48', '72', '24', '31'), +('3', '1', '36', '78', '49', '73', '24', '32'), +('3', '1', '37', '80', '50', '75', '24', '32'), +('3', '1', '38', '82', '51', '76', '24', '33'), +('3', '1', '39', '84', '52', '78', '24', '33'), +('3', '1', '40', '85', '54', '80', '24', '34'), +('3', '1', '41', '87', '55', '81', '25', '34'), +('3', '1', '42', '89', '56', '83', '25', '35'), +('3', '1', '43', '91', '57', '85', '25', '35'), +('3', '1', '44', '93', '58', '87', '25', '36'), +('3', '1', '45', '95', '59', '88', '26', '36'), +('3', '1', '46', '97', '61', '90', '26', '37'), +('3', '1', '47', '99', '62', '92', '26', '37'), +('3', '1', '48', '101', '63', '94', '26', '38'), +('3', '1', '49', '102', '64', '95', '26', '38'), +('3', '1', '50', '104', '65', '97', '27', '39'), +('3', '1', '51', '106', '67', '99', '27', '39'), +('3', '1', '52', '108', '68', '101', '27', '40'), +('3', '1', '53', '110', '69', '103', '27', '40'), +('3', '1', '54', '112', '70', '104', '28', '41'), +('3', '1', '55', '115', '72', '106', '28', '41'), +('3', '1', '56', '117', '73', '108', '28', '42'), +('3', '1', '57', '119', '74', '110', '28', '42'), +('3', '1', '58', '121', '76', '112', '29', '43'), +('3', '1', '59', '123', '77', '114', '29', '43'), +('3', '1', '60', '125', '78', '116', '29', '44'), +('3', '1', '61', '127', '80', '118', '29', '45'), +('3', '1', '62', '129', '81', '120', '30', '45'), +('3', '1', '63', '131', '82', '122', '30', '46'), +('3', '1', '64', '134', '84', '124', '30', '46'), +('3', '1', '65', '136', '85', '126', '31', '47'), +('3', '1', '66', '138', '86', '128', '31', '48'), +('3', '1', '67', '140', '88', '130', '31', '48'), +('3', '1', '68', '142', '89', '132', '31', '49'), +('3', '1', '69', '145', '91', '134', '32', '49'), +('3', '1', '70', '147', '92', '136', '32', '50'), +('3', '1', '71', '150', '93', '138', '32', '51'), +('3', '1', '72', '152', '95', '141', '32', '52'), +('3', '1', '73', '164', '97', '151', '32', '53'), +('3', '1', '74', '164', '98', '151', '33', '53'), +('3', '1', '75', '170', '100', '156', '33', '54'), +('3', '1', '76', '173', '102', '160', '33', '55'), +('3', '1', '77', '173', '104', '160', '34', '56'), +('3', '1', '78', '176', '105', '162', '34', '56'), +('3', '1', '79', '183', '107', '168', '34', '57'), +('3', '1', '80', '186', '109', '171', '35', '58'), +('3', '2', '1', '24', '16', '25', '19', '20'), +('3', '2', '2', '25', '17', '26', '20', '21'), +('3', '2', '3', '26', '17', '27', '20', '21'), +('3', '2', '4', '27', '18', '28', '21', '22'), +('3', '2', '5', '28', '18', '29', '22', '23'), +('3', '2', '6', '29', '19', '30', '22', '24'), +('3', '2', '7', '31', '20', '31', '23', '24'), +('3', '2', '8', '32', '20', '32', '24', '25'), +('3', '2', '9', '33', '21', '33', '24', '26'), +('3', '2', '10', '34', '21', '34', '25', '26'), +('3', '2', '11', '35', '22', '36', '26', '27'), +('3', '2', '12', '36', '23', '37', '26', '28'), +('3', '2', '13', '38', '23', '38', '27', '29'), +('3', '2', '14', '39', '24', '39', '28', '30'), +('3', '2', '15', '40', '25', '40', '29', '30'), +('3', '2', '16', '41', '25', '41', '29', '31'), +('3', '2', '17', '43', '26', '43', '30', '32'), +('3', '2', '18', '44', '27', '44', '31', '33'), +('3', '2', '19', '45', '28', '45', '32', '34'), +('3', '2', '20', '47', '28', '46', '32', '35'), +('3', '2', '21', '48', '29', '47', '33', '35'), +('3', '2', '22', '49', '30', '49', '34', '36'), +('3', '2', '23', '51', '30', '50', '35', '37'), +('3', '2', '24', '52', '31', '51', '36', '38'), +('3', '2', '25', '53', '32', '52', '36', '39'), +('3', '2', '26', '55', '33', '54', '37', '40'), +('3', '2', '27', '56', '33', '55', '38', '41'), +('3', '2', '28', '57', '34', '56', '39', '42'), +('3', '2', '29', '59', '35', '58', '40', '43'), +('3', '2', '30', '60', '36', '59', '41', '43'), +('3', '2', '31', '62', '37', '60', '42', '44'), +('3', '2', '32', '63', '37', '62', '42', '45'), +('3', '2', '33', '65', '38', '63', '43', '46'), +('3', '2', '34', '66', '39', '65', '44', '47'), +('3', '2', '35', '68', '40', '66', '45', '48'), +('3', '2', '36', '69', '41', '67', '46', '49'), +('3', '2', '37', '71', '41', '69', '47', '50'), +('3', '2', '38', '72', '42', '70', '48', '51'), +('3', '2', '39', '74', '43', '72', '49', '52'), +('3', '2', '40', '75', '44', '73', '50', '53'), +('3', '2', '41', '77', '45', '75', '51', '54'), +('3', '2', '42', '78', '46', '76', '52', '55'), +('3', '2', '43', '80', '47', '78', '53', '56'), +('3', '2', '44', '82', '47', '79', '54', '57'), +('3', '2', '45', '83', '48', '81', '55', '59'), +('3', '2', '46', '85', '49', '82', '56', '60'), +('3', '2', '47', '87', '50', '84', '57', '61'), +('3', '2', '48', '88', '51', '85', '58', '62'), +('3', '2', '49', '90', '52', '87', '59', '63'), +('3', '2', '50', '92', '53', '89', '60', '64'), +('3', '2', '51', '93', '54', '90', '61', '65'), +('3', '2', '52', '95', '55', '92', '62', '66'), +('3', '2', '53', '97', '56', '93', '63', '67'), +('3', '2', '54', '98', '57', '95', '64', '69'), +('3', '2', '55', '100', '58', '97', '65', '70'), +('3', '2', '56', '102', '59', '98', '66', '71'), +('3', '2', '57', '104', '60', '100', '67', '72'), +('3', '2', '58', '106', '61', '102', '68', '73'), +('3', '2', '59', '107', '62', '103', '69', '74'), +('3', '2', '60', '109', '63', '105', '70', '76'), +('3', '2', '61', '111', '64', '107', '72', '77'), +('3', '2', '62', '113', '65', '109', '73', '78'), +('3', '2', '63', '115', '66', '110', '74', '79'), +('3', '2', '64', '117', '67', '112', '75', '80'), +('3', '2', '65', '118', '68', '114', '76', '82'), +('3', '2', '66', '120', '69', '116', '77', '83'), +('3', '2', '67', '122', '70', '118', '78', '84'), +('3', '2', '68', '124', '71', '119', '80', '85'), +('3', '2', '69', '126', '72', '121', '81', '87'), +('3', '2', '70', '128', '73', '123', '82', '88'), +('3', '2', '71', '150', '74', '125', '83', '89'), +('3', '2', '72', '152', '75', '128', '85', '91'), +('3', '2', '73', '156', '76', '130', '86', '93'), +('3', '2', '74', '158', '78', '132', '88', '94'), +('3', '2', '75', '161', '79', '134', '89', '96'), +('3', '2', '76', '164', '80', '137', '91', '97'), +('3', '2', '77', '166', '82', '139', '92', '99'), +('3', '2', '78', '170', '83', '141', '94', '101'), +('3', '2', '79', '172', '84', '144', '95', '102'), +('3', '2', '80', '175', '86', '146', '97', '104'), +('3', '3', '1', '22', '19', '24', '19', '20'), +('3', '3', '2', '22', '20', '25', '20', '21'), +('3', '3', '3', '23', '22', '26', '20', '21'), +('3', '3', '4', '23', '23', '27', '21', '22'), +('3', '3', '5', '24', '25', '28', '21', '23'), +('3', '3', '6', '24', '26', '29', '22', '23'), +('3', '3', '7', '25', '27', '29', '23', '24'), +('3', '3', '8', '25', '29', '30', '23', '25'), +('3', '3', '9', '25', '30', '31', '24', '25'), +('3', '3', '10', '26', '32', '32', '24', '26'), +('3', '3', '11', '26', '33', '33', '25', '27'), +('3', '3', '12', '27', '35', '34', '26', '27'), +('3', '3', '13', '27', '36', '35', '26', '28'), +('3', '3', '14', '28', '38', '36', '27', '29'), +('3', '3', '15', '28', '39', '37', '28', '29'), +('3', '3', '16', '29', '41', '38', '28', '30'), +('3', '3', '17', '29', '42', '39', '29', '31'), +('3', '3', '18', '30', '44', '41', '30', '32'), +('3', '3', '19', '30', '46', '42', '30', '32'), +('3', '3', '20', '31', '47', '43', '31', '33'), +('3', '3', '21', '32', '49', '44', '32', '34'), +('3', '3', '22', '32', '51', '45', '33', '35'), +('3', '3', '23', '33', '52', '46', '33', '36'), +('3', '3', '24', '33', '54', '47', '34', '36'), +('3', '3', '25', '34', '56', '48', '35', '37'), +('3', '3', '26', '34', '57', '49', '35', '38'), +('3', '3', '27', '35', '59', '51', '36', '39'), +('3', '3', '28', '35', '61', '52', '37', '40'), +('3', '3', '29', '36', '63', '53', '38', '40'), +('3', '3', '30', '37', '64', '54', '39', '41'), +('3', '3', '31', '37', '66', '55', '39', '42'), +('3', '3', '32', '38', '68', '57', '40', '43'), +('3', '3', '33', '38', '70', '58', '41', '44'), +('3', '3', '34', '39', '71', '59', '42', '45'), +('3', '3', '35', '40', '73', '60', '43', '46'), +('3', '3', '36', '40', '75', '62', '43', '47'), +('3', '3', '37', '41', '77', '63', '44', '47'), +('3', '3', '38', '42', '79', '64', '45', '48'), +('3', '3', '39', '42', '81', '65', '46', '49'), +('3', '3', '40', '43', '83', '67', '47', '50'), +('3', '3', '41', '44', '85', '68', '48', '51'), +('3', '3', '42', '44', '87', '69', '49', '52'), +('3', '3', '43', '45', '89', '71', '49', '53'), +('3', '3', '44', '46', '91', '72', '50', '54'), +('3', '3', '45', '46', '93', '73', '51', '55'), +('3', '3', '46', '47', '95', '75', '52', '56'), +('3', '3', '47', '48', '97', '76', '53', '57'), +('3', '3', '48', '49', '99', '78', '54', '58'), +('3', '3', '49', '49', '101', '79', '55', '59'), +('3', '3', '50', '50', '103', '80', '56', '60'), +('3', '3', '51', '51', '105', '82', '57', '61'), +('3', '3', '52', '51', '107', '83', '58', '62'), +('3', '3', '53', '52', '109', '85', '59', '63'), +('3', '3', '54', '53', '111', '86', '60', '64'), +('3', '3', '55', '54', '113', '88', '61', '65'), +('3', '3', '56', '55', '115', '89', '62', '66'), +('3', '3', '57', '55', '118', '91', '62', '67'), +('3', '3', '58', '56', '120', '92', '63', '68'), +('3', '3', '59', '57', '122', '94', '64', '70'), +('3', '3', '60', '58', '124', '95', '65', '71'), +('3', '3', '61', '58', '126', '97', '67', '72'), +('3', '3', '62', '59', '129', '98', '68', '73'), +('3', '3', '63', '60', '131', '100', '69', '74'), +('3', '3', '64', '61', '133', '101', '70', '75'), +('3', '3', '65', '62', '135', '103', '71', '76'), +('3', '3', '66', '63', '138', '105', '72', '77'), +('3', '3', '67', '63', '140', '106', '73', '78'), +('3', '3', '68', '64', '142', '108', '74', '80'), +('3', '3', '69', '65', '145', '109', '75', '81'), +('3', '3', '70', '66', '147', '111', '76', '82'), +('3', '3', '71', '67', '150', '113', '77', '83'), +('3', '3', '72', '68', '153', '115', '78', '84'), +('3', '3', '73', '69', '156', '117', '79', '86'), +('3', '3', '74', '70', '159', '119', '81', '87'), +('3', '3', '75', '71', '162', '121', '82', '89'), +('3', '3', '76', '72', '165', '123', '83', '90'), +('3', '3', '77', '73', '168', '125', '85', '92'), +('3', '3', '78', '74', '171', '127', '86', '93'), +('3', '3', '79', '75', '174', '129', '87', '95'), +('3', '3', '80', '76', '177', '131', '89', '96'), +('3', '4', '1', '23', '19', '24', '19', '19'), +('3', '4', '2', '24', '20', '25', '19', '19'), +('3', '4', '3', '24', '22', '25', '19', '20'), +('3', '4', '4', '25', '23', '26', '19', '20'), +('3', '4', '5', '26', '25', '27', '20', '20'), +('3', '4', '6', '27', '26', '27', '20', '21'), +('3', '4', '7', '28', '28', '28', '20', '21'), +('3', '4', '8', '28', '29', '29', '20', '22'), +('3', '4', '9', '29', '31', '30', '20', '22'), +('3', '4', '10', '30', '32', '30', '20', '22'), +('3', '4', '11', '31', '34', '31', '21', '23'), +('3', '4', '12', '32', '36', '32', '21', '23'), +('3', '4', '13', '33', '37', '33', '21', '24'), +('3', '4', '14', '33', '39', '33', '21', '24'), +('3', '4', '15', '34', '40', '34', '21', '25'), +('3', '4', '16', '35', '42', '35', '22', '25'), +('3', '4', '17', '36', '44', '36', '22', '25'), +('3', '4', '18', '37', '45', '37', '22', '26'), +('3', '4', '19', '38', '47', '38', '22', '26'), +('3', '4', '20', '39', '49', '38', '22', '27'), +('3', '4', '21', '40', '51', '39', '23', '27'), +('3', '4', '22', '41', '52', '40', '23', '28'), +('3', '4', '23', '42', '54', '41', '23', '28'), +('3', '4', '24', '43', '56', '42', '23', '29'), +('3', '4', '25', '44', '58', '43', '24', '29'), +('3', '4', '26', '44', '59', '44', '24', '30'), +('3', '4', '27', '45', '61', '44', '24', '30'), +('3', '4', '28', '46', '63', '45', '24', '31'), +('3', '4', '29', '47', '65', '46', '25', '31'), +('3', '4', '30', '48', '67', '47', '25', '32'), +('3', '4', '31', '49', '69', '48', '25', '32'), +('3', '4', '32', '51', '71', '49', '25', '33'), +('3', '4', '33', '52', '72', '50', '26', '33'), +('3', '4', '34', '53', '74', '51', '26', '34'), +('3', '4', '35', '54', '76', '52', '26', '34'), +('3', '4', '36', '55', '78', '53', '26', '35'), +('3', '4', '37', '56', '80', '54', '27', '35'), +('3', '4', '38', '57', '82', '55', '27', '36'), +('3', '4', '39', '58', '84', '56', '27', '37'), +('3', '4', '40', '59', '86', '57', '28', '37'), +('3', '4', '41', '60', '88', '58', '28', '38'), +('3', '4', '42', '61', '90', '59', '28', '38'), +('3', '4', '43', '63', '92', '60', '28', '39'), +('3', '4', '44', '64', '95', '61', '29', '39'), +('3', '4', '45', '65', '97', '62', '29', '40'), +('3', '4', '46', '66', '99', '63', '29', '41'), +('3', '4', '47', '67', '101', '64', '30', '41'), +('3', '4', '48', '68', '103', '66', '30', '42'), +('3', '4', '49', '70', '105', '67', '30', '43'), +('3', '4', '50', '71', '107', '68', '31', '43'), +('3', '4', '51', '72', '110', '69', '31', '44'), +('3', '4', '52', '73', '112', '70', '31', '44'), +('3', '4', '53', '74', '114', '71', '32', '45'), +('3', '4', '54', '76', '116', '72', '32', '46'), +('3', '4', '55', '77', '118', '73', '32', '46'), +('3', '4', '56', '78', '121', '75', '33', '47'), +('3', '4', '57', '80', '123', '76', '33', '48'), +('3', '4', '58', '81', '125', '77', '33', '48'), +('3', '4', '59', '82', '128', '78', '34', '49'), +('3', '4', '60', '83', '130', '79', '34', '50'), +('3', '4', '61', '85', '132', '81', '34', '51'), +('3', '4', '62', '86', '135', '82', '35', '51'), +('3', '4', '63', '87', '137', '83', '35', '52'), +('3', '4', '64', '89', '139', '84', '36', '53'), +('3', '4', '65', '90', '142', '86', '36', '53'), +('3', '4', '66', '91', '144', '87', '36', '54'), +('3', '4', '67', '93', '147', '88', '37', '55'), +('3', '4', '68', '94', '149', '89', '37', '56'), +('3', '4', '69', '96', '152', '91', '38', '56'), +('3', '4', '70', '97', '154', '92', '38', '57'), +('3', '4', '71', '99', '157', '93', '38', '58'), +('3', '4', '72', '101', '160', '96', '39', '58'), +('3', '4', '73', '102', '163', '97', '39', '59'), +('3', '4', '74', '104', '166', '98', '40', '60'), +('3', '4', '75', '106', '169', '100', '40', '61'), +('3', '4', '76', '107', '172', '101', '40', '62'), +('3', '4', '77', '109', '175', '103', '41', '63'), +('3', '4', '78', '111', '179', '105', '41', '64'), +('3', '4', '79', '113', '182', '106', '42', '65'), +('3', '4', '80', '115', '185', '108', '42', '66'), +('3', '5', '1', '22', '16', '23', '21', '22'), +('3', '5', '2', '22', '16', '23', '22', '23'), +('3', '5', '3', '22', '16', '24', '24', '25'), +('3', '5', '4', '22', '17', '24', '25', '26'), +('3', '5', '5', '23', '17', '24', '26', '27'), +('3', '5', '6', '23', '17', '25', '28', '29'), +('3', '5', '7', '23', '17', '25', '29', '30'), +('3', '5', '8', '23', '18', '26', '30', '32'), +('3', '5', '9', '23', '18', '26', '32', '33'), +('3', '5', '10', '23', '18', '26', '33', '35'), +('3', '5', '11', '24', '18', '27', '35', '36'), +('3', '5', '12', '24', '19', '27', '36', '38'), +('3', '5', '13', '24', '19', '28', '37', '39'), +('3', '5', '14', '24', '19', '28', '39', '41'), +('3', '5', '15', '24', '19', '28', '40', '42'), +('3', '5', '16', '24', '20', '29', '42', '44'), +('3', '5', '17', '25', '20', '29', '43', '45'), +('3', '5', '18', '25', '20', '30', '45', '47'), +('3', '5', '19', '25', '21', '30', '46', '49'), +('3', '5', '20', '25', '21', '31', '48', '50'), +('3', '5', '21', '25', '21', '31', '50', '52'), +('3', '5', '22', '26', '22', '31', '51', '53'), +('3', '5', '23', '26', '22', '32', '53', '55'), +('3', '5', '24', '26', '22', '32', '54', '57'), +('3', '5', '25', '26', '22', '33', '56', '58'), +('3', '5', '26', '27', '23', '33', '58', '60'), +('3', '5', '27', '27', '23', '34', '59', '62'), +('3', '5', '28', '27', '23', '34', '61', '64'), +('3', '5', '29', '27', '24', '35', '63', '65'), +('3', '5', '30', '28', '24', '35', '64', '67'), +('3', '5', '31', '28', '24', '36', '66', '69'), +('3', '5', '32', '28', '25', '36', '68', '71'), +('3', '5', '33', '28', '25', '37', '70', '72'), +('3', '5', '34', '29', '26', '38', '71', '74'), +('3', '5', '35', '29', '26', '38', '73', '76'), +('3', '5', '36', '29', '26', '39', '75', '78'), +('3', '5', '37', '29', '27', '39', '77', '80'), +('3', '5', '38', '30', '27', '40', '78', '82'), +('3', '5', '39', '30', '27', '40', '80', '84'), +('3', '5', '40', '30', '28', '41', '82', '86'), +('3', '5', '41', '31', '28', '41', '84', '88'), +('3', '5', '42', '31', '29', '42', '86', '89'), +('3', '5', '43', '31', '29', '43', '88', '91'), +('3', '5', '44', '32', '29', '43', '90', '93'), +('3', '5', '45', '32', '30', '44', '92', '95'), +('3', '5', '46', '32', '30', '44', '93', '97'), +('3', '5', '47', '32', '30', '45', '95', '99'), +('3', '5', '48', '33', '31', '46', '97', '101'), +('3', '5', '49', '33', '31', '46', '99', '103'), +('3', '5', '50', '33', '32', '47', '101', '106'), +('3', '5', '51', '34', '32', '48', '103', '108'), +('3', '5', '52', '34', '33', '48', '105', '110'), +('3', '5', '53', '35', '33', '49', '107', '112'), +('3', '5', '54', '35', '33', '50', '109', '114'), +('3', '5', '55', '35', '34', '50', '111', '116'), +('3', '5', '56', '36', '34', '51', '113', '118'), +('3', '5', '57', '36', '35', '52', '116', '120'), +('3', '5', '58', '36', '35', '52', '118', '123'), +('3', '5', '59', '37', '36', '53', '120', '125'), +('3', '5', '60', '37', '36', '54', '122', '127'), +('3', '5', '61', '37', '37', '54', '124', '129'), +('3', '5', '62', '38', '37', '55', '126', '131'), +('3', '5', '63', '38', '38', '56', '128', '134'), +('3', '5', '64', '39', '38', '57', '131', '136'), +('3', '5', '65', '39', '39', '57', '133', '138'), +('3', '5', '66', '39', '39', '58', '135', '141'), +('3', '5', '67', '40', '40', '59', '137', '143'), +('3', '5', '68', '40', '40', '59', '139', '145'), +('3', '5', '69', '41', '40', '60', '142', '148'), +('3', '5', '70', '41', '41', '61', '144', '150'), +('3', '5', '71', '41', '42', '62', '147', '153'), +('3', '5', '72', '42', '42', '62', '150', '163'), +('3', '5', '73', '42', '43', '63', '153', '166'), +('3', '5', '74', '43', '43', '64', '155', '170'), +('3', '5', '75', '43', '44', '65', '158', '173'), +('3', '5', '76', '43', '45', '66', '161', '176'), +('3', '5', '77', '44', '45', '67', '164', '179'), +('3', '5', '78', '44', '46', '68', '167', '182'), +('3', '5', '79', '45', '46', '69', '170', '184'), +('3', '5', '80', '45', '47', '70', '173', '189'), +('3', '6', '1', '25', '16', '25', '19', '19'), +('3', '6', '2', '26', '17', '26', '19', '19'), +('3', '6', '3', '28', '18', '27', '19', '20'), +('3', '6', '4', '29', '18', '28', '19', '20'), +('3', '6', '5', '30', '19', '30', '19', '20'), +('3', '6', '6', '31', '20', '31', '19', '20'), +('3', '6', '7', '33', '21', '32', '20', '21'), +('3', '6', '8', '34', '22', '33', '20', '21'), +('3', '6', '9', '36', '23', '35', '20', '21'), +('3', '6', '10', '37', '23', '36', '20', '22'), +('3', '6', '11', '38', '24', '37', '20', '22'), +('3', '6', '12', '40', '25', '38', '20', '22'), +('3', '6', '13', '41', '26', '40', '20', '23'), +('3', '6', '14', '43', '27', '41', '20', '23'), +('3', '6', '15', '44', '28', '42', '20', '23'), +('3', '6', '16', '46', '29', '44', '21', '24'), +('3', '6', '17', '47', '30', '45', '21', '24'), +('3', '6', '18', '49', '31', '46', '21', '24'), +('3', '6', '19', '50', '32', '48', '21', '25'), +('3', '6', '20', '52', '33', '49', '21', '25'), +('3', '6', '21', '53', '34', '51', '21', '26'), +('3', '6', '22', '55', '34', '52', '21', '26'), +('3', '6', '23', '56', '35', '53', '21', '26'), +('3', '6', '24', '58', '36', '55', '22', '27'), +('3', '6', '25', '59', '37', '56', '22', '27'), +('3', '6', '26', '61', '38', '58', '22', '27'), +('3', '6', '27', '63', '39', '59', '22', '28'), +('3', '6', '28', '64', '41', '61', '22', '28'), +('3', '6', '29', '66', '42', '62', '22', '29'), +('3', '6', '30', '68', '43', '64', '23', '29'), +('3', '6', '31', '69', '44', '65', '23', '30'), +('3', '6', '32', '71', '45', '67', '23', '30'), +('3', '6', '33', '73', '46', '68', '23', '30'), +('3', '6', '34', '75', '47', '70', '23', '31'), +('3', '6', '35', '76', '48', '72', '24', '31'), +('3', '6', '36', '78', '49', '73', '24', '32'), +('3', '6', '37', '80', '50', '75', '24', '32'), +('3', '6', '38', '82', '51', '76', '24', '33'), +('3', '6', '39', '84', '52', '78', '24', '33'), +('3', '6', '40', '85', '54', '80', '24', '34'), +('3', '6', '41', '87', '55', '81', '25', '34'), +('3', '6', '42', '89', '56', '83', '25', '35'), +('3', '6', '43', '91', '57', '85', '25', '35'), +('3', '6', '44', '93', '58', '87', '25', '36'), +('3', '6', '45', '95', '59', '88', '26', '36'), +('3', '6', '46', '97', '61', '90', '26', '37'), +('3', '6', '47', '99', '62', '92', '26', '37'), +('3', '6', '48', '101', '63', '94', '26', '38'), +('3', '6', '49', '102', '64', '95', '26', '38'), +('3', '6', '50', '104', '65', '97', '27', '39'), +('3', '6', '51', '106', '67', '99', '27', '39'), +('3', '6', '52', '108', '68', '99', '27', '40'), +('3', '6', '53', '109', '68', '101', '27', '40'), +('3', '6', '54', '110', '69', '101', '28', '41'), +('3', '6', '55', '110', '69', '102', '28', '41'), +('3', '6', '56', '113', '71', '105', '28', '42'), +('3', '6', '57', '118', '72', '107', '28', '42'), +('3', '6', '58', '120', '73', '109', '29', '43'), +('3', '6', '59', '123', '75', '111', '29', '43'), +('3', '6', '60', '125', '76', '113', '29', '44'), +('3', '6', '61', '126', '77', '115', '29', '45'), +('3', '6', '62', '127', '79', '117', '29', '45'), +('3', '6', '63', '129', '80', '120', '30', '46'), +('3', '6', '64', '132', '82', '122', '30', '46'), +('3', '6', '65', '135', '83', '124', '30', '47'), +('3', '6', '66', '137', '85', '127', '30', '48'), +('3', '6', '67', '144', '86', '129', '31', '48'), +('3', '6', '68', '146', '88', '131', '31', '49'), +('3', '6', '69', '149', '89', '133', '31', '50'), +('3', '6', '70', '152', '91', '136', '31', '50'), +('3', '6', '71', '154', '93', '139', '32', '51'), +('3', '6', '72', '157', '94', '141', '32', '52'), +('3', '6', '73', '160', '96', '144', '32', '53'), +('3', '6', '74', '163', '98', '146', '32', '53'), +('3', '6', '75', '166', '99', '150', '33', '54'), +('3', '6', '76', '169', '101', '152', '33', '55'), +('3', '6', '77', '172', '103', '155', '33', '56'), +('3', '6', '78', '176', '104', '157', '33', '56'), +('3', '6', '79', '179', '106', '160', '34', '57'), +('3', '6', '80', '182', '108', '163', '34', '58'), +('4', '1', '1', '20', '25', '21', '20', '20'), +('4', '1', '2', '21', '26', '22', '20', '20'), +('4', '1', '3', '23', '27', '23', '20', '21'), +('4', '1', '4', '24', '27', '25', '20', '21'), +('4', '1', '5', '25', '28', '26', '20', '21'), +('4', '1', '6', '27', '29', '27', '20', '21'), +('4', '1', '7', '28', '30', '28', '21', '22'), +('4', '1', '8', '29', '31', '29', '21', '22'), +('4', '1', '9', '31', '31', '31', '21', '22'), +('4', '1', '10', '32', '32', '32', '21', '23'), +('4', '1', '11', '33', '33', '33', '21', '23'), +('4', '1', '12', '35', '34', '34', '21', '23'), +('4', '1', '13', '36', '35', '36', '21', '24'), +('4', '1', '14', '38', '36', '37', '21', '24'), +('4', '1', '15', '39', '37', '38', '21', '24'), +('4', '1', '16', '41', '37', '40', '21', '25'), +('4', '1', '17', '42', '38', '41', '22', '25'), +('4', '1', '18', '44', '39', '43', '22', '25'), +('4', '1', '19', '45', '40', '44', '22', '26'), +('4', '1', '20', '47', '41', '45', '22', '26'), +('4', '1', '21', '48', '42', '47', '22', '26'), +('4', '1', '22', '50', '43', '48', '22', '27'), +('4', '1', '23', '52', '44', '50', '22', '27'), +('4', '1', '24', '53', '45', '51', '23', '28'), +('4', '1', '25', '55', '46', '52', '23', '28'), +('4', '1', '26', '56', '47', '54', '23', '28'), +('4', '1', '27', '58', '48', '55', '23', '29'), +('4', '1', '28', '60', '49', '57', '23', '29'), +('4', '1', '29', '61', '50', '58', '23', '30'), +('4', '1', '30', '63', '51', '60', '24', '30'), +('4', '1', '31', '65', '52', '62', '24', '30'), +('4', '1', '32', '66', '53', '63', '24', '31'), +('4', '1', '33', '68', '54', '65', '24', '31'), +('4', '1', '34', '70', '55', '66', '24', '32'), +('4', '1', '35', '72', '56', '68', '24', '32'), +('4', '1', '36', '73', '58', '69', '25', '33'), +('4', '1', '37', '75', '59', '71', '25', '33'), +('4', '1', '38', '77', '60', '73', '25', '34'), +('4', '1', '39', '79', '61', '74', '25', '34'), +('4', '1', '40', '81', '62', '76', '25', '35'), +('4', '1', '41', '82', '63', '78', '26', '35'), +('4', '1', '42', '84', '64', '79', '26', '35'), +('4', '1', '43', '86', '66', '81', '26', '36'), +('4', '1', '44', '88', '67', '83', '26', '36'), +('4', '1', '45', '90', '68', '85', '26', '37'), +('4', '1', '46', '92', '69', '86', '27', '37'), +('4', '1', '47', '94', '70', '88', '27', '38'), +('4', '1', '48', '96', '72', '90', '27', '38'), +('4', '1', '49', '98', '73', '92', '27', '39'), +('4', '1', '50', '100', '74', '93', '28', '40'), +('4', '1', '51', '102', '75', '95', '28', '40'), +('4', '1', '52', '104', '77', '97', '28', '41'), +('4', '1', '53', '106', '78', '99', '28', '41'), +('4', '1', '54', '108', '79', '101', '29', '42'), +('4', '1', '55', '110', '80', '103', '29', '42'), +('4', '1', '56', '112', '82', '104', '29', '43'), +('4', '1', '57', '114', '83', '106', '29', '43'), +('4', '1', '58', '116', '84', '108', '30', '44'), +('4', '1', '59', '118', '86', '110', '30', '44'), +('4', '1', '60', '120', '87', '112', '30', '45'), +('4', '1', '61', '122', '88', '114', '30', '46'), +('4', '1', '62', '124', '90', '116', '31', '46'), +('4', '1', '63', '127', '91', '118', '31', '47'), +('4', '1', '64', '129', '92', '120', '31', '47'), +('4', '1', '65', '131', '94', '122', '32', '48'), +('4', '1', '66', '133', '95', '124', '32', '49'), +('4', '1', '67', '135', '97', '126', '32', '49'), +('4', '1', '68', '138', '98', '128', '32', '50'), +('4', '1', '69', '140', '100', '130', '33', '50'), +('4', '1', '70', '142', '101', '132', '33', '51'), +('4', '1', '71', '145', '102', '134', '33', '52'), +('4', '1', '72', '147', '104', '137', '33', '53'), +('4', '1', '73', '150', '106', '139', '33', '54'), +('4', '1', '74', '153', '107', '142', '34', '54'), +('4', '1', '75', '156', '109', '144', '34', '55'), +('4', '1', '76', '159', '111', '148', '34', '56'), +('4', '1', '77', '162', '113', '150', '35', '57'), +('4', '1', '78', '165', '114', '152', '35', '57'), +('4', '1', '79', '178', '116', '164', '35', '58'), +('4', '1', '80', '181', '118', '167', '36', '59'), +('4', '3', '1', '17', '28', '20', '20', '21'), +('4', '3', '2', '17', '29', '21', '21', '22'), +('4', '3', '3', '18', '31', '22', '21', '22'), +('4', '3', '4', '18', '32', '23', '22', '23'), +('4', '3', '5', '19', '33', '24', '22', '24'), +('4', '3', '6', '19', '35', '25', '23', '24'), +('4', '3', '7', '20', '36', '26', '24', '25'), +('4', '3', '8', '20', '38', '27', '24', '25'), +('4', '3', '9', '21', '39', '27', '25', '26'), +('4', '3', '10', '21', '40', '28', '25', '27'), +('4', '3', '11', '22', '42', '29', '26', '28'), +('4', '3', '12', '22', '43', '30', '27', '28'), +('4', '3', '13', '23', '45', '31', '27', '29'), +('4', '3', '14', '23', '46', '32', '28', '30'), +('4', '3', '15', '24', '48', '34', '29', '30'), +('4', '3', '16', '24', '50', '35', '29', '31'), +('4', '3', '17', '25', '51', '36', '30', '32'), +('4', '3', '18', '25', '53', '37', '31', '33'), +('4', '3', '19', '26', '54', '38', '31', '33'), +('4', '3', '20', '26', '56', '39', '32', '34'), +('4', '3', '21', '27', '57', '40', '33', '35'), +('4', '3', '22', '27', '59', '41', '33', '36'), +('4', '3', '23', '28', '61', '42', '34', '36'), +('4', '3', '24', '28', '62', '43', '35', '37'), +('4', '3', '25', '29', '64', '44', '36', '38'), +('4', '3', '26', '30', '66', '46', '36', '39'), +('4', '3', '27', '30', '68', '47', '37', '40'), +('4', '3', '28', '31', '69', '48', '38', '41'), +('4', '3', '29', '31', '71', '49', '39', '41'), +('4', '3', '30', '32', '73', '50', '39', '42'), +('4', '3', '31', '33', '75', '52', '40', '43'), +('4', '3', '32', '33', '76', '53', '41', '44'), +('4', '3', '33', '34', '78', '54', '42', '45'), +('4', '3', '34', '34', '80', '55', '43', '46'), +('4', '3', '35', '35', '82', '57', '44', '47'), +('4', '3', '36', '36', '84', '58', '44', '48'), +('4', '3', '37', '36', '86', '59', '45', '48'), +('4', '3', '38', '37', '87', '60', '46', '49'), +('4', '3', '39', '38', '89', '62', '47', '50'), +('4', '3', '40', '38', '91', '63', '48', '51'), +('4', '3', '41', '39', '93', '64', '49', '52'), +('4', '3', '42', '40', '95', '66', '49', '53'), +('4', '3', '43', '40', '97', '67', '50', '54'), +('4', '3', '44', '41', '99', '68', '51', '55'), +('4', '3', '45', '42', '101', '70', '52', '56'), +('4', '3', '46', '42', '103', '71', '53', '57'), +('4', '3', '47', '43', '105', '72', '54', '58'), +('4', '3', '48', '44', '107', '74', '55', '59'), +('4', '3', '49', '45', '109', '75', '56', '60'), +('4', '3', '50', '45', '111', '77', '57', '61'), +('4', '3', '51', '46', '113', '78', '58', '62'), +('4', '3', '52', '47', '115', '79', '59', '63'), +('4', '3', '53', '47', '118', '81', '60', '64'), +('4', '3', '54', '48', '120', '82', '61', '65'), +('4', '3', '55', '49', '122', '84', '61', '66'), +('4', '3', '56', '50', '124', '85', '62', '67'), +('4', '3', '57', '50', '126', '87', '63', '68'), +('4', '3', '58', '51', '128', '88', '64', '69'), +('4', '3', '59', '52', '131', '90', '65', '70'), +('4', '3', '60', '53', '133', '91', '66', '72'), +('4', '3', '61', '54', '135', '93', '67', '73'), +('4', '3', '62', '54', '137', '94', '69', '74'), +('4', '3', '63', '55', '140', '96', '70', '75'), +('4', '3', '64', '56', '142', '97', '71', '76'), +('4', '3', '65', '57', '144', '99', '72', '77'), +('4', '3', '66', '58', '147', '101', '73', '78'), +('4', '3', '67', '58', '149', '102', '74', '79'), +('4', '3', '68', '59', '151', '104', '75', '81'), +('4', '3', '69', '60', '154', '105', '76', '82'), +('4', '3', '70', '61', '156', '107', '77', '83'), +('4', '3', '71', '62', '159', '109', '78', '84'), +('4', '3', '72', '63', '162', '111', '79', '85'), +('4', '3', '73', '64', '165', '113', '80', '87'), +('4', '3', '74', '65', '168', '115', '82', '88'), +('4', '3', '75', '66', '171', '117', '83', '90'), +('4', '3', '76', '67', '174', '119', '84', '91'), +('4', '3', '77', '68', '177', '121', '86', '93'), +('4', '3', '78', '69', '180', '123', '87', '94'), +('4', '3', '79', '70', '190', '125', '91', '96'), +('4', '3', '80', '71', '193', '127', '93', '97'), +('4', '4', '1', '18', '28', '20', '20', '20'), +('4', '4', '2', '19', '29', '21', '20', '20'), +('4', '4', '3', '20', '31', '21', '20', '21'), +('4', '4', '4', '20', '32', '22', '20', '21'), +('4', '4', '5', '21', '34', '23', '21', '21'), +('4', '4', '6', '22', '35', '24', '21', '22'), +('4', '4', '7', '23', '37', '24', '21', '22'), +('4', '4', '8', '24', '38', '25', '21', '23'), +('4', '4', '9', '24', '40', '26', '21', '23'), +('4', '4', '10', '25', '41', '26', '21', '23'), +('4', '4', '11', '26', '43', '27', '22', '24'), +('4', '4', '12', '27', '44', '28', '22', '24'), +('4', '4', '13', '28', '46', '29', '22', '25'), +('4', '4', '14', '29', '48', '30', '22', '25'), +('4', '4', '15', '29', '49', '30', '22', '25'), +('4', '4', '16', '30', '51', '31', '23', '26'), +('4', '4', '17', '31', '52', '32', '23', '26'), +('4', '4', '18', '32', '54', '33', '23', '27'), +('4', '4', '19', '33', '56', '34', '23', '27'), +('4', '4', '20', '34', '57', '35', '23', '28'), +('4', '4', '21', '35', '59', '35', '24', '28'), +('4', '4', '22', '36', '61', '36', '24', '29'), +('4', '4', '23', '37', '63', '37', '24', '29'), +('4', '4', '24', '38', '64', '38', '24', '30'), +('4', '4', '25', '39', '66', '39', '25', '30'), +('4', '4', '26', '40', '68', '40', '25', '31'), +('4', '4', '27', '41', '70', '41', '25', '31'), +('4', '4', '28', '42', '72', '42', '25', '32'), +('4', '4', '29', '43', '73', '43', '25', '32'), +('4', '4', '30', '44', '75', '43', '26', '33'), +('4', '4', '31', '45', '77', '44', '26', '33'), +('4', '4', '32', '46', '79', '45', '26', '34'), +('4', '4', '33', '47', '81', '46', '27', '34'), +('4', '4', '34', '48', '83', '47', '27', '35'), +('4', '4', '35', '49', '85', '48', '27', '35'), +('4', '4', '36', '50', '87', '49', '27', '36'), +('4', '4', '37', '51', '89', '50', '28', '36'), +('4', '4', '38', '52', '91', '51', '28', '37'), +('4', '4', '39', '53', '93', '52', '28', '38'), +('4', '4', '40', '54', '95', '53', '28', '38'), +('4', '4', '41', '56', '97', '54', '29', '39'), +('4', '4', '42', '57', '99', '55', '29', '39'), +('4', '4', '43', '58', '101', '56', '29', '40'), +('4', '4', '44', '59', '103', '57', '30', '40'), +('4', '4', '45', '60', '105', '59', '30', '41'), +('4', '4', '46', '61', '107', '60', '30', '42'), +('4', '4', '47', '62', '109', '61', '31', '42'), +('4', '4', '48', '64', '112', '62', '31', '43'), +('4', '4', '49', '65', '114', '63', '31', '44'), +('4', '4', '50', '66', '116', '64', '32', '44'), +('4', '4', '51', '67', '118', '65', '32', '45'), +('4', '4', '52', '68', '120', '66', '32', '45'), +('4', '4', '53', '70', '123', '67', '33', '46'), +('4', '4', '54', '71', '125', '69', '33', '47'), +('4', '4', '55', '72', '127', '70', '33', '47'), +('4', '4', '56', '73', '129', '71', '34', '48'), +('4', '4', '57', '75', '132', '72', '34', '49'), +('4', '4', '58', '76', '134', '73', '34', '49'), +('4', '4', '59', '77', '136', '74', '35', '50'), +('4', '4', '60', '79', '139', '76', '35', '51'), +('4', '4', '61', '80', '141', '77', '35', '51'), +('4', '4', '62', '81', '143', '78', '36', '52'), +('4', '4', '63', '82', '146', '79', '36', '53'), +('4', '4', '64', '84', '148', '80', '37', '54'), +('4', '4', '65', '85', '151', '82', '37', '54'), +('4', '4', '66', '87', '153', '83', '37', '55'), +('4', '4', '67', '88', '156', '84', '38', '56'), +('4', '4', '68', '89', '158', '85', '38', '57'), +('4', '4', '69', '91', '160', '87', '39', '57'), +('4', '4', '70', '92', '163', '88', '39', '58'), +('4', '4', '71', '94', '166', '90', '39', '59'), +('4', '4', '72', '96', '169', '91', '40', '59'), +('4', '4', '73', '97', '172', '93', '40', '60'), +('4', '4', '74', '99', '175', '94', '41', '61'), +('4', '4', '75', '101', '178', '96', '41', '62'), +('4', '4', '76', '102', '181', '97', '41', '63'), +('4', '4', '77', '104', '184', '99', '42', '64'), +('4', '4', '78', '106', '188', '101', '42', '65'), +('4', '4', '79', '108', '191', '102', '43', '66'), +('4', '4', '80', '110', '194', '104', '43', '67'), +('4', '5', '1', '17', '25', '19', '22', '23'), +('4', '5', '2', '17', '25', '19', '23', '24'), +('4', '5', '3', '17', '25', '20', '25', '26'), +('4', '5', '4', '17', '26', '20', '26', '27'), +('4', '5', '5', '18', '26', '20', '27', '28'), +('4', '5', '6', '18', '26', '21', '29', '30'), +('4', '5', '7', '18', '26', '21', '30', '31'), +('4', '5', '8', '18', '26', '22', '31', '33'), +('4', '5', '9', '18', '27', '22', '33', '34'), +('4', '5', '10', '19', '27', '22', '34', '36'), +('4', '5', '11', '19', '27', '23', '36', '37'), +('4', '5', '12', '19', '27', '23', '37', '39'), +('4', '5', '13', '19', '28', '24', '38', '40'), +('4', '5', '14', '19', '28', '24', '40', '42'), +('4', '5', '15', '19', '28', '25', '41', '43'), +('4', '5', '16', '20', '28', '25', '43', '45'), +('4', '5', '17', '20', '29', '25', '44', '46'), +('4', '5', '18', '20', '29', '26', '46', '48'), +('4', '5', '19', '20', '29', '26', '47', '49'), +('4', '5', '20', '21', '30', '27', '49', '51'), +('4', '5', '21', '21', '30', '27', '51', '53'), +('4', '5', '22', '21', '30', '28', '52', '54'), +('4', '5', '23', '21', '30', '28', '54', '56'), +('4', '5', '24', '21', '31', '29', '55', '58'), +('4', '5', '25', '22', '31', '29', '57', '59'), +('4', '5', '26', '22', '31', '30', '59', '61'), +('4', '5', '27', '22', '32', '30', '60', '63'), +('4', '5', '28', '22', '32', '31', '62', '65'), +('4', '5', '29', '23', '32', '31', '64', '66'), +('4', '5', '30', '23', '33', '32', '65', '68'), +('4', '5', '31', '23', '33', '32', '67', '70'), +('4', '5', '32', '23', '33', '33', '69', '72'), +('4', '5', '33', '24', '34', '33', '70', '73'), +('4', '5', '34', '24', '34', '34', '72', '75'), +('4', '5', '35', '24', '34', '34', '74', '77'), +('4', '5', '36', '24', '35', '35', '76', '79'), +('4', '5', '37', '25', '35', '35', '78', '81'), +('4', '5', '38', '25', '35', '36', '79', '83'), +('4', '5', '39', '25', '36', '37', '81', '85'), +('4', '5', '40', '26', '36', '37', '83', '87'), +('4', '5', '41', '26', '37', '38', '85', '88'), +('4', '5', '42', '26', '37', '38', '87', '90'), +('4', '5', '43', '27', '37', '39', '89', '92'), +('4', '5', '44', '27', '38', '39', '91', '94'), +('4', '5', '45', '27', '38', '40', '92', '96'), +('4', '5', '46', '27', '39', '41', '94', '98'), +('4', '5', '47', '28', '39', '41', '96', '100'), +('4', '5', '48', '28', '39', '42', '98', '102'), +('4', '5', '49', '28', '40', '43', '100', '104'), +('4', '5', '50', '29', '40', '43', '102', '106'), +('4', '5', '51', '29', '41', '44', '104', '109'), +('4', '5', '52', '29', '41', '44', '106', '111'), +('4', '5', '53', '30', '42', '45', '108', '113'), +('4', '5', '54', '30', '42', '46', '110', '115'), +('4', '5', '55', '30', '43', '46', '112', '117'), +('4', '5', '56', '31', '43', '47', '114', '119'), +('4', '5', '57', '31', '43', '48', '117', '121'), +('4', '5', '58', '31', '44', '48', '119', '124'), +('4', '5', '59', '32', '44', '49', '121', '126'), +('4', '5', '60', '32', '45', '50', '123', '128'), +('4', '5', '61', '33', '45', '51', '125', '130'), +('4', '5', '62', '33', '46', '51', '127', '132'), +('4', '5', '63', '33', '46', '52', '129', '135'), +('4', '5', '64', '34', '47', '53', '132', '137'), +('4', '5', '65', '34', '47', '53', '134', '139'), +('4', '5', '66', '34', '48', '54', '136', '142'), +('4', '5', '67', '35', '48', '55', '138', '144'), +('4', '5', '68', '35', '49', '56', '140', '146'), +('4', '5', '69', '36', '49', '56', '143', '149'), +('4', '5', '70', '36', '50', '57', '145', '151'), +('4', '5', '71', '36', '51', '58', '148', '161'), +('4', '5', '72', '37', '51', '58', '151', '164'), +('4', '5', '73', '37', '52', '59', '154', '168'), +('4', '5', '74', '38', '52', '60', '156', '171'), +('4', '5', '75', '38', '53', '61', '159', '174'), +('4', '5', '76', '38', '54', '62', '162', '177'), +('4', '5', '77', '39', '54', '63', '165', '180'), +('4', '5', '78', '39', '55', '64', '168', '183'), +('4', '5', '79', '40', '55', '65', '171', '186'), +('4', '5', '80', '40', '56', '66', '200', '191'), +('4', '6', '1', '20', '25', '21', '20', '20'), +('4', '6', '2', '21', '26', '22', '20', '20'), +('4', '6', '3', '23', '27', '23', '20', '21'), +('4', '6', '4', '24', '27', '25', '20', '21'), +('4', '6', '5', '25', '28', '26', '20', '21'), +('4', '6', '6', '27', '29', '27', '20', '21'), +('4', '6', '7', '28', '30', '28', '21', '22'), +('4', '6', '8', '29', '31', '29', '21', '22'), +('4', '6', '9', '31', '31', '31', '21', '22'), +('4', '6', '10', '32', '32', '32', '21', '23'), +('4', '6', '11', '33', '33', '33', '21', '23'), +('4', '6', '12', '35', '34', '34', '21', '23'), +('4', '6', '13', '36', '35', '36', '21', '24'), +('4', '6', '14', '38', '36', '37', '21', '24'), +('4', '6', '15', '39', '37', '38', '21', '24'), +('4', '6', '16', '41', '37', '40', '21', '25'), +('4', '6', '17', '42', '38', '41', '22', '25'), +('4', '6', '18', '44', '39', '43', '22', '25'), +('4', '6', '19', '45', '40', '44', '22', '26'), +('4', '6', '20', '47', '41', '45', '22', '26'), +('4', '6', '21', '48', '42', '47', '22', '26'), +('4', '6', '22', '50', '43', '48', '22', '27'), +('4', '6', '23', '52', '44', '50', '22', '27'), +('4', '6', '24', '53', '45', '51', '23', '28'), +('4', '6', '25', '55', '46', '52', '23', '28'), +('4', '6', '26', '56', '47', '54', '23', '28'), +('4', '6', '27', '58', '48', '55', '23', '29'), +('4', '6', '28', '60', '49', '57', '23', '29'), +('4', '6', '29', '61', '50', '58', '23', '30'), +('4', '6', '30', '63', '51', '60', '24', '30'), +('4', '6', '31', '65', '52', '62', '24', '30'), +('4', '6', '32', '66', '53', '63', '24', '31'), +('4', '6', '33', '68', '54', '65', '24', '31'), +('4', '6', '34', '70', '55', '66', '24', '32'), +('4', '6', '35', '72', '56', '68', '24', '32'), +('4', '6', '36', '73', '58', '69', '25', '33'), +('4', '6', '37', '75', '59', '71', '25', '33'), +('4', '6', '38', '77', '60', '73', '25', '34'), +('4', '6', '39', '79', '61', '74', '25', '34'), +('4', '6', '40', '81', '62', '76', '25', '35'), +('4', '6', '41', '82', '63', '78', '26', '35'), +('4', '6', '42', '84', '64', '79', '26', '35'), +('4', '6', '43', '86', '66', '81', '26', '36'), +('4', '6', '44', '88', '67', '83', '26', '36'), +('4', '6', '45', '90', '68', '85', '26', '37'), +('4', '6', '46', '92', '69', '86', '27', '37'), +('4', '6', '47', '94', '70', '88', '27', '38'), +('4', '6', '48', '96', '72', '90', '27', '38'), +('4', '6', '49', '98', '73', '92', '27', '39'), +('4', '6', '50', '100', '74', '93', '28', '40'), +('4', '6', '51', '101', '75', '94', '28', '40'), +('4', '6', '52', '102', '76', '95', '28', '41'), +('4', '6', '53', '103', '77', '96', '28', '41'), +('4', '6', '54', '104', '77', '97', '29', '42'), +('4', '6', '55', '105', '78', '98', '29', '42'), +('4', '6', '56', '108', '80', '101', '29', '43'), +('4', '6', '57', '113', '81', '103', '29', '43'), +('4', '6', '58', '115', '82', '105', '30', '44'), +('4', '6', '59', '115', '84', '107', '30', '44'), +('4', '6', '60', '120', '85', '109', '30', '45'), +('4', '6', '61', '122', '86', '111', '30', '46'), +('4', '6', '62', '122', '88', '113', '30', '46'), +('4', '6', '63', '127', '89', '116', '31', '47'), +('4', '6', '64', '127', '91', '118', '31', '47'), +('4', '6', '65', '133', '92', '120', '31', '48'), +('4', '6', '66', '135', '94', '123', '31', '49'), +('4', '6', '67', '136', '95', '125', '32', '49'), +('4', '6', '68', '137', '97', '127', '32', '50'), +('4', '6', '69', '140', '98', '130', '32', '51'), +('4', '6', '70', '147', '100', '132', '32', '51'), +('4', '6', '71', '154', '102', '135', '33', '52'), +('4', '6', '72', '156', '103', '137', '33', '53'), +('4', '6', '73', '157', '105', '140', '33', '54'), +('4', '6', '74', '158', '107', '142', '33', '54'), +('4', '6', '75', '161', '108', '145', '34', '55'), +('4', '6', '76', '164', '110', '148', '34', '56'), +('4', '6', '77', '167', '112', '150', '34', '57'), +('4', '6', '78', '170', '113', '153', '34', '57'), +('4', '6', '79', '172', '115', '156', '35', '58'), +('4', '6', '80', '177', '117', '159', '35', '59'), +('4', '11', '1', '18', '25', '19', '22', '22'), +('4', '11', '2', '19', '25', '20', '23', '23'), +('4', '11', '3', '19', '26', '20', '24', '24'), +('4', '11', '4', '20', '26', '21', '25', '26'), +('4', '11', '5', '20', '27', '22', '26', '27'), +('4', '11', '6', '21', '27', '22', '27', '28'), +('4', '11', '7', '21', '28', '23', '28', '29'), +('4', '11', '8', '22', '28', '24', '29', '30'), +('4', '11', '9', '23', '29', '24', '30', '32'), +('4', '11', '10', '23', '29', '25', '32', '33'), +('4', '11', '11', '24', '30', '26', '33', '34'), +('4', '11', '12', '24', '31', '26', '34', '35'), +('4', '11', '13', '25', '31', '27', '35', '37'), +('4', '11', '14', '26', '32', '28', '36', '38'), +('4', '11', '15', '26', '32', '29', '37', '39'), +('4', '11', '16', '27', '33', '29', '38', '41'), +('4', '11', '17', '28', '33', '30', '40', '42'), +('4', '11', '18', '28', '34', '31', '41', '43'), +('4', '11', '19', '29', '35', '32', '42', '45'), +('4', '11', '20', '30', '35', '32', '43', '46'), +('4', '11', '21', '30', '36', '33', '45', '48'), +('4', '11', '22', '31', '36', '34', '46', '49'), +('4', '11', '23', '32', '37', '35', '47', '51'), +('4', '11', '24', '32', '38', '36', '48', '52'), +('4', '11', '25', '33', '38', '36', '50', '53'), +('4', '11', '26', '34', '39', '37', '51', '55'), +('4', '11', '27', '35', '40', '38', '52', '56'), +('4', '11', '28', '35', '40', '39', '54', '58'), +('4', '11', '29', '36', '41', '40', '55', '59'), +('4', '11', '30', '37', '42', '41', '56', '61'), +('4', '11', '31', '38', '42', '42', '58', '62'), +('4', '11', '32', '38', '43', '42', '59', '64'), +('4', '11', '33', '39', '44', '43', '60', '66'), +('4', '11', '34', '40', '44', '44', '62', '67'), +('4', '11', '35', '41', '45', '45', '63', '69'), +('4', '11', '36', '42', '46', '46', '65', '70'), +('4', '11', '37', '42', '47', '47', '66', '72'), +('4', '11', '38', '43', '47', '48', '67', '74'), +('4', '11', '39', '44', '48', '49', '69', '75'), +('4', '11', '40', '45', '49', '50', '70', '77'), +('4', '11', '41', '46', '50', '51', '72', '79'), +('4', '11', '42', '46', '50', '52', '73', '80'), +('4', '11', '43', '47', '51', '53', '75', '82'), +('4', '11', '44', '48', '52', '54', '76', '84'), +('4', '11', '45', '49', '53', '55', '78', '85'), +('4', '11', '46', '50', '54', '56', '79', '87'), +('4', '11', '47', '51', '54', '57', '81', '89'), +('4', '11', '48', '52', '55', '58', '83', '91'), +('4', '11', '49', '53', '56', '59', '84', '93'), +('4', '11', '50', '53', '57', '60', '86', '94'), +('4', '11', '51', '54', '58', '61', '87', '96'), +('4', '11', '52', '55', '59', '62', '89', '98'), +('4', '11', '53', '56', '59', '63', '91', '100'), +('4', '11', '54', '57', '60', '64', '92', '102'), +('4', '11', '55', '58', '61', '65', '94', '103'), +('4', '11', '56', '59', '62', '66', '95', '105'), +('4', '11', '57', '60', '63', '67', '97', '107'), +('4', '11', '58', '61', '64', '68', '99', '109'), +('4', '11', '59', '62', '65', '69', '101', '111'), +('4', '11', '60', '63', '66', '70', '102', '113'), +('4', '11', '61', '64', '66', '72', '104', '115'), +('4', '11', '62', '65', '67', '73', '106', '117'), +('4', '11', '63', '66', '68', '74', '107', '119'), +('4', '11', '64', '67', '69', '75', '109', '121'), +('4', '11', '65', '68', '70', '76', '111', '123'), +('4', '11', '66', '69', '71', '77', '113', '125'), +('4', '11', '67', '70', '72', '78', '115', '127'), +('4', '11', '68', '71', '73', '80', '116', '129'), +('4', '11', '69', '72', '74', '81', '118', '131'), +('4', '11', '70', '73', '75', '82', '120', '133'), +('4', '11', '71', '75', '76', '83', '122', '135'), +('4', '11', '72', '76', '78', '85', '125', '138'), +('4', '11', '73', '77', '79', '86', '127', '140'), +('4', '11', '74', '78', '80', '88', '131', '143'), +('4', '11', '75', '80', '81', '89', '133', '145'), +('4', '11', '76', '81', '82', '91', '134', '148'), +('4', '11', '77', '82', '83', '92', '136', '151'), +('4', '11', '78', '84', '85', '94', '138', '153'), +('4', '11', '79', '85', '86', '95', '141', '156'), +('4', '11', '80', '86', '87', '97', '143', '159'), +('5', '1', '1', '22', '18', '23', '18', '25'), +('5', '1', '2', '23', '19', '24', '18', '25'), +('5', '1', '3', '25', '20', '25', '18', '26'), +('5', '1', '4', '26', '20', '26', '18', '26'), +('5', '1', '5', '27', '21', '28', '18', '26'), +('5', '1', '6', '29', '22', '29', '18', '26'), +('5', '1', '7', '30', '23', '30', '19', '27'), +('5', '1', '8', '31', '24', '31', '19', '27'), +('5', '1', '9', '33', '25', '33', '19', '27'), +('5', '1', '10', '34', '25', '34', '19', '28'), +('5', '1', '11', '35', '26', '35', '19', '28'), +('5', '1', '12', '37', '27', '36', '19', '28'), +('5', '1', '13', '38', '28', '38', '19', '28'), +('5', '1', '14', '40', '29', '39', '19', '29'), +('5', '1', '15', '41', '30', '40', '19', '29'), +('5', '1', '16', '43', '31', '42', '20', '29'), +('5', '1', '17', '44', '32', '43', '20', '30'), +('5', '1', '18', '46', '33', '44', '20', '30'), +('5', '1', '19', '47', '34', '46', '20', '31'), +('5', '1', '20', '49', '34', '47', '20', '31'), +('5', '1', '21', '50', '35', '49', '20', '31'), +('5', '1', '22', '52', '36', '50', '20', '32'), +('5', '1', '23', '53', '37', '51', '21', '32'), +('5', '1', '24', '55', '38', '53', '21', '32'), +('5', '1', '25', '57', '39', '54', '21', '33'), +('5', '1', '26', '58', '40', '56', '21', '33'), +('5', '1', '27', '60', '41', '57', '21', '34'), +('5', '1', '28', '62', '42', '59', '21', '34'), +('5', '1', '29', '63', '43', '60', '21', '34'), +('5', '1', '30', '65', '44', '62', '22', '35'), +('5', '1', '31', '67', '46', '63', '22', '35'), +('5', '1', '32', '68', '47', '65', '22', '36'), +('5', '1', '33', '70', '48', '67', '22', '36'), +('5', '1', '34', '72', '49', '68', '22', '36'), +('5', '1', '35', '74', '50', '70', '23', '37'), +('5', '1', '36', '75', '51', '71', '23', '37'), +('5', '1', '37', '77', '52', '73', '23', '38'), +('5', '1', '38', '79', '53', '75', '23', '38'), +('5', '1', '39', '81', '54', '76', '23', '39'), +('5', '1', '40', '83', '55', '78', '24', '39'), +('5', '1', '41', '84', '57', '80', '24', '40'), +('5', '1', '42', '86', '58', '81', '24', '40'), +('5', '1', '43', '88', '59', '83', '24', '41'), +('5', '1', '44', '90', '60', '85', '24', '41'), +('5', '1', '45', '92', '61', '86', '25', '42'), +('5', '1', '46', '94', '62', '88', '25', '42'), +('5', '1', '47', '96', '64', '90', '25', '43'), +('5', '1', '48', '98', '65', '92', '25', '43'), +('5', '1', '49', '100', '66', '93', '25', '44'), +('5', '1', '50', '102', '67', '95', '26', '44'), +('5', '1', '51', '104', '69', '97', '26', '45'), +('5', '1', '52', '106', '70', '99', '26', '45'), +('5', '1', '53', '108', '71', '101', '26', '46'), +('5', '1', '54', '110', '72', '103', '27', '46'), +('5', '1', '55', '112', '74', '104', '27', '47'), +('5', '1', '56', '114', '75', '106', '27', '48'), +('5', '1', '57', '116', '76', '108', '27', '48'), +('5', '1', '58', '118', '78', '110', '28', '49'), +('5', '1', '59', '120', '79', '112', '28', '49'), +('5', '1', '60', '122', '80', '114', '28', '50'), +('5', '1', '61', '124', '82', '116', '28', '50'), +('5', '1', '62', '126', '83', '118', '29', '51'), +('5', '1', '63', '128', '84', '120', '29', '52'), +('5', '1', '64', '131', '86', '122', '29', '52'), +('5', '1', '65', '133', '87', '124', '30', '53'), +('5', '1', '66', '135', '88', '126', '30', '53'), +('5', '1', '67', '137', '90', '128', '30', '54'), +('5', '1', '68', '139', '91', '130', '30', '55'), +('5', '1', '69', '142', '93', '132', '31', '55'), +('5', '1', '70', '144', '94', '134', '31', '56'), +('5', '1', '71', '147', '95', '136', '31', '57'), +('5', '1', '72', '150', '97', '139', '31', '58'), +('5', '1', '73', '152', '99', '141', '31', '59'), +('5', '1', '74', '155', '100', '144', '32', '59'), +('5', '1', '75', '158', '102', '146', '32', '60'), +('5', '1', '76', '163', '104', '149', '32', '61'), +('5', '1', '77', '167', '106', '152', '33', '62'), +('5', '1', '78', '167', '107', '154', '33', '62'), +('5', '1', '79', '170', '109', '157', '33', '63'), +('5', '1', '80', '173', '111', '160', '34', '64'), +('5', '4', '1', '20', '21', '22', '18', '25'), +('5', '4', '2', '21', '22', '23', '18', '25'), +('5', '4', '3', '22', '24', '23', '18', '26'), +('5', '4', '4', '22', '25', '24', '18', '26'), +('5', '4', '5', '23', '27', '25', '19', '26'), +('5', '4', '6', '24', '28', '25', '19', '27'), +('5', '4', '7', '25', '30', '26', '19', '27'), +('5', '4', '8', '25', '31', '27', '19', '27'), +('5', '4', '9', '26', '33', '28', '19', '28'), +('5', '4', '10', '27', '34', '28', '19', '28'), +('5', '4', '11', '28', '36', '29', '20', '29'), +('5', '4', '12', '29', '38', '30', '20', '29'), +('5', '4', '13', '30', '39', '31', '20', '29'), +('5', '4', '14', '31', '41', '32', '20', '30'), +('5', '4', '15', '31', '42', '32', '20', '30'), +('5', '4', '16', '32', '44', '33', '21', '31'), +('5', '4', '17', '33', '46', '34', '21', '31'), +('5', '4', '18', '34', '47', '35', '21', '32'), +('5', '4', '19', '35', '49', '36', '21', '32'), +('5', '4', '20', '36', '51', '36', '21', '32'), +('5', '4', '21', '37', '52', '37', '22', '33'), +('5', '4', '22', '38', '54', '38', '22', '33'), +('5', '4', '23', '39', '56', '39', '22', '34'), +('5', '4', '24', '40', '58', '40', '22', '34'), +('5', '4', '25', '41', '60', '41', '23', '35'), +('5', '4', '26', '42', '61', '42', '23', '35'), +('5', '4', '27', '43', '63', '43', '23', '36'), +('5', '4', '28', '44', '65', '44', '23', '36'), +('5', '4', '29', '45', '67', '44', '24', '37'), +('5', '4', '30', '46', '69', '45', '24', '37'), +('5', '4', '31', '47', '71', '46', '24', '38'), +('5', '4', '32', '48', '72', '47', '24', '38'), +('5', '4', '33', '49', '74', '48', '25', '39'), +('5', '4', '34', '50', '76', '49', '25', '39'), +('5', '4', '35', '51', '78', '50', '25', '40'), +('5', '4', '36', '52', '80', '51', '25', '41'), +('5', '4', '37', '53', '82', '52', '26', '41'), +('5', '4', '38', '54', '84', '53', '26', '42'), +('5', '4', '39', '55', '86', '54', '26', '42'), +('5', '4', '40', '56', '88', '55', '27', '43'), +('5', '4', '41', '57', '90', '56', '27', '43'), +('5', '4', '42', '59', '92', '57', '27', '44'), +('5', '4', '43', '60', '94', '58', '27', '45'), +('5', '4', '44', '61', '96', '59', '28', '45'), +('5', '4', '45', '62', '99', '60', '28', '46'), +('5', '4', '46', '63', '101', '61', '28', '46'), +('5', '4', '47', '64', '103', '63', '29', '47'), +('5', '4', '48', '66', '105', '64', '29', '48'), +('5', '4', '49', '67', '107', '65', '29', '48'), +('5', '4', '50', '68', '109', '66', '30', '49'), +('5', '4', '51', '69', '111', '67', '30', '50'), +('5', '4', '52', '70', '114', '68', '30', '50'), +('5', '4', '53', '72', '116', '69', '31', '51'), +('5', '4', '54', '73', '118', '70', '31', '52'), +('5', '4', '55', '74', '120', '72', '31', '52'), +('5', '4', '56', '75', '123', '73', '32', '53'), +('5', '4', '57', '77', '125', '74', '32', '54'), +('5', '4', '58', '78', '127', '75', '32', '54'), +('5', '4', '59', '79', '130', '76', '33', '55'), +('5', '4', '60', '81', '132', '77', '33', '56'), +('5', '4', '61', '82', '134', '79', '34', '56'), +('5', '4', '62', '83', '137', '80', '34', '57'), +('5', '4', '63', '84', '139', '81', '34', '58'), +('5', '4', '64', '86', '141', '82', '35', '59'), +('5', '4', '65', '87', '144', '84', '35', '59'), +('5', '4', '66', '88', '146', '85', '35', '60'), +('5', '4', '67', '90', '149', '86', '36', '61'), +('5', '4', '68', '91', '151', '87', '36', '61'), +('5', '4', '69', '93', '154', '89', '37', '62'), +('5', '4', '70', '94', '156', '90', '37', '63'), +('5', '4', '71', '96', '159', '91', '37', '64'), +('5', '4', '72', '98', '162', '93', '38', '64'), +('5', '4', '73', '99', '165', '95', '38', '65'), +('5', '4', '74', '101', '168', '96', '39', '66'), +('5', '4', '75', '103', '171', '98', '39', '67'), +('5', '4', '76', '104', '174', '99', '39', '68'), +('5', '4', '77', '106', '177', '101', '40', '69'), +('5', '4', '78', '108', '181', '103', '40', '70'), +('5', '4', '79', '110', '184', '104', '41', '71'), +('5', '4', '80', '112', '187', '106', '41', '72'), +('5', '5', '1', '19', '18', '21', '20', '28'), +('5', '5', '2', '19', '18', '21', '21', '29'), +('5', '5', '3', '19', '18', '22', '23', '31'), +('5', '5', '4', '19', '19', '22', '24', '32'), +('5', '5', '5', '20', '19', '22', '25', '33'), +('5', '5', '6', '20', '19', '23', '27', '35'), +('5', '5', '7', '20', '19', '23', '28', '36'), +('5', '5', '8', '20', '20', '24', '29', '38'), +('5', '5', '9', '20', '20', '24', '31', '39'), +('5', '5', '10', '20', '20', '24', '32', '40'), +('5', '5', '11', '21', '20', '25', '34', '42'), +('5', '5', '12', '21', '21', '25', '35', '43'), +('5', '5', '13', '21', '21', '26', '37', '45'), +('5', '5', '14', '21', '21', '26', '38', '46'), +('5', '5', '15', '21', '21', '26', '39', '48'), +('5', '5', '16', '22', '22', '27', '41', '50'), +('5', '5', '17', '22', '22', '27', '42', '51'), +('5', '5', '18', '22', '22', '28', '44', '53'), +('5', '5', '19', '22', '23', '28', '46', '54'), +('5', '5', '20', '22', '23', '29', '47', '56'), +('5', '5', '21', '23', '23', '29', '49', '57'), +('5', '5', '22', '23', '23', '30', '50', '59'), +('5', '5', '23', '23', '24', '30', '52', '61'), +('5', '5', '24', '23', '24', '31', '53', '62'), +('5', '5', '25', '24', '24', '31', '55', '64'), +('5', '5', '26', '24', '25', '32', '57', '66'), +('5', '5', '27', '24', '25', '32', '58', '68'), +('5', '5', '28', '24', '25', '33', '60', '69'), +('5', '5', '29', '25', '26', '33', '62', '71'), +('5', '5', '30', '25', '26', '34', '63', '73'), +('5', '5', '31', '25', '26', '34', '65', '75'), +('5', '5', '32', '25', '27', '35', '67', '76'), +('5', '5', '33', '26', '27', '35', '69', '78'), +('5', '5', '34', '26', '27', '36', '70', '80'), +('5', '5', '35', '26', '28', '36', '72', '82'), +('5', '5', '36', '26', '28', '37', '74', '84'), +('5', '5', '37', '27', '28', '37', '76', '86'), +('5', '5', '38', '27', '29', '38', '77', '87'), +('5', '5', '39', '27', '29', '38', '79', '89'), +('5', '5', '40', '28', '30', '39', '81', '91'), +('5', '5', '41', '28', '30', '40', '83', '93'), +('5', '5', '42', '28', '30', '40', '85', '95'), +('5', '5', '43', '28', '31', '41', '87', '97'), +('5', '5', '44', '29', '31', '41', '89', '99'), +('5', '5', '45', '29', '32', '42', '91', '101'), +('5', '5', '46', '29', '32', '43', '92', '103'), +('5', '5', '47', '30', '32', '43', '94', '105'), +('5', '5', '48', '30', '33', '44', '96', '107'), +('5', '5', '49', '30', '33', '44', '98', '109'), +('5', '5', '50', '31', '34', '45', '100', '111'), +('5', '5', '51', '31', '34', '46', '102', '113'), +('5', '5', '52', '31', '35', '46', '104', '115'), +('5', '5', '53', '32', '35', '47', '106', '118'), +('5', '5', '54', '32', '35', '48', '108', '120'), +('5', '5', '55', '32', '36', '48', '110', '122'), +('5', '5', '56', '33', '36', '49', '113', '124'), +('5', '5', '57', '33', '37', '50', '115', '126'), +('5', '5', '58', '33', '37', '50', '117', '128'), +('5', '5', '59', '34', '38', '51', '119', '131'), +('5', '5', '60', '34', '38', '52', '121', '133'), +('5', '5', '61', '34', '39', '52', '123', '135'), +('5', '5', '62', '35', '39', '53', '125', '137'), +('5', '5', '63', '35', '40', '54', '127', '140'), +('5', '5', '64', '36', '40', '55', '130', '142'), +('5', '5', '65', '36', '41', '55', '132', '144'), +('5', '5', '66', '36', '41', '56', '134', '147'), +('5', '5', '67', '37', '41', '57', '136', '149'), +('5', '5', '68', '37', '42', '58', '138', '151'), +('5', '5', '69', '38', '42', '58', '141', '154'), +('5', '5', '70', '38', '43', '59', '143', '156'), +('5', '5', '71', '38', '44', '60', '146', '159'), +('5', '5', '72', '39', '44', '60', '149', '162'), +('5', '5', '73', '39', '45', '61', '152', '165'), +('5', '5', '74', '40', '45', '62', '157', '168'), +('5', '5', '75', '40', '46', '63', '157', '171'), +('5', '5', '76', '40', '47', '64', '160', '174'), +('5', '5', '77', '41', '47', '65', '163', '177'), +('5', '5', '78', '41', '48', '66', '166', '180'), +('5', '5', '79', '42', '48', '67', '169', '183'), +('5', '5', '80', '42', '49', '68', '172', '186'), +('5', '6', '1', '22', '18', '23', '18', '25'), +('5', '6', '2', '23', '19', '24', '18', '25'), +('5', '6', '3', '25', '20', '25', '18', '26'), +('5', '6', '4', '26', '20', '26', '18', '26'), +('5', '6', '5', '27', '21', '28', '18', '26'), +('5', '6', '6', '29', '22', '29', '18', '26'), +('5', '6', '7', '30', '23', '30', '19', '27'), +('5', '6', '8', '31', '24', '31', '19', '27'), +('5', '6', '9', '33', '25', '33', '19', '27'), +('5', '6', '10', '34', '25', '34', '19', '28'), +('5', '6', '11', '35', '26', '35', '19', '28'), +('5', '6', '12', '37', '27', '36', '19', '28'), +('5', '6', '13', '38', '28', '38', '19', '28'), +('5', '6', '14', '40', '29', '39', '19', '29'), +('5', '6', '15', '41', '30', '40', '19', '29'), +('5', '6', '16', '43', '31', '42', '20', '29'), +('5', '6', '17', '44', '32', '43', '20', '30'), +('5', '6', '18', '46', '33', '44', '20', '30'), +('5', '6', '19', '47', '34', '46', '20', '31'), +('5', '6', '20', '49', '34', '47', '20', '31'), +('5', '6', '21', '50', '35', '49', '20', '31'), +('5', '6', '22', '52', '36', '50', '20', '32'), +('5', '6', '23', '53', '37', '51', '21', '32'), +('5', '6', '24', '55', '38', '53', '21', '32'), +('5', '6', '25', '57', '39', '54', '21', '33'), +('5', '6', '26', '58', '40', '56', '21', '33'), +('5', '6', '27', '60', '41', '57', '21', '34'), +('5', '6', '28', '62', '42', '59', '21', '34'), +('5', '6', '29', '63', '43', '60', '21', '34'), +('5', '6', '30', '65', '44', '62', '22', '35'), +('5', '6', '31', '67', '46', '63', '22', '35'), +('5', '6', '32', '68', '47', '65', '22', '36'), +('5', '6', '33', '70', '48', '67', '22', '36'), +('5', '6', '34', '72', '49', '68', '22', '36'), +('5', '6', '35', '74', '50', '70', '23', '37'), +('5', '6', '36', '75', '51', '71', '23', '37'), +('5', '6', '37', '77', '52', '73', '23', '38'), +('5', '6', '38', '79', '53', '75', '23', '38'), +('5', '6', '39', '81', '54', '76', '23', '39'), +('5', '6', '40', '83', '55', '78', '24', '39'), +('5', '6', '41', '84', '57', '80', '24', '40'), +('5', '6', '42', '86', '58', '81', '24', '40'), +('5', '6', '43', '88', '59', '83', '24', '41'), +('5', '6', '44', '90', '60', '85', '24', '41'), +('5', '6', '45', '92', '61', '86', '25', '42'), +('5', '6', '46', '94', '62', '88', '25', '42'), +('5', '6', '47', '96', '64', '90', '25', '43'), +('5', '6', '48', '98', '65', '92', '25', '43'), +('5', '6', '49', '100', '66', '93', '25', '44'), +('5', '6', '50', '102', '67', '95', '26', '44'), +('5', '6', '51', '103', '67', '96', '26', '45'), +('5', '6', '52', '104', '68', '97', '26', '45'), +('5', '6', '53', '105', '69', '98', '26', '46'), +('5', '6', '54', '106', '70', '99', '27', '46'), +('5', '6', '55', '107', '71', '100', '27', '47'), +('5', '6', '56', '110', '73', '103', '27', '48'), +('5', '6', '57', '112', '74', '105', '27', '48'), +('5', '6', '58', '114', '75', '107', '28', '49'), +('5', '6', '59', '119', '77', '109', '28', '49'), +('5', '6', '60', '122', '78', '111', '28', '50'), +('5', '6', '61', '124', '79', '113', '28', '51'), +('5', '6', '62', '127', '81', '115', '28', '51'), +('5', '6', '63', '129', '82', '118', '29', '52'), +('5', '6', '64', '136', '84', '120', '29', '52'), +('5', '6', '65', '137', '85', '123', '29', '53'), +('5', '6', '66', '138', '87', '125', '29', '54'), +('5', '6', '67', '141', '88', '127', '30', '54'), +('5', '6', '68', '143', '90', '129', '30', '55'), +('5', '6', '69', '146', '91', '132', '30', '56'), +('5', '6', '70', '149', '93', '134', '30', '56'), +('5', '6', '71', '152', '95', '137', '31', '57'), +('5', '6', '72', '154', '96', '139', '31', '58'), +('5', '6', '73', '157', '98', '142', '31', '59'), +('5', '6', '74', '158', '100', '145', '31', '59'), +('5', '6', '75', '159', '101', '147', '32', '60'), +('5', '6', '76', '162', '103', '150', '32', '61'), +('5', '6', '77', '167', '105', '152', '32', '62'), +('5', '6', '78', '173', '106', '155', '32', '62'), +('5', '6', '79', '174', '108', '158', '33', '63'), +('5', '6', '80', '174', '110', '161', '33', '64'), +('5', '8', '1', '19', '18', '21', '21', '27'), +('5', '8', '2', '19', '18', '21', '22', '28'), +('5', '8', '3', '19', '18', '22', '24', '30'), +('5', '8', '4', '19', '18', '22', '25', '31'), +('5', '8', '5', '19', '19', '22', '26', '32'), +('5', '8', '6', '19', '19', '22', '28', '34'), +('5', '8', '7', '20', '19', '23', '29', '35'), +('5', '8', '8', '20', '19', '23', '31', '36'), +('5', '8', '9', '20', '19', '23', '32', '38'), +('5', '8', '10', '20', '19', '24', '34', '39'), +('5', '8', '11', '20', '20', '24', '35', '40'), +('5', '8', '12', '20', '20', '24', '37', '42'), +('5', '8', '13', '20', '20', '25', '38', '43'), +('5', '8', '14', '20', '20', '25', '40', '45'), +('5', '8', '15', '20', '20', '25', '41', '46'), +('5', '8', '16', '21', '21', '26', '43', '48'), +('5', '8', '17', '21', '21', '26', '44', '49'), +('5', '8', '18', '21', '21', '26', '46', '51'), +('5', '8', '19', '21', '21', '27', '48', '52'), +('5', '8', '20', '21', '21', '27', '49', '54'), +('5', '8', '21', '21', '22', '27', '51', '55'), +('5', '8', '22', '21', '22', '28', '52', '57'), +('5', '8', '23', '21', '22', '28', '54', '58'), +('5', '8', '24', '22', '22', '29', '56', '60'), +('5', '8', '25', '22', '23', '29', '57', '62'), +('5', '8', '26', '22', '23', '29', '59', '63'), +('5', '8', '27', '22', '23', '30', '61', '65'), +('5', '8', '28', '22', '23', '30', '63', '67'), +('5', '8', '29', '22', '24', '31', '64', '68'), +('5', '8', '30', '23', '24', '31', '66', '70'), +('5', '8', '31', '23', '24', '31', '68', '72'), +('5', '8', '32', '23', '24', '32', '70', '73'), +('5', '8', '33', '23', '25', '32', '72', '75'), +('5', '8', '34', '23', '25', '33', '73', '77'), +('5', '8', '35', '24', '25', '33', '75', '79'), +('5', '8', '36', '24', '25', '34', '77', '80'), +('5', '8', '37', '24', '26', '34', '79', '82'), +('5', '8', '38', '24', '26', '35', '81', '84'), +('5', '8', '39', '24', '26', '35', '83', '86'), +('5', '8', '40', '24', '27', '35', '85', '88'), +('5', '8', '41', '25', '27', '36', '87', '90'), +('5', '8', '42', '25', '27', '36', '89', '91'), +('5', '8', '43', '25', '27', '37', '90', '93'), +('5', '8', '44', '25', '28', '37', '92', '95'), +('5', '8', '45', '26', '28', '38', '94', '97'), +('5', '8', '46', '26', '28', '38', '96', '99'), +('5', '8', '47', '26', '29', '39', '98', '101'), +('5', '8', '48', '26', '29', '39', '100', '103'), +('5', '8', '49', '26', '29', '40', '103', '105'), +('5', '8', '50', '27', '30', '40', '105', '107'), +('5', '8', '51', '27', '30', '41', '107', '109'), +('5', '8', '52', '27', '30', '42', '109', '111'), +('5', '8', '53', '27', '31', '42', '111', '113'), +('5', '8', '54', '28', '31', '43', '113', '115'), +('5', '8', '55', '28', '31', '43', '115', '117'), +('5', '8', '56', '28', '32', '44', '117', '119'), +('5', '8', '57', '28', '32', '44', '119', '121'), +('5', '8', '58', '29', '32', '45', '122', '123'), +('5', '8', '59', '29', '33', '45', '124', '126'), +('5', '8', '60', '29', '33', '46', '126', '128'), +('5', '8', '61', '29', '34', '47', '128', '130'), +('5', '8', '62', '30', '34', '47', '131', '132'), +('5', '8', '63', '30', '34', '48', '133', '134'), +('5', '8', '64', '30', '35', '48', '135', '136'), +('5', '8', '65', '31', '35', '49', '137', '139'), +('5', '8', '66', '31', '35', '50', '140', '141'), +('5', '8', '67', '31', '36', '50', '142', '143'), +('5', '8', '68', '31', '36', '51', '144', '145'), +('5', '8', '69', '32', '37', '51', '147', '148'), +('5', '8', '70', '32', '37', '52', '149', '150'), +('5', '8', '71', '32', '37', '53', '152', '153'), +('5', '8', '72', '32', '38', '54', '155', '156'), +('5', '8', '73', '32', '38', '55', '158', '159'), +('5', '8', '74', '33', '39', '55', '161', '161'), +('5', '8', '75', '33', '39', '56', '164', '164'), +('5', '8', '76', '33', '39', '57', '167', '167'), +('5', '8', '77', '34', '40', '58', '170', '170'), +('5', '8', '78', '34', '40', '58', '173', '173'), +('5', '8', '79', '34', '41', '59', '176', '176'), +('5', '8', '80', '35', '41', '60', '179', '179'), +('5', '9', '1', '19', '18', '22', '20', '27'), +('5', '9', '2', '19', '18', '23', '21', '28'), +('5', '9', '3', '20', '19', '23', '22', '29'), +('5', '9', '4', '20', '19', '24', '24', '30'), +('5', '9', '5', '20', '19', '24', '25', '32'), +('5', '9', '6', '20', '20', '25', '26', '33'), +('5', '9', '7', '21', '20', '25', '27', '34'), +('5', '9', '8', '21', '21', '26', '28', '35'), +('5', '9', '9', '21', '21', '26', '30', '36'), +('5', '9', '10', '22', '21', '27', '31', '38'), +('5', '9', '11', '22', '22', '28', '32', '39'), +('5', '9', '12', '22', '22', '28', '34', '40'), +('5', '9', '13', '23', '23', '29', '35', '41'), +('5', '9', '14', '23', '23', '30', '36', '43'), +('5', '9', '15', '23', '24', '30', '37', '44'), +('5', '9', '16', '24', '24', '31', '39', '45'), +('5', '9', '17', '24', '24', '31', '40', '47'), +('5', '9', '18', '24', '25', '32', '42', '48'), +('5', '9', '19', '25', '25', '33', '43', '49'), +('5', '9', '20', '25', '26', '33', '44', '51'), +('5', '9', '21', '26', '26', '34', '46', '52'), +('5', '9', '22', '26', '27', '35', '47', '53'), +('5', '9', '23', '26', '27', '36', '49', '55'), +('5', '9', '24', '27', '28', '36', '50', '56'), +('5', '9', '25', '27', '28', '37', '52', '58'), +('5', '9', '26', '27', '29', '38', '53', '59'), +('5', '9', '27', '28', '29', '38', '55', '60'), +('5', '9', '28', '28', '30', '39', '56', '62'), +('5', '9', '29', '29', '30', '40', '58', '63'), +('5', '9', '30', '29', '31', '41', '59', '65'), +('5', '9', '31', '30', '31', '41', '61', '66'), +('5', '9', '32', '30', '32', '42', '62', '68'), +('5', '9', '33', '30', '32', '43', '64', '69'), +('5', '9', '34', '31', '33', '44', '65', '71'), +('5', '9', '35', '31', '33', '45', '67', '73'), +('5', '9', '36', '32', '34', '45', '69', '74'), +('5', '9', '37', '32', '34', '46', '70', '76'), +('5', '9', '38', '33', '35', '47', '72', '77'), +('5', '9', '39', '33', '36', '48', '73', '79'), +('5', '9', '40', '34', '36', '49', '75', '81'), +('5', '9', '41', '34', '37', '49', '77', '82'), +('5', '9', '42', '35', '37', '50', '78', '84'), +('5', '9', '43', '35', '38', '51', '80', '86'), +('5', '9', '44', '36', '39', '52', '82', '87'), +('5', '9', '45', '36', '39', '53', '84', '89'), +('5', '9', '46', '37', '40', '54', '85', '91'), +('5', '9', '47', '37', '40', '55', '87', '92'), +('5', '9', '48', '38', '41', '55', '89', '94'), +('5', '9', '49', '38', '42', '56', '91', '96'), +('5', '9', '50', '39', '42', '57', '92', '98'), +('5', '9', '51', '39', '43', '58', '94', '100'), +('5', '9', '52', '40', '44', '59', '96', '101'), +('5', '9', '53', '40', '44', '60', '98', '103'), +('5', '9', '54', '41', '45', '61', '100', '105'), +('5', '9', '55', '41', '45', '62', '102', '107'), +('5', '9', '56', '42', '46', '63', '103', '109'), +('5', '9', '57', '42', '47', '64', '105', '111'), +('5', '9', '58', '43', '47', '65', '107', '112'), +('5', '9', '59', '43', '48', '66', '109', '114'), +('5', '9', '60', '44', '49', '67', '111', '116'), +('5', '9', '61', '45', '50', '68', '113', '118'), +('5', '9', '62', '45', '50', '69', '115', '120'), +('5', '9', '63', '46', '51', '70', '117', '122'), +('5', '9', '64', '46', '52', '71', '119', '124'), +('5', '9', '65', '47', '52', '72', '121', '126'), +('5', '9', '66', '48', '53', '73', '123', '128'), +('5', '9', '67', '48', '54', '74', '125', '130'), +('5', '9', '68', '49', '55', '75', '127', '132'), +('5', '9', '69', '49', '55', '76', '129', '134'), +('5', '9', '70', '50', '56', '77', '131', '136'), +('5', '9', '71', '51', '57', '86', '135', '147'), +('5', '9', '72', '52', '57', '88', '136', '149'), +('5', '9', '73', '53', '58', '89', '138', '152'), +('5', '9', '74', '53', '59', '90', '141', '155'), +('5', '9', '75', '54', '60', '92', '143', '157'), +('5', '9', '76', '55', '61', '93', '146', '160'), +('5', '9', '77', '56', '62', '94', '149', '163'), +('5', '9', '78', '56', '63', '96', '151', '166'), +('5', '9', '79', '57', '64', '97', '154', '169'), +('5', '9', '80', '58', '65', '99', '157', '171'), +('6', '1', '1', '28', '15', '24', '15', '22'), +('6', '1', '2', '29', '16', '25', '15', '22'), +('6', '1', '3', '31', '17', '26', '15', '23'), +('6', '1', '4', '32', '17', '27', '15', '23'), +('6', '1', '5', '33', '18', '29', '15', '23'), +('6', '1', '6', '34', '19', '30', '15', '23'), +('6', '1', '7', '36', '20', '31', '16', '24'), +('6', '1', '8', '37', '21', '32', '16', '24'), +('6', '1', '9', '38', '22', '34', '16', '24'), +('6', '1', '10', '40', '22', '35', '16', '25'), +('6', '1', '11', '41', '23', '36', '16', '25'), +('6', '1', '12', '43', '24', '37', '16', '25'), +('6', '1', '13', '44', '25', '39', '16', '26'), +('6', '1', '14', '46', '26', '40', '16', '26'), +('6', '1', '15', '47', '27', '41', '17', '26'), +('6', '1', '16', '48', '28', '43', '17', '27'), +('6', '1', '17', '50', '29', '44', '17', '27'), +('6', '1', '18', '51', '30', '45', '17', '27'), +('6', '1', '19', '53', '31', '47', '17', '28'), +('6', '1', '20', '54', '32', '48', '17', '28'), +('6', '1', '21', '56', '33', '50', '17', '28'), +('6', '1', '22', '58', '34', '51', '18', '29'), +('6', '1', '23', '59', '35', '52', '18', '29'), +('6', '1', '24', '61', '36', '54', '18', '30'), +('6', '1', '25', '62', '37', '55', '18', '30'), +('6', '1', '26', '64', '38', '57', '18', '30'), +('6', '1', '27', '66', '39', '58', '18', '31'), +('6', '1', '28', '67', '40', '60', '18', '31'), +('6', '1', '29', '69', '41', '61', '19', '32'), +('6', '1', '30', '71', '42', '63', '19', '32'), +('6', '1', '31', '72', '43', '64', '19', '32'), +('6', '1', '32', '74', '44', '66', '19', '33'), +('6', '1', '33', '76', '45', '67', '19', '33'), +('6', '1', '34', '77', '46', '69', '20', '34'), +('6', '1', '35', '79', '47', '71', '20', '34'), +('6', '1', '36', '81', '48', '72', '20', '35'), +('6', '1', '37', '83', '49', '74', '20', '35'), +('6', '1', '38', '85', '50', '76', '20', '35'), +('6', '1', '39', '86', '51', '77', '21', '36'), +('6', '1', '40', '88', '53', '79', '21', '36'), +('6', '1', '41', '90', '54', '81', '21', '37'), +('6', '1', '42', '92', '55', '82', '21', '37'), +('6', '1', '43', '94', '56', '84', '21', '38'), +('6', '1', '44', '96', '57', '86', '22', '38'), +('6', '1', '45', '98', '58', '87', '22', '39'), +('6', '1', '46', '99', '60', '89', '22', '39'), +('6', '1', '47', '101', '61', '91', '22', '40'), +('6', '1', '48', '103', '62', '93', '22', '40'), +('6', '1', '49', '105', '63', '94', '23', '41'), +('6', '1', '50', '107', '65', '96', '23', '41'), +('6', '1', '51', '109', '66', '98', '23', '42'), +('6', '1', '52', '111', '67', '100', '23', '42'), +('6', '1', '53', '113', '68', '102', '24', '43'), +('6', '1', '54', '115', '70', '104', '24', '44'), +('6', '1', '55', '117', '71', '105', '24', '44'), +('6', '1', '56', '119', '72', '107', '24', '45'), +('6', '1', '57', '122', '73', '109', '25', '45'), +('6', '1', '58', '124', '75', '111', '25', '46'), +('6', '1', '59', '126', '76', '113', '25', '46'), +('6', '1', '60', '128', '77', '115', '25', '47'), +('6', '1', '61', '130', '79', '117', '26', '48'), +('6', '1', '62', '132', '80', '119', '26', '48'), +('6', '1', '63', '134', '81', '121', '26', '49'), +('6', '1', '64', '137', '83', '123', '26', '49'), +('6', '1', '65', '139', '84', '125', '27', '50'), +('6', '1', '66', '141', '85', '127', '27', '51'), +('6', '1', '67', '143', '87', '129', '27', '51'), +('6', '1', '68', '145', '88', '131', '27', '52'), +('6', '1', '69', '148', '90', '133', '28', '52'), +('6', '1', '70', '150', '91', '135', '28', '53'), +('6', '1', '71', '153', '92', '137', '28', '54'), +('6', '1', '72', '155', '94', '140', '28', '55'), +('6', '1', '73', '158', '96', '142', '28', '56'), +('6', '1', '74', '161', '97', '145', '29', '56'), +('6', '1', '75', '164', '99', '147', '29', '57'), +('6', '1', '76', '167', '101', '150', '29', '58'), +('6', '1', '77', '170', '103', '153', '30', '59'), +('6', '1', '78', '173', '104', '155', '30', '59'), +('6', '1', '79', '176', '106', '164', '30', '60'), +('6', '1', '80', '179', '108', '170', '31', '61'), +('6', '3', '1', '25', '18', '23', '15', '23'), +('6', '3', '2', '25', '19', '24', '16', '24'), +('6', '3', '3', '26', '21', '25', '16', '24'), +('6', '3', '4', '26', '22', '26', '17', '25'), +('6', '3', '5', '27', '24', '27', '17', '25'), +('6', '3', '6', '27', '25', '28', '18', '26'), +('6', '3', '7', '28', '26', '28', '19', '27'), +('6', '3', '8', '28', '28', '29', '19', '27'), +('6', '3', '9', '28', '29', '30', '20', '28'), +('6', '3', '10', '29', '31', '31', '20', '29'), +('6', '3', '11', '29', '32', '32', '21', '29'), +('6', '3', '12', '30', '34', '33', '22', '30'), +('6', '3', '13', '30', '35', '34', '22', '31'), +('6', '3', '14', '31', '37', '35', '23', '32'), +('6', '3', '15', '31', '38', '36', '24', '32'), +('6', '3', '16', '32', '40', '37', '24', '33'), +('6', '3', '17', '32', '41', '39', '25', '34'), +('6', '3', '18', '33', '43', '40', '26', '35'), +('6', '3', '19', '33', '45', '41', '27', '35'), +('6', '3', '20', '34', '46', '42', '27', '36'), +('6', '3', '21', '34', '48', '43', '28', '37'), +('6', '3', '22', '35', '50', '44', '29', '38'), +('6', '3', '23', '35', '51', '45', '29', '38'), +('6', '3', '24', '36', '53', '46', '30', '39'), +('6', '3', '25', '37', '55', '47', '31', '40'), +('6', '3', '26', '37', '56', '48', '32', '41'), +('6', '3', '27', '38', '58', '50', '32', '42'), +('6', '3', '28', '38', '60', '51', '33', '42'), +('6', '3', '29', '39', '62', '52', '34', '43'), +('6', '3', '30', '39', '63', '53', '35', '44'), +('6', '3', '31', '40', '65', '54', '36', '45'), +('6', '3', '32', '41', '67', '56', '36', '46'), +('6', '3', '33', '41', '69', '57', '37', '47'), +('6', '3', '34', '42', '71', '58', '38', '48'), +('6', '3', '35', '43', '72', '59', '39', '48'), +('6', '3', '36', '43', '74', '61', '40', '49'), +('6', '3', '37', '44', '76', '62', '40', '50'), +('6', '3', '38', '45', '78', '63', '41', '51'), +('6', '3', '39', '45', '80', '64', '42', '52'), +('6', '3', '40', '46', '82', '66', '43', '53'), +('6', '3', '41', '47', '84', '67', '44', '54'), +('6', '3', '42', '47', '86', '68', '45', '55'), +('6', '3', '43', '48', '88', '70', '46', '56'), +('6', '3', '44', '49', '90', '71', '46', '57'), +('6', '3', '45', '49', '92', '72', '47', '58'), +('6', '3', '46', '50', '94', '74', '48', '59'), +('6', '3', '47', '51', '96', '75', '49', '60'), +('6', '3', '48', '51', '98', '77', '50', '61'), +('6', '3', '49', '52', '100', '78', '51', '62'), +('6', '3', '50', '53', '102', '79', '52', '63'), +('6', '3', '51', '54', '104', '81', '53', '64'), +('6', '3', '52', '54', '106', '82', '54', '65'), +('6', '3', '53', '55', '108', '84', '55', '66'), +('6', '3', '54', '56', '110', '85', '56', '67'), +('6', '3', '55', '57', '112', '87', '57', '68'), +('6', '3', '56', '57', '114', '88', '58', '69'), +('6', '3', '57', '58', '117', '90', '59', '70'), +('6', '3', '58', '59', '119', '91', '60', '71'), +('6', '3', '59', '60', '121', '93', '61', '72'), +('6', '3', '60', '61', '123', '94', '62', '74'), +('6', '3', '61', '61', '125', '96', '63', '75'), +('6', '3', '62', '62', '128', '97', '64', '76'), +('6', '3', '63', '63', '130', '99', '65', '77'), +('6', '3', '64', '64', '132', '100', '66', '78'), +('6', '3', '65', '65', '134', '102', '67', '79'), +('6', '3', '66', '66', '137', '104', '68', '80'), +('6', '3', '67', '66', '139', '105', '69', '81'), +('6', '3', '68', '67', '141', '107', '70', '83'), +('6', '3', '69', '68', '144', '108', '71', '84'), +('6', '3', '70', '69', '146', '110', '72', '85'), +('6', '3', '71', '70', '149', '112', '73', '86'), +('6', '3', '72', '71', '152', '114', '74', '87'), +('6', '3', '73', '72', '155', '116', '75', '89'), +('6', '3', '74', '73', '158', '118', '77', '90'), +('6', '3', '75', '74', '161', '120', '78', '92'), +('6', '3', '76', '75', '164', '122', '79', '93'), +('6', '3', '77', '76', '167', '124', '81', '95'), +('6', '3', '78', '77', '176', '126', '85', '96'), +('6', '3', '79', '78', '179', '128', '86', '98'), +('6', '3', '80', '79', '183', '130', '88', '99'), +('6', '6', '1', '28', '15', '24', '15', '22'), +('6', '6', '2', '29', '16', '25', '15', '22'), +('6', '6', '3', '31', '17', '26', '15', '23'), +('6', '6', '4', '32', '17', '27', '15', '23'), +('6', '6', '5', '33', '18', '29', '15', '23'), +('6', '6', '6', '34', '19', '30', '15', '23'), +('6', '6', '7', '36', '20', '31', '16', '24'), +('6', '6', '8', '37', '21', '32', '16', '24'), +('6', '6', '9', '38', '22', '34', '16', '24'), +('6', '6', '10', '40', '22', '35', '16', '25'), +('6', '6', '11', '41', '23', '36', '16', '25'), +('6', '6', '12', '43', '24', '37', '16', '25'), +('6', '6', '13', '44', '25', '39', '16', '26'), +('6', '6', '14', '46', '26', '40', '16', '26'), +('6', '6', '15', '47', '27', '41', '17', '26'), +('6', '6', '16', '48', '28', '43', '17', '27'), +('6', '6', '17', '50', '29', '44', '17', '27'), +('6', '6', '18', '51', '30', '45', '17', '27'), +('6', '6', '19', '53', '31', '47', '17', '28'), +('6', '6', '20', '54', '32', '48', '17', '28'), +('6', '6', '21', '56', '33', '50', '17', '28'), +('6', '6', '22', '58', '34', '51', '18', '29'), +('6', '6', '23', '59', '35', '52', '18', '29'), +('6', '6', '24', '61', '36', '54', '18', '30'), +('6', '6', '25', '62', '37', '55', '18', '30'), +('6', '6', '26', '64', '38', '57', '18', '30'), +('6', '6', '27', '66', '39', '58', '18', '31'), +('6', '6', '28', '67', '40', '60', '18', '31'), +('6', '6', '29', '69', '41', '61', '19', '32'), +('6', '6', '30', '71', '42', '63', '19', '32'), +('6', '6', '31', '72', '43', '64', '19', '32'), +('6', '6', '32', '74', '44', '66', '19', '33'), +('6', '6', '33', '76', '45', '67', '19', '33'), +('6', '6', '34', '77', '46', '69', '20', '34'), +('6', '6', '35', '79', '47', '71', '20', '34'), +('6', '6', '36', '81', '48', '72', '20', '35'), +('6', '6', '37', '83', '49', '74', '20', '35'), +('6', '6', '38', '85', '50', '76', '20', '35'), +('6', '6', '39', '86', '51', '77', '21', '36'), +('6', '6', '40', '88', '53', '79', '21', '36'), +('6', '6', '41', '90', '54', '81', '21', '37'), +('6', '6', '42', '92', '55', '82', '21', '37'), +('6', '6', '43', '94', '56', '84', '21', '38'), +('6', '6', '44', '96', '57', '86', '22', '38'), +('6', '6', '45', '98', '58', '87', '22', '39'), +('6', '6', '46', '99', '60', '89', '22', '39'), +('6', '6', '47', '101', '60', '91', '22', '40'), +('6', '6', '48', '103', '61', '93', '22', '40'), +('6', '6', '49', '105', '62', '94', '23', '41'), +('6', '6', '50', '107', '63', '96', '23', '41'), +('6', '6', '51', '109', '64', '97', '23', '42'), +('6', '6', '52', '110', '65', '98', '23', '42'), +('6', '6', '53', '111', '66', '99', '24', '43'), +('6', '6', '54', '112', '67', '100', '24', '44'), +('6', '6', '55', '113', '68', '101', '24', '44'), +('6', '6', '56', '116', '70', '104', '24', '45'), +('6', '6', '57', '121', '71', '106', '24', '45'), +('6', '6', '58', '123', '72', '108', '25', '46'), +('6', '6', '59', '123', '74', '110', '25', '46'), +('6', '6', '60', '125', '75', '112', '25', '47'), +('6', '6', '61', '127', '76', '114', '25', '48'), +('6', '6', '62', '133', '78', '116', '25', '48'), +('6', '6', '63', '135', '79', '119', '26', '49'), +('6', '6', '64', '139', '81', '121', '26', '49'), +('6', '6', '65', '142', '82', '123', '26', '50'), +('6', '6', '66', '146', '84', '126', '26', '51'), +('6', '6', '67', '150', '85', '132', '27', '51'), +('6', '6', '68', '153', '87', '137', '27', '52'), +('6', '6', '69', '157', '88', '140', '27', '53'), +('6', '6', '70', '160', '90', '143', '27', '53'), +('6', '6', '71', '163', '92', '146', '28', '54'), +('6', '6', '72', '165', '93', '148', '28', '55'), +('6', '6', '73', '167', '95', '150', '28', '56'), +('6', '6', '74', '171', '97', '153', '28', '56'), +('6', '6', '75', '174', '98', '156', '29', '57'), +('6', '6', '76', '178', '100', '156', '29', '58'), +('6', '6', '77', '179', '102', '156', '29', '59'), +('6', '6', '78', '179', '103', '156', '29', '59'), +('6', '6', '79', '182', '105', '159', '30', '60'), +('6', '6', '80', '185', '107', '162', '30', '61'), +('6', '7', '1', '26', '15', '23', '16', '24'), +('6', '7', '2', '27', '15', '24', '17', '25'), +('6', '7', '3', '28', '16', '25', '18', '26'), +('6', '7', '4', '28', '16', '26', '19', '27'), +('6', '7', '5', '29', '17', '27', '20', '28'), +('6', '7', '6', '30', '17', '28', '21', '29'), +('6', '7', '7', '31', '18', '29', '22', '30'), +('6', '7', '8', '32', '18', '30', '23', '31'), +('6', '7', '9', '33', '19', '31', '24', '32'), +('6', '7', '10', '34', '19', '32', '25', '33'), +('6', '7', '11', '35', '20', '33', '26', '35'), +('6', '7', '12', '35', '20', '34', '27', '36'), +('6', '7', '13', '36', '21', '35', '28', '37'), +('6', '7', '14', '37', '21', '36', '29', '38'), +('6', '7', '15', '38', '22', '37', '30', '39'), +('6', '7', '16', '39', '22', '39', '31', '40'), +('6', '7', '17', '40', '23', '40', '32', '42'), +('6', '7', '18', '41', '23', '41', '33', '43'), +('6', '7', '19', '42', '24', '42', '34', '44'), +('6', '7', '20', '43', '24', '43', '35', '45'), +('6', '7', '21', '44', '25', '44', '36', '46'), +('6', '7', '22', '45', '25', '45', '37', '48'), +('6', '7', '23', '46', '26', '47', '38', '49'), +('6', '7', '24', '47', '27', '48', '40', '50'), +('6', '7', '25', '48', '27', '49', '41', '51'), +('6', '7', '26', '49', '28', '50', '42', '53'), +('6', '7', '27', '51', '28', '52', '43', '54'), +('6', '7', '28', '52', '29', '53', '44', '55'), +('6', '7', '29', '53', '29', '54', '45', '57'), +('6', '7', '30', '54', '30', '55', '47', '58'), +('6', '7', '31', '55', '31', '57', '48', '59'), +('6', '7', '32', '56', '31', '58', '49', '61'), +('6', '7', '33', '57', '32', '59', '50', '62'), +('6', '7', '34', '58', '33', '61', '51', '64'), +('6', '7', '35', '60', '33', '62', '53', '65'), +('6', '7', '36', '61', '34', '63', '54', '66'), +('6', '7', '37', '62', '34', '65', '55', '68'), +('6', '7', '38', '63', '35', '66', '57', '69'), +('6', '7', '39', '64', '36', '67', '58', '71'), +('6', '7', '40', '66', '36', '69', '59', '72'), +('6', '7', '41', '67', '37', '70', '60', '74'), +('6', '7', '42', '68', '38', '72', '62', '75'), +('6', '7', '43', '69', '38', '73', '63', '77'), +('6', '7', '44', '70', '39', '74', '64', '78'), +('6', '7', '45', '72', '40', '76', '66', '80'), +('6', '7', '46', '73', '41', '77', '67', '81'), +('6', '7', '47', '74', '41', '79', '69', '83'), +('6', '7', '48', '76', '42', '80', '70', '84'), +('6', '7', '49', '77', '43', '82', '71', '86'), +('6', '7', '50', '78', '43', '83', '73', '88'), +('6', '7', '51', '80', '44', '85', '74', '89'), +('6', '7', '52', '81', '45', '86', '76', '91'), +('6', '7', '53', '82', '46', '88', '77', '92'), +('6', '7', '54', '84', '46', '90', '78', '94'), +('6', '7', '55', '85', '47', '91', '80', '96'), +('6', '7', '56', '86', '48', '93', '81', '97'), +('6', '7', '57', '88', '49', '94', '83', '99'), +('6', '7', '58', '89', '49', '96', '84', '101'), +('6', '7', '59', '91', '50', '97', '86', '102'), +('6', '7', '60', '92', '51', '99', '87', '104'), +('6', '7', '61', '94', '52', '101', '89', '106'), +('6', '7', '62', '95', '52', '102', '90', '108'), +('6', '7', '63', '96', '53', '104', '92', '109'), +('6', '7', '64', '98', '54', '106', '93', '111'), +('6', '7', '65', '99', '55', '107', '95', '113'), +('6', '7', '66', '101', '56', '109', '97', '115'), +('6', '7', '67', '102', '57', '111', '98', '117'), +('6', '7', '68', '104', '57', '113', '100', '118'), +('6', '7', '69', '105', '58', '114', '101', '120'), +('6', '7', '70', '107', '59', '116', '103', '122'), +('6', '7', '71', '108', '60', '118', '113', '124'), +('6', '7', '72', '110', '61', '120', '117', '127'), +('6', '7', '73', '112', '62', '122', '119', '129'), +('6', '7', '74', '114', '63', '125', '122', '131'), +('6', '7', '75', '116', '64', '127', '124', '133'), +('6', '7', '76', '118', '65', '129', '126', '136'), +('6', '7', '77', '119', '66', '131', '128', '138'), +('6', '7', '78', '121', '67', '133', '130', '140'), +('6', '7', '79', '123', '68', '136', '133', '143'), +('6', '7', '80', '125', '69', '138', '135', '145'), +('6', '11', '1', '26', '15', '22', '17', '24'), +('6', '11', '2', '27', '16', '23', '18', '25'), +('6', '11', '3', '27', '16', '23', '19', '26'), +('6', '11', '4', '28', '17', '24', '20', '27'), +('6', '11', '5', '28', '17', '25', '21', '29'), +('6', '11', '6', '29', '18', '25', '22', '30'), +('6', '11', '7', '29', '18', '26', '23', '31'), +('6', '11', '8', '30', '19', '27', '24', '32'), +('6', '11', '9', '30', '19', '27', '26', '34'), +('6', '11', '10', '31', '20', '28', '27', '35'), +('6', '11', '11', '32', '20', '29', '28', '36'), +('6', '11', '12', '32', '21', '29', '29', '37'), +('6', '11', '13', '33', '21', '30', '30', '39'), +('6', '11', '14', '33', '22', '31', '31', '40'), +('6', '11', '15', '34', '23', '32', '32', '41'), +('6', '11', '16', '35', '23', '32', '34', '43'), +('6', '11', '17', '35', '24', '33', '35', '44'), +('6', '11', '18', '36', '24', '34', '36', '45'), +('6', '11', '19', '37', '25', '35', '37', '47'), +('6', '11', '20', '37', '26', '35', '39', '48'), +('6', '11', '21', '38', '26', '36', '40', '50'), +('6', '11', '22', '39', '27', '37', '41', '51'), +('6', '11', '23', '39', '28', '38', '42', '52'), +('6', '11', '24', '40', '28', '39', '44', '54'), +('6', '11', '25', '41', '29', '39', '45', '55'), +('6', '11', '26', '41', '30', '40', '46', '57'), +('6', '11', '27', '42', '30', '41', '47', '58'), +('6', '11', '28', '43', '31', '42', '49', '60'), +('6', '11', '29', '44', '32', '43', '50', '61'), +('6', '11', '30', '44', '32', '44', '52', '63'), +('6', '11', '31', '45', '33', '44', '53', '64'), +('6', '11', '32', '46', '34', '45', '54', '66'), +('6', '11', '33', '47', '34', '46', '56', '67'), +('6', '11', '34', '47', '35', '47', '57', '69'), +('6', '11', '35', '48', '36', '48', '58', '71'), +('6', '11', '36', '49', '36', '49', '60', '72'), +('6', '11', '37', '50', '37', '50', '61', '74'), +('6', '11', '38', '51', '38', '51', '63', '76'), +('6', '11', '39', '52', '39', '52', '64', '77'), +('6', '11', '40', '52', '39', '53', '66', '79'), +('6', '11', '41', '53', '40', '54', '67', '81'), +('6', '11', '42', '54', '41', '55', '69', '82'), +('6', '11', '43', '55', '42', '56', '70', '84'), +('6', '11', '44', '56', '43', '57', '72', '86'), +('6', '11', '45', '57', '43', '57', '73', '87'), +('6', '11', '46', '57', '44', '58', '75', '89'), +('6', '11', '47', '58', '45', '60', '76', '91'), +('6', '11', '48', '59', '46', '61', '78', '93'), +('6', '11', '49', '60', '47', '62', '79', '94'), +('6', '11', '50', '61', '47', '63', '81', '96'), +('6', '11', '51', '62', '48', '64', '83', '98'), +('6', '11', '52', '63', '49', '65', '84', '100'), +('6', '11', '53', '64', '50', '66', '86', '102'), +('6', '11', '54', '65', '51', '67', '87', '104'), +('6', '11', '55', '66', '51', '68', '89', '105'), +('6', '11', '56', '67', '52', '69', '91', '107'), +('6', '11', '57', '68', '53', '70', '92', '109'), +('6', '11', '58', '69', '54', '71', '94', '111'), +('6', '11', '59', '70', '55', '72', '96', '113'), +('6', '11', '60', '71', '56', '73', '97', '115'), +('6', '11', '61', '72', '57', '74', '99', '117'), +('6', '11', '62', '73', '58', '76', '101', '119'), +('6', '11', '63', '74', '59', '77', '103', '121'), +('6', '11', '64', '75', '59', '78', '104', '123'), +('6', '11', '65', '76', '60', '79', '106', '125'), +('6', '11', '66', '77', '61', '80', '108', '127'), +('6', '11', '67', '78', '62', '81', '110', '129'), +('6', '11', '68', '79', '63', '83', '111', '131'), +('6', '11', '69', '80', '64', '84', '113', '133'), +('6', '11', '70', '81', '65', '85', '115', '135'), +('6', '11', '71', '83', '66', '86', '117', '137'), +('6', '11', '72', '84', '68', '88', '120', '140'), +('6', '11', '73', '85', '69', '89', '122', '142'), +('6', '11', '74', '86', '70', '91', '124', '145'), +('6', '11', '75', '88', '71', '92', '126', '147'), +('6', '11', '76', '89', '72', '94', '128', '150'), +('6', '11', '77', '90', '73', '95', '131', '153'), +('6', '11', '78', '92', '75', '97', '133', '155'), +('6', '11', '79', '93', '76', '98', '136', '158'), +('6', '11', '80', '94', '77', '100', '138', '185'), +('7', '1', '1', '18', '23', '21', '24', '20'), +('7', '1', '2', '19', '24', '22', '24', '20'), +('7', '1', '3', '21', '25', '23', '24', '21'), +('7', '1', '4', '22', '25', '25', '24', '21'), +('7', '1', '5', '23', '26', '26', '24', '21'), +('7', '1', '6', '25', '27', '27', '24', '21'), +('7', '1', '7', '26', '28', '28', '24', '22'), +('7', '1', '8', '27', '29', '29', '25', '22'), +('7', '1', '9', '29', '29', '31', '25', '22'), +('7', '1', '10', '30', '30', '32', '25', '23'), +('7', '1', '11', '32', '31', '33', '25', '23'), +('7', '1', '12', '33', '32', '34', '25', '23'), +('7', '1', '13', '34', '33', '36', '25', '24'), +('7', '1', '14', '36', '34', '37', '25', '24'), +('7', '1', '15', '37', '35', '38', '25', '24'), +('7', '1', '16', '39', '36', '40', '25', '25'), +('7', '1', '17', '40', '36', '41', '25', '25'), +('7', '1', '18', '42', '37', '43', '26', '25'), +('7', '1', '19', '43', '38', '44', '26', '26'), +('7', '1', '20', '45', '39', '45', '26', '26'), +('7', '1', '21', '47', '40', '47', '26', '26'), +('7', '1', '22', '48', '41', '48', '26', '27'), +('7', '1', '23', '50', '42', '50', '26', '27'), +('7', '1', '24', '51', '43', '51', '26', '28'), +('7', '1', '25', '53', '44', '52', '27', '28'), +('7', '1', '26', '55', '45', '54', '27', '28'), +('7', '1', '27', '56', '46', '55', '27', '29'), +('7', '1', '28', '58', '47', '57', '27', '29'), +('7', '1', '29', '59', '48', '58', '27', '30'), +('7', '1', '30', '61', '49', '60', '27', '30'), +('7', '1', '31', '63', '50', '62', '27', '30'), +('7', '1', '32', '65', '51', '63', '28', '31'), +('7', '1', '33', '66', '52', '65', '28', '31'), +('7', '1', '34', '68', '53', '66', '28', '32'), +('7', '1', '35', '70', '55', '68', '28', '32'), +('7', '1', '36', '72', '56', '69', '28', '33'), +('7', '1', '37', '73', '57', '71', '29', '33'), +('7', '1', '38', '75', '58', '73', '29', '34'), +('7', '1', '39', '77', '59', '74', '29', '34'), +('7', '1', '40', '79', '60', '76', '29', '35'), +('7', '1', '41', '81', '61', '78', '29', '35'), +('7', '1', '42', '82', '62', '79', '30', '35'), +('7', '1', '43', '84', '64', '81', '30', '36'), +('7', '1', '44', '86', '65', '83', '30', '36'), +('7', '1', '45', '88', '66', '85', '30', '37'), +('7', '1', '46', '90', '67', '86', '30', '37'), +('7', '1', '47', '92', '68', '88', '31', '38'), +('7', '1', '48', '94', '70', '90', '31', '38'), +('7', '1', '49', '96', '71', '92', '31', '39'), +('7', '1', '50', '98', '72', '93', '31', '40'), +('7', '1', '51', '100', '73', '95', '32', '40'), +('7', '1', '52', '102', '75', '97', '32', '41'), +('7', '1', '53', '104', '76', '99', '32', '41'), +('7', '1', '54', '106', '77', '101', '32', '42'), +('7', '1', '55', '108', '78', '103', '33', '42'), +('7', '1', '56', '110', '80', '104', '33', '43'), +('7', '1', '57', '112', '81', '106', '33', '43'), +('7', '1', '58', '114', '82', '108', '33', '44'), +('7', '1', '59', '116', '84', '110', '34', '44'), +('7', '1', '60', '118', '85', '112', '34', '45'), +('7', '1', '61', '120', '86', '114', '34', '46'), +('7', '1', '62', '122', '88', '116', '35', '46'), +('7', '1', '63', '125', '89', '118', '35', '47'), +('7', '1', '64', '127', '91', '120', '35', '47'), +('7', '1', '65', '129', '92', '122', '35', '48'), +('7', '1', '66', '131', '93', '124', '36', '49'), +('7', '1', '67', '133', '95', '126', '36', '49'), +('7', '1', '68', '136', '96', '128', '36', '50'), +('7', '1', '69', '138', '98', '130', '37', '50'), +('7', '1', '70', '140', '99', '132', '37', '51'), +('7', '1', '71', '143', '100', '134', '37', '52'), +('7', '1', '72', '145', '102', '137', '37', '53'), +('7', '1', '73', '148', '104', '139', '37', '54'), +('7', '1', '74', '151', '105', '142', '38', '54'), +('7', '1', '75', '154', '107', '144', '38', '55'), +('7', '1', '76', '157', '109', '147', '38', '56'), +('7', '1', '77', '163', '111', '153', '39', '57'), +('7', '1', '78', '169', '112', '158', '39', '57'), +('7', '1', '79', '172', '114', '161', '39', '58'), +('7', '1', '80', '175', '116', '164', '40', '59'), +('7', '4', '1', '16', '26', '20', '24', '20'), +('7', '4', '2', '17', '27', '21', '24', '20'), +('7', '4', '3', '18', '29', '21', '24', '21'), +('7', '4', '4', '18', '30', '22', '24', '21'), +('7', '4', '5', '19', '32', '23', '25', '21'), +('7', '4', '6', '20', '33', '24', '25', '22'), +('7', '4', '7', '21', '35', '24', '25', '22'), +('7', '4', '8', '22', '36', '25', '25', '23'), +('7', '4', '9', '22', '38', '26', '25', '23'), +('7', '4', '10', '23', '39', '26', '25', '23'), +('7', '4', '11', '24', '41', '27', '25', '24'), +('7', '4', '12', '25', '42', '28', '26', '24'), +('7', '4', '13', '26', '44', '29', '26', '25'), +('7', '4', '14', '27', '46', '30', '26', '25'), +('7', '4', '15', '28', '47', '30', '26', '25'), +('7', '4', '16', '28', '49', '31', '26', '26'), +('7', '4', '17', '29', '50', '32', '27', '26'), +('7', '4', '18', '30', '52', '33', '27', '27'), +('7', '4', '19', '31', '54', '34', '27', '27'), +('7', '4', '20', '32', '56', '35', '27', '28'), +('7', '4', '21', '33', '57', '35', '27', '28'), +('7', '4', '22', '34', '59', '36', '28', '29'), +('7', '4', '23', '35', '61', '37', '28', '29'), +('7', '4', '24', '36', '62', '38', '28', '30'), +('7', '4', '25', '37', '64', '39', '28', '30'), +('7', '4', '26', '38', '66', '40', '29', '31'), +('7', '4', '27', '39', '68', '41', '29', '31'), +('7', '4', '28', '40', '70', '42', '29', '32'), +('7', '4', '29', '41', '72', '43', '29', '32'), +('7', '4', '30', '42', '73', '43', '29', '33'), +('7', '4', '31', '43', '75', '44', '30', '33'), +('7', '4', '32', '44', '77', '45', '30', '34'), +('7', '4', '33', '45', '79', '46', '30', '34'), +('7', '4', '34', '46', '81', '47', '31', '35'), +('7', '4', '35', '47', '83', '48', '31', '35'), +('7', '4', '36', '48', '85', '49', '31', '36'), +('7', '4', '37', '49', '87', '50', '31', '36'), +('7', '4', '38', '50', '89', '51', '32', '37'), +('7', '4', '39', '51', '91', '52', '32', '38'), +('7', '4', '40', '53', '93', '53', '32', '38'), +('7', '4', '41', '54', '95', '54', '33', '39'), +('7', '4', '42', '55', '97', '55', '33', '39'), +('7', '4', '43', '56', '99', '56', '33', '40'), +('7', '4', '44', '57', '101', '57', '33', '40'), +('7', '4', '45', '58', '103', '59', '34', '41'), +('7', '4', '46', '59', '105', '60', '34', '42'), +('7', '4', '47', '61', '107', '61', '34', '42'), +('7', '4', '48', '62', '110', '62', '35', '43'), +('7', '4', '49', '63', '112', '63', '35', '44'), +('7', '4', '50', '64', '114', '64', '35', '44'), +('7', '4', '51', '65', '116', '65', '36', '45'), +('7', '4', '52', '67', '118', '66', '36', '45'), +('7', '4', '53', '68', '121', '67', '36', '46'), +('7', '4', '54', '69', '123', '69', '37', '47'), +('7', '4', '55', '70', '125', '70', '37', '47'), +('7', '4', '56', '72', '127', '71', '37', '48'), +('7', '4', '57', '73', '130', '72', '38', '49'), +('7', '4', '58', '74', '132', '73', '38', '49'), +('7', '4', '59', '75', '134', '74', '39', '50'), +('7', '4', '60', '77', '137', '76', '39', '51'), +('7', '4', '61', '78', '139', '77', '39', '51'), +('7', '4', '62', '79', '141', '78', '40', '52'), +('7', '4', '63', '81', '144', '79', '40', '53'), +('7', '4', '64', '82', '146', '80', '41', '54'), +('7', '4', '65', '83', '149', '82', '41', '54'), +('7', '4', '66', '85', '151', '83', '41', '55'), +('7', '4', '67', '86', '154', '84', '42', '56'), +('7', '4', '68', '87', '156', '85', '42', '57'), +('7', '4', '69', '89', '158', '87', '43', '57'), +('7', '4', '70', '90', '161', '88', '43', '58'), +('7', '4', '71', '92', '164', '89', '44', '59'), +('7', '4', '72', '94', '167', '91', '45', '59'), +('7', '4', '73', '95', '170', '93', '45', '60'), +('7', '4', '74', '97', '173', '94', '46', '61'), +('7', '4', '75', '99', '176', '96', '46', '62'), +('7', '4', '76', '100', '179', '97', '46', '63'), +('7', '4', '77', '102', '182', '102', '47', '64'), +('7', '4', '78', '104', '186', '105', '47', '65'), +('7', '4', '79', '106', '189', '106', '48', '66'), +('7', '4', '80', '108', '192', '108', '48', '67'), +('7', '6', '1', '18', '23', '21', '24', '20'), +('7', '6', '2', '19', '24', '22', '24', '20'), +('7', '6', '3', '21', '25', '23', '24', '21'), +('7', '6', '4', '22', '25', '25', '24', '21'), +('7', '6', '5', '23', '26', '26', '24', '21'), +('7', '6', '6', '25', '27', '27', '24', '21'), +('7', '6', '7', '26', '28', '28', '24', '22'), +('7', '6', '8', '27', '29', '29', '25', '22'), +('7', '6', '9', '29', '29', '31', '25', '22'), +('7', '6', '10', '30', '30', '32', '25', '23'), +('7', '6', '11', '32', '31', '33', '25', '23'), +('7', '6', '12', '33', '32', '34', '25', '23'), +('7', '6', '13', '34', '33', '36', '25', '24'), +('7', '6', '14', '36', '34', '37', '25', '24'), +('7', '6', '15', '37', '35', '38', '25', '24'), +('7', '6', '16', '39', '36', '40', '25', '25'), +('7', '6', '17', '40', '36', '41', '25', '25'), +('7', '6', '18', '42', '37', '43', '26', '25'), +('7', '6', '19', '43', '38', '44', '26', '26'), +('7', '6', '20', '45', '39', '45', '26', '26'), +('7', '6', '21', '47', '40', '47', '26', '26'), +('7', '6', '22', '48', '41', '48', '26', '27'), +('7', '6', '23', '50', '42', '50', '26', '27'), +('7', '6', '24', '51', '43', '51', '26', '28'), +('7', '6', '25', '53', '44', '52', '27', '28'), +('7', '6', '26', '55', '45', '54', '27', '28'), +('7', '6', '27', '56', '46', '55', '27', '29'), +('7', '6', '28', '58', '47', '57', '27', '29'), +('7', '6', '29', '59', '48', '58', '27', '30'), +('7', '6', '30', '61', '49', '60', '27', '30'), +('7', '6', '31', '63', '50', '62', '27', '30'), +('7', '6', '32', '65', '51', '63', '28', '31'), +('7', '6', '33', '66', '52', '65', '28', '31'), +('7', '6', '34', '68', '53', '66', '28', '32'), +('7', '6', '35', '70', '55', '68', '28', '32'), +('7', '6', '36', '72', '56', '69', '28', '33'), +('7', '6', '37', '73', '57', '71', '29', '33'), +('7', '6', '38', '75', '58', '73', '29', '34'), +('7', '6', '39', '77', '59', '74', '29', '34'), +('7', '6', '40', '79', '60', '76', '29', '35'), +('7', '6', '41', '81', '61', '78', '29', '35'), +('7', '6', '42', '82', '62', '79', '30', '35'), +('7', '6', '43', '84', '64', '81', '30', '36'), +('7', '6', '44', '86', '65', '83', '30', '36'), +('7', '6', '45', '88', '66', '85', '30', '37'), +('7', '6', '46', '90', '67', '86', '30', '37'), +('7', '6', '47', '92', '68', '88', '31', '38'), +('7', '6', '48', '94', '70', '90', '31', '38'), +('7', '6', '49', '96', '71', '92', '31', '39'), +('7', '6', '50', '98', '72', '93', '31', '40'), +('7', '6', '51', '99', '72', '93', '32', '40'), +('7', '6', '52', '100', '73', '95', '32', '41'), +('7', '6', '53', '101', '74', '96', '32', '41'), +('7', '6', '54', '102', '75', '97', '32', '42'), +('7', '6', '55', '103', '76', '98', '33', '42'), +('7', '6', '56', '106', '78', '101', '33', '43'), +('7', '6', '57', '111', '79', '103', '33', '43'), +('7', '6', '58', '113', '80', '105', '34', '44'), +('7', '6', '59', '116', '82', '107', '34', '44'), +('7', '6', '60', '118', '83', '109', '34', '45'), +('7', '6', '61', '120', '84', '111', '34', '46'), +('7', '6', '62', '127', '86', '119', '34', '46'), +('7', '6', '63', '129', '87', '122', '35', '47'), +('7', '6', '64', '132', '89', '125', '35', '47'), +('7', '6', '65', '135', '90', '127', '35', '48'), +('7', '6', '66', '137', '92', '130', '35', '49'), +('7', '6', '67', '138', '93', '130', '36', '49'), +('7', '6', '68', '140', '95', '131', '36', '50'), +('7', '6', '69', '142', '96', '131', '36', '51'), +('7', '6', '70', '145', '98', '132', '36', '51'), +('7', '6', '71', '148', '100', '135', '37', '52'), +('7', '6', '72', '150', '101', '137', '37', '53'), +('7', '6', '73', '153', '103', '140', '37', '54'), +('7', '6', '74', '154', '105', '142', '37', '54'), +('7', '6', '75', '155', '106', '145', '38', '55'), +('7', '6', '76', '158', '108', '151', '38', '56'), +('7', '6', '77', '161', '110', '157', '38', '57'), +('7', '6', '78', '164', '111', '162', '38', '57'), +('7', '6', '79', '167', '113', '165', '39', '58'), +('7', '6', '80', '170', '115', '168', '39', '59'), +('7', '8', '1', '15', '23', '19', '27', '22'), +('7', '8', '2', '15', '23', '19', '28', '23'), +('7', '8', '3', '15', '23', '20', '30', '25'), +('7', '8', '4', '15', '23', '20', '31', '26'), +('7', '8', '5', '15', '24', '20', '32', '27'), +('7', '8', '6', '15', '24', '20', '34', '29'), +('7', '8', '7', '16', '24', '21', '35', '30'), +('7', '8', '8', '16', '24', '21', '37', '31'), +('7', '8', '9', '16', '24', '21', '38', '33'), +('7', '8', '10', '16', '24', '22', '40', '34'), +('7', '8', '11', '16', '25', '22', '41', '36'), +('7', '8', '12', '16', '25', '22', '42', '37'), +('7', '8', '13', '16', '25', '23', '44', '38'), +('7', '8', '14', '16', '25', '23', '45', '40'), +('7', '8', '15', '17', '25', '23', '47', '41'), +('7', '8', '16', '17', '25', '24', '49', '43'), +('7', '8', '17', '17', '26', '24', '50', '44'), +('7', '8', '18', '17', '26', '24', '52', '46'), +('7', '8', '19', '17', '26', '25', '53', '47'), +('7', '8', '20', '17', '26', '25', '55', '49'), +('7', '8', '21', '17', '26', '26', '57', '51'), +('7', '8', '22', '18', '27', '26', '58', '52'), +('7', '8', '23', '18', '27', '26', '60', '54'), +('7', '8', '24', '18', '27', '27', '61', '55'), +('7', '8', '25', '18', '27', '27', '63', '57'), +('7', '8', '26', '18', '28', '27', '65', '59'), +('7', '8', '27', '18', '28', '28', '67', '60'), +('7', '8', '28', '18', '28', '28', '68', '62'), +('7', '8', '29', '19', '28', '29', '70', '64'), +('7', '8', '30', '19', '29', '29', '72', '65'), +('7', '8', '31', '19', '29', '30', '74', '67'), +('7', '8', '32', '19', '29', '30', '75', '69'), +('7', '8', '33', '19', '29', '30', '77', '70'), +('7', '8', '34', '20', '30', '31', '79', '72'), +('7', '8', '35', '20', '30', '31', '81', '74'), +('7', '8', '36', '20', '30', '32', '83', '76'), +('7', '8', '37', '20', '30', '32', '85', '78'), +('7', '8', '38', '20', '31', '33', '86', '79'), +('7', '8', '39', '21', '31', '33', '88', '81'), +('7', '8', '40', '21', '31', '34', '90', '83'), +('7', '8', '41', '21', '32', '34', '92', '85'), +('7', '8', '42', '21', '32', '35', '94', '87'), +('7', '8', '43', '21', '32', '35', '96', '89'), +('7', '8', '44', '22', '32', '36', '98', '91'), +('7', '8', '45', '22', '33', '36', '100', '92'), +('7', '8', '46', '22', '33', '37', '102', '94'), +('7', '8', '47', '22', '33', '37', '104', '96'), +('7', '8', '48', '22', '34', '38', '106', '98'), +('7', '8', '49', '23', '34', '38', '108', '100'), +('7', '8', '50', '23', '34', '39', '110', '102'), +('7', '8', '51', '23', '35', '39', '112', '104'), +('7', '8', '52', '23', '35', '40', '114', '106'), +('7', '8', '53', '24', '35', '40', '117', '108'), +('7', '8', '54', '24', '36', '41', '119', '110'), +('7', '8', '55', '24', '36', '41', '121', '112'), +('7', '8', '56', '24', '37', '42', '123', '114'), +('7', '8', '57', '25', '37', '42', '125', '117'), +('7', '8', '58', '25', '37', '43', '127', '119'), +('7', '8', '59', '25', '38', '43', '130', '121'), +('7', '8', '60', '25', '38', '44', '132', '123'), +('7', '8', '61', '26', '38', '45', '134', '125'), +('7', '8', '62', '26', '39', '45', '136', '127'), +('7', '8', '63', '26', '39', '46', '139', '129'), +('7', '8', '64', '26', '40', '46', '141', '132'), +('7', '8', '65', '27', '40', '47', '143', '134'), +('7', '8', '66', '27', '40', '48', '146', '136'), +('7', '8', '67', '27', '41', '48', '148', '138'), +('7', '8', '68', '27', '41', '49', '150', '140'), +('7', '8', '69', '28', '42', '49', '153', '143'), +('7', '8', '70', '28', '42', '50', '155', '145'), +('7', '8', '71', '28', '42', '51', '168', '148'), +('7', '8', '72', '28', '43', '52', '168', '151'), +('7', '8', '73', '28', '43', '53', '171', '154'), +('7', '8', '74', '29', '44', '53', '174', '156'), +('7', '8', '75', '29', '44', '54', '177', '159'), +('7', '8', '76', '29', '44', '55', '180', '162'), +('7', '8', '77', '30', '45', '56', '183', '165'), +('7', '8', '78', '30', '45', '56', '186', '168'), +('7', '8', '79', '30', '46', '57', '190', '171'), +('7', '8', '80', '31', '46', '58', '193', '174'), +('7', '9', '1', '15', '23', '20', '26', '22'), +('7', '9', '2', '15', '23', '21', '27', '23'), +('7', '9', '3', '16', '24', '21', '28', '24'), +('7', '9', '4', '16', '24', '22', '29', '25'), +('7', '9', '5', '16', '24', '22', '31', '27'), +('7', '9', '6', '17', '25', '23', '32', '28'), +('7', '9', '7', '17', '25', '23', '33', '29'), +('7', '9', '8', '17', '26', '24', '34', '30'), +('7', '9', '9', '17', '26', '25', '36', '31'), +('7', '9', '10', '18', '26', '25', '37', '33'), +('7', '9', '11', '18', '27', '26', '38', '34'), +('7', '9', '12', '18', '27', '26', '39', '35'), +('7', '9', '13', '19', '28', '27', '41', '36'), +('7', '9', '14', '19', '28', '28', '42', '38'), +('7', '9', '15', '20', '28', '28', '43', '39'), +('7', '9', '16', '20', '29', '29', '45', '40'), +('7', '9', '17', '20', '29', '30', '46', '42'), +('7', '9', '18', '21', '30', '30', '47', '43'), +('7', '9', '19', '21', '30', '31', '49', '44'), +('7', '9', '20', '21', '31', '32', '50', '46'), +('7', '9', '21', '22', '31', '32', '51', '47'), +('7', '9', '22', '22', '31', '33', '53', '49'), +('7', '9', '23', '23', '32', '34', '54', '50'), +('7', '9', '24', '23', '32', '34', '56', '51'), +('7', '9', '25', '23', '33', '35', '57', '53'), +('7', '9', '26', '24', '33', '36', '59', '54'), +('7', '9', '27', '24', '34', '37', '60', '56'), +('7', '9', '28', '25', '34', '37', '62', '57'), +('7', '9', '29', '25', '35', '38', '63', '59'), +('7', '9', '30', '25', '35', '39', '65', '60'), +('7', '9', '31', '26', '36', '40', '66', '62'), +('7', '9', '32', '26', '36', '40', '68', '63'), +('7', '9', '33', '27', '37', '41', '69', '65'), +('7', '9', '34', '27', '38', '42', '71', '66'), +('7', '9', '35', '28', '38', '43', '73', '68'), +('7', '9', '36', '28', '39', '43', '74', '69'), +('7', '9', '37', '28', '39', '44', '76', '71'), +('7', '9', '38', '29', '40', '45', '77', '73'), +('7', '9', '39', '29', '40', '46', '79', '74'), +('7', '9', '40', '30', '41', '47', '81', '76'), +('7', '9', '41', '30', '41', '48', '82', '78'), +('7', '9', '42', '31', '42', '48', '84', '79'), +('7', '9', '43', '31', '43', '49', '86', '81'), +('7', '9', '44', '32', '43', '50', '88', '83'), +('7', '9', '45', '32', '44', '51', '89', '84'), +('7', '9', '46', '33', '44', '52', '91', '86'), +('7', '9', '47', '33', '45', '53', '93', '88'), +('7', '9', '48', '34', '46', '54', '95', '89'), +('7', '9', '49', '34', '46', '54', '96', '91'), +('7', '9', '50', '35', '47', '55', '98', '93'), +('7', '9', '51', '35', '48', '56', '100', '95'), +('7', '9', '52', '36', '48', '57', '102', '97'), +('7', '9', '53', '36', '49', '58', '104', '98'), +('7', '9', '54', '37', '50', '59', '105', '100'), +('7', '9', '55', '37', '50', '60', '107', '102'), +('7', '9', '56', '38', '51', '61', '109', '104'), +('7', '9', '57', '38', '52', '62', '111', '106'), +('7', '9', '58', '39', '52', '63', '113', '108'), +('7', '9', '59', '40', '53', '64', '115', '109'), +('7', '9', '60', '40', '54', '65', '117', '111'), +('7', '9', '61', '41', '54', '66', '119', '113'), +('7', '9', '62', '41', '55', '67', '121', '115'), +('7', '9', '63', '42', '56', '68', '123', '117'), +('7', '9', '64', '42', '57', '69', '125', '119'), +('7', '9', '65', '43', '57', '70', '127', '121'), +('7', '9', '66', '44', '58', '71', '129', '123'), +('7', '9', '67', '44', '59', '72', '131', '125'), +('7', '9', '68', '45', '59', '73', '133', '127'), +('7', '9', '69', '45', '60', '74', '135', '129'), +('7', '9', '70', '46', '61', '75', '137', '131'), +('7', '9', '71', '47', '62', '84', '147', '142'), +('7', '9', '72', '48', '62', '85', '148', '144'), +('7', '9', '73', '49', '63', '85', '153', '147'), +('7', '9', '74', '49', '64', '88', '153', '150'), +('7', '9', '75', '50', '65', '90', '155', '152'), +('7', '9', '76', '51', '66', '91', '158', '155'), +('7', '9', '77', '52', '67', '92', '161', '158'), +('7', '9', '78', '52', '68', '93', '163', '161'), +('7', '9', '79', '53', '69', '95', '166', '164'), +('7', '9', '80', '54', '70', '96', '170', '166'), +('8', '1', '1', '24', '22', '23', '16', '21'), +('8', '1', '2', '25', '23', '24', '16', '21'), +('8', '1', '3', '27', '24', '25', '16', '22'), +('8', '1', '4', '28', '24', '26', '16', '22'), +('8', '1', '5', '29', '25', '28', '16', '22'), +('8', '1', '6', '31', '26', '29', '16', '22'), +('8', '1', '7', '32', '27', '30', '17', '23'), +('8', '1', '8', '33', '28', '31', '17', '23'), +('8', '1', '9', '35', '28', '33', '17', '23'), +('8', '1', '10', '36', '29', '34', '17', '24'), +('8', '1', '11', '37', '30', '35', '17', '24'), +('8', '1', '12', '39', '31', '36', '17', '24'), +('8', '1', '13', '40', '32', '38', '17', '25'), +('8', '1', '14', '42', '33', '39', '17', '25'), +('8', '1', '15', '43', '34', '40', '18', '25'), +('8', '1', '16', '45', '35', '42', '18', '26'), +('8', '1', '17', '46', '35', '43', '18', '26'), +('8', '1', '18', '48', '36', '44', '18', '26'), +('8', '1', '19', '49', '37', '46', '18', '27'), +('8', '1', '20', '51', '38', '47', '18', '27'), +('8', '1', '21', '52', '39', '49', '18', '27'), +('8', '1', '22', '54', '40', '50', '18', '28'), +('8', '1', '23', '55', '41', '51', '19', '28'), +('8', '1', '24', '57', '42', '53', '19', '29'), +('8', '1', '25', '59', '43', '54', '19', '29'), +('8', '1', '26', '60', '44', '56', '19', '29'), +('8', '1', '27', '62', '45', '57', '19', '30'), +('8', '1', '28', '63', '46', '59', '19', '30'), +('8', '1', '29', '65', '47', '60', '20', '31'), +('8', '1', '30', '67', '48', '62', '20', '31'), +('8', '1', '31', '69', '49', '63', '20', '31'), +('8', '1', '32', '70', '50', '65', '20', '32'), +('8', '1', '33', '72', '51', '67', '20', '32'), +('8', '1', '34', '74', '53', '68', '20', '33'), +('8', '1', '35', '75', '54', '70', '21', '33'), +('8', '1', '36', '77', '55', '71', '21', '34'), +('8', '1', '37', '79', '56', '73', '21', '34'), +('8', '1', '38', '81', '57', '75', '21', '35'), +('8', '1', '39', '83', '58', '76', '21', '35'), +('8', '1', '40', '84', '59', '78', '22', '35'), +('8', '1', '41', '86', '60', '80', '22', '36'), +('8', '1', '42', '88', '62', '81', '22', '36'), +('8', '1', '43', '90', '63', '83', '22', '37'), +('8', '1', '44', '92', '64', '85', '22', '37'), +('8', '1', '45', '94', '65', '86', '23', '38'), +('8', '1', '46', '96', '66', '88', '23', '38'), +('8', '1', '47', '98', '67', '90', '23', '39'), +('8', '1', '48', '100', '69', '92', '23', '39'), +('8', '1', '49', '102', '70', '93', '24', '40'), +('8', '1', '50', '103', '71', '95', '24', '40'), +('8', '1', '51', '105', '72', '97', '24', '41'), +('8', '1', '52', '107', '74', '99', '24', '42'), +('8', '1', '53', '109', '75', '101', '25', '42'), +('8', '1', '54', '112', '76', '103', '25', '43'), +('8', '1', '55', '114', '78', '104', '25', '43'), +('8', '1', '56', '116', '79', '106', '25', '44'), +('8', '1', '57', '118', '80', '108', '25', '44'), +('8', '1', '58', '120', '81', '110', '26', '45'), +('8', '1', '59', '122', '83', '112', '26', '45'), +('8', '1', '60', '124', '84', '114', '26', '46'), +('8', '1', '61', '126', '85', '116', '27', '47'), +('8', '1', '62', '128', '87', '118', '27', '47'), +('8', '1', '63', '130', '88', '120', '27', '48'), +('8', '1', '64', '133', '90', '122', '27', '48'), +('8', '1', '65', '135', '91', '124', '28', '49'), +('8', '1', '66', '137', '92', '126', '28', '50'), +('8', '1', '67', '139', '94', '128', '28', '50'), +('8', '1', '68', '141', '95', '130', '28', '51'), +('8', '1', '69', '144', '97', '132', '29', '51'), +('8', '1', '70', '146', '98', '134', '29', '52'), +('8', '1', '71', '149', '99', '136', '29', '53'), +('8', '1', '72', '151', '101', '139', '29', '54'), +('8', '1', '73', '154', '103', '141', '29', '55'), +('8', '1', '74', '157', '104', '144', '30', '55'), +('8', '1', '75', '166', '106', '151', '30', '56'), +('8', '1', '76', '172', '108', '157', '30', '57'), +('8', '1', '77', '175', '110', '161', '31', '58'), +('8', '1', '78', '179', '111', '163', '31', '58'), +('8', '1', '79', '182', '113', '164', '31', '59'), +('8', '1', '80', '185', '115', '169', '32', '60'), +('8', '3', '1', '21', '25', '22', '16', '22'), +('8', '3', '2', '21', '26', '23', '17', '23'), +('8', '3', '3', '22', '28', '24', '17', '23'), +('8', '3', '4', '22', '29', '25', '18', '24'), +('8', '3', '5', '23', '30', '26', '18', '25'), +('8', '3', '6', '23', '32', '27', '19', '25'), +('8', '3', '7', '24', '33', '28', '20', '26'), +('8', '3', '8', '24', '35', '28', '20', '26'), +('8', '3', '9', '25', '36', '29', '21', '27'), +('8', '3', '10', '25', '38', '30', '21', '28'), +('8', '3', '11', '25', '39', '31', '22', '29'), +('8', '3', '12', '26', '41', '32', '23', '29'), +('8', '3', '13', '26', '42', '33', '23', '30'), +('8', '3', '14', '27', '44', '34', '24', '31'), +('8', '3', '15', '27', '45', '35', '25', '31'), +('8', '3', '16', '28', '47', '36', '25', '32'), +('8', '3', '17', '28', '48', '38', '26', '33'), +('8', '3', '18', '29', '50', '39', '27', '34'), +('8', '3', '19', '29', '51', '40', '28', '34'), +('8', '3', '20', '30', '53', '41', '28', '35'), +('8', '3', '21', '31', '55', '42', '29', '36'), +('8', '3', '22', '31', '56', '43', '30', '37'), +('8', '3', '23', '32', '58', '44', '30', '37'), +('8', '3', '24', '32', '60', '45', '31', '38'), +('8', '3', '25', '33', '61', '46', '32', '39'), +('8', '3', '26', '33', '63', '48', '33', '40'), +('8', '3', '27', '34', '65', '49', '33', '41'), +('8', '3', '28', '35', '66', '50', '34', '41'), +('8', '3', '29', '35', '68', '51', '35', '42'), +('8', '3', '30', '36', '70', '52', '36', '43'), +('8', '3', '31', '36', '72', '53', '37', '44'), +('8', '3', '32', '37', '73', '55', '37', '45'), +('8', '3', '33', '38', '75', '56', '38', '46'), +('8', '3', '34', '38', '77', '57', '39', '47'), +('8', '3', '35', '39', '79', '58', '40', '48'), +('8', '3', '36', '39', '81', '60', '41', '48'), +('8', '3', '37', '40', '83', '61', '41', '49'), +('8', '3', '38', '41', '85', '62', '42', '50'), +('8', '3', '39', '41', '86', '63', '43', '51'), +('8', '3', '40', '42', '88', '65', '44', '52'), +('8', '3', '41', '43', '90', '66', '45', '53'), +('8', '3', '42', '43', '92', '67', '46', '54'), +('8', '3', '43', '44', '94', '69', '47', '55'), +('8', '3', '44', '45', '96', '70', '47', '56'), +('8', '3', '45', '45', '98', '71', '48', '57'), +('8', '3', '46', '46', '100', '73', '49', '58'), +('8', '3', '47', '47', '102', '74', '50', '59'), +('8', '3', '48', '48', '104', '76', '51', '60'), +('8', '3', '49', '48', '106', '77', '52', '61'), +('8', '3', '50', '49', '108', '78', '53', '62'), +('8', '3', '51', '50', '110', '80', '54', '63'), +('8', '3', '52', '51', '113', '81', '55', '64'), +('8', '3', '53', '51', '115', '83', '56', '65'), +('8', '3', '54', '52', '117', '84', '57', '66'), +('8', '3', '55', '53', '119', '86', '58', '67'), +('8', '3', '56', '54', '121', '87', '59', '68'), +('8', '3', '57', '54', '123', '89', '60', '69'), +('8', '3', '58', '55', '126', '90', '61', '70'), +('8', '3', '59', '56', '128', '92', '62', '71'), +('8', '3', '60', '57', '130', '93', '63', '73'), +('8', '3', '61', '58', '132', '95', '64', '74'), +('8', '3', '62', '58', '134', '96', '65', '75'), +('8', '3', '63', '59', '137', '98', '66', '76'), +('8', '3', '64', '60', '139', '99', '67', '77'), +('8', '3', '65', '61', '141', '101', '68', '78'), +('8', '3', '66', '62', '144', '103', '69', '79'), +('8', '3', '67', '62', '146', '104', '70', '80'), +('8', '3', '68', '63', '148', '106', '71', '82'), +('8', '3', '69', '64', '151', '107', '72', '83'), +('8', '3', '70', '65', '153', '109', '73', '84'), +('8', '3', '71', '66', '156', '111', '74', '85'), +('8', '3', '72', '67', '159', '113', '75', '86'), +('8', '3', '73', '68', '162', '115', '76', '88'), +('8', '3', '74', '69', '165', '117', '78', '89'), +('8', '3', '75', '70', '174', '119', '82', '91'), +('8', '3', '76', '71', '177', '121', '83', '92'), +('8', '3', '77', '72', '180', '123', '85', '94'), +('8', '3', '78', '73', '184', '125', '86', '95'), +('8', '3', '79', '74', '187', '127', '87', '97'), +('8', '3', '80', '75', '190', '129', '89', '98'), +('8', '4', '1', '22', '25', '22', '16', '21'), +('8', '4', '2', '23', '26', '23', '16', '21'), +('8', '4', '3', '24', '28', '23', '16', '22'), +('8', '4', '4', '24', '29', '24', '16', '22'), +('8', '4', '5', '25', '31', '25', '17', '22'), +('8', '4', '6', '26', '32', '25', '17', '23'), +('8', '4', '7', '27', '34', '26', '17', '23'), +('8', '4', '8', '27', '35', '27', '17', '24'), +('8', '4', '9', '28', '37', '28', '17', '24'), +('8', '4', '10', '29', '38', '28', '18', '24'), +('8', '4', '11', '30', '40', '29', '18', '25'), +('8', '4', '12', '31', '41', '30', '18', '25'), +('8', '4', '13', '32', '43', '31', '18', '26'), +('8', '4', '14', '32', '45', '32', '18', '26'), +('8', '4', '15', '33', '46', '32', '19', '26'), +('8', '4', '16', '34', '48', '33', '19', '27'), +('8', '4', '17', '35', '50', '34', '19', '27'), +('8', '4', '18', '36', '51', '35', '19', '28'), +('8', '4', '19', '37', '53', '36', '19', '28'), +('8', '4', '20', '38', '55', '36', '20', '29'), +('8', '4', '21', '39', '56', '37', '20', '29'), +('8', '4', '22', '40', '58', '38', '20', '30'), +('8', '4', '23', '41', '60', '39', '20', '30'), +('8', '4', '24', '42', '62', '40', '20', '31'), +('8', '4', '25', '43', '63', '41', '21', '31'), +('8', '4', '26', '44', '65', '42', '21', '32'), +('8', '4', '27', '45', '67', '43', '21', '32'), +('8', '4', '28', '46', '69', '44', '21', '33'), +('8', '4', '29', '47', '71', '44', '22', '33'), +('8', '4', '30', '48', '72', '45', '22', '34'), +('8', '4', '31', '49', '74', '46', '22', '34'), +('8', '4', '32', '50', '76', '47', '22', '35'), +('8', '4', '33', '51', '78', '48', '23', '35'), +('8', '4', '34', '52', '80', '49', '23', '36'), +('8', '4', '35', '53', '82', '50', '23', '36'), +('8', '4', '36', '54', '84', '51', '24', '37'), +('8', '4', '37', '55', '86', '52', '24', '37'), +('8', '4', '38', '56', '88', '53', '24', '38'), +('8', '4', '39', '57', '90', '54', '24', '38'), +('8', '4', '40', '58', '92', '55', '25', '39'), +('8', '4', '41', '59', '94', '56', '25', '40'), +('8', '4', '42', '60', '96', '57', '25', '40'), +('8', '4', '43', '62', '98', '58', '26', '41'), +('8', '4', '44', '63', '100', '59', '26', '41'), +('8', '4', '45', '64', '102', '60', '26', '42'), +('8', '4', '46', '65', '104', '61', '27', '43'), +('8', '4', '47', '66', '107', '63', '27', '43'), +('8', '4', '48', '67', '109', '64', '27', '44'), +('8', '4', '49', '69', '111', '65', '27', '44'), +('8', '4', '50', '70', '113', '66', '28', '45'), +('8', '4', '51', '71', '115', '67', '28', '46'), +('8', '4', '52', '72', '117', '68', '28', '46'), +('8', '4', '53', '74', '120', '69', '29', '47'), +('8', '4', '54', '75', '122', '70', '29', '48'), +('8', '4', '55', '76', '124', '72', '29', '48'), +('8', '4', '56', '77', '126', '73', '30', '49'), +('8', '4', '57', '79', '129', '74', '30', '50'), +('8', '4', '58', '80', '131', '75', '30', '50'), +('8', '4', '59', '81', '133', '76', '31', '51'), +('8', '4', '60', '82', '136', '77', '31', '52'), +('8', '4', '61', '84', '138', '79', '32', '52'), +('8', '4', '62', '85', '140', '80', '32', '53'), +('8', '4', '63', '86', '143', '81', '32', '54'), +('8', '4', '64', '88', '145', '82', '33', '55'), +('8', '4', '65', '89', '148', '84', '33', '55'), +('8', '4', '66', '90', '150', '85', '33', '56'), +('8', '4', '67', '92', '153', '86', '34', '57'), +('8', '4', '68', '93', '155', '87', '34', '58'), +('8', '4', '69', '95', '157', '89', '35', '58'), +('8', '4', '70', '96', '160', '90', '35', '59'), +('8', '4', '71', '98', '163', '94', '35', '60'), +('8', '4', '72', '100', '166', '96', '36', '60'), +('8', '4', '73', '101', '169', '96', '36', '61'), +('8', '4', '74', '103', '172', '97', '37', '62'), +('8', '4', '75', '105', '175', '98', '37', '63'), +('8', '4', '76', '106', '178', '99', '37', '64'), +('8', '4', '77', '108', '181', '105', '38', '65'), +('8', '4', '78', '110', '185', '107', '38', '66'), +('8', '4', '79', '112', '188', '109', '39', '67'), +('8', '4', '80', '114', '191', '110', '39', '68'), +('8', '5', '1', '21', '22', '21', '18', '24'), +('8', '5', '2', '21', '22', '21', '19', '25'), +('8', '5', '3', '21', '22', '22', '21', '27'), +('8', '5', '4', '21', '23', '22', '22', '28'), +('8', '5', '5', '22', '23', '22', '23', '29'), +('8', '5', '6', '22', '23', '23', '25', '31'), +('8', '5', '7', '22', '23', '23', '26', '32'), +('8', '5', '8', '22', '24', '24', '27', '34'), +('8', '5', '9', '22', '24', '24', '29', '35'), +('8', '5', '10', '22', '24', '24', '30', '37'), +('8', '5', '11', '23', '24', '25', '32', '38'), +('8', '5', '12', '23', '24', '25', '33', '40'), +('8', '5', '13', '23', '25', '26', '35', '41'), +('8', '5', '14', '23', '25', '26', '36', '43'), +('8', '5', '15', '23', '25', '26', '38', '44'), +('8', '5', '16', '24', '26', '27', '39', '46'), +('8', '5', '17', '24', '26', '27', '41', '47'), +('8', '5', '18', '24', '26', '28', '42', '49'), +('8', '5', '19', '24', '26', '28', '44', '50'), +('8', '5', '20', '24', '27', '29', '45', '52'), +('8', '5', '21', '25', '27', '29', '47', '54'), +('8', '5', '22', '25', '27', '30', '48', '55'), +('8', '5', '23', '25', '28', '30', '50', '57'), +('8', '5', '24', '25', '28', '31', '52', '59'), +('8', '5', '25', '25', '28', '31', '53', '60'), +('8', '5', '26', '26', '28', '32', '55', '62'), +('8', '5', '27', '26', '29', '32', '56', '64'), +('8', '5', '28', '26', '29', '33', '58', '65'), +('8', '5', '29', '26', '29', '33', '60', '67'), +('8', '5', '30', '27', '30', '34', '62', '69'), +('8', '5', '31', '27', '30', '34', '63', '71'), +('8', '5', '32', '27', '30', '35', '65', '73'), +('8', '5', '33', '27', '31', '35', '67', '74'), +('8', '5', '34', '28', '31', '36', '68', '76'), +('8', '5', '35', '28', '32', '36', '70', '78'), +('8', '5', '36', '28', '32', '37', '72', '80'), +('8', '5', '37', '29', '32', '37', '74', '82'), +('8', '5', '38', '29', '33', '38', '76', '84'), +('8', '5', '39', '29', '33', '38', '77', '86'), +('8', '5', '40', '29', '33', '39', '79', '87'), +('8', '5', '41', '30', '34', '40', '81', '89'), +('8', '5', '42', '30', '34', '40', '83', '91'), +('8', '5', '43', '30', '35', '41', '85', '93'), +('8', '5', '44', '31', '35', '41', '87', '95'), +('8', '5', '45', '31', '35', '42', '89', '97'), +('8', '5', '46', '31', '36', '43', '91', '99'), +('8', '5', '47', '32', '36', '43', '93', '101'), +('8', '5', '48', '32', '37', '44', '94', '103'), +('8', '5', '49', '32', '37', '44', '96', '105'), +('8', '5', '50', '33', '37', '45', '98', '107'), +('8', '5', '51', '33', '38', '46', '100', '110'), +('8', '5', '52', '33', '38', '46', '102', '112'), +('8', '5', '53', '34', '39', '47', '104', '114'), +('8', '5', '54', '34', '39', '48', '106', '116'), +('8', '5', '55', '34', '40', '48', '109', '118'), +('8', '5', '56', '35', '40', '49', '111', '120'), +('8', '5', '57', '35', '41', '50', '113', '122'), +('8', '5', '58', '35', '41', '50', '115', '125'), +('8', '5', '59', '36', '42', '51', '117', '127'), +('8', '5', '60', '36', '42', '52', '119', '129'), +('8', '5', '61', '36', '42', '52', '121', '131'), +('8', '5', '62', '37', '43', '53', '123', '133'), +('8', '5', '63', '37', '43', '54', '125', '136'), +('8', '5', '64', '38', '44', '55', '128', '138'), +('8', '5', '65', '38', '44', '55', '130', '140'), +('8', '5', '66', '38', '45', '56', '132', '143'), +('8', '5', '67', '39', '45', '57', '134', '145'), +('8', '5', '68', '39', '46', '58', '136', '147'), +('8', '5', '69', '40', '46', '58', '139', '150'), +('8', '5', '70', '40', '47', '59', '141', '152'), +('8', '5', '71', '40', '48', '60', '144', '155'), +('8', '5', '72', '41', '48', '60', '147', '158'), +('8', '5', '73', '41', '49', '61', '150', '161'), +('8', '5', '74', '42', '49', '62', '152', '164'), +('8', '5', '75', '42', '50', '63', '155', '167'), +('8', '5', '76', '42', '51', '64', '158', '170'), +('8', '5', '77', '43', '51', '65', '161', '173'), +('8', '5', '78', '43', '52', '66', '164', '176'), +('8', '5', '79', '44', '52', '67', '167', '179'), +('8', '5', '80', '44', '53', '68', '170', '182'), +('8', '6', '1', '24', '22', '23', '16', '21'), +('8', '6', '2', '25', '23', '24', '16', '21'), +('8', '6', '3', '27', '24', '25', '16', '22'), +('8', '6', '4', '28', '24', '26', '16', '22'), +('8', '6', '5', '29', '25', '28', '16', '22'), +('8', '6', '6', '31', '26', '29', '16', '22'), +('8', '6', '7', '32', '27', '30', '17', '23'), +('8', '6', '8', '33', '28', '31', '17', '23'), +('8', '6', '9', '35', '28', '33', '17', '23'), +('8', '6', '10', '36', '29', '34', '17', '24'), +('8', '6', '11', '37', '30', '35', '17', '24'), +('8', '6', '12', '39', '31', '36', '17', '24'), +('8', '6', '13', '40', '32', '38', '17', '25'), +('8', '6', '14', '42', '33', '39', '17', '25'), +('8', '6', '15', '43', '34', '40', '18', '25'), +('8', '6', '16', '45', '35', '42', '18', '26'), +('8', '6', '17', '46', '35', '43', '18', '26'), +('8', '6', '18', '48', '36', '44', '18', '26'), +('8', '6', '19', '49', '37', '46', '18', '27'), +('8', '6', '20', '51', '38', '47', '18', '27'), +('8', '6', '21', '52', '39', '49', '18', '27'), +('8', '6', '22', '54', '40', '50', '18', '28'), +('8', '6', '23', '55', '41', '51', '19', '28'), +('8', '6', '24', '57', '42', '53', '19', '29'), +('8', '6', '25', '59', '43', '54', '19', '29'), +('8', '6', '26', '60', '44', '56', '19', '29'), +('8', '6', '27', '62', '45', '57', '19', '30'), +('8', '6', '28', '63', '46', '59', '19', '30'), +('8', '6', '29', '65', '47', '60', '20', '31'), +('8', '6', '30', '67', '48', '62', '20', '31'), +('8', '6', '31', '69', '49', '63', '20', '31'), +('8', '6', '32', '70', '50', '65', '20', '32'), +('8', '6', '33', '72', '51', '67', '20', '32'), +('8', '6', '34', '74', '53', '68', '20', '33'), +('8', '6', '35', '75', '54', '70', '21', '33'), +('8', '6', '36', '77', '55', '71', '21', '34'), +('8', '6', '37', '79', '56', '73', '21', '34'), +('8', '6', '38', '81', '57', '75', '21', '35'), +('8', '6', '39', '83', '58', '76', '21', '35'), +('8', '6', '40', '84', '59', '78', '22', '35'), +('8', '6', '41', '86', '60', '80', '22', '36'), +('8', '6', '42', '88', '62', '81', '22', '36'), +('8', '6', '43', '90', '63', '83', '22', '37'), +('8', '6', '44', '92', '64', '85', '22', '37'), +('8', '6', '45', '94', '65', '86', '23', '38'), +('8', '6', '46', '96', '66', '88', '23', '38'), +('8', '6', '47', '98', '67', '90', '23', '39'), +('8', '6', '48', '100', '69', '92', '23', '39'), +('8', '6', '49', '102', '70', '93', '24', '40'), +('8', '6', '50', '103', '71', '95', '24', '40'), +('8', '6', '51', '105', '72', '96', '24', '41'), +('8', '6', '52', '106', '74', '97', '24', '42'), +('8', '6', '53', '107', '73', '98', '25', '42'), +('8', '6', '54', '108', '74', '99', '25', '43'), +('8', '6', '55', '109', '75', '100', '25', '43'), +('8', '6', '56', '112', '77', '103', '25', '44'), +('8', '6', '57', '114', '78', '105', '25', '44'), +('8', '6', '58', '118', '79', '107', '26', '45'), +('8', '6', '59', '119', '81', '109', '26', '45'), +('8', '6', '60', '121', '82', '111', '26', '46'), +('8', '6', '61', '123', '83', '113', '26', '47'), +('8', '6', '62', '126', '85', '115', '26', '47'), +('8', '6', '63', '128', '86', '118', '27', '48'), +('8', '6', '64', '131', '88', '120', '27', '48'), +('8', '6', '65', '138', '89', '122', '27', '49'), +('8', '6', '66', '140', '91', '125', '27', '50'), +('8', '6', '67', '143', '92', '127', '28', '50'), +('8', '6', '68', '145', '94', '129', '28', '51'), +('8', '6', '69', '148', '95', '132', '28', '52'), +('8', '6', '70', '151', '97', '134', '28', '52'), +('8', '6', '71', '154', '99', '137', '29', '53'), +('8', '6', '72', '156', '100', '139', '29', '54'), +('8', '6', '73', '159', '102', '142', '29', '55'), +('8', '6', '74', '162', '104', '144', '29', '55'), +('8', '6', '75', '165', '105', '147', '30', '56'), +('8', '6', '76', '168', '107', '150', '30', '57'), +('8', '6', '77', '169', '109', '153', '30', '58'), +('8', '6', '78', '170', '110', '155', '30', '58'), +('8', '6', '79', '178', '112', '158', '31', '59'), +('8', '6', '80', '181', '114', '161', '31', '60'), +('8', '7', '1', '22', '22', '22', '17', '23'), +('8', '7', '2', '23', '22', '23', '18', '24'), +('8', '7', '3', '24', '23', '24', '19', '25'), +('8', '7', '4', '25', '23', '25', '20', '26'), +('8', '7', '5', '25', '24', '26', '21', '27'), +('8', '7', '6', '26', '24', '27', '22', '28'), +('8', '7', '7', '27', '25', '28', '23', '29'), +('8', '7', '8', '28', '25', '29', '24', '30'), +('8', '7', '9', '29', '25', '30', '25', '31'), +('8', '7', '10', '30', '26', '31', '26', '33'), +('8', '7', '11', '31', '26', '32', '27', '34'), +('8', '7', '12', '32', '27', '33', '28', '35'), +('8', '7', '13', '33', '27', '34', '29', '36'), +('8', '7', '14', '34', '28', '35', '30', '37'), +('8', '7', '15', '34', '28', '36', '31', '38'), +('8', '7', '16', '35', '29', '38', '32', '39'), +('8', '7', '17', '36', '29', '39', '33', '41'), +('8', '7', '18', '37', '30', '40', '34', '42'), +('8', '7', '19', '38', '30', '41', '35', '43'), +('8', '7', '20', '39', '31', '42', '36', '44'), +('8', '7', '21', '40', '32', '43', '37', '45'), +('8', '7', '22', '41', '32', '45', '38', '47'), +('8', '7', '23', '43', '33', '46', '39', '48'), +('8', '7', '24', '44', '33', '47', '40', '49'), +('8', '7', '25', '45', '34', '48', '42', '51'), +('8', '7', '26', '46', '34', '49', '43', '52'), +('8', '7', '27', '47', '35', '51', '44', '53'), +('8', '7', '28', '48', '35', '52', '45', '54'), +('8', '7', '29', '49', '36', '53', '46', '56'), +('8', '7', '30', '50', '37', '54', '48', '57'), +('8', '7', '31', '51', '37', '56', '49', '59'), +('8', '7', '32', '52', '38', '57', '50', '60'), +('8', '7', '33', '53', '38', '58', '51', '61'), +('8', '7', '34', '55', '39', '60', '52', '63'), +('8', '7', '35', '56', '40', '61', '54', '64'), +('8', '7', '36', '57', '40', '62', '55', '66'), +('8', '7', '37', '58', '41', '64', '56', '67'), +('8', '7', '38', '59', '42', '65', '57', '68'), +('8', '7', '39', '61', '42', '66', '59', '70'), +('8', '7', '40', '62', '43', '68', '60', '71'), +('8', '7', '41', '63', '44', '69', '61', '73'), +('8', '7', '42', '64', '44', '71', '63', '74'), +('8', '7', '43', '65', '45', '72', '64', '76'), +('8', '7', '44', '67', '46', '74', '65', '77'), +('8', '7', '45', '68', '46', '75', '67', '79'), +('8', '7', '46', '69', '47', '76', '68', '80'), +('8', '7', '47', '71', '48', '78', '69', '82'), +('8', '7', '48', '72', '49', '79', '71', '83'), +('8', '7', '49', '73', '49', '81', '72', '85'), +('8', '7', '50', '74', '50', '82', '74', '87'), +('8', '7', '51', '76', '51', '84', '75', '88'), +('8', '7', '52', '77', '51', '85', '77', '90'), +('8', '7', '53', '78', '52', '87', '78', '92'), +('8', '7', '54', '80', '53', '89', '79', '93'), +('8', '7', '55', '81', '54', '90', '81', '95'), +('8', '7', '56', '83', '55', '92', '82', '96'), +('8', '7', '57', '84', '55', '93', '84', '98'), +('8', '7', '58', '85', '56', '95', '85', '100'), +('8', '7', '59', '87', '57', '97', '87', '102'), +('8', '7', '60', '88', '58', '98', '88', '103'), +('8', '7', '61', '90', '58', '100', '90', '105'), +('8', '7', '62', '91', '59', '101', '91', '107'), +('8', '7', '63', '93', '60', '103', '93', '108'), +('8', '7', '64', '94', '61', '105', '94', '110'), +('8', '7', '65', '95', '62', '106', '96', '112'), +('8', '7', '66', '97', '63', '108', '98', '114'), +('8', '7', '67', '98', '63', '110', '99', '116'), +('8', '7', '68', '100', '64', '112', '101', '117'), +('8', '7', '69', '101', '65', '113', '102', '119'), +('8', '7', '70', '103', '66', '115', '104', '121'), +('8', '7', '71', '104', '67', '117', '116', '123'), +('8', '7', '72', '106', '68', '119', '118', '126'), +('8', '7', '73', '108', '69', '121', '121', '128'), +('8', '7', '74', '110', '70', '124', '123', '130'), +('8', '7', '75', '112', '71', '126', '125', '132'), +('8', '7', '76', '114', '72', '128', '127', '135'), +('8', '7', '77', '115', '73', '130', '129', '137'), +('8', '7', '78', '117', '74', '132', '132', '139'), +('8', '7', '79', '119', '75', '135', '134', '142'), +('8', '7', '80', '121', '76', '137', '136', '144'), +('8', '8', '1', '21', '22', '21', '19', '23'), +('8', '8', '2', '21', '22', '21', '20', '24'), +('8', '8', '3', '21', '22', '22', '22', '26'), +('8', '8', '4', '21', '22', '22', '23', '27'), +('8', '8', '5', '21', '23', '22', '25', '28'), +('8', '8', '6', '21', '23', '22', '26', '30'), +('8', '8', '7', '21', '23', '23', '27', '31'), +('8', '8', '8', '22', '23', '23', '29', '32'), +('8', '8', '9', '22', '23', '23', '30', '34'), +('8', '8', '10', '22', '23', '24', '32', '35'), +('8', '8', '11', '22', '24', '24', '33', '37'), +('8', '8', '12', '22', '24', '24', '35', '38'), +('8', '8', '13', '22', '24', '25', '36', '39'), +('8', '8', '14', '22', '24', '25', '38', '41'), +('8', '8', '15', '22', '24', '25', '39', '42'), +('8', '8', '16', '22', '24', '26', '41', '44'), +('8', '8', '17', '23', '25', '26', '42', '45'), +('8', '8', '18', '23', '25', '26', '44', '47'), +('8', '8', '19', '23', '25', '27', '46', '48'), +('8', '8', '20', '23', '25', '27', '47', '50'), +('8', '8', '21', '23', '25', '27', '49', '51'), +('8', '8', '22', '23', '26', '28', '51', '53'), +('8', '8', '23', '23', '26', '28', '52', '55'), +('8', '8', '24', '24', '26', '29', '54', '56'), +('8', '8', '25', '24', '26', '29', '56', '58'), +('8', '8', '26', '24', '27', '29', '57', '60'), +('8', '8', '27', '24', '27', '30', '59', '61'), +('8', '8', '28', '24', '27', '30', '61', '63'), +('8', '8', '29', '24', '27', '31', '63', '65'), +('8', '8', '30', '24', '28', '31', '64', '66'), +('8', '8', '31', '25', '28', '31', '66', '68'), +('8', '8', '32', '25', '28', '32', '68', '70'), +('8', '8', '33', '25', '28', '32', '70', '71'), +('8', '8', '34', '25', '29', '33', '71', '73'), +('8', '8', '35', '25', '29', '33', '73', '75'), +('8', '8', '36', '26', '29', '34', '75', '77'), +('8', '8', '37', '26', '29', '34', '77', '79'), +('8', '8', '38', '26', '30', '35', '79', '80'), +('8', '8', '39', '26', '30', '35', '81', '82'), +('8', '8', '40', '26', '30', '35', '83', '84'), +('8', '8', '41', '27', '31', '36', '85', '86'), +('8', '8', '42', '27', '31', '36', '87', '88'), +('8', '8', '43', '27', '31', '37', '89', '90'), +('8', '8', '44', '27', '32', '37', '91', '91'), +('8', '8', '45', '27', '32', '38', '93', '93'), +('8', '8', '46', '28', '32', '38', '95', '95'), +('8', '8', '47', '28', '32', '39', '97', '97'), +('8', '8', '48', '28', '33', '39', '99', '99'), +('8', '8', '49', '28', '33', '40', '101', '101'), +('8', '8', '50', '29', '33', '40', '103', '103'), +('8', '8', '51', '29', '34', '41', '105', '105'), +('8', '8', '52', '29', '34', '42', '107', '107'), +('8', '8', '53', '29', '35', '42', '109', '109'), +('8', '8', '54', '30', '35', '43', '111', '111'), +('8', '8', '55', '30', '35', '43', '113', '113'), +('8', '8', '56', '30', '36', '44', '115', '115'), +('8', '8', '57', '30', '36', '44', '118', '118'), +('8', '8', '58', '31', '36', '45', '120', '120'), +('8', '8', '59', '31', '37', '45', '122', '122'), +('8', '8', '60', '31', '37', '46', '124', '124'), +('8', '8', '61', '31', '37', '47', '126', '126'), +('8', '8', '62', '32', '38', '47', '129', '128'), +('8', '8', '63', '32', '38', '48', '131', '130'), +('8', '8', '64', '32', '39', '48', '133', '133'), +('8', '8', '65', '33', '39', '49', '135', '135'), +('8', '8', '66', '33', '39', '50', '138', '137'), +('8', '8', '67', '33', '40', '50', '140', '139'), +('8', '8', '68', '33', '40', '51', '142', '141'), +('8', '8', '69', '34', '41', '51', '145', '144'), +('8', '8', '70', '34', '41', '52', '147', '146'), +('8', '8', '71', '34', '41', '53', '150', '149'), +('8', '8', '72', '34', '42', '54', '153', '152'), +('8', '8', '73', '34', '42', '55', '156', '155'), +('8', '8', '74', '35', '43', '55', '159', '157'), +('8', '8', '75', '35', '43', '56', '162', '160'), +('8', '8', '76', '35', '43', '57', '168', '163'), +('8', '8', '77', '36', '44', '58', '168', '166'), +('8', '8', '78', '36', '44', '58', '171', '169'), +('8', '8', '79', '36', '45', '59', '177', '172'), +('8', '8', '80', '37', '45', '60', '177', '175'), +('10', '2', '1', '19', '22', '21', '24', '20'), +('10', '2', '2', '20', '23', '22', '25', '21'), +('10', '2', '3', '21', '23', '23', '25', '21'), +('10', '2', '4', '22', '24', '24', '26', '22'), +('10', '2', '5', '23', '24', '25', '27', '23'), +('10', '2', '6', '25', '25', '26', '27', '24'), +('10', '2', '7', '26', '25', '27', '28', '24'), +('10', '2', '8', '27', '26', '28', '29', '25'), +('10', '2', '9', '28', '27', '29', '29', '26'), +('10', '2', '10', '29', '27', '31', '30', '26'), +('10', '2', '11', '30', '28', '32', '31', '27'), +('10', '2', '12', '32', '29', '33', '31', '28'), +('10', '2', '13', '33', '29', '34', '32', '29'), +('10', '2', '14', '34', '30', '35', '33', '30'), +('10', '2', '15', '35', '31', '36', '33', '30'), +('10', '2', '16', '37', '31', '37', '34', '31'), +('10', '2', '17', '38', '32', '39', '35', '32'), +('10', '2', '18', '39', '33', '40', '36', '33'), +('10', '2', '19', '40', '33', '41', '36', '34'), +('10', '2', '20', '42', '34', '42', '37', '35'), +('10', '2', '21', '43', '35', '44', '38', '35'), +('10', '2', '22', '44', '35', '45', '39', '36'), +('10', '2', '23', '46', '36', '46', '40', '37'), +('10', '2', '24', '47', '37', '47', '40', '38'), +('10', '2', '25', '49', '38', '49', '41', '39'), +('10', '2', '26', '50', '38', '50', '42', '40'), +('10', '2', '27', '51', '39', '51', '43', '41'), +('10', '2', '28', '53', '40', '53', '44', '42'), +('10', '2', '29', '54', '41', '54', '45', '43'), +('10', '2', '30', '56', '41', '55', '45', '43'), +('10', '2', '31', '57', '42', '57', '46', '44'), +('10', '2', '32', '58', '43', '58', '47', '45'), +('10', '2', '33', '60', '44', '59', '48', '46'), +('10', '2', '34', '61', '45', '61', '49', '47'), +('10', '2', '35', '63', '45', '62', '50', '48'), +('10', '2', '36', '64', '46', '64', '51', '49'), +('10', '2', '37', '66', '47', '65', '52', '50'), +('10', '2', '38', '67', '48', '67', '53', '51'), +('10', '2', '39', '69', '49', '68', '54', '52'), +('10', '2', '40', '71', '50', '69', '55', '53'), +('10', '2', '41', '72', '50', '71', '55', '54'), +('10', '2', '42', '74', '51', '72', '56', '55'), +('10', '2', '43', '75', '52', '74', '57', '56'), +('10', '2', '44', '77', '53', '75', '58', '57'), +('10', '2', '45', '79', '54', '77', '59', '59'), +('10', '2', '46', '80', '55', '78', '60', '60'), +('10', '2', '47', '82', '56', '80', '61', '61'), +('10', '2', '48', '83', '57', '82', '62', '62'), +('10', '2', '49', '85', '58', '83', '63', '63'), +('10', '2', '50', '87', '59', '85', '64', '64'), +('10', '2', '51', '89', '60', '86', '66', '65'), +('10', '2', '52', '90', '61', '88', '67', '66'), +('10', '2', '53', '92', '61', '90', '68', '67'), +('10', '2', '54', '94', '62', '91', '69', '69'), +('10', '2', '55', '95', '63', '93', '70', '70'), +('10', '2', '56', '97', '64', '95', '71', '71'), +('10', '2', '57', '99', '65', '96', '72', '72'), +('10', '2', '58', '101', '66', '98', '73', '73'), +('10', '2', '59', '102', '67', '100', '74', '74'), +('10', '2', '60', '104', '68', '101', '75', '76'), +('10', '2', '61', '106', '69', '103', '76', '77'), +('10', '2', '62', '108', '70', '105', '78', '78'), +('10', '2', '63', '110', '72', '106', '79', '79'), +('10', '2', '64', '112', '73', '108', '80', '80'), +('10', '2', '65', '113', '74', '110', '81', '82'), +('10', '2', '66', '115', '75', '112', '82', '83'), +('10', '2', '67', '117', '76', '114', '83', '84'), +('10', '2', '68', '119', '77', '115', '85', '85'), +('10', '2', '69', '121', '78', '117', '86', '87'), +('10', '2', '70', '123', '79', '119', '87', '88'), +('10', '2', '71', '125', '80', '120', '88', '89'), +('10', '2', '72', '128', '81', '123', '90', '91'), +('10', '2', '73', '130', '82', '125', '91', '93'), +('10', '2', '74', '133', '84', '127', '93', '94'), +('10', '2', '75', '135', '85', '129', '94', '96'), +('10', '2', '76', '137', '86', '132', '96', '97'), +('10', '2', '77', '140', '88', '134', '97', '99'), +('10', '2', '78', '143', '89', '136', '99', '101'), +('10', '2', '79', '145', '90', '139', '100', '102'), +('10', '2', '80', '148', '92', '141', '102', '104'), +('10', '3', '1', '17', '25', '20', '24', '20'), +('10', '3', '2', '17', '26', '21', '25', '21'), +('10', '3', '3', '18', '28', '22', '25', '21'), +('10', '3', '4', '18', '29', '23', '26', '22'), +('10', '3', '5', '19', '30', '24', '26', '23'), +('10', '3', '6', '19', '32', '25', '27', '23'), +('10', '3', '7', '20', '33', '26', '27', '24'), +('10', '3', '8', '20', '35', '27', '28', '25'), +('10', '3', '9', '21', '36', '27', '29', '25'), +('10', '3', '10', '21', '38', '28', '29', '26'), +('10', '3', '11', '22', '39', '29', '30', '27'), +('10', '3', '12', '22', '41', '30', '31', '27'), +('10', '3', '13', '23', '42', '31', '31', '28'), +('10', '3', '14', '23', '44', '32', '32', '29'), +('10', '3', '15', '24', '45', '34', '32', '29'), +('10', '3', '16', '24', '47', '35', '33', '30'), +('10', '3', '17', '25', '48', '36', '34', '31'), +('10', '3', '18', '25', '50', '37', '34', '32'), +('10', '3', '19', '26', '51', '38', '35', '32'), +('10', '3', '20', '26', '53', '39', '36', '33'), +('10', '3', '21', '27', '55', '40', '37', '34'), +('10', '3', '22', '27', '56', '41', '37', '35'), +('10', '3', '23', '28', '58', '42', '38', '36'), +('10', '3', '24', '28', '60', '43', '39', '36'), +('10', '3', '25', '29', '61', '44', '39', '37'), +('10', '3', '26', '30', '63', '46', '40', '38'), +('10', '3', '27', '30', '65', '47', '41', '39'), +('10', '3', '28', '31', '66', '48', '42', '40'), +('10', '3', '29', '31', '68', '49', '42', '40'), +('10', '3', '30', '32', '70', '50', '43', '41'), +('10', '3', '31', '33', '72', '52', '44', '42'), +('10', '3', '32', '33', '73', '53', '45', '43'), +('10', '3', '33', '34', '75', '54', '46', '44'), +('10', '3', '34', '34', '77', '55', '46', '45'), +('10', '3', '35', '35', '79', '57', '47', '46'), +('10', '3', '36', '36', '81', '58', '48', '47'), +('10', '3', '37', '36', '83', '59', '49', '47'), +('10', '3', '38', '37', '85', '60', '50', '48'), +('10', '3', '39', '38', '86', '62', '51', '49'), +('10', '3', '40', '38', '88', '63', '51', '50'), +('10', '3', '41', '39', '90', '64', '52', '51'), +('10', '3', '42', '40', '92', '66', '53', '52'), +('10', '3', '43', '40', '94', '67', '54', '53'), +('10', '3', '44', '41', '96', '68', '55', '54'), +('10', '3', '45', '42', '98', '70', '56', '55'), +('10', '3', '46', '42', '100', '71', '57', '56'), +('10', '3', '47', '43', '102', '72', '58', '57'), +('10', '3', '48', '44', '104', '74', '59', '58'), +('10', '3', '49', '45', '106', '75', '60', '59'), +('10', '3', '50', '45', '108', '77', '61', '60'), +('10', '3', '51', '46', '110', '78', '61', '61'), +('10', '3', '52', '47', '113', '79', '62', '62'), +('10', '3', '53', '47', '115', '81', '63', '63'), +('10', '3', '54', '48', '117', '82', '64', '64'), +('10', '3', '55', '49', '119', '84', '65', '65'), +('10', '3', '56', '50', '121', '85', '66', '66'), +('10', '3', '57', '50', '123', '87', '67', '67'), +('10', '3', '58', '51', '126', '88', '68', '68'), +('10', '3', '59', '52', '128', '90', '69', '70'), +('10', '3', '60', '53', '130', '91', '70', '71'), +('10', '3', '61', '54', '132', '93', '71', '72'), +('10', '3', '62', '54', '134', '94', '72', '73'), +('10', '3', '63', '55', '137', '96', '73', '74'), +('10', '3', '64', '56', '139', '97', '75', '75'), +('10', '3', '65', '57', '141', '99', '76', '76'), +('10', '3', '66', '58', '144', '101', '77', '77'), +('10', '3', '67', '58', '146', '102', '78', '78'), +('10', '3', '68', '59', '148', '104', '79', '80'), +('10', '3', '69', '60', '151', '105', '80', '81'), +('10', '3', '70', '61', '153', '107', '81', '82'), +('10', '3', '71', '62', '156', '108', '82', '83'), +('10', '3', '72', '63', '159', '110', '83', '84'), +('10', '3', '73', '64', '162', '112', '84', '86'), +('10', '3', '74', '65', '165', '114', '86', '87'), +('10', '3', '75', '66', '168', '116', '87', '89'), +('10', '3', '76', '67', '171', '118', '89', '90'), +('10', '3', '77', '68', '174', '120', '90', '92'), +('10', '3', '78', '69', '177', '122', '91', '93'), +('10', '3', '79', '70', '180', '124', '92', '95'), +('10', '3', '80', '71', '183', '126', '94', '96'), +('10', '4', '1', '18', '25', '20', '24', '19'), +('10', '4', '2', '19', '26', '21', '24', '19'), +('10', '4', '3', '20', '28', '21', '24', '20'), +('10', '4', '4', '20', '29', '22', '24', '20'), +('10', '4', '5', '21', '31', '23', '25', '20'), +('10', '4', '6', '22', '32', '24', '25', '21'), +('10', '4', '7', '23', '34', '24', '25', '21'), +('10', '4', '8', '24', '35', '25', '25', '22'), +('10', '4', '9', '24', '37', '26', '25', '22'), +('10', '4', '10', '25', '38', '26', '25', '22'), +('10', '4', '11', '26', '40', '27', '25', '23'), +('10', '4', '12', '27', '41', '28', '26', '23'), +('10', '4', '13', '28', '43', '29', '26', '24'), +('10', '4', '14', '29', '45', '30', '26', '24'), +('10', '4', '15', '29', '46', '30', '26', '25'), +('10', '4', '16', '30', '48', '31', '26', '25'), +('10', '4', '17', '31', '50', '32', '27', '25'), +('10', '4', '18', '32', '51', '33', '27', '26'), +('10', '4', '19', '33', '53', '34', '27', '26'), +('10', '4', '20', '34', '55', '35', '27', '27'), +('10', '4', '21', '35', '56', '35', '27', '27'), +('10', '4', '22', '36', '58', '36', '28', '28'), +('10', '4', '23', '37', '60', '37', '28', '28'), +('10', '4', '24', '38', '62', '38', '28', '29'), +('10', '4', '25', '39', '63', '39', '28', '29'), +('10', '4', '26', '40', '65', '40', '29', '30'), +('10', '4', '27', '41', '67', '41', '29', '30'), +('10', '4', '28', '42', '69', '42', '29', '31'), +('10', '4', '29', '43', '71', '43', '29', '31'), +('10', '4', '30', '44', '72', '43', '29', '32'), +('10', '4', '31', '45', '74', '44', '30', '32'), +('10', '4', '32', '46', '76', '45', '30', '33'), +('10', '4', '33', '47', '78', '46', '30', '33'), +('10', '4', '34', '48', '80', '47', '31', '34'), +('10', '4', '35', '49', '82', '48', '31', '34'), +('10', '4', '36', '50', '84', '49', '31', '35'), +('10', '4', '37', '51', '86', '50', '31', '35'), +('10', '4', '38', '52', '88', '51', '32', '36'), +('10', '4', '39', '53', '90', '52', '32', '37'), +('10', '4', '40', '54', '92', '53', '32', '37'), +('10', '4', '41', '56', '94', '54', '33', '38'), +('10', '4', '42', '57', '96', '55', '33', '38'), +('10', '4', '43', '58', '98', '56', '33', '39'), +('10', '4', '44', '59', '100', '57', '33', '39'), +('10', '4', '45', '60', '102', '59', '34', '40'), +('10', '4', '46', '61', '104', '60', '34', '41'), +('10', '4', '47', '62', '107', '61', '34', '41'), +('10', '4', '48', '64', '109', '62', '35', '42'), +('10', '4', '49', '65', '111', '63', '35', '43'), +('10', '4', '50', '66', '113', '64', '35', '43'), +('10', '4', '51', '67', '115', '65', '36', '44'), +('10', '4', '52', '68', '117', '66', '36', '44'), +('10', '4', '53', '70', '120', '67', '36', '45'), +('10', '4', '54', '71', '122', '69', '37', '46'), +('10', '4', '55', '72', '124', '70', '37', '46'), +('10', '4', '56', '73', '126', '71', '37', '47'), +('10', '4', '57', '75', '129', '72', '38', '48'), +('10', '4', '58', '76', '131', '73', '38', '48'), +('10', '4', '59', '77', '133', '74', '39', '49'), +('10', '4', '60', '79', '136', '76', '39', '50'), +('10', '4', '61', '80', '138', '77', '39', '51'), +('10', '4', '62', '81', '140', '78', '40', '51'), +('10', '4', '63', '82', '143', '79', '40', '52'), +('10', '4', '64', '84', '145', '80', '41', '53'), +('10', '4', '65', '85', '148', '82', '41', '53'), +('10', '4', '66', '87', '150', '83', '41', '54'), +('10', '4', '67', '88', '153', '84', '42', '55'), +('10', '4', '68', '89', '155', '85', '42', '56'), +('10', '4', '69', '91', '157', '87', '43', '56'), +('10', '4', '70', '92', '160', '88', '43', '57'), +('10', '4', '71', '94', '163', '88', '43', '58'), +('10', '4', '72', '96', '166', '90', '44', '58'), +('10', '4', '73', '97', '169', '92', '44', '59'), +('10', '4', '74', '99', '172', '93', '45', '60'), +('10', '4', '75', '101', '175', '95', '45', '61'), +('10', '4', '76', '102', '178', '96', '45', '62'), +('10', '4', '77', '104', '181', '101', '46', '63'), +('10', '4', '78', '106', '185', '104', '46', '64'), +('10', '4', '79', '108', '188', '105', '47', '65'), +('10', '4', '80', '110', '191', '107', '47', '66'), +('10', '5', '1', '17', '22', '19', '26', '22'), +('10', '5', '2', '17', '22', '19', '27', '23'), +('10', '5', '3', '17', '22', '20', '29', '25'), +('10', '5', '4', '17', '23', '20', '30', '26'), +('10', '5', '5', '18', '23', '20', '31', '27'), +('10', '5', '6', '18', '23', '21', '33', '29'), +('10', '5', '7', '18', '23', '21', '34', '30'), +('10', '5', '8', '18', '24', '22', '35', '32'), +('10', '5', '9', '18', '24', '22', '37', '33'), +('10', '5', '10', '19', '24', '22', '38', '35'), +('10', '5', '11', '19', '24', '23', '39', '36'), +('10', '5', '12', '19', '24', '23', '41', '38'), +('10', '5', '13', '19', '25', '24', '42', '39'), +('10', '5', '14', '19', '25', '24', '44', '41'), +('10', '5', '15', '19', '25', '25', '45', '42'), +('10', '5', '16', '20', '26', '25', '47', '44'), +('10', '5', '17', '20', '26', '25', '48', '45'), +('10', '5', '18', '20', '26', '26', '50', '47'), +('10', '5', '19', '20', '26', '26', '51', '49'), +('10', '5', '20', '21', '27', '27', '53', '50'), +('10', '5', '21', '21', '27', '27', '54', '52'), +('10', '5', '22', '21', '27', '28', '56', '53'), +('10', '5', '23', '21', '28', '28', '58', '55'), +('10', '5', '24', '21', '28', '29', '59', '57'), +('10', '5', '25', '22', '28', '29', '61', '58'), +('10', '5', '26', '22', '28', '30', '62', '60'), +('10', '5', '27', '22', '29', '30', '64', '62'), +('10', '5', '28', '22', '29', '31', '66', '64'), +('10', '5', '29', '23', '29', '31', '67', '65'), +('10', '5', '30', '23', '30', '32', '69', '67'), +('10', '5', '31', '23', '30', '32', '71', '69'), +('10', '5', '32', '23', '30', '33', '72', '71'), +('10', '5', '33', '24', '31', '33', '74', '72'), +('10', '5', '34', '24', '31', '34', '76', '74'), +('10', '5', '35', '24', '32', '34', '78', '76'), +('10', '5', '36', '24', '32', '35', '80', '78'), +('10', '5', '37', '25', '32', '35', '81', '80'), +('10', '5', '38', '25', '33', '36', '83', '82'), +('10', '5', '39', '25', '33', '37', '85', '84'), +('10', '5', '40', '26', '33', '37', '87', '86'), +('10', '5', '41', '26', '34', '38', '89', '88'), +('10', '5', '42', '26', '34', '38', '91', '89'), +('10', '5', '43', '27', '35', '39', '92', '91'), +('10', '5', '44', '27', '35', '39', '94', '93'), +('10', '5', '45', '27', '35', '40', '96', '95'), +('10', '5', '46', '27', '36', '41', '98', '97'), +('10', '5', '47', '28', '36', '41', '100', '99'), +('10', '5', '48', '28', '37', '42', '102', '101'), +('10', '5', '49', '28', '37', '43', '104', '103'), +('10', '5', '50', '29', '37', '43', '106', '106'), +('10', '5', '51', '29', '38', '44', '108', '108'), +('10', '5', '52', '29', '38', '44', '110', '110'), +('10', '5', '53', '30', '39', '45', '112', '112'), +('10', '5', '54', '30', '39', '46', '114', '114'), +('10', '5', '55', '30', '40', '46', '116', '116'), +('10', '5', '56', '31', '40', '47', '118', '118'), +('10', '5', '57', '31', '41', '48', '120', '120'), +('10', '5', '58', '31', '41', '48', '123', '123'), +('10', '5', '59', '32', '42', '49', '125', '125'), +('10', '5', '60', '32', '42', '50', '127', '127'), +('10', '5', '61', '33', '42', '51', '129', '129'), +('10', '5', '62', '33', '43', '51', '131', '131'), +('10', '5', '63', '33', '43', '52', '133', '134'), +('10', '5', '64', '34', '44', '53', '135', '136'), +('10', '5', '65', '34', '44', '53', '138', '138'), +('10', '5', '66', '34', '45', '54', '140', '141'), +('10', '5', '67', '35', '45', '55', '142', '143'), +('10', '5', '68', '35', '46', '56', '144', '145'), +('10', '5', '69', '36', '46', '56', '147', '148'), +('10', '5', '70', '36', '47', '57', '149', '150'), +('10', '5', '71', '36', '48', '57', '152', '153'), +('10', '5', '72', '37', '48', '57', '155', '156'), +('10', '5', '73', '37', '49', '58', '158', '159'), +('10', '5', '74', '38', '49', '59', '160', '163'), +('10', '5', '75', '38', '50', '60', '163', '165'), +('10', '5', '76', '38', '51', '61', '166', '170'), +('10', '5', '77', '39', '51', '62', '168', '175'), +('10', '5', '78', '39', '52', '63', '172', '174'), +('10', '5', '79', '40', '52', '64', '175', '177'), +('10', '5', '80', '40', '53', '65', '178', '180'), +('10', '6', '1', '18', '23', '21', '24', '20'), +('10', '6', '2', '19', '24', '22', '24', '20'), +('10', '6', '3', '21', '25', '23', '24', '21'), +('10', '6', '4', '22', '25', '25', '24', '21'), +('10', '6', '5', '23', '26', '26', '24', '21'), +('10', '6', '6', '25', '27', '27', '24', '21'), +('10', '6', '7', '26', '28', '28', '24', '22'), +('10', '6', '8', '27', '29', '29', '25', '22'), +('10', '6', '9', '29', '29', '31', '25', '22'), +('10', '6', '10', '30', '30', '32', '25', '23'), +('10', '6', '11', '32', '31', '33', '25', '23'), +('10', '6', '12', '33', '32', '34', '25', '23'), +('10', '6', '13', '34', '33', '36', '25', '24'), +('10', '6', '14', '36', '34', '37', '25', '24'), +('10', '6', '15', '37', '35', '38', '25', '24'), +('10', '6', '16', '39', '36', '40', '25', '25'), +('10', '6', '17', '40', '36', '41', '25', '25'), +('10', '6', '18', '42', '37', '43', '26', '25'), +('10', '6', '19', '43', '38', '44', '26', '26'), +('10', '6', '20', '45', '39', '45', '26', '26'), +('10', '6', '21', '47', '40', '47', '26', '26'), +('10', '6', '22', '48', '41', '48', '26', '27'), +('10', '6', '23', '50', '42', '50', '26', '27'), +('10', '6', '24', '51', '43', '51', '26', '28'), +('10', '6', '25', '53', '44', '52', '27', '28'), +('10', '6', '26', '55', '45', '54', '27', '28'), +('10', '6', '27', '56', '46', '55', '27', '29'), +('10', '6', '28', '58', '47', '57', '27', '29'), +('10', '6', '29', '59', '48', '58', '27', '30'), +('10', '6', '30', '61', '49', '60', '27', '30'), +('10', '6', '31', '63', '50', '62', '27', '30'), +('10', '6', '32', '65', '51', '63', '28', '31'), +('10', '6', '33', '66', '52', '65', '28', '31'), +('10', '6', '34', '68', '53', '66', '28', '32'), +('10', '6', '35', '70', '55', '68', '28', '32'), +('10', '6', '36', '72', '56', '69', '28', '33'), +('10', '6', '37', '73', '57', '71', '29', '33'), +('10', '6', '38', '75', '58', '73', '29', '34'), +('10', '6', '39', '77', '59', '74', '29', '34'), +('10', '6', '40', '79', '60', '76', '29', '35'), +('10', '6', '41', '81', '61', '78', '29', '35'), +('10', '6', '42', '82', '62', '79', '30', '35'), +('10', '6', '43', '84', '64', '81', '30', '36'), +('10', '6', '44', '86', '65', '83', '30', '36'), +('10', '6', '45', '88', '66', '85', '30', '37'), +('10', '6', '46', '90', '67', '86', '30', '37'), +('10', '6', '47', '92', '68', '88', '31', '38'), +('10', '6', '48', '94', '69', '90', '31', '38'), +('10', '6', '49', '96', '69', '92', '31', '39'), +('10', '6', '50', '98', '70', '93', '31', '40'), +('10', '6', '51', '100', '71', '95', '32', '40'), +('10', '6', '52', '102', '72', '96', '32', '41'), +('10', '6', '53', '103', '73', '97', '32', '41'), +('10', '6', '54', '104', '74', '98', '32', '41'), +('10', '6', '55', '105', '75', '97', '33', '41'), +('10', '6', '56', '108', '77', '100', '33', '42'), +('10', '6', '57', '113', '78', '102', '33', '42'), +('10', '6', '58', '115', '79', '104', '34', '43'), +('10', '6', '59', '117', '81', '106', '34', '43'), +('10', '6', '60', '118', '82', '108', '34', '44'), +('10', '6', '61', '119', '83', '110', '34', '45'), +('10', '6', '62', '121', '85', '112', '34', '45'), +('10', '6', '63', '124', '86', '115', '35', '46'), +('10', '6', '64', '127', '88', '117', '35', '46'), +('10', '6', '65', '133', '89', '119', '35', '47'), +('10', '6', '66', '135', '91', '122', '35', '48'), +('10', '6', '67', '139', '92', '124', '36', '48'), +('10', '6', '68', '141', '94', '126', '36', '49'), +('10', '6', '69', '142', '95', '129', '36', '50'), +('10', '6', '70', '145', '97', '131', '36', '50'), +('10', '6', '71', '150', '99', '134', '37', '51'), +('10', '6', '72', '152', '100', '136', '37', '52'), +('10', '6', '73', '155', '102', '139', '37', '53'), +('10', '6', '74', '158', '104', '141', '37', '53'), +('10', '6', '75', '159', '105', '144', '38', '54'), +('10', '6', '76', '160', '107', '147', '38', '55'), +('10', '6', '77', '163', '109', '149', '38', '56'), +('10', '6', '78', '166', '110', '152', '38', '56'), +('10', '6', '79', '169', '112', '155', '39', '57'), +('10', '6', '80', '172', '114', '158', '39', '58'), +('10', '8', '1', '17', '22', '19', '27', '21'), +('10', '8', '2', '17', '22', '19', '28', '22'), +('10', '8', '3', '17', '22', '20', '30', '24'), +('10', '8', '4', '17', '22', '20', '31', '25'), +('10', '8', '5', '17', '23', '20', '32', '26'), +('10', '8', '6', '17', '23', '20', '34', '28'), +('10', '8', '7', '18', '23', '21', '35', '29'), +('10', '8', '8', '18', '23', '21', '37', '30'), +('10', '8', '9', '18', '23', '21', '38', '32'), +('10', '8', '10', '18', '23', '22', '40', '33'), +('10', '8', '11', '18', '24', '22', '41', '35'), +('10', '8', '12', '18', '24', '22', '42', '36'), +('10', '8', '13', '18', '24', '23', '44', '37'), +('10', '8', '14', '18', '24', '23', '45', '39'), +('10', '8', '15', '18', '24', '23', '47', '40'), +('10', '8', '16', '19', '24', '24', '49', '42'), +('10', '8', '17', '19', '25', '24', '50', '43'), +('10', '8', '18', '19', '25', '24', '52', '45'), +('10', '8', '19', '19', '25', '25', '53', '46'), +('10', '8', '20', '19', '25', '25', '55', '48'), +('10', '8', '21', '19', '25', '26', '57', '50'), +('10', '8', '22', '19', '26', '26', '58', '51'), +('10', '8', '23', '20', '26', '26', '60', '53'), +('10', '8', '24', '20', '26', '27', '61', '54'), +('10', '8', '25', '20', '26', '27', '63', '56'), +('10', '8', '26', '20', '27', '27', '65', '58'), +('10', '8', '27', '20', '27', '28', '67', '59'), +('10', '8', '28', '20', '27', '28', '68', '61'), +('10', '8', '29', '21', '27', '29', '70', '63'), +('10', '8', '30', '21', '28', '29', '72', '64'), +('10', '8', '31', '21', '28', '30', '74', '66'), +('10', '8', '32', '21', '28', '30', '75', '68'), +('10', '8', '33', '21', '28', '30', '77', '70'), +('10', '8', '34', '21', '29', '31', '79', '71'), +('10', '8', '35', '22', '29', '31', '81', '73'), +('10', '8', '36', '22', '29', '32', '83', '75'), +('10', '8', '37', '22', '29', '32', '85', '77'), +('10', '8', '38', '22', '30', '33', '86', '78'), +('10', '8', '39', '22', '30', '33', '88', '80'), +('10', '8', '40', '23', '30', '34', '90', '82'), +('10', '8', '41', '23', '31', '34', '92', '84'), +('10', '8', '42', '23', '31', '35', '94', '86'), +('10', '8', '43', '23', '31', '35', '96', '88'), +('10', '8', '44', '23', '32', '36', '98', '90'), +('10', '8', '45', '24', '32', '36', '100', '92'), +('10', '8', '46', '24', '32', '37', '102', '93'), +('10', '8', '47', '24', '32', '37', '104', '95'), +('10', '8', '48', '24', '33', '38', '106', '97'), +('10', '8', '49', '25', '33', '38', '108', '99'), +('10', '8', '50', '25', '33', '39', '110', '101'), +('10', '8', '51', '25', '34', '39', '112', '103'), +('10', '8', '52', '25', '34', '40', '114', '105'), +('10', '8', '53', '25', '35', '40', '117', '107'), +('10', '8', '54', '26', '35', '41', '119', '109'), +('10', '8', '55', '26', '35', '41', '121', '111'), +('10', '8', '56', '26', '36', '42', '123', '113'), +('10', '8', '57', '26', '36', '42', '125', '116'), +('10', '8', '58', '27', '36', '43', '127', '118'), +('10', '8', '59', '27', '37', '43', '130', '120'), +('10', '8', '60', '27', '37', '44', '132', '122'), +('10', '8', '61', '27', '37', '45', '134', '124'), +('10', '8', '62', '28', '38', '45', '136', '126'), +('10', '8', '63', '28', '38', '46', '139', '128'), +('10', '8', '64', '28', '39', '46', '141', '131'), +('10', '8', '65', '29', '39', '47', '143', '133'), +('10', '8', '66', '29', '39', '48', '146', '135'), +('10', '8', '67', '29', '40', '48', '148', '137'), +('10', '8', '68', '29', '40', '49', '150', '139'), +('10', '8', '69', '30', '41', '49', '153', '142'), +('10', '8', '70', '30', '41', '50', '155', '144'), +('10', '8', '71', '30', '41', '50', '158', '147'), +('10', '8', '72', '30', '42', '51', '161', '150'), +('10', '8', '73', '30', '42', '52', '164', '153'), +('10', '8', '74', '31', '43', '52', '167', '155'), +('10', '8', '75', '31', '43', '53', '170', '158'), +('10', '8', '76', '31', '43', '54', '173', '161'), +('10', '8', '77', '32', '44', '55', '176', '164'), +('10', '8', '78', '32', '44', '55', '179', '167'), +('10', '8', '79', '32', '45', '56', '182', '170'), +('10', '8', '80', '33', '45', '57', '185', '173'), +('10', '9', '1', '17', '22', '20', '26', '21'), +('10', '9', '2', '17', '22', '21', '27', '22'), +('10', '9', '3', '18', '23', '21', '28', '23'), +('10', '9', '4', '18', '23', '22', '29', '24'), +('10', '9', '5', '18', '23', '22', '31', '26'), +('10', '9', '6', '18', '24', '23', '32', '27'), +('10', '9', '7', '19', '24', '23', '33', '28'), +('10', '9', '8', '19', '25', '24', '34', '29'), +('10', '9', '9', '19', '25', '25', '36', '30'), +('10', '9', '10', '20', '25', '25', '37', '32'), +('10', '9', '11', '20', '26', '26', '38', '33'), +('10', '9', '12', '20', '26', '26', '39', '34'), +('10', '9', '13', '21', '27', '27', '41', '36'), +('10', '9', '14', '21', '27', '28', '42', '37'), +('10', '9', '15', '21', '27', '28', '43', '38'), +('10', '9', '16', '22', '28', '29', '45', '39'), +('10', '9', '17', '22', '28', '30', '46', '41'), +('10', '9', '18', '23', '29', '30', '47', '42'), +('10', '9', '19', '23', '29', '31', '49', '43'), +('10', '9', '20', '23', '30', '32', '50', '45'), +('10', '9', '21', '24', '30', '32', '51', '46'), +('10', '9', '22', '24', '31', '33', '53', '48'), +('10', '9', '23', '24', '31', '34', '54', '49'), +('10', '9', '24', '25', '31', '34', '56', '50'), +('10', '9', '25', '25', '32', '35', '57', '52'), +('10', '9', '26', '26', '32', '36', '59', '53'), +('10', '9', '27', '26', '33', '37', '60', '55'), +('10', '9', '28', '26', '33', '37', '62', '56'), +('10', '9', '29', '27', '34', '38', '63', '58'), +('10', '9', '30', '27', '34', '39', '65', '59'), +('10', '9', '31', '28', '35', '40', '66', '61'), +('10', '9', '32', '28', '36', '40', '68', '62'), +('10', '9', '33', '29', '36', '41', '69', '64'), +('10', '9', '34', '29', '37', '42', '71', '65'), +('10', '9', '35', '29', '37', '43', '73', '67'), +('10', '9', '36', '30', '38', '43', '74', '69'), +('10', '9', '37', '30', '38', '44', '76', '70'), +('10', '9', '38', '31', '39', '45', '77', '72'), +('10', '9', '39', '31', '39', '46', '79', '73'), +('10', '9', '40', '32', '40', '47', '81', '75'), +('10', '9', '41', '32', '41', '48', '82', '77'), +('10', '9', '42', '33', '41', '48', '84', '78'), +('10', '9', '43', '33', '42', '49', '86', '80'), +('10', '9', '44', '34', '42', '50', '88', '82'), +('10', '9', '45', '34', '43', '51', '89', '83'), +('10', '9', '46', '35', '44', '52', '91', '85'), +('10', '9', '47', '35', '44', '53', '93', '87'), +('10', '9', '48', '36', '45', '54', '95', '89'), +('10', '9', '49', '36', '45', '54', '96', '90'), +('10', '9', '50', '37', '46', '55', '98', '92'), +('10', '9', '51', '37', '47', '56', '100', '94'), +('10', '9', '52', '38', '47', '57', '102', '96'), +('10', '9', '53', '38', '48', '58', '104', '97'), +('10', '9', '54', '39', '49', '59', '105', '99'), +('10', '9', '55', '39', '49', '60', '107', '101'), +('10', '9', '56', '40', '50', '61', '109', '103'), +('10', '9', '57', '40', '51', '62', '111', '105'), +('10', '9', '58', '41', '51', '63', '113', '107'), +('10', '9', '59', '42', '52', '64', '115', '108'), +('10', '9', '60', '42', '53', '65', '117', '110'), +('10', '9', '61', '43', '53', '66', '119', '112'), +('10', '9', '62', '43', '54', '67', '121', '114'), +('10', '9', '63', '44', '55', '68', '123', '116'), +('10', '9', '64', '44', '56', '69', '125', '118'), +('10', '9', '65', '45', '56', '70', '127', '120'), +('10', '9', '66', '46', '57', '71', '129', '122'), +('10', '9', '67', '46', '58', '72', '131', '124'), +('10', '9', '68', '47', '58', '73', '133', '126'), +('10', '9', '69', '47', '59', '74', '135', '128'), +('10', '9', '70', '48', '60', '75', '137', '130'), +('10', '9', '71', '49', '61', '83', '139', '141'), +('10', '9', '72', '50', '61', '84', '142', '143'), +('10', '9', '73', '51', '62', '84', '144', '146'), +('10', '9', '74', '51', '63', '86', '147', '149'), +('10', '9', '75', '52', '64', '89', '149', '151'), +('10', '9', '76', '53', '65', '90', '155', '154'), +('10', '9', '77', '54', '66', '91', '155', '157'), +('10', '9', '78', '54', '67', '93', '157', '160'), +('10', '9', '79', '55', '68', '94', '160', '163'), +('10', '9', '80', '56', '69', '95', '163', '165'), +('11', '1', '1', '24', '17', '21', '21', '22'), +('11', '1', '2', '25', '18', '22', '21', '22'), +('11', '1', '3', '27', '19', '23', '21', '23'), +('11', '1', '4', '28', '19', '25', '21', '23'), +('11', '1', '5', '29', '20', '26', '21', '23'), +('11', '1', '6', '31', '21', '27', '21', '23'), +('11', '1', '7', '32', '22', '28', '21', '24'), +('11', '1', '8', '33', '23', '29', '22', '24'), +('11', '1', '9', '35', '24', '31', '22', '24'), +('11', '1', '10', '36', '24', '32', '22', '25'), +('11', '1', '11', '37', '25', '33', '22', '25'), +('11', '1', '12', '39', '26', '34', '22', '25'), +('11', '1', '13', '40', '27', '36', '22', '26'), +('11', '1', '14', '42', '28', '37', '22', '26'), +('11', '1', '15', '43', '29', '38', '22', '26'), +('11', '1', '16', '45', '30', '40', '22', '27'), +('11', '1', '17', '46', '31', '41', '23', '27'), +('11', '1', '18', '48', '32', '43', '23', '27'), +('11', '1', '19', '49', '33', '44', '23', '28'), +('11', '1', '20', '51', '34', '45', '23', '28'), +('11', '1', '21', '52', '34', '47', '23', '28'), +('11', '1', '22', '54', '35', '48', '23', '29'), +('11', '1', '23', '55', '36', '50', '23', '29'), +('11', '1', '24', '57', '37', '51', '24', '30'), +('11', '1', '25', '59', '38', '52', '24', '30'), +('11', '1', '26', '60', '39', '54', '24', '30'), +('11', '1', '27', '62', '40', '55', '24', '31'), +('11', '1', '28', '63', '41', '57', '24', '31'), +('11', '1', '29', '65', '43', '58', '24', '32'), +('11', '1', '30', '67', '44', '60', '24', '32'), +('11', '1', '31', '69', '45', '62', '25', '32'), +('11', '1', '32', '70', '46', '63', '25', '33'), +('11', '1', '33', '72', '47', '65', '25', '33'), +('11', '1', '34', '74', '48', '66', '25', '34'), +('11', '1', '35', '75', '49', '68', '25', '34'), +('11', '1', '36', '77', '50', '69', '26', '35'), +('11', '1', '37', '79', '51', '71', '26', '35'), +('11', '1', '38', '81', '52', '73', '26', '35'), +('11', '1', '39', '83', '53', '74', '26', '36'), +('11', '1', '40', '84', '55', '76', '26', '36'), +('11', '1', '41', '86', '56', '78', '27', '37'), +('11', '1', '42', '88', '57', '79', '27', '37'), +('11', '1', '43', '90', '58', '81', '27', '38'), +('11', '1', '44', '92', '59', '83', '27', '38'), +('11', '1', '45', '94', '60', '85', '27', '39'), +('11', '1', '46', '96', '62', '86', '28', '39'), +('11', '1', '47', '98', '63', '88', '28', '40'), +('11', '1', '48', '100', '64', '90', '28', '40'), +('11', '1', '49', '102', '65', '92', '28', '41'), +('11', '1', '50', '103', '66', '93', '29', '41'), +('11', '1', '51', '105', '68', '95', '29', '42'), +('11', '1', '52', '107', '69', '97', '29', '42'), +('11', '1', '53', '109', '70', '99', '29', '43'), +('11', '1', '54', '112', '71', '101', '30', '44'), +('11', '1', '55', '114', '73', '103', '30', '44'), +('11', '1', '56', '116', '74', '104', '30', '45'), +('11', '1', '57', '118', '75', '106', '30', '45'), +('11', '1', '58', '120', '77', '108', '31', '46'), +('11', '1', '59', '122', '78', '110', '31', '46'), +('11', '1', '60', '124', '79', '112', '31', '47'), +('11', '1', '61', '126', '81', '114', '31', '48'), +('11', '1', '62', '128', '82', '116', '32', '48'), +('11', '1', '63', '130', '83', '118', '32', '49'), +('11', '1', '64', '133', '85', '120', '32', '49'), +('11', '1', '65', '135', '86', '122', '33', '50'), +('11', '1', '66', '137', '87', '124', '33', '51'), +('11', '1', '67', '139', '89', '126', '33', '51'), +('11', '1', '68', '141', '90', '128', '33', '52'), +('11', '1', '69', '144', '92', '130', '34', '52'), +('11', '1', '70', '146', '93', '132', '34', '53'), +('11', '1', '71', '149', '94', '134', '34', '54'), +('11', '1', '72', '151', '96', '137', '34', '55'), +('11', '1', '73', '154', '98', '139', '34', '56'), +('11', '1', '74', '157', '99', '142', '35', '56'), +('11', '1', '75', '166', '101', '149', '35', '57'), +('11', '1', '76', '172', '103', '155', '35', '58'), +('11', '1', '77', '175', '105', '159', '36', '59'), +('11', '1', '78', '179', '106', '161', '36', '59'), +('11', '1', '79', '182', '108', '164', '36', '60'), +('11', '1', '80', '185', '110', '167', '37', '61'), +('11', '2', '1', '23', '17', '21', '21', '23'), +('11', '2', '2', '24', '18', '22', '22', '24'), +('11', '2', '3', '25', '18', '23', '22', '24'), +('11', '2', '4', '26', '19', '24', '23', '25'), +('11', '2', '5', '27', '19', '25', '24', '26'), +('11', '2', '6', '29', '20', '26', '24', '26'), +('11', '2', '7', '30', '21', '27', '25', '27'), +('11', '2', '8', '31', '21', '28', '26', '28'), +('11', '2', '9', '32', '22', '29', '26', '29'), +('11', '2', '10', '33', '22', '31', '27', '29'), +('11', '2', '11', '34', '23', '32', '28', '30'), +('11', '2', '12', '36', '24', '33', '28', '31'), +('11', '2', '13', '37', '24', '34', '29', '32'), +('11', '2', '14', '38', '25', '35', '30', '32'), +('11', '2', '15', '39', '26', '36', '31', '33'), +('11', '2', '16', '40', '26', '37', '31', '34'), +('11', '2', '17', '42', '27', '39', '32', '35'), +('11', '2', '18', '43', '28', '40', '33', '36'), +('11', '2', '19', '44', '28', '41', '34', '37'), +('11', '2', '20', '46', '29', '42', '34', '37'), +('11', '2', '21', '47', '30', '44', '35', '38'), +('11', '2', '22', '48', '31', '45', '36', '39'), +('11', '2', '23', '50', '31', '46', '37', '40'), +('11', '2', '24', '51', '32', '47', '38', '41'), +('11', '2', '25', '52', '33', '49', '38', '42'), +('11', '2', '26', '54', '34', '50', '39', '43'), +('11', '2', '27', '55', '34', '51', '40', '44'), +('11', '2', '28', '56', '35', '53', '41', '44'), +('11', '2', '29', '58', '36', '54', '42', '45'), +('11', '2', '30', '59', '37', '55', '43', '46'), +('11', '2', '31', '61', '37', '57', '43', '47'), +('11', '2', '32', '62', '38', '58', '44', '48'), +('11', '2', '33', '64', '39', '59', '45', '49'), +('11', '2', '34', '65', '40', '61', '46', '50'), +('11', '2', '35', '67', '41', '62', '47', '51'), +('11', '2', '36', '68', '42', '64', '48', '52'), +('11', '2', '37', '70', '42', '65', '49', '53'), +('11', '2', '38', '71', '43', '67', '50', '54'), +('11', '2', '39', '73', '44', '68', '51', '55'), +('11', '2', '40', '74', '45', '69', '52', '56'), +('11', '2', '41', '76', '46', '71', '53', '57'), +('11', '2', '42', '78', '47', '72', '54', '58'), +('11', '2', '43', '79', '47', '74', '55', '59'), +('11', '2', '44', '81', '48', '75', '56', '60'), +('11', '2', '45', '82', '49', '77', '57', '61'), +('11', '2', '46', '84', '50', '78', '58', '62'), +('11', '2', '47', '86', '51', '80', '59', '64'), +('11', '2', '48', '87', '52', '82', '60', '65'), +('11', '2', '49', '89', '53', '83', '61', '66'), +('11', '2', '50', '91', '54', '85', '62', '67'), +('11', '2', '51', '92', '55', '86', '63', '68'), +('11', '2', '52', '94', '56', '88', '64', '69'), +('11', '2', '53', '96', '57', '90', '65', '70'), +('11', '2', '54', '97', '58', '91', '66', '71'), +('11', '2', '55', '99', '59', '93', '67', '73'), +('11', '2', '56', '101', '60', '95', '68', '74'), +('11', '2', '57', '103', '61', '96', '69', '75'), +('11', '2', '58', '105', '62', '98', '70', '76'), +('11', '2', '59', '106', '63', '100', '71', '77'), +('11', '2', '60', '108', '64', '101', '72', '78'), +('11', '2', '61', '110', '65', '103', '74', '80'), +('11', '2', '62', '112', '66', '105', '75', '81'), +('11', '2', '63', '114', '67', '106', '76', '82'), +('11', '2', '64', '116', '68', '108', '77', '83'), +('11', '2', '65', '117', '69', '110', '78', '85'), +('11', '2', '66', '119', '70', '112', '79', '86'), +('11', '2', '67', '121', '71', '114', '80', '87'), +('11', '2', '68', '123', '72', '115', '82', '88'), +('11', '2', '69', '125', '73', '117', '83', '90'), +('11', '2', '70', '127', '74', '119', '84', '91'), +('11', '2', '71', '130', '75', '121', '87', '92'), +('11', '2', '72', '132', '76', '124', '90', '94'), +('11', '2', '73', '134', '77', '126', '93', '96'), +('11', '2', '74', '137', '79', '128', '97', '97'), +('11', '2', '75', '139', '80', '130', '101', '99'), +('11', '2', '76', '142', '81', '133', '106', '100'), +('11', '2', '77', '144', '83', '135', '108', '102'), +('11', '2', '78', '147', '84', '137', '110', '104'), +('11', '2', '79', '149', '85', '140', '111', '105'), +('11', '2', '80', '152', '87', '142', '113', '107'), +('11', '3', '1', '21', '20', '20', '21', '23'), +('11', '3', '2', '21', '21', '21', '22', '24'), +('11', '3', '3', '22', '23', '22', '22', '24'), +('11', '3', '4', '22', '24', '23', '23', '25'), +('11', '3', '5', '23', '25', '24', '23', '25'), +('11', '3', '6', '23', '27', '25', '24', '26'), +('11', '3', '7', '24', '28', '26', '24', '27'), +('11', '3', '8', '24', '30', '27', '25', '27'), +('11', '3', '9', '25', '31', '27', '26', '28'), +('11', '3', '10', '25', '33', '28', '26', '29'), +('11', '3', '11', '25', '34', '29', '27', '29'), +('11', '3', '12', '26', '36', '30', '28', '30'), +('11', '3', '13', '26', '37', '31', '28', '31'), +('11', '3', '14', '27', '39', '32', '29', '32'), +('11', '3', '15', '27', '40', '34', '30', '32'), +('11', '3', '16', '28', '42', '35', '30', '33'), +('11', '3', '17', '28', '43', '36', '31', '34'), +('11', '3', '18', '29', '45', '37', '32', '35'), +('11', '3', '19', '29', '47', '38', '32', '35'), +('11', '3', '20', '30', '48', '39', '33', '36'), +('11', '3', '21', '31', '50', '40', '34', '37'), +('11', '3', '22', '31', '51', '41', '34', '38'), +('11', '3', '23', '32', '53', '42', '35', '38'), +('11', '3', '24', '32', '55', '43', '36', '39'), +('11', '3', '25', '33', '57', '44', '37', '40'), +('11', '3', '26', '33', '58', '46', '37', '41'), +('11', '3', '27', '34', '60', '47', '38', '42'), +('11', '3', '28', '35', '62', '48', '39', '42'), +('11', '3', '29', '35', '63', '49', '40', '43'), +('11', '3', '30', '36', '65', '50', '40', '44'), +('11', '3', '31', '36', '67', '52', '41', '45'), +('11', '3', '32', '37', '69', '53', '42', '46'), +('11', '3', '33', '38', '71', '54', '43', '47'), +('11', '3', '34', '38', '72', '55', '44', '48'), +('11', '3', '35', '39', '74', '57', '44', '48'), +('11', '3', '36', '39', '76', '58', '45', '49'), +('11', '3', '37', '40', '78', '59', '46', '50'), +('11', '3', '38', '41', '80', '60', '47', '51'), +('11', '3', '39', '41', '82', '62', '48', '52'), +('11', '3', '40', '42', '84', '63', '49', '53'), +('11', '3', '41', '43', '86', '64', '50', '54'), +('11', '3', '42', '43', '88', '66', '50', '55'), +('11', '3', '43', '44', '90', '67', '51', '56'), +('11', '3', '44', '45', '91', '68', '52', '57'), +('11', '3', '45', '45', '93', '70', '53', '58'), +('11', '3', '46', '46', '95', '71', '54', '59'), +('11', '3', '47', '47', '98', '72', '55', '60'), +('11', '3', '48', '48', '100', '74', '56', '61'), +('11', '3', '49', '48', '102', '75', '57', '62'), +('11', '3', '50', '49', '104', '77', '58', '63'), +('11', '3', '51', '50', '106', '78', '59', '64'), +('11', '3', '52', '51', '108', '79', '60', '65'), +('11', '3', '53', '51', '110', '81', '61', '66'), +('11', '3', '54', '52', '112', '82', '61', '67'), +('11', '3', '55', '53', '114', '84', '62', '68'), +('11', '3', '56', '54', '116', '85', '63', '69'), +('11', '3', '57', '54', '118', '87', '64', '70'), +('11', '3', '58', '55', '121', '88', '65', '71'), +('11', '3', '59', '56', '123', '90', '66', '72'), +('11', '3', '60', '57', '125', '91', '67', '74'), +('11', '3', '61', '58', '127', '93', '68', '75'), +('11', '3', '62', '58', '130', '94', '69', '76'), +('11', '3', '63', '59', '132', '96', '71', '77'), +('11', '3', '64', '60', '134', '97', '72', '78'), +('11', '3', '65', '61', '136', '99', '73', '79'), +('11', '3', '66', '62', '139', '101', '74', '80'), +('11', '3', '67', '62', '141', '102', '75', '81'), +('11', '3', '68', '63', '143', '104', '76', '83'), +('11', '3', '69', '64', '146', '105', '77', '84'), +('11', '3', '70', '65', '148', '107', '78', '85'), +('11', '3', '71', '66', '151', '109', '79', '86'), +('11', '3', '72', '67', '154', '111', '80', '87'), +('11', '3', '73', '68', '157', '113', '81', '89'), +('11', '3', '74', '69', '160', '115', '83', '90'), +('11', '3', '75', '70', '163', '117', '84', '92'), +('11', '3', '76', '71', '166', '119', '85', '93'), +('11', '3', '77', '72', '169', '121', '87', '95'), +('11', '3', '78', '73', '172', '123', '88', '96'), +('11', '3', '79', '74', '175', '125', '89', '98'), +('11', '3', '80', '75', '178', '127', '91', '99'), +('11', '5', '1', '21', '17', '19', '23', '25'), +('11', '5', '2', '21', '17', '19', '24', '26'), +('11', '5', '3', '21', '17', '20', '26', '28'), +('11', '5', '4', '21', '18', '20', '27', '29'), +('11', '5', '5', '22', '18', '20', '28', '30'), +('11', '5', '6', '22', '18', '21', '30', '32'), +('11', '5', '7', '22', '18', '21', '31', '33'), +('11', '5', '8', '22', '19', '22', '32', '35'), +('11', '5', '9', '22', '19', '22', '34', '36'), +('11', '5', '10', '22', '19', '22', '35', '38'), +('11', '5', '11', '23', '19', '23', '37', '39'), +('11', '5', '12', '23', '20', '23', '38', '41'), +('11', '5', '13', '23', '20', '24', '39', '42'), +('11', '5', '14', '23', '20', '24', '41', '44'), +('11', '5', '15', '23', '20', '25', '42', '45'), +('11', '5', '16', '24', '21', '25', '44', '47'), +('11', '5', '17', '24', '21', '25', '45', '48'), +('11', '5', '18', '24', '21', '26', '47', '50'), +('11', '5', '19', '24', '22', '26', '48', '51'), +('11', '5', '20', '24', '22', '27', '50', '53'), +('11', '5', '21', '25', '22', '27', '51', '55'), +('11', '5', '22', '25', '22', '28', '53', '56'), +('11', '5', '23', '25', '23', '28', '55', '58'), +('11', '5', '24', '25', '23', '29', '56', '60'), +('11', '5', '25', '25', '23', '29', '58', '61'), +('11', '5', '26', '26', '24', '30', '60', '63'), +('11', '5', '27', '26', '24', '30', '61', '65'), +('11', '5', '28', '26', '24', '31', '63', '66'), +('11', '5', '29', '26', '25', '31', '65', '68'), +('11', '5', '30', '27', '25', '32', '66', '70'), +('11', '5', '31', '27', '25', '32', '68', '72'), +('11', '5', '32', '27', '26', '33', '70', '73'), +('11', '5', '33', '27', '26', '33', '71', '75'), +('11', '5', '34', '28', '26', '34', '73', '77'), +('11', '5', '35', '28', '27', '34', '75', '79'), +('11', '5', '36', '28', '27', '35', '77', '81'), +('11', '5', '37', '29', '28', '35', '79', '83'), +('11', '5', '38', '29', '28', '36', '80', '85'), +('11', '5', '39', '29', '28', '37', '82', '86'), +('11', '5', '40', '29', '29', '37', '84', '88'), +('11', '5', '41', '30', '29', '38', '86', '90'), +('11', '5', '42', '30', '29', '38', '88', '92'), +('11', '5', '43', '30', '30', '39', '90', '94'), +('11', '5', '44', '31', '30', '39', '91', '96'), +('11', '5', '45', '31', '31', '40', '93', '98'), +('11', '5', '46', '31', '31', '41', '95', '100'), +('11', '5', '47', '32', '31', '41', '97', '102'), +('11', '5', '48', '32', '32', '42', '99', '104'), +('11', '5', '49', '32', '32', '43', '101', '106'), +('11', '5', '50', '33', '33', '43', '103', '108'), +('11', '5', '51', '33', '33', '44', '105', '110'), +('11', '5', '52', '33', '34', '44', '107', '113'), +('11', '5', '53', '34', '34', '45', '109', '115'), +('11', '5', '54', '34', '34', '46', '111', '117'), +('11', '5', '55', '34', '35', '46', '113', '119'), +('11', '5', '56', '35', '35', '47', '115', '121'), +('11', '5', '57', '35', '36', '48', '118', '123'), +('11', '5', '58', '35', '36', '48', '120', '126'), +('11', '5', '59', '36', '37', '49', '122', '128'), +('11', '5', '60', '36', '37', '50', '124', '130'), +('11', '5', '61', '36', '38', '51', '126', '132'), +('11', '5', '62', '37', '38', '51', '128', '134'), +('11', '5', '63', '37', '39', '52', '130', '137'), +('11', '5', '64', '38', '39', '53', '133', '139'), +('11', '5', '65', '38', '40', '53', '135', '141'), +('11', '5', '66', '38', '40', '54', '137', '144'), +('11', '5', '67', '39', '40', '55', '139', '146'), +('11', '5', '68', '39', '41', '56', '141', '148'), +('11', '5', '69', '40', '41', '56', '144', '151'), +('11', '5', '70', '40', '42', '57', '146', '153'), +('11', '5', '71', '40', '43', '58', '149', '156'), +('11', '5', '72', '41', '43', '58', '155', '159'), +('11', '5', '73', '41', '44', '59', '157', '160'), +('11', '5', '74', '42', '44', '61', '160', '163'), +('11', '5', '75', '42', '45', '62', '164', '166'), +('11', '5', '76', '42', '46', '62', '167', '169'), +('11', '5', '77', '43', '46', '63', '168', '172'), +('11', '5', '78', '43', '47', '64', '169', '177'), +('11', '5', '79', '44', '47', '65', '172', '180'), +('11', '5', '80', '44', '48', '66', '175', '183'), +('11', '6', '1', '24', '17', '21', '21', '22'), +('11', '6', '2', '25', '18', '22', '21', '22'), +('11', '6', '3', '27', '19', '23', '21', '23'), +('11', '6', '4', '28', '19', '25', '21', '23'), +('11', '6', '5', '29', '20', '26', '21', '23'), +('11', '6', '6', '31', '21', '27', '21', '23'), +('11', '6', '7', '32', '22', '28', '21', '24'), +('11', '6', '8', '33', '23', '29', '22', '24'), +('11', '6', '9', '35', '24', '31', '22', '24'), +('11', '6', '10', '36', '24', '32', '22', '25'), +('11', '6', '11', '37', '25', '33', '22', '25'), +('11', '6', '12', '39', '26', '34', '22', '25'), +('11', '6', '13', '40', '27', '36', '22', '26'), +('11', '6', '14', '42', '28', '37', '22', '26'), +('11', '6', '15', '43', '29', '38', '22', '26'), +('11', '6', '16', '45', '30', '40', '22', '27'), +('11', '6', '17', '46', '31', '41', '23', '27'), +('11', '6', '18', '48', '32', '43', '23', '27'), +('11', '6', '19', '49', '33', '44', '23', '28'), +('11', '6', '20', '51', '34', '45', '23', '28'), +('11', '6', '21', '52', '34', '47', '23', '28'), +('11', '6', '22', '54', '35', '48', '23', '29'), +('11', '6', '23', '55', '36', '50', '23', '29'), +('11', '6', '24', '57', '37', '51', '24', '30'), +('11', '6', '25', '59', '38', '52', '24', '30'), +('11', '6', '26', '60', '39', '54', '24', '30'), +('11', '6', '27', '62', '40', '55', '24', '31'), +('11', '6', '28', '63', '41', '57', '24', '31'), +('11', '6', '29', '65', '43', '58', '24', '32'), +('11', '6', '30', '67', '44', '60', '24', '32'), +('11', '6', '31', '69', '45', '62', '25', '32'), +('11', '6', '32', '70', '46', '63', '25', '33'), +('11', '6', '33', '72', '47', '65', '25', '33'), +('11', '6', '34', '74', '48', '66', '25', '34'), +('11', '6', '35', '75', '49', '68', '25', '34'), +('11', '6', '36', '77', '50', '69', '26', '35'), +('11', '6', '37', '79', '51', '71', '26', '35'), +('11', '6', '38', '81', '52', '73', '26', '35'), +('11', '6', '39', '83', '53', '74', '26', '36'), +('11', '6', '40', '84', '55', '76', '26', '36'), +('11', '6', '41', '86', '56', '78', '27', '37'), +('11', '6', '42', '88', '57', '79', '27', '37'), +('11', '6', '43', '90', '58', '81', '27', '38'), +('11', '6', '44', '92', '59', '83', '27', '38'), +('11', '6', '45', '94', '60', '85', '27', '39'), +('11', '6', '46', '96', '62', '86', '28', '39'), +('11', '6', '47', '98', '63', '88', '28', '40'), +('11', '6', '48', '100', '64', '90', '28', '40'), +('11', '6', '49', '102', '65', '92', '28', '41'), +('11', '6', '50', '103', '65', '93', '29', '41'), +('11', '6', '51', '105', '66', '94', '29', '42'), +('11', '6', '52', '106', '67', '95', '29', '42'), +('11', '6', '53', '107', '68', '96', '29', '43'), +('11', '6', '54', '108', '69', '97', '30', '44'), +('11', '6', '55', '109', '70', '98', '30', '44'), +('11', '6', '56', '112', '72', '101', '30', '45'), +('11', '6', '57', '114', '73', '103', '30', '45'), +('11', '6', '58', '117', '74', '105', '31', '46'), +('11', '6', '59', '119', '76', '107', '31', '46'), +('11', '6', '60', '121', '77', '109', '31', '47'), +('11', '6', '61', '123', '78', '111', '31', '48'), +('11', '6', '62', '126', '80', '113', '31', '48'), +('11', '6', '63', '128', '81', '116', '32', '49'), +('11', '6', '64', '131', '83', '118', '32', '49'), +('11', '6', '65', '136', '84', '120', '32', '50'), +('11', '6', '66', '140', '86', '123', '32', '51'), +('11', '6', '67', '141', '87', '125', '33', '51'), +('11', '6', '68', '141', '89', '127', '33', '52'), +('11', '6', '69', '144', '90', '130', '33', '53'), +('11', '6', '70', '147', '92', '132', '33', '53'), +('11', '6', '71', '150', '94', '135', '34', '54'), +('11', '6', '72', '152', '95', '137', '34', '55'), +('11', '6', '73', '155', '97', '140', '34', '56'), +('11', '6', '74', '162', '99', '142', '34', '56'), +('11', '6', '75', '165', '100', '145', '35', '57'), +('11', '6', '76', '167', '102', '146', '35', '58'), +('11', '6', '77', '169', '104', '150', '35', '59'), +('11', '6', '78', '170', '105', '152', '35', '59'), +('11', '6', '79', '173', '107', '156', '36', '60'), +('11', '6', '80', '176', '109', '159', '36', '61'), +('11', '7', '1', '22', '17', '20', '22', '24'), +('11', '7', '2', '23', '17', '21', '23', '25'), +('11', '7', '3', '24', '18', '22', '24', '26'), +('11', '7', '4', '25', '18', '23', '25', '27'), +('11', '7', '5', '25', '19', '24', '26', '28'), +('11', '7', '6', '26', '19', '25', '27', '29'), +('11', '7', '7', '27', '20', '26', '28', '30'), +('11', '7', '8', '28', '20', '27', '28', '31'), +('11', '7', '9', '29', '21', '28', '29', '32'), +('11', '7', '10', '30', '21', '29', '30', '33'), +('11', '7', '11', '31', '22', '30', '31', '35'), +('11', '7', '12', '32', '22', '31', '32', '36'), +('11', '7', '13', '33', '23', '32', '33', '37'), +('11', '7', '14', '34', '23', '33', '34', '38'), +('11', '7', '15', '34', '24', '35', '35', '39'), +('11', '7', '16', '35', '24', '36', '36', '40'), +('11', '7', '17', '36', '25', '37', '38', '42'), +('11', '7', '18', '37', '25', '38', '39', '43'), +('11', '7', '19', '38', '26', '39', '40', '44'), +('11', '7', '20', '39', '26', '40', '41', '45'), +('11', '7', '21', '40', '27', '41', '42', '46'), +('11', '7', '22', '41', '27', '43', '43', '48'), +('11', '7', '23', '43', '28', '44', '44', '49'), +('11', '7', '24', '44', '28', '45', '45', '50'), +('11', '7', '25', '45', '29', '46', '46', '51'), +('11', '7', '26', '46', '30', '47', '48', '53'), +('11', '7', '27', '47', '30', '49', '49', '54'), +('11', '7', '28', '48', '31', '50', '50', '55'), +('11', '7', '29', '49', '31', '51', '51', '57'), +('11', '7', '30', '50', '32', '53', '52', '58'), +('11', '7', '31', '51', '33', '54', '53', '59'), +('11', '7', '32', '52', '33', '55', '55', '61'), +('11', '7', '33', '53', '34', '56', '56', '62'), +('11', '7', '34', '55', '34', '58', '57', '64'), +('11', '7', '35', '56', '35', '59', '58', '65'), +('11', '7', '36', '57', '36', '60', '60', '66'), +('11', '7', '37', '58', '36', '62', '61', '68'), +('11', '7', '38', '59', '37', '63', '62', '69'), +('11', '7', '39', '61', '38', '65', '63', '71'), +('11', '7', '40', '62', '38', '66', '65', '72'), +('11', '7', '41', '63', '39', '67', '66', '74'), +('11', '7', '42', '64', '40', '69', '67', '75'), +('11', '7', '43', '65', '40', '70', '69', '77'), +('11', '7', '44', '67', '41', '72', '70', '78'), +('11', '7', '45', '68', '42', '73', '71', '80'), +('11', '7', '46', '69', '42', '75', '73', '81'), +('11', '7', '47', '71', '43', '76', '74', '83'), +('11', '7', '48', '72', '44', '78', '76', '84'), +('11', '7', '49', '73', '45', '79', '77', '86'), +('11', '7', '50', '74', '45', '81', '78', '88'), +('11', '7', '51', '76', '46', '82', '80', '89'), +('11', '7', '52', '77', '47', '84', '81', '91'), +('11', '7', '53', '78', '47', '85', '83', '92'), +('11', '7', '54', '80', '48', '87', '84', '94'), +('11', '7', '55', '81', '49', '88', '86', '96'), +('11', '7', '56', '83', '50', '90', '87', '97'), +('11', '7', '57', '84', '50', '91', '89', '99'), +('11', '7', '58', '85', '51', '93', '90', '101'), +('11', '7', '59', '87', '52', '95', '92', '102'), +('11', '7', '60', '88', '53', '96', '93', '104'), +('11', '7', '61', '90', '54', '98', '95', '106'), +('11', '7', '62', '91', '54', '99', '96', '108'), +('11', '7', '63', '93', '55', '101', '98', '109'), +('11', '7', '64', '94', '56', '103', '99', '111'), +('11', '7', '65', '95', '57', '104', '101', '113'), +('11', '7', '66', '97', '58', '106', '103', '115'), +('11', '7', '67', '98', '58', '108', '104', '117'), +('11', '7', '68', '100', '59', '110', '106', '118'), +('11', '7', '69', '101', '60', '111', '107', '120'), +('11', '7', '70', '103', '61', '113', '109', '122'), +('11', '7', '71', '104', '62', '115', '122', '124'), +('11', '7', '72', '106', '63', '117', '124', '127'), +('11', '7', '73', '108', '64', '119', '126', '129'), +('11', '7', '74', '110', '65', '122', '128', '131'), +('11', '7', '75', '112', '66', '124', '130', '133'), +('11', '7', '76', '114', '67', '126', '133', '136'), +('11', '7', '77', '115', '68', '128', '135', '138'), +('11', '7', '78', '117', '69', '130', '137', '140'), +('11', '7', '79', '119', '70', '133', '139', '143'), +('11', '7', '80', '121', '71', '135', '141', '145'), +('11', '8', '1', '21', '17', '19', '24', '24'), +('11', '8', '2', '21', '17', '19', '25', '25'), +('11', '8', '3', '21', '17', '20', '27', '27'), +('11', '8', '4', '21', '17', '20', '28', '28'), +('11', '8', '5', '21', '18', '20', '29', '29'), +('11', '8', '6', '21', '18', '20', '31', '31'), +('11', '8', '7', '21', '18', '21', '32', '32'), +('11', '8', '8', '22', '18', '21', '34', '33'), +('11', '8', '9', '22', '18', '21', '35', '35'), +('11', '8', '10', '22', '19', '22', '37', '36'), +('11', '8', '11', '22', '19', '22', '38', '37'), +('11', '8', '12', '22', '19', '22', '40', '39'), +('11', '8', '13', '22', '19', '23', '41', '40'), +('11', '8', '14', '22', '19', '23', '43', '42'), +('11', '8', '15', '22', '19', '23', '44', '43'), +('11', '8', '16', '22', '20', '24', '46', '45'), +('11', '8', '17', '23', '20', '24', '47', '46'), +('11', '8', '18', '23', '20', '24', '49', '48'), +('11', '8', '19', '23', '20', '25', '50', '49'), +('11', '8', '20', '23', '21', '25', '52', '51'), +('11', '8', '21', '23', '21', '26', '54', '52'), +('11', '8', '22', '23', '21', '26', '55', '54'), +('11', '8', '23', '23', '21', '26', '57', '56'), +('11', '8', '24', '24', '21', '27', '59', '57'), +('11', '8', '25', '24', '22', '27', '60', '59'), +('11', '8', '26', '24', '22', '27', '62', '60'), +('11', '8', '27', '24', '22', '28', '64', '62'), +('11', '8', '28', '24', '22', '28', '65', '64'), +('11', '8', '29', '24', '23', '29', '67', '65'), +('11', '8', '30', '24', '23', '29', '69', '67'), +('11', '8', '31', '25', '23', '30', '71', '69'), +('11', '8', '32', '25', '23', '30', '73', '71'), +('11', '8', '33', '25', '24', '30', '74', '72'), +('11', '8', '34', '25', '24', '31', '76', '74'), +('11', '8', '35', '25', '24', '31', '78', '76'), +('11', '8', '36', '26', '24', '32', '80', '78'), +('11', '8', '37', '26', '25', '32', '82', '79'), +('11', '8', '38', '26', '25', '33', '84', '81'), +('11', '8', '39', '26', '25', '33', '86', '83'), +('11', '8', '40', '26', '26', '34', '87', '85'), +('11', '8', '41', '27', '26', '34', '89', '87'), +('11', '8', '42', '27', '26', '35', '91', '89'), +('11', '8', '43', '27', '27', '35', '93', '91'), +('11', '8', '44', '27', '27', '36', '95', '92'), +('11', '8', '45', '27', '27', '36', '97', '94'), +('11', '8', '46', '28', '27', '37', '99', '96'), +('11', '8', '47', '28', '28', '37', '101', '98'), +('11', '8', '48', '28', '28', '38', '103', '100'), +('11', '8', '49', '28', '28', '38', '105', '102'), +('11', '8', '50', '29', '29', '39', '107', '104'), +('11', '8', '51', '29', '29', '39', '110', '106'), +('11', '8', '52', '29', '29', '40', '112', '108'), +('11', '8', '53', '29', '30', '40', '114', '110'), +('11', '8', '54', '30', '30', '41', '116', '112'), +('11', '8', '55', '30', '30', '41', '118', '114'), +('11', '8', '56', '30', '31', '42', '120', '116'), +('11', '8', '57', '30', '31', '42', '122', '118'), +('11', '8', '58', '31', '31', '43', '125', '121'), +('11', '8', '59', '31', '32', '43', '127', '123'), +('11', '8', '60', '31', '32', '44', '129', '125'), +('11', '8', '61', '31', '33', '45', '131', '127'), +('11', '8', '62', '32', '33', '45', '133', '129'), +('11', '8', '63', '32', '33', '46', '136', '131'), +('11', '8', '64', '32', '34', '46', '138', '134'), +('11', '8', '65', '33', '34', '47', '140', '136'), +('11', '8', '66', '33', '34', '48', '143', '138'), +('11', '8', '67', '33', '35', '48', '145', '140'), +('11', '8', '68', '33', '35', '49', '147', '142'), +('11', '8', '69', '34', '36', '49', '150', '145'), +('11', '8', '70', '34', '36', '50', '152', '147'), +('11', '8', '71', '34', '36', '51', '155', '150'), +('11', '8', '72', '34', '37', '52', '161', '153'), +('11', '8', '73', '34', '37', '53', '161', '156'), +('11', '8', '74', '35', '38', '53', '164', '158'), +('11', '8', '75', '35', '38', '54', '167', '161'), +('11', '8', '76', '35', '38', '55', '170', '164'), +('11', '8', '77', '36', '39', '56', '173', '167'), +('11', '8', '78', '36', '39', '56', '176', '170'), +('11', '8', '79', '36', '40', '57', '179', '173'), +('11', '8', '80', '37', '40', '58', '182', '176'), +('11', '4', '1', '24', '20', '23', '17', '23'), +('11', '4', '2', '25', '21', '24', '17', '23'), +('11', '4', '3', '25', '23', '24', '17', '24'), +('11', '4', '4', '26', '24', '25', '17', '24'), +('11', '4', '5', '27', '26', '26', '18', '24'), +('11', '4', '6', '28', '27', '26', '18', '25'), +('11', '4', '7', '29', '29', '27', '18', '25'), +('11', '4', '8', '29', '30', '28', '18', '26'), +('11', '4', '9', '30', '32', '29', '18', '26'), +('11', '4', '10', '31', '33', '29', '19', '26'), +('11', '4', '11', '32', '35', '30', '19', '27'), +('11', '4', '12', '33', '37', '31', '19', '27'), +('11', '4', '13', '34', '38', '32', '19', '28'), +('11', '4', '14', '34', '40', '32', '19', '28'), +('11', '4', '15', '35', '41', '33', '19', '28'), +('11', '4', '16', '36', '43', '34', '20', '29'), +('11', '4', '17', '37', '45', '35', '20', '29'), +('11', '4', '18', '38', '46', '36', '20', '30'), +('11', '4', '19', '39', '48', '37', '20', '30'), +('11', '4', '20', '40', '50', '37', '21', '31'), +('11', '4', '21', '41', '52', '38', '21', '31'), +('11', '4', '22', '42', '53', '39', '21', '31'), +('11', '4', '23', '43', '55', '40', '21', '32'), +('11', '4', '24', '43', '57', '41', '21', '32'), +('11', '4', '25', '44', '59', '42', '22', '33'), +('11', '4', '26', '45', '60', '43', '22', '33'), +('11', '4', '27', '46', '62', '44', '22', '34'), +('11', '4', '28', '47', '64', '44', '22', '34'), +('11', '4', '29', '48', '66', '45', '23', '35'), +('11', '4', '30', '49', '68', '46', '23', '35'), +('11', '4', '31', '50', '70', '47', '23', '36'), +('11', '4', '32', '51', '72', '48', '23', '36'), +('11', '4', '33', '53', '73', '49', '24', '37'), +('11', '4', '34', '54', '75', '50', '24', '38'), +('11', '4', '35', '55', '77', '51', '24', '38'), +('11', '4', '36', '56', '79', '52', '24', '39'), +('11', '4', '37', '57', '81', '53', '25', '39'), +('11', '4', '38', '58', '83', '54', '25', '40'), +('11', '4', '39', '59', '85', '55', '25', '40'), +('11', '4', '40', '60', '87', '56', '26', '41'), +('11', '4', '41', '61', '89', '57', '26', '41'), +('11', '4', '42', '62', '91', '58', '26', '42'), +('11', '4', '43', '63', '93', '59', '27', '43'), +('11', '4', '44', '65', '95', '60', '27', '43'), +('11', '4', '45', '66', '98', '61', '27', '44'), +('11', '4', '46', '67', '100', '62', '27', '44'), +('11', '4', '47', '68', '102', '64', '28', '45'), +('11', '4', '48', '69', '104', '65', '28', '46'), +('11', '4', '49', '71', '106', '66', '28', '46'), +('11', '4', '50', '72', '108', '67', '29', '47'), +('11', '4', '51', '73', '110', '68', '29', '48'), +('11', '4', '52', '74', '113', '69', '29', '48'), +('11', '4', '53', '75', '115', '70', '30', '49'), +('11', '4', '54', '77', '117', '71', '30', '50'), +('11', '4', '55', '78', '119', '73', '30', '50'), +('11', '4', '56', '79', '122', '74', '31', '51'), +('11', '4', '57', '80', '124', '75', '31', '52'), +('11', '4', '58', '82', '126', '76', '31', '52'), +('11', '4', '59', '83', '129', '77', '32', '53'), +('11', '4', '60', '84', '131', '78', '32', '54'), +('11', '4', '61', '86', '133', '80', '33', '54'), +('11', '4', '62', '87', '136', '81', '33', '55'), +('11', '4', '63', '88', '138', '82', '33', '56'), +('11', '4', '64', '90', '140', '83', '34', '57'), +('11', '4', '65', '91', '143', '85', '34', '57'), +('11', '4', '66', '92', '145', '86', '34', '58'), +('11', '4', '67', '94', '148', '87', '35', '59'), +('11', '4', '68', '95', '150', '88', '35', '59'), +('11', '4', '69', '97', '153', '90', '36', '60'), +('11', '4', '70', '98', '155', '91', '36', '61'), +('11', '4', '71', '100', '158', '92', '36', '62'), +('11', '4', '72', '102', '161', '94', '37', '62'), +('11', '4', '73', '103', '164', '99', '37', '63'), +('11', '4', '74', '105', '167', '100', '38', '64'), +('11', '4', '75', '107', '170', '102', '38', '65'), +('11', '4', '76', '108', '173', '102', '38', '66'), +('11', '4', '77', '110', '176', '102', '39', '67'), +('11', '4', '78', '112', '180', '103', '39', '68'), +('11', '4', '79', '114', '183', '105', '40', '69'), +('11', '4', '80', '116', '186', '107', '40', '70'), +('11', '9', '1', '20', '20', '21', '22', '22'), +('11', '9', '2', '20', '20', '22', '23', '23'), +('11', '9', '3', '21', '21', '22', '24', '24'), +('11', '9', '4', '21', '21', '23', '26', '25'), +('11', '9', '5', '21', '21', '23', '27', '27'), +('11', '9', '6', '21', '22', '24', '28', '28'), +('11', '9', '7', '22', '22', '24', '29', '29'), +('11', '9', '8', '22', '23', '25', '30', '30'), +('11', '9', '9', '22', '23', '26', '32', '31'), +('11', '9', '10', '23', '23', '26', '33', '33'), +('11', '9', '11', '23', '24', '27', '34', '34'), +('11', '9', '12', '23', '24', '27', '35', '35'), +('11', '9', '13', '24', '25', '28', '37', '36'), +('11', '9', '14', '24', '25', '29', '38', '38'), +('11', '9', '15', '24', '25', '29', '39', '39'), +('11', '9', '16', '25', '26', '30', '41', '40'), +('11', '9', '17', '25', '26', '31', '42', '42'), +('11', '9', '18', '25', '27', '31', '43', '43'), +('11', '9', '19', '26', '27', '32', '45', '44'), +('11', '9', '20', '26', '28', '33', '46', '46'), +('11', '9', '21', '26', '28', '33', '48', '47'), +('11', '9', '22', '27', '29', '34', '49', '49'), +('11', '9', '23', '27', '29', '35', '51', '50'), +('11', '9', '24', '28', '30', '35', '52', '51'), +('11', '9', '25', '28', '30', '36', '53', '53'), +('11', '9', '26', '28', '31', '37', '55', '54'), +('11', '9', '27', '29', '31', '37', '56', '56'), +('11', '9', '28', '29', '32', '38', '58', '57'), +('11', '9', '29', '30', '32', '39', '59', '59'), +('11', '9', '30', '30', '33', '40', '61', '60'), +('11', '9', '31', '30', '33', '40', '62', '62'), +('11', '9', '32', '31', '34', '41', '64', '63'), +('11', '9', '33', '31', '34', '42', '66', '65'), +('11', '9', '34', '32', '35', '43', '67', '66'), +('11', '9', '35', '32', '35', '44', '69', '68'), +('11', '9', '36', '33', '36', '44', '70', '69'), +('11', '9', '37', '33', '36', '45', '72', '71'), +('11', '9', '38', '34', '37', '46', '74', '73'), +('11', '9', '39', '34', '38', '47', '75', '74'), +('11', '9', '40', '35', '38', '48', '77', '76'), +('11', '9', '41', '35', '39', '48', '79', '78'), +('11', '9', '42', '35', '39', '49', '80', '79'), +('11', '9', '43', '36', '40', '50', '82', '81'), +('11', '9', '44', '36', '40', '51', '84', '83'), +('11', '9', '45', '37', '41', '52', '85', '84'), +('11', '9', '46', '37', '42', '53', '87', '86'), +('11', '9', '47', '38', '42', '54', '89', '88'), +('11', '9', '48', '38', '43', '55', '91', '89'), +('11', '9', '49', '39', '44', '55', '93', '91'), +('11', '9', '50', '40', '44', '56', '94', '93'), +('11', '9', '51', '40', '45', '57', '96', '95'), +('11', '9', '52', '41', '45', '58', '98', '97'), +('11', '9', '53', '41', '46', '59', '100', '98'), +('11', '9', '54', '42', '47', '60', '102', '100'), +('11', '9', '55', '42', '47', '61', '103', '102'), +('11', '9', '56', '43', '48', '62', '105', '104'), +('11', '9', '57', '43', '49', '63', '107', '106'), +('11', '9', '58', '44', '49', '64', '109', '108'), +('11', '9', '59', '44', '50', '65', '111', '109'), +('11', '9', '60', '45', '51', '66', '113', '111'), +('11', '9', '61', '46', '51', '67', '115', '113'), +('11', '9', '62', '46', '52', '68', '117', '115'), +('11', '9', '63', '47', '53', '69', '119', '117'), +('11', '9', '64', '47', '54', '70', '121', '119'), +('11', '9', '65', '48', '54', '71', '123', '121'), +('11', '9', '66', '49', '55', '72', '125', '123'), +('11', '9', '67', '49', '56', '73', '127', '125'), +('11', '9', '68', '50', '57', '74', '129', '127'), +('11', '9', '69', '50', '57', '75', '131', '129'), +('11', '9', '70', '51', '58', '76', '133', '131'), +('11', '9', '71', '52', '59', '78', '135', '146'), +('11', '9', '72', '53', '59', '79', '138', '148'), +('11', '9', '73', '54', '60', '80', '140', '151'), +('11', '9', '74', '54', '61', '89', '143', '154'), +('11', '9', '75', '55', '62', '91', '145', '156'), +('11', '9', '76', '56', '63', '92', '148', '159'), +('11', '9', '77', '57', '64', '93', '151', '162'), +('11', '9', '78', '57', '65', '95', '153', '165'), +('11', '9', '79', '58', '66', '96', '156', '168'), +('11', '9', '80', '59', '67', '97', '159', '170'), +('11', '11', '1', '26', '15', '22', '17', '24'), +('11', '11', '2', '27', '16', '23', '18', '25'), +('11', '11', '3', '27', '16', '23', '19', '26'), +('11', '11', '4', '28', '17', '24', '20', '27'), +('11', '11', '5', '28', '17', '25', '21', '29'), +('11', '11', '6', '29', '18', '25', '22', '30'), +('11', '11', '7', '29', '18', '26', '23', '31'), +('11', '11', '8', '30', '19', '27', '24', '32'), +('11', '11', '9', '30', '19', '27', '26', '34'), +('11', '11', '10', '31', '20', '28', '27', '35'), +('11', '11', '11', '32', '20', '29', '28', '36'), +('11', '11', '12', '32', '21', '29', '29', '37'), +('11', '11', '13', '33', '21', '30', '30', '39'), +('11', '11', '14', '33', '22', '31', '31', '40'), +('11', '11', '15', '34', '23', '32', '32', '41'), +('11', '11', '16', '35', '23', '32', '34', '43'), +('11', '11', '17', '35', '24', '33', '35', '44'), +('11', '11', '18', '36', '24', '34', '36', '45'), +('11', '11', '19', '37', '25', '35', '37', '47'), +('11', '11', '20', '37', '26', '35', '39', '48'), +('11', '11', '21', '38', '26', '36', '40', '50'), +('11', '11', '22', '39', '27', '37', '41', '51'), +('11', '11', '23', '39', '28', '38', '42', '52'), +('11', '11', '24', '40', '28', '39', '44', '54'), +('11', '11', '25', '41', '29', '39', '45', '55'), +('11', '11', '26', '41', '30', '40', '46', '57'), +('11', '11', '27', '42', '30', '41', '47', '58'), +('11', '11', '28', '43', '31', '42', '49', '60'), +('11', '11', '29', '44', '32', '43', '50', '61'), +('11', '11', '30', '44', '32', '44', '52', '63'), +('11', '11', '31', '45', '33', '44', '53', '64'), +('11', '11', '32', '46', '34', '45', '54', '66'), +('11', '11', '33', '47', '34', '46', '56', '67'), +('11', '11', '34', '47', '35', '47', '57', '69'), +('11', '11', '35', '48', '36', '48', '58', '71'), +('11', '11', '36', '49', '36', '49', '60', '72'), +('11', '11', '37', '50', '37', '50', '61', '74'), +('11', '11', '38', '51', '38', '51', '63', '76'), +('11', '11', '39', '52', '39', '52', '64', '77'), +('11', '11', '40', '52', '39', '53', '66', '79'), +('11', '11', '41', '53', '40', '54', '67', '81'), +('11', '11', '42', '54', '41', '55', '69', '82'), +('11', '11', '43', '55', '42', '56', '70', '84'), +('11', '11', '44', '56', '43', '57', '72', '86'), +('11', '11', '45', '57', '43', '57', '73', '87'), +('11', '11', '46', '57', '44', '58', '75', '89'), +('11', '11', '47', '58', '45', '60', '76', '91'), +('11', '11', '48', '59', '46', '61', '78', '93'), +('11', '11', '49', '60', '47', '62', '79', '94'), +('11', '11', '50', '61', '47', '63', '81', '96'), +('11', '11', '51', '62', '48', '64', '83', '98'), +('11', '11', '52', '63', '49', '65', '84', '100'), +('11', '11', '53', '64', '50', '66', '86', '102'), +('11', '11', '54', '65', '51', '67', '87', '104'), +('11', '11', '55', '66', '51', '68', '89', '105'), +('11', '11', '56', '67', '52', '69', '91', '107'), +('11', '11', '57', '68', '53', '70', '92', '109'), +('11', '11', '58', '69', '54', '71', '94', '111'), +('11', '11', '59', '70', '55', '72', '96', '113'), +('11', '11', '60', '71', '56', '73', '97', '115'), +('11', '11', '61', '72', '57', '74', '99', '117'), +('11', '11', '62', '73', '58', '76', '101', '119'), +('11', '11', '63', '74', '59', '77', '103', '121'), +('11', '11', '64', '75', '59', '78', '104', '123'), +('11', '11', '65', '76', '60', '79', '106', '125'), +('11', '11', '66', '77', '61', '80', '108', '127'), +('11', '11', '67', '78', '62', '81', '110', '129'), +('11', '11', '68', '79', '63', '83', '111', '131'), +('11', '11', '69', '80', '64', '84', '113', '133'), +('11', '11', '70', '81', '65', '85', '115', '135'), +('11', '11', '71', '83', '66', '86', '117', '137'), +('11', '11', '72', '84', '68', '88', '120', '140'), +('11', '11', '73', '85', '69', '89', '122', '142'), +('11', '11', '74', '86', '70', '91', '124', '145'), +('11', '11', '75', '88', '71', '92', '126', '147'), +('11', '11', '76', '89', '72', '94', '128', '150'), +('11', '11', '77', '90', '73', '95', '131', '153'), +('11', '11', '78', '92', '75', '97', '133', '155'), +('11', '11', '79', '93', '76', '98', '136', '158'), +('11', '11', '80', '94', '77', '100', '138', '185'), +('10', '1', '1', '23', '20', '22', '20', '20'), +('10', '1', '2', '24', '21', '23', '20', '20'), +('10', '1', '3', '26', '22', '24', '20', '21'), +('10', '1', '4', '27', '22', '26', '20', '21'), +('10', '1', '5', '28', '23', '27', '20', '21'), +('10', '1', '6', '30', '24', '28', '20', '21'), +('10', '1', '7', '31', '25', '29', '21', '22'), +('10', '1', '8', '32', '26', '30', '21', '22'), +('10', '1', '9', '34', '26', '32', '21', '22'), +('10', '1', '10', '35', '27', '33', '21', '23'), +('10', '1', '11', '36', '28', '34', '21', '23'), +('10', '1', '12', '38', '29', '35', '21', '23'), +('10', '1', '13', '39', '30', '37', '21', '24'), +('10', '1', '14', '41', '31', '38', '21', '24'), +('10', '1', '15', '42', '32', '39', '21', '24'), +('10', '1', '16', '44', '33', '41', '21', '25'), +('10', '1', '17', '45', '34', '42', '22', '25'), +('10', '1', '18', '47', '34', '43', '22', '25'), +('10', '1', '19', '48', '35', '45', '22', '26'), +('10', '1', '20', '50', '36', '46', '22', '26'), +('10', '1', '21', '51', '37', '48', '22', '26'), +('10', '1', '22', '53', '38', '49', '22', '27'), +('10', '1', '23', '54', '39', '51', '22', '27'), +('10', '1', '24', '56', '40', '52', '23', '28'), +('10', '1', '25', '58', '41', '53', '23', '28'), +('10', '1', '26', '59', '42', '55', '23', '28'), +('10', '1', '27', '61', '43', '56', '23', '29'), +('10', '1', '28', '63', '44', '58', '23', '29'), +('10', '1', '29', '64', '45', '59', '23', '30'), +('10', '1', '30', '66', '46', '61', '24', '30'), +('10', '1', '31', '68', '47', '62', '24', '30'), +('10', '1', '32', '69', '48', '64', '24', '31'), +('10', '1', '33', '71', '50', '66', '24', '31'), +('10', '1', '34', '73', '51', '67', '24', '32'), +('10', '1', '35', '74', '52', '69', '24', '32'), +('10', '1', '36', '76', '53', '70', '25', '33'), +('10', '1', '37', '78', '54', '72', '25', '33'), +('10', '1', '38', '80', '55', '74', '25', '34'), +('10', '1', '39', '82', '56', '75', '25', '34'), +('10', '1', '40', '83', '57', '77', '25', '35'), +('10', '1', '41', '85', '58', '79', '26', '35'), +('10', '1', '42', '87', '60', '80', '26', '35'), +('10', '1', '43', '89', '61', '82', '26', '36'), +('10', '1', '44', '91', '62', '84', '26', '36'), +('10', '1', '45', '93', '63', '85', '26', '37'), +('10', '1', '46', '95', '64', '87', '27', '37'), +('10', '1', '47', '97', '66', '89', '27', '38'), +('10', '1', '48', '99', '67', '91', '27', '38'), +('10', '1', '49', '101', '68', '93', '27', '39'), +('10', '1', '50', '103', '69', '94', '28', '40'), +('10', '1', '51', '105', '71', '96', '28', '40'), +('10', '1', '52', '107', '72', '98', '28', '41'), +('10', '1', '53', '109', '73', '100', '28', '41'), +('10', '1', '54', '111', '74', '102', '29', '42'), +('10', '1', '55', '113', '76', '103', '29', '42'), +('10', '1', '56', '115', '77', '105', '29', '43'), +('10', '1', '57', '117', '78', '107', '29', '43'), +('10', '1', '58', '119', '79', '109', '30', '44'), +('10', '1', '59', '121', '81', '111', '30', '44'), +('10', '1', '60', '123', '82', '113', '30', '45'), +('10', '1', '61', '125', '83', '115', '30', '46'), +('10', '1', '62', '127', '85', '117', '31', '46'), +('10', '1', '63', '129', '86', '119', '31', '47'), +('10', '1', '64', '132', '88', '121', '31', '47'), +('10', '1', '65', '134', '89', '123', '32', '48'), +('10', '1', '66', '136', '90', '125', '32', '49'), +('10', '1', '67', '138', '92', '127', '32', '49'), +('10', '1', '68', '140', '93', '129', '32', '50'), +('10', '1', '69', '143', '95', '131', '33', '50'), +('10', '1', '70', '145', '96', '133', '33', '51'), +('10', '1', '71', '148', '97', '140', '33', '53'), +('10', '1', '72', '156', '99', '143', '33', '54'), +('10', '1', '73', '162', '101', '148', '33', '55'), +('10', '1', '74', '162', '102', '148', '34', '55'), +('10', '1', '75', '165', '104', '150', '34', '56'), +('10', '1', '76', '171', '106', '156', '34', '57'), +('10', '1', '77', '171', '108', '157', '35', '58'), +('10', '1', '78', '174', '109', '159', '35', '58'), +('10', '1', '79', '181', '111', '165', '35', '59'), +('10', '1', '80', '184', '113', '168', '36', '60'), +('10', '7', '1', '24', '17', '23', '18', '25'), +('10', '7', '2', '25', '17', '24', '19', '26'), +('10', '7', '3', '26', '18', '25', '20', '27'), +('10', '7', '4', '26', '18', '26', '21', '28'), +('10', '7', '5', '27', '19', '27', '22', '29'), +('10', '7', '6', '28', '19', '28', '23', '30'), +('10', '7', '7', '29', '20', '29', '24', '31'), +('10', '7', '8', '30', '20', '30', '25', '32'), +('10', '7', '9', '31', '21', '31', '26', '33'), +('10', '7', '10', '32', '21', '32', '27', '34'), +('10', '7', '11', '33', '22', '33', '28', '36'), +('10', '7', '12', '34', '22', '34', '29', '37'), +('10', '7', '13', '34', '23', '35', '30', '38'), +('10', '7', '14', '35', '23', '36', '31', '39'), +('10', '7', '15', '36', '24', '37', '32', '40'), +('10', '7', '16', '37', '24', '39', '33', '41'), +('10', '7', '17', '38', '25', '40', '34', '43'), +('10', '7', '18', '39', '25', '41', '35', '44'), +('10', '7', '19', '40', '26', '42', '36', '45'), +('10', '7', '20', '41', '26', '43', '37', '46'), +('10', '7', '21', '42', '27', '44', '38', '47'), +('10', '7', '22', '43', '27', '45', '39', '49'), +('10', '7', '23', '44', '28', '47', '40', '50'), +('10', '7', '24', '45', '28', '48', '41', '51'), +('10', '7', '25', '47', '29', '49', '43', '52'), +('10', '7', '26', '48', '30', '50', '44', '54'), +('10', '7', '27', '49', '30', '52', '45', '55'), +('10', '7', '28', '50', '31', '53', '46', '56'), +('10', '7', '29', '51', '31', '54', '47', '58'), +('10', '7', '30', '52', '32', '55', '48', '59'), +('10', '7', '31', '53', '33', '57', '50', '60'), +('10', '7', '32', '54', '33', '58', '51', '62'), +('10', '7', '33', '55', '34', '59', '52', '63'), +('10', '7', '34', '57', '34', '61', '53', '65'), +('10', '7', '35', '58', '35', '62', '55', '66'), +('10', '7', '36', '59', '36', '63', '56', '67'), +('10', '7', '37', '60', '36', '65', '57', '69'), +('10', '7', '38', '61', '37', '66', '58', '70'), +('10', '7', '39', '62', '38', '67', '60', '72'), +('10', '7', '40', '64', '38', '69', '61', '73'), +('10', '7', '41', '65', '39', '70', '62', '75'), +('10', '7', '42', '66', '40', '72', '64', '76'), +('10', '7', '43', '67', '40', '73', '65', '78'), +('10', '7', '44', '69', '41', '74', '66', '79'), +('10', '7', '45', '70', '42', '76', '68', '81'), +('10', '7', '46', '71', '42', '77', '69', '82'), +('10', '7', '47', '72', '43', '79', '70', '84'), +('10', '7', '48', '74', '44', '80', '72', '85'), +('10', '7', '49', '75', '45', '82', '73', '87'), +('10', '7', '50', '76', '45', '83', '75', '89'), +('10', '7', '51', '78', '46', '85', '76', '90'), +('10', '7', '52', '79', '47', '86', '77', '92'), +('10', '7', '53', '80', '47', '88', '79', '93'), +('10', '7', '54', '82', '48', '90', '80', '95'), +('10', '7', '55', '83', '49', '91', '82', '97'), +('10', '7', '56', '85', '50', '93', '83', '98'), +('10', '7', '57', '86', '50', '94', '85', '100'), +('10', '7', '58', '87', '51', '96', '86', '102'), +('10', '7', '59', '89', '52', '97', '88', '103'), +('10', '7', '60', '90', '53', '99', '89', '105'), +('10', '7', '61', '92', '54', '101', '91', '107'), +('10', '7', '62', '93', '54', '102', '92', '109'), +('10', '7', '63', '95', '55', '104', '94', '110'), +('10', '7', '64', '96', '56', '106', '95', '112'), +('10', '7', '65', '97', '57', '107', '97', '114'), +('10', '7', '66', '99', '58', '109', '99', '116'), +('10', '7', '67', '100', '58', '111', '100', '118'), +('10', '7', '68', '102', '59', '113', '102', '119'), +('10', '7', '69', '103', '60', '114', '103', '121'), +('10', '7', '70', '105', '61', '116', '105', '123'), +('10', '7', '71', '106', '62', '118', '117', '125'), +('10', '7', '72', '108', '63', '120', '119', '128'), +('10', '7', '73', '110', '64', '122', '122', '130'), +('10', '7', '74', '112', '65', '125', '124', '132'), +('10', '7', '75', '114', '66', '127', '126', '134'), +('10', '7', '76', '116', '67', '129', '128', '137'), +('10', '7', '77', '117', '68', '131', '128', '139'), +('10', '7', '78', '119', '69', '133', '133', '141'), +('10', '7', '79', '121', '70', '136', '135', '144'), +('10', '7', '80', '123', '71', '138', '137', '146'), +('10', '11', '1', '26', '15', '22', '17', '24'), +('10', '11', '2', '27', '16', '23', '18', '25'), +('10', '11', '3', '27', '16', '23', '19', '26'), +('10', '11', '4', '28', '17', '24', '20', '27'), +('10', '11', '5', '28', '17', '25', '21', '29'), +('10', '11', '6', '29', '18', '25', '22', '30'), +('10', '11', '7', '29', '18', '26', '23', '31'), +('10', '11', '8', '30', '19', '27', '24', '32'), +('10', '11', '9', '30', '19', '27', '26', '34'), +('10', '11', '10', '31', '20', '28', '27', '35'), +('10', '11', '11', '32', '20', '29', '28', '36'), +('10', '11', '12', '32', '21', '29', '29', '37'), +('10', '11', '13', '33', '21', '30', '30', '39'), +('10', '11', '14', '33', '22', '31', '31', '40'), +('10', '11', '15', '34', '23', '32', '32', '41'), +('10', '11', '16', '35', '23', '32', '34', '43'), +('10', '11', '17', '35', '24', '33', '35', '44'), +('10', '11', '18', '36', '24', '34', '36', '45'), +('10', '11', '19', '37', '25', '35', '37', '47'), +('10', '11', '20', '37', '26', '35', '39', '48'), +('10', '11', '21', '38', '26', '36', '40', '50'), +('10', '11', '22', '39', '27', '37', '41', '51'), +('10', '11', '23', '39', '28', '38', '42', '52'), +('10', '11', '24', '40', '28', '39', '44', '54'), +('10', '11', '25', '41', '29', '39', '45', '55'), +('10', '11', '26', '41', '30', '40', '46', '57'), +('10', '11', '27', '42', '30', '41', '47', '58'), +('10', '11', '28', '43', '31', '42', '49', '60'), +('10', '11', '29', '44', '32', '43', '50', '61'), +('10', '11', '30', '44', '32', '44', '52', '63'), +('10', '11', '31', '45', '33', '44', '53', '64'), +('10', '11', '32', '46', '34', '45', '54', '66'), +('10', '11', '33', '47', '34', '46', '56', '67'), +('10', '11', '34', '47', '35', '47', '57', '69'), +('10', '11', '35', '48', '36', '48', '58', '71'), +('10', '11', '36', '49', '36', '49', '60', '72'), +('10', '11', '37', '50', '37', '50', '61', '74'), +('10', '11', '38', '51', '38', '51', '63', '76'), +('10', '11', '39', '52', '39', '52', '64', '77'), +('10', '11', '40', '52', '39', '53', '66', '79'), +('10', '11', '41', '53', '40', '54', '67', '81'), +('10', '11', '42', '54', '41', '55', '69', '82'), +('10', '11', '43', '55', '42', '56', '70', '84'), +('10', '11', '44', '56', '43', '57', '72', '86'), +('10', '11', '45', '57', '43', '57', '73', '87'), +('10', '11', '46', '57', '44', '58', '75', '89'), +('10', '11', '47', '58', '45', '60', '76', '91'), +('10', '11', '48', '59', '46', '61', '78', '93'), +('10', '11', '49', '60', '47', '62', '79', '94'), +('10', '11', '50', '61', '47', '63', '81', '96'), +('10', '11', '51', '62', '48', '64', '83', '98'), +('10', '11', '52', '63', '49', '65', '84', '100'), +('10', '11', '53', '64', '50', '66', '86', '102'), +('10', '11', '54', '65', '51', '67', '87', '104'), +('10', '11', '55', '66', '51', '68', '89', '105'), +('10', '11', '56', '67', '52', '69', '91', '107'), +('10', '11', '57', '68', '53', '70', '92', '109'), +('10', '11', '58', '69', '54', '71', '94', '111'), +('10', '11', '59', '70', '55', '72', '96', '113'), +('10', '11', '60', '71', '56', '73', '97', '115'), +('10', '11', '61', '72', '57', '74', '99', '117'), +('10', '11', '62', '73', '58', '76', '101', '119'), +('10', '11', '63', '74', '59', '77', '103', '121'), +('10', '11', '64', '75', '59', '78', '104', '123'), +('10', '11', '65', '76', '60', '79', '106', '125'), +('10', '11', '66', '77', '61', '80', '108', '127'), +('10', '11', '67', '78', '62', '81', '110', '129'), +('10', '11', '68', '79', '63', '83', '111', '131'), +('10', '11', '69', '80', '64', '84', '113', '133'), +('10', '11', '70', '81', '65', '85', '115', '135'), +('10', '11', '71', '83', '66', '86', '117', '137'), +('10', '11', '72', '84', '68', '88', '120', '140'), +('10', '11', '73', '85', '69', '89', '122', '142'), +('10', '11', '74', '86', '70', '91', '124', '145'), +('10', '11', '75', '88', '71', '92', '126', '147'), +('10', '11', '76', '89', '72', '94', '128', '150'), +('10', '11', '77', '90', '73', '95', '131', '153'), +('10', '11', '78', '92', '75', '97', '133', '155'), +('10', '11', '79', '93', '76', '98', '136', '158'), +('10', '11', '80', '94', '77', '100', '138', '185'), +('3', '7', '1', '24', '17', '23', '18', '25'), +('3', '7', '2', '25', '17', '24', '19', '26'), +('3', '7', '3', '26', '18', '25', '20', '27'), +('3', '7', '4', '26', '18', '26', '21', '28'), +('3', '7', '5', '27', '19', '27', '22', '29'), +('3', '7', '6', '28', '19', '28', '23', '30'), +('3', '7', '7', '29', '20', '29', '24', '31'), +('3', '7', '8', '30', '20', '30', '25', '32'), +('3', '7', '9', '31', '21', '31', '26', '33'), +('3', '7', '10', '32', '21', '32', '27', '34'), +('3', '7', '11', '33', '22', '33', '28', '36'), +('3', '7', '12', '34', '22', '34', '29', '37'), +('3', '7', '13', '34', '23', '35', '30', '38'), +('3', '7', '14', '35', '23', '36', '31', '39'), +('3', '7', '15', '36', '24', '37', '32', '40'), +('3', '7', '16', '37', '24', '39', '33', '41'), +('3', '7', '17', '38', '25', '40', '34', '43'), +('3', '7', '18', '39', '25', '41', '35', '44'), +('3', '7', '19', '40', '26', '42', '36', '45'), +('3', '7', '20', '41', '26', '43', '37', '46'), +('3', '7', '21', '42', '27', '44', '38', '47'), +('3', '7', '22', '43', '27', '45', '39', '49'), +('3', '7', '23', '44', '28', '47', '40', '50'), +('3', '7', '24', '45', '28', '48', '41', '51'), +('3', '7', '25', '47', '29', '49', '43', '52'), +('3', '7', '26', '48', '30', '50', '44', '54'), +('3', '7', '27', '49', '30', '52', '45', '55'), +('3', '7', '28', '50', '31', '53', '46', '56'), +('3', '7', '29', '51', '31', '54', '47', '58'), +('3', '7', '30', '52', '32', '55', '48', '59'), +('3', '7', '31', '53', '33', '57', '50', '60'), +('3', '7', '32', '54', '33', '58', '51', '62'), +('3', '7', '33', '55', '34', '59', '52', '63'), +('3', '7', '34', '57', '34', '61', '53', '65'), +('3', '7', '35', '58', '35', '62', '55', '66'), +('3', '7', '36', '59', '36', '63', '56', '67'), +('3', '7', '37', '60', '36', '65', '57', '69'), +('3', '7', '38', '61', '37', '66', '58', '70'), +('3', '7', '39', '62', '38', '67', '60', '72'), +('3', '7', '40', '64', '38', '69', '61', '73'), +('3', '7', '41', '65', '39', '70', '62', '75'), +('3', '7', '42', '66', '40', '72', '64', '76'), +('3', '7', '43', '67', '40', '73', '65', '78'), +('3', '7', '44', '69', '41', '74', '66', '79'), +('3', '7', '45', '70', '42', '76', '68', '81'), +('3', '7', '46', '71', '42', '77', '69', '82'), +('3', '7', '47', '72', '43', '79', '70', '84'), +('3', '7', '48', '74', '44', '80', '72', '85'), +('3', '7', '49', '75', '45', '82', '73', '87'), +('3', '7', '50', '76', '45', '83', '75', '89'), +('3', '7', '51', '78', '46', '85', '76', '90'), +('3', '7', '52', '79', '47', '86', '77', '92'), +('3', '7', '53', '80', '47', '88', '79', '93'), +('3', '7', '54', '82', '48', '90', '80', '95'), +('3', '7', '55', '83', '49', '91', '82', '97'), +('3', '7', '56', '85', '50', '93', '83', '98'), +('3', '7', '57', '86', '50', '94', '85', '100'), +('3', '7', '58', '87', '51', '96', '86', '102'), +('3', '7', '59', '89', '52', '97', '88', '103'), +('3', '7', '60', '90', '53', '99', '89', '105'), +('3', '7', '61', '92', '54', '101', '91', '107'), +('3', '7', '62', '93', '54', '102', '92', '109'), +('3', '7', '63', '95', '55', '104', '94', '110'), +('3', '7', '64', '96', '56', '106', '95', '112'), +('3', '7', '65', '97', '57', '107', '97', '114'), +('3', '7', '66', '99', '58', '109', '99', '116'), +('3', '7', '67', '100', '58', '111', '100', '118'), +('3', '7', '68', '102', '59', '113', '102', '119'), +('3', '7', '69', '103', '60', '114', '103', '121'), +('3', '7', '70', '105', '61', '116', '105', '123'), +('3', '7', '71', '106', '62', '118', '117', '125'), +('3', '7', '72', '108', '63', '120', '119', '128'), +('3', '7', '73', '110', '64', '122', '122', '130'), +('3', '7', '74', '112', '65', '125', '124', '132'), +('3', '7', '75', '114', '66', '127', '126', '134'), +('3', '7', '76', '116', '67', '129', '128', '137'), +('3', '7', '77', '117', '68', '131', '128', '139'), +('3', '7', '78', '119', '69', '133', '133', '141'), +('3', '7', '79', '121', '70', '136', '135', '144'), +('3', '7', '80', '123', '71', '138', '137', '146'), +('3', '8', '1', '20', '20', '20', '23', '22'), +('3', '8', '2', '20', '20', '20', '24', '23'), +('3', '8', '3', '20', '20', '21', '26', '25'), +('3', '8', '4', '20', '20', '21', '27', '26'), +('3', '8', '5', '20', '21', '21', '28', '27'), +('3', '8', '6', '20', '21', '21', '30', '29'), +('3', '8', '7', '21', '21', '22', '31', '30'), +('3', '8', '8', '21', '21', '22', '33', '31'), +('3', '8', '9', '21', '21', '22', '34', '33'), +('3', '8', '10', '21', '21', '23', '36', '34'), +('3', '8', '11', '21', '22', '23', '37', '36'), +('3', '8', '12', '21', '22', '23', '39', '37'), +('3', '8', '13', '21', '22', '24', '40', '38'), +('3', '8', '14', '21', '22', '24', '42', '40'), +('3', '8', '15', '21', '22', '24', '43', '41'), +('3', '8', '16', '21', '23', '25', '45', '43'), +('3', '8', '17', '22', '23', '25', '46', '44'), +('3', '8', '18', '22', '23', '25', '48', '46'), +('3', '8', '19', '22', '23', '26', '49', '47'), +('3', '8', '20', '22', '23', '26', '51', '49'), +('3', '8', '21', '22', '24', '26', '53', '51'), +('3', '8', '22', '22', '24', '27', '54', '52'), +('3', '8', '23', '22', '24', '27', '56', '54'), +('3', '8', '24', '23', '24', '28', '58', '55'), +('3', '8', '25', '23', '25', '28', '59', '57'), +('3', '8', '26', '23', '25', '28', '61', '59'), +('3', '8', '27', '23', '25', '29', '63', '60'), +('3', '8', '28', '23', '25', '29', '65', '62'), +('3', '8', '29', '23', '25', '30', '66', '64'), +('3', '8', '30', '24', '26', '30', '68', '65'), +('3', '8', '31', '24', '26', '30', '70', '67'), +('3', '8', '32', '24', '26', '31', '72', '69'), +('3', '8', '33', '24', '27', '31', '73', '70'), +('3', '8', '34', '24', '27', '32', '75', '72'), +('3', '8', '35', '24', '27', '32', '77', '74'), +('3', '8', '36', '25', '27', '33', '79', '76'), +('3', '8', '37', '25', '28', '33', '81', '78'), +('3', '8', '38', '25', '28', '34', '83', '79'), +('3', '8', '39', '25', '28', '34', '85', '81'), +('3', '8', '40', '25', '28', '35', '87', '83'), +('3', '8', '41', '26', '29', '35', '88', '85'), +('3', '8', '42', '26', '29', '35', '90', '87'), +('3', '8', '43', '26', '29', '36', '92', '89'), +('3', '8', '44', '26', '30', '36', '94', '91'), +('3', '8', '45', '26', '30', '37', '96', '92'), +('3', '8', '46', '27', '30', '37', '98', '94'), +('3', '8', '47', '27', '31', '38', '100', '96'), +('3', '8', '48', '27', '31', '38', '102', '98'), +('3', '8', '49', '27', '31', '39', '104', '100'), +('3', '8', '50', '28', '32', '40', '106', '102'), +('3', '8', '51', '28', '32', '40', '109', '104'), +('3', '8', '52', '28', '32', '41', '111', '106'), +('3', '8', '53', '28', '33', '41', '113', '108'), +('3', '8', '54', '29', '33', '42', '115', '110'), +('3', '8', '55', '29', '33', '42', '117', '112'), +('3', '8', '56', '29', '34', '43', '119', '114'), +('3', '8', '57', '29', '34', '43', '121', '117'), +('3', '8', '58', '30', '34', '44', '124', '119'), +('3', '8', '59', '30', '35', '44', '126', '121'), +('3', '8', '60', '30', '35', '45', '128', '123'), +('3', '8', '61', '30', '35', '46', '130', '125'), +('3', '8', '62', '31', '36', '46', '132', '127'), +('3', '8', '63', '31', '36', '47', '135', '129'), +('3', '8', '64', '31', '37', '47', '137', '132'), +('3', '8', '65', '32', '37', '48', '139', '134'), +('3', '8', '66', '32', '37', '49', '142', '136'), +('3', '8', '67', '32', '38', '49', '144', '138'), +('3', '8', '68', '32', '38', '50', '146', '140'), +('3', '8', '69', '33', '39', '50', '149', '143'), +('3', '8', '70', '33', '39', '51', '151', '145'), +('3', '8', '71', '33', '39', '52', '154', '152'), +('3', '8', '72', '33', '40', '53', '160', '155'), +('3', '8', '73', '33', '40', '54', '160', '158'), +('3', '8', '74', '34', '41', '54', '163', '160'), +('3', '8', '75', '34', '41', '55', '166', '163'), +('3', '8', '76', '34', '41', '56', '169', '166'), +('3', '8', '77', '35', '42', '57', '172', '169'), +('3', '8', '78', '35', '42', '57', '175', '173'), +('3', '8', '79', '35', '43', '58', '178', '176'), +('3', '8', '80', '36', '43', '59', '181', '179'), +('3', '9', '1', '20', '20', '21', '22', '22'), +('3', '9', '2', '20', '20', '22', '23', '23'), +('3', '9', '3', '21', '21', '22', '24', '24'), +('3', '9', '4', '21', '21', '23', '26', '25'), +('3', '9', '5', '21', '21', '23', '27', '27'), +('3', '9', '6', '21', '22', '24', '28', '28'), +('3', '9', '7', '22', '22', '24', '29', '29'), +('3', '9', '8', '22', '23', '25', '30', '30'), +('3', '9', '9', '22', '23', '26', '32', '31'), +('3', '9', '10', '23', '23', '26', '33', '33'), +('3', '9', '11', '23', '24', '27', '34', '34'), +('3', '9', '12', '23', '24', '27', '35', '35'), +('3', '9', '13', '24', '25', '28', '37', '36'), +('3', '9', '14', '24', '25', '29', '38', '38'), +('3', '9', '15', '24', '25', '29', '39', '39'), +('3', '9', '16', '25', '26', '30', '41', '40'), +('3', '9', '17', '25', '26', '31', '42', '42'), +('3', '9', '18', '25', '27', '31', '43', '43'), +('3', '9', '19', '26', '27', '32', '45', '44'), +('3', '9', '20', '26', '28', '33', '46', '46'), +('3', '9', '21', '26', '28', '33', '48', '47'), +('3', '9', '22', '27', '29', '34', '49', '49'), +('3', '9', '23', '27', '29', '35', '51', '50'), +('3', '9', '24', '28', '30', '35', '52', '51'), +('3', '9', '25', '28', '30', '36', '53', '53'), +('3', '9', '26', '28', '31', '37', '55', '54'), +('3', '9', '27', '29', '31', '37', '56', '56'), +('3', '9', '28', '29', '32', '38', '58', '57'), +('3', '9', '29', '30', '32', '39', '59', '59'), +('3', '9', '30', '30', '33', '40', '61', '60'), +('3', '9', '31', '30', '33', '40', '62', '62'), +('3', '9', '32', '31', '34', '41', '64', '63'), +('3', '9', '33', '31', '34', '42', '66', '65'), +('3', '9', '34', '32', '35', '43', '67', '66'), +('3', '9', '35', '32', '35', '44', '69', '68'), +('3', '9', '36', '33', '36', '44', '70', '69'), +('3', '9', '37', '33', '36', '45', '72', '71'), +('3', '9', '38', '34', '37', '46', '74', '73'), +('3', '9', '39', '34', '38', '47', '75', '74'), +('3', '9', '40', '35', '38', '48', '77', '76'), +('3', '9', '41', '35', '39', '48', '79', '78'), +('3', '9', '42', '35', '39', '49', '80', '79'), +('3', '9', '43', '36', '40', '50', '82', '81'), +('3', '9', '44', '36', '40', '51', '84', '83'), +('3', '9', '45', '37', '41', '52', '85', '84'), +('3', '9', '46', '37', '42', '53', '87', '86'), +('3', '9', '47', '38', '42', '54', '89', '88'), +('3', '9', '48', '38', '43', '55', '91', '89'), +('3', '9', '49', '39', '44', '55', '93', '91'), +('3', '9', '50', '40', '44', '56', '94', '93'), +('3', '9', '51', '40', '45', '57', '96', '95'), +('3', '9', '52', '41', '45', '58', '98', '97'), +('3', '9', '53', '41', '46', '59', '100', '98'), +('3', '9', '54', '42', '47', '60', '102', '100'), +('3', '9', '55', '42', '47', '61', '103', '102'), +('3', '9', '56', '43', '48', '62', '105', '104'), +('3', '9', '57', '43', '49', '63', '107', '106'), +('3', '9', '58', '44', '49', '64', '109', '108'), +('3', '9', '59', '44', '50', '65', '111', '109'), +('3', '9', '60', '45', '51', '66', '113', '111'), +('3', '9', '61', '46', '51', '67', '115', '113'), +('3', '9', '62', '46', '52', '68', '117', '115'), +('3', '9', '63', '47', '53', '69', '119', '117'), +('3', '9', '64', '47', '54', '70', '121', '119'), +('3', '9', '65', '48', '54', '71', '123', '121'), +('3', '9', '66', '49', '55', '72', '125', '123'), +('3', '9', '67', '49', '56', '73', '127', '125'), +('3', '9', '68', '50', '57', '74', '129', '127'), +('3', '9', '69', '50', '57', '75', '131', '129'), +('3', '9', '70', '51', '58', '76', '133', '131'), +('3', '9', '71', '52', '59', '78', '135', '146'), +('3', '9', '72', '53', '59', '79', '138', '148'), +('3', '9', '73', '54', '60', '80', '140', '151'), +('3', '9', '74', '54', '61', '89', '143', '154'), +('3', '9', '75', '55', '62', '91', '145', '156'), +('3', '9', '76', '56', '63', '92', '148', '159'), +('3', '9', '77', '57', '64', '93', '151', '162'), +('3', '9', '78', '57', '65', '95', '153', '165'), +('3', '9', '79', '58', '66', '96', '156', '168'), +('3', '9', '80', '59', '67', '97', '159', '170'), +('3', '11', '1', '26', '15', '22', '17', '24'), +('3', '11', '2', '27', '16', '23', '18', '25'), +('3', '11', '3', '27', '16', '23', '19', '26'), +('3', '11', '4', '28', '17', '24', '20', '27'), +('3', '11', '5', '28', '17', '25', '21', '29'), +('3', '11', '6', '29', '18', '25', '22', '30'), +('3', '11', '7', '29', '18', '26', '23', '31'), +('3', '11', '8', '30', '19', '27', '24', '32'), +('3', '11', '9', '30', '19', '27', '26', '34'), +('3', '11', '10', '31', '20', '28', '27', '35'), +('3', '11', '11', '32', '20', '29', '28', '36'), +('3', '11', '12', '32', '21', '29', '29', '37'), +('3', '11', '13', '33', '21', '30', '30', '39'), +('3', '11', '14', '33', '22', '31', '31', '40'), +('3', '11', '15', '34', '23', '32', '32', '41'), +('3', '11', '16', '35', '23', '32', '34', '43'), +('3', '11', '17', '35', '24', '33', '35', '44'), +('3', '11', '18', '36', '24', '34', '36', '45'), +('3', '11', '19', '37', '25', '35', '37', '47'), +('3', '11', '20', '37', '26', '35', '39', '48'), +('3', '11', '21', '38', '26', '36', '40', '50'), +('3', '11', '22', '39', '27', '37', '41', '51'), +('3', '11', '23', '39', '28', '38', '42', '52'), +('3', '11', '24', '40', '28', '39', '44', '54'), +('3', '11', '25', '41', '29', '39', '45', '55'), +('3', '11', '26', '41', '30', '40', '46', '57'), +('3', '11', '27', '42', '30', '41', '47', '58'), +('3', '11', '28', '43', '31', '42', '49', '60'), +('3', '11', '29', '44', '32', '43', '50', '61'), +('3', '11', '30', '44', '32', '44', '52', '63'), +('3', '11', '31', '45', '33', '44', '53', '64'), +('3', '11', '32', '46', '34', '45', '54', '66'), +('3', '11', '33', '47', '34', '46', '56', '67'), +('3', '11', '34', '47', '35', '47', '57', '69'), +('3', '11', '35', '48', '36', '48', '58', '71'), +('3', '11', '36', '49', '36', '49', '60', '72'), +('3', '11', '37', '50', '37', '50', '61', '74'), +('3', '11', '38', '51', '38', '51', '63', '76'), +('3', '11', '39', '52', '39', '52', '64', '77'), +('3', '11', '40', '52', '39', '53', '66', '79'), +('3', '11', '41', '53', '40', '54', '67', '81'), +('3', '11', '42', '54', '41', '55', '69', '82'), +('3', '11', '43', '55', '42', '56', '70', '84'), +('3', '11', '44', '56', '43', '57', '72', '86'), +('3', '11', '45', '57', '43', '57', '73', '87'), +('3', '11', '46', '57', '44', '58', '75', '89'), +('3', '11', '47', '58', '45', '60', '76', '91'), +('3', '11', '48', '59', '46', '61', '78', '93'), +('3', '11', '49', '60', '47', '62', '79', '94'), +('3', '11', '50', '61', '47', '63', '81', '96'), +('3', '11', '51', '62', '48', '64', '83', '98'), +('3', '11', '52', '63', '49', '65', '84', '100'), +('3', '11', '53', '64', '50', '66', '86', '102'), +('3', '11', '54', '65', '51', '67', '87', '104'), +('3', '11', '55', '66', '51', '68', '89', '105'), +('3', '11', '56', '67', '52', '69', '91', '107'), +('3', '11', '57', '68', '53', '70', '92', '109'), +('3', '11', '58', '69', '54', '71', '94', '111'), +('3', '11', '59', '70', '55', '72', '96', '113'), +('3', '11', '60', '71', '56', '73', '97', '115'), +('3', '11', '61', '72', '57', '74', '99', '117'), +('3', '11', '62', '73', '58', '76', '101', '119'), +('3', '11', '63', '74', '59', '77', '103', '121'), +('3', '11', '64', '75', '59', '78', '104', '123'), +('3', '11', '65', '76', '60', '79', '106', '125'), +('3', '11', '66', '77', '61', '80', '108', '127'), +('3', '11', '67', '78', '62', '81', '110', '129'), +('3', '11', '68', '79', '63', '83', '111', '131'), +('3', '11', '69', '80', '64', '84', '113', '133'), +('3', '11', '70', '81', '65', '85', '115', '135'), +('3', '11', '71', '83', '66', '86', '117', '137'), +('3', '11', '72', '84', '68', '88', '120', '140'), +('3', '11', '73', '85', '69', '89', '122', '142'), +('3', '11', '74', '86', '70', '91', '124', '145'), +('3', '11', '75', '88', '71', '92', '126', '147'), +('3', '11', '76', '89', '72', '94', '128', '150'), +('3', '11', '77', '90', '73', '95', '131', '153'), +('3', '11', '78', '92', '75', '97', '133', '155'), +('3', '11', '79', '93', '76', '98', '136', '158'), +('3', '11', '80', '94', '77', '100', '138', '185'), +('7', '2', '1', '22', '20', '22', '20', '21'), +('7', '2', '2', '23', '21', '23', '21', '22'), +('7', '2', '3', '24', '21', '24', '21', '22'), +('7', '2', '4', '25', '22', '25', '22', '23'), +('7', '2', '5', '26', '22', '26', '23', '24'), +('7', '2', '6', '28', '23', '27', '23', '25'), +('7', '2', '7', '29', '24', '28', '24', '25'), +('7', '2', '8', '30', '24', '29', '25', '26'), +('7', '2', '9', '31', '25', '30', '25', '27'), +('7', '2', '10', '32', '25', '32', '26', '27'), +('7', '2', '11', '33', '26', '33', '27', '28'), +('7', '2', '12', '35', '27', '34', '27', '29'), +('7', '2', '13', '36', '27', '35', '28', '30'), +('7', '2', '14', '37', '28', '36', '29', '31'), +('7', '2', '15', '38', '29', '37', '30', '31'), +('7', '2', '16', '40', '29', '38', '30', '32'), +('7', '2', '17', '41', '30', '40', '31', '33'), +('7', '2', '18', '42', '31', '41', '32', '34'), +('7', '2', '19', '43', '31', '42', '33', '35'), +('7', '2', '20', '45', '32', '43', '33', '35'), +('7', '2', '21', '46', '33', '45', '34', '36'), +('7', '2', '22', '47', '33', '46', '35', '37'), +('7', '2', '23', '49', '34', '47', '36', '38'), +('7', '2', '24', '50', '35', '48', '37', '39'), +('7', '2', '25', '51', '36', '50', '37', '40'), +('7', '2', '26', '53', '36', '51', '38', '41'), +('7', '2', '27', '54', '37', '52', '39', '42'), +('7', '2', '28', '56', '38', '54', '40', '43'), +('7', '2', '29', '57', '39', '55', '41', '43'), +('7', '2', '30', '58', '39', '56', '42', '44'), +('7', '2', '31', '60', '40', '58', '43', '45'), +('7', '2', '32', '61', '41', '59', '43', '46'), +('7', '2', '33', '63', '42', '60', '44', '47'), +('7', '2', '34', '64', '43', '62', '45', '48'), +('7', '2', '35', '66', '44', '63', '46', '49'), +('7', '2', '36', '67', '44', '65', '47', '50'), +('7', '2', '37', '69', '45', '66', '48', '51'), +('7', '2', '38', '70', '46', '67', '49', '52'), +('7', '2', '39', '72', '47', '69', '50', '53'), +('7', '2', '40', '73', '48', '70', '51', '54'), +('7', '2', '41', '75', '49', '72', '52', '55'), +('7', '2', '42', '77', '49', '73', '53', '56'), +('7', '2', '43', '78', '50', '75', '54', '57'), +('7', '2', '44', '80', '51', '76', '55', '58'), +('7', '2', '45', '81', '52', '78', '56', '59'), +('7', '2', '46', '83', '53', '79', '57', '61'), +('7', '2', '47', '85', '54', '81', '58', '62'), +('7', '2', '48', '86', '55', '83', '59', '63'), +('7', '2', '49', '88', '56', '84', '60', '64'), +('7', '2', '50', '90', '57', '86', '61', '65'), +('7', '2', '51', '91', '58', '87', '62', '66'), +('7', '2', '52', '93', '59', '89', '63', '67'), +('7', '2', '53', '95', '60', '91', '64', '68'), +('7', '2', '54', '97', '61', '92', '65', '69'), +('7', '2', '55', '98', '61', '94', '66', '71'), +('7', '2', '56', '100', '62', '95', '67', '72'), +('7', '2', '57', '102', '63', '97', '68', '73'), +('7', '2', '58', '104', '64', '99', '69', '74'), +('7', '2', '59', '105', '65', '101', '70', '75'), +('7', '2', '60', '107', '66', '102', '71', '77'), +('7', '2', '61', '109', '67', '104', '73', '78'), +('7', '2', '62', '111', '69', '106', '74', '79'), +('7', '2', '63', '113', '70', '107', '75', '80'), +('7', '2', '64', '115', '71', '109', '76', '81'), +('7', '2', '65', '116', '72', '111', '77', '83'), +('7', '2', '66', '118', '73', '113', '78', '84'), +('7', '2', '67', '120', '74', '115', '79', '85'), +('7', '2', '68', '122', '75', '116', '81', '86'), +('7', '2', '69', '124', '76', '118', '82', '88'), +('7', '2', '70', '126', '77', '120', '83', '89'), +('7', '2', '71', '148', '78', '122', '84', '92'), +('7', '2', '72', '150', '79', '125', '86', '94'), +('7', '2', '73', '152', '80', '127', '87', '96'), +('7', '2', '74', '156', '82', '129', '89', '97'), +('7', '2', '75', '158', '83', '131', '90', '99'), +('7', '2', '76', '162', '84', '134', '92', '100'), +('7', '2', '77', '164', '86', '136', '93', '103'), +('7', '2', '78', '167', '87', '138', '95', '105'), +('7', '2', '79', '170', '88', '153', '96', '106'), +('7', '2', '80', '173', '90', '160', '98', '108'), +('7', '3', '1', '23', '20', '23', '17', '24'), +('7', '3', '2', '23', '21', '24', '18', '25'), +('7', '3', '3', '24', '23', '25', '18', '25'), +('7', '3', '4', '24', '24', '26', '19', '26'), +('7', '3', '5', '25', '25', '27', '19', '26'), +('7', '3', '6', '25', '27', '28', '20', '27'), +('7', '3', '7', '26', '28', '28', '21', '28'), +('7', '3', '8', '26', '30', '29', '21', '28'), +('7', '3', '9', '26', '31', '30', '22', '29'), +('7', '3', '10', '27', '33', '31', '22', '30'), +('7', '3', '11', '27', '34', '32', '23', '30'), +('7', '3', '12', '28', '36', '33', '24', '31'), +('7', '3', '13', '28', '37', '34', '24', '32'), +('7', '3', '14', '29', '39', '35', '25', '33'), +('7', '3', '15', '29', '40', '36', '26', '33'), +('7', '3', '16', '30', '42', '37', '26', '34'), +('7', '3', '17', '30', '43', '39', '27', '35'), +('7', '3', '18', '31', '45', '40', '28', '35'), +('7', '3', '19', '31', '47', '41', '28', '36'), +('7', '3', '20', '32', '48', '42', '29', '37'), +('7', '3', '21', '32', '50', '43', '30', '38'), +('7', '3', '22', '33', '51', '44', '31', '39'), +('7', '3', '23', '34', '53', '45', '31', '39'), +('7', '3', '24', '34', '55', '46', '32', '40'), +('7', '3', '25', '35', '57', '47', '33', '41'), +('7', '3', '26', '35', '58', '48', '34', '42'), +('7', '3', '27', '36', '60', '50', '34', '43'), +('7', '3', '28', '36', '62', '51', '35', '43'), +('7', '3', '29', '37', '63', '52', '36', '44'), +('7', '3', '30', '38', '65', '53', '37', '45'), +('7', '3', '31', '38', '67', '54', '37', '46'), +('7', '3', '32', '39', '69', '56', '38', '47'), +('7', '3', '33', '39', '71', '57', '39', '48'), +('7', '3', '34', '40', '72', '58', '40', '49'), +('7', '3', '35', '41', '74', '59', '41', '49'), +('7', '3', '36', '41', '76', '61', '42', '50'), +('7', '3', '37', '42', '78', '62', '42', '51'), +('7', '3', '38', '43', '80', '63', '43', '52'), +('7', '3', '39', '43', '82', '64', '44', '53'), +('7', '3', '40', '44', '84', '66', '45', '54'), +('7', '3', '41', '45', '86', '67', '46', '55'), +('7', '3', '42', '45', '88', '68', '47', '56'), +('7', '3', '43', '46', '90', '70', '47', '57'), +('7', '3', '44', '47', '91', '71', '48', '58'), +('7', '3', '45', '47', '93', '72', '49', '59'), +('7', '3', '46', '48', '95', '74', '50', '60'), +('7', '3', '47', '49', '98', '75', '51', '61'), +('7', '3', '48', '50', '100', '77', '52', '62'), +('7', '3', '49', '50', '102', '78', '53', '63'), +('7', '3', '50', '51', '104', '79', '54', '64'), +('7', '3', '51', '52', '106', '81', '55', '65'), +('7', '3', '52', '52', '108', '82', '56', '66'), +('7', '3', '53', '53', '110', '84', '57', '67'), +('7', '3', '54', '54', '112', '85', '58', '68'), +('7', '3', '55', '55', '114', '87', '59', '69'), +('7', '3', '56', '55', '116', '88', '60', '70'), +('7', '3', '57', '56', '118', '90', '61', '71'), +('7', '3', '58', '57', '121', '91', '62', '72'), +('7', '3', '59', '58', '123', '93', '63', '73'), +('7', '3', '60', '59', '125', '94', '64', '74'), +('7', '3', '61', '59', '127', '96', '65', '76'), +('7', '3', '62', '60', '130', '97', '66', '77'), +('7', '3', '63', '61', '132', '99', '67', '78'), +('7', '3', '64', '62', '134', '100', '68', '79'), +('7', '3', '65', '63', '136', '102', '69', '80'), +('7', '3', '66', '64', '139', '104', '70', '81'), +('7', '3', '67', '64', '141', '105', '71', '82'), +('7', '3', '68', '65', '143', '107', '72', '84'), +('7', '3', '69', '66', '146', '108', '73', '85'), +('7', '3', '70', '67', '148', '110', '74', '86'), +('7', '3', '71', '68', '151', '112', '75', '87'), +('7', '3', '72', '69', '154', '114', '76', '88'), +('7', '3', '73', '70', '157', '116', '77', '90'), +('7', '3', '74', '71', '160', '118', '79', '91'), +('7', '3', '75', '72', '163', '120', '80', '93'), +('7', '3', '76', '73', '166', '122', '81', '94'), +('7', '3', '77', '74', '169', '124', '83', '96'), +('7', '3', '78', '75', '172', '126', '84', '97'), +('7', '3', '79', '76', '175', '128', '85', '99'), +('7', '3', '80', '77', '178', '130', '87', '100'), +('7', '5', '1', '20', '20', '20', '22', '23'), +('7', '5', '2', '20', '20', '20', '23', '24'), +('7', '5', '3', '20', '20', '21', '25', '26'), +('7', '5', '4', '20', '21', '21', '26', '27'), +('7', '5', '5', '21', '21', '21', '27', '28'), +('7', '5', '6', '21', '21', '22', '29', '30'), +('7', '5', '7', '21', '21', '22', '30', '31'), +('7', '5', '8', '21', '22', '23', '31', '33'), +('7', '5', '9', '21', '22', '23', '33', '34'), +('7', '5', '10', '21', '22', '23', '34', '36'), +('7', '5', '11', '22', '22', '24', '36', '37'), +('7', '5', '12', '22', '23', '24', '37', '39'), +('7', '5', '13', '22', '23', '25', '38', '40'), +('7', '5', '14', '22', '23', '25', '40', '42'), +('7', '5', '15', '22', '23', '25', '41', '43'), +('7', '5', '16', '23', '24', '26', '43', '45'), +('7', '5', '17', '23', '24', '26', '44', '46'), +('7', '5', '18', '23', '24', '27', '46', '48'), +('7', '5', '19', '23', '24', '27', '47', '49'), +('7', '5', '20', '23', '25', '28', '49', '51'), +('7', '5', '21', '24', '25', '28', '51', '53'), +('7', '5', '22', '24', '25', '29', '52', '54'), +('7', '5', '23', '24', '26', '29', '54', '56'), +('7', '5', '24', '24', '26', '30', '55', '58'), +('7', '5', '25', '25', '26', '30', '57', '59'), +('7', '5', '26', '25', '27', '31', '59', '61'), +('7', '5', '27', '25', '27', '31', '60', '63'), +('7', '5', '28', '25', '27', '32', '62', '65'), +('7', '5', '29', '25', '28', '32', '64', '66'), +('7', '5', '30', '26', '28', '33', '65', '68'), +('7', '5', '31', '26', '28', '33', '67', '70'), +('7', '5', '32', '26', '29', '34', '69', '72'), +('7', '5', '33', '27', '29', '34', '70', '73'), +('7', '5', '34', '27', '29', '35', '72', '75'), +('7', '5', '35', '27', '30', '35', '74', '77'), +('7', '5', '36', '27', '30', '36', '76', '79'), +('7', '5', '37', '28', '30', '36', '78', '81'), +('7', '5', '38', '28', '31', '37', '79', '83'), +('7', '5', '39', '28', '31', '38', '81', '85'), +('7', '5', '40', '28', '31', '38', '83', '87'), +('7', '5', '41', '29', '32', '39', '85', '88'), +('7', '5', '42', '29', '32', '39', '87', '90'), +('7', '5', '43', '29', '33', '40', '89', '92'), +('7', '5', '44', '30', '33', '40', '91', '94'), +('7', '5', '45', '30', '33', '41', '92', '96'), +('7', '5', '46', '30', '34', '42', '94', '98'), +('7', '5', '47', '31', '34', '42', '96', '100'), +('7', '5', '48', '31', '35', '43', '98', '102'), +('7', '5', '49', '31', '35', '44', '100', '104'), +('7', '5', '50', '32', '36', '44', '102', '106'), +('7', '5', '51', '32', '36', '45', '104', '109'), +('7', '5', '52', '32', '36', '45', '106', '111'), +('7', '5', '53', '33', '37', '46', '108', '113'), +('7', '5', '54', '33', '37', '47', '110', '115'), +('7', '5', '55', '33', '38', '47', '112', '117'), +('7', '5', '56', '34', '38', '48', '114', '119'), +('7', '5', '57', '34', '39', '49', '117', '121'), +('7', '5', '58', '34', '39', '49', '119', '124'), +('7', '5', '59', '35', '40', '50', '121', '126'), +('7', '5', '60', '35', '40', '51', '123', '128'), +('7', '5', '61', '35', '41', '51', '125', '130'), +('7', '5', '62', '36', '41', '52', '127', '132'), +('7', '5', '63', '36', '41', '53', '129', '135'), +('7', '5', '64', '37', '42', '54', '132', '137'), +('7', '5', '65', '37', '42', '54', '134', '139'), +('7', '5', '66', '37', '43', '55', '136', '142'), +('7', '5', '67', '38', '43', '56', '138', '144'), +('7', '5', '68', '38', '44', '57', '140', '146'), +('7', '5', '69', '39', '44', '57', '143', '149'), +('7', '5', '70', '39', '45', '58', '145', '151'), +('7', '5', '71', '39', '46', '59', '148', '158'), +('7', '5', '72', '40', '46', '59', '151', '161'), +('7', '5', '73', '40', '47', '60', '154', '164'), +('7', '5', '74', '41', '47', '61', '156', '167'), +('7', '5', '75', '41', '48', '62', '159', '170'), +('7', '5', '76', '41', '49', '63', '162', '174'), +('7', '5', '77', '42', '49', '64', '165', '177'), +('7', '5', '78', '42', '50', '65', '168', '180'), +('7', '5', '79', '43', '50', '66', '171', '183'), +('7', '5', '80', '43', '51', '67', '174', '186'), +('7', '7', '1', '24', '17', '23', '18', '25'), +('7', '7', '2', '25', '17', '24', '19', '26'), +('7', '7', '3', '26', '18', '25', '20', '27'), +('7', '7', '4', '26', '18', '26', '21', '28'), +('7', '7', '5', '27', '19', '27', '22', '29'), +('7', '7', '6', '28', '19', '28', '23', '30'), +('7', '7', '7', '29', '20', '29', '24', '31'), +('7', '7', '8', '30', '20', '30', '25', '32'), +('7', '7', '9', '31', '21', '31', '26', '33'), +('7', '7', '10', '32', '21', '32', '27', '34'), +('7', '7', '11', '33', '22', '33', '28', '36'), +('7', '7', '12', '34', '22', '34', '29', '37'), +('7', '7', '13', '34', '23', '35', '30', '38'), +('7', '7', '14', '35', '23', '36', '31', '39'), +('7', '7', '15', '36', '24', '37', '32', '40'), +('7', '7', '16', '37', '24', '39', '33', '41'), +('7', '7', '17', '38', '25', '40', '34', '43'), +('7', '7', '18', '39', '25', '41', '35', '44'), +('7', '7', '19', '40', '26', '42', '36', '45'), +('7', '7', '20', '41', '26', '43', '37', '46'), +('7', '7', '21', '42', '27', '44', '38', '47'), +('7', '7', '22', '43', '27', '45', '39', '49'), +('7', '7', '23', '44', '28', '47', '40', '50'), +('7', '7', '24', '45', '28', '48', '41', '51'), +('7', '7', '25', '47', '29', '49', '43', '52'), +('7', '7', '26', '48', '30', '50', '44', '54'), +('7', '7', '27', '49', '30', '52', '45', '55'), +('7', '7', '28', '50', '31', '53', '46', '56'), +('7', '7', '29', '51', '31', '54', '47', '58'), +('7', '7', '30', '52', '32', '55', '48', '59'), +('7', '7', '31', '53', '33', '57', '50', '60'), +('7', '7', '32', '54', '33', '58', '51', '62'), +('7', '7', '33', '55', '34', '59', '52', '63'), +('7', '7', '34', '57', '34', '61', '53', '65'), +('7', '7', '35', '58', '35', '62', '55', '66'), +('7', '7', '36', '59', '36', '63', '56', '67'), +('7', '7', '37', '60', '36', '65', '57', '69'), +('7', '7', '38', '61', '37', '66', '58', '70'), +('7', '7', '39', '62', '38', '67', '60', '72'), +('7', '7', '40', '64', '38', '69', '61', '73'), +('7', '7', '41', '65', '39', '70', '62', '75'), +('7', '7', '42', '66', '40', '72', '64', '76'), +('7', '7', '43', '67', '40', '73', '65', '78'), +('7', '7', '44', '69', '41', '74', '66', '79'), +('7', '7', '45', '70', '42', '76', '68', '81'), +('7', '7', '46', '71', '42', '77', '69', '82'), +('7', '7', '47', '72', '43', '79', '70', '84'), +('7', '7', '48', '74', '44', '80', '72', '85'), +('7', '7', '49', '75', '45', '82', '73', '87'), +('7', '7', '50', '76', '45', '83', '75', '89'), +('7', '7', '51', '78', '46', '85', '76', '90'), +('7', '7', '52', '79', '47', '86', '77', '92'), +('7', '7', '53', '80', '47', '88', '79', '93'), +('7', '7', '54', '82', '48', '90', '80', '95'), +('7', '7', '55', '83', '49', '91', '82', '97'), +('7', '7', '56', '85', '50', '93', '83', '98'), +('7', '7', '57', '86', '50', '94', '85', '100'), +('7', '7', '58', '87', '51', '96', '86', '102'), +('7', '7', '59', '89', '52', '97', '88', '103'), +('7', '7', '60', '90', '53', '99', '89', '105'), +('7', '7', '61', '92', '54', '101', '91', '107'), +('7', '7', '62', '93', '54', '102', '92', '109'), +('7', '7', '63', '95', '55', '104', '94', '110'), +('7', '7', '64', '96', '56', '106', '95', '112'), +('7', '7', '65', '97', '57', '107', '97', '114'), +('7', '7', '66', '99', '58', '109', '99', '116'), +('7', '7', '67', '100', '58', '111', '100', '118'), +('7', '7', '68', '102', '59', '113', '102', '119'), +('7', '7', '69', '103', '60', '114', '103', '121'), +('7', '7', '70', '105', '61', '116', '105', '123'), +('7', '7', '71', '106', '62', '118', '117', '125'), +('7', '7', '72', '108', '63', '120', '119', '128'), +('7', '7', '73', '110', '64', '122', '122', '130'), +('7', '7', '74', '112', '65', '125', '124', '132'), +('7', '7', '75', '114', '66', '127', '126', '134'), +('7', '7', '76', '116', '67', '129', '128', '137'), +('7', '7', '77', '117', '68', '131', '128', '139'), +('7', '7', '78', '119', '69', '133', '133', '141'), +('7', '7', '79', '121', '70', '136', '135', '144'), +('7', '7', '80', '123', '71', '138', '137', '146'), +('7', '11', '1', '18', '25', '19', '22', '22'), +('7', '11', '2', '19', '25', '20', '23', '23'), +('7', '11', '3', '19', '26', '20', '24', '24'), +('7', '11', '4', '20', '26', '21', '25', '26'), +('7', '11', '5', '20', '27', '22', '26', '27'), +('7', '11', '6', '21', '27', '22', '27', '28'), +('7', '11', '7', '21', '28', '23', '28', '29'), +('7', '11', '8', '22', '28', '24', '29', '30'), +('7', '11', '9', '23', '29', '24', '30', '32'), +('7', '11', '10', '23', '29', '25', '32', '33'), +('7', '11', '11', '24', '30', '26', '33', '34'), +('7', '11', '12', '24', '31', '26', '34', '35'), +('7', '11', '13', '25', '31', '27', '35', '37'), +('7', '11', '14', '26', '32', '28', '36', '38'), +('7', '11', '15', '26', '32', '29', '37', '39'), +('7', '11', '16', '27', '33', '29', '38', '41'), +('7', '11', '17', '28', '33', '30', '40', '42'), +('7', '11', '18', '28', '34', '31', '41', '43'), +('7', '11', '19', '29', '35', '32', '42', '45'), +('7', '11', '20', '30', '35', '32', '43', '46'), +('7', '11', '21', '30', '36', '33', '45', '48'), +('7', '11', '22', '31', '36', '34', '46', '49'), +('7', '11', '23', '32', '37', '35', '47', '51'), +('7', '11', '24', '32', '38', '36', '48', '52'), +('7', '11', '25', '33', '38', '36', '50', '53'), +('7', '11', '26', '34', '39', '37', '51', '55'), +('7', '11', '27', '35', '40', '38', '52', '56'), +('7', '11', '28', '35', '40', '39', '54', '58'), +('7', '11', '29', '36', '41', '40', '55', '59'), +('7', '11', '30', '37', '42', '41', '56', '61'), +('7', '11', '31', '38', '42', '42', '58', '62'), +('7', '11', '32', '38', '43', '42', '59', '64'), +('7', '11', '33', '39', '44', '43', '60', '66'), +('7', '11', '34', '40', '44', '44', '62', '67'), +('7', '11', '35', '41', '45', '45', '63', '69'), +('7', '11', '36', '42', '46', '46', '65', '70'), +('7', '11', '37', '42', '47', '47', '66', '72'), +('7', '11', '38', '43', '47', '48', '67', '74'), +('7', '11', '39', '44', '48', '49', '69', '75'), +('7', '11', '40', '45', '49', '50', '70', '77'), +('7', '11', '41', '46', '50', '51', '72', '79'), +('7', '11', '42', '46', '50', '52', '73', '80'), +('7', '11', '43', '47', '51', '53', '75', '82'), +('7', '11', '44', '48', '52', '54', '76', '84'), +('7', '11', '45', '49', '53', '55', '78', '85'), +('7', '11', '46', '50', '54', '56', '79', '87'), +('7', '11', '47', '51', '54', '57', '81', '89'), +('7', '11', '48', '52', '55', '58', '83', '91'), +('7', '11', '49', '53', '56', '59', '84', '93'), +('7', '11', '50', '53', '57', '60', '86', '94'), +('7', '11', '51', '54', '58', '61', '87', '96'), +('7', '11', '52', '55', '59', '62', '89', '98'), +('7', '11', '53', '56', '59', '63', '91', '100'), +('7', '11', '54', '57', '60', '64', '92', '102'), +('7', '11', '55', '58', '61', '65', '94', '103'), +('7', '11', '56', '59', '62', '66', '95', '105'), +('7', '11', '57', '60', '63', '67', '97', '107'), +('7', '11', '58', '61', '64', '68', '99', '109'), +('7', '11', '59', '62', '65', '69', '101', '111'), +('7', '11', '60', '63', '66', '70', '102', '113'), +('7', '11', '61', '64', '66', '72', '104', '115'), +('7', '11', '62', '65', '67', '73', '106', '117'), +('7', '11', '63', '66', '68', '74', '107', '119'), +('7', '11', '64', '67', '69', '75', '109', '121'), +('7', '11', '65', '68', '70', '76', '111', '123'), +('7', '11', '66', '69', '71', '77', '113', '125'), +('7', '11', '67', '70', '72', '78', '115', '127'), +('7', '11', '68', '71', '73', '80', '116', '129'), +('7', '11', '69', '72', '74', '81', '118', '131'), +('7', '11', '70', '73', '75', '82', '120', '133'), +('7', '11', '71', '75', '76', '83', '122', '135'), +('7', '11', '72', '76', '78', '85', '125', '138'), +('7', '11', '73', '77', '79', '86', '127', '140'), +('7', '11', '74', '78', '80', '88', '131', '143'), +('7', '11', '75', '80', '81', '89', '133', '145'), +('7', '11', '76', '81', '82', '91', '134', '148'), +('7', '11', '77', '82', '83', '92', '136', '151'), +('7', '11', '78', '84', '85', '94', '138', '153'), +('7', '11', '79', '85', '86', '95', '141', '156'), +('7', '11', '80', '86', '87', '97', '143', '159'), +('1', '3', '1', '23', '20', '23', '17', '24'), +('1', '3', '2', '23', '21', '24', '18', '25'), +('1', '3', '3', '24', '23', '25', '18', '25'), +('1', '3', '4', '24', '24', '26', '19', '26'), +('1', '3', '5', '25', '25', '27', '19', '26'), +('1', '3', '6', '25', '27', '28', '20', '27'), +('1', '3', '7', '26', '28', '28', '21', '28'), +('1', '3', '8', '26', '30', '29', '21', '28'), +('1', '3', '9', '26', '31', '30', '22', '29'), +('1', '3', '10', '27', '33', '31', '22', '30'), +('1', '3', '11', '27', '34', '32', '23', '30'), +('1', '3', '12', '28', '36', '33', '24', '31'), +('1', '3', '13', '28', '37', '34', '24', '32'), +('1', '3', '14', '29', '39', '35', '25', '33'), +('1', '3', '15', '29', '40', '36', '26', '33'), +('1', '3', '16', '30', '42', '37', '26', '34'), +('1', '3', '17', '30', '43', '39', '27', '35'), +('1', '3', '18', '31', '45', '40', '28', '35'), +('1', '3', '19', '31', '47', '41', '28', '36'), +('1', '3', '20', '32', '48', '42', '29', '37'), +('1', '3', '21', '32', '50', '43', '30', '38'), +('1', '3', '22', '33', '51', '44', '31', '39'), +('1', '3', '23', '34', '53', '45', '31', '39'), +('1', '3', '24', '34', '55', '46', '32', '40'), +('1', '3', '25', '35', '57', '47', '33', '41'), +('1', '3', '26', '35', '58', '48', '34', '42'), +('1', '3', '27', '36', '60', '50', '34', '43'), +('1', '3', '28', '36', '62', '51', '35', '43'), +('1', '3', '29', '37', '63', '52', '36', '44'), +('1', '3', '30', '38', '65', '53', '37', '45'), +('1', '3', '31', '38', '67', '54', '37', '46'), +('1', '3', '32', '39', '69', '56', '38', '47'), +('1', '3', '33', '39', '71', '57', '39', '48'), +('1', '3', '34', '40', '72', '58', '40', '49'), +('1', '3', '35', '41', '74', '59', '41', '49'), +('1', '3', '36', '41', '76', '61', '42', '50'), +('1', '3', '37', '42', '78', '62', '42', '51'), +('1', '3', '38', '43', '80', '63', '43', '52'), +('1', '3', '39', '43', '82', '64', '44', '53'), +('1', '3', '40', '44', '84', '66', '45', '54'), +('1', '3', '41', '45', '86', '67', '46', '55'), +('1', '3', '42', '45', '88', '68', '47', '56'), +('1', '3', '43', '46', '90', '70', '47', '57'), +('1', '3', '44', '47', '91', '71', '48', '58'), +('1', '3', '45', '47', '93', '72', '49', '59'), +('1', '3', '46', '48', '95', '74', '50', '60'), +('1', '3', '47', '49', '98', '75', '51', '61'), +('1', '3', '48', '50', '100', '77', '52', '62'), +('1', '3', '49', '50', '102', '78', '53', '63'), +('1', '3', '50', '51', '104', '79', '54', '64'), +('1', '3', '51', '52', '106', '81', '55', '65'), +('1', '3', '52', '52', '108', '82', '56', '66'), +('1', '3', '53', '53', '110', '84', '57', '67'), +('1', '3', '54', '54', '112', '85', '58', '68'), +('1', '3', '55', '55', '114', '87', '59', '69'), +('1', '3', '56', '55', '116', '88', '60', '70'), +('1', '3', '57', '56', '118', '90', '61', '71'), +('1', '3', '58', '57', '121', '91', '62', '72'), +('1', '3', '59', '58', '123', '93', '63', '73'), +('1', '3', '60', '59', '125', '94', '64', '74'), +('1', '3', '61', '59', '127', '96', '65', '76'), +('1', '3', '62', '60', '130', '97', '66', '77'), +('1', '3', '63', '61', '132', '99', '67', '78'), +('1', '3', '64', '62', '134', '100', '68', '79'), +('1', '3', '65', '63', '136', '102', '69', '80'), +('1', '3', '66', '64', '139', '104', '70', '81'), +('1', '3', '67', '64', '141', '105', '71', '82'), +('1', '3', '68', '65', '143', '107', '72', '84'), +('1', '3', '69', '66', '146', '108', '73', '85'), +('1', '3', '70', '67', '148', '110', '74', '86'), +('1', '3', '71', '68', '151', '112', '75', '87'), +('1', '3', '72', '69', '154', '114', '76', '88'), +('1', '3', '73', '70', '157', '116', '77', '90'), +('1', '3', '74', '71', '160', '118', '79', '91'), +('1', '3', '75', '72', '163', '120', '80', '93'), +('1', '3', '76', '73', '166', '122', '81', '94'), +('1', '3', '77', '74', '169', '124', '83', '96'), +('1', '3', '78', '75', '172', '126', '84', '97'), +('1', '3', '79', '76', '175', '128', '85', '99'), +('1', '3', '80', '77', '178', '130', '87', '100'), +('1', '7', '1', '24', '17', '23', '18', '25'), +('1', '7', '2', '25', '17', '24', '19', '26'), +('1', '7', '3', '26', '18', '25', '20', '27'), +('1', '7', '4', '26', '18', '26', '21', '28'), +('1', '7', '5', '27', '19', '27', '22', '29'), +('1', '7', '6', '28', '19', '28', '23', '30'), +('1', '7', '7', '29', '20', '29', '24', '31'), +('1', '7', '8', '30', '20', '30', '25', '32'), +('1', '7', '9', '31', '21', '31', '26', '33'), +('1', '7', '10', '32', '21', '32', '27', '34'), +('1', '7', '11', '33', '22', '33', '28', '36'), +('1', '7', '12', '34', '22', '34', '29', '37'), +('1', '7', '13', '34', '23', '35', '30', '38'), +('1', '7', '14', '35', '23', '36', '31', '39'), +('1', '7', '15', '36', '24', '37', '32', '40'), +('1', '7', '16', '37', '24', '39', '33', '41'), +('1', '7', '17', '38', '25', '40', '34', '43'), +('1', '7', '18', '39', '25', '41', '35', '44'), +('1', '7', '19', '40', '26', '42', '36', '45'), +('1', '7', '20', '41', '26', '43', '37', '46'), +('1', '7', '21', '42', '27', '44', '38', '47'), +('1', '7', '22', '43', '27', '45', '39', '49'), +('1', '7', '23', '44', '28', '47', '40', '50'), +('1', '7', '24', '45', '28', '48', '41', '51'), +('1', '7', '25', '47', '29', '49', '43', '52'), +('1', '7', '26', '48', '30', '50', '44', '54'), +('1', '7', '27', '49', '30', '52', '45', '55'), +('1', '7', '28', '50', '31', '53', '46', '56'), +('1', '7', '29', '51', '31', '54', '47', '58'), +('1', '7', '30', '52', '32', '55', '48', '59'), +('1', '7', '31', '53', '33', '57', '50', '60'), +('1', '7', '32', '54', '33', '58', '51', '62'), +('1', '7', '33', '55', '34', '59', '52', '63'), +('1', '7', '34', '57', '34', '61', '53', '65'), +('1', '7', '35', '58', '35', '62', '55', '66'), +('1', '7', '36', '59', '36', '63', '56', '67'), +('1', '7', '37', '60', '36', '65', '57', '69'), +('1', '7', '38', '61', '37', '66', '58', '70'), +('1', '7', '39', '62', '38', '67', '60', '72'), +('1', '7', '40', '64', '38', '69', '61', '73'), +('1', '7', '41', '65', '39', '70', '62', '75'), +('1', '7', '42', '66', '40', '72', '64', '76'), +('1', '7', '43', '67', '40', '73', '65', '78'), +('1', '7', '44', '69', '41', '74', '66', '79'), +('1', '7', '45', '70', '42', '76', '68', '81'), +('1', '7', '46', '71', '42', '77', '69', '82'), +('1', '7', '47', '72', '43', '79', '70', '84'), +('1', '7', '48', '74', '44', '80', '72', '85'), +('1', '7', '49', '75', '45', '82', '73', '87'), +('1', '7', '50', '76', '45', '83', '75', '89'), +('1', '7', '51', '78', '46', '85', '76', '90'), +('1', '7', '52', '79', '47', '86', '77', '92'), +('1', '7', '53', '80', '47', '88', '79', '93'), +('1', '7', '54', '82', '48', '90', '80', '95'), +('1', '7', '55', '83', '49', '91', '82', '97'), +('1', '7', '56', '85', '50', '93', '83', '98'), +('1', '7', '57', '86', '50', '94', '85', '100'), +('1', '7', '58', '87', '51', '96', '86', '102'), +('1', '7', '59', '89', '52', '97', '88', '103'), +('1', '7', '60', '90', '53', '99', '89', '105'), +('1', '7', '61', '92', '54', '101', '91', '107'), +('1', '7', '62', '93', '54', '102', '92', '109'), +('1', '7', '63', '95', '55', '104', '94', '110'), +('1', '7', '64', '96', '56', '106', '95', '112'), +('1', '7', '65', '97', '57', '107', '97', '114'), +('1', '7', '66', '99', '58', '109', '99', '116'), +('1', '7', '67', '100', '58', '111', '100', '118'), +('1', '7', '68', '102', '59', '113', '102', '119'), +('1', '7', '69', '103', '60', '114', '103', '121'), +('1', '7', '70', '105', '61', '116', '105', '123'), +('1', '7', '71', '106', '62', '118', '117', '125'), +('1', '7', '72', '108', '63', '120', '119', '128'), +('1', '7', '73', '110', '64', '122', '122', '130'), +('1', '7', '74', '112', '65', '125', '124', '132'), +('1', '7', '75', '114', '66', '127', '126', '134'), +('1', '7', '76', '116', '67', '129', '128', '137'), +('1', '7', '77', '117', '68', '131', '128', '139'), +('1', '7', '78', '119', '69', '133', '133', '141'), +('1', '7', '79', '121', '70', '136', '135', '144'), +('1', '7', '80', '123', '71', '138', '137', '146'), +('1', '11', '1', '18', '25', '19', '22', '22'), +('1', '11', '2', '19', '25', '20', '23', '23'), +('1', '11', '3', '19', '26', '20', '24', '24'), +('1', '11', '4', '20', '26', '21', '25', '26'), +('1', '11', '5', '20', '27', '22', '26', '27'), +('1', '11', '6', '21', '27', '22', '27', '28'), +('1', '11', '7', '21', '28', '23', '28', '29'), +('1', '11', '8', '22', '28', '24', '29', '30'), +('1', '11', '9', '23', '29', '24', '30', '32'), +('1', '11', '10', '23', '29', '25', '32', '33'), +('1', '11', '11', '24', '30', '26', '33', '34'), +('1', '11', '12', '24', '31', '26', '34', '35'), +('1', '11', '13', '25', '31', '27', '35', '37'), +('1', '11', '14', '26', '32', '28', '36', '38'), +('1', '11', '15', '26', '32', '29', '37', '39'), +('1', '11', '16', '27', '33', '29', '38', '41'), +('1', '11', '17', '28', '33', '30', '40', '42'), +('1', '11', '18', '28', '34', '31', '41', '43'), +('1', '11', '19', '29', '35', '32', '42', '45'), +('1', '11', '20', '30', '35', '32', '43', '46'), +('1', '11', '21', '30', '36', '33', '45', '48'), +('1', '11', '22', '31', '36', '34', '46', '49'), +('1', '11', '23', '32', '37', '35', '47', '51'), +('1', '11', '24', '32', '38', '36', '48', '52'), +('1', '11', '25', '33', '38', '36', '50', '53'), +('1', '11', '26', '34', '39', '37', '51', '55'), +('1', '11', '27', '35', '40', '38', '52', '56'), +('1', '11', '28', '35', '40', '39', '54', '58'), +('1', '11', '29', '36', '41', '40', '55', '59'), +('1', '11', '30', '37', '42', '41', '56', '61'), +('1', '11', '31', '38', '42', '42', '58', '62'), +('1', '11', '32', '38', '43', '42', '59', '64'), +('1', '11', '33', '39', '44', '43', '60', '66'), +('1', '11', '34', '40', '44', '44', '62', '67'), +('1', '11', '35', '41', '45', '45', '63', '69'), +('1', '11', '36', '42', '46', '46', '65', '70'), +('1', '11', '37', '42', '47', '47', '66', '72'), +('1', '11', '38', '43', '47', '48', '67', '74'), +('1', '11', '39', '44', '48', '49', '69', '75'), +('1', '11', '40', '45', '49', '50', '70', '77'), +('1', '11', '41', '46', '50', '51', '72', '79'), +('1', '11', '42', '46', '50', '52', '73', '80'), +('1', '11', '43', '47', '51', '53', '75', '82'), +('1', '11', '44', '48', '52', '54', '76', '84'), +('1', '11', '45', '49', '53', '55', '78', '85'), +('1', '11', '46', '50', '54', '56', '79', '87'), +('1', '11', '47', '51', '54', '57', '81', '89'), +('1', '11', '48', '52', '55', '58', '83', '91'), +('1', '11', '49', '53', '56', '59', '84', '93'), +('1', '11', '50', '53', '57', '60', '86', '94'), +('1', '11', '51', '54', '58', '61', '87', '96'), +('1', '11', '52', '55', '59', '62', '89', '98'), +('1', '11', '53', '56', '59', '63', '91', '100'), +('1', '11', '54', '57', '60', '64', '92', '102'), +('1', '11', '55', '58', '61', '65', '94', '103'), +('1', '11', '56', '59', '62', '66', '95', '105'), +('1', '11', '57', '60', '63', '67', '97', '107'), +('1', '11', '58', '61', '64', '68', '99', '109'), +('1', '11', '59', '62', '65', '69', '101', '111'), +('1', '11', '60', '63', '66', '70', '102', '113'), +('1', '11', '61', '64', '66', '72', '104', '115'), +('1', '11', '62', '65', '67', '73', '106', '117'), +('1', '11', '63', '66', '68', '74', '107', '119'), +('1', '11', '64', '67', '69', '75', '109', '121'), +('1', '11', '65', '68', '70', '76', '111', '123'), +('1', '11', '66', '69', '71', '77', '113', '125'), +('1', '11', '67', '70', '72', '78', '115', '127'), +('1', '11', '68', '71', '73', '80', '116', '129'), +('1', '11', '69', '72', '74', '81', '118', '131'), +('1', '11', '70', '73', '75', '82', '120', '133'), +('1', '11', '71', '75', '76', '83', '122', '135'), +('1', '11', '72', '76', '78', '85', '125', '138'), +('1', '11', '73', '77', '79', '86', '127', '140'), +('1', '11', '74', '78', '80', '88', '131', '143'), +('1', '11', '75', '80', '81', '89', '133', '145'), +('1', '11', '76', '81', '82', '91', '134', '148'), +('1', '11', '77', '82', '83', '92', '136', '151'), +('1', '11', '78', '84', '85', '94', '138', '153'), +('1', '11', '79', '85', '86', '95', '141', '156'), +('1', '11', '80', '86', '87', '97', '143', '159'), +('4', '2', '1', '22', '20', '22', '20', '21'), +('4', '2', '2', '23', '21', '23', '21', '22'), +('4', '2', '3', '24', '21', '24', '21', '22'), +('4', '2', '4', '25', '22', '25', '22', '23'), +('4', '2', '5', '26', '22', '26', '23', '24'), +('4', '2', '6', '28', '23', '27', '23', '25'), +('4', '2', '7', '29', '24', '28', '24', '25'), +('4', '2', '8', '30', '24', '29', '25', '26'), +('4', '2', '9', '31', '25', '30', '25', '27'), +('4', '2', '10', '32', '25', '32', '26', '27'), +('4', '2', '11', '33', '26', '33', '27', '28'), +('4', '2', '12', '35', '27', '34', '27', '29'), +('4', '2', '13', '36', '27', '35', '28', '30'), +('4', '2', '14', '37', '28', '36', '29', '31'), +('4', '2', '15', '38', '29', '37', '30', '31'), +('4', '2', '16', '40', '29', '38', '30', '32'), +('4', '2', '17', '41', '30', '40', '31', '33'), +('4', '2', '18', '42', '31', '41', '32', '34'), +('4', '2', '19', '43', '31', '42', '33', '35'), +('4', '2', '20', '45', '32', '43', '33', '35'), +('4', '2', '21', '46', '33', '45', '34', '36'), +('4', '2', '22', '47', '33', '46', '35', '37'), +('4', '2', '23', '49', '34', '47', '36', '38'), +('4', '2', '24', '50', '35', '48', '37', '39'), +('4', '2', '25', '51', '36', '50', '37', '40'), +('4', '2', '26', '53', '36', '51', '38', '41'), +('4', '2', '27', '54', '37', '52', '39', '42'), +('4', '2', '28', '56', '38', '54', '40', '43'), +('4', '2', '29', '57', '39', '55', '41', '43'), +('4', '2', '30', '58', '39', '56', '42', '44'), +('4', '2', '31', '60', '40', '58', '43', '45'), +('4', '2', '32', '61', '41', '59', '43', '46'), +('4', '2', '33', '63', '42', '60', '44', '47'), +('4', '2', '34', '64', '43', '62', '45', '48'), +('4', '2', '35', '66', '44', '63', '46', '49'), +('4', '2', '36', '67', '44', '65', '47', '50'), +('4', '2', '37', '69', '45', '66', '48', '51'), +('4', '2', '38', '70', '46', '67', '49', '52'), +('4', '2', '39', '72', '47', '69', '50', '53'), +('4', '2', '40', '73', '48', '70', '51', '54'), +('4', '2', '41', '75', '49', '72', '52', '55'), +('4', '2', '42', '77', '49', '73', '53', '56'), +('4', '2', '43', '78', '50', '75', '54', '57'), +('4', '2', '44', '80', '51', '76', '55', '58'), +('4', '2', '45', '81', '52', '78', '56', '59'), +('4', '2', '46', '83', '53', '79', '57', '61'), +('4', '2', '47', '85', '54', '81', '58', '62'), +('4', '2', '48', '86', '55', '83', '59', '63'), +('4', '2', '49', '88', '56', '84', '60', '64'), +('4', '2', '50', '90', '57', '86', '61', '65'), +('4', '2', '51', '91', '58', '87', '62', '66'), +('4', '2', '52', '93', '59', '89', '63', '67'), +('4', '2', '53', '95', '60', '91', '64', '68'), +('4', '2', '54', '97', '61', '92', '65', '69'), +('4', '2', '55', '98', '61', '94', '66', '71'), +('4', '2', '56', '100', '62', '95', '67', '72'), +('4', '2', '57', '102', '63', '97', '68', '73'), +('4', '2', '58', '104', '64', '99', '69', '74'), +('4', '2', '59', '105', '65', '101', '70', '75'), +('4', '2', '60', '107', '66', '102', '71', '77'), +('4', '2', '61', '109', '67', '104', '73', '78'), +('4', '2', '62', '111', '69', '106', '74', '79'), +('4', '2', '63', '113', '70', '107', '75', '80'), +('4', '2', '64', '115', '71', '109', '76', '81'), +('4', '2', '65', '116', '72', '111', '77', '83'), +('4', '2', '66', '118', '73', '113', '78', '84'), +('4', '2', '67', '120', '74', '115', '79', '85'), +('4', '2', '68', '122', '75', '116', '81', '86'), +('4', '2', '69', '124', '76', '118', '82', '88'), +('4', '2', '70', '126', '77', '120', '83', '89'), +('4', '2', '71', '148', '78', '122', '84', '92'), +('4', '2', '72', '150', '79', '125', '86', '94'), +('4', '2', '73', '152', '80', '127', '87', '96'), +('4', '2', '74', '156', '82', '129', '89', '97'), +('4', '2', '75', '158', '83', '131', '90', '99'), +('4', '2', '76', '162', '84', '134', '92', '100'), +('4', '2', '77', '164', '86', '136', '93', '103'), +('4', '2', '78', '167', '87', '138', '95', '105'), +('4', '2', '79', '170', '88', '153', '96', '106'), +('4', '2', '80', '173', '90', '160', '98', '108'), +('4', '7', '1', '24', '17', '23', '18', '25'), +('4', '7', '2', '25', '17', '24', '19', '26'), +('4', '7', '3', '26', '18', '25', '20', '27'), +('4', '7', '4', '26', '18', '26', '21', '28'), +('4', '7', '5', '27', '19', '27', '22', '29'), +('4', '7', '6', '28', '19', '28', '23', '30'), +('4', '7', '7', '29', '20', '29', '24', '31'), +('4', '7', '8', '30', '20', '30', '25', '32'), +('4', '7', '9', '31', '21', '31', '26', '33'), +('4', '7', '10', '32', '21', '32', '27', '34'), +('4', '7', '11', '33', '22', '33', '28', '36'), +('4', '7', '12', '34', '22', '34', '29', '37'), +('4', '7', '13', '34', '23', '35', '30', '38'), +('4', '7', '14', '35', '23', '36', '31', '39'), +('4', '7', '15', '36', '24', '37', '32', '40'), +('4', '7', '16', '37', '24', '39', '33', '41'), +('4', '7', '17', '38', '25', '40', '34', '43'), +('4', '7', '18', '39', '25', '41', '35', '44'), +('4', '7', '19', '40', '26', '42', '36', '45'), +('4', '7', '20', '41', '26', '43', '37', '46'), +('4', '7', '21', '42', '27', '44', '38', '47'), +('4', '7', '22', '43', '27', '45', '39', '49'), +('4', '7', '23', '44', '28', '47', '40', '50'), +('4', '7', '24', '45', '28', '48', '41', '51'), +('4', '7', '25', '47', '29', '49', '43', '52'), +('4', '7', '26', '48', '30', '50', '44', '54'), +('4', '7', '27', '49', '30', '52', '45', '55'), +('4', '7', '28', '50', '31', '53', '46', '56'), +('4', '7', '29', '51', '31', '54', '47', '58'), +('4', '7', '30', '52', '32', '55', '48', '59'), +('4', '7', '31', '53', '33', '57', '50', '60'), +('4', '7', '32', '54', '33', '58', '51', '62'), +('4', '7', '33', '55', '34', '59', '52', '63'), +('4', '7', '34', '57', '34', '61', '53', '65'), +('4', '7', '35', '58', '35', '62', '55', '66'), +('4', '7', '36', '59', '36', '63', '56', '67'), +('4', '7', '37', '60', '36', '65', '57', '69'), +('4', '7', '38', '61', '37', '66', '58', '70'), +('4', '7', '39', '62', '38', '67', '60', '72'), +('4', '7', '40', '64', '38', '69', '61', '73'), +('4', '7', '41', '65', '39', '70', '62', '75'), +('4', '7', '42', '66', '40', '72', '64', '76'), +('4', '7', '43', '67', '40', '73', '65', '78'), +('4', '7', '44', '69', '41', '74', '66', '79'), +('4', '7', '45', '70', '42', '76', '68', '81'), +('4', '7', '46', '71', '42', '77', '69', '82'), +('4', '7', '47', '72', '43', '79', '70', '84'), +('4', '7', '48', '74', '44', '80', '72', '85'), +('4', '7', '49', '75', '45', '82', '73', '87'), +('4', '7', '50', '76', '45', '83', '75', '89'), +('4', '7', '51', '78', '46', '85', '76', '90'), +('4', '7', '52', '79', '47', '86', '77', '92'), +('4', '7', '53', '80', '47', '88', '79', '93'), +('4', '7', '54', '82', '48', '90', '80', '95'), +('4', '7', '55', '83', '49', '91', '82', '97'), +('4', '7', '56', '85', '50', '93', '83', '98'), +('4', '7', '57', '86', '50', '94', '85', '100'), +('4', '7', '58', '87', '51', '96', '86', '102'), +('4', '7', '59', '89', '52', '97', '88', '103'), +('4', '7', '60', '90', '53', '99', '89', '105'), +('4', '7', '61', '92', '54', '101', '91', '107'), +('4', '7', '62', '93', '54', '102', '92', '109'), +('4', '7', '63', '95', '55', '104', '94', '110'), +('4', '7', '64', '96', '56', '106', '95', '112'), +('4', '7', '65', '97', '57', '107', '97', '114'), +('4', '7', '66', '99', '58', '109', '99', '116'), +('4', '7', '67', '100', '58', '111', '100', '118'), +('4', '7', '68', '102', '59', '113', '102', '119'), +('4', '7', '69', '103', '60', '114', '103', '121'), +('4', '7', '70', '105', '61', '116', '105', '123'), +('4', '7', '71', '106', '62', '118', '117', '125'), +('4', '7', '72', '108', '63', '120', '119', '128'), +('4', '7', '73', '110', '64', '122', '122', '130'), +('4', '7', '74', '112', '65', '125', '124', '132'), +('4', '7', '75', '114', '66', '127', '126', '134'), +('4', '7', '76', '116', '67', '129', '128', '137'), +('4', '7', '77', '117', '68', '131', '128', '139'), +('4', '7', '78', '119', '69', '133', '133', '141'), +('4', '7', '79', '121', '70', '136', '135', '144'), +('4', '7', '80', '123', '71', '138', '137', '146'), +('4', '8', '1', '20', '20', '20', '23', '22'), +('4', '8', '2', '20', '20', '20', '24', '23'), +('4', '8', '3', '20', '20', '21', '26', '25'), +('4', '8', '4', '20', '20', '21', '27', '26'), +('4', '8', '5', '20', '21', '21', '28', '27'), +('4', '8', '6', '20', '21', '21', '30', '29'), +('4', '8', '7', '21', '21', '22', '31', '30'), +('4', '8', '8', '21', '21', '22', '33', '31'), +('4', '8', '9', '21', '21', '22', '34', '33'), +('4', '8', '10', '21', '21', '23', '36', '34'), +('4', '8', '11', '21', '22', '23', '37', '36'), +('4', '8', '12', '21', '22', '23', '39', '37'), +('4', '8', '13', '21', '22', '24', '40', '38'), +('4', '8', '14', '21', '22', '24', '42', '40'), +('4', '8', '15', '21', '22', '24', '43', '41'), +('4', '8', '16', '21', '23', '25', '45', '43'), +('4', '8', '17', '22', '23', '25', '46', '44'), +('4', '8', '18', '22', '23', '25', '48', '46'), +('4', '8', '19', '22', '23', '26', '49', '47'), +('4', '8', '20', '22', '23', '26', '51', '49'), +('4', '8', '21', '22', '24', '26', '53', '51'), +('4', '8', '22', '22', '24', '27', '54', '52'), +('4', '8', '23', '22', '24', '27', '56', '54'), +('4', '8', '24', '23', '24', '28', '58', '55'), +('4', '8', '25', '23', '25', '28', '59', '57'), +('4', '8', '26', '23', '25', '28', '61', '59'), +('4', '8', '27', '23', '25', '29', '63', '60'), +('4', '8', '28', '23', '25', '29', '65', '62'), +('4', '8', '29', '23', '25', '30', '66', '64'), +('4', '8', '30', '24', '26', '30', '68', '65'), +('4', '8', '31', '24', '26', '30', '70', '67'), +('4', '8', '32', '24', '26', '31', '72', '69'), +('4', '8', '33', '24', '27', '31', '73', '70'), +('4', '8', '34', '24', '27', '32', '75', '72'), +('4', '8', '35', '24', '27', '32', '77', '74'), +('4', '8', '36', '25', '27', '33', '79', '76'), +('4', '8', '37', '25', '28', '33', '81', '78'), +('4', '8', '38', '25', '28', '34', '83', '79'), +('4', '8', '39', '25', '28', '34', '85', '81'), +('4', '8', '40', '25', '28', '35', '87', '83'), +('4', '8', '41', '26', '29', '35', '88', '85'), +('4', '8', '42', '26', '29', '35', '90', '87'), +('4', '8', '43', '26', '29', '36', '92', '89'), +('4', '8', '44', '26', '30', '36', '94', '91'), +('4', '8', '45', '26', '30', '37', '96', '92'), +('4', '8', '46', '27', '30', '37', '98', '94'), +('4', '8', '47', '27', '31', '38', '100', '96'), +('4', '8', '48', '27', '31', '38', '102', '98'), +('4', '8', '49', '27', '31', '39', '104', '100'), +('4', '8', '50', '28', '32', '40', '106', '102'), +('4', '8', '51', '28', '32', '40', '109', '104'), +('4', '8', '52', '28', '32', '41', '111', '106'), +('4', '8', '53', '28', '33', '41', '113', '108'), +('4', '8', '54', '29', '33', '42', '115', '110'), +('4', '8', '55', '29', '33', '42', '117', '112'), +('4', '8', '56', '29', '34', '43', '119', '114'), +('4', '8', '57', '29', '34', '43', '121', '117'), +('4', '8', '58', '30', '34', '44', '124', '119'), +('4', '8', '59', '30', '35', '44', '126', '121'), +('4', '8', '60', '30', '35', '45', '128', '123'), +('4', '8', '61', '30', '35', '46', '130', '125'), +('4', '8', '62', '31', '36', '46', '132', '127'), +('4', '8', '63', '31', '36', '47', '135', '129'), +('4', '8', '64', '31', '37', '47', '137', '132'), +('4', '8', '65', '32', '37', '48', '139', '134'), +('4', '8', '66', '32', '37', '49', '142', '136'), +('4', '8', '67', '32', '38', '49', '144', '138'), +('4', '8', '68', '32', '38', '50', '146', '140'), +('4', '8', '69', '33', '39', '50', '149', '143'), +('4', '8', '70', '33', '39', '51', '151', '145'), +('4', '8', '71', '33', '39', '52', '154', '152'), +('4', '8', '72', '33', '40', '53', '160', '155'), +('4', '8', '73', '33', '40', '54', '160', '158'), +('4', '8', '74', '34', '41', '54', '163', '160'), +('4', '8', '75', '34', '41', '55', '166', '163'), +('4', '8', '76', '34', '41', '56', '169', '166'), +('4', '8', '77', '35', '42', '57', '172', '169'), +('4', '8', '78', '35', '42', '57', '175', '173'), +('4', '8', '79', '35', '43', '58', '178', '176'), +('4', '8', '80', '36', '43', '59', '181', '179'), +('4', '9', '1', '20', '20', '21', '22', '22'), +('4', '9', '2', '20', '20', '22', '23', '23'), +('4', '9', '3', '21', '21', '22', '24', '24'), +('4', '9', '4', '21', '21', '23', '26', '25'), +('4', '9', '5', '21', '21', '23', '27', '27'), +('4', '9', '6', '21', '22', '24', '28', '28'), +('4', '9', '7', '22', '22', '24', '29', '29'), +('4', '9', '8', '22', '23', '25', '30', '30'), +('4', '9', '9', '22', '23', '26', '32', '31'), +('4', '9', '10', '23', '23', '26', '33', '33'), +('4', '9', '11', '23', '24', '27', '34', '34'), +('4', '9', '12', '23', '24', '27', '35', '35'), +('4', '9', '13', '24', '25', '28', '37', '36'), +('4', '9', '14', '24', '25', '29', '38', '38'), +('4', '9', '15', '24', '25', '29', '39', '39'), +('4', '9', '16', '25', '26', '30', '41', '40'), +('4', '9', '17', '25', '26', '31', '42', '42'), +('4', '9', '18', '25', '27', '31', '43', '43'), +('4', '9', '19', '26', '27', '32', '45', '44'), +('4', '9', '20', '26', '28', '33', '46', '46'), +('4', '9', '21', '26', '28', '33', '48', '47'), +('4', '9', '22', '27', '29', '34', '49', '49'), +('4', '9', '23', '27', '29', '35', '51', '50'), +('4', '9', '24', '28', '30', '35', '52', '51'), +('4', '9', '25', '28', '30', '36', '53', '53'), +('4', '9', '26', '28', '31', '37', '55', '54'), +('4', '9', '27', '29', '31', '37', '56', '56'), +('4', '9', '28', '29', '32', '38', '58', '57'), +('4', '9', '29', '30', '32', '39', '59', '59'), +('4', '9', '30', '30', '33', '40', '61', '60'), +('4', '9', '31', '30', '33', '40', '62', '62'), +('4', '9', '32', '31', '34', '41', '64', '63'), +('4', '9', '33', '31', '34', '42', '66', '65'), +('4', '9', '34', '32', '35', '43', '67', '66'), +('4', '9', '35', '32', '35', '44', '69', '68'), +('4', '9', '36', '33', '36', '44', '70', '69'), +('4', '9', '37', '33', '36', '45', '72', '71'), +('4', '9', '38', '34', '37', '46', '74', '73'), +('4', '9', '39', '34', '38', '47', '75', '74'), +('4', '9', '40', '35', '38', '48', '77', '76'), +('4', '9', '41', '35', '39', '48', '79', '78'), +('4', '9', '42', '35', '39', '49', '80', '79'), +('4', '9', '43', '36', '40', '50', '82', '81'), +('4', '9', '44', '36', '40', '51', '84', '83'), +('4', '9', '45', '37', '41', '52', '85', '84'), +('4', '9', '46', '37', '42', '53', '87', '86'), +('4', '9', '47', '38', '42', '54', '89', '88'), +('4', '9', '48', '38', '43', '55', '91', '89'), +('4', '9', '49', '39', '44', '55', '93', '91'), +('4', '9', '50', '40', '44', '56', '94', '93'), +('4', '9', '51', '40', '45', '57', '96', '95'), +('4', '9', '52', '41', '45', '58', '98', '97'), +('4', '9', '53', '41', '46', '59', '100', '98'), +('4', '9', '54', '42', '47', '60', '102', '100'), +('4', '9', '55', '42', '47', '61', '103', '102'), +('4', '9', '56', '43', '48', '62', '105', '104'), +('4', '9', '57', '43', '49', '63', '107', '106'), +('4', '9', '58', '44', '49', '64', '109', '108'), +('4', '9', '59', '44', '50', '65', '111', '109'), +('4', '9', '60', '45', '51', '66', '113', '111'), +('4', '9', '61', '46', '51', '67', '115', '113'), +('4', '9', '62', '46', '52', '68', '117', '115'), +('4', '9', '63', '47', '53', '69', '119', '117'), +('4', '9', '64', '47', '54', '70', '121', '119'), +('4', '9', '65', '48', '54', '71', '123', '121'), +('4', '9', '66', '49', '55', '72', '125', '123'), +('4', '9', '67', '49', '56', '73', '127', '125'), +('4', '9', '68', '50', '57', '74', '129', '127'), +('4', '9', '69', '50', '57', '75', '131', '129'), +('4', '9', '70', '51', '58', '76', '133', '131'), +('4', '9', '71', '52', '59', '78', '135', '146'), +('4', '9', '72', '53', '59', '79', '138', '148'), +('4', '9', '73', '54', '60', '80', '140', '151'), +('4', '9', '74', '54', '61', '89', '143', '154'), +('4', '9', '75', '55', '62', '91', '145', '156'), +('4', '9', '76', '56', '63', '92', '148', '159'), +('4', '9', '77', '57', '64', '93', '151', '162'), +('4', '9', '78', '57', '65', '95', '153', '165'), +('4', '9', '79', '58', '66', '96', '156', '168'), +('4', '9', '80', '59', '67', '97', '159', '170'), +('2', '5', '1', '20', '20', '20', '22', '23'), +('2', '5', '2', '20', '20', '20', '23', '24'), +('2', '5', '3', '20', '20', '21', '25', '26'), +('2', '5', '4', '20', '21', '21', '26', '27'), +('2', '5', '5', '21', '21', '21', '27', '28'), +('2', '5', '6', '21', '21', '22', '29', '30'), +('2', '5', '7', '21', '21', '22', '30', '31'), +('2', '5', '8', '21', '22', '23', '31', '33'), +('2', '5', '9', '21', '22', '23', '33', '34'), +('2', '5', '10', '21', '22', '23', '34', '36'), +('2', '5', '11', '22', '22', '24', '36', '37'), +('2', '5', '12', '22', '23', '24', '37', '39'), +('2', '5', '13', '22', '23', '25', '38', '40'), +('2', '5', '14', '22', '23', '25', '40', '42'), +('2', '5', '15', '22', '23', '25', '41', '43'), +('2', '5', '16', '23', '24', '26', '43', '45'), +('2', '5', '17', '23', '24', '26', '44', '46'), +('2', '5', '18', '23', '24', '27', '46', '48'), +('2', '5', '19', '23', '24', '27', '47', '49'), +('2', '5', '20', '23', '25', '28', '49', '51'), +('2', '5', '21', '24', '25', '28', '51', '53'), +('2', '5', '22', '24', '25', '29', '52', '54'), +('2', '5', '23', '24', '26', '29', '54', '56'), +('2', '5', '24', '24', '26', '30', '55', '58'), +('2', '5', '25', '25', '26', '30', '57', '59'), +('2', '5', '26', '25', '27', '31', '59', '61'), +('2', '5', '27', '25', '27', '31', '60', '63'), +('2', '5', '28', '25', '27', '32', '62', '65'), +('2', '5', '29', '25', '28', '32', '64', '66'), +('2', '5', '30', '26', '28', '33', '65', '68'), +('2', '5', '31', '26', '28', '33', '67', '70'), +('2', '5', '32', '26', '29', '34', '69', '72'), +('2', '5', '33', '27', '29', '34', '70', '73'), +('2', '5', '34', '27', '29', '35', '72', '75'), +('2', '5', '35', '27', '30', '35', '74', '77'), +('2', '5', '36', '27', '30', '36', '76', '79'), +('2', '5', '37', '28', '30', '36', '78', '81'), +('2', '5', '38', '28', '31', '37', '79', '83'), +('2', '5', '39', '28', '31', '38', '81', '85'), +('2', '5', '40', '28', '31', '38', '83', '87'), +('2', '5', '41', '29', '32', '39', '85', '88'), +('2', '5', '42', '29', '32', '39', '87', '90'), +('2', '5', '43', '29', '33', '40', '89', '92'), +('2', '5', '44', '30', '33', '40', '91', '94'), +('2', '5', '45', '30', '33', '41', '92', '96'), +('2', '5', '46', '30', '34', '42', '94', '98'), +('2', '5', '47', '31', '34', '42', '96', '100'), +('2', '5', '48', '31', '35', '43', '98', '102'), +('2', '5', '49', '31', '35', '44', '100', '104'), +('2', '5', '50', '32', '36', '44', '102', '106'), +('2', '5', '51', '32', '36', '45', '104', '109'), +('2', '5', '52', '32', '36', '45', '106', '111'), +('2', '5', '53', '33', '37', '46', '108', '113'), +('2', '5', '54', '33', '37', '47', '110', '115'), +('2', '5', '55', '33', '38', '47', '112', '117'), +('2', '5', '56', '34', '38', '48', '114', '119'), +('2', '5', '57', '34', '39', '49', '117', '121'), +('2', '5', '58', '34', '39', '49', '119', '124'), +('2', '5', '59', '35', '40', '50', '121', '126'), +('2', '5', '60', '35', '40', '51', '123', '128'), +('2', '5', '61', '35', '41', '51', '125', '130'), +('2', '5', '62', '36', '41', '52', '127', '132'), +('2', '5', '63', '36', '41', '53', '129', '135'), +('2', '5', '64', '37', '42', '54', '132', '137'), +('2', '5', '65', '37', '42', '54', '134', '139'), +('2', '5', '66', '37', '43', '55', '136', '142'), +('2', '5', '67', '38', '43', '56', '138', '144'), +('2', '5', '68', '38', '44', '57', '140', '146'), +('2', '5', '69', '39', '44', '57', '143', '149'), +('2', '5', '70', '39', '45', '58', '145', '151'), +('2', '5', '71', '39', '46', '59', '148', '158'), +('2', '5', '72', '40', '46', '59', '151', '161'), +('2', '5', '73', '40', '47', '60', '154', '164'), +('2', '5', '74', '41', '47', '61', '156', '167'), +('2', '5', '75', '41', '48', '62', '159', '170'), +('2', '5', '76', '41', '49', '63', '162', '174'), +('2', '5', '77', '42', '49', '64', '165', '177'), +('2', '5', '78', '42', '50', '65', '168', '180'), +('2', '5', '79', '43', '50', '66', '171', '183'), +('2', '5', '80', '43', '51', '67', '174', '186'), +('2', '2', '1', '22', '20', '22', '20', '21'), +('2', '2', '2', '23', '21', '23', '21', '22'), +('2', '2', '3', '24', '21', '24', '21', '22'), +('2', '2', '4', '25', '22', '25', '22', '23'), +('2', '2', '5', '26', '22', '26', '23', '24'), +('2', '2', '6', '28', '23', '27', '23', '25'), +('2', '2', '7', '29', '24', '28', '24', '25'), +('2', '2', '8', '30', '24', '29', '25', '26'), +('2', '2', '9', '31', '25', '30', '25', '27'), +('2', '2', '10', '32', '25', '32', '26', '27'), +('2', '2', '11', '33', '26', '33', '27', '28'), +('2', '2', '12', '35', '27', '34', '27', '29'), +('2', '2', '13', '36', '27', '35', '28', '30'), +('2', '2', '14', '37', '28', '36', '29', '31'), +('2', '2', '15', '38', '29', '37', '30', '31'), +('2', '2', '16', '40', '29', '38', '30', '32'), +('2', '2', '17', '41', '30', '40', '31', '33'), +('2', '2', '18', '42', '31', '41', '32', '34'), +('2', '2', '19', '43', '31', '42', '33', '35'), +('2', '2', '20', '45', '32', '43', '33', '35'), +('2', '2', '21', '46', '33', '45', '34', '36'), +('2', '2', '22', '47', '33', '46', '35', '37'), +('2', '2', '23', '49', '34', '47', '36', '38'), +('2', '2', '24', '50', '35', '48', '37', '39'), +('2', '2', '25', '51', '36', '50', '37', '40'), +('2', '2', '26', '53', '36', '51', '38', '41'), +('2', '2', '27', '54', '37', '52', '39', '42'), +('2', '2', '28', '56', '38', '54', '40', '43'), +('2', '2', '29', '57', '39', '55', '41', '43'), +('2', '2', '30', '58', '39', '56', '42', '44'), +('2', '2', '31', '60', '40', '58', '43', '45'), +('2', '2', '32', '61', '41', '59', '43', '46'), +('2', '2', '33', '63', '42', '60', '44', '47'), +('2', '2', '34', '64', '43', '62', '45', '48'), +('2', '2', '35', '66', '44', '63', '46', '49'), +('2', '2', '36', '67', '44', '65', '47', '50'), +('2', '2', '37', '69', '45', '66', '48', '51'), +('2', '2', '38', '70', '46', '67', '49', '52'), +('2', '2', '39', '72', '47', '69', '50', '53'), +('2', '2', '40', '73', '48', '70', '51', '54'), +('2', '2', '41', '75', '49', '72', '52', '55'), +('2', '2', '42', '77', '49', '73', '53', '56'), +('2', '2', '43', '78', '50', '75', '54', '57'), +('2', '2', '44', '80', '51', '76', '55', '58'), +('2', '2', '45', '81', '52', '78', '56', '59'), +('2', '2', '46', '83', '53', '79', '57', '61'), +('2', '2', '47', '85', '54', '81', '58', '62'), +('2', '2', '48', '86', '55', '83', '59', '63'), +('2', '2', '49', '88', '56', '84', '60', '64'), +('2', '2', '50', '90', '57', '86', '61', '65'), +('2', '2', '51', '91', '58', '87', '62', '66'), +('2', '2', '52', '93', '59', '89', '63', '67'), +('2', '2', '53', '95', '60', '91', '64', '68'), +('2', '2', '54', '97', '61', '92', '65', '69'), +('2', '2', '55', '98', '61', '94', '66', '71'), +('2', '2', '56', '100', '62', '95', '67', '72'), +('2', '2', '57', '102', '63', '97', '68', '73'), +('2', '2', '58', '104', '64', '99', '69', '74'), +('2', '2', '59', '105', '65', '101', '70', '75'), +('2', '2', '60', '107', '66', '102', '71', '77'), +('2', '2', '61', '109', '67', '104', '73', '78'), +('2', '2', '62', '111', '69', '106', '74', '79'), +('2', '2', '63', '113', '70', '107', '75', '80'), +('2', '2', '64', '115', '71', '109', '76', '81'), +('2', '2', '65', '116', '72', '111', '77', '83'), +('2', '2', '66', '118', '73', '113', '78', '84'), +('2', '2', '67', '120', '74', '115', '79', '85'), +('2', '2', '68', '122', '75', '116', '81', '86'), +('2', '2', '69', '124', '76', '118', '82', '88'), +('2', '2', '70', '126', '77', '120', '83', '89'), +('2', '2', '71', '148', '78', '122', '84', '92'), +('2', '2', '72', '150', '79', '125', '86', '94'), +('2', '2', '73', '152', '80', '127', '87', '96'), +('2', '2', '74', '156', '82', '129', '89', '97'), +('2', '2', '75', '158', '83', '131', '90', '99'), +('2', '2', '76', '162', '84', '134', '92', '100'), +('2', '2', '77', '164', '86', '136', '93', '103'), +('2', '2', '78', '167', '87', '138', '95', '105'), +('2', '2', '79', '170', '88', '153', '96', '106'), +('2', '2', '80', '173', '90', '160', '98', '108'), +('2', '8', '1', '20', '20', '20', '23', '22'), +('2', '8', '2', '20', '20', '20', '24', '23'), +('2', '8', '3', '20', '20', '21', '26', '25'), +('2', '8', '4', '20', '20', '21', '27', '26'), +('2', '8', '5', '20', '21', '21', '28', '27'), +('2', '8', '6', '20', '21', '21', '30', '29'), +('2', '8', '7', '21', '21', '22', '31', '30'), +('2', '8', '8', '21', '21', '22', '33', '31'), +('2', '8', '9', '21', '21', '22', '34', '33'), +('2', '8', '10', '21', '21', '23', '36', '34'), +('2', '8', '11', '21', '22', '23', '37', '36'), +('2', '8', '12', '21', '22', '23', '39', '37'), +('2', '8', '13', '21', '22', '24', '40', '38'), +('2', '8', '14', '21', '22', '24', '42', '40'), +('2', '8', '15', '21', '22', '24', '43', '41'), +('2', '8', '16', '21', '23', '25', '45', '43'), +('2', '8', '17', '22', '23', '25', '46', '44'), +('2', '8', '18', '22', '23', '25', '48', '46'), +('2', '8', '19', '22', '23', '26', '49', '47'), +('2', '8', '20', '22', '23', '26', '51', '49'), +('2', '8', '21', '22', '24', '26', '53', '51'), +('2', '8', '22', '22', '24', '27', '54', '52'), +('2', '8', '23', '22', '24', '27', '56', '54'), +('2', '8', '24', '23', '24', '28', '58', '55'), +('2', '8', '25', '23', '25', '28', '59', '57'), +('2', '8', '26', '23', '25', '28', '61', '59'), +('2', '8', '27', '23', '25', '29', '63', '60'), +('2', '8', '28', '23', '25', '29', '65', '62'), +('2', '8', '29', '23', '25', '30', '66', '64'), +('2', '8', '30', '24', '26', '30', '68', '65'), +('2', '8', '31', '24', '26', '30', '70', '67'), +('2', '8', '32', '24', '26', '31', '72', '69'), +('2', '8', '33', '24', '27', '31', '73', '70'), +('2', '8', '34', '24', '27', '32', '75', '72'), +('2', '8', '35', '24', '27', '32', '77', '74'), +('2', '8', '36', '25', '27', '33', '79', '76'), +('2', '8', '37', '25', '28', '33', '81', '78'), +('2', '8', '38', '25', '28', '34', '83', '79'), +('2', '8', '39', '25', '28', '34', '85', '81'), +('2', '8', '40', '25', '28', '35', '87', '83'), +('2', '8', '41', '26', '29', '35', '88', '85'), +('2', '8', '42', '26', '29', '35', '90', '87'), +('2', '8', '43', '26', '29', '36', '92', '89'), +('2', '8', '44', '26', '30', '36', '94', '91'), +('2', '8', '45', '26', '30', '37', '96', '92'), +('2', '8', '46', '27', '30', '37', '98', '94'), +('2', '8', '47', '27', '31', '38', '100', '96'), +('2', '8', '48', '27', '31', '38', '102', '98'), +('2', '8', '49', '27', '31', '39', '104', '100'), +('2', '8', '50', '28', '32', '40', '106', '102'), +('2', '8', '51', '28', '32', '40', '109', '104'), +('2', '8', '52', '28', '32', '41', '111', '106'), +('2', '8', '53', '28', '33', '41', '113', '108'), +('2', '8', '54', '29', '33', '42', '115', '110'), +('2', '8', '55', '29', '33', '42', '117', '112'), +('2', '8', '56', '29', '34', '43', '119', '114'), +('2', '8', '57', '29', '34', '43', '121', '117'), +('2', '8', '58', '30', '34', '44', '124', '119'), +('2', '8', '59', '30', '35', '44', '126', '121'), +('2', '8', '60', '30', '35', '45', '128', '123'), +('2', '8', '61', '30', '35', '46', '130', '125'), +('2', '8', '62', '31', '36', '46', '132', '127'), +('2', '8', '63', '31', '36', '47', '135', '129'), +('2', '8', '64', '31', '37', '47', '137', '132'), +('2', '8', '65', '32', '37', '48', '139', '134'), +('2', '8', '66', '32', '37', '49', '142', '136'), +('2', '8', '67', '32', '38', '49', '144', '138'), +('2', '8', '68', '32', '38', '50', '146', '140'), +('2', '8', '69', '33', '39', '50', '149', '143'), +('2', '8', '70', '33', '39', '51', '151', '145'), +('2', '8', '71', '33', '39', '52', '154', '152'), +('2', '8', '72', '33', '40', '53', '160', '155'), +('2', '8', '73', '33', '40', '54', '160', '158'), +('2', '8', '74', '34', '41', '54', '163', '160'), +('2', '8', '75', '34', '41', '55', '166', '163'), +('2', '8', '76', '34', '41', '56', '169', '166'), +('2', '8', '77', '35', '42', '57', '172', '169'), +('2', '8', '78', '35', '42', '57', '175', '173'), +('2', '8', '79', '35', '43', '58', '178', '176'), +('2', '8', '80', '36', '43', '59', '181', '179'), +('2', '11', '1', '26', '15', '22', '17', '24'), +('2', '11', '2', '27', '16', '23', '18', '25'), +('2', '11', '3', '27', '16', '23', '19', '26'), +('2', '11', '4', '28', '17', '24', '20', '27'), +('2', '11', '5', '28', '17', '25', '21', '29'), +('2', '11', '6', '29', '18', '25', '22', '30'), +('2', '11', '7', '29', '18', '26', '23', '31'), +('2', '11', '8', '30', '19', '27', '24', '32'), +('2', '11', '9', '30', '19', '27', '26', '34'), +('2', '11', '10', '31', '20', '28', '27', '35'), +('2', '11', '11', '32', '20', '29', '28', '36'), +('2', '11', '12', '32', '21', '29', '29', '37'), +('2', '11', '13', '33', '21', '30', '30', '39'), +('2', '11', '14', '33', '22', '31', '31', '40'), +('2', '11', '15', '34', '23', '32', '32', '41'), +('2', '11', '16', '35', '23', '32', '34', '43'), +('2', '11', '17', '35', '24', '33', '35', '44'), +('2', '11', '18', '36', '24', '34', '36', '45'), +('2', '11', '19', '37', '25', '35', '37', '47'), +('2', '11', '20', '37', '26', '35', '39', '48'), +('2', '11', '21', '38', '26', '36', '40', '50'), +('2', '11', '22', '39', '27', '37', '41', '51'), +('2', '11', '23', '39', '28', '38', '42', '52'), +('2', '11', '24', '40', '28', '39', '44', '54'), +('2', '11', '25', '41', '29', '39', '45', '55'), +('2', '11', '26', '41', '30', '40', '46', '57'), +('2', '11', '27', '42', '30', '41', '47', '58'), +('2', '11', '28', '43', '31', '42', '49', '60'), +('2', '11', '29', '44', '32', '43', '50', '61'), +('2', '11', '30', '44', '32', '44', '52', '63'), +('2', '11', '31', '45', '33', '44', '53', '64'), +('2', '11', '32', '46', '34', '45', '54', '66'), +('2', '11', '33', '47', '34', '46', '56', '67'), +('2', '11', '34', '47', '35', '47', '57', '69'), +('2', '11', '35', '48', '36', '48', '58', '71'), +('2', '11', '36', '49', '36', '49', '60', '72'), +('2', '11', '37', '50', '37', '50', '61', '74'), +('2', '11', '38', '51', '38', '51', '63', '76'), +('2', '11', '39', '52', '39', '52', '64', '77'), +('2', '11', '40', '52', '39', '53', '66', '79'), +('2', '11', '41', '53', '40', '54', '67', '81'), +('2', '11', '42', '54', '41', '55', '69', '82'), +('2', '11', '43', '55', '42', '56', '70', '84'), +('2', '11', '44', '56', '43', '57', '72', '86'), +('2', '11', '45', '57', '43', '57', '73', '87'), +('2', '11', '46', '57', '44', '58', '75', '89'), +('2', '11', '47', '58', '45', '60', '76', '91'), +('2', '11', '48', '59', '46', '61', '78', '93'), +('2', '11', '49', '60', '47', '62', '79', '94'), +('2', '11', '50', '61', '47', '63', '81', '96'), +('2', '11', '51', '62', '48', '64', '83', '98'), +('2', '11', '52', '63', '49', '65', '84', '100'), +('2', '11', '53', '64', '50', '66', '86', '102'), +('2', '11', '54', '65', '51', '67', '87', '104'), +('2', '11', '55', '66', '51', '68', '89', '105'), +('2', '11', '56', '67', '52', '69', '91', '107'), +('2', '11', '57', '68', '53', '70', '92', '109'), +('2', '11', '58', '69', '54', '71', '94', '111'), +('2', '11', '59', '70', '55', '72', '96', '113'), +('2', '11', '60', '71', '56', '73', '97', '115'), +('2', '11', '61', '72', '57', '74', '99', '117'), +('2', '11', '62', '73', '58', '76', '101', '119'), +('2', '11', '63', '74', '59', '77', '103', '121'), +('2', '11', '64', '75', '59', '78', '104', '123'), +('2', '11', '65', '76', '60', '79', '106', '125'), +('2', '11', '66', '77', '61', '80', '108', '127'), +('2', '11', '67', '78', '62', '81', '110', '129'), +('2', '11', '68', '79', '63', '83', '111', '131'), +('2', '11', '69', '80', '64', '84', '113', '133'), +('2', '11', '70', '81', '65', '85', '115', '135'), +('2', '11', '71', '83', '66', '86', '117', '137'), +('2', '11', '72', '84', '68', '88', '120', '140'), +('2', '11', '73', '85', '69', '89', '122', '142'), +('2', '11', '74', '86', '70', '91', '124', '145'), +('2', '11', '75', '88', '71', '92', '126', '147'), +('2', '11', '76', '89', '72', '94', '128', '150'), +('2', '11', '77', '90', '73', '95', '131', '153'), +('2', '11', '78', '92', '75', '97', '133', '155'), +('2', '11', '79', '93', '76', '98', '136', '158'), +('2', '11', '80', '94', '77', '100', '138', '185'), +('8', '2', '1', '22', '20', '22', '20', '21'), +('8', '2', '2', '23', '21', '23', '21', '22'), +('8', '2', '3', '24', '21', '24', '21', '22'), +('8', '2', '4', '25', '22', '25', '22', '23'), +('8', '2', '5', '26', '22', '26', '23', '24'), +('8', '2', '6', '28', '23', '27', '23', '25'), +('8', '2', '7', '29', '24', '28', '24', '25'), +('8', '2', '8', '30', '24', '29', '25', '26'), +('8', '2', '9', '31', '25', '30', '25', '27'), +('8', '2', '10', '32', '25', '32', '26', '27'), +('8', '2', '11', '33', '26', '33', '27', '28'), +('8', '2', '12', '35', '27', '34', '27', '29'), +('8', '2', '13', '36', '27', '35', '28', '30'), +('8', '2', '14', '37', '28', '36', '29', '31'), +('8', '2', '15', '38', '29', '37', '30', '31'), +('8', '2', '16', '40', '29', '38', '30', '32'), +('8', '2', '17', '41', '30', '40', '31', '33'), +('8', '2', '18', '42', '31', '41', '32', '34'), +('8', '2', '19', '43', '31', '42', '33', '35'), +('8', '2', '20', '45', '32', '43', '33', '35'), +('8', '2', '21', '46', '33', '45', '34', '36'), +('8', '2', '22', '47', '33', '46', '35', '37'), +('8', '2', '23', '49', '34', '47', '36', '38'), +('8', '2', '24', '50', '35', '48', '37', '39'), +('8', '2', '25', '51', '36', '50', '37', '40'), +('8', '2', '26', '53', '36', '51', '38', '41'), +('8', '2', '27', '54', '37', '52', '39', '42'), +('8', '2', '28', '56', '38', '54', '40', '43'), +('8', '2', '29', '57', '39', '55', '41', '43'), +('8', '2', '30', '58', '39', '56', '42', '44'), +('8', '2', '31', '60', '40', '58', '43', '45'), +('8', '2', '32', '61', '41', '59', '43', '46'), +('8', '2', '33', '63', '42', '60', '44', '47'), +('8', '2', '34', '64', '43', '62', '45', '48'), +('8', '2', '35', '66', '44', '63', '46', '49'), +('8', '2', '36', '67', '44', '65', '47', '50'), +('8', '2', '37', '69', '45', '66', '48', '51'), +('8', '2', '38', '70', '46', '67', '49', '52'), +('8', '2', '39', '72', '47', '69', '50', '53'), +('8', '2', '40', '73', '48', '70', '51', '54'), +('8', '2', '41', '75', '49', '72', '52', '55'), +('8', '2', '42', '77', '49', '73', '53', '56'), +('8', '2', '43', '78', '50', '75', '54', '57'), +('8', '2', '44', '80', '51', '76', '55', '58'), +('8', '2', '45', '81', '52', '78', '56', '59'), +('8', '2', '46', '83', '53', '79', '57', '61'), +('8', '2', '47', '85', '54', '81', '58', '62'), +('8', '2', '48', '86', '55', '83', '59', '63'), +('8', '2', '49', '88', '56', '84', '60', '64'), +('8', '2', '50', '90', '57', '86', '61', '65'), +('8', '2', '51', '91', '58', '87', '62', '66'), +('8', '2', '52', '93', '59', '89', '63', '67'), +('8', '2', '53', '95', '60', '91', '64', '68'), +('8', '2', '54', '97', '61', '92', '65', '69'), +('8', '2', '55', '98', '61', '94', '66', '71'), +('8', '2', '56', '100', '62', '95', '67', '72'), +('8', '2', '57', '102', '63', '97', '68', '73'), +('8', '2', '58', '104', '64', '99', '69', '74'), +('8', '2', '59', '105', '65', '101', '70', '75'), +('8', '2', '60', '107', '66', '102', '71', '77'), +('8', '2', '61', '109', '67', '104', '73', '78'), +('8', '2', '62', '111', '69', '106', '74', '79'), +('8', '2', '63', '113', '70', '107', '75', '80'), +('8', '2', '64', '115', '71', '109', '76', '81'), +('8', '2', '65', '116', '72', '111', '77', '83'), +('8', '2', '66', '118', '73', '113', '78', '84'), +('8', '2', '67', '120', '74', '115', '79', '85'), +('8', '2', '68', '122', '75', '116', '81', '86'), +('8', '2', '69', '124', '76', '118', '82', '88'), +('8', '2', '70', '126', '77', '120', '83', '89'), +('8', '2', '71', '148', '78', '122', '84', '92'), +('8', '2', '72', '150', '79', '125', '86', '94'), +('8', '2', '73', '152', '80', '127', '87', '96'), +('8', '2', '74', '156', '82', '129', '89', '97'), +('8', '2', '75', '158', '83', '131', '90', '99'), +('8', '2', '76', '162', '84', '134', '92', '100'), +('8', '2', '77', '164', '86', '136', '93', '103'), +('8', '2', '78', '167', '87', '138', '95', '105'), +('8', '2', '79', '170', '88', '153', '96', '106'), +('8', '2', '80', '173', '90', '160', '98', '108'), +('8', '9', '1', '20', '20', '21', '22', '22'), +('8', '9', '2', '20', '20', '22', '23', '23'), +('8', '9', '3', '21', '21', '22', '24', '24'), +('8', '9', '4', '21', '21', '23', '26', '25'), +('8', '9', '5', '21', '21', '23', '27', '27'), +('8', '9', '6', '21', '22', '24', '28', '28'), +('8', '9', '7', '22', '22', '24', '29', '29'), +('8', '9', '8', '22', '23', '25', '30', '30'), +('8', '9', '9', '22', '23', '26', '32', '31'), +('8', '9', '10', '23', '23', '26', '33', '33'), +('8', '9', '11', '23', '24', '27', '34', '34'), +('8', '9', '12', '23', '24', '27', '35', '35'), +('8', '9', '13', '24', '25', '28', '37', '36'), +('8', '9', '14', '24', '25', '29', '38', '38'), +('8', '9', '15', '24', '25', '29', '39', '39'), +('8', '9', '16', '25', '26', '30', '41', '40'), +('8', '9', '17', '25', '26', '31', '42', '42'), +('8', '9', '18', '25', '27', '31', '43', '43'), +('8', '9', '19', '26', '27', '32', '45', '44'), +('8', '9', '20', '26', '28', '33', '46', '46'), +('8', '9', '21', '26', '28', '33', '48', '47'), +('8', '9', '22', '27', '29', '34', '49', '49'), +('8', '9', '23', '27', '29', '35', '51', '50'), +('8', '9', '24', '28', '30', '35', '52', '51'), +('8', '9', '25', '28', '30', '36', '53', '53'), +('8', '9', '26', '28', '31', '37', '55', '54'), +('8', '9', '27', '29', '31', '37', '56', '56'), +('8', '9', '28', '29', '32', '38', '58', '57'), +('8', '9', '29', '30', '32', '39', '59', '59'), +('8', '9', '30', '30', '33', '40', '61', '60'), +('8', '9', '31', '30', '33', '40', '62', '62'), +('8', '9', '32', '31', '34', '41', '64', '63'), +('8', '9', '33', '31', '34', '42', '66', '65'), +('8', '9', '34', '32', '35', '43', '67', '66'), +('8', '9', '35', '32', '35', '44', '69', '68'), +('8', '9', '36', '33', '36', '44', '70', '69'), +('8', '9', '37', '33', '36', '45', '72', '71'), +('8', '9', '38', '34', '37', '46', '74', '73'), +('8', '9', '39', '34', '38', '47', '75', '74'), +('8', '9', '40', '35', '38', '48', '77', '76'), +('8', '9', '41', '35', '39', '48', '79', '78'), +('8', '9', '42', '35', '39', '49', '80', '79'), +('8', '9', '43', '36', '40', '50', '82', '81'), +('8', '9', '44', '36', '40', '51', '84', '83'), +('8', '9', '45', '37', '41', '52', '85', '84'), +('8', '9', '46', '37', '42', '53', '87', '86'), +('8', '9', '47', '38', '42', '54', '89', '88'), +('8', '9', '48', '38', '43', '55', '91', '89'), +('8', '9', '49', '39', '44', '55', '93', '91'), +('8', '9', '50', '40', '44', '56', '94', '93'), +('8', '9', '51', '40', '45', '57', '96', '95'), +('8', '9', '52', '41', '45', '58', '98', '97'), +('8', '9', '53', '41', '46', '59', '100', '98'), +('8', '9', '54', '42', '47', '60', '102', '100'), +('8', '9', '55', '42', '47', '61', '103', '102'), +('8', '9', '56', '43', '48', '62', '105', '104'), +('8', '9', '57', '43', '49', '63', '107', '106'), +('8', '9', '58', '44', '49', '64', '109', '108'), +('8', '9', '59', '44', '50', '65', '111', '109'), +('8', '9', '60', '45', '51', '66', '113', '111'), +('8', '9', '61', '46', '51', '67', '115', '113'), +('8', '9', '62', '46', '52', '68', '117', '115'), +('8', '9', '63', '47', '53', '69', '119', '117'), +('8', '9', '64', '47', '54', '70', '121', '119'), +('8', '9', '65', '48', '54', '71', '123', '121'), +('8', '9', '66', '49', '55', '72', '125', '123'), +('8', '9', '67', '49', '56', '73', '127', '125'), +('8', '9', '68', '50', '57', '74', '129', '127'), +('8', '9', '69', '50', '57', '75', '131', '129'), +('8', '9', '70', '51', '58', '76', '133', '131'), +('8', '9', '71', '52', '59', '78', '135', '146'), +('8', '9', '72', '53', '59', '79', '138', '148'), +('8', '9', '73', '54', '60', '80', '140', '151'), +('8', '9', '74', '54', '61', '89', '143', '154'), +('8', '9', '75', '55', '62', '91', '145', '156'), +('8', '9', '76', '56', '63', '92', '148', '159'), +('8', '9', '77', '57', '64', '93', '151', '162'), +('8', '9', '78', '57', '65', '95', '153', '165'), +('8', '9', '79', '58', '66', '96', '156', '168'), +('8', '9', '80', '59', '67', '97', '159', '170'), +('8', '11', '1', '18', '25', '19', '22', '22'), +('8', '11', '2', '19', '25', '20', '23', '23'), +('8', '11', '3', '19', '26', '20', '24', '24'), +('8', '11', '4', '20', '26', '21', '25', '26'), +('8', '11', '5', '20', '27', '22', '26', '27'), +('8', '11', '6', '21', '27', '22', '27', '28'), +('8', '11', '7', '21', '28', '23', '28', '29'), +('8', '11', '8', '22', '28', '24', '29', '30'), +('8', '11', '9', '23', '29', '24', '30', '32'), +('8', '11', '10', '23', '29', '25', '32', '33'), +('8', '11', '11', '24', '30', '26', '33', '34'), +('8', '11', '12', '24', '31', '26', '34', '35'), +('8', '11', '13', '25', '31', '27', '35', '37'), +('8', '11', '14', '26', '32', '28', '36', '38'), +('8', '11', '15', '26', '32', '29', '37', '39'), +('8', '11', '16', '27', '33', '29', '38', '41'), +('8', '11', '17', '28', '33', '30', '40', '42'), +('8', '11', '18', '28', '34', '31', '41', '43'), +('8', '11', '19', '29', '35', '32', '42', '45'), +('8', '11', '20', '30', '35', '32', '43', '46'), +('8', '11', '21', '30', '36', '33', '45', '48'), +('8', '11', '22', '31', '36', '34', '46', '49'), +('8', '11', '23', '32', '37', '35', '47', '51'), +('8', '11', '24', '32', '38', '36', '48', '52'), +('8', '11', '25', '33', '38', '36', '50', '53'), +('8', '11', '26', '34', '39', '37', '51', '55'), +('8', '11', '27', '35', '40', '38', '52', '56'), +('8', '11', '28', '35', '40', '39', '54', '58'), +('8', '11', '29', '36', '41', '40', '55', '59'), +('8', '11', '30', '37', '42', '41', '56', '61'), +('8', '11', '31', '38', '42', '42', '58', '62'), +('8', '11', '32', '38', '43', '42', '59', '64'), +('8', '11', '33', '39', '44', '43', '60', '66'), +('8', '11', '34', '40', '44', '44', '62', '67'), +('8', '11', '35', '41', '45', '45', '63', '69'), +('8', '11', '36', '42', '46', '46', '65', '70'), +('8', '11', '37', '42', '47', '47', '66', '72'), +('8', '11', '38', '43', '47', '48', '67', '74'), +('8', '11', '39', '44', '48', '49', '69', '75'), +('8', '11', '40', '45', '49', '50', '70', '77'), +('8', '11', '41', '46', '50', '51', '72', '79'), +('8', '11', '42', '46', '50', '52', '73', '80'), +('8', '11', '43', '47', '51', '53', '75', '82'), +('8', '11', '44', '48', '52', '54', '76', '84'), +('8', '11', '45', '49', '53', '55', '78', '85'), +('8', '11', '46', '50', '54', '56', '79', '87'), +('8', '11', '47', '51', '54', '57', '81', '89'), +('8', '11', '48', '52', '55', '58', '83', '91'), +('8', '11', '49', '53', '56', '59', '84', '93'), +('8', '11', '50', '53', '57', '60', '86', '94'), +('8', '11', '51', '54', '58', '61', '87', '96'), +('8', '11', '52', '55', '59', '62', '89', '98'), +('8', '11', '53', '56', '59', '63', '91', '100'), +('8', '11', '54', '57', '60', '64', '92', '102'), +('8', '11', '55', '58', '61', '65', '94', '103'), +('8', '11', '56', '59', '62', '66', '95', '105'), +('8', '11', '57', '60', '63', '67', '97', '107'), +('8', '11', '58', '61', '64', '68', '99', '109'), +('8', '11', '59', '62', '65', '69', '101', '111'), +('8', '11', '60', '63', '66', '70', '102', '113'), +('8', '11', '61', '64', '66', '72', '104', '115'), +('8', '11', '62', '65', '67', '73', '106', '117'), +('8', '11', '63', '66', '68', '74', '107', '119'), +('8', '11', '64', '67', '69', '75', '109', '121'), +('8', '11', '65', '68', '70', '76', '111', '123'), +('8', '11', '66', '69', '71', '77', '113', '125'), +('8', '11', '67', '70', '72', '78', '115', '127'), +('8', '11', '68', '71', '73', '80', '116', '129'), +('8', '11', '69', '72', '74', '81', '118', '131'), +('8', '11', '70', '73', '75', '82', '120', '133'), +('8', '11', '71', '75', '76', '83', '122', '135'), +('8', '11', '72', '76', '78', '85', '125', '138'), +('8', '11', '73', '77', '79', '86', '127', '140'), +('8', '11', '74', '78', '80', '88', '131', '143'), +('8', '11', '75', '80', '81', '89', '133', '145'), +('8', '11', '76', '81', '82', '91', '134', '148'), +('8', '11', '77', '82', '83', '92', '136', '151'), +('8', '11', '78', '84', '85', '94', '138', '153'), +('8', '11', '79', '85', '86', '95', '141', '156'), +('8', '11', '80', '86', '87', '97', '143', '159'), +('6', '2', '1', '22', '20', '22', '20', '21'), +('6', '2', '2', '23', '21', '23', '21', '22'), +('6', '2', '3', '24', '21', '24', '21', '22'), +('6', '2', '4', '25', '22', '25', '22', '23'), +('6', '2', '5', '26', '22', '26', '23', '24'), +('6', '2', '6', '28', '23', '27', '23', '25'), +('6', '2', '7', '29', '24', '28', '24', '25'), +('6', '2', '8', '30', '24', '29', '25', '26'), +('6', '2', '9', '31', '25', '30', '25', '27'), +('6', '2', '10', '32', '25', '32', '26', '27'), +('6', '2', '11', '33', '26', '33', '27', '28'), +('6', '2', '12', '35', '27', '34', '27', '29'), +('6', '2', '13', '36', '27', '35', '28', '30'), +('6', '2', '14', '37', '28', '36', '29', '31'), +('6', '2', '15', '38', '29', '37', '30', '31'), +('6', '2', '16', '40', '29', '38', '30', '32'), +('6', '2', '17', '41', '30', '40', '31', '33'), +('6', '2', '18', '42', '31', '41', '32', '34'), +('6', '2', '19', '43', '31', '42', '33', '35'), +('6', '2', '20', '45', '32', '43', '33', '35'), +('6', '2', '21', '46', '33', '45', '34', '36'), +('6', '2', '22', '47', '33', '46', '35', '37'), +('6', '2', '23', '49', '34', '47', '36', '38'), +('6', '2', '24', '50', '35', '48', '37', '39'), +('6', '2', '25', '51', '36', '50', '37', '40'), +('6', '2', '26', '53', '36', '51', '38', '41'), +('6', '2', '27', '54', '37', '52', '39', '42'), +('6', '2', '28', '56', '38', '54', '40', '43'), +('6', '2', '29', '57', '39', '55', '41', '43'), +('6', '2', '30', '58', '39', '56', '42', '44'), +('6', '2', '31', '60', '40', '58', '43', '45'), +('6', '2', '32', '61', '41', '59', '43', '46'), +('6', '2', '33', '63', '42', '60', '44', '47'), +('6', '2', '34', '64', '43', '62', '45', '48'), +('6', '2', '35', '66', '44', '63', '46', '49'), +('6', '2', '36', '67', '44', '65', '47', '50'), +('6', '2', '37', '69', '45', '66', '48', '51'), +('6', '2', '38', '70', '46', '67', '49', '52'), +('6', '2', '39', '72', '47', '69', '50', '53'), +('6', '2', '40', '73', '48', '70', '51', '54'), +('6', '2', '41', '75', '49', '72', '52', '55'), +('6', '2', '42', '77', '49', '73', '53', '56'), +('6', '2', '43', '78', '50', '75', '54', '57'), +('6', '2', '44', '80', '51', '76', '55', '58'), +('6', '2', '45', '81', '52', '78', '56', '59'), +('6', '2', '46', '83', '53', '79', '57', '61'), +('6', '2', '47', '85', '54', '81', '58', '62'), +('6', '2', '48', '86', '55', '83', '59', '63'), +('6', '2', '49', '88', '56', '84', '60', '64'), +('6', '2', '50', '90', '57', '86', '61', '65'), +('6', '2', '51', '91', '58', '87', '62', '66'), +('6', '2', '52', '93', '59', '89', '63', '67'), +('6', '2', '53', '95', '60', '91', '64', '68'), +('6', '2', '54', '97', '61', '92', '65', '69'), +('6', '2', '55', '98', '61', '94', '66', '71'), +('6', '2', '56', '100', '62', '95', '67', '72'), +('6', '2', '57', '102', '63', '97', '68', '73'), +('6', '2', '58', '104', '64', '99', '69', '74'), +('6', '2', '59', '105', '65', '101', '70', '75'), +('6', '2', '60', '107', '66', '102', '71', '77'), +('6', '2', '61', '109', '67', '104', '73', '78'), +('6', '2', '62', '111', '69', '106', '74', '79'), +('6', '2', '63', '113', '70', '107', '75', '80'), +('6', '2', '64', '115', '71', '109', '76', '81'), +('6', '2', '65', '116', '72', '111', '77', '83'), +('6', '2', '66', '118', '73', '113', '78', '84'), +('6', '2', '67', '120', '74', '115', '79', '85'), +('6', '2', '68', '122', '75', '116', '81', '86'), +('6', '2', '69', '124', '76', '118', '82', '88'), +('6', '2', '70', '126', '77', '120', '83', '89'), +('6', '2', '71', '148', '78', '122', '84', '92'), +('6', '2', '72', '150', '79', '125', '86', '94'), +('6', '2', '73', '152', '80', '127', '87', '96'), +('6', '2', '74', '156', '82', '129', '89', '97'), +('6', '2', '75', '158', '83', '131', '90', '99'), +('6', '2', '76', '162', '84', '134', '92', '100'), +('6', '2', '77', '164', '86', '136', '93', '103'), +('6', '2', '78', '167', '87', '138', '95', '105'), +('6', '2', '79', '170', '88', '153', '96', '106'), +('6', '2', '80', '173', '90', '160', '98', '108'), +('6', '4', '1', '24', '20', '23', '17', '23'), +('6', '4', '2', '25', '21', '24', '17', '23'), +('6', '4', '3', '25', '23', '24', '17', '24'), +('6', '4', '4', '26', '24', '25', '17', '24'), +('6', '4', '5', '27', '26', '26', '18', '24'), +('6', '4', '6', '28', '27', '26', '18', '25'), +('6', '4', '7', '29', '29', '27', '18', '25'), +('6', '4', '8', '29', '30', '28', '18', '26'), +('6', '4', '9', '30', '32', '29', '18', '26'), +('6', '4', '10', '31', '33', '29', '19', '26'), +('6', '4', '11', '32', '35', '30', '19', '27'), +('6', '4', '12', '33', '37', '31', '19', '27'), +('6', '4', '13', '34', '38', '32', '19', '28'), +('6', '4', '14', '34', '40', '32', '19', '28'), +('6', '4', '15', '35', '41', '33', '19', '28'), +('6', '4', '16', '36', '43', '34', '20', '29'), +('6', '4', '17', '37', '45', '35', '20', '29'), +('6', '4', '18', '38', '46', '36', '20', '30'), +('6', '4', '19', '39', '48', '37', '20', '30'), +('6', '4', '20', '40', '50', '37', '21', '31'), +('6', '4', '21', '41', '52', '38', '21', '31'), +('6', '4', '22', '42', '53', '39', '21', '31'), +('6', '4', '23', '43', '55', '40', '21', '32'), +('6', '4', '24', '43', '57', '41', '21', '32'), +('6', '4', '25', '44', '59', '42', '22', '33'), +('6', '4', '26', '45', '60', '43', '22', '33'), +('6', '4', '27', '46', '62', '44', '22', '34'), +('6', '4', '28', '47', '64', '44', '22', '34'), +('6', '4', '29', '48', '66', '45', '23', '35'), +('6', '4', '30', '49', '68', '46', '23', '35'), +('6', '4', '31', '50', '70', '47', '23', '36'), +('6', '4', '32', '51', '72', '48', '23', '36'), +('6', '4', '33', '53', '73', '49', '24', '37'), +('6', '4', '34', '54', '75', '50', '24', '38'), +('6', '4', '35', '55', '77', '51', '24', '38'), +('6', '4', '36', '56', '79', '52', '24', '39'), +('6', '4', '37', '57', '81', '53', '25', '39'), +('6', '4', '38', '58', '83', '54', '25', '40'), +('6', '4', '39', '59', '85', '55', '25', '40'), +('6', '4', '40', '60', '87', '56', '26', '41'), +('6', '4', '41', '61', '89', '57', '26', '41'), +('6', '4', '42', '62', '91', '58', '26', '42'), +('6', '4', '43', '63', '93', '59', '27', '43'), +('6', '4', '44', '65', '95', '60', '27', '43'), +('6', '4', '45', '66', '98', '61', '27', '44'), +('6', '4', '46', '67', '100', '62', '27', '44'), +('6', '4', '47', '68', '102', '64', '28', '45'), +('6', '4', '48', '69', '104', '65', '28', '46'), +('6', '4', '49', '71', '106', '66', '28', '46'), +('6', '4', '50', '72', '108', '67', '29', '47'), +('6', '4', '51', '73', '110', '68', '29', '48'), +('6', '4', '52', '74', '113', '69', '29', '48'), +('6', '4', '53', '75', '115', '70', '30', '49'), +('6', '4', '54', '77', '117', '71', '30', '50'), +('6', '4', '55', '78', '119', '73', '30', '50'), +('6', '4', '56', '79', '122', '74', '31', '51'), +('6', '4', '57', '80', '124', '75', '31', '52'), +('6', '4', '58', '82', '126', '76', '31', '52'), +('6', '4', '59', '83', '129', '77', '32', '53'), +('6', '4', '60', '84', '131', '78', '32', '54'), +('6', '4', '61', '86', '133', '80', '33', '54'), +('6', '4', '62', '87', '136', '81', '33', '55'), +('6', '4', '63', '88', '138', '82', '33', '56'), +('6', '4', '64', '90', '140', '83', '34', '57'), +('6', '4', '65', '91', '143', '85', '34', '57'), +('6', '4', '66', '92', '145', '86', '34', '58'), +('6', '4', '67', '94', '148', '87', '35', '59'), +('6', '4', '68', '95', '150', '88', '35', '59'), +('6', '4', '69', '97', '153', '90', '36', '60'), +('6', '4', '70', '98', '155', '91', '36', '61'), +('6', '4', '71', '100', '158', '92', '36', '62'), +('6', '4', '72', '102', '161', '94', '37', '62'), +('6', '4', '73', '103', '164', '99', '37', '63'), +('6', '4', '74', '105', '167', '100', '38', '64'), +('6', '4', '75', '107', '170', '102', '38', '65'), +('6', '4', '76', '108', '173', '102', '38', '66'), +('6', '4', '77', '110', '176', '102', '39', '67'), +('6', '4', '78', '112', '180', '103', '39', '68'), +('6', '4', '79', '114', '183', '105', '40', '69'), +('6', '4', '80', '116', '186', '107', '40', '70'), +('6', '5', '1', '20', '20', '20', '22', '23'), +('6', '5', '2', '20', '20', '20', '23', '24'), +('6', '5', '3', '20', '20', '21', '25', '26'), +('6', '5', '4', '20', '21', '21', '26', '27'), +('6', '5', '5', '21', '21', '21', '27', '28'), +('6', '5', '6', '21', '21', '22', '29', '30'), +('6', '5', '7', '21', '21', '22', '30', '31'), +('6', '5', '8', '21', '22', '23', '31', '33'), +('6', '5', '9', '21', '22', '23', '33', '34'), +('6', '5', '10', '21', '22', '23', '34', '36'), +('6', '5', '11', '22', '22', '24', '36', '37'), +('6', '5', '12', '22', '23', '24', '37', '39'), +('6', '5', '13', '22', '23', '25', '38', '40'), +('6', '5', '14', '22', '23', '25', '40', '42'), +('6', '5', '15', '22', '23', '25', '41', '43'), +('6', '5', '16', '23', '24', '26', '43', '45'), +('6', '5', '17', '23', '24', '26', '44', '46'), +('6', '5', '18', '23', '24', '27', '46', '48'), +('6', '5', '19', '23', '24', '27', '47', '49'), +('6', '5', '20', '23', '25', '28', '49', '51'), +('6', '5', '21', '24', '25', '28', '51', '53'), +('6', '5', '22', '24', '25', '29', '52', '54'), +('6', '5', '23', '24', '26', '29', '54', '56'), +('6', '5', '24', '24', '26', '30', '55', '58'), +('6', '5', '25', '25', '26', '30', '57', '59'), +('6', '5', '26', '25', '27', '31', '59', '61'), +('6', '5', '27', '25', '27', '31', '60', '63'), +('6', '5', '28', '25', '27', '32', '62', '65'), +('6', '5', '29', '25', '28', '32', '64', '66'), +('6', '5', '30', '26', '28', '33', '65', '68'), +('6', '5', '31', '26', '28', '33', '67', '70'), +('6', '5', '32', '26', '29', '34', '69', '72'), +('6', '5', '33', '27', '29', '34', '70', '73'), +('6', '5', '34', '27', '29', '35', '72', '75'), +('6', '5', '35', '27', '30', '35', '74', '77'), +('6', '5', '36', '27', '30', '36', '76', '79'), +('6', '5', '37', '28', '30', '36', '78', '81'), +('6', '5', '38', '28', '31', '37', '79', '83'), +('6', '5', '39', '28', '31', '38', '81', '85'), +('6', '5', '40', '28', '31', '38', '83', '87'), +('6', '5', '41', '29', '32', '39', '85', '88'), +('6', '5', '42', '29', '32', '39', '87', '90'), +('6', '5', '43', '29', '33', '40', '89', '92'), +('6', '5', '44', '30', '33', '40', '91', '94'), +('6', '5', '45', '30', '33', '41', '92', '96'), +('6', '5', '46', '30', '34', '42', '94', '98'), +('6', '5', '47', '31', '34', '42', '96', '100'), +('6', '5', '48', '31', '35', '43', '98', '102'), +('6', '5', '49', '31', '35', '44', '100', '104'), +('6', '5', '50', '32', '36', '44', '102', '106'), +('6', '5', '51', '32', '36', '45', '104', '109'), +('6', '5', '52', '32', '36', '45', '106', '111'), +('6', '5', '53', '33', '37', '46', '108', '113'), +('6', '5', '54', '33', '37', '47', '110', '115'), +('6', '5', '55', '33', '38', '47', '112', '117'), +('6', '5', '56', '34', '38', '48', '114', '119'), +('6', '5', '57', '34', '39', '49', '117', '121'), +('6', '5', '58', '34', '39', '49', '119', '124'), +('6', '5', '59', '35', '40', '50', '121', '126'), +('6', '5', '60', '35', '40', '51', '123', '128'), +('6', '5', '61', '35', '41', '51', '125', '130'), +('6', '5', '62', '36', '41', '52', '127', '132'), +('6', '5', '63', '36', '41', '53', '129', '135'), +('6', '5', '64', '37', '42', '54', '132', '137'), +('6', '5', '65', '37', '42', '54', '134', '139'), +('6', '5', '66', '37', '43', '55', '136', '142'), +('6', '5', '67', '38', '43', '56', '138', '144'), +('6', '5', '68', '38', '44', '57', '140', '146'), +('6', '5', '69', '39', '44', '57', '143', '149'), +('6', '5', '70', '39', '45', '58', '145', '151'), +('6', '5', '71', '39', '46', '59', '148', '158'), +('6', '5', '72', '40', '46', '59', '151', '161'), +('6', '5', '73', '40', '47', '60', '154', '164'), +('6', '5', '74', '41', '47', '61', '156', '167'), +('6', '5', '75', '41', '48', '62', '159', '170'), +('6', '5', '76', '41', '49', '63', '162', '174'), +('6', '5', '77', '42', '49', '64', '165', '177'), +('6', '5', '78', '42', '50', '65', '168', '180'), +('6', '5', '79', '43', '50', '66', '171', '183'), +('6', '5', '80', '43', '51', '67', '174', '186'), +('6', '8', '1', '20', '20', '20', '23', '22'), +('6', '8', '2', '20', '20', '20', '24', '23'), +('6', '8', '3', '20', '20', '21', '26', '25'), +('6', '8', '4', '20', '20', '21', '27', '26'), +('6', '8', '5', '20', '21', '21', '28', '27'), +('6', '8', '6', '20', '21', '21', '30', '29'), +('6', '8', '7', '21', '21', '22', '31', '30'), +('6', '8', '8', '21', '21', '22', '33', '31'), +('6', '8', '9', '21', '21', '22', '34', '33'), +('6', '8', '10', '21', '21', '23', '36', '34'), +('6', '8', '11', '21', '22', '23', '37', '36'), +('6', '8', '12', '21', '22', '23', '39', '37'), +('6', '8', '13', '21', '22', '24', '40', '38'), +('6', '8', '14', '21', '22', '24', '42', '40'), +('6', '8', '15', '21', '22', '24', '43', '41'), +('6', '8', '16', '21', '23', '25', '45', '43'), +('6', '8', '17', '22', '23', '25', '46', '44'), +('6', '8', '18', '22', '23', '25', '48', '46'), +('6', '8', '19', '22', '23', '26', '49', '47'), +('6', '8', '20', '22', '23', '26', '51', '49'), +('6', '8', '21', '22', '24', '26', '53', '51'), +('6', '8', '22', '22', '24', '27', '54', '52'), +('6', '8', '23', '22', '24', '27', '56', '54'), +('6', '8', '24', '23', '24', '28', '58', '55'), +('6', '8', '25', '23', '25', '28', '59', '57'), +('6', '8', '26', '23', '25', '28', '61', '59'), +('6', '8', '27', '23', '25', '29', '63', '60'), +('6', '8', '28', '23', '25', '29', '65', '62'), +('6', '8', '29', '23', '25', '30', '66', '64'), +('6', '8', '30', '24', '26', '30', '68', '65'), +('6', '8', '31', '24', '26', '30', '70', '67'), +('6', '8', '32', '24', '26', '31', '72', '69'), +('6', '8', '33', '24', '27', '31', '73', '70'), +('6', '8', '34', '24', '27', '32', '75', '72'), +('6', '8', '35', '24', '27', '32', '77', '74'), +('6', '8', '36', '25', '27', '33', '79', '76'), +('6', '8', '37', '25', '28', '33', '81', '78'), +('6', '8', '38', '25', '28', '34', '83', '79'), +('6', '8', '39', '25', '28', '34', '85', '81'), +('6', '8', '40', '25', '28', '35', '87', '83'), +('6', '8', '41', '26', '29', '35', '88', '85'), +('6', '8', '42', '26', '29', '35', '90', '87'), +('6', '8', '43', '26', '29', '36', '92', '89'), +('6', '8', '44', '26', '30', '36', '94', '91'), +('6', '8', '45', '26', '30', '37', '96', '92'), +('6', '8', '46', '27', '30', '37', '98', '94'), +('6', '8', '47', '27', '31', '38', '100', '96'), +('6', '8', '48', '27', '31', '38', '102', '98'), +('6', '8', '49', '27', '31', '39', '104', '100'), +('6', '8', '50', '28', '32', '40', '106', '102'), +('6', '8', '51', '28', '32', '40', '109', '104'), +('6', '8', '52', '28', '32', '41', '111', '106'), +('6', '8', '53', '28', '33', '41', '113', '108'), +('6', '8', '54', '29', '33', '42', '115', '110'), +('6', '8', '55', '29', '33', '42', '117', '112'), +('6', '8', '56', '29', '34', '43', '119', '114'), +('6', '8', '57', '29', '34', '43', '121', '117'), +('6', '8', '58', '30', '34', '44', '124', '119'), +('6', '8', '59', '30', '35', '44', '126', '121'), +('6', '8', '60', '30', '35', '45', '128', '123'), +('6', '8', '61', '30', '35', '46', '130', '125'), +('6', '8', '62', '31', '36', '46', '132', '127'), +('6', '8', '63', '31', '36', '47', '135', '129'), +('6', '8', '64', '31', '37', '47', '137', '132'), +('6', '8', '65', '32', '37', '48', '139', '134'), +('6', '8', '66', '32', '37', '49', '142', '136'), +('6', '8', '67', '32', '38', '49', '144', '138'), +('6', '8', '68', '32', '38', '50', '146', '140'), +('6', '8', '69', '33', '39', '50', '149', '143'), +('6', '8', '70', '33', '39', '51', '151', '145'), +('6', '8', '71', '33', '39', '52', '154', '152'), +('6', '8', '72', '33', '40', '53', '160', '155'), +('6', '8', '73', '33', '40', '54', '160', '158'), +('6', '8', '74', '34', '41', '54', '163', '160'), +('6', '8', '75', '34', '41', '55', '166', '163'), +('6', '8', '76', '34', '41', '56', '169', '166'), +('6', '8', '77', '35', '42', '57', '172', '169'), +('6', '8', '78', '35', '42', '57', '175', '173'), +('6', '8', '79', '35', '43', '58', '178', '176'), +('6', '8', '80', '36', '43', '59', '181', '179'), +('6', '9', '1', '20', '20', '21', '22', '22'), +('6', '9', '2', '20', '20', '22', '23', '23'), +('6', '9', '3', '21', '21', '22', '24', '24'), +('6', '9', '4', '21', '21', '23', '26', '25'), +('6', '9', '5', '21', '21', '23', '27', '27'), +('6', '9', '6', '21', '22', '24', '28', '28'), +('6', '9', '7', '22', '22', '24', '29', '29'), +('6', '9', '8', '22', '23', '25', '30', '30'), +('6', '9', '9', '22', '23', '26', '32', '31'), +('6', '9', '10', '23', '23', '26', '33', '33'), +('6', '9', '11', '23', '24', '27', '34', '34'), +('6', '9', '12', '23', '24', '27', '35', '35'), +('6', '9', '13', '24', '25', '28', '37', '36'), +('6', '9', '14', '24', '25', '29', '38', '38'), +('6', '9', '15', '24', '25', '29', '39', '39'), +('6', '9', '16', '25', '26', '30', '41', '40'), +('6', '9', '17', '25', '26', '31', '42', '42'), +('6', '9', '18', '25', '27', '31', '43', '43'), +('6', '9', '19', '26', '27', '32', '45', '44'), +('6', '9', '20', '26', '28', '33', '46', '46'), +('6', '9', '21', '26', '28', '33', '48', '47'), +('6', '9', '22', '27', '29', '34', '49', '49'), +('6', '9', '23', '27', '29', '35', '51', '50'), +('6', '9', '24', '28', '30', '35', '52', '51'), +('6', '9', '25', '28', '30', '36', '53', '53'), +('6', '9', '26', '28', '31', '37', '55', '54'), +('6', '9', '27', '29', '31', '37', '56', '56'), +('6', '9', '28', '29', '32', '38', '58', '57'), +('6', '9', '29', '30', '32', '39', '59', '59'), +('6', '9', '30', '30', '33', '40', '61', '60'), +('6', '9', '31', '30', '33', '40', '62', '62'), +('6', '9', '32', '31', '34', '41', '64', '63'), +('6', '9', '33', '31', '34', '42', '66', '65'), +('6', '9', '34', '32', '35', '43', '67', '66'), +('6', '9', '35', '32', '35', '44', '69', '68'), +('6', '9', '36', '33', '36', '44', '70', '69'), +('6', '9', '37', '33', '36', '45', '72', '71'), +('6', '9', '38', '34', '37', '46', '74', '73'), +('6', '9', '39', '34', '38', '47', '75', '74'), +('6', '9', '40', '35', '38', '48', '77', '76'), +('6', '9', '41', '35', '39', '48', '79', '78'), +('6', '9', '42', '35', '39', '49', '80', '79'), +('6', '9', '43', '36', '40', '50', '82', '81'), +('6', '9', '44', '36', '40', '51', '84', '83'), +('6', '9', '45', '37', '41', '52', '85', '84'), +('6', '9', '46', '37', '42', '53', '87', '86'), +('6', '9', '47', '38', '42', '54', '89', '88'), +('6', '9', '48', '38', '43', '55', '91', '89'), +('6', '9', '49', '39', '44', '55', '93', '91'), +('6', '9', '50', '40', '44', '56', '94', '93'), +('6', '9', '51', '40', '45', '57', '96', '95'), +('6', '9', '52', '41', '45', '58', '98', '97'), +('6', '9', '53', '41', '46', '59', '100', '98'), +('6', '9', '54', '42', '47', '60', '102', '100'), +('6', '9', '55', '42', '47', '61', '103', '102'), +('6', '9', '56', '43', '48', '62', '105', '104'), +('6', '9', '57', '43', '49', '63', '107', '106'), +('6', '9', '58', '44', '49', '64', '109', '108'), +('6', '9', '59', '44', '50', '65', '111', '109'), +('6', '9', '60', '45', '51', '66', '113', '111'), +('6', '9', '61', '46', '51', '67', '115', '113'), +('6', '9', '62', '46', '52', '68', '117', '115'), +('6', '9', '63', '47', '53', '69', '119', '117'), +('6', '9', '64', '47', '54', '70', '121', '119'), +('6', '9', '65', '48', '54', '71', '123', '121'), +('6', '9', '66', '49', '55', '72', '125', '123'), +('6', '9', '67', '49', '56', '73', '127', '125'), +('6', '9', '68', '50', '57', '74', '129', '127'), +('6', '9', '69', '50', '57', '75', '131', '129'), +('6', '9', '70', '51', '58', '76', '133', '131'), +('6', '9', '71', '52', '59', '78', '135', '146'), +('6', '9', '72', '53', '59', '79', '138', '148'), +('6', '9', '73', '54', '60', '80', '140', '151'), +('6', '9', '74', '54', '61', '89', '143', '154'), +('6', '9', '75', '55', '62', '91', '145', '156'), +('6', '9', '76', '56', '63', '92', '148', '159'), +('6', '9', '77', '57', '64', '93', '151', '162'), +('6', '9', '78', '57', '65', '95', '153', '165'), +('6', '9', '79', '58', '66', '96', '156', '168'), +('6', '9', '80', '59', '67', '97', '159', '170'), +('5', '2', '1', '22', '20', '22', '20', '21'), +('5', '2', '2', '23', '21', '23', '21', '22'), +('5', '2', '3', '24', '21', '24', '21', '22'), +('5', '2', '4', '25', '22', '25', '22', '23'), +('5', '2', '5', '26', '22', '26', '23', '24'), +('5', '2', '6', '28', '23', '27', '23', '25'), +('5', '2', '7', '29', '24', '28', '24', '25'), +('5', '2', '8', '30', '24', '29', '25', '26'), +('5', '2', '9', '31', '25', '30', '25', '27'), +('5', '2', '10', '32', '25', '32', '26', '27'), +('5', '2', '11', '33', '26', '33', '27', '28'), +('5', '2', '12', '35', '27', '34', '27', '29'), +('5', '2', '13', '36', '27', '35', '28', '30'), +('5', '2', '14', '37', '28', '36', '29', '31'), +('5', '2', '15', '38', '29', '37', '30', '31'), +('5', '2', '16', '40', '29', '38', '30', '32'), +('5', '2', '17', '41', '30', '40', '31', '33'), +('5', '2', '18', '42', '31', '41', '32', '34'), +('5', '2', '19', '43', '31', '42', '33', '35'), +('5', '2', '20', '45', '32', '43', '33', '35'), +('5', '2', '21', '46', '33', '45', '34', '36'), +('5', '2', '22', '47', '33', '46', '35', '37'), +('5', '2', '23', '49', '34', '47', '36', '38'), +('5', '2', '24', '50', '35', '48', '37', '39'), +('5', '2', '25', '51', '36', '50', '37', '40'), +('5', '2', '26', '53', '36', '51', '38', '41'), +('5', '2', '27', '54', '37', '52', '39', '42'), +('5', '2', '28', '56', '38', '54', '40', '43'), +('5', '2', '29', '57', '39', '55', '41', '43'), +('5', '2', '30', '58', '39', '56', '42', '44'), +('5', '2', '31', '60', '40', '58', '43', '45'), +('5', '2', '32', '61', '41', '59', '43', '46'), +('5', '2', '33', '63', '42', '60', '44', '47'), +('5', '2', '34', '64', '43', '62', '45', '48'), +('5', '2', '35', '66', '44', '63', '46', '49'), +('5', '2', '36', '67', '44', '65', '47', '50'), +('5', '2', '37', '69', '45', '66', '48', '51'), +('5', '2', '38', '70', '46', '67', '49', '52'), +('5', '2', '39', '72', '47', '69', '50', '53'), +('5', '2', '40', '73', '48', '70', '51', '54'), +('5', '2', '41', '75', '49', '72', '52', '55'), +('5', '2', '42', '77', '49', '73', '53', '56'), +('5', '2', '43', '78', '50', '75', '54', '57'), +('5', '2', '44', '80', '51', '76', '55', '58'), +('5', '2', '45', '81', '52', '78', '56', '59'), +('5', '2', '46', '83', '53', '79', '57', '61'), +('5', '2', '47', '85', '54', '81', '58', '62'), +('5', '2', '48', '86', '55', '83', '59', '63'), +('5', '2', '49', '88', '56', '84', '60', '64'), +('5', '2', '50', '90', '57', '86', '61', '65'), +('5', '2', '51', '91', '58', '87', '62', '66'), +('5', '2', '52', '93', '59', '89', '63', '67'), +('5', '2', '53', '95', '60', '91', '64', '68'), +('5', '2', '54', '97', '61', '92', '65', '69'), +('5', '2', '55', '98', '61', '94', '66', '71'), +('5', '2', '56', '100', '62', '95', '67', '72'), +('5', '2', '57', '102', '63', '97', '68', '73'), +('5', '2', '58', '104', '64', '99', '69', '74'), +('5', '2', '59', '105', '65', '101', '70', '75'), +('5', '2', '60', '107', '66', '102', '71', '77'), +('5', '2', '61', '109', '67', '104', '73', '78'), +('5', '2', '62', '111', '69', '106', '74', '79'), +('5', '2', '63', '113', '70', '107', '75', '80'), +('5', '2', '64', '115', '71', '109', '76', '81'), +('5', '2', '65', '116', '72', '111', '77', '83'), +('5', '2', '66', '118', '73', '113', '78', '84'), +('5', '2', '67', '120', '74', '115', '79', '85'), +('5', '2', '68', '122', '75', '116', '81', '86'), +('5', '2', '69', '124', '76', '118', '82', '88'), +('5', '2', '70', '126', '77', '120', '83', '89'), +('5', '2', '71', '148', '78', '122', '84', '92'), +('5', '2', '72', '150', '79', '125', '86', '94'), +('5', '2', '73', '152', '80', '127', '87', '96'), +('5', '2', '74', '156', '82', '129', '89', '97'), +('5', '2', '75', '158', '83', '131', '90', '99'), +('5', '2', '76', '162', '84', '134', '92', '100'), +('5', '2', '77', '164', '86', '136', '93', '103'), +('5', '2', '78', '167', '87', '138', '95', '105'), +('5', '2', '79', '170', '88', '153', '96', '106'), +('5', '2', '80', '173', '90', '160', '98', '108'), +('5', '3', '1', '23', '20', '23', '17', '24'), +('5', '3', '2', '23', '21', '24', '18', '25'), +('5', '3', '3', '24', '23', '25', '18', '25'), +('5', '3', '4', '24', '24', '26', '19', '26'), +('5', '3', '5', '25', '25', '27', '19', '26'), +('5', '3', '6', '25', '27', '28', '20', '27'), +('5', '3', '7', '26', '28', '28', '21', '28'), +('5', '3', '8', '26', '30', '29', '21', '28'), +('5', '3', '9', '26', '31', '30', '22', '29'), +('5', '3', '10', '27', '33', '31', '22', '30'), +('5', '3', '11', '27', '34', '32', '23', '30'), +('5', '3', '12', '28', '36', '33', '24', '31'), +('5', '3', '13', '28', '37', '34', '24', '32'), +('5', '3', '14', '29', '39', '35', '25', '33'), +('5', '3', '15', '29', '40', '36', '26', '33'), +('5', '3', '16', '30', '42', '37', '26', '34'), +('5', '3', '17', '30', '43', '39', '27', '35'), +('5', '3', '18', '31', '45', '40', '28', '35'), +('5', '3', '19', '31', '47', '41', '28', '36'), +('5', '3', '20', '32', '48', '42', '29', '37'), +('5', '3', '21', '32', '50', '43', '30', '38'), +('5', '3', '22', '33', '51', '44', '31', '39'), +('5', '3', '23', '34', '53', '45', '31', '39'), +('5', '3', '24', '34', '55', '46', '32', '40'), +('5', '3', '25', '35', '57', '47', '33', '41'), +('5', '3', '26', '35', '58', '48', '34', '42'), +('5', '3', '27', '36', '60', '50', '34', '43'), +('5', '3', '28', '36', '62', '51', '35', '43'), +('5', '3', '29', '37', '63', '52', '36', '44'), +('5', '3', '30', '38', '65', '53', '37', '45'), +('5', '3', '31', '38', '67', '54', '37', '46'), +('5', '3', '32', '39', '69', '56', '38', '47'), +('5', '3', '33', '39', '71', '57', '39', '48'), +('5', '3', '34', '40', '72', '58', '40', '49'), +('5', '3', '35', '41', '74', '59', '41', '49'), +('5', '3', '36', '41', '76', '61', '42', '50'), +('5', '3', '37', '42', '78', '62', '42', '51'), +('5', '3', '38', '43', '80', '63', '43', '52'), +('5', '3', '39', '43', '82', '64', '44', '53'), +('5', '3', '40', '44', '84', '66', '45', '54'), +('5', '3', '41', '45', '86', '67', '46', '55'), +('5', '3', '42', '45', '88', '68', '47', '56'), +('5', '3', '43', '46', '90', '70', '47', '57'), +('5', '3', '44', '47', '91', '71', '48', '58'), +('5', '3', '45', '47', '93', '72', '49', '59'), +('5', '3', '46', '48', '95', '74', '50', '60'), +('5', '3', '47', '49', '98', '75', '51', '61'), +('5', '3', '48', '50', '100', '77', '52', '62'), +('5', '3', '49', '50', '102', '78', '53', '63'), +('5', '3', '50', '51', '104', '79', '54', '64'), +('5', '3', '51', '52', '106', '81', '55', '65'), +('5', '3', '52', '52', '108', '82', '56', '66'), +('5', '3', '53', '53', '110', '84', '57', '67'), +('5', '3', '54', '54', '112', '85', '58', '68'), +('5', '3', '55', '55', '114', '87', '59', '69'), +('5', '3', '56', '55', '116', '88', '60', '70'), +('5', '3', '57', '56', '118', '90', '61', '71'), +('5', '3', '58', '57', '121', '91', '62', '72'), +('5', '3', '59', '58', '123', '93', '63', '73'), +('5', '3', '60', '59', '125', '94', '64', '74'), +('5', '3', '61', '59', '127', '96', '65', '76'), +('5', '3', '62', '60', '130', '97', '66', '77'), +('5', '3', '63', '61', '132', '99', '67', '78'), +('5', '3', '64', '62', '134', '100', '68', '79'), +('5', '3', '65', '63', '136', '102', '69', '80'), +('5', '3', '66', '64', '139', '104', '70', '81'), +('5', '3', '67', '64', '141', '105', '71', '82'), +('5', '3', '68', '65', '143', '107', '72', '84'), +('5', '3', '69', '66', '146', '108', '73', '85'), +('5', '3', '70', '67', '148', '110', '74', '86'), +('5', '3', '71', '68', '151', '112', '75', '87'), +('5', '3', '72', '69', '154', '114', '76', '88'), +('5', '3', '73', '70', '157', '116', '77', '90'), +('5', '3', '74', '71', '160', '118', '79', '91'), +('5', '3', '75', '72', '163', '120', '80', '93'), +('5', '3', '76', '73', '166', '122', '81', '94'), +('5', '3', '77', '74', '169', '124', '83', '96'), +('5', '3', '78', '75', '172', '126', '84', '97'), +('5', '3', '79', '76', '175', '128', '85', '99'), +('5', '3', '80', '77', '178', '130', '87', '100'), +('5', '7', '1', '24', '17', '23', '18', '25'), +('5', '7', '2', '25', '17', '24', '19', '26'), +('5', '7', '3', '26', '18', '25', '20', '27'), +('5', '7', '4', '26', '18', '26', '21', '28'), +('5', '7', '5', '27', '19', '27', '22', '29'), +('5', '7', '6', '28', '19', '28', '23', '30'), +('5', '7', '7', '29', '20', '29', '24', '31'), +('5', '7', '8', '30', '20', '30', '25', '32'), +('5', '7', '9', '31', '21', '31', '26', '33'), +('5', '7', '10', '32', '21', '32', '27', '34'), +('5', '7', '11', '33', '22', '33', '28', '36'), +('5', '7', '12', '34', '22', '34', '29', '37'), +('5', '7', '13', '34', '23', '35', '30', '38'), +('5', '7', '14', '35', '23', '36', '31', '39'), +('5', '7', '15', '36', '24', '37', '32', '40'), +('5', '7', '16', '37', '24', '39', '33', '41'), +('5', '7', '17', '38', '25', '40', '34', '43'), +('5', '7', '18', '39', '25', '41', '35', '44'), +('5', '7', '19', '40', '26', '42', '36', '45'), +('5', '7', '20', '41', '26', '43', '37', '46'), +('5', '7', '21', '42', '27', '44', '38', '47'), +('5', '7', '22', '43', '27', '45', '39', '49'), +('5', '7', '23', '44', '28', '47', '40', '50'), +('5', '7', '24', '45', '28', '48', '41', '51'), +('5', '7', '25', '47', '29', '49', '43', '52'), +('5', '7', '26', '48', '30', '50', '44', '54'), +('5', '7', '27', '49', '30', '52', '45', '55'), +('5', '7', '28', '50', '31', '53', '46', '56'), +('5', '7', '29', '51', '31', '54', '47', '58'), +('5', '7', '30', '52', '32', '55', '48', '59'), +('5', '7', '31', '53', '33', '57', '50', '60'), +('5', '7', '32', '54', '33', '58', '51', '62'), +('5', '7', '33', '55', '34', '59', '52', '63'), +('5', '7', '34', '57', '34', '61', '53', '65'), +('5', '7', '35', '58', '35', '62', '55', '66'), +('5', '7', '36', '59', '36', '63', '56', '67'), +('5', '7', '37', '60', '36', '65', '57', '69'), +('5', '7', '38', '61', '37', '66', '58', '70'), +('5', '7', '39', '62', '38', '67', '60', '72'), +('5', '7', '40', '64', '38', '69', '61', '73'), +('5', '7', '41', '65', '39', '70', '62', '75'), +('5', '7', '42', '66', '40', '72', '64', '76'), +('5', '7', '43', '67', '40', '73', '65', '78'), +('5', '7', '44', '69', '41', '74', '66', '79'), +('5', '7', '45', '70', '42', '76', '68', '81'), +('5', '7', '46', '71', '42', '77', '69', '82'), +('5', '7', '47', '72', '43', '79', '70', '84'), +('5', '7', '48', '74', '44', '80', '72', '85'), +('5', '7', '49', '75', '45', '82', '73', '87'), +('5', '7', '50', '76', '45', '83', '75', '89'), +('5', '7', '51', '78', '46', '85', '76', '90'), +('5', '7', '52', '79', '47', '86', '77', '92'), +('5', '7', '53', '80', '47', '88', '79', '93'), +('5', '7', '54', '82', '48', '90', '80', '95'), +('5', '7', '55', '83', '49', '91', '82', '97'), +('5', '7', '56', '85', '50', '93', '83', '98'), +('5', '7', '57', '86', '50', '94', '85', '100'), +('5', '7', '58', '87', '51', '96', '86', '102'), +('5', '7', '59', '89', '52', '97', '88', '103'), +('5', '7', '60', '90', '53', '99', '89', '105'), +('5', '7', '61', '92', '54', '101', '91', '107'), +('5', '7', '62', '93', '54', '102', '92', '109'), +('5', '7', '63', '95', '55', '104', '94', '110'), +('5', '7', '64', '96', '56', '106', '95', '112'), +('5', '7', '65', '97', '57', '107', '97', '114'), +('5', '7', '66', '99', '58', '109', '99', '116'), +('5', '7', '67', '100', '58', '111', '100', '118'), +('5', '7', '68', '102', '59', '113', '102', '119'), +('5', '7', '69', '103', '60', '114', '103', '121'), +('5', '7', '70', '105', '61', '116', '105', '123'), +('5', '7', '71', '106', '62', '118', '117', '125'), +('5', '7', '72', '108', '63', '120', '119', '128'), +('5', '7', '73', '110', '64', '122', '122', '130'), +('5', '7', '74', '112', '65', '125', '124', '132'), +('5', '7', '75', '114', '66', '127', '126', '134'), +('5', '7', '76', '116', '67', '129', '128', '137'), +('5', '7', '77', '117', '68', '131', '128', '139'), +('5', '7', '78', '119', '69', '133', '133', '141'), +('5', '7', '79', '121', '70', '136', '135', '144'), +('5', '7', '80', '123', '71', '138', '137', '146'), +('5', '11', '1', '18', '25', '19', '22', '22'), +('5', '11', '2', '19', '25', '20', '23', '23'), +('5', '11', '3', '19', '26', '20', '24', '24'), +('5', '11', '4', '20', '26', '21', '25', '26'), +('5', '11', '5', '20', '27', '22', '26', '27'), +('5', '11', '6', '21', '27', '22', '27', '28'), +('5', '11', '7', '21', '28', '23', '28', '29'), +('5', '11', '8', '22', '28', '24', '29', '30'), +('5', '11', '9', '23', '29', '24', '30', '32'), +('5', '11', '10', '23', '29', '25', '32', '33'), +('5', '11', '11', '24', '30', '26', '33', '34'), +('5', '11', '12', '24', '31', '26', '34', '35'), +('5', '11', '13', '25', '31', '27', '35', '37'), +('5', '11', '14', '26', '32', '28', '36', '38'), +('5', '11', '15', '26', '32', '29', '37', '39'), +('5', '11', '16', '27', '33', '29', '38', '41'), +('5', '11', '17', '28', '33', '30', '40', '42'), +('5', '11', '18', '28', '34', '31', '41', '43'), +('5', '11', '19', '29', '35', '32', '42', '45'), +('5', '11', '20', '30', '35', '32', '43', '46'), +('5', '11', '21', '30', '36', '33', '45', '48'), +('5', '11', '22', '31', '36', '34', '46', '49'), +('5', '11', '23', '32', '37', '35', '47', '51'), +('5', '11', '24', '32', '38', '36', '48', '52'), +('5', '11', '25', '33', '38', '36', '50', '53'), +('5', '11', '26', '34', '39', '37', '51', '55'), +('5', '11', '27', '35', '40', '38', '52', '56'), +('5', '11', '28', '35', '40', '39', '54', '58'), +('5', '11', '29', '36', '41', '40', '55', '59'), +('5', '11', '30', '37', '42', '41', '56', '61'), +('5', '11', '31', '38', '42', '42', '58', '62'), +('5', '11', '32', '38', '43', '42', '59', '64'), +('5', '11', '33', '39', '44', '43', '60', '66'), +('5', '11', '34', '40', '44', '44', '62', '67'), +('5', '11', '35', '41', '45', '45', '63', '69'), +('5', '11', '36', '42', '46', '46', '65', '70'), +('5', '11', '37', '42', '47', '47', '66', '72'), +('5', '11', '38', '43', '47', '48', '67', '74'), +('5', '11', '39', '44', '48', '49', '69', '75'), +('5', '11', '40', '45', '49', '50', '70', '77'), +('5', '11', '41', '46', '50', '51', '72', '79'), +('5', '11', '42', '46', '50', '52', '73', '80'), +('5', '11', '43', '47', '51', '53', '75', '82'), +('5', '11', '44', '48', '52', '54', '76', '84'), +('5', '11', '45', '49', '53', '55', '78', '85'), +('5', '11', '46', '50', '54', '56', '79', '87'), +('5', '11', '47', '51', '54', '57', '81', '89'), +('5', '11', '48', '52', '55', '58', '83', '91'), +('5', '11', '49', '53', '56', '59', '84', '93'), +('5', '11', '50', '53', '57', '60', '86', '94'), +('5', '11', '51', '54', '58', '61', '87', '96'), +('5', '11', '52', '55', '59', '62', '89', '98'), +('5', '11', '53', '56', '59', '63', '91', '100'), +('5', '11', '54', '57', '60', '64', '92', '102'), +('5', '11', '55', '58', '61', '65', '94', '103'), +('5', '11', '56', '59', '62', '66', '95', '105'), +('5', '11', '57', '60', '63', '67', '97', '107'), +('5', '11', '58', '61', '64', '68', '99', '109'), +('5', '11', '59', '62', '65', '69', '101', '111'), +('5', '11', '60', '63', '66', '70', '102', '113'), +('5', '11', '61', '64', '66', '72', '104', '115'), +('5', '11', '62', '65', '67', '73', '106', '117'), +('5', '11', '63', '66', '68', '74', '107', '119'), +('5', '11', '64', '67', '69', '75', '109', '121'), +('5', '11', '65', '68', '70', '76', '111', '123'), +('5', '11', '66', '69', '71', '77', '113', '125'), +('5', '11', '67', '70', '72', '78', '115', '127'), +('5', '11', '68', '71', '73', '80', '116', '129'), +('5', '11', '69', '72', '74', '81', '118', '131'), +('5', '11', '70', '73', '75', '82', '120', '133'), +('5', '11', '71', '75', '76', '83', '122', '135'), +('5', '11', '72', '76', '78', '85', '125', '138'), +('5', '11', '73', '77', '79', '86', '127', '140'), +('5', '11', '74', '78', '80', '88', '131', '143'), +('5', '11', '75', '80', '81', '89', '133', '145'), +('5', '11', '76', '81', '82', '91', '134', '148'), +('5', '11', '77', '82', '83', '92', '136', '151'), +('5', '11', '78', '84', '85', '94', '138', '153'), +('5', '11', '79', '85', '86', '95', '141', '156'), +('5', '11', '80', '86', '87', '97', '143', '159'); + +-- playercreateinfo + +INSERT IGNORE INTO `playercreateinfo` VALUES +('1', '1', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '2', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '4', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '5', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '8', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '9', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('2', '1', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '3', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '4', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '7', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '9', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('3', '1', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '2', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '3', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '4', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '5', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('4', '1', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '3', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '4', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '5', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '11', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('5', '1', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '4', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '5', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '8', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '9', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('6', '1', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '3', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '7', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '11', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('7', '1', '0', '1', '-6240.32', '331.033', '382.758', '0'), +('7', '9', '0', '1', '-6240', '331', '383', '0'), +('7', '8', '0', '1', '-6240', '331', '383', '0'), +('7', '4', '0', '1', '-6240', '331', '383', '0'), +('8', '1', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '3', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '4', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '5', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '7', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '8', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('10', '2', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '3', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '4', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '5', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '8', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '9', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('11', '1', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '2', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '3', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '5', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '7', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '8', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('1', '6', '609', '4298', '2355.84', '-5664.77', '426.028', '3.65997'), +('2', '6', '609', '4298', '2358.44', '-5666.9', '426.023', '3.65997'), +('3', '6', '609', '4298', '2358.44', '-5666.9', '426.023', '3.65997'), +('4', '6', '609', '4298', '2356.21', '-5662.21', '426.026', '3.65997'), +('5', '6', '609', '4298', '2356.21', '-5662.21', '426.026', '3.65997'), +('6', '6', '609', '4298', '2358.17', '-5663.21', '426.027', '3.65997'), +('7', '6', '609', '4298', '2355.05', '-5661.7', '426.026', '3.65997'), +('8', '6', '609', '4298', '2355.05', '-5661.7', '426.026', '3.65997'), +('10', '6', '609', '4298', '2355.84', '-5664.77', '426.028', '3.65997'), +('11', '6', '609', '4298', '2358.17', '-5663.21', '426.027', '3.65997'), +('11', '4', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '9', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('11', '11', '530', '3526', '-3961.64', '-13931.2', '100.615', '2.08364'), +('10', '1', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '7', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('10', '11', '530', '3431', '10349.6', '-6357.29', '33.4026', '5.31605'), +('3', '7', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '8', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '9', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('3', '11', '0', '1', '-6240.32', '331.033', '382.758', '6.17716'), +('7', '2', '0', '1', '-6240.32', '331.033', '382.758', '0'), +('7', '3', '0', '1', '-6240.32', '331.033', '382.758', '0'), +('7', '5', '0', '1', '-6240', '331', '383', '0'), +('7', '7', '0', '1', '-6240', '331', '383', '0'), +('7', '11', '0', '1', '-6240', '331', '383', '0'), +('1', '3', '0', '0', '-8949.95', '-132.493', '83.5312', '0'), +('1', '7', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('1', '11', '0', '12', '-8949.95', '-132.493', '83.5312', '0'), +('4', '2', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '7', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '8', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('4', '9', '1', '141', '10311.3', '832.463', '1326.41', '5.69632'), +('2', '2', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '5', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('2', '8', '1', '14', '-618.518', '-4215.67', '38.718', '0'), +('2', '11', '1', '14', '-618.518', '-4215.67', '38.718', '0'), +('8', '2', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '9', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('8', '11', '1', '14', '-618.518', '-4251.67', '38.718', '0'), +('6', '2', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '4', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '5', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '8', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('6', '9', '1', '215', '-2917.58', '-257.98', '52.9968', '0'), +('5', '2', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '3', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '7', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'), +('5', '11', '0', '85', '1676.71', '1678.31', '121.67', '2.70526'); + +-- playercreateinfo_action + +INSERT IGNORE INTO `playercreateinfo_action` VALUES +('1', '1', '0', '6603', '0'), +('1', '1', '72', '6603', '0'), +('1', '1', '73', '78', '0'), +('1', '1', '82', '59752', '0'), +('1', '1', '84', '6603', '0'), +('1', '1', '96', '6603', '0'), +('1', '1', '108', '6603', '0'), +('1', '2', '0', '6603', '0'), +('1', '2', '1', '21084', '0'), +('1', '2', '2', '635', '0'), +('1', '2', '11', '59752', '0'), +('1', '4', '0', '6603', '0'), +('1', '4', '1', '1752', '0'), +('1', '4', '2', '2098', '0'), +('1', '4', '3', '2764', '0'), +('1', '4', '11', '59752', '0'), +('1', '5', '0', '585', '0'), +('1', '5', '1', '2050', '0'), +('1', '5', '11', '59752', '0'), +('1', '6', '0', '6603', '0'), +('1', '6', '1', '49576', '0'), +('1', '6', '2', '45477', '0'), +('1', '6', '3', '45462', '0'), +('1', '6', '4', '45902', '0'), +('1', '6', '5', '47541', '0'), +('1', '6', '11', '59752', '0'), +('1', '8', '0', '133', '0'), +('1', '8', '1', '168', '0'), +('1', '8', '11', '59752', '0'), +('1', '9', '0', '686', '0'), +('1', '9', '1', '687', '0'), +('1', '9', '11', '59752', '0'), +('2', '1', '0', '6603', '0'), +('2', '1', '72', '6603', '0'), +('2', '1', '73', '78', '0'), +('2', '1', '74', '20572', '0'), +('2', '1', '84', '6603', '0'), +('2', '1', '96', '6603', '0'), +('2', '1', '108', '6603', '0'), +('2', '3', '0', '6603', '0'), +('2', '3', '1', '2973', '0'), +('2', '3', '2', '75', '0'), +('2', '3', '11', '20572', '0'), +('2', '4', '0', '6603', '0'), +('2', '4', '1', '1752', '0'), +('2', '4', '2', '2098', '0'), +('2', '4', '3', '2764', '0'), +('2', '4', '4', '20572', '0'), +('2', '6', '0', '6603', '0'), +('2', '6', '1', '49576', '0'), +('2', '6', '2', '45477', '0'), +('2', '6', '3', '45462', '0'), +('2', '6', '4', '45902', '0'), +('2', '6', '5', '47541', '0'), +('2', '6', '10', '20572', '0'), +('2', '7', '0', '6603', '0'), +('2', '7', '1', '403', '0'), +('2', '7', '2', '331', '0'), +('2', '7', '3', '33697', '0'), +('2', '9', '0', '686', '0'), +('2', '9', '1', '687', '0'), +('2', '9', '2', '33702', '0'), +('3', '1', '0', '6603', '0'), +('3', '1', '1', '78', '0'), +('3', '1', '72', '6603', '0'), +('3', '1', '73', '78', '0'), +('3', '1', '74', '20594', '0'), +('3', '1', '75', '2481', '0'), +('3', '1', '84', '6603', '0'), +('3', '1', '96', '6603', '0'), +('3', '1', '108', '6603', '0'), +('3', '2', '0', '6603', '0'), +('3', '2', '1', '21084', '0'), +('3', '2', '2', '635', '0'), +('3', '2', '3', '20594', '0'), +('3', '2', '4', '2481', '0'), +('3', '3', '0', '6603', '0'), +('3', '3', '1', '2973', '0'), +('3', '3', '2', '75', '0'), +('3', '3', '3', '20594', '0'), +('3', '3', '4', '2481', '0'), +('3', '3', '75', '20594', '0'), +('3', '3', '76', '2481', '0'), +('3', '4', '0', '6603', '0'), +('3', '4', '1', '1752', '0'), +('3', '4', '2', '2098', '0'), +('3', '4', '3', '2764', '0'), +('3', '4', '4', '20594', '0'), +('3', '4', '5', '2481', '0'), +('3', '5', '0', '585', '0'), +('3', '5', '1', '2050', '0'), +('3', '5', '2', '20594', '0'), +('3', '5', '3', '2481', '0'), +('3', '6', '0', '6603', '0'), +('3', '6', '1', '49576', '0'), +('3', '6', '2', '45477', '0'), +('3', '6', '3', '45462', '0'), +('3', '6', '4', '45902', '0'), +('3', '6', '5', '47541', '0'), +('3', '6', '10', '2481', '0'), +('4', '1', '72', '6603', '0'), +('4', '4', '82', '58984', '0'), +('4', '1', '73', '78', '0'), +('4', '1', '82', '58984', '0'), +('4', '1', '85', '6603', '0'), +('4', '1', '97', '6603', '0'), +('4', '1', '109', '6603', '0'), +('4', '3', '0', '6603', '0'), +('4', '3', '1', '2973', '0'), +('4', '3', '2', '75', '0'), +('4', '3', '3', '58984', '0'), +('4', '4', '0', '6603', '0'), +('4', '4', '1', '1752', '0'), +('4', '4', '2', '2098', '0'), +('4', '4', '3', '2764', '0'), +('4', '4', '11', '58984', '0'), +('4', '5', '0', '585', '0'), +('4', '5', '1', '2050', '0'), +('4', '5', '2', '58984', '0'), +('4', '6', '0', '6603', '0'), +('4', '6', '1', '49576', '0'), +('4', '6', '2', '45477', '0'), +('4', '6', '3', '45462', '0'), +('4', '6', '4', '45902', '0'), +('4', '6', '5', '47541', '0'), +('4', '6', '10', '58984', '0'), +('4', '6', '83', '58984', '0'), +('4', '11', '0', '5176', '0'), +('4', '11', '1', '5185', '0'), +('4', '11', '11', '58984', '0'), +('5', '1', '0', '6603', '0'), +('5', '1', '72', '6603', '0'), +('5', '1', '73', '78', '0'), +('5', '1', '74', '20577', '0'), +('5', '1', '84', '6603', '0'), +('5', '1', '96', '6603', '0'), +('5', '1', '108', '6603', '0'), +('5', '4', '0', '6603', '0'), +('5', '4', '1', '1752', '0'), +('5', '4', '2', '2098', '0'), +('5', '4', '3', '2764', '0'), +('5', '4', '4', '20577', '0'), +('5', '5', '0', '585', '0'), +('5', '5', '1', '2050', '0'), +('5', '5', '2', '20577', '0'), +('5', '6', '0', '6603', '0'), +('5', '6', '1', '49576', '0'), +('5', '6', '2', '45477', '0'), +('5', '6', '3', '45462', '0'), +('5', '6', '4', '45902', '0'), +('5', '6', '5', '47541', '0'), +('5', '6', '10', '20577', '0'), +('5', '8', '0', '133', '0'), +('5', '8', '1', '168', '0'), +('5', '8', '2', '20577', '0'), +('5', '9', '0', '686', '0'), +('5', '9', '1', '687', '0'), +('5', '9', '2', '20577', '0'), +('6', '1', '0', '6603', '0'), +('6', '1', '1', '78', '0'), +('6', '1', '3', '20549', '0'), +('6', '1', '72', '6603', '0'), +('6', '1', '73', '78', '0'), +('6', '1', '74', '20549', '0'), +('6', '1', '84', '6603', '0'), +('6', '1', '96', '6603', '0'), +('6', '1', '108', '6603', '0'), +('6', '3', '0', '6603', '0'), +('6', '3', '1', '2973', '0'), +('6', '3', '2', '75', '0'), +('6', '3', '3', '20549', '0'), +('6', '3', '76', '20549', '0'), +('6', '6', '0', '6603', '0'), +('6', '6', '1', '49576', '0'), +('6', '6', '2', '45477', '0'), +('6', '6', '3', '45462', '0'), +('6', '6', '4', '45902', '0'), +('6', '6', '5', '47541', '0'), +('6', '6', '10', '20549', '0'), +('6', '6', '75', '20549', '0'), +('6', '7', '0', '6603', '0'), +('6', '7', '1', '403', '0'), +('6', '7', '2', '331', '0'), +('6', '7', '3', '20549', '0'), +('6', '7', '76', '20549', '0'), +('6', '11', '0', '5176', '0'), +('6', '11', '1', '5185', '0'), +('6', '11', '2', '20549', '0'), +('6', '11', '73', '6603', '0'), +('6', '11', '76', '20549', '0'), +('6', '11', '85', '6603', '0'), +('6', '11', '97', '6603', '0'), +('6', '11', '109', '6603', '0'), +('7', '1', '0', '6603', '0'), +('7', '1', '1', '78', '0'), +('7', '1', '11', '20589', '0'), +('7', '1', '72', '6603', '0'), +('7', '1', '73', '78', '0'), +('7', '1', '82', '20589', '0'), +('7', '1', '84', '6603', '0'), +('7', '1', '96', '6603', '0'), +('7', '1', '108', '6603', '0'), +('7', '4', '0', '6603', '0'), +('7', '4', '1', '1752', '0'), +('7', '4', '2', '2098', '0'), +('7', '4', '3', '2764', '0'), +('7', '4', '11', '20589', '0'), +('7', '6', '0', '6603', '0'), +('7', '6', '1', '49576', '0'), +('7', '6', '2', '45477', '0'), +('7', '6', '3', '45462', '0'), +('7', '6', '4', '45902', '0'), +('7', '6', '5', '47541', '0'), +('7', '6', '10', '20589', '0'), +('7', '6', '83', '41751', '128'), +('7', '6', '72', '6603', '0'), +('7', '6', '11', '41751', '128'), +('7', '6', '84', '6603', '0'), +('7', '6', '96', '6603', '0'), +('7', '6', '108', '6603', '0'), +('7', '8', '0', '133', '0'), +('7', '8', '1', '168', '0'), +('7', '8', '11', '20589', '0'), +('7', '9', '0', '686', '0'), +('7', '9', '1', '687', '0'), +('7', '9', '11', '20589', '0'), +('8', '1', '0', '6603', '0'), +('8', '1', '72', '6603', '0'), +('8', '1', '73', '78', '0'), +('8', '1', '74', '2764', '0'), +('8', '1', '75', '26297', '0'), +('8', '1', '84', '6603', '0'), +('8', '1', '96', '6603', '0'), +('8', '1', '108', '6603', '0'), +('8', '3', '0', '6603', '0'), +('8', '3', '1', '2973', '0'), +('8', '3', '2', '75', '0'), +('8', '8', '2', '26297', '0'), +('8', '4', '0', '6603', '0'), +('8', '4', '1', '1752', '0'), +('8', '4', '2', '2098', '0'), +('8', '4', '3', '2764', '0'), +('8', '4', '4', '26297', '0'), +('8', '5', '0', '585', '0'), +('8', '5', '1', '2050', '0'), +('8', '7', '3', '26297', '0'), +('8', '6', '0', '6603', '0'), +('8', '6', '1', '49576', '0'), +('8', '6', '2', '45477', '0'), +('8', '6', '3', '45462', '0'), +('8', '6', '4', '45902', '0'), +('8', '6', '5', '47541', '0'), +('8', '6', '10', '26297', '0'), +('8', '7', '0', '6603', '0'), +('8', '7', '1', '403', '0'), +('8', '7', '2', '331', '0'), +('8', '5', '2', '26297', '0'), +('8', '8', '0', '133', '0'), +('8', '8', '1', '168', '0'), +('8', '3', '3', '26297', '0'), +('10', '2', '0', '6603', '0'), +('10', '2', '1', '21084', '0'), +('10', '2', '2', '635', '0'), +('10', '2', '3', '28730', '0'), +('10', '3', '0', '6603', '0'), +('10', '3', '1', '2973', '0'), +('10', '3', '2', '75', '0'), +('10', '3', '3', '28730', '0'), +('10', '4', '0', '6603', '0'), +('10', '4', '1', '1752', '0'), +('10', '4', '2', '2098', '0'), +('10', '4', '3', '2764', '0'), +('10', '4', '4', '25046', '0'), +('10', '5', '0', '585', '0'), +('10', '5', '1', '2050', '0'), +('10', '5', '2', '28730', '0'), +('10', '6', '0', '6603', '0'), +('10', '6', '1', '49576', '0'), +('10', '6', '2', '45477', '0'), +('10', '6', '3', '45462', '0'), +('10', '6', '4', '45902', '0'), +('10', '6', '5', '47541', '0'), +('10', '6', '6', '50613', '0'), +('10', '8', '0', '133', '0'), +('10', '8', '1', '168', '0'), +('10', '8', '2', '28730', '0'), +('10', '9', '0', '686', '0'), +('10', '9', '1', '687', '0'), +('10', '9', '2', '28730', '0'), +('11', '1', '0', '6603', '0'), +('11', '1', '72', '6603', '0'), +('11', '1', '73', '78', '0'), +('11', '1', '74', '28880', '0'), +('11', '1', '84', '6603', '0'), +('11', '1', '96', '6603', '0'), +('11', '1', '108', '6603', '0'), +('11', '2', '0', '6603', '0'), +('11', '2', '1', '21084', '0'), +('11', '2', '2', '635', '0'), +('11', '2', '3', '59542', '0'), +('11', '3', '0', '6603', '0'), +('11', '3', '1', '2973', '0'), +('11', '3', '2', '75', '0'), +('11', '3', '3', '59543', '0'), +('11', '3', '72', '6603', '0'), +('11', '3', '73', '2973', '0'), +('11', '3', '74', '75', '0'), +('11', '5', '0', '585', '0'), +('11', '5', '1', '2050', '0'), +('11', '5', '2', '59544', '0'), +('11', '6', '0', '6603', '0'), +('11', '6', '1', '49576', '0'), +('11', '6', '2', '45477', '0'), +('11', '6', '3', '45462', '0'), +('11', '6', '4', '45902', '0'), +('11', '6', '5', '47541', '0'), +('11', '6', '10', '59545', '0'), +('11', '7', '0', '6603', '0'), +('11', '7', '1', '403', '0'), +('11', '7', '2', '331', '0'), +('11', '7', '3', '59547', '0'), +('11', '8', '0', '133', '0'), +('11', '8', '1', '168', '0'), +('11', '8', '2', '59548', '0'), +('11', '6', '11', '41751', '128'), +('11', '4', '3', '2764', '0'), +('11', '4', '11', '28880', '0'), +('11', '4', '2', '2098', '0'), +('11', '4', '1', '1752', '0'), +('11', '4', '0', '6603', '0'), +('11', '9', '1', '687', '0'), +('11', '9', '11', '28880', '0'), +('11', '9', '0', '686', '0'), +('11', '11', '1', '5185', '0'), +('11', '11', '11', '28880', '0'), +('11', '11', '0', '5176', '0'), +('10', '1', '108', '6603', '0'), +('10', '1', '73', '78', '0'), +('10', '1', '82', '28730', '0'), +('10', '1', '84', '6603', '0'), +('10', '1', '96', '6603', '0'), +('10', '1', '72', '6603', '0'), +('10', '1', '0', '6603', '0'), +('10', '7', '2', '331', '0'), +('10', '7', '3', '20554', '0'), +('10', '7', '1', '403', '0'), +('10', '7', '0', '6603', '0'), +('10', '11', '1', '5185', '0'), +('10', '11', '11', '28730', '0'), +('10', '11', '0', '5176', '0'), +('3', '7', '3', '20594', '0'), +('3', '7', '4', '2481', '0'), +('3', '7', '1', '403', '0'), +('3', '7', '2', '331', '0'), +('3', '7', '0', '6603', '0'), +('3', '8', '11', '20594', '0'), +('3', '8', '10', '2481', '0'), +('3', '8', '0', '133', '0'), +('3', '8', '1', '168', '0'), +('3', '9', '11', '20594', '0'), +('3', '9', '10', '2481', '0'), +('3', '9', '0', '686', '0'), +('3', '9', '1', '687', '0'), +('3', '11', '1', '5185', '0'), +('3', '11', '11', '20594', '0'), +('3', '11', '10', '2481', '0'), +('3', '11', '0', '5176', '0'), +('7', '2', '1', '21084', '0'), +('7', '2', '11', '20589', '0'), +('7', '2', '0', '6603', '0'), +('7', '2', '2', '635', '0'), +('7', '3', '2', '75', '0'), +('7', '3', '0', '6603', '0'), +('7', '3', '1', '2973', '0'), +('7', '3', '11', '20589', '0'), +('7', '5', '0', '585', '0'), +('7', '5', '11', '20589', '0'), +('7', '5', '1', '2050', '0'), +('7', '7', '0', '6603', '0'), +('7', '7', '1', '403', '0'), +('7', '7', '2', '331', '0'), +('7', '7', '3', '20589', '0'), +('7', '11', '11', '20589', '0'), +('7', '11', '1', '5185', '0'), +('7', '11', '0', '5176', '0'), +('1', '3', '11', '59752', '0'), +('1', '3', '1', '2973', '0'), +('1', '3', '0', '6603', '0'), +('1', '3', '2', '75', '0'), +('1', '7', '0', '6603', '0'), +('1', '7', '3', '59752', '0'), +('1', '7', '1', '403', '0'), +('1', '7', '2', '331', '0'), +('1', '11', '0', '5176', '0'), +('1', '11', '1', '5185', '0'), +('1', '11', '11', '59752', '0'), +('4', '2', '2', '635', '0'), +('4', '2', '1', '21084', '0'), +('4', '2', '0', '6603', '0'), +('4', '2', '11', '58984', '0'), +('4', '7', '2', '331', '0'), +('4', '7', '3', '58984', '0'), +('4', '7', '1', '403', '0'), +('4', '7', '0', '6603', '0'), +('4', '8', '11', '58984', '0'), +('4', '8', '1', '168', '0'), +('4', '8', '0', '133', '0'), +('4', '9', '11', '58984', '0'), +('4', '9', '0', '686', '0'), +('4', '9', '1', '687', '0'), +('2', '2', '0', '6603', '0'), +('2', '2', '11', '20572', '0'), +('2', '2', '2', '635', '0'), +('2', '2', '1', '21084', '0'), +('2', '5', '0', '585', '0'), +('2', '5', '1', '2050', '0'), +('2', '5', '11', '20572', '0'), +('2', '8', '11', '20572', '0'), +('2', '8', '1', '168', '0'), +('2', '8', '0', '133', '0'), +('2', '11', '85', '6603', '0'), +('2', '11', '0', '5176', '0'), +('2', '11', '109', '6603', '0'), +('2', '11', '2', '20572', '0'), +('2', '11', '1', '5185', '0'), +('2', '11', '73', '6603', '0'), +('2', '11', '97', '6603', '0'), +('2', '11', '76', '20572', '0'), +('8', '2', '11', '20554', '0'), +('8', '2', '2', '635', '0'), +('8', '2', '1', '21084', '0'), +('8', '2', '0', '6603', '0'), +('8', '9', '0', '686', '0'), +('8', '9', '11', '20554', '0'), +('8', '9', '1', '687', '0'), +('8', '11', '0', '5176', '0'), +('8', '11', '11', '20554', '0'), +('8', '11', '1', '5185', '0'), +('6', '2', '11', '59752', '0'), +('6', '2', '0', '6603', '0'), +('6', '2', '1', '21084', '0'), +('6', '2', '2', '635', '0'), +('6', '4', '11', '20549', '0'), +('6', '4', '2', '2098', '0'), +('6', '4', '1', '1752', '0'), +('6', '4', '3', '2764', '0'), +('6', '4', '0', '6603', '0'), +('6', '5', '11', '20549', '0'), +('6', '5', '1', '2050', '0'), +('6', '5', '0', '585', '0'), +('6', '8', '1', '168', '0'), +('6', '8', '0', '133', '0'), +('6', '8', '11', '20549', '0'), +('6', '9', '11', '20549', '0'), +('6', '9', '0', '686', '0'), +('6', '9', '1', '687', '0'), +('5', '2', '1', '21084', '0'), +('5', '2', '11', '20577', '0'), +('5', '2', '2', '635', '0'), +('5', '2', '0', '6603', '0'), +('5', '3', '2', '75', '0'), +('5', '3', '0', '6603', '0'), +('5', '3', '1', '2973', '0'), +('5', '3', '11', '20577', '0'), +('5', '7', '0', '6603', '0'), +('5', '7', '1', '403', '0'), +('5', '7', '2', '331', '0'), +('5', '7', '3', '20577', '0'), +('5', '11', '11', '20577', '0'), +('5', '11', '0', '5176', '0'), +('5', '11', '1', '5185', '0'); + +-- playercreateinfo_item + +INSERT IGNORE INTO `playercreateinfo_item` VALUES +('0', '6', '40582', '-1', ''), +('1', '3', '129', '1', ''), +('1', '3', '147', '1', ''), +('1', '3', '148', '1', ''), +('1', '3', '2508', '1', ''), +('1', '3', '2102', '1', ''), +('1', '3', '2516', '200', ''), +('1', '3', '12282', '1', ''), +('1', '3', '6948', '1', ''), +('1', '7', '153', '1', ''), +('1', '7', '154', '1', ''), +('1', '7', '36', '1', ''), +('1', '7', '2362', '1', ''), +('1', '7', '6948', '1', ''), +('1', '11', '6123', '1', ''), +('1', '11', '6124', '1', ''), +('1', '11', '3661', '1', ''), +('1', '11', '6948', '1', ''), +('2', '2', '43', '1', ''), +('2', '2', '44', '1', ''), +('2', '2', '45', '1', ''), +('2', '2', '2361', '1', ''), +('2', '2', '6948', '1', ''), +('2', '5', '51', '1', ''), +('2', '5', '52', '1', ''), +('2', '5', '53', '1', ''), +('2', '5', '6144', '1', ''), +('2', '5', '35', '1', ''), +('2', '5', '6948', '1', ''), +('2', '8', '55', '1', ''), +('2', '8', '6096', '1', ''), +('2', '8', '1395', '1', ''), +('2', '8', '6140', '1', ''), +('2', '8', '35', '1', ''), +('2', '8', '6948', '1', ''), +('2', '11', '6139', '1', ''), +('2', '11', '6124', '1', ''), +('2', '11', '35', '1', ''), +('2', '11', '6948', '1', ''), +('3', '7', '153', '1', ''), +('3', '7', '154', '1', ''), +('3', '7', '36', '1', ''), +('3', '7', '2362', '1', ''), +('3', '7', '6948', '1', ''), +('3', '9', '57', '1', ''), +('3', '9', '59', '1', ''), +('3', '9', '1396', '1', ''), +('3', '9', '6097', '1', ''), +('3', '9', '35', '1', ''), +('3', '9', '6948', '1', ''), +('3', '11', '6139', '1', ''), +('3', '11', '6124', '1', ''), +('3', '11', '3661', '1', ''), +('3', '11', '6948', '1', ''), +('4', '2', '43', '1', ''), +('4', '2', '44', '1', ''), +('4', '2', '45', '1', ''), +('4', '2', '2361', '1', ''), +('4', '2', '6948', '1', ''), +('4', '7', '153', '1', ''), +('4', '7', '154', '1', ''), +('4', '7', '36', '1', ''), +('4', '7', '2362', '1', ''), +('4', '7', '6948', '1', ''), +('4', '8', '55', '1', ''), +('4', '8', '6096', '1', ''), +('4', '8', '1395', '1', ''), +('4', '8', '56', '1', ''), +('4', '8', '35', '1', ''), +('4', '8', '6948', '1', ''), +('4', '9', '57', '1', ''), +('4', '9', '59', '1', ''), +('4', '9', '1396', '1', ''), +('4', '9', '6097', '1', ''), +('4', '9', '35', '1', ''), +('4', '9', '6948', '1', ''), +('5', '2', '43', '1', ''), +('5', '2', '44', '1', ''), +('5', '2', '45', '1', ''), +('5', '2', '2361', '1', ''), +('5', '2', '6948', '1', ''), +('5', '3', '129', '1', ''), +('5', '3', '147', '1', ''), +('5', '3', '148', '1', ''), +('5', '3', '2508', '1', ''), +('5', '3', '2102', '1', ''), +('5', '3', '2516', '200', ''), +('5', '3', '12282', '1', ''), +('5', '3', '6948', '1', ''), +('5', '7', '153', '1', ''), +('5', '7', '154', '1', ''), +('5', '7', '36', '1', ''), +('5', '7', '2362', '1', ''), +('5', '7', '6948', '1', ''), +('5', '11', '6139', '1', ''), +('5', '11', '6124', '1', ''), +('5', '11', '35', '1', ''), +('5', '11', '6948', '1', ''), +('6', '2', '43', '1', ''), +('6', '2', '44', '1', ''), +('6', '2', '45', '1', ''), +('6', '2', '23346', '1', ''), +('6', '2', '6948', '1', ''), +('6', '4', '120', '1', ''), +('6', '4', '121', '1', ''), +('6', '4', '2105', '1', ''), +('6', '4', '2092', '1', ''), +('6', '4', '50055', '1', ''), +('6', '4', '28979', '1', ''), +('6', '4', '6948', '1', ''), +('6', '5', '51', '1', ''), +('6', '5', '52', '1', ''), +('6', '5', '53', '1', ''), +('6', '5', '6144', '1', ''), +('6', '5', '35', '1', ''), +('6', '5', '6948', '1', ''), +('6', '8', '55', '1', ''), +('6', '8', '6096', '1', ''), +('6', '8', '1395', '1', ''), +('6', '8', '6140', '1', ''), +('6', '8', '35', '1', ''), +('6', '8', '6948', '1', ''), +('6', '9', '6129', '1', ''), +('6', '9', '59', '1', ''), +('6', '9', '1396', '1', ''), +('6', '9', '6097', '1', ''), +('6', '9', '35', '1', ''), +('6', '9', '6948', '1', ''), +('7', '2', '43', '1', ''), +('7', '2', '44', '1', ''), +('7', '2', '45', '1', ''), +('7', '2', '2361', '1', ''), +('7', '2', '6948', '1', ''), +('7', '3', '129', '1', ''), +('7', '3', '147', '1', ''), +('7', '3', '148', '1', ''), +('7', '3', '2508', '1', ''), +('7', '3', '2102', '1', ''), +('7', '3', '2516', '200', ''), +('7', '3', '12282', '1', ''), +('7', '3', '6948', '1', ''), +('7', '5', '51', '1', ''), +('7', '5', '52', '1', ''), +('7', '5', '53', '1', ''), +('7', '5', '6098', '1', ''), +('7', '5', '35', '1', ''), +('7', '5', '6948', '1', ''), +('7', '7', '153', '1', ''), +('7', '7', '154', '1', ''), +('7', '7', '36', '1', ''), +('7', '7', '2362', '1', ''), +('7', '7', '6948', '1', ''), +('7', '11', '6139', '1', ''), +('7', '11', '6124', '1', ''), +('7', '11', '3661', '1', ''), +('7', '11', '6948', '1', ''), +('8', '2', '43', '1', ''), +('8', '2', '44', '1', ''), +('8', '2', '45', '1', ''), +('8', '2', '2361', '1', ''), +('8', '2', '6948', '1', ''), +('8', '9', '6129', '1', ''), +('8', '9', '59', '1', ''), +('8', '9', '1396', '1', ''), +('8', '9', '6097', '1', ''), +('8', '9', '35', '1', ''), +('8', '9', '6948', '1', ''), +('8', '11', '6139', '1', ''), +('8', '11', '6124', '1', ''), +('8', '11', '35', '1', ''), +('8', '11', '6948', '1', ''), +('10', '1', '20915', '1', ''), +('10', '1', '20918', '1', ''), +('10', '1', '20919', '1', ''), +('10', '1', '23346', '1', ''), +('10', '1', '6948', '1', ''), +('10', '7', '153', '1', ''), +('10', '7', '154', '1', ''), +('10', '7', '36', '1', ''), +('10', '7', '2362', '1', ''), +('10', '7', '6948', '1', ''), +('10', '11', '6123', '1', ''), +('10', '11', '6124', '1', ''), +('10', '11', '3661', '1', ''), +('10', '11', '6948', '1', ''), +('11', '4', '120', '1', ''), +('11', '4', '121', '1', ''), +('11', '4', '2105', '1', ''), +('11', '4', '2092', '1', ''), +('11', '4', '50055', '1', ''), +('11', '4', '28979', '1', ''), +('11', '4', '6948', '1', ''), +('11', '9', '6129', '1', ''), +('11', '9', '59', '1', ''), +('11', '9', '1396', '1', ''), +('11', '9', '6097', '1', ''), +('11', '9', '35', '1', ''), +('11', '9', '6948', '1', ''), +('11', '11', '6123', '1', ''), +('11', '11', '6124', '1', ''), +('11', '11', '3661', '1', ''), +('11', '11', '6948', '1', ''); + +-- playercreateinfo_spell_custom + +INSERT IGNORE INTO `playercreateinfo_spell_custom` VALUES +('1', '1', '78', 'Heroic Strike'), +('1', '1', '81', 'Dodge'), +('1', '1', '107', 'Block'), +('1', '1', '196', 'One-Handed Axes'), +('1', '1', '198', 'One-Handed Maces'), +('1', '1', '201', 'One-Handed Swords'), +('1', '1', '203', 'Unarmed'), +('1', '1', '204', 'Defense'), +('1', '1', '522', 'SPELLDEFENSE(DND)'), +('1', '1', '668', 'Language Common'), +('1', '1', '2382', 'Generic'), +('1', '1', '2457', 'Battle Stance'), +('1', '1', '2479', 'Honorless Target'), +('1', '1', '3050', 'Detect'), +('1', '1', '3365', 'Opening'), +('1', '1', '5301', 'Defensive State(DND)'), +('1', '1', '6233', 'Closing'), +('1', '1', '6246', 'Closing'), +('1', '1', '6247', 'Opening'), +('1', '1', '6477', 'Opening'), +('1', '1', '6478', 'Opening'), +('1', '1', '6603', 'Attack'), +('1', '1', '7266', 'Duel'), +('1', '1', '7267', 'Grovel'), +('1', '1', '7355', 'Stuck'), +('1', '1', '7376', 'Defensive Stance Passive'), +('1', '1', '7381', 'Berserker Stance Passive'), +('1', '1', '8386', 'Attacking'), +('1', '1', '8737', 'Mail'), +('1', '1', '9077', 'Leather'), +('1', '1', '9078', 'Cloth'), +('1', '1', '9116', 'Shield'), +('1', '1', '9125', 'Generic'), +('1', '1', '20597', 'Sword Specialization'), +('1', '1', '20598', 'The Human Spirit'), +('1', '1', '20599', 'Diplomacy'), +('1', '1', '20600', 'Perception'), +('1', '1', '20864', 'Mace Specialization'), +('1', '1', '21156', 'Battle Stance Passive'), +('1', '1', '21651', 'Opening'), +('1', '1', '21652', 'Closing'), +('1', '1', '22027', 'Remove Insignia'), +('1', '1', '22810', 'Opening - No Text'), +('1', '1', '32215', 'Victorious State'), +('1', '2', '81', 'Dodge'), +('1', '2', '107', 'Block'), +('1', '2', '198', 'One-Handed Maces'), +('1', '2', '199', 'Two-Handed Maces'), +('1', '2', '203', 'Unarmed'), +('1', '2', '204', 'Defense'), +('1', '2', '522', 'SPELLDEFENSE(DND)'), +('1', '2', '635', 'Holy Light'), +('1', '2', '668', 'Language Common'), +('1', '2', '2382', 'Generic'), +('1', '2', '2479', 'Honorless Target'), +('1', '2', '3050', 'Detect'), +('1', '2', '3365', 'Opening'), +('1', '2', '6233', 'Closing'), +('1', '2', '6246', 'Closing'), +('1', '2', '6247', 'Opening'), +('1', '2', '6477', 'Opening'), +('1', '2', '6478', 'Opening'), +('1', '2', '6603', 'Attack'), +('1', '2', '7266', 'Duel'), +('1', '2', '7267', 'Grovel'), +('1', '2', '7355', 'Stuck'), +('1', '2', '8386', 'Attacking'), +('1', '2', '8737', 'Mail'), +('1', '2', '9077', 'Leather'), +('1', '2', '9078', 'Cloth'), +('1', '2', '9116', 'Shield'), +('1', '2', '9125', 'Generic'), +('1', '2', '21084', 'Seal of Righteousness'), +('1', '2', '20597', 'Sword Specialization'), +('1', '2', '20598', 'The Human Spirit'), +('1', '2', '20599', 'Diplomacy'), +('1', '2', '20600', 'Perception'), +('1', '2', '20864', 'Mace Specialization'), +('1', '2', '21651', 'Opening'), +('1', '2', '21652', 'Closing'), +('1', '2', '22027', 'Remove Insignia'), +('1', '2', '22810', 'Opening - No Text'), +('1', '2', '27762', 'Libram'), +('1', '8', '81', 'Dodge'), +('1', '8', '203', 'Unarmed'), +('1', '8', '204', 'Defense'), +('1', '8', '522', 'SPELLDEFENSE(DND)'), +('1', '8', '668', 'Language Common'), +('1', '8', '1180', 'Daggers'), +('1', '8', '1752', 'Sinister Strike'), +('1', '8', '2098', 'Eviscerate'), +('1', '8', '2382', 'Generic'), +('1', '8', '2479', 'Honorless Target'), +('1', '8', '2567', 'Thrown'), +('1', '8', '2764', 'Throw'), +('1', '8', '3050', 'Detect'), +('1', '8', '3365', 'Opening'), +('1', '8', '6233', 'Closing'), +('1', '8', '6246', 'Closing'), +('1', '8', '6247', 'Opening'), +('1', '8', '6477', 'Opening'), +('1', '8', '6478', 'Opening'), +('1', '8', '6603', 'Attack'), +('1', '8', '7266', 'Duel'), +('1', '8', '7267', 'Grovel'), +('1', '8', '7355', 'Stuck'), +('1', '8', '8386', 'Attacking'), +('1', '8', '9077', 'Leather'), +('1', '8', '9078', 'Cloth'), +('1', '8', '9125', 'Generic'), +('1', '8', '16092', 'Defensive State(DND)'), +('1', '8', '20597', 'Sword Specialization'), +('1', '8', '20598', 'The Human Spirit'), +('1', '8', '20599', 'Diplomacy'), +('1', '8', '20600', 'Perception'), +('1', '8', '20864', 'Mace Specialization'), +('1', '8', '21184', 'Rogue Passive(DND)'), +('1', '8', '21651', 'Opening'), +('1', '8', '21652', 'Closing'), +('1', '8', '22027', 'Remove Insignia'), +('1', '8', '22810', 'Opening - No Text'), +('1', '16', '81', 'Dodge'), +('1', '16', '198', 'One-Handed Maces'), +('1', '16', '203', 'Unarmed'), +('1', '16', '204', 'Defense'), +('1', '16', '522', 'SPELLDEFENSE(DND)'), +('1', '16', '585', 'Smite'), +('1', '16', '668', 'Language Common'), +('1', '16', '2050', 'Lesser Heal'), +('1', '16', '2382', 'Generic'), +('1', '16', '2479', 'Honorless Target'), +('1', '16', '3050', 'Detect'), +('1', '16', '3365', 'Opening'), +('1', '16', '5009', 'Wands'), +('1', '16', '5019', 'Shoot'), +('1', '16', '6233', 'Closing'), +('1', '16', '6246', 'Closing'), +('1', '16', '6247', 'Opening'), +('1', '16', '6477', 'Opening'), +('1', '16', '6478', 'Opening'), +('1', '16', '6603', 'Attack'), +('1', '16', '7266', 'Duel'), +('1', '16', '7267', 'Grovel'), +('1', '16', '7355', 'Stuck'), +('1', '16', '8386', 'Attacking'), +('1', '16', '9078', 'Cloth'), +('1', '16', '9125', 'Generic'), +('1', '16', '20597', 'Sword Specialization'), +('1', '16', '20598', 'The Human Spirit'), +('1', '16', '20599', 'Diplomacy'), +('1', '16', '20600', 'Perception'), +('1', '16', '20864', 'Mace Specialization'), +('1', '16', '21651', 'Opening'), +('1', '16', '21652', 'Closing'), +('1', '16', '22027', 'Remove Insignia'), +('1', '16', '22810', 'Opening - No Text'), +('1', '128', '81', 'Dodge'), +('1', '128', '133', 'Fireball'), +('1', '128', '168', 'Frost Armor'), +('1', '128', '203', 'Unarmed'), +('1', '128', '204', 'Defense'), +('1', '128', '227', 'Staves'), +('1', '128', '522', 'SPELLDEFENSE(DND)'), +('1', '128', '668', 'Language Common'), +('1', '128', '2382', 'Generic'), +('1', '128', '2479', 'Honorless Target'), +('1', '128', '3050', 'Detect'), +('1', '128', '3365', 'Opening'), +('1', '128', '5009', 'Wands'), +('1', '128', '5019', 'Shoot'), +('1', '128', '6233', 'Closing'), +('1', '128', '6246', 'Closing'), +('1', '128', '6247', 'Opening'), +('1', '128', '6477', 'Opening'), +('1', '128', '6478', 'Opening'), +('1', '128', '6603', 'Attack'), +('1', '128', '7266', 'Duel'), +('1', '128', '7267', 'Grovel'), +('1', '128', '7355', 'Stuck'), +('1', '128', '8386', 'Attacking'), +('1', '128', '9078', 'Cloth'), +('1', '128', '9125', 'Generic'), +('1', '128', '20597', 'Sword Specialization'), +('1', '128', '20598', 'The Human Spirit'), +('1', '128', '20599', 'Diplomacy'), +('1', '128', '20600', 'Perception'), +('1', '128', '20864', 'Mace Specialization'), +('1', '128', '21651', 'Opening'), +('1', '128', '21652', 'Closing'), +('1', '128', '22027', 'Remove Insignia'), +('1', '128', '22810', 'Opening - No Text'), +('1', '256', '81', 'Dodge'), +('1', '256', '203', 'Unarmed'), +('1', '256', '204', 'Defense'), +('1', '256', '522', 'SPELLDEFENSE(DND)'), +('1', '256', '668', 'Language Common'), +('1', '256', '686', 'Shadow Bolt'), +('1', '256', '687', 'Demon Skin'), +('1', '256', '1180', 'Daggers'), +('1', '256', '2382', 'Generic'), +('1', '256', '2479', 'Honorless Target'), +('1', '256', '3050', 'Detect'), +('1', '256', '3365', 'Opening'), +('1', '256', '5009', 'Wands'), +('1', '256', '5019', 'Shoot'), +('1', '256', '6233', 'Closing'), +('1', '256', '6246', 'Closing'), +('1', '256', '6247', 'Opening'), +('1', '256', '6477', 'Opening'), +('1', '256', '6478', 'Opening'), +('1', '256', '6603', 'Attack'), +('1', '256', '7266', 'Duel'), +('1', '256', '7267', 'Grovel'), +('1', '256', '7355', 'Stuck'), +('1', '256', '8386', 'Attacking'), +('1', '256', '9078', 'Cloth'), +('1', '256', '9125', 'Generic'), +('1', '256', '20597', 'Sword Specialization'), +('1', '256', '20598', 'The Human Spirit'), +('1', '256', '20599', 'Diplomacy'), +('1', '256', '20600', 'Perception'), +('1', '256', '20864', 'Mace Specialization'), +('1', '256', '21651', 'Opening'), +('1', '256', '21652', 'Closing'), +('1', '256', '22027', 'Remove Insignia'), +('1', '256', '22810', 'Opening - No Text'), +('2', '1', '78', 'Heroic Strike'), +('2', '1', '81', 'Dodge'), +('2', '1', '107', 'Block'), +('2', '1', '196', 'One-Handed Axes'), +('2', '1', '197', 'Two-Handed Axes'), +('2', '1', '201', 'One-Handed Swords'), +('2', '1', '203', 'Unarmed'), +('2', '1', '204', 'Defense'), +('2', '1', '522', 'SPELLDEFENSE(DND)'), +('2', '1', '669', 'Language Orcish'), +('2', '1', '2382', 'Generic'), +('2', '1', '2457', 'Battle Stance'), +('2', '1', '2479', 'Honorless Target'), +('2', '1', '3050', 'Detect'), +('2', '1', '3365', 'Opening'), +('2', '1', '5301', 'Defensive State(DND)'), +('2', '1', '6233', 'Closing'), +('2', '1', '6246', 'Closing'), +('2', '1', '6247', 'Opening'), +('2', '1', '6477', 'Opening'), +('2', '1', '6478', 'Opening'), +('2', '1', '6603', 'Attack'), +('2', '1', '7266', 'Duel'), +('2', '1', '7267', 'Grovel'), +('2', '1', '7355', 'Stuck'), +('2', '1', '7376', 'Defensive Stance Passive'), +('2', '1', '7381', 'Berserker Stance Passive'), +('2', '1', '8386', 'Attacking'), +('2', '1', '8737', 'Mail'), +('2', '1', '9077', 'Leather'), +('2', '1', '9078', 'Cloth'), +('2', '1', '9116', 'Shield'), +('2', '1', '9125', 'Generic'), +('2', '1', '20572', 'Blood Fury'), +('2', '1', '20573', 'Hardiness'), +('2', '1', '20574', 'Axe Specialization'), +('2', '1', '21156', 'Battle Stance Passive'), +('2', '1', '21563', 'Command'), +('2', '1', '21651', 'Opening'), +('2', '1', '21652', 'Closing'), +('2', '1', '22027', 'Remove Insignia'), +('2', '1', '22810', 'Opening - No Text'), +('2', '1', '32215', 'Victorious State'), +('2', '4', '75', 'Auto Shot'), +('2', '4', '81', 'Dodge'), +('2', '4', '196', 'One-Handed Axes'), +('2', '4', '203', 'Unarmed'), +('2', '4', '204', 'Defense'), +('2', '4', '264', 'Bows'), +('2', '4', '522', 'SPELLDEFENSE(DND)'), +('2', '4', '669', 'Language Orcish'), +('2', '4', '2382', 'Generic'), +('2', '4', '2479', 'Honorless Target'), +('2', '4', '2973', 'Raptor Strike'), +('2', '4', '3050', 'Detect'), +('2', '4', '3365', 'Opening'), +('2', '4', '6233', 'Closing'), +('2', '4', '6246', 'Closing'), +('2', '4', '6247', 'Opening'), +('2', '4', '6477', 'Opening'), +('2', '4', '6478', 'Opening'), +('2', '4', '6603', 'Attack'), +('2', '4', '7266', 'Duel'), +('2', '4', '7267', 'Grovel'), +('2', '4', '7355', 'Stuck'), +('2', '4', '8386', 'Attacking'), +('2', '4', '9077', 'Leather'), +('2', '4', '9078', 'Cloth'), +('2', '4', '9125', 'Generic'), +('2', '4', '13358', 'Defensive State(DND)'), +('2', '4', '20572', 'Blood Fury'), +('2', '4', '20573', 'Hardiness'), +('2', '4', '20574', 'Axe Specialization'), +('2', '4', '20576', 'Command'), +('2', '4', '21651', 'Opening'), +('2', '4', '21652', 'Closing'), +('2', '4', '22027', 'Remove Insignia'), +('2', '4', '22810', 'Opening - No Text'), +('2', '4', '24949', 'Defensive State 2(DND)'), +('2', '4', '34082', 'Advantaged State(DND)'), +('2', '8', '81', 'Dodge'), +('2', '8', '203', 'Unarmed'), +('2', '8', '204', 'Defense'), +('2', '8', '522', 'SPELLDEFENSE(DND)'), +('2', '8', '669', 'Language Orcish'), +('2', '8', '1180', 'Daggers'), +('2', '8', '1752', 'Sinister Strike'), +('2', '8', '2098', 'Eviscerate'), +('2', '8', '2382', 'Generic'), +('2', '8', '2479', 'Honorless Target'), +('2', '8', '2567', 'Thrown'), +('2', '8', '2764', 'Throw'), +('2', '8', '3050', 'Detect'), +('2', '8', '3365', 'Opening'), +('2', '8', '6233', 'Closing'), +('2', '8', '6246', 'Closing'), +('2', '8', '6247', 'Opening'), +('2', '8', '6477', 'Opening'), +('2', '8', '6478', 'Opening'), +('2', '8', '6603', 'Attack'), +('2', '8', '7266', 'Duel'), +('2', '8', '7267', 'Grovel'), +('2', '8', '7355', 'Stuck'), +('2', '8', '8386', 'Attacking'), +('2', '8', '9077', 'Leather'), +('2', '8', '9078', 'Cloth'), +('2', '8', '9125', 'Generic'), +('2', '8', '16092', 'Defensive State(DND)'), +('2', '8', '20572', 'Blood Fury'), +('2', '8', '20573', 'Hardiness'), +('2', '8', '20574', 'Axe Specialization'), +('2', '8', '21184', 'Rogue Passive(DND)'), +('2', '8', '21563', 'Command'), +('2', '8', '21651', 'Opening'), +('2', '8', '21652', 'Closing'), +('2', '8', '22027', 'Remove Insignia'), +('2', '8', '22810', 'Opening - No Text'), +('2', '64', '81', 'Dodge'), +('2', '64', '107', 'Block'), +('2', '64', '198', 'One-Handed Maces'), +('2', '64', '203', 'Unarmed'), +('2', '64', '204', 'Defense'), +('2', '64', '227', 'Staves'), +('2', '64', '331', 'Healing Wave'), +('2', '64', '403', 'Lightning Bolt'), +('2', '64', '522', 'SPELLDEFENSE(DND)'), +('2', '64', '669', 'Language Orcish'), +('2', '64', '2382', 'Generic'), +('2', '64', '2479', 'Honorless Target'), +('2', '64', '3050', 'Detect'), +('2', '64', '3365', 'Opening'), +('2', '64', '6233', 'Closing'), +('2', '64', '6246', 'Closing'), +('2', '64', '6247', 'Opening'), +('2', '64', '6477', 'Opening'), +('2', '64', '6478', 'Opening'), +('2', '64', '6603', 'Attack'), +('2', '64', '7266', 'Duel'), +('2', '64', '7267', 'Grovel'), +('2', '64', '7355', 'Stuck'), +('2', '64', '8386', 'Attacking'), +('2', '64', '9077', 'Leather'), +('2', '64', '9078', 'Cloth'), +('2', '64', '9116', 'Shield'), +('2', '64', '9125', 'Generic'), +('2', '64', '20573', 'Hardiness'), +('2', '64', '20574', 'Axe Specialization'), +('2', '64', '21563', 'Command'), +('2', '64', '21651', 'Opening'), +('2', '64', '21652', 'Closing'), +('2', '64', '22027', 'Remove Insignia'), +('2', '64', '22810', 'Opening - No Text'), +('2', '64', '27763', 'Totem'), +('2', '64', '33697', 'Blood Fury'), +('2', '256', '81', 'Dodge'), +('2', '256', '203', 'Unarmed'), +('2', '256', '204', 'Defense'), +('2', '256', '522', 'SPELLDEFENSE(DND)'), +('2', '256', '669', 'Language Orcish'), +('2', '256', '686', 'Shadow Bolt'), +('2', '256', '687', 'Demon Skin'), +('2', '256', '1180', 'Daggers'), +('2', '256', '2382', 'Generic'), +('2', '256', '2479', 'Honorless Target'), +('2', '256', '3050', 'Detect'), +('2', '256', '3365', 'Opening'), +('2', '256', '5009', 'Wands'), +('2', '256', '5019', 'Shoot'), +('2', '256', '6233', 'Closing'), +('2', '256', '6246', 'Closing'), +('2', '256', '6247', 'Opening'), +('2', '256', '6477', 'Opening'), +('2', '256', '6478', 'Opening'), +('2', '256', '6603', 'Attack'), +('2', '256', '7266', 'Duel'), +('2', '256', '7267', 'Grovel'), +('2', '256', '7355', 'Stuck'), +('2', '256', '8386', 'Attacking'), +('2', '256', '9078', 'Cloth'), +('2', '256', '9125', 'Generic'), +('2', '256', '20573', 'Hardiness'), +('2', '256', '20574', 'Axe Specialization'), +('2', '256', '20575', 'Command'), +('2', '256', '21651', 'Opening'), +('2', '256', '21652', 'Closing'), +('2', '256', '22027', 'Remove Insignia'), +('2', '256', '22810', 'Opening - No Text'), +('2', '256', '33702', 'Blood Fury'), +('4', '1', '78', 'Heroic Strike'), +('4', '1', '81', 'Dodge'), +('4', '1', '107', 'Block'), +('4', '1', '196', 'One-Handed Axes'), +('4', '1', '197', 'Two-Handed Axes'), +('4', '1', '198', 'One-Handed Maces'), +('4', '1', '203', 'Unarmed'), +('4', '1', '204', 'Defense'), +('4', '1', '522', 'SPELLDEFENSE(DND)'), +('4', '1', '668', 'Language Common'), +('4', '1', '672', 'Language Dwarven'), +('4', '1', '2382', 'Generic'), +('4', '1', '2457', 'Battle Stance'), +('4', '1', '2479', 'Honorless Target'), +('4', '1', '2481', 'Find Treasure'), +('4', '1', '3050', 'Detect'), +('4', '1', '3365', 'Opening'), +('4', '1', '5301', 'Defensive State(DND)'), +('4', '1', '6233', 'Closing'), +('4', '1', '6246', 'Closing'), +('4', '1', '6247', 'Opening'), +('4', '1', '6477', 'Opening'), +('4', '1', '6478', 'Opening'), +('4', '1', '6603', 'Attack'), +('4', '1', '7266', 'Duel'), +('4', '1', '7267', 'Grovel'), +('4', '1', '7355', 'Stuck'), +('4', '1', '7376', 'Defensive Stance Passive'), +('4', '1', '7381', 'Berserker Stance Passive'), +('4', '1', '8386', 'Attacking'), +('4', '1', '8737', 'Mail'), +('4', '1', '9077', 'Leather'), +('4', '1', '9078', 'Cloth'), +('4', '1', '9116', 'Shield'), +('4', '1', '9125', 'Generic'), +('4', '1', '20594', 'Stoneform'), +('4', '1', '20595', 'Gun Specialization'), +('4', '1', '20596', 'Frost Resistance'), +('4', '1', '21156', 'Battle Stance Passive'), +('4', '1', '21651', 'Opening'), +('4', '1', '21652', 'Closing'), +('4', '1', '22027', 'Remove Insignia'), +('4', '1', '22810', 'Opening - No Text'), +('4', '1', '32215', 'Victorious State'), +('4', '2', '81', 'Dodge'), +('4', '2', '107', 'Block'), +('4', '2', '198', 'One-Handed Maces'), +('4', '2', '199', 'Two-Handed Maces'), +('4', '2', '203', 'Unarmed'), +('4', '2', '204', 'Defense'), +('4', '2', '522', 'SPELLDEFENSE(DND)'), +('4', '2', '635', 'Holy Light'), +('4', '2', '668', 'Language Common'), +('4', '2', '672', 'Language Dwarven'), +('4', '2', '2382', 'Generic'), +('4', '2', '2479', 'Honorless Target'), +('4', '2', '2481', 'Find Treasure'), +('4', '2', '3050', 'Detect'), +('4', '2', '3365', 'Opening'), +('4', '2', '6233', 'Closing'), +('4', '2', '6246', 'Closing'), +('4', '2', '6247', 'Opening'), +('4', '2', '6477', 'Opening'), +('4', '2', '6478', 'Opening'), +('4', '2', '6603', 'Attack'), +('4', '2', '7266', 'Duel'), +('4', '2', '7267', 'Grovel'), +('4', '2', '7355', 'Stuck'), +('4', '2', '8386', 'Attacking'), +('4', '2', '8737', 'Mail'), +('4', '2', '9077', 'Leather'), +('4', '2', '9078', 'Cloth'), +('4', '2', '9116', 'Shield'), +('4', '2', '9125', 'Generic'), +('4', '2', '21084', 'Seal of Righteousness'), +('4', '2', '20594', 'Stoneform'), +('4', '2', '20595', 'Gun Specialization'), +('4', '2', '20596', 'Frost Resistance'), +('4', '2', '21651', 'Opening'), +('4', '2', '21652', 'Closing'), +('4', '2', '22027', 'Remove Insignia'), +('4', '2', '22810', 'Opening - No Text'), +('4', '2', '27762', 'Libram'), +('4', '4', '75', 'Auto Shot'), +('4', '4', '81', 'Dodge'), +('4', '4', '196', 'One-Handed Axes'), +('4', '4', '203', 'Unarmed'), +('4', '4', '204', 'Defense'), +('4', '4', '266', 'Guns'), +('4', '4', '522', 'SPELLDEFENSE(DND)'), +('4', '4', '668', 'Language Common'), +('4', '4', '672', 'Language Dwarven'), +('4', '4', '2382', 'Generic'), +('4', '4', '2479', 'Honorless Target'), +('4', '4', '2481', 'Find Treasure'), +('4', '4', '2973', 'Raptor Strike'), +('4', '4', '3050', 'Detect'), +('4', '4', '3365', 'Opening'), +('4', '4', '6233', 'Closing'), +('4', '4', '6246', 'Closing'), +('4', '4', '6247', 'Opening'), +('4', '4', '6477', 'Opening'), +('4', '4', '6478', 'Opening'), +('4', '4', '6603', 'Attack'), +('4', '4', '7266', 'Duel'), +('4', '4', '7267', 'Grovel'), +('4', '4', '7355', 'Stuck'), +('4', '4', '8386', 'Attacking'), +('4', '4', '9077', 'Leather'), +('4', '4', '9078', 'Cloth'), +('4', '4', '9125', 'Generic'), +('4', '4', '13358', 'Defensive State(DND)'), +('4', '4', '20594', 'Stoneform'), +('4', '4', '20595', 'Gun Specialization'), +('4', '4', '20596', 'Frost Resistance'), +('4', '4', '21651', 'Opening'), +('4', '4', '21652', 'Closing'), +('4', '4', '22027', 'Remove Insignia'), +('4', '4', '22810', 'Opening - No Text'), +('4', '4', '24949', 'Defensive State 2(DND)'), +('4', '4', '34082', 'Advantaged State(DND)'), +('4', '8', '81', 'Dodge'), +('4', '8', '203', 'Unarmed'), +('4', '8', '204', 'Defense'), +('4', '8', '522', 'SPELLDEFENSE(DND)'), +('4', '8', '668', 'Language Common'), +('4', '8', '672', 'Language Dwarven'), +('4', '8', '1180', 'Daggers'), +('4', '8', '1752', 'Sinister Strike'), +('4', '8', '2098', 'Eviscerate'), +('4', '8', '2382', 'Generic'), +('4', '8', '2479', 'Honorless Target'), +('4', '8', '2481', 'Find Treasure'), +('4', '8', '2567', 'Thrown'), +('4', '8', '2764', 'Throw'), +('4', '8', '3050', 'Detect'), +('4', '8', '3365', 'Opening'), +('4', '8', '6233', 'Closing'), +('4', '8', '6246', 'Closing'), +('4', '8', '6247', 'Opening'), +('4', '8', '6477', 'Opening'), +('4', '8', '6478', 'Opening'), +('4', '8', '6603', 'Attack'), +('4', '8', '7266', 'Duel'), +('4', '8', '7267', 'Grovel'), +('4', '8', '7355', 'Stuck'), +('4', '8', '8386', 'Attacking'), +('4', '8', '9077', 'Leather'), +('4', '8', '9078', 'Cloth'), +('4', '8', '9125', 'Generic'), +('4', '8', '16092', 'Defensive State(DND)'), +('4', '8', '20594', 'Stoneform'), +('4', '8', '20595', 'Gun Specialization'), +('4', '8', '20596', 'Frost Resistance'), +('4', '8', '21184', 'Rogue Passive(DND)'), +('4', '8', '21651', 'Opening'), +('4', '8', '21652', 'Closing'), +('4', '8', '22027', 'Remove Insignia'), +('4', '8', '22810', 'Opening - No Text'), +('4', '16', '81', 'Dodge'), +('4', '16', '198', 'One-Handed Maces'), +('4', '16', '203', 'Unarmed'), +('4', '16', '204', 'Defense'), +('4', '16', '522', 'SPELLDEFENSE(DND)'), +('4', '16', '585', 'Smite'), +('4', '16', '668', 'Language Common'), +('4', '16', '672', 'Language Dwarven'), +('4', '16', '2050', 'Lesser Heal'), +('4', '16', '2382', 'Generic'), +('4', '16', '2479', 'Honorless Target'), +('4', '16', '2481', 'Find Treasure'), +('4', '16', '3050', 'Detect'), +('4', '16', '3365', 'Opening'), +('4', '16', '5009', 'Wands'), +('4', '16', '5019', 'Shoot'), +('4', '16', '6233', 'Closing'), +('4', '16', '6246', 'Closing'), +('4', '16', '6247', 'Opening'), +('4', '16', '6477', 'Opening'), +('4', '16', '6478', 'Opening'), +('4', '16', '6603', 'Attack'), +('4', '16', '7266', 'Duel'), +('4', '16', '7267', 'Grovel'), +('4', '16', '7355', 'Stuck'), +('4', '16', '8386', 'Attacking'), +('4', '16', '9078', 'Cloth'), +('4', '16', '9125', 'Generic'), +('4', '16', '20594', 'Stoneform'), +('4', '16', '20595', 'Gun Specialization'), +('4', '16', '20596', 'Frost Resistance'), +('4', '16', '21651', 'Opening'), +('4', '16', '21652', 'Closing'), +('4', '16', '22027', 'Remove Insignia'), +('4', '16', '22810', 'Opening - No Text'), +('8', '1', '78', 'Heroic Strike'), +('8', '1', '81', 'Dodge'), +('8', '1', '107', 'Block'), +('8', '1', '198', 'One-Handed Maces'), +('8', '1', '201', 'One-Handed Swords'), +('8', '1', '203', 'Unarmed'), +('8', '1', '204', 'Defense'), +('8', '1', '522', 'SPELLDEFENSE(DND)'), +('8', '1', '668', 'Language Common'), +('8', '1', '671', 'Language Darnassian'), +('8', '1', '1180', 'Daggers'), +('8', '1', '2382', 'Generic'), +('8', '1', '2457', 'Battle Stance'), +('8', '1', '2479', 'Honorless Target'), +('8', '1', '3050', 'Detect'), +('8', '1', '3365', 'Opening'), +('8', '1', '5301', 'Defensive State(DND)'), +('8', '1', '6233', 'Closing'), +('8', '1', '6246', 'Closing'), +('8', '1', '6247', 'Opening'), +('8', '1', '6477', 'Opening'), +('8', '1', '6478', 'Opening'), +('8', '1', '6603', 'Attack'), +('8', '1', '7266', 'Duel'), +('8', '1', '7267', 'Grovel'), +('8', '1', '7355', 'Stuck'), +('8', '1', '7376', 'Defensive Stance Passive'), +('8', '1', '7381', 'Berserker Stance Passive'), +('8', '1', '8386', 'Attacking'), +('8', '1', '8737', 'Mail'), +('8', '1', '9077', 'Leather'), +('8', '1', '9078', 'Cloth'), +('8', '1', '9116', 'Shield'), +('8', '1', '9125', 'Generic'), +('8', '1', '20580', 'Shadowmeld'), +('8', '1', '20582', 'Quickness'), +('8', '1', '20583', 'Nature Resistance'), +('8', '1', '20585', 'Wisp Spirit'), +('8', '1', '21009', 'Shadowmeld Passive'), +('8', '1', '21156', 'Battle Stance Passive'), +('8', '1', '21651', 'Opening'), +('8', '1', '21652', 'Closing'), +('8', '1', '22027', 'Remove Insignia'), +('8', '1', '22810', 'Opening - No Text'), +('8', '1', '32215', 'Victorious State'), +('8', '4', '75', 'Auto Shot'), +('8', '4', '81', 'Dodge'), +('8', '4', '203', 'Unarmed'), +('8', '4', '204', 'Defense'), +('8', '4', '264', 'Bows'), +('8', '4', '522', 'SPELLDEFENSE(DND)'), +('8', '4', '668', 'Language Common'), +('8', '4', '671', 'Language Darnassian'), +('8', '4', '1180', 'Daggers'), +('8', '4', '2382', 'Generic'), +('8', '4', '2479', 'Honorless Target'), +('8', '4', '2973', 'Raptor Strike'), +('8', '4', '3050', 'Detect'), +('8', '4', '3365', 'Opening'), +('8', '4', '6233', 'Closing'), +('8', '4', '6246', 'Closing'), +('8', '4', '6247', 'Opening'), +('8', '4', '6477', 'Opening'), +('8', '4', '6478', 'Opening'), +('8', '4', '6603', 'Attack'), +('8', '4', '7266', 'Duel'), +('8', '4', '7267', 'Grovel'), +('8', '4', '7355', 'Stuck'), +('8', '4', '8386', 'Attacking'), +('8', '4', '9077', 'Leather'), +('8', '4', '9078', 'Cloth'), +('8', '4', '9125', 'Generic'), +('8', '4', '13358', 'Defensive State(DND)'), +('8', '4', '20580', 'Shadowmeld'), +('8', '4', '20582', 'Quickness'), +('8', '4', '20583', 'Nature Resistance'), +('8', '4', '20585', 'Wisp Spirit'), +('8', '4', '21009', 'Shadowmeld Passive'), +('8', '4', '21651', 'Opening'), +('8', '4', '21652', 'Closing'), +('8', '4', '22027', 'Remove Insignia'), +('8', '4', '22810', 'Opening - No Text'), +('8', '4', '24949', 'Defensive State 2(DND)'), +('8', '4', '34082', 'Advantaged State(DND)'), +('8', '8', '81', 'Dodge'), +('8', '8', '203', 'Unarmed'), +('8', '8', '204', 'Defense'), +('8', '8', '522', 'SPELLDEFENSE(DND)'), +('8', '8', '668', 'Language Common'), +('8', '8', '671', 'Language Darnassian'), +('8', '8', '1180', 'Daggers'), +('8', '8', '1752', 'Sinister Strike'), +('8', '8', '2098', 'Eviscerate'), +('8', '8', '2382', 'Generic'), +('8', '8', '2479', 'Honorless Target'), +('8', '8', '2567', 'Thrown'), +('8', '8', '2764', 'Throw'), +('8', '8', '3050', 'Detect'), +('8', '8', '3365', 'Opening'), +('8', '8', '6233', 'Closing'), +('8', '8', '6246', 'Closing'), +('8', '8', '6247', 'Opening'), +('8', '8', '6477', 'Opening'), +('8', '8', '6478', 'Opening'), +('8', '8', '6603', 'Attack'), +('8', '8', '7266', 'Duel'), +('8', '8', '7267', 'Grovel'), +('8', '8', '7355', 'Stuck'), +('8', '8', '8386', 'Attacking'), +('8', '8', '9077', 'Leather'), +('8', '8', '9078', 'Cloth'), +('8', '8', '9125', 'Generic'), +('8', '8', '16092', 'Defensive State(DND)'), +('8', '8', '20580', 'Shadowmeld'), +('8', '8', '20582', 'Quickness'), +('8', '8', '20583', 'Nature Resistance'), +('8', '8', '20585', 'Wisp Spirit'), +('8', '8', '21009', 'Shadowmeld Passive'), +('8', '8', '21184', 'Rogue Passive(DND)'), +('8', '8', '21651', 'Opening'), +('8', '8', '21652', 'Closing'), +('8', '8', '22027', 'Remove Insignia'), +('8', '8', '22810', 'Opening - No Text'), +('8', '16', '81', 'Dodge'), +('8', '16', '198', 'One-Handed Maces'), +('8', '16', '203', 'Unarmed'), +('8', '16', '204', 'Defense'), +('8', '16', '522', 'SPELLDEFENSE(DND)'), +('8', '16', '585', 'Smite'), +('8', '16', '668', 'Language Common'), +('8', '16', '671', 'Language Darnassian'), +('8', '16', '2050', 'Lesser Heal'), +('8', '16', '2382', 'Generic'), +('8', '16', '2479', 'Honorless Target'), +('8', '16', '3050', 'Detect'), +('8', '16', '3365', 'Opening'), +('8', '16', '5009', 'Wands'), +('8', '16', '5019', 'Shoot'), +('8', '16', '6233', 'Closing'), +('8', '16', '6246', 'Closing'), +('8', '16', '6247', 'Opening'), +('8', '16', '6477', 'Opening'), +('8', '16', '6478', 'Opening'), +('8', '16', '6603', 'Attack'), +('8', '16', '7266', 'Duel'), +('8', '16', '7267', 'Grovel'), +('8', '16', '7355', 'Stuck'), +('8', '16', '8386', 'Attacking'), +('8', '16', '9078', 'Cloth'), +('8', '16', '9125', 'Generic'), +('8', '16', '20580', 'Shadowmeld'), +('8', '16', '20582', 'Quickness'), +('8', '16', '20583', 'Nature Resistance'), +('8', '16', '20585', 'Wisp Spirit'), +('8', '16', '21009', 'Shadowmeld Passive'), +('8', '16', '21651', 'Opening'), +('8', '16', '21652', 'Closing'), +('8', '16', '22027', 'Remove Insignia'), +('8', '16', '22810', 'Opening - No Text'), +('8', '1024', '81', 'Dodge'), +('8', '1024', '203', 'Unarmed'), +('8', '1024', '204', 'Defense'), +('8', '1024', '227', 'Staves'), +('8', '1024', '522', 'SPELLDEFENSE(DND)'), +('8', '1024', '668', 'Language Common'), +('8', '1024', '671', 'Language Darnassian'), +('8', '1024', '1178', 'Bear Form(Passive)'), +('8', '1024', '1180', 'Daggers'), +('8', '1024', '2382', 'Generic'), +('8', '1024', '2479', 'Honorless Target'), +('8', '1024', '3025', 'Cat Form(Passive)'), +('8', '1024', '3050', 'Detect'), +('8', '1024', '3365', 'Opening'), +('8', '1024', '5176', 'Wrath'), +('8', '1024', '5185', 'Healing Touch'), +('8', '1024', '5419', 'Travel Form(Passive)'), +('8', '1024', '5420', 'Tree of Life'), +('8', '1024', '5421', 'Aquatic Form(Passive)'), +('8', '1024', '6233', 'Closing'), +('8', '1024', '6246', 'Closing'), +('8', '1024', '6247', 'Opening'), +('8', '1024', '6477', 'Opening'), +('8', '1024', '6478', 'Opening'), +('8', '1024', '6603', 'Attack'), +('8', '1024', '7266', 'Duel'), +('8', '1024', '7267', 'Grovel'), +('8', '1024', '7355', 'Stuck'), +('8', '1024', '8386', 'Attacking'), +('8', '1024', '9077', 'Leather'), +('8', '1024', '9078', 'Cloth'), +('8', '1024', '9125', 'Generic'), +('8', '1024', '9635', 'Dire Bear Form(Passive)'), +('8', '1024', '20580', 'Shadowmeld'), +('8', '1024', '20582', 'Quickness'), +('8', '1024', '20583', 'Nature Resistance'), +('8', '1024', '20585', 'Wisp Spirit'), +('8', '1024', '21009', 'Shadowmeld Passive'), +('8', '1024', '21178', 'Bear Form(Passive2)'), +('8', '1024', '21651', 'Opening'), +('8', '1024', '21652', 'Closing'), +('8', '1024', '22027', 'Remove Insignia'), +('8', '1024', '22810', 'Opening - No Text'), +('8', '1024', '24905', 'Moonkin Form(Passive)'), +('8', '1024', '27764', 'Fetish'), +('8', '1024', '33948', 'Flight Form(Passive)'), +('8', '1024', '34123', 'Tree of Life(Passive)'), +('8', '1024', '40121', 'Swift Flight Form(Passive)'), +('16', '1', '78', 'Heroic Strike'), +('16', '1', '81', 'Dodge'), +('16', '1', '107', 'Block'), +('16', '1', '201', 'One-Handed Swords'), +('16', '1', '202', 'Two-Handed Swords'), +('16', '1', '203', 'Unarmed'), +('16', '1', '204', 'Defense'), +('16', '1', '522', 'SPELLDEFENSE(DND)'), +('16', '1', '669', 'Language Orcish'), +('16', '1', '1180', 'Daggers'), +('16', '1', '2382', 'Generic'), +('16', '1', '2457', 'Battle Stance'), +('16', '1', '2479', 'Honorless Target'), +('16', '1', '3050', 'Detect'), +('16', '1', '3365', 'Opening'), +('16', '1', '5227', 'Underwater Breathing'), +('16', '1', '5301', 'Defensive State(DND)'), +('16', '1', '6233', 'Closing'), +('16', '1', '6246', 'Closing'), +('16', '1', '6247', 'Opening'), +('16', '1', '6477', 'Opening'), +('16', '1', '6478', 'Opening'), +('16', '1', '6603', 'Attack'), +('16', '1', '7266', 'Duel'), +('16', '1', '7267', 'Grovel'), +('16', '1', '7355', 'Stuck'), +('16', '1', '7376', 'Defensive Stance Passive'), +('16', '1', '7381', 'Berserker Stance Passive'), +('16', '1', '7744', 'Will of the Forsaken'), +('16', '1', '8386', 'Attacking'), +('16', '1', '8737', 'Mail'), +('16', '1', '9077', 'Leather'), +('16', '1', '9078', 'Cloth'), +('16', '1', '9116', 'Shield'), +('16', '1', '9125', 'Generic'), +('16', '1', '17737', 'Language Gutterspeak'), +('16', '1', '20577', 'Cannibalize'), +('16', '1', '20579', 'Shadow Resistance'), +('16', '1', '21156', 'Battle Stance Passive'), +('16', '1', '21651', 'Opening'), +('16', '1', '21652', 'Closing'), +('16', '1', '22027', 'Remove Insignia'), +('16', '1', '22810', 'Opening - No Text'), +('16', '1', '32215', 'Victorious State'), +('16', '8', '81', 'Dodge'), +('16', '8', '203', 'Unarmed'), +('16', '8', '204', 'Defense'), +('16', '8', '522', 'SPELLDEFENSE(DND)'), +('16', '8', '669', 'Language Orcish'), +('16', '8', '1180', 'Daggers'), +('16', '8', '1752', 'Sinister Strike'), +('16', '8', '2098', 'Eviscerate'), +('16', '8', '2382', 'Generic'), +('16', '8', '2479', 'Honorless Target'), +('16', '8', '2567', 'Thrown'), +('16', '8', '2764', 'Throw'), +('16', '8', '3050', 'Detect'), +('16', '8', '3365', 'Opening'), +('16', '8', '5227', 'Underwater Breathing'), +('16', '8', '6233', 'Closing'), +('16', '8', '6246', 'Closing'), +('16', '8', '6247', 'Opening'), +('16', '8', '6477', 'Opening'), +('16', '8', '6478', 'Opening'), +('16', '8', '6603', 'Attack'), +('16', '8', '7266', 'Duel'), +('16', '8', '7267', 'Grovel'), +('16', '8', '7355', 'Stuck'), +('16', '8', '7744', 'Will of the Forsaken'), +('16', '8', '8386', 'Attacking'), +('16', '8', '9077', 'Leather'), +('16', '8', '9078', 'Cloth'), +('16', '8', '9125', 'Generic'), +('16', '8', '16092', 'Defensive State(DND)'), +('16', '8', '17737', 'Language Gutterspeak'), +('16', '8', '20577', 'Cannibalize'), +('16', '8', '20579', 'Shadow Resistance'), +('16', '8', '21184', 'Rogue Passive(DND)'), +('16', '8', '21651', 'Opening'), +('16', '8', '21652', 'Closing'), +('16', '8', '22027', 'Remove Insignia'), +('16', '8', '22810', 'Opening - No Text'), +('16', '16', '81', 'Dodge'), +('16', '16', '198', 'One-Handed Maces'), +('16', '16', '203', 'Unarmed'), +('16', '16', '204', 'Defense'), +('16', '16', '522', 'SPELLDEFENSE(DND)'), +('16', '16', '585', 'Smite'), +('16', '16', '669', 'Language Orcish'), +('16', '16', '2050', 'Lesser Heal'), +('16', '16', '2382', 'Generic'), +('16', '16', '2479', 'Honorless Target'), +('16', '16', '3050', 'Detect'), +('16', '16', '3365', 'Opening'), +('16', '16', '5009', 'Wands'), +('16', '16', '5019', 'Shoot'), +('16', '16', '5227', 'Underwater Breathing'), +('16', '16', '6233', 'Closing'), +('16', '16', '6246', 'Closing'), +('16', '16', '6247', 'Opening'), +('16', '16', '6477', 'Opening'), +('16', '16', '6478', 'Opening'), +('16', '16', '6603', 'Attack'), +('16', '16', '7266', 'Duel'), +('16', '16', '7267', 'Grovel'), +('16', '16', '7355', 'Stuck'), +('16', '16', '7744', 'Will of the Forsaken'), +('16', '16', '8386', 'Attacking'), +('16', '16', '9078', 'Cloth'), +('16', '16', '9125', 'Generic'), +('16', '16', '17737', 'Language Gutterspeak'), +('16', '16', '20577', 'Cannibalize'), +('16', '16', '20579', 'Shadow Resistance'), +('16', '16', '21651', 'Opening'), +('16', '16', '21652', 'Closing'), +('16', '16', '22027', 'Remove Insignia'), +('16', '16', '22810', 'Opening - No Text'), +('16', '128', '81', 'Dodge'), +('16', '128', '133', 'Fireball'), +('16', '128', '168', 'Frost Armor'), +('16', '128', '203', 'Unarmed'), +('16', '128', '204', 'Defense'), +('16', '128', '227', 'Staves'), +('16', '128', '522', 'SPELLDEFENSE(DND)'), +('16', '128', '669', 'Language Orcish'), +('16', '128', '2382', 'Generic'), +('16', '128', '2479', 'Honorless Target'), +('16', '128', '3050', 'Detect'), +('16', '128', '3365', 'Opening'), +('16', '128', '5009', 'Wands'), +('16', '128', '5019', 'Shoot'), +('16', '128', '5227', 'Underwater Breathing'), +('16', '128', '6233', 'Closing'), +('16', '128', '6246', 'Closing'), +('16', '128', '6247', 'Opening'), +('16', '128', '6477', 'Opening'), +('16', '128', '6478', 'Opening'), +('16', '128', '6603', 'Attack'), +('16', '128', '7266', 'Duel'), +('16', '128', '7267', 'Grovel'), +('16', '128', '7355', 'Stuck'), +('16', '128', '7744', 'Will of the Forsaken'), +('16', '128', '8386', 'Attacking'), +('16', '128', '9078', 'Cloth'), +('16', '128', '9125', 'Generic'), +('16', '128', '17737', 'Language Gutterspeak'), +('16', '128', '20577', 'Cannibalize'), +('16', '128', '20579', 'Shadow Resistance'), +('16', '128', '21651', 'Opening'), +('16', '128', '21652', 'Closing'), +('16', '128', '22027', 'Remove Insignia'), +('16', '128', '22810', 'Opening - No Text'), +('16', '256', '81', 'Dodge'), +('16', '256', '203', 'Unarmed'), +('16', '256', '204', 'Defense'), +('16', '256', '522', 'SPELLDEFENSE(DND)'), +('16', '256', '669', 'Language Orcish'), +('16', '256', '686', 'Shadow Bolt'), +('16', '256', '687', 'Demon Skin'), +('16', '256', '1180', 'Daggers'), +('16', '256', '2382', 'Generic'), +('16', '256', '2479', 'Honorless Target'), +('16', '256', '3050', 'Detect'), +('16', '256', '3365', 'Opening'), +('16', '256', '5009', 'Wands'), +('16', '256', '5019', 'Shoot'), +('16', '256', '5227', 'Underwater Breathing'), +('16', '256', '6233', 'Closing'), +('16', '256', '6246', 'Closing'), +('16', '256', '6247', 'Opening'), +('16', '256', '6477', 'Opening'), +('16', '256', '6478', 'Opening'), +('16', '256', '6603', 'Attack'), +('16', '256', '7266', 'Duel'), +('16', '256', '7267', 'Grovel'), +('16', '256', '7355', 'Stuck'), +('16', '256', '7744', 'Will of the Forsaken'), +('16', '256', '8386', 'Attacking'), +('16', '256', '9078', 'Cloth'), +('16', '256', '9125', 'Generic'), +('16', '256', '17737', 'Language Gutterspeak'), +('16', '256', '20577', 'Cannibalize'), +('16', '256', '20579', 'Shadow Resistance'), +('16', '256', '21651', 'Opening'), +('16', '256', '21652', 'Closing'), +('16', '256', '22027', 'Remove Insignia'), +('16', '256', '22810', 'Opening - No Text'), +('32', '1', '78', 'Heroic Strike'), +('32', '1', '81', 'Dodge'), +('32', '1', '107', 'Block'), +('32', '1', '196', 'One-Handed Axes'), +('32', '1', '198', 'One-Handed Maces'), +('32', '1', '199', 'Two-Handed Maces'), +('32', '1', '203', 'Unarmed'), +('32', '1', '204', 'Defense'), +('32', '1', '522', 'SPELLDEFENSE(DND)'), +('32', '1', '669', 'Language Orcish'), +('32', '1', '670', 'Language Taurahe'), +('32', '1', '2382', 'Generic'), +('32', '1', '2457', 'Battle Stance'), +('32', '1', '2479', 'Honorless Target'), +('32', '1', '3050', 'Detect'), +('32', '1', '3365', 'Opening'), +('32', '1', '5301', 'Defensive State(DND)'), +('32', '1', '6233', 'Closing'), +('32', '1', '6246', 'Closing'), +('32', '1', '6247', 'Opening'), +('32', '1', '6477', 'Opening'), +('32', '1', '6478', 'Opening'), +('32', '1', '6603', 'Attack'), +('32', '1', '7266', 'Duel'), +('32', '1', '7267', 'Grovel'), +('32', '1', '7355', 'Stuck'), +('32', '1', '7376', 'Defensive Stance Passive'), +('32', '1', '7381', 'Berserker Stance Passive'), +('32', '1', '8386', 'Attacking'), +('32', '1', '8737', 'Mail'), +('32', '1', '9077', 'Leather'), +('32', '1', '9078', 'Cloth'), +('32', '1', '9116', 'Shield'), +('32', '1', '9125', 'Generic'), +('32', '1', '20549', 'War Stomp'), +('32', '1', '20550', 'Endurance'), +('32', '1', '20551', 'Nature Resistance'), +('32', '1', '20552', 'Cultivation'), +('32', '1', '21156', 'Battle Stance Passive'), +('32', '1', '21651', 'Opening'), +('32', '1', '21652', 'Closing'), +('32', '1', '22027', 'Remove Insignia'), +('32', '1', '22810', 'Opening - No Text'), +('32', '1', '32215', 'Victorious State'), +('32', '4', '75', 'Auto Shot'), +('32', '4', '81', 'Dodge'), +('32', '4', '196', 'One-Handed Axes'), +('32', '4', '203', 'Unarmed'), +('32', '4', '204', 'Defense'), +('32', '4', '266', 'Guns'), +('32', '4', '522', 'SPELLDEFENSE(DND)'), +('32', '4', '669', 'Language Orcish'), +('32', '4', '670', 'Language Taurahe'), +('32', '4', '2382', 'Generic'), +('32', '4', '2479', 'Honorless Target'), +('32', '4', '2973', 'Raptor Strike'), +('32', '4', '3050', 'Detect'), +('32', '4', '3365', 'Opening'), +('32', '4', '6233', 'Closing'), +('32', '4', '6246', 'Closing'), +('32', '4', '6247', 'Opening'), +('32', '4', '6477', 'Opening'), +('32', '4', '6478', 'Opening'), +('32', '4', '6603', 'Attack'), +('32', '4', '7266', 'Duel'), +('32', '4', '7267', 'Grovel'), +('32', '4', '7355', 'Stuck'), +('32', '4', '8386', 'Attacking'), +('32', '4', '9077', 'Leather'), +('32', '4', '9078', 'Cloth'), +('32', '4', '9125', 'Generic'), +('32', '4', '13358', 'Defensive State(DND)'), +('32', '4', '20549', 'War Stomp'), +('32', '4', '20550', 'Endurance'), +('32', '4', '20551', 'Nature Resistance'), +('32', '4', '20552', 'Cultivation'), +('32', '4', '21651', 'Opening'), +('32', '4', '21652', 'Closing'), +('32', '4', '22027', 'Remove Insignia'), +('32', '4', '22810', 'Opening - No Text'), +('32', '4', '24949', 'Defensive State 2(DND)'), +('32', '4', '34082', 'Advantaged State(DND)'), +('32', '64', '81', 'Dodge'), +('32', '64', '107', 'Block'), +('32', '64', '198', 'One-Handed Maces'), +('32', '64', '203', 'Unarmed'), +('32', '64', '204', 'Defense'), +('32', '64', '227', 'Staves'), +('32', '64', '331', 'Healing Wave'), +('32', '64', '403', 'Lightning Bolt'), +('32', '64', '522', 'SPELLDEFENSE(DND)'), +('32', '64', '669', 'Language Orcish'), +('32', '64', '670', 'Language Taurahe'), +('32', '64', '2382', 'Generic'), +('32', '64', '2479', 'Honorless Target'), +('32', '64', '3050', 'Detect'), +('32', '64', '3365', 'Opening'), +('32', '64', '6233', 'Closing'), +('32', '64', '6246', 'Closing'), +('32', '64', '6247', 'Opening'), +('32', '64', '6477', 'Opening'), +('32', '64', '6478', 'Opening'), +('32', '64', '6603', 'Attack'), +('32', '64', '7266', 'Duel'), +('32', '64', '7267', 'Grovel'), +('32', '64', '7355', 'Stuck'), +('32', '64', '8386', 'Attacking'), +('32', '64', '9077', 'Leather'), +('32', '64', '9078', 'Cloth'), +('32', '64', '9116', 'Shield'), +('32', '64', '9125', 'Generic'), +('32', '64', '20549', 'War Stomp'), +('32', '64', '20550', 'Endurance'), +('32', '64', '20551', 'Nature Resistance'), +('32', '64', '20552', 'Cultivation'), +('32', '64', '21651', 'Opening'), +('32', '64', '21652', 'Closing'), +('32', '64', '22027', 'Remove Insignia'), +('32', '64', '22810', 'Opening - No Text'), +('32', '64', '27763', 'Totem'), +('32', '1024', '81', 'Dodge'), +('32', '1024', '198', 'One-Handed Maces'), +('32', '1024', '203', 'Unarmed'), +('32', '1024', '204', 'Defense'), +('32', '1024', '227', 'Staves'), +('32', '1024', '522', 'SPELLDEFENSE(DND)'), +('32', '1024', '669', 'Language Orcish'), +('32', '1024', '670', 'Language Taurahe'), +('32', '1024', '1178', 'Bear Form(Passive)'), +('32', '1024', '2382', 'Generic'), +('32', '1024', '2479', 'Honorless Target'), +('32', '1024', '3025', 'Cat Form(Passive)'), +('32', '1024', '3050', 'Detect'), +('32', '1024', '3365', 'Opening'), +('32', '1024', '5176', 'Wrath'), +('32', '1024', '5185', 'Healing Touch'), +('32', '1024', '5419', 'Travel Form(Passive)'), +('32', '1024', '5420', 'Tree of Life'), +('32', '1024', '5421', 'Aquatic Form(Passive)'), +('32', '1024', '6233', 'Closing'), +('32', '1024', '6246', 'Closing'), +('32', '1024', '6247', 'Opening'), +('32', '1024', '6477', 'Opening'), +('32', '1024', '6478', 'Opening'), +('32', '1024', '6603', 'Attack'), +('32', '1024', '7266', 'Duel'), +('32', '1024', '7267', 'Grovel'), +('32', '1024', '7355', 'Stuck'), +('32', '1024', '8386', 'Attacking'), +('32', '1024', '9077', 'Leather'), +('32', '1024', '9078', 'Cloth'), +('32', '1024', '9125', 'Generic'), +('32', '1024', '9635', 'Dire Bear Form(Passive)'), +('32', '1024', '20549', 'War Stomp'), +('32', '1024', '20550', 'Endurance'), +('32', '1024', '20551', 'Nature Resistance'), +('32', '1024', '20552', 'Cultivation'), +('32', '1024', '21178', 'Bear Form(Passive2)'), +('32', '1024', '21651', 'Opening'), +('32', '1024', '21652', 'Closing'), +('32', '1024', '22027', 'Remove Insignia'), +('32', '1024', '22810', 'Opening - No Text'), +('32', '1024', '24905', 'Moonkin Form(Passive)'), +('32', '1024', '27764', 'Fetish'), +('32', '1024', '33948', 'Flight Form(Passive)'), +('32', '1024', '34123', 'Tree of Life(Passive)'), +('32', '1024', '40121', 'Swift Flight Form(Passive)'), +('64', '1', '78', 'Heroic Strike'), +('64', '1', '81', 'Dodge'), +('64', '1', '107', 'Block'), +('64', '1', '198', 'One-Handed Maces'), +('64', '1', '201', 'One-Handed Swords'), +('64', '1', '203', 'Unarmed'), +('64', '1', '204', 'Defense'), +('64', '1', '522', 'SPELLDEFENSE(DND)'), +('64', '1', '668', 'Language Common'), +('64', '1', '1180', 'Daggers'), +('64', '1', '2382', 'Generic'), +('64', '1', '2457', 'Battle Stance'), +('64', '1', '2479', 'Honorless Target'), +('64', '1', '3050', 'Detect'), +('64', '1', '3365', 'Opening'), +('64', '1', '5301', 'Defensive State(DND)'), +('64', '1', '6233', 'Closing'), +('64', '1', '6246', 'Closing'), +('64', '1', '6247', 'Opening'), +('64', '1', '6477', 'Opening'), +('64', '1', '6478', 'Opening'), +('64', '1', '6603', 'Attack'), +('64', '1', '7266', 'Duel'), +('64', '1', '7267', 'Grovel'), +('64', '1', '7340', 'Language Gnomish'), +('64', '1', '7355', 'Stuck'), +('64', '1', '7376', 'Defensive Stance Passive'), +('64', '1', '7381', 'Berserker Stance Passive'), +('64', '1', '8386', 'Attacking'), +('64', '1', '8737', 'Mail'), +('64', '1', '9077', 'Leather'), +('64', '1', '9078', 'Cloth'), +('64', '1', '9116', 'Shield'), +('64', '1', '9125', 'Generic'), +('64', '1', '20589', 'Escape Artist'), +('64', '1', '20591', 'Expansive Mind'), +('64', '1', '20592', 'Arcane Resistance'), +('64', '1', '20593', 'Engineering Specialization'), +('64', '1', '21156', 'Battle Stance Passive'), +('64', '1', '21651', 'Opening'), +('64', '1', '21652', 'Closing'), +('64', '1', '22027', 'Remove Insignia'), +('64', '1', '22810', 'Opening - No Text'), +('64', '1', '32215', 'Victorious State'), +('64', '8', '81', 'Dodge'), +('64', '8', '203', 'Unarmed'), +('64', '8', '204', 'Defense'), +('64', '8', '522', 'SPELLDEFENSE(DND)'), +('64', '8', '668', 'Language Common'), +('64', '8', '1180', 'Daggers'), +('64', '8', '1752', 'Sinister Strike'), +('64', '8', '2098', 'Eviscerate'), +('64', '8', '2382', 'Generic'), +('64', '8', '2479', 'Honorless Target'), +('64', '8', '2567', 'Thrown'), +('64', '8', '2764', 'Throw'), +('64', '8', '3050', 'Detect'), +('64', '8', '3365', 'Opening'), +('64', '8', '6233', 'Closing'), +('64', '8', '6246', 'Closing'), +('64', '8', '6247', 'Opening'), +('64', '8', '6477', 'Opening'), +('64', '8', '6478', 'Opening'), +('64', '8', '6603', 'Attack'), +('64', '8', '7266', 'Duel'), +('64', '8', '7267', 'Grovel'), +('64', '8', '7340', 'Language Gnomish'), +('64', '8', '7355', 'Stuck'), +('64', '8', '8386', 'Attacking'), +('64', '8', '9077', 'Leather'), +('64', '8', '9078', 'Cloth'), +('64', '8', '9125', 'Generic'), +('64', '8', '16092', 'Defensive State(DND)'), +('64', '8', '20589', 'Escape Artist'), +('64', '8', '20591', 'Expansive Mind'), +('64', '8', '20592', 'Arcane Resistance'), +('64', '8', '20593', 'Engineering Specialization'), +('64', '8', '21184', 'Rogue Passive(DND)'), +('64', '8', '21651', 'Opening'), +('64', '8', '21652', 'Closing'), +('64', '8', '22027', 'Remove Insignia'), +('64', '8', '22810', 'Opening - No Text'), +('64', '128', '81', 'Dodge'), +('64', '128', '133', 'Fireball'), +('64', '128', '168', 'Frost Armor'), +('64', '128', '203', 'Unarmed'), +('64', '128', '204', 'Defense'), +('64', '128', '227', 'Staves'), +('64', '128', '522', 'SPELLDEFENSE(DND)'), +('64', '128', '668', 'Language Common'), +('64', '128', '2382', 'Generic'), +('64', '128', '2479', 'Honorless Target'), +('64', '128', '3050', 'Detect'), +('64', '128', '3365', 'Opening'), +('64', '128', '5009', 'Wands'), +('64', '128', '5019', 'Shoot'), +('64', '128', '6233', 'Closing'), +('64', '128', '6246', 'Closing'), +('64', '128', '6247', 'Opening'), +('64', '128', '6477', 'Opening'), +('64', '128', '6478', 'Opening'), +('64', '128', '6603', 'Attack'), +('64', '128', '7266', 'Duel'), +('64', '128', '7267', 'Grovel'), +('64', '128', '7340', 'Language Gnomish'), +('64', '128', '7355', 'Stuck'), +('64', '128', '8386', 'Attacking'), +('64', '128', '9078', 'Cloth'), +('64', '128', '9125', 'Generic'), +('64', '128', '20589', 'Escape Artist'), +('64', '128', '20591', 'Expansive Mind'), +('64', '128', '20592', 'Arcane Resistance'), +('64', '128', '20593', 'Engineering Specialization'), +('64', '128', '21651', 'Opening'), +('64', '128', '21652', 'Closing'), +('64', '128', '22027', 'Remove Insignia'), +('64', '128', '22810', 'Opening - No Text'), +('64', '256', '81', 'Dodge'), +('64', '256', '203', 'Unarmed'), +('64', '256', '204', 'Defense'), +('64', '256', '522', 'SPELLDEFENSE(DND)'), +('64', '256', '668', 'Language Common'), +('64', '256', '686', 'Shadow Bolt'), +('64', '256', '687', 'Demon Skin'), +('64', '256', '1180', 'Daggers'), +('64', '256', '2382', 'Generic'), +('64', '256', '2479', 'Honorless Target'), +('64', '256', '3050', 'Detect'), +('64', '256', '3365', 'Opening'), +('64', '256', '5009', 'Wands'), +('64', '256', '5019', 'Shoot'), +('64', '256', '6233', 'Closing'), +('64', '256', '6246', 'Closing'), +('64', '256', '6247', 'Opening'), +('64', '256', '6477', 'Opening'), +('64', '256', '6478', 'Opening'), +('64', '256', '6603', 'Attack'), +('64', '256', '7266', 'Duel'), +('64', '256', '7267', 'Grovel'), +('64', '256', '7340', 'Language Gnomish'), +('64', '256', '7355', 'Stuck'), +('64', '256', '8386', 'Attacking'), +('64', '256', '9078', 'Cloth'), +('64', '256', '9125', 'Generic'), +('64', '256', '20589', 'Escape Artist'), +('64', '256', '20591', 'Expansive Mind'), +('64', '256', '20592', 'Arcane Resistance'), +('64', '256', '20593', 'Engineering Specialization'), +('64', '256', '21651', 'Opening'), +('64', '256', '21652', 'Closing'), +('64', '256', '22027', 'Remove Insignia'), +('64', '256', '22810', 'Opening - No Text'), +('128', '1', '78', 'Heroic Strike'), +('128', '1', '81', 'Dodge'), +('128', '1', '107', 'Block'), +('128', '1', '196', 'One-Handed Axes'), +('128', '1', '203', 'Unarmed'), +('128', '1', '204', 'Defense'), +('128', '1', '522', 'SPELLDEFENSE(DND)'), +('128', '1', '669', 'Language Orcish'), +('128', '1', '1180', 'Daggers'), +('128', '1', '2382', 'Generic'), +('128', '1', '2457', 'Battle Stance'), +('128', '1', '2479', 'Honorless Target'), +('128', '1', '2567', 'Thrown'), +('128', '1', '2764', 'Throw'), +('128', '1', '3050', 'Detect'), +('128', '1', '3365', 'Opening'), +('128', '1', '5301', 'Defensive State(DND)'), +('128', '1', '6233', 'Closing'), +('128', '1', '6246', 'Closing'), +('128', '1', '6247', 'Opening'), +('128', '1', '6477', 'Opening'), +('128', '1', '6478', 'Opening'), +('128', '1', '6603', 'Attack'), +('128', '1', '7266', 'Duel'), +('128', '1', '7267', 'Grovel'), +('128', '1', '7341', 'Language Troll'), +('128', '1', '7355', 'Stuck'), +('128', '1', '7376', 'Defensive Stance Passive'), +('128', '1', '7381', 'Berserker Stance Passive'), +('128', '1', '8386', 'Attacking'), +('128', '1', '8737', 'Mail'), +('128', '1', '9077', 'Leather'), +('128', '1', '9078', 'Cloth'), +('128', '1', '9116', 'Shield'), +('128', '1', '9125', 'Generic'), +('128', '1', '20555', 'Regeneration'), +('128', '1', '20557', 'Beast Slaying'), +('128', '1', '20558', 'Throwing Specialization'), +('128', '1', '21156', 'Battle Stance Passive'), +('128', '1', '21651', 'Opening'), +('128', '1', '21652', 'Closing'), +('128', '1', '22027', 'Remove Insignia'), +('128', '1', '22810', 'Opening - No Text'), +('128', '1', '26290', 'Bow Specialization'), +('128', '1', '26296', 'Berserking'), +('128', '1', '32215', 'Victorious State'), +('128', '4', '75', 'Auto Shot'), +('128', '4', '81', 'Dodge'), +('128', '4', '196', 'One-Handed Axes'), +('128', '4', '203', 'Unarmed'), +('128', '4', '204', 'Defense'), +('128', '4', '264', 'Bows'), +('128', '4', '522', 'SPELLDEFENSE(DND)'), +('128', '4', '669', 'Language Orcish'), +('128', '4', '2382', 'Generic'), +('128', '4', '2479', 'Honorless Target'), +('128', '4', '2973', 'Raptor Strike'), +('128', '4', '3050', 'Detect'), +('128', '4', '3365', 'Opening'), +('128', '4', '6233', 'Closing'), +('128', '4', '6246', 'Closing'), +('128', '4', '6247', 'Opening'), +('128', '4', '6477', 'Opening'), +('128', '4', '6478', 'Opening'), +('128', '4', '6603', 'Attack'), +('128', '4', '7266', 'Duel'), +('128', '4', '7267', 'Grovel'), +('128', '4', '7341', 'Language Troll'), +('128', '4', '7355', 'Stuck'), +('128', '4', '8386', 'Attacking'), +('128', '4', '9077', 'Leather'), +('128', '4', '9078', 'Cloth'), +('128', '4', '9125', 'Generic'), +('128', '4', '13358', 'Defensive State(DND)'), +('128', '4', '20554', 'Berserking'), +('128', '4', '20555', 'Regeneration'), +('128', '4', '20557', 'Beast Slaying'), +('128', '4', '20558', 'Throwing Specialization'), +('128', '4', '21651', 'Opening'), +('128', '4', '21652', 'Closing'), +('128', '4', '22027', 'Remove Insignia'), +('128', '4', '22810', 'Opening - No Text'), +('128', '4', '24949', 'Defensive State 2(DND)'), +('128', '4', '26290', 'Bow Specialization'), +('128', '4', '34082', 'Advantaged State(DND)'), +('128', '8', '81', 'Dodge'), +('128', '8', '203', 'Unarmed'), +('128', '8', '204', 'Defense'), +('128', '8', '522', 'SPELLDEFENSE(DND)'), +('128', '8', '669', 'Language Orcish'), +('128', '8', '1180', 'Daggers'), +('128', '8', '1752', 'Sinister Strike'), +('128', '8', '2098', 'Eviscerate'), +('128', '8', '2382', 'Generic'), +('128', '8', '2479', 'Honorless Target'), +('128', '8', '2567', 'Thrown'), +('128', '8', '2764', 'Throw'), +('128', '8', '3050', 'Detect'), +('128', '8', '3365', 'Opening'), +('128', '8', '6233', 'Closing'), +('128', '8', '6246', 'Closing'), +('128', '8', '6247', 'Opening'), +('128', '8', '6477', 'Opening'), +('128', '8', '6478', 'Opening'), +('128', '8', '6603', 'Attack'), +('128', '8', '7266', 'Duel'), +('128', '8', '7267', 'Grovel'), +('128', '8', '7341', 'Language Troll'), +('128', '8', '7355', 'Stuck'), +('128', '8', '8386', 'Attacking'), +('128', '8', '9077', 'Leather'), +('128', '8', '9078', 'Cloth'), +('128', '8', '9125', 'Generic'), +('128', '8', '16092', 'Defensive State(DND)'), +('128', '8', '20555', 'Regeneration'), +('128', '8', '20557', 'Beast Slaying'), +('128', '8', '20558', 'Throwing Specialization'), +('128', '8', '21184', 'Rogue Passive(DND)'), +('128', '8', '21651', 'Opening'), +('128', '8', '21652', 'Closing'), +('128', '8', '22027', 'Remove Insignia'), +('128', '8', '22810', 'Opening - No Text'), +('128', '8', '26290', 'Bow Specialization'), +('128', '8', '26297', 'Berserking'), +('128', '16', '81', 'Dodge'), +('128', '16', '198', 'One-Handed Maces'), +('128', '16', '203', 'Unarmed'), +('128', '16', '204', 'Defense'), +('128', '16', '522', 'SPELLDEFENSE(DND)'), +('128', '16', '585', 'Smite'), +('128', '16', '669', 'Language Orcish'), +('128', '16', '2050', 'Lesser Heal'), +('128', '16', '2382', 'Generic'), +('128', '16', '2479', 'Honorless Target'), +('128', '16', '3050', 'Detect'), +('128', '16', '3365', 'Opening'), +('128', '16', '5009', 'Wands'), +('128', '16', '5019', 'Shoot'), +('128', '16', '6233', 'Closing'), +('128', '16', '6246', 'Closing'), +('128', '16', '6247', 'Opening'), +('128', '16', '6477', 'Opening'), +('128', '16', '6478', 'Opening'), +('128', '16', '6603', 'Attack'), +('128', '16', '7266', 'Duel'), +('128', '16', '7267', 'Grovel'), +('128', '16', '7341', 'Language Troll'), +('128', '16', '7355', 'Stuck'), +('128', '16', '8386', 'Attacking'), +('128', '16', '9078', 'Cloth'), +('128', '16', '9125', 'Generic'), +('128', '16', '20554', 'Berserking'), +('128', '16', '20555', 'Regeneration'), +('128', '16', '20557', 'Beast Slaying'), +('128', '16', '20558', 'Throwing Specialization'), +('128', '16', '21651', 'Opening'), +('128', '16', '21652', 'Closing'), +('128', '16', '22027', 'Remove Insignia'), +('128', '16', '22810', 'Opening - No Text'), +('128', '16', '26290', 'Bow Specialization'), +('128', '64', '81', 'Dodge'), +('128', '64', '107', 'Block'), +('128', '64', '198', 'One-Handed Maces'), +('128', '64', '203', 'Unarmed'), +('128', '64', '204', 'Defense'), +('128', '64', '227', 'Staves'), +('128', '64', '331', 'Healing Wave'), +('128', '64', '403', 'Lightning Bolt'), +('128', '64', '522', 'SPELLDEFENSE(DND)'), +('128', '64', '669', 'Language Orcish'), +('128', '64', '2382', 'Generic'), +('128', '64', '2479', 'Honorless Target'), +('128', '64', '3050', 'Detect'), +('128', '64', '3365', 'Opening'), +('128', '64', '6233', 'Closing'), +('128', '64', '6246', 'Closing'), +('128', '64', '6247', 'Opening'), +('128', '64', '6477', 'Opening'), +('128', '64', '6478', 'Opening'), +('128', '64', '6603', 'Attack'), +('128', '64', '7266', 'Duel'), +('128', '64', '7267', 'Grovel'), +('128', '64', '7341', 'Language Troll'), +('128', '64', '7355', 'Stuck'), +('128', '64', '8386', 'Attacking'), +('128', '64', '9077', 'Leather'), +('128', '64', '9078', 'Cloth'), +('128', '64', '9116', 'Shield'), +('128', '64', '9125', 'Generic'), +('128', '64', '20554', 'Berserking'), +('128', '64', '20555', 'Regeneration'), +('128', '64', '20557', 'Beast Slaying'), +('128', '64', '20558', 'Throwing Specialization'), +('128', '64', '21651', 'Opening'), +('128', '64', '21652', 'Closing'), +('128', '64', '22027', 'Remove Insignia'), +('128', '64', '22810', 'Opening - No Text'), +('128', '64', '26290', 'Bow Specialization'), +('128', '64', '27763', 'Totem'), +('128', '128', '81', 'Dodge'), +('128', '128', '133', 'Fireball'), +('128', '128', '168', 'Frost Armor'), +('128', '128', '203', 'Unarmed'), +('128', '128', '204', 'Defense'), +('128', '128', '227', 'Staves'), +('128', '128', '522', 'SPELLDEFENSE(DND)'), +('128', '128', '669', 'Language Orcish'), +('128', '128', '2382', 'Generic'), +('128', '128', '2479', 'Honorless Target'), +('128', '128', '3050', 'Detect'), +('128', '128', '3365', 'Opening'), +('128', '128', '5009', 'Wands'), +('128', '128', '5019', 'Shoot'), +('128', '128', '6233', 'Closing'), +('128', '128', '6246', 'Closing'), +('128', '128', '6247', 'Opening'), +('128', '128', '6477', 'Opening'), +('128', '128', '6478', 'Opening'), +('128', '128', '6603', 'Attack'), +('128', '128', '7266', 'Duel'), +('128', '128', '7267', 'Grovel'), +('128', '128', '7341', 'Language Troll'), +('128', '128', '7355', 'Stuck'), +('128', '128', '8386', 'Attacking'), +('128', '128', '9078', 'Cloth'), +('128', '128', '9125', 'Generic'), +('128', '128', '20554', 'Berserking'), +('128', '128', '20555', 'Regeneration'), +('128', '128', '20557', 'Beast Slaying'), +('128', '128', '20558', 'Throwing Specialization'), +('128', '128', '21651', 'Opening'), +('128', '128', '21652', 'Closing'), +('128', '128', '22027', 'Remove Insignia'), +('128', '128', '22810', 'Opening - No Text'), +('128', '128', '26290', 'Bow Specialization'), +('512', '2', '81', 'Dodge'), +('512', '2', '107', 'Block'), +('512', '2', '201', 'One-Handed Swords'), +('512', '2', '202', 'Two-Handed Swords'), +('512', '2', '203', 'Unarmed'), +('512', '2', '204', 'Defense'), +('512', '2', '522', 'SPELLDEFENSE(DND)'), +('512', '2', '635', 'Holy Light'), +('512', '2', '669', 'Language Orcish'), +('512', '2', '813', 'Language Thalassian'), +('512', '2', '822', 'Magic Resistance'), +('512', '2', '2382', 'Generic'), +('512', '2', '2479', 'Honorless Target'), +('512', '2', '3050', 'Detect'), +('512', '2', '3365', 'Opening'), +('512', '2', '6233', 'Closing'), +('512', '2', '6246', 'Closing'), +('512', '2', '6247', 'Opening'), +('512', '2', '6477', 'Opening'), +('512', '2', '6478', 'Opening'), +('512', '2', '6603', 'Attack'), +('512', '2', '7266', 'Duel'), +('512', '2', '7267', 'Grovel'), +('512', '2', '7355', 'Stuck'), +('512', '2', '8386', 'Attacking'), +('512', '2', '8737', 'Mail'), +('512', '2', '9077', 'Leather'), +('512', '2', '9078', 'Cloth'), +('512', '2', '9116', 'Shield'), +('512', '2', '9125', 'Generic'), +('512', '2', '21084', 'Seal of Righteousness'), +('512', '2', '21651', 'Opening'), +('512', '2', '21652', 'Closing'), +('512', '2', '22027', 'Remove Insignia'), +('512', '2', '22810', 'Opening - No Text'), +('512', '2', '27762', 'Libram'), +('512', '2', '28730', 'Arcane Torrent'), +('512', '2', '28877', 'Arcane Affinity'), +('512', '4', '75', 'Auto Shot'), +('512', '4', '81', 'Dodge'), +('512', '4', '203', 'Unarmed'), +('512', '4', '204', 'Defense'), +('512', '4', '264', 'Bows'), +('512', '4', '522', 'SPELLDEFENSE(DND)'), +('512', '4', '669', 'Language Orcish'), +('512', '4', '813', 'Language Thalassian'), +('512', '4', '822', 'Magic Resistance'), +('512', '4', '1180', 'Daggers'), +('512', '4', '2382', 'Generic'), +('512', '4', '2479', 'Honorless Target'), +('512', '4', '2973', 'Raptor Strike'), +('512', '4', '3050', 'Detect'), +('512', '4', '3365', 'Opening'), +('512', '4', '6233', 'Closing'), +('512', '4', '6246', 'Closing'), +('512', '4', '6247', 'Opening'), +('512', '4', '6477', 'Opening'), +('512', '4', '6478', 'Opening'), +('512', '4', '6603', 'Attack'), +('512', '4', '7266', 'Duel'), +('512', '4', '7267', 'Grovel'), +('512', '4', '7355', 'Stuck'), +('512', '4', '8386', 'Attacking'), +('512', '4', '9077', 'Leather'), +('512', '4', '9078', 'Cloth'), +('512', '4', '9125', 'Generic'), +('512', '4', '13358', 'Defensive State(DND)'), +('512', '4', '21651', 'Opening'), +('512', '4', '21652', 'Closing'), +('512', '4', '22027', 'Remove Insignia'), +('512', '4', '22810', 'Opening - No Text'), +('512', '4', '24949', 'Defensive State 2(DND)'), +('512', '4', '28730', 'Arcane Torrent'), +('512', '4', '28877', 'Arcane Affinity'), +('512', '4', '34082', 'Advantaged State(DND)'), +('512', '8', '81', 'Dodge'), +('512', '8', '203', 'Unarmed'), +('512', '8', '204', 'Defense'), +('512', '8', '522', 'SPELLDEFENSE(DND)'), +('512', '8', '669', 'Language Orcish'), +('512', '8', '813', 'Language Thalassian'), +('512', '8', '822', 'Magic Resistance'), +('512', '8', '1180', 'Daggers'), +('512', '8', '1752', 'Sinister Strike'), +('512', '8', '2098', 'Eviscerate'), +('512', '8', '2382', 'Generic'), +('512', '8', '2479', 'Honorless Target'), +('512', '8', '2567', 'Thrown'), +('512', '8', '2764', 'Throw'), +('512', '8', '3050', 'Detect'), +('512', '8', '3365', 'Opening'), +('512', '8', '6233', 'Closing'), +('512', '8', '6246', 'Closing'), +('512', '8', '6247', 'Opening'), +('512', '8', '6477', 'Opening'), +('512', '8', '6478', 'Opening'), +('512', '8', '6603', 'Attack'), +('512', '8', '7266', 'Duel'), +('512', '8', '7267', 'Grovel'), +('512', '8', '7355', 'Stuck'), +('512', '8', '8386', 'Attacking'), +('512', '8', '9077', 'Leather'), +('512', '8', '9078', 'Cloth'), +('512', '8', '9125', 'Generic'), +('512', '8', '16092', 'Defensive State(DND)'), +('512', '8', '21184', 'Rogue Passive(DND)'), +('512', '8', '21651', 'Opening'), +('512', '8', '21652', 'Closing'), +('512', '8', '22027', 'Remove Insignia'), +('512', '8', '22810', 'Opening - No Text'), +('512', '8', '25046', 'Arcane Torrent'), +('512', '8', '28877', 'Arcane Affinity'), +('512', '16', '81', 'Dodge'), +('512', '16', '198', 'One-Handed Maces'), +('512', '16', '203', 'Unarmed'), +('512', '16', '204', 'Defense'), +('512', '16', '522', 'SPELLDEFENSE(DND)'), +('512', '16', '585', 'Smite'), +('512', '16', '669', 'Language Orcish'), +('512', '16', '813', 'Language Thalassian'), +('512', '16', '822', 'Magic Resistance'), +('512', '16', '2050', 'Lesser Heal'), +('512', '16', '2382', 'Generic'), +('512', '16', '2479', 'Honorless Target'), +('512', '16', '3050', 'Detect'), +('512', '16', '3365', 'Opening'), +('512', '16', '5009', 'Wands'), +('512', '16', '5019', 'Shoot'), +('512', '16', '6233', 'Closing'), +('512', '16', '6246', 'Closing'), +('512', '16', '6247', 'Opening'), +('512', '16', '6477', 'Opening'), +('512', '16', '6478', 'Opening'), +('512', '16', '6603', 'Attack'), +('512', '16', '7266', 'Duel'), +('512', '16', '7267', 'Grovel'), +('512', '16', '7355', 'Stuck'), +('512', '16', '8386', 'Attacking'), +('512', '16', '9078', 'Cloth'), +('512', '16', '9125', 'Generic'), +('512', '16', '21651', 'Opening'), +('512', '16', '21652', 'Closing'), +('512', '16', '22027', 'Remove Insignia'), +('512', '16', '22810', 'Opening - No Text'), +('512', '16', '28730', 'Arcane Torrent'), +('512', '16', '28877', 'Arcane Affinity'), +('512', '128', '81', 'Dodge'), +('512', '128', '133', 'Fireball'), +('512', '128', '168', 'Frost Armor'), +('512', '128', '203', 'Unarmed'), +('512', '128', '204', 'Defense'), +('512', '128', '227', 'Staves'), +('512', '128', '522', 'SPELLDEFENSE(DND)'), +('512', '128', '669', 'Language Orcish'), +('512', '128', '813', 'Language Thalassian'), +('512', '128', '822', 'Magic Resistance'), +('512', '128', '2382', 'Generic'), +('512', '128', '2479', 'Honorless Target'), +('512', '128', '3050', 'Detect'), +('512', '128', '3365', 'Opening'), +('512', '128', '5009', 'Wands'), +('512', '128', '5019', 'Shoot'), +('512', '128', '6233', 'Closing'), +('512', '128', '6246', 'Closing'), +('512', '128', '6247', 'Opening'), +('512', '128', '6477', 'Opening'), +('512', '128', '6478', 'Opening'), +('512', '128', '6603', 'Attack'), +('512', '128', '7266', 'Duel'), +('512', '128', '7267', 'Grovel'), +('512', '128', '7355', 'Stuck'), +('512', '128', '8386', 'Attacking'), +('512', '128', '9078', 'Cloth'), +('512', '128', '9125', 'Generic'), +('512', '128', '21651', 'Opening'), +('512', '128', '21652', 'Closing'), +('512', '128', '22027', 'Remove Insignia'), +('512', '128', '22810', 'Opening - No Text'), +('512', '128', '28730', 'Arcane Torrent'), +('512', '128', '28877', 'Arcane Affinity'), +('512', '256', '81', 'Dodge'), +('512', '256', '203', 'Unarmed'), +('512', '256', '204', 'Defense'), +('512', '256', '522', 'SPELLDEFENSE(DND)'), +('512', '256', '669', 'Language Orcish'), +('512', '256', '686', 'Shadow Bolt'), +('512', '256', '687', 'Demon Skin'), +('512', '256', '813', 'Language Thalassian'), +('512', '256', '822', 'Magic Resistance'), +('512', '256', '1180', 'Daggers'), +('512', '256', '2382', 'Generic'), +('512', '256', '2479', 'Honorless Target'), +('512', '256', '3050', 'Detect'), +('512', '256', '3365', 'Opening'), +('512', '256', '5009', 'Wands'), +('512', '256', '5019', 'Shoot'), +('512', '256', '6233', 'Closing'), +('512', '256', '6246', 'Closing'), +('512', '256', '6247', 'Opening'), +('512', '256', '6477', 'Opening'), +('512', '256', '6478', 'Opening'), +('512', '256', '6603', 'Attack'), +('512', '256', '7266', 'Duel'), +('512', '256', '7267', 'Grovel'), +('512', '256', '7355', 'Stuck'), +('512', '256', '8386', 'Attacking'), +('512', '256', '9078', 'Cloth'), +('512', '256', '9125', 'Generic'), +('512', '256', '21651', 'Opening'), +('512', '256', '21652', 'Closing'), +('512', '256', '22027', 'Remove Insignia'), +('512', '256', '22810', 'Opening - No Text'), +('512', '256', '28730', 'Arcane Torrent'), +('512', '256', '28877', 'Arcane Affinity'), +('1024', '1', '78', 'Heroic Strike'), +('1024', '1', '81', 'Dodge'), +('1024', '1', '107', 'Block'), +('1024', '1', '198', 'One-Handed Maces'), +('1024', '1', '201', 'One-Handed Swords'), +('1024', '1', '202', 'Two-Handed Swords'), +('1024', '1', '203', 'Unarmed'), +('1024', '1', '204', 'Defense'), +('1024', '1', '522', 'SPELLDEFENSE(DND)'), +('1024', '1', '668', 'Language Common'), +('1024', '1', '2382', 'Generic'), +('1024', '1', '2457', 'Battle Stance'), +('1024', '1', '2479', 'Honorless Target'), +('1024', '1', '3050', 'Detect'), +('1024', '1', '3365', 'Opening'), +('1024', '1', '5301', 'Defensive State(DND)'), +('1024', '1', '6233', 'Closing'), +('1024', '1', '6246', 'Closing'), +('1024', '1', '6247', 'Opening'), +('1024', '1', '6477', 'Opening'), +('1024', '1', '6478', 'Opening'), +('1024', '1', '6562', 'Heroic Presence'), +('1024', '1', '6603', 'Attack'), +('1024', '1', '7266', 'Duel'), +('1024', '1', '7267', 'Grovel'), +('1024', '1', '7355', 'Stuck'), +('1024', '1', '7376', 'Defensive Stance Passive'), +('1024', '1', '7381', 'Berserker Stance Passive'), +('1024', '1', '8386', 'Attacking'), +('1024', '1', '8737', 'Mail'), +('1024', '1', '9077', 'Leather'), +('1024', '1', '9078', 'Cloth'), +('1024', '1', '9116', 'Shield'), +('1024', '1', '9125', 'Generic'), +('1024', '1', '20579', 'Shadow Resistance'), +('1024', '1', '21156', 'Battle Stance Passive'), +('1024', '1', '21651', 'Opening'), +('1024', '1', '21652', 'Closing'), +('1024', '1', '22027', 'Remove Insignia'), +('1024', '1', '22810', 'Opening - No Text'), +('1024', '1', '28875', 'Gemcutting'), +('1024', '1', '28880', 'Gift of the Naaru'), +('1024', '1', '29932', 'Language Draenei'), +('1024', '1', '32215', 'Victorious State'), +('1024', '2', '81', 'Dodge'), +('1024', '2', '107', 'Block'), +('1024', '2', '198', 'One-Handed Maces'), +('1024', '2', '199', 'Two-Handed Maces'), +('1024', '2', '203', 'Unarmed'), +('1024', '2', '204', 'Defense'), +('1024', '2', '522', 'SPELLDEFENSE(DND)'), +('1024', '2', '635', 'Holy Light'), +('1024', '2', '668', 'Language Common'), +('1024', '2', '2382', 'Generic'), +('1024', '2', '2479', 'Honorless Target'), +('1024', '2', '3050', 'Detect'), +('1024', '2', '3365', 'Opening'), +('1024', '2', '6233', 'Closing'), +('1024', '2', '6246', 'Closing'), +('1024', '2', '6247', 'Opening'), +('1024', '2', '6477', 'Opening'), +('1024', '2', '6478', 'Opening'), +('1024', '2', '6562', 'Heroic Presence'), +('1024', '2', '6603', 'Attack'), +('1024', '2', '7266', 'Duel'), +('1024', '2', '7267', 'Grovel'), +('1024', '2', '7355', 'Stuck'), +('1024', '2', '8386', 'Attacking'), +('1024', '2', '8737', 'Mail'), +('1024', '2', '9077', 'Leather'), +('1024', '2', '9078', 'Cloth'), +('1024', '2', '9116', 'Shield'), +('1024', '2', '9125', 'Generic'), +('1024', '2', '21084', 'Seal of Righteousness'), +('1024', '2', '20579', 'Shadow Resistance'), +('1024', '2', '21651', 'Opening'), +('1024', '2', '21652', 'Closing'), +('1024', '2', '22027', 'Remove Insignia'), +('1024', '2', '22810', 'Opening - No Text'), +('1024', '2', '27762', 'Libram'), +('1024', '2', '28875', 'Gemcutting'), +('1024', '2', '28880', 'Gift of the Naaru'), +('1024', '2', '29932', 'Language Draenei'), +('1024', '4', '75', 'Auto Shot'), +('1024', '4', '81', 'Dodge'), +('1024', '4', '201', 'One-Handed Swords'), +('1024', '4', '203', 'Unarmed'), +('1024', '4', '204', 'Defense'), +('1024', '4', '522', 'SPELLDEFENSE(DND)'), +('1024', '4', '668', 'Language Common'), +('1024', '4', '2382', 'Generic'), +('1024', '4', '2479', 'Honorless Target'), +('1024', '4', '2973', 'Raptor Strike'), +('1024', '4', '3050', 'Detect'), +('1024', '4', '3365', 'Opening'), +('1024', '4', '5011', 'Crossbows'), +('1024', '4', '6233', 'Closing'), +('1024', '4', '6246', 'Closing'), +('1024', '4', '6247', 'Opening'), +('1024', '4', '6477', 'Opening'), +('1024', '4', '6478', 'Opening'), +('1024', '4', '6562', 'Heroic Presence'), +('1024', '4', '6603', 'Attack'), +('1024', '4', '7266', 'Duel'), +('1024', '4', '7267', 'Grovel'), +('1024', '4', '7355', 'Stuck'), +('1024', '4', '8386', 'Attacking'), +('1024', '4', '9077', 'Leather'), +('1024', '4', '9078', 'Cloth'), +('1024', '4', '9125', 'Generic'), +('1024', '4', '13358', 'Defensive State(DND)'), +('1024', '4', '20579', 'Shadow Resistance'), +('1024', '4', '21651', 'Opening'), +('1024', '4', '21652', 'Closing'), +('1024', '4', '22027', 'Remove Insignia'), +('1024', '4', '22810', 'Opening - No Text'), +('1024', '4', '24949', 'Defensive State 2(DND)'), +('1024', '4', '28875', 'Gemcutting'), +('1024', '4', '28880', 'Gift of the Naaru'), +('1024', '4', '29932', 'Language Draenei'), +('1024', '4', '34082', 'Advantaged State(DND)'), +('1024', '16', '81', 'Dodge'), +('1024', '16', '198', 'One-Handed Maces'), +('1024', '16', '203', 'Unarmed'), +('1024', '16', '204', 'Defense'), +('1024', '16', '522', 'SPELLDEFENSE(DND)'), +('1024', '16', '585', 'Smite'), +('1024', '16', '668', 'Language Common'), +('1024', '16', '2050', 'Lesser Heal'), +('1024', '16', '2382', 'Generic'), +('1024', '16', '2479', 'Honorless Target'), +('1024', '16', '3050', 'Detect'), +('1024', '16', '3365', 'Opening'), +('1024', '16', '5009', 'Wands'), +('1024', '16', '5019', 'Shoot'), +('1024', '16', '6233', 'Closing'), +('1024', '16', '6246', 'Closing'), +('1024', '16', '6247', 'Opening'), +('1024', '16', '6477', 'Opening'), +('1024', '16', '6478', 'Opening'), +('1024', '16', '6603', 'Attack'), +('1024', '16', '7266', 'Duel'), +('1024', '16', '7267', 'Grovel'), +('1024', '16', '7355', 'Stuck'), +('1024', '16', '8386', 'Attacking'), +('1024', '16', '9078', 'Cloth'), +('1024', '16', '9125', 'Generic'), +('1024', '16', '20579', 'Shadow Resistance'), +('1024', '16', '21651', 'Opening'), +('1024', '16', '21652', 'Closing'), +('1024', '16', '22027', 'Remove Insignia'), +('1024', '16', '22810', 'Opening - No Text'), +('1024', '16', '28875', 'Gemcutting'), +('1024', '16', '28878', 'Inspiring Presence'), +('1024', '16', '28880', 'Gift of the Naaru'), +('1024', '16', '29932', 'Language Draenei'), +('1024', '64', '81', 'Dodge'), +('1024', '64', '107', 'Block'), +('1024', '64', '198', 'One-Handed Maces'), +('1024', '64', '203', 'Unarmed'), +('1024', '64', '204', 'Defense'), +('1024', '64', '227', 'Staves'), +('1024', '64', '331', 'Healing Wave'), +('1024', '64', '403', 'Lightning Bolt'), +('1024', '64', '522', 'SPELLDEFENSE(DND)'), +('1024', '64', '668', 'Language Common'), +('1024', '64', '2382', 'Generic'), +('1024', '64', '2479', 'Honorless Target'), +('1024', '64', '3050', 'Detect'), +('1024', '64', '3365', 'Opening'), +('1024', '64', '6233', 'Closing'), +('1024', '64', '6246', 'Closing'), +('1024', '64', '6247', 'Opening'), +('1024', '64', '6477', 'Opening'), +('1024', '64', '6478', 'Opening'), +('1024', '64', '6603', 'Attack'), +('1024', '64', '7266', 'Duel'), +('1024', '64', '7267', 'Grovel'), +('1024', '64', '7355', 'Stuck'), +('1024', '64', '8386', 'Attacking'), +('1024', '64', '9077', 'Leather'), +('1024', '64', '9078', 'Cloth'), +('1024', '64', '9116', 'Shield'), +('1024', '64', '9125', 'Generic'), +('1024', '64', '20579', 'Shadow Resistance'), +('1024', '64', '21651', 'Opening'), +('1024', '64', '21652', 'Closing'), +('1024', '64', '22027', 'Remove Insignia'), +('1024', '64', '22810', 'Opening - No Text'), +('1024', '64', '27763', 'Totem'), +('1024', '64', '28875', 'Gemcutting'), +('1024', '64', '28878', 'Inspiring Presence'), +('1024', '64', '28880', 'Gift of the Naaru'), +('1024', '64', '29932', 'Language Draenei'), +('1024', '128', '81', 'Dodge'), +('1024', '128', '133', 'Fireball'), +('1024', '128', '168', 'Frost Armor'), +('1024', '128', '203', 'Unarmed'), +('1024', '128', '204', 'Defense'), +('1024', '128', '227', 'Staves'), +('1024', '128', '522', 'SPELLDEFENSE(DND)'), +('1024', '128', '668', 'Language Common'), +('1024', '128', '2382', 'Generic'), +('1024', '128', '2479', 'Honorless Target'), +('1024', '128', '3050', 'Detect'), +('1024', '128', '3365', 'Opening'), +('1024', '128', '5009', 'Wands'), +('1024', '128', '5019', 'Shoot'), +('1024', '128', '6233', 'Closing'), +('1024', '128', '6246', 'Closing'), +('1024', '128', '6247', 'Opening'), +('1024', '128', '6477', 'Opening'), +('1024', '128', '6478', 'Opening'), +('1024', '128', '6603', 'Attack'), +('1024', '128', '7266', 'Duel'), +('1024', '128', '7267', 'Grovel'), +('1024', '128', '7355', 'Stuck'), +('1024', '128', '8386', 'Attacking'), +('1024', '128', '9078', 'Cloth'), +('1024', '128', '9125', 'Generic'), +('1024', '128', '20579', 'Shadow Resistance'), +('1024', '128', '21651', 'Opening'), +('1024', '128', '21652', 'Closing'), +('1024', '128', '22027', 'Remove Insignia'), +('1024', '128', '22810', 'Opening - No Text'), +('1024', '128', '28875', 'Gemcutting'), +('1024', '128', '28878', 'Inspiring Presence'), +('1024', '128', '28880', 'Gift of the Naaru'), +('1024', '128', '29932', 'Language Draenei'), +('1', '1', '2048', null), +('1', '1', '30324', null), +('1', '1', '11578', null), +('1', '1', '25208', null), +('1', '1', '25264', null), +('1', '1', '2687', null), +('1', '1', '71', null), +('1', '1', '25225', null), +('1', '1', '355', null), +('1', '1', '11585', null), +('1', '1', '29704', null), +('1', '1', '25203', null), +('1', '1', '30357', null), +('1', '1', '25266', null), +('1', '1', '2565', null), +('1', '1', '676', null), +('1', '1', '25231', null), +('1', '1', '20230', null), +('1', '1', '5246', null), +('1', '1', '25236', null), +('1', '1', '1161', null), +('1', '1', '871', null), +('1', '1', '2458', null), +('1', '1', '25275', null), +('1', '1', '25242', null), +('1', '1', '18499', null), +('1', '1', '1680', null), +('1', '1', '6554', null), +('1', '1', '1719', null), +('1', '1', '34428', null), +('1', '1', '23920', null), +('1', '1', '469', null), +('1', '1', '3411', null), +('2', '1', '2048', null), +('2', '1', '30324', null), +('2', '1', '11578', null), +('2', '1', '25208', null), +('2', '1', '25264', null), +('2', '1', '2687', null), +('2', '1', '71', null), +('2', '1', '25225', null), +('2', '1', '355', null), +('2', '1', '11585', null), +('2', '1', '29704', null), +('2', '1', '25203', null), +('2', '1', '30357', null), +('2', '1', '25266', null), +('2', '1', '2565', null), +('2', '1', '676', null), +('2', '1', '25231', null), +('2', '1', '20230', null), +('2', '1', '5246', null), +('2', '1', '25236', null), +('2', '1', '1161', null), +('2', '1', '871', null), +('2', '1', '2458', null), +('2', '1', '25275', null), +('2', '1', '25242', null), +('2', '1', '18499', null), +('2', '1', '1680', null), +('2', '1', '6554', null), +('2', '1', '1719', null), +('2', '1', '34428', null), +('2', '1', '23920', null), +('2', '1', '469', null), +('2', '1', '3411', null), +('4', '1', '2048', null), +('4', '1', '30324', null), +('4', '1', '11578', null), +('4', '1', '25208', null), +('4', '1', '25264', null), +('4', '1', '2687', null), +('4', '1', '71', null), +('4', '1', '25225', null), +('4', '1', '355', null), +('4', '1', '11585', null), +('4', '1', '29704', null), +('4', '1', '25203', null), +('4', '1', '30357', null), +('4', '1', '25266', null), +('4', '1', '2565', null), +('4', '1', '676', null), +('4', '1', '25231', null), +('4', '1', '20230', null), +('4', '1', '5246', null), +('4', '1', '25236', null), +('4', '1', '1161', null), +('4', '1', '871', null), +('4', '1', '2458', null), +('4', '1', '25275', null), +('4', '1', '25242', null), +('4', '1', '18499', null), +('4', '1', '1680', null), +('4', '1', '6554', null), +('4', '1', '1719', null), +('4', '1', '34428', null), +('4', '1', '23920', null), +('4', '1', '469', null), +('4', '1', '3411', null), +('8', '1', '2048', null), +('8', '1', '30324', null), +('8', '1', '11578', null), +('8', '1', '25208', null), +('8', '1', '25264', null), +('8', '1', '2687', null), +('8', '1', '71', null), +('8', '1', '25225', null), +('8', '1', '355', null), +('8', '1', '11585', null), +('8', '1', '29704', null), +('8', '1', '25203', null), +('8', '1', '30357', null), +('8', '1', '25266', null), +('8', '1', '2565', null), +('8', '1', '676', null), +('8', '1', '25231', null), +('8', '1', '20230', null), +('8', '1', '5246', null), +('8', '1', '25236', null), +('8', '1', '1161', null), +('8', '1', '871', null), +('8', '1', '2458', null), +('8', '1', '25275', null), +('8', '1', '25242', null), +('8', '1', '18499', null), +('8', '1', '1680', null), +('8', '1', '6554', null), +('8', '1', '1719', null), +('8', '1', '34428', null), +('8', '1', '23920', null), +('8', '1', '469', null), +('8', '1', '3411', null), +('16', '1', '2048', null), +('16', '1', '30324', null), +('16', '1', '11578', null), +('16', '1', '25208', null), +('16', '1', '25264', null), +('16', '1', '2687', null), +('16', '1', '71', null), +('16', '1', '25225', null), +('16', '1', '355', null), +('16', '1', '11585', null), +('16', '1', '29704', null), +('16', '1', '25203', null), +('16', '1', '30357', null), +('16', '1', '25266', null), +('16', '1', '2565', null), +('16', '1', '676', null), +('16', '1', '25231', null), +('16', '1', '20230', null), +('16', '1', '5246', null), +('16', '1', '25236', null), +('16', '1', '1161', null), +('16', '1', '871', null), +('16', '1', '2458', null), +('16', '1', '25275', null), +('16', '1', '25242', null), +('16', '1', '18499', null), +('16', '1', '1680', null), +('16', '1', '6554', null), +('16', '1', '1719', null), +('16', '1', '34428', null), +('16', '1', '23920', null), +('16', '1', '469', null), +('16', '1', '3411', null), +('32', '1', '2048', null), +('32', '1', '30324', null), +('32', '1', '11578', null), +('32', '1', '25208', null), +('32', '1', '25264', null), +('32', '1', '2687', null), +('32', '1', '71', null), +('32', '1', '25225', null), +('32', '1', '355', null), +('32', '1', '11585', null), +('32', '1', '29704', null), +('32', '1', '25203', null), +('32', '1', '30357', null), +('32', '1', '25266', null), +('32', '1', '2565', null), +('32', '1', '676', null), +('32', '1', '25231', null), +('32', '1', '20230', null), +('32', '1', '5246', null), +('32', '1', '25236', null), +('32', '1', '1161', null), +('32', '1', '871', null), +('32', '1', '2458', null), +('32', '1', '25275', null), +('32', '1', '25242', null), +('32', '1', '18499', null), +('32', '1', '1680', null), +('32', '1', '6554', null), +('32', '1', '1719', null), +('32', '1', '34428', null), +('32', '1', '23920', null), +('32', '1', '469', null), +('32', '1', '3411', null), +('64', '1', '2048', null), +('64', '1', '30324', null), +('64', '1', '11578', null), +('64', '1', '25208', null), +('64', '1', '25264', null), +('64', '1', '2687', null), +('64', '1', '71', null), +('64', '1', '25225', null), +('64', '1', '355', null), +('64', '1', '11585', null), +('64', '1', '29704', null), +('64', '1', '25203', null), +('64', '1', '30357', null), +('64', '1', '25266', null), +('64', '1', '2565', null), +('64', '1', '676', null), +('64', '1', '25231', null), +('64', '1', '20230', null), +('64', '1', '5246', null), +('64', '1', '25236', null), +('64', '1', '1161', null), +('64', '1', '871', null), +('64', '1', '2458', null), +('64', '1', '25275', null), +('64', '1', '25242', null), +('64', '1', '18499', null), +('64', '1', '1680', null), +('64', '1', '6554', null), +('64', '1', '1719', null), +('64', '1', '34428', null), +('64', '1', '23920', null), +('64', '1', '469', null), +('64', '1', '3411', null), +('128', '1', '2048', null), +('128', '1', '30324', null), +('128', '1', '11578', null), +('128', '1', '25208', null), +('128', '1', '25264', null), +('128', '1', '2687', null), +('128', '1', '71', null), +('128', '1', '25225', null), +('128', '1', '355', null), +('128', '1', '11585', null), +('128', '1', '29704', null), +('128', '1', '25203', null), +('128', '1', '30357', null), +('128', '1', '25266', null), +('128', '1', '2565', null), +('128', '1', '676', null), +('128', '1', '25231', null), +('128', '1', '20230', null), +('128', '1', '5246', null), +('128', '1', '25236', null), +('128', '1', '1161', null), +('128', '1', '871', null), +('128', '1', '2458', null), +('128', '1', '25275', null), +('128', '1', '25242', null), +('128', '1', '18499', null), +('128', '1', '1680', null), +('128', '1', '6554', null), +('128', '1', '1719', null), +('128', '1', '34428', null), +('128', '1', '23920', null), +('128', '1', '469', null), +('128', '1', '3411', null), +('1024', '1', '2048', null), +('1024', '1', '30324', null), +('1024', '1', '11578', null), +('1024', '1', '25208', null), +('1024', '1', '25264', null), +('1024', '1', '2687', null), +('1024', '1', '71', null), +('1024', '1', '25225', null), +('1024', '1', '355', null), +('1024', '1', '11585', null), +('1024', '1', '29704', null), +('1024', '1', '25203', null), +('1024', '1', '30357', null), +('1024', '1', '25266', null), +('1024', '1', '2565', null), +('1024', '1', '676', null), +('1024', '1', '25231', null), +('1024', '1', '20230', null), +('1024', '1', '5246', null), +('1024', '1', '25236', null), +('1024', '1', '1161', null), +('1024', '1', '871', null), +('1024', '1', '2458', null), +('1024', '1', '25275', null), +('1024', '1', '25242', null), +('1024', '1', '18499', null), +('1024', '1', '1680', null), +('1024', '1', '6554', null), +('1024', '1', '1719', null), +('1024', '1', '34428', null), +('1024', '1', '23920', null), +('1024', '1', '469', null), +('1024', '1', '3411', null), +('2', '4', '27014', null), +('2', '4', '1494', null), +('2', '4', '13163', null), +('2', '4', '27016', null), +('2', '4', '27019', null), +('2', '4', '14325', null), +('2', '4', '5116', null), +('2', '4', '27044', null), +('2', '4', '883', null), +('2', '4', '2641', null), +('2', '4', '6991', null), +('2', '4', '982', null), +('2', '4', '1515', null), +('2', '4', '19883', null), +('2', '4', '27020', null), +('2', '4', '27046', null), +('2', '4', '14268', null), +('2', '4', '6197', null), +('2', '4', '1002', null), +('2', '4', '14327', null), +('2', '4', '27023', null), +('2', '4', '36916', null), +('2', '4', '27021', null), +('2', '4', '19884', null), +('2', '4', '5118', null), +('2', '4', '27015', null), +('2', '4', '14311', null), +('2', '4', '3043', null), +('2', '4', '1462', null), +('2', '4', '19885', null), +('2', '4', '3045', null), +('2', '4', '19880', null), +('2', '4', '13809', null), +('2', '4', '13161', null), +('2', '4', '5384', null), +('2', '4', '1543', null), +('2', '4', '19878', null), +('2', '4', '27025', null), +('2', '4', '27018', null), +('2', '4', '13159', null), +('2', '4', '19882', null), +('2', '4', '27022', null), +('2', '4', '27045', null), +('2', '4', '19879', null), +('2', '4', '19801', null), +('2', '4', '34120', null), +('2', '4', '34074', null), +('2', '4', '34026', null), +('2', '4', '34600', null), +('2', '4', '34477', null), +('4', '4', '27014', null), +('4', '4', '1494', null), +('4', '4', '13163', null), +('4', '4', '27016', null), +('4', '4', '27019', null), +('4', '4', '14325', null), +('4', '4', '5116', null), +('4', '4', '27044', null), +('4', '4', '883', null), +('4', '4', '2641', null), +('4', '4', '6991', null), +('4', '4', '982', null), +('4', '4', '1515', null), +('4', '4', '19883', null), +('4', '4', '27020', null), +('4', '4', '27046', null), +('4', '4', '14268', null), +('4', '4', '6197', null), +('4', '4', '1002', null), +('4', '4', '14327', null), +('4', '4', '27023', null), +('4', '4', '36916', null), +('4', '4', '27021', null), +('4', '4', '19884', null), +('4', '4', '5118', null), +('4', '4', '27015', null), +('4', '4', '14311', null), +('4', '4', '3043', null), +('4', '4', '1462', null), +('4', '4', '19885', null), +('4', '4', '3045', null), +('4', '4', '19880', null), +('4', '4', '13809', null), +('4', '4', '13161', null), +('4', '4', '5384', null), +('4', '4', '1543', null), +('4', '4', '19878', null), +('4', '4', '27025', null), +('4', '4', '27018', null), +('4', '4', '13159', null), +('4', '4', '19882', null), +('4', '4', '27022', null), +('4', '4', '27045', null), +('4', '4', '19879', null), +('4', '4', '19801', null), +('4', '4', '34120', null), +('4', '4', '34074', null), +('4', '4', '34026', null), +('4', '4', '34600', null), +('4', '4', '34477', null), +('8', '4', '27014', null), +('8', '4', '1494', null), +('8', '4', '13163', null), +('8', '4', '27016', null), +('8', '4', '27019', null), +('8', '4', '14325', null), +('8', '4', '5116', null), +('8', '4', '27044', null), +('8', '4', '883', null), +('8', '4', '2641', null), +('8', '4', '6991', null), +('8', '4', '982', null), +('8', '4', '1515', null), +('8', '4', '19883', null), +('8', '4', '27020', null), +('8', '4', '27046', null), +('8', '4', '14268', null), +('8', '4', '6197', null), +('8', '4', '1002', null), +('8', '4', '14327', null), +('8', '4', '27023', null), +('8', '4', '36916', null), +('8', '4', '27021', null), +('8', '4', '19884', null), +('8', '4', '5118', null), +('8', '4', '27015', null), +('8', '4', '14311', null), +('8', '4', '3043', null), +('8', '4', '1462', null), +('8', '4', '19885', null), +('8', '4', '3045', null), +('8', '4', '19880', null), +('8', '4', '13809', null), +('8', '4', '13161', null), +('8', '4', '5384', null), +('8', '4', '1543', null), +('8', '4', '19878', null), +('8', '4', '27025', null), +('8', '4', '27018', null), +('8', '4', '13159', null), +('8', '4', '19882', null), +('8', '4', '27022', null), +('8', '4', '27045', null), +('8', '4', '19879', null), +('8', '4', '19801', null), +('8', '4', '34120', null), +('8', '4', '34074', null), +('8', '4', '34026', null), +('8', '4', '34600', null), +('8', '4', '34477', null), +('32', '4', '27014', null), +('32', '4', '1494', null), +('32', '4', '13163', null), +('32', '4', '27016', null), +('32', '4', '27019', null), +('32', '4', '14325', null), +('32', '4', '5116', null), +('32', '4', '27044', null), +('32', '4', '883', null), +('32', '4', '2641', null), +('32', '4', '6991', null), +('32', '4', '982', null), +('32', '4', '1515', null), +('32', '4', '19883', null), +('32', '4', '27020', null), +('32', '4', '27046', null), +('32', '4', '14268', null), +('32', '4', '6197', null), +('32', '4', '1002', null), +('32', '4', '14327', null), +('32', '4', '27023', null), +('32', '4', '36916', null), +('32', '4', '27021', null), +('32', '4', '19884', null), +('32', '4', '5118', null), +('32', '4', '27015', null), +('32', '4', '14311', null), +('32', '4', '3043', null), +('32', '4', '1462', null), +('32', '4', '19885', null), +('32', '4', '3045', null), +('32', '4', '19880', null), +('32', '4', '13809', null), +('32', '4', '13161', null), +('32', '4', '5384', null), +('32', '4', '1543', null), +('32', '4', '19878', null), +('32', '4', '27025', null), +('32', '4', '27018', null), +('32', '4', '13159', null), +('32', '4', '19882', null), +('32', '4', '27022', null), +('32', '4', '27045', null), +('32', '4', '19879', null), +('32', '4', '19801', null), +('32', '4', '34120', null), +('32', '4', '34074', null), +('32', '4', '34026', null), +('32', '4', '34600', null), +('32', '4', '34477', null), +('128', '4', '27014', null), +('128', '4', '1494', null), +('128', '4', '13163', null), +('128', '4', '27016', null), +('128', '4', '27019', null), +('128', '4', '14325', null), +('128', '4', '5116', null), +('128', '4', '27044', null), +('128', '4', '883', null), +('128', '4', '2641', null), +('128', '4', '6991', null), +('128', '4', '982', null), +('128', '4', '1515', null), +('128', '4', '19883', null), +('128', '4', '27020', null), +('128', '4', '27046', null), +('128', '4', '14268', null), +('128', '4', '6197', null), +('128', '4', '1002', null), +('128', '4', '14327', null), +('128', '4', '27023', null), +('128', '4', '36916', null), +('128', '4', '27021', null), +('128', '4', '19884', null), +('128', '4', '5118', null), +('128', '4', '27015', null), +('128', '4', '14311', null), +('128', '4', '3043', null), +('128', '4', '1462', null), +('128', '4', '19885', null), +('128', '4', '3045', null), +('128', '4', '19880', null), +('128', '4', '13809', null), +('128', '4', '13161', null), +('128', '4', '5384', null), +('128', '4', '1543', null), +('128', '4', '19878', null), +('128', '4', '27025', null), +('128', '4', '27018', null), +('128', '4', '13159', null), +('128', '4', '19882', null), +('128', '4', '27022', null), +('128', '4', '27045', null), +('128', '4', '19879', null), +('128', '4', '19801', null), +('128', '4', '34120', null), +('128', '4', '34074', null), +('128', '4', '34026', null), +('128', '4', '34600', null), +('128', '4', '34477', null), +('512', '4', '27014', null), +('512', '4', '1494', null), +('512', '4', '13163', null), +('512', '4', '27016', null), +('512', '4', '27019', null), +('512', '4', '14325', null), +('512', '4', '5116', null), +('512', '4', '27044', null), +('512', '4', '883', null), +('512', '4', '2641', null), +('512', '4', '6991', null), +('512', '4', '982', null), +('512', '4', '1515', null), +('512', '4', '19883', null), +('512', '4', '27020', null), +('512', '4', '27046', null), +('512', '4', '14268', null), +('512', '4', '6197', null), +('512', '4', '1002', null), +('512', '4', '14327', null), +('512', '4', '27023', null), +('512', '4', '36916', null), +('512', '4', '27021', null), +('512', '4', '19884', null), +('512', '4', '5118', null), +('512', '4', '27015', null), +('512', '4', '14311', null), +('512', '4', '3043', null), +('512', '4', '1462', null), +('512', '4', '19885', null), +('512', '4', '3045', null), +('512', '4', '19880', null), +('512', '4', '13809', null), +('512', '4', '13161', null), +('512', '4', '5384', null), +('512', '4', '1543', null), +('512', '4', '19878', null), +('512', '4', '27025', null), +('512', '4', '27018', null), +('512', '4', '13159', null), +('512', '4', '19882', null), +('512', '4', '27022', null), +('512', '4', '27045', null), +('512', '4', '19879', null), +('512', '4', '19801', null), +('512', '4', '34120', null), +('512', '4', '34074', null), +('512', '4', '34026', null), +('512', '4', '34600', null), +('512', '4', '34477', null), +('1024', '4', '27014', null), +('1024', '4', '1494', null), +('1024', '4', '13163', null), +('1024', '4', '27016', null), +('1024', '4', '27019', null), +('1024', '4', '14325', null), +('1024', '4', '5116', null), +('1024', '4', '27044', null), +('1024', '4', '883', null), +('1024', '4', '2641', null), +('1024', '4', '6991', null), +('1024', '4', '982', null), +('1024', '4', '1515', null), +('1024', '4', '19883', null), +('1024', '4', '27020', null), +('1024', '4', '27046', null), +('1024', '4', '14268', null), +('1024', '4', '6197', null), +('1024', '4', '1002', null), +('1024', '4', '14327', null), +('1024', '4', '27023', null), +('1024', '4', '36916', null), +('1024', '4', '27021', null), +('1024', '4', '19884', null), +('1024', '4', '5118', null), +('1024', '4', '27015', null), +('1024', '4', '14311', null), +('1024', '4', '3043', null), +('1024', '4', '1462', null), +('1024', '4', '19885', null), +('1024', '4', '3045', null), +('1024', '4', '19880', null), +('1024', '4', '13809', null), +('1024', '4', '13161', null), +('1024', '4', '5384', null), +('1024', '4', '1543', null), +('1024', '4', '19878', null), +('1024', '4', '27025', null), +('1024', '4', '27018', null), +('1024', '4', '13159', null), +('1024', '4', '19882', null), +('1024', '4', '27022', null), +('1024', '4', '27045', null), +('1024', '4', '19879', null), +('1024', '4', '19801', null), +('1024', '4', '34120', null), +('1024', '4', '34074', null), +('1024', '4', '34026', null), +('1024', '4', '34600', null), +('1024', '4', '34477', null), +('1', '2', '27149', null), +('1', '2', '27136', null), +('1', '2', '27155', null), +('1', '2', '27140', null), +('1', '2', '20271', null), +('1', '2', '27158', null), +('1', '2', '10308', null), +('1', '2', '10278', null), +('1', '2', '27154', null), +('1', '2', '20773', null), +('1', '2', '27142', null), +('1', '2', '31789', null), +('1', '2', '27150', null), +('1', '2', '25780', null), +('1', '2', '1044', null), +('1', '2', '33776', null), +('1', '2', '27173', null), +('1', '2', '27138', null), +('1', '2', '27137', null), +('1', '2', '5502', null), +('1', '2', '19746', null), +('1', '2', '31895', null), +('1', '2', '5627', null), +('1', '2', '1038', null), +('1', '2', '27151', null), +('1', '2', '19752', null), +('1', '2', '27160', null), +('1', '2', '27152', null), +('1', '2', '1020', null), +('1', '2', '27153', null), +('1', '2', '27166', null), +('1', '2', '27144', null), +('1', '2', '4987', null), +('1', '2', '27180', null), +('1', '2', '27148', null), +('1', '2', '27139', null), +('1', '2', '27141', null), +('1', '2', '10326', null), +('1', '2', '27143', null), +('1', '2', '25898', null), +('1', '2', '27145', null), +('1', '2', '25895', null), +('1', '2', '32223', null), +('1', '2', '27169', null), +('1', '2', '31884', null), +('4', '2', '27149', null), +('4', '2', '27136', null), +('4', '2', '27155', null), +('4', '2', '27140', null), +('4', '2', '20271', null), +('4', '2', '27158', null), +('4', '2', '10308', null), +('4', '2', '10278', null), +('4', '2', '27154', null), +('4', '2', '20773', null), +('4', '2', '27142', null), +('4', '2', '31789', null), +('4', '2', '27150', null), +('4', '2', '25780', null), +('4', '2', '1044', null), +('4', '2', '33776', null), +('4', '2', '27173', null), +('4', '2', '27138', null), +('4', '2', '27137', null), +('4', '2', '5502', null), +('4', '2', '19746', null), +('4', '2', '31895', null), +('4', '2', '5627', null), +('4', '2', '1038', null), +('4', '2', '27151', null), +('4', '2', '19752', null), +('4', '2', '27160', null), +('4', '2', '27152', null), +('4', '2', '1020', null), +('4', '2', '27153', null), +('4', '2', '27166', null), +('4', '2', '27144', null), +('4', '2', '4987', null), +('4', '2', '27180', null), +('4', '2', '27148', null), +('4', '2', '27139', null), +('4', '2', '27141', null), +('4', '2', '10326', null), +('4', '2', '27143', null), +('4', '2', '25898', null), +('4', '2', '27145', null), +('4', '2', '25895', null), +('4', '2', '32223', null), +('4', '2', '27169', null), +('4', '2', '31884', null), +('512', '2', '27149', null), +('512', '2', '27136', null), +('512', '2', '27155', null), +('512', '2', '27140', null), +('512', '2', '20271', null), +('512', '2', '27158', null), +('512', '2', '10308', null), +('512', '2', '10278', null), +('512', '2', '27154', null), +('512', '2', '20773', null), +('512', '2', '27142', null), +('512', '2', '31789', null), +('512', '2', '27150', null), +('512', '2', '25780', null), +('512', '2', '1044', null), +('512', '2', '33776', null), +('512', '2', '27173', null), +('512', '2', '27138', null), +('512', '2', '27137', null), +('512', '2', '5502', null), +('512', '2', '19746', null), +('512', '2', '31895', null), +('512', '2', '5627', null), +('512', '2', '1038', null), +('512', '2', '27151', null), +('512', '2', '19752', null), +('512', '2', '27160', null), +('512', '2', '27152', null), +('512', '2', '1020', null), +('512', '2', '27153', null), +('512', '2', '27166', null), +('512', '2', '27144', null), +('512', '2', '4987', null), +('512', '2', '27180', null), +('512', '2', '27148', null), +('512', '2', '27139', null), +('512', '2', '27141', null), +('512', '2', '10326', null), +('512', '2', '27143', null), +('512', '2', '25898', null), +('512', '2', '27145', null), +('512', '2', '25895', null), +('512', '2', '32223', null), +('512', '2', '27169', null), +('512', '2', '31884', null), +('1024', '2', '27149', null), +('1024', '2', '27136', null), +('1024', '2', '27155', null), +('1024', '2', '27140', null), +('1024', '2', '20271', null), +('1024', '2', '27158', null), +('1024', '2', '10308', null), +('1024', '2', '10278', null), +('1024', '2', '27154', null), +('1024', '2', '20773', null), +('1024', '2', '27142', null), +('1024', '2', '31789', null), +('1024', '2', '27150', null), +('1024', '2', '25780', null), +('1024', '2', '1044', null), +('1024', '2', '33776', null), +('1024', '2', '27173', null), +('1024', '2', '27138', null), +('1024', '2', '27137', null), +('1024', '2', '5502', null), +('1024', '2', '19746', null), +('1024', '2', '31895', null), +('1024', '2', '5627', null), +('1024', '2', '1038', null), +('1024', '2', '27151', null), +('1024', '2', '19752', null), +('1024', '2', '27160', null), +('1024', '2', '27152', null), +('1024', '2', '1020', null), +('1024', '2', '27153', null), +('1024', '2', '27166', null), +('1024', '2', '27144', null), +('1024', '2', '4987', null), +('1024', '2', '27180', null), +('1024', '2', '27148', null), +('1024', '2', '27139', null), +('1024', '2', '27141', null), +('1024', '2', '10326', null), +('1024', '2', '27143', null), +('1024', '2', '25898', null), +('1024', '2', '27145', null), +('1024', '2', '25895', null), +('1024', '2', '32223', null), +('1024', '2', '27169', null), +('1024', '2', '31884', null), +('1', '8', '26865', null), +('1', '8', '26862', null), +('1', '8', '1787', null), +('1', '8', '26863', null), +('1', '8', '921', null), +('1', '8', '38764', null), +('1', '8', '26669', null), +('1', '8', '11297', null), +('1', '8', '6774', null), +('1', '8', '11305', null), +('1', '8', '38768', null), +('1', '8', '26866', null), +('1', '8', '26884', null), +('1', '8', '27448', null), +('1', '8', '1804', null), +('1', '8', '27441', null), +('1', '8', '2842', null), +('1', '8', '1725', null), +('1', '8', '26867', null), +('1', '8', '26889', null), +('1', '8', '1833', null), +('1', '8', '1842', null), +('1', '8', '408', null), +('1', '8', '2094', null), +('1', '8', '32684', null), +('1', '8', '26679', null), +('1', '8', '31224', null), +('1', '8', '5938', null), +('2', '8', '26865', null), +('2', '8', '26862', null), +('2', '8', '1787', null), +('2', '8', '26863', null), +('2', '8', '921', null), +('2', '8', '38764', null), +('2', '8', '26669', null), +('2', '8', '11297', null), +('2', '8', '6774', null), +('2', '8', '11305', null), +('2', '8', '38768', null), +('2', '8', '26866', null), +('2', '8', '26884', null), +('2', '8', '27448', null), +('2', '8', '1804', null), +('2', '8', '27441', null), +('2', '8', '2842', null), +('2', '8', '1725', null), +('2', '8', '26867', null), +('2', '8', '26889', null), +('2', '8', '1833', null), +('2', '8', '1842', null), +('2', '8', '408', null), +('2', '8', '2094', null), +('2', '8', '32684', null), +('2', '8', '26679', null), +('2', '8', '31224', null), +('2', '8', '5938', null), +('4', '8', '26865', null), +('4', '8', '26862', null), +('4', '8', '1787', null), +('4', '8', '26863', null), +('4', '8', '921', null), +('4', '8', '38764', null), +('4', '8', '26669', null), +('4', '8', '11297', null), +('4', '8', '6774', null), +('4', '8', '11305', null), +('4', '8', '38768', null), +('4', '8', '26866', null), +('4', '8', '26884', null), +('4', '8', '27448', null), +('4', '8', '1804', null), +('4', '8', '27441', null), +('4', '8', '2842', null), +('4', '8', '1725', null), +('4', '8', '26867', null), +('4', '8', '26889', null), +('4', '8', '1833', null), +('4', '8', '1842', null), +('4', '8', '408', null), +('4', '8', '2094', null), +('4', '8', '32684', null), +('4', '8', '26679', null), +('4', '8', '31224', null), +('4', '8', '5938', null), +('8', '8', '26865', null), +('8', '8', '26862', null), +('8', '8', '1787', null), +('8', '8', '26863', null), +('8', '8', '921', null), +('8', '8', '38764', null), +('8', '8', '26669', null), +('8', '8', '11297', null), +('8', '8', '6774', null), +('8', '8', '11305', null), +('8', '8', '38768', null), +('8', '8', '26866', null), +('8', '8', '426884', null), +('8', '8', '427448', null), +('8', '8', '1804', null), +('8', '8', '27441', null), +('8', '8', '2842', null), +('8', '8', '1725', null), +('8', '8', '26867', null), +('8', '8', '26889', null), +('8', '8', '1833', null), +('8', '8', '1842', null), +('8', '8', '408', null), +('8', '8', '2094', null), +('8', '8', '32684', null), +('8', '8', '26679', null), +('8', '8', '31224', null), +('8', '8', '5938', null), +('16', '8', '26865', null), +('16', '8', '26862', null), +('16', '8', '1787', null), +('16', '8', '26863', null), +('16', '8', '921', null), +('16', '8', '38764', null), +('16', '8', '26669', null), +('16', '8', '11297', null), +('16', '8', '6774', null), +('16', '8', '11305', null), +('16', '8', '38768', null), +('16', '8', '26866', null), +('16', '8', '26884', null), +('16', '8', '27448', null), +('16', '8', '1804', null), +('16', '8', '27441', null), +('16', '8', '2842', null), +('16', '8', '1725', null), +('16', '8', '26867', null), +('16', '8', '26889', null), +('16', '8', '1833', null), +('16', '8', '1842', null), +('16', '8', '408', null), +('16', '8', '2094', null), +('16', '8', '32684', null), +('16', '8', '26679', null), +('16', '8', '31224', null), +('16', '8', '5938', null), +('64', '8', '26865', null), +('64', '8', '26862', null), +('64', '8', '1787', null), +('64', '8', '26863', null), +('64', '8', '921', null), +('64', '8', '38764', null), +('64', '8', '26669', null), +('64', '8', '11297', null), +('64', '8', '6774', null), +('64', '8', '11305', null), +('64', '8', '38768', null), +('64', '8', '26866', null), +('64', '8', '26884', null), +('64', '8', '27448', null), +('64', '8', '1804', null), +('64', '8', '27441', null), +('64', '8', '2842', null), +('64', '8', '1725', null), +('64', '8', '26867', null), +('64', '8', '26889', null), +('64', '8', '1833', null), +('64', '8', '1842', null), +('64', '8', '408', null), +('64', '8', '2094', null), +('64', '8', '32684', null), +('64', '8', '26679', null), +('64', '8', '31224', null), +('64', '8', '5938', null), +('128', '8', '26865', null), +('128', '8', '26862', null), +('128', '8', '1787', null), +('128', '8', '26863', null), +('128', '8', '921', null), +('128', '8', '38764', null), +('128', '8', '26669', null), +('128', '8', '11297', null), +('128', '8', '6774', null), +('128', '8', '11305', null), +('128', '8', '38768', null), +('128', '8', '26866', null), +('128', '8', '26884', null), +('128', '8', '27448', null), +('128', '8', '1804', null), +('128', '8', '27441', null), +('128', '8', '2842', null), +('128', '8', '1725', null), +('128', '8', '26867', null), +('128', '8', '26889', null), +('128', '8', '1833', null), +('128', '8', '1842', null), +('128', '8', '408', null), +('128', '8', '2094', null), +('128', '8', '32684', null), +('128', '8', '26679', null), +('128', '8', '31224', null), +('128', '8', '5938', null), +('512', '8', '26865', null), +('512', '8', '26862', null), +('512', '8', '1787', null), +('512', '8', '26863', null), +('512', '8', '921', null), +('512', '8', '38764', null), +('512', '8', '26669', null), +('512', '8', '11297', null), +('512', '8', '6774', null), +('512', '8', '11305', null), +('512', '8', '38768', null), +('512', '8', '26866', null), +('512', '8', '26884', null), +('512', '8', '27448', null), +('512', '8', '1804', null), +('512', '8', '27441', null), +('512', '8', '2842', null), +('512', '8', '1725', null), +('512', '8', '26867', null), +('512', '8', '26889', null), +('512', '8', '1833', null), +('512', '8', '1842', null), +('512', '8', '408', null), +('512', '8', '2094', null), +('512', '8', '32684', null), +('512', '8', '26679', null), +('512', '8', '31224', null), +('512', '8', '5938', null), +('1', '256', '27215', null), +('1', '256', '27209', null), +('1', '256', '27216', null), +('1', '256', '30909', null), +('1', '256', '27222', null), +('1', '256', '27218', null), +('1', '256', '6215', null), +('1', '256', '27230', null), +('1', '256', '27217', null), +('1', '256', '27259', null), +('1', '256', '27226', null), +('1', '256', '27220', null), +('1', '256', '5697', null), +('1', '256', '27238', null), +('1', '256', '30459', null), +('1', '256', '27260', null), +('1', '256', '27212', null), +('1', '256', '698', null), +('1', '256', '5500', null), +('1', '256', '30908', null), +('1', '256', '11719', null), +('1', '256', '132', null), +('1', '256', '18647', null), +('1', '256', '27213', null), +('1', '256', '11726', null), +('1', '256', '27228', null), +('1', '256', '28610', null), +('1', '256', '28172', null), +('1', '256', '27250', null), +('1', '256', '17928', null), +('1', '256', '27223', null), +('1', '256', '27229', null), +('1', '256', '30545', null), +('1', '256', '30910', null), +('1', '256', '18540', null), +('1', '256', '28189', null), +('1', '256', '32231', null), +('1', '256', '29858', null), +('1', '256', '29893', null), +('1', '256', '27243', null), +('2', '256', '27215', null), +('2', '256', '27209', null), +('2', '256', '27216', null), +('2', '256', '30909', null), +('2', '256', '27222', null), +('2', '256', '27218', null), +('2', '256', '6215', null), +('2', '256', '27230', null), +('2', '256', '27217', null), +('2', '256', '27259', null), +('2', '256', '27226', null), +('2', '256', '27220', null), +('2', '256', '5697', null), +('2', '256', '27238', null), +('2', '256', '30459', null), +('2', '256', '27260', null), +('2', '256', '27212', null), +('2', '256', '698', null), +('2', '256', '5500', null), +('2', '256', '30908', null), +('2', '256', '11719', null), +('2', '256', '132', null), +('2', '256', '18647', null), +('2', '256', '27213', null), +('2', '256', '11726', null), +('2', '256', '27228', null), +('2', '256', '28610', null), +('2', '256', '28172', null), +('2', '256', '27250', null), +('2', '256', '17928', null), +('2', '256', '27223', null), +('2', '256', '27229', null), +('2', '256', '30545', null), +('2', '256', '30910', null), +('2', '256', '18540', null), +('2', '256', '28189', null), +('2', '256', '32231', null), +('2', '256', '29858', null), +('2', '256', '29893', null), +('2', '256', '27243', null), +('16', '256', '27215', null), +('16', '256', '27209', null), +('16', '256', '27216', null), +('16', '256', '30909', null), +('16', '256', '27222', null), +('16', '256', '27218', null), +('16', '256', '6215', null), +('16', '256', '27230', null), +('16', '256', '27217', null), +('16', '256', '27259', null), +('16', '256', '27226', null), +('16', '256', '27220', null), +('16', '256', '5697', null), +('16', '256', '27238', null), +('16', '256', '30459', null), +('16', '256', '27260', null), +('16', '256', '27212', null), +('16', '256', '698', null), +('16', '256', '5500', null), +('16', '256', '30908', null), +('16', '256', '11719', null), +('16', '256', '132', null), +('16', '256', '18647', null), +('16', '256', '27213', null), +('16', '256', '11726', null), +('16', '256', '27228', null), +('16', '256', '28610', null), +('16', '256', '28172', null), +('16', '256', '27250', null), +('16', '256', '17928', null), +('16', '256', '27223', null), +('16', '256', '27229', null), +('16', '256', '30545', null), +('16', '256', '30910', null), +('16', '256', '18540', null), +('16', '256', '28189', null), +('16', '256', '32231', null), +('16', '256', '29858', null), +('16', '256', '29893', null), +('16', '256', '27243', null), +('64', '256', '27215', null), +('64', '256', '27209', null), +('64', '256', '27216', null), +('64', '256', '30909', null), +('64', '256', '27222', null), +('64', '256', '27218', null), +('64', '256', '6215', null), +('64', '256', '27230', null), +('64', '256', '27217', null), +('64', '256', '27259', null), +('64', '256', '27226', null), +('64', '256', '27220', null), +('64', '256', '5697', null), +('64', '256', '27238', null), +('64', '256', '30459', null), +('64', '256', '27260', null), +('64', '256', '27212', null), +('64', '256', '698', null), +('64', '256', '5500', null), +('64', '256', '30908', null), +('64', '256', '11719', null), +('64', '256', '132', null), +('64', '256', '18647', null), +('64', '256', '27213', null), +('64', '256', '11726', null), +('64', '256', '27228', null), +('64', '256', '28610', null), +('64', '256', '28172', null), +('64', '256', '27250', null), +('64', '256', '17928', null), +('64', '256', '27223', null), +('64', '256', '27229', null), +('64', '256', '30545', null), +('64', '256', '30910', null), +('64', '256', '18540', null), +('64', '256', '28189', null), +('64', '256', '32231', null), +('64', '256', '29858', null), +('64', '256', '29893', null), +('64', '256', '27243', null), +('1024', '256', '27215', null), +('1024', '256', '27209', null), +('1024', '256', '27216', null), +('1024', '256', '30909', null), +('1024', '256', '27222', null), +('1024', '256', '27218', null), +('1024', '256', '6215', null), +('1024', '256', '27230', null), +('1024', '256', '27217', null), +('1024', '256', '27259', null), +('1024', '256', '27226', null), +('1024', '256', '27220', null), +('1024', '256', '5697', null), +('1024', '256', '27238', null), +('1024', '256', '30459', null), +('1024', '256', '27260', null), +('1024', '256', '27212', null), +('1024', '256', '698', null), +('1024', '256', '5500', null), +('1024', '256', '30908', null), +('1024', '256', '11719', null), +('1024', '256', '132', null), +('1024', '256', '18647', null), +('1024', '256', '27213', null), +('1024', '256', '11726', null), +('1024', '256', '27228', null), +('1024', '256', '28610', null), +('1024', '256', '28172', null), +('1024', '256', '27250', null), +('1024', '256', '17928', null), +('1024', '256', '27223', null), +('1024', '256', '27229', null), +('1024', '256', '30545', null), +('1024', '256', '30910', null), +('1024', '256', '18540', null), +('1024', '256', '28189', null), +('1024', '256', '32231', null), +('1024', '256', '29858', null), +('1024', '256', '29893', null), +('1024', '256', '27243', null), +('8', '1024', '26979', null), +('8', '1024', '26990', null), +('8', '1024', '26985', null), +('8', '1024', '26988', null), +('8', '1024', '26982', null), +('8', '1024', '26992', null), +('8', '1024', '26989', null), +('8', '1024', '26998', null), +('8', '1024', '6795', null), +('8', '1024', '26996', null), +('8', '1024', '18960', null), +('8', '1024', '9634', null), +('8', '1024', '768', null), +('8', '1024', '783', null), +('8', '1024', '1066', null), +('8', '1024', '40120', null), +('8', '1024', '5229', null), +('8', '1024', '26980', null), +('8', '1024', '8983', null), +('8', '1024', '8946', null), +('8', '1024', '26997', null), +('8', '1024', '26993', null), +('8', '1024', '18658', null), +('8', '1024', '27000', null), +('8', '1024', '9913', null), +('8', '1024', '26994', null), +('8', '1024', '27008', null), +('8', '1024', '26986', null), +('8', '1024', '27002', null), +('8', '1024', '26995', null), +('8', '1024', '27003', null), +('8', '1024', '2782', null), +('8', '1024', '9846', null), +('8', '1024', '2893', null), +('8', '1024', '33357', null), +('8', '1024', '5209', null), +('8', '1024', '27004', null), +('8', '1024', '26983', null), +('8', '1024', '24248', null), +('8', '1024', '27005', null), +('8', '1024', '5225', null), +('8', '1024', '26999', null), +('8', '1024', '27012', null), +('8', '1024', '27006', null), +('8', '1024', '29166', null), +('8', '1024', '22812', null), +('8', '1024', '26991', null), +('8', '1024', '22570', null), +('8', '1024', '33763', null), +('8', '1024', '33745', null), +('8', '1024', '33786', null), +('32', '1024', '26979', null), +('32', '1024', '26990', null), +('32', '1024', '26985', null), +('32', '1024', '26988', null), +('32', '1024', '26982', null), +('32', '1024', '26992', null), +('32', '1024', '26989', null), +('32', '1024', '26998', null), +('32', '1024', '6795', null), +('32', '1024', '26996', null), +('32', '1024', '18960', null), +('32', '1024', '9634', null), +('32', '1024', '768', null), +('32', '1024', '783', null), +('32', '1024', '1066', null), +('32', '1024', '40120', null), +('32', '1024', '5229', null), +('32', '1024', '26980', null), +('32', '1024', '8983', null), +('32', '1024', '8946', null), +('32', '1024', '26997', null), +('32', '1024', '26993', null), +('32', '1024', '18658', null), +('32', '1024', '27000', null), +('32', '1024', '9913', null), +('32', '1024', '26994', null), +('32', '1024', '27008', null), +('32', '1024', '26986', null), +('32', '1024', '27002', null), +('32', '1024', '26995', null), +('32', '1024', '27003', null), +('32', '1024', '2782', null), +('32', '1024', '9846', null), +('32', '1024', '2893', null), +('32', '1024', '33357', null), +('32', '1024', '5209', null), +('32', '1024', '27004', null), +('32', '1024', '26983', null), +('32', '1024', '24248', null), +('32', '1024', '27005', null), +('32', '1024', '5225', null), +('32', '1024', '26999', null), +('32', '1024', '27012', null), +('32', '1024', '27006', null), +('32', '1024', '29166', null), +('32', '1024', '22812', null), +('32', '1024', '26991', null), +('32', '1024', '22570', null), +('32', '1024', '33763', null), +('32', '1024', '33745', null), +('32', '1024', '33786', null), +('1', '128', '27126', null), +('1', '128', '27070', null), +('1', '128', '22018', null), +('1', '128', '27072', null), +('1', '128', '22019', null), +('1', '128', '27079', null), +('1', '128', '38704', null), +('1', '128', '28272', null), +('1', '128', '28271', null), +('1', '128', '12826', null), +('1', '128', '27088', null), +('1', '128', '33944', null), +('1', '128', '130', null), +('1', '128', '27082', null), +('1', '128', '27086', null), +('1', '128', '33946', null), +('1', '128', '475', null), +('1', '128', '1953', null), +('1', '128', '27085', null), +('1', '128', '12051', null), +('1', '128', '27128', null), +('1', '128', '27131', null), +('1', '128', '32796', null), +('1', '128', '27074', null), +('1', '128', '2139', null), +('1', '128', '27101', null), +('1', '128', '27124', null), +('1', '128', '45438', null), +('1', '128', '27125', null), +('1', '128', '27127', null), +('1', '128', '30482', null), +('1', '128', '30451', null), +('1', '128', '30455', null), +('1', '128', '66', null), +('1', '128', '43987', null), +('1', '128', '30449', null), +('16', '128', '27126', null), +('16', '128', '27070', null), +('16', '128', '22018', null), +('16', '128', '27072', null), +('16', '128', '22019', null), +('16', '128', '27079', null), +('16', '128', '38704', null), +('16', '128', '28272', null), +('16', '128', '28271', null), +('16', '128', '12826', null), +('16', '128', '27088', null), +('16', '128', '33944', null), +('16', '128', '130', null), +('16', '128', '27082', null), +('16', '128', '27086', null), +('16', '128', '33946', null), +('16', '128', '475', null), +('16', '128', '1953', null), +('16', '128', '27085', null), +('16', '128', '12051', null), +('16', '128', '27128', null), +('16', '128', '27131', null), +('16', '128', '32796', null), +('16', '128', '27074', null), +('16', '128', '2139', null), +('16', '128', '27101', null), +('16', '128', '27124', null), +('16', '128', '45438', null), +('16', '128', '27125', null), +('16', '128', '27127', null), +('16', '128', '30482', null), +('16', '128', '30451', null), +('16', '128', '30455', null), +('16', '128', '66', null), +('16', '128', '43987', null), +('16', '128', '30449', null), +('64', '128', '27126', null), +('64', '128', '27070', null), +('64', '128', '22018', null), +('64', '128', '27072', null), +('64', '128', '22019', null), +('64', '128', '27079', null), +('64', '128', '38704', null), +('64', '128', '28272', null), +('64', '128', '28271', null), +('64', '128', '12826', null), +('64', '128', '27088', null), +('64', '128', '33944', null), +('64', '128', '130', null), +('64', '128', '27082', null), +('64', '128', '27086', null), +('64', '128', '33946', null), +('64', '128', '475', null), +('64', '128', '1953', null), +('64', '128', '27085', null), +('64', '128', '12051', null), +('64', '128', '27128', null), +('64', '128', '27131', null), +('64', '128', '32796', null), +('64', '128', '27074', null), +('64', '128', '2139', null), +('64', '128', '27101', null), +('64', '128', '27124', null), +('64', '128', '45438', null), +('64', '128', '27125', null), +('64', '128', '27127', null), +('64', '128', '30482', null), +('64', '128', '30451', null), +('64', '128', '30455', null), +('64', '128', '66', null), +('64', '128', '43987', null), +('64', '128', '30449', null), +('128', '128', '27126', null), +('128', '128', '27070', null), +('128', '128', '22018', null), +('128', '128', '27072', null), +('128', '128', '22019', null), +('128', '128', '27079', null), +('128', '128', '38704', null), +('128', '128', '28272', null), +('128', '128', '28271', null), +('128', '128', '12826', null), +('128', '128', '27088', null), +('128', '128', '33944', null), +('128', '128', '130', null), +('128', '128', '27082', null), +('128', '128', '27086', null), +('128', '128', '33946', null), +('128', '128', '475', null), +('128', '128', '1953', null), +('128', '128', '27085', null), +('128', '128', '12051', null), +('128', '128', '27128', null), +('128', '128', '27131', null), +('128', '128', '32796', null), +('128', '128', '27074', null), +('128', '128', '2139', null), +('128', '128', '27101', null), +('128', '128', '27124', null), +('128', '128', '45438', null), +('128', '128', '27125', null), +('128', '128', '27127', null), +('128', '128', '30482', null), +('128', '128', '30451', null), +('128', '128', '30455', null), +('128', '128', '66', null), +('128', '128', '43987', null), +('128', '128', '30449', null), +('512', '128', '27126', null), +('512', '128', '27070', null), +('512', '128', '22018', null), +('512', '128', '27072', null), +('512', '128', '22019', null), +('512', '128', '27079', null), +('512', '128', '38704', null), +('512', '128', '28272', null), +('512', '128', '28271', null), +('512', '128', '12826', null), +('512', '128', '27088', null), +('512', '128', '33944', null), +('512', '128', '130', null), +('512', '128', '27082', null), +('512', '128', '27086', null), +('512', '128', '33946', null), +('512', '128', '475', null), +('512', '128', '1953', null), +('512', '128', '27085', null), +('512', '128', '12051', null), +('512', '128', '27128', null), +('512', '128', '27131', null), +('512', '128', '32796', null), +('512', '128', '27074', null), +('512', '128', '2139', null), +('512', '128', '27101', null), +('512', '128', '27124', null), +('512', '128', '45438', null), +('512', '128', '27125', null), +('512', '128', '27127', null), +('512', '128', '30482', null), +('512', '128', '30451', null), +('512', '128', '30455', null), +('512', '128', '66', null), +('512', '128', '43987', null), +('512', '128', '30449', null), +('1024', '128', '27126', null), +('1024', '128', '27070', null), +('1024', '128', '22018', null), +('1024', '128', '27072', null), +('1024', '128', '22019', null), +('1024', '128', '27079', null), +('1024', '128', '38704', null), +('1024', '128', '28272', null), +('1024', '128', '28271', null), +('1024', '128', '12826', null), +('1024', '128', '27088', null), +('1024', '128', '33944', null), +('1024', '128', '130', null), +('1024', '128', '27082', null), +('1024', '128', '27086', null), +('1024', '128', '33946', null), +('1024', '128', '475', null), +('1024', '128', '1953', null), +('1024', '128', '27085', null), +('1024', '128', '12051', null), +('1024', '128', '27128', null), +('1024', '128', '27131', null), +('1024', '128', '32796', null), +('1024', '128', '27074', null), +('1024', '128', '2139', null), +('1024', '128', '27101', null), +('1024', '128', '27124', null), +('1024', '128', '45438', null), +('1024', '128', '27125', null), +('1024', '128', '27127', null), +('1024', '128', '30482', null), +('1024', '128', '30451', null), +('1024', '128', '30455', null), +('1024', '128', '66', null), +('1024', '128', '43987', null), +('1024', '128', '30449', null), +('1', '16', '25389', null), +('1', '16', '25364', null), +('1', '16', '25368', null), +('1', '16', '25218', null), +('1', '16', '25429', null), +('1', '16', '25222', null), +('1', '16', '25375', null), +('1', '16', '25435', null), +('1', '16', '25431', null), +('1', '16', '528', null), +('1', '16', '10890', null), +('1', '16', '988', null), +('1', '16', '6346', null), +('1', '16', '25235', null), +('1', '16', '25384', null), +('1', '16', '25596', null), +('1', '16', '10955', null), +('1', '16', '10909', null), +('1', '16', '25380', null), +('1', '16', '10912', null), +('1', '16', '25308', null), +('1', '16', '25433', null), +('1', '16', '552', null), +('1', '16', '1706', null), +('1', '16', '25213', null), +('1', '16', '25392', null), +('1', '16', '39374', null), +('1', '16', '32999', null), +('1', '16', '32996', null), +('1', '16', '32546', null), +('1', '16', '34433', null), +('1', '16', '33076', null), +('1', '16', '32375', null), +('4', '16', '25389', null), +('4', '16', '25364', null), +('4', '16', '25368', null), +('4', '16', '25218', null), +('4', '16', '25429', null), +('4', '16', '25222', null), +('4', '16', '25375', null), +('4', '16', '25435', null), +('4', '16', '25431', null), +('4', '16', '528', null), +('4', '16', '10890', null), +('4', '16', '988', null), +('4', '16', '6346', null), +('4', '16', '25235', null), +('4', '16', '25384', null), +('4', '16', '25596', null), +('4', '16', '10955', null), +('4', '16', '10909', null), +('4', '16', '25380', null), +('4', '16', '10912', null), +('4', '16', '25308', null), +('4', '16', '25433', null), +('4', '16', '552', null), +('4', '16', '1706', null), +('4', '16', '25213', null), +('4', '16', '25392', null), +('4', '16', '39374', null), +('4', '16', '32999', null), +('4', '16', '32996', null), +('4', '16', '32546', null), +('4', '16', '34433', null), +('4', '16', '33076', null), +('4', '16', '32375', null), +('8', '16', '25389', null), +('8', '16', '25364', null), +('8', '16', '25368', null), +('8', '16', '25218', null), +('8', '16', '25429', null), +('8', '16', '25222', null), +('8', '16', '25375', null), +('8', '16', '25435', null), +('8', '16', '25431', null), +('8', '16', '528', null), +('8', '16', '10890', null), +('8', '16', '988', null), +('8', '16', '6346', null), +('8', '16', '25235', null), +('8', '16', '25384', null), +('8', '16', '25596', null), +('8', '16', '10955', null), +('8', '16', '10909', null), +('8', '16', '25380', null), +('8', '16', '10912', null), +('8', '16', '25308', null), +('8', '16', '25433', null), +('8', '16', '552', null), +('8', '16', '1706', null), +('8', '16', '25213', null), +('8', '16', '25392', null), +('8', '16', '39374', null), +('8', '16', '32999', null), +('8', '16', '32996', null), +('8', '16', '32546', null), +('8', '16', '34433', null), +('8', '16', '33076', null), +('8', '16', '32375', null), +('16', '16', '25389', null), +('16', '16', '25364', null), +('16', '16', '25368', null), +('16', '16', '25218', null), +('16', '16', '25429', null), +('16', '16', '25222', null), +('16', '16', '25375', null), +('16', '16', '25435', null), +('16', '16', '25431', null), +('16', '16', '528', null), +('16', '16', '10890', null), +('16', '16', '988', null), +('16', '16', '6346', null), +('16', '16', '25235', null), +('16', '16', '25384', null), +('16', '16', '25596', null), +('16', '16', '10955', null), +('16', '16', '10909', null), +('16', '16', '25380', null), +('16', '16', '10912', null), +('16', '16', '25308', null), +('16', '16', '25433', null), +('16', '16', '552', null), +('16', '16', '1706', null), +('16', '16', '25213', null), +('16', '16', '25392', null), +('16', '16', '39374', null), +('16', '16', '32999', null), +('16', '16', '32996', null), +('16', '16', '32546', null), +('16', '16', '34433', null), +('16', '16', '33076', null), +('16', '16', '32375', null), +('128', '16', '25389', null), +('128', '16', '25364', null), +('128', '16', '25368', null), +('128', '16', '25218', null), +('128', '16', '25429', null), +('128', '16', '25222', null), +('128', '16', '25375', null), +('128', '16', '25435', null), +('128', '16', '25431', null), +('128', '16', '528', null), +('128', '16', '10890', null), +('128', '16', '988', null), +('128', '16', '6346', null), +('128', '16', '25235', null), +('128', '16', '25384', null), +('128', '16', '25596', null), +('128', '16', '10955', null), +('128', '16', '10909', null), +('128', '16', '25380', null), +('128', '16', '10912', null), +('128', '16', '25308', null), +('128', '16', '25433', null), +('128', '16', '552', null), +('128', '16', '1706', null), +('128', '16', '25213', null), +('128', '16', '25392', null), +('128', '16', '39374', null), +('128', '16', '32999', null), +('128', '16', '32996', null), +('128', '16', '32546', null), +('128', '16', '34433', null), +('128', '16', '33076', null), +('128', '16', '32375', null), +('512', '16', '25389', null), +('512', '16', '25364', null), +('512', '16', '25368', null), +('512', '16', '25218', null), +('512', '16', '25429', null), +('512', '16', '25222', null), +('512', '16', '25375', null), +('512', '16', '25435', null), +('512', '16', '25431', null), +('512', '16', '528', null), +('512', '16', '10890', null), +('512', '16', '988', null), +('512', '16', '6346', null), +('512', '16', '25235', null), +('512', '16', '25384', null), +('512', '16', '25596', null), +('512', '16', '10955', null), +('512', '16', '10909', null), +('512', '16', '25380', null), +('512', '16', '10912', null), +('512', '16', '25308', null), +('512', '16', '25433', null), +('512', '16', '552', null), +('512', '16', '1706', null), +('512', '16', '25213', null), +('512', '16', '25392', null), +('512', '16', '39374', null), +('512', '16', '32999', null), +('512', '16', '32996', null), +('512', '16', '32546', null), +('512', '16', '34433', null), +('512', '16', '33076', null), +('512', '16', '32375', null), +('1024', '16', '25389', null), +('1024', '16', '25364', null), +('1024', '16', '25368', null), +('1024', '16', '25218', null), +('1024', '16', '25429', null), +('1024', '16', '25222', null), +('1024', '16', '25375', null), +('1024', '16', '25435', null), +('1024', '16', '25431', null), +('1024', '16', '528', null), +('1024', '16', '10890', null), +('1024', '16', '988', null), +('1024', '16', '6346', null), +('1024', '16', '25235', null), +('1024', '16', '25384', null), +('1024', '16', '25596', null), +('1024', '16', '10955', null), +('1024', '16', '10909', null), +('1024', '16', '25380', null), +('1024', '16', '10912', null), +('1024', '16', '25308', null), +('1024', '16', '25433', null), +('1024', '16', '552', null), +('1024', '16', '1706', null), +('1024', '16', '25213', null), +('1024', '16', '25392', null), +('1024', '16', '39374', null), +('1024', '16', '32999', null), +('1024', '16', '32996', null), +('1024', '16', '32546', null), +('1024', '16', '34433', null), +('1024', '16', '33076', null), +('1024', '16', '32375', null), +('2', '64', '25396', null), +('2', '64', '25449', null), +('2', '64', '25485', null), +('2', '64', '25454', null), +('2', '64', '25509', null), +('2', '64', '2484', null), +('2', '64', '25472', null), +('2', '64', '25525', null), +('2', '64', '25457', null), +('2', '64', '25489', null), +('2', '64', '25533', null), +('2', '64', '25528', null), +('2', '64', '20777', null), +('2', '64', '25547', null), +('2', '64', '8012', null), +('2', '64', '526', null), +('2', '64', '8143', null), +('2', '64', '25464', null), +('2', '64', '25500', null), +('2', '64', '2645', null), +('2', '64', '25567', null), +('2', '64', '25420', null), +('2', '64', '2870', null), +('2', '64', '8166', null), +('2', '64', '131', null), +('2', '64', '25560', null), +('2', '64', '6196', null), +('2', '64', '25552', null), +('2', '64', '25570', null), +('2', '64', '25563', null), +('2', '64', '25557', null), +('2', '64', '546', null), +('2', '64', '556', null), +('2', '64', '8177', null), +('2', '64', '25574', null), +('2', '64', '36936', null), +('2', '64', '25505', null), +('2', '64', '421', null), +('2', '64', '25587', null), +('2', '64', '6495', null), +('2', '64', '25577', null), +('2', '64', '8170', null), +('2', '64', '25423', null), +('2', '64', '25359', null), +('2', '64', '25908', null), +('2', '64', '33736', null), +('2', '64', '3738', null), +('2', '64', '2062', null), +('2', '64', '2894', null), +('2', '64', '2825', null), +('32', '64', '25396', null), +('32', '64', '25449', null), +('32', '64', '25485', null), +('32', '64', '25454', null), +('32', '64', '25509', null), +('32', '64', '2484', null), +('32', '64', '25472', null), +('32', '64', '25525', null), +('32', '64', '25457', null), +('32', '64', '25489', null), +('32', '64', '25533', null), +('32', '64', '25528', null), +('32', '64', '20777', null), +('32', '64', '25547', null), +('32', '64', '8012', null), +('32', '64', '526', null), +('32', '64', '8143', null), +('32', '64', '25464', null), +('32', '64', '25500', null), +('32', '64', '2645', null), +('32', '64', '25567', null), +('32', '64', '25420', null), +('32', '64', '2870', null), +('32', '64', '8166', null), +('32', '64', '131', null), +('32', '64', '25560', null), +('32', '64', '6196', null), +('32', '64', '25552', null), +('32', '64', '25570', null), +('32', '64', '25563', null), +('32', '64', '25557', null), +('32', '64', '546', null), +('32', '64', '556', null), +('32', '64', '8177', null), +('32', '64', '25574', null), +('32', '64', '36936', null), +('32', '64', '25505', null), +('32', '64', '421', null), +('32', '64', '25587', null), +('32', '64', '6495', null), +('32', '64', '25577', null), +('32', '64', '8170', null), +('32', '64', '25423', null), +('32', '64', '25359', null), +('32', '64', '25908', null), +('32', '64', '33736', null), +('32', '64', '3738', null), +('32', '64', '2062', null), +('32', '64', '2894', null), +('32', '64', '2825', null), +('128', '64', '25396', null), +('128', '64', '25449', null), +('128', '64', '25485', null), +('128', '64', '25454', null), +('128', '64', '25509', null), +('128', '64', '2484', null), +('128', '64', '25472', null), +('128', '64', '25525', null), +('128', '64', '25457', null), +('128', '64', '25489', null), +('128', '64', '25533', null), +('128', '64', '25528', null), +('128', '64', '20777', null), +('128', '64', '25547', null), +('128', '64', '8012', null), +('128', '64', '526', null), +('128', '64', '8143', null), +('128', '64', '25464', null), +('128', '64', '25500', null), +('128', '64', '2645', null), +('128', '64', '25567', null), +('128', '64', '25420', null), +('128', '64', '2870', null), +('128', '64', '8166', null), +('128', '64', '131', null), +('128', '64', '25560', null), +('128', '64', '6196', null), +('128', '64', '25552', null), +('128', '64', '25570', null), +('128', '64', '25563', null), +('128', '64', '25557', null), +('128', '64', '546', null), +('128', '64', '556', null), +('128', '64', '8177', null), +('128', '64', '25574', null), +('128', '64', '36936', null), +('128', '64', '25505', null), +('128', '64', '421', null), +('128', '64', '25587', null), +('128', '64', '6495', null), +('128', '64', '25577', null), +('128', '64', '8170', null), +('128', '64', '25423', null), +('128', '64', '25359', null), +('128', '64', '25908', null), +('128', '64', '33736', null), +('128', '64', '3738', null), +('128', '64', '2062', null), +('128', '64', '2894', null), +('128', '64', '2825', null), +('1024', '64', '25396', null), +('1024', '64', '25449', null), +('1024', '64', '25485', null), +('1024', '64', '25454', null), +('1024', '64', '25509', null), +('1024', '64', '2484', null), +('1024', '64', '25472', null), +('1024', '64', '25525', null), +('1024', '64', '25457', null), +('1024', '64', '25489', null), +('1024', '64', '25533', null), +('1024', '64', '25528', null), +('1024', '64', '20777', null), +('1024', '64', '25547', null), +('1024', '64', '8012', null), +('1024', '64', '526', null), +('1024', '64', '8143', null), +('1024', '64', '25464', null), +('1024', '64', '25500', null), +('1024', '64', '2645', null), +('1024', '64', '25567', null), +('1024', '64', '25420', null), +('1024', '64', '2870', null), +('1024', '64', '8166', null), +('1024', '64', '131', null), +('1024', '64', '25560', null), +('1024', '64', '6196', null), +('1024', '64', '25552', null), +('1024', '64', '25570', null), +('1024', '64', '25563', null), +('1024', '64', '25557', null), +('1024', '64', '546', null), +('1024', '64', '556', null), +('1024', '64', '8177', null), +('1024', '64', '25574', null), +('1024', '64', '36936', null), +('1024', '64', '25505', null), +('1024', '64', '421', null), +('1024', '64', '25587', null), +('1024', '64', '6495', null), +('1024', '64', '25577', null), +('1024', '64', '8170', null), +('1024', '64', '25423', null), +('1024', '64', '25359', null), +('1024', '64', '25908', null), +('1024', '64', '33736', null), +('1024', '64', '3738', null), +('1024', '64', '2062', null), +('1024', '64', '2894', null), +('1024', '64', '32182', null), +('2', '4', '674', null), +('2', '4', '8737', null), +('4', '4', '674', null), +('4', '4', '8737', null), +('8', '4', '674', null), +('8', '4', '8737', null), +('32', '4', '674', null), +('32', '4', '8737', null), +('128', '4', '674', null), +('128', '4', '8737', null), +('512', '4', '674', null), +('512', '4', '8737', null), +('1024', '4', '674', null), +('1024', '4', '8737', null), +('1', '2', '750', null), +('1', '2', '3127', null), +('4', '2', '750', null), +('4', '2', '3127', null), +('512', '2', '750', null), +('512', '2', '3127', null), +('1024', '2', '750', null), +('1024', '2', '3127', null), +('2', '64', '25442', null), +('2', '64', '8737', null), +('2', '64', '20608', null), +('32', '64', '25442', null), +('32', '64', '8737', null), +('32', '64', '20608', null), +('128', '64', '25442', null), +('128', '64', '8737', null), +('128', '64', '20608', null), +('1024', '64', '25442', null), +('1024', '64', '8737', null), +('1024', '64', '20608', null), +('1', '128', '27087', null), +('16', '128', '27087', null), +('64', '128', '27087', null), +('128', '128', '27087', null), +('512', '128', '27087', null), +('1024', '128', '27087', null), +('1', '8', '8643', null), +('1', '8', '3127', null), +('1', '8', '674', null), +('2', '8', '8643', null), +('2', '8', '3127', null), +('2', '8', '674', null), +('4', '8', '8643', null), +('4', '8', '3127', null), +('4', '8', '674', null), +('8', '8', '8643', null), +('8', '8', '3127', null), +('8', '8', '674', null), +('16', '8', '8643', null), +('16', '8', '3127', null), +('16', '8', '674', null), +('64', '8', '8643', null), +('64', '8', '3127', null), +('64', '8', '674', null), +('128', '8', '8643', null), +('128', '8', '3127', null), +('128', '8', '674', null), +('512', '8', '8643', null), +('512', '8', '3127', null), +('512', '8', '674', null), +('1', '1', '25212', null), +('1', '1', '674', null), +('1', '1', '750', null), +('1', '1', '12678', null), +('2', '1', '25212', null), +('2', '1', '674', null), +('2', '1', '750', null), +('2', '1', '12678', null), +('4', '1', '25212', null), +('4', '1', '674', null), +('4', '1', '750', null), +('4', '1', '12678', null), +('8', '1', '25212', null), +('8', '1', '674', null), +('8', '1', '750', null), +('8', '1', '12678', null), +('16', '1', '25212', null), +('16', '1', '674', null), +('16', '1', '750', null), +('16', '1', '12678', null), +('32', '1', '25212', null), +('32', '1', '674', null), +('32', '1', '750', null), +('32', '1', '12678', null), +('64', '1', '25212', null), +('64', '1', '674', null), +('64', '1', '750', null), +('64', '1', '12678', null), +('128', '1', '25212', null), +('128', '1', '674', null), +('128', '1', '750', null), +('128', '1', '12678', null), +('1024', '1', '25212', null), +('1024', '1', '674', null), +('1024', '1', '750', null), +('1024', '1', '12678', null), +('2', '4', '5149', null), +('4', '4', '5149', null), +('8', '4', '5149', null), +('32', '4', '5149', null), +('128', '4', '5149', null), +('512', '4', '5149', null), +('1024', '4', '5149', null), +('1', '2', '23214', null), +('4', '2', '23214', null), +('512', '2', '34767', null), +('1024', '2', '23214', null), +('1', '256', '23161', null), +('2', '256', '23161', null), +('16', '256', '23161', null), +('64', '256', '23161', null), +('512', '256', '23161', null), +('1024', '256', '23161', null), +('1', '256', '688', null), +('2', '256', '688', null), +('16', '256', '688', null), +('64', '256', '688', null), +('512', '256', '688', null), +('1024', '256', '688', null), +('1', '256', '697', null), +('2', '256', '697', null), +('16', '256', '697', null), +('64', '256', '697', null), +('512', '256', '697', null), +('1024', '256', '697', null), +('1', '256', '712', null), +('2', '256', '712', null), +('16', '256', '712', null), +('64', '256', '712', null), +('512', '256', '712', null), +('1024', '256', '712', null), +('1', '256', '691', null), +('2', '256', '691', null), +('16', '256', '691', null), +('64', '256', '691', null), +('512', '256', '691', null), +('1024', '256', '691', null), +('32', '1024', '20719', null), +('8', '1024', '20719', null), +('1', '256', '126', null), +('2', '256', '126', null), +('16', '256', '126', null), +('64', '256', '126', null), +('512', '256', '126', null), +('1', '2', '31801', null), +('4', '2', '31801', null), +('1024', '2', '31801', null), +('1', '8', '3776', null), +('1', '8', '9186', null), +('1', '8', '21927', null), +('1', '8', '22054', null), +('1', '8', '22055', null), +('1', '8', '2836', null), +('1', '8', '1860', null), +('2', '8', '3776', null), +('2', '8', '9186', null), +('2', '8', '21927', null), +('2', '8', '22054', null), +('2', '8', '22055', null), +('2', '8', '2836', null), +('2', '8', '1860', null), +('4', '8', '3776', null), +('4', '8', '9186', null), +('4', '8', '21927', null), +('4', '8', '22054', null), +('4', '8', '22055', null), +('4', '8', '2836', null), +('4', '8', '1860', null), +('8', '8', '3776', null), +('8', '8', '9186', null), +('8', '8', '21927', null), +('8', '8', '22054', null), +('8', '8', '22055', null), +('8', '8', '2836', null), +('8', '8', '1860', null), +('16', '8', '3776', null), +('16', '8', '9186', null), +('16', '8', '21927', null), +('16', '8', '22054', null), +('16', '8', '22055', null), +('16', '8', '2836', null), +('16', '8', '1860', null), +('64', '8', '3776', null), +('64', '8', '9186', null), +('64', '8', '21927', null), +('64', '8', '22054', null), +('64', '8', '22055', null), +('64', '8', '2836', null), +('64', '8', '1860', null), +('128', '8', '3776', null), +('128', '8', '9186', null), +('128', '8', '21927', null), +('128', '8', '22054', null), +('128', '8', '22055', null), +('128', '8', '2836', null), +('128', '8', '1860', null), +('512', '8', '3776', null), +('512', '8', '9186', null), +('512', '8', '21927', null), +('512', '8', '22054', null), +('512', '8', '22055', null), +('512', '8', '2836', null), +('512', '8', '1860', null), +('1', '16', '25441', null), +('1', '16', '25312', null), +('4', '16', '25312', null), +('8', '16', '25312', null), +('16', '16', '25312', null), +('128', '16', '25312', null), +('1024', '16', '25312', null), +('512', '16', '25312', null), +('1', '16', '25437', null), +('4', '16', '25437', null), +('2', '4', '3127', null), +('4', '4', '3127', null), +('8', '4', '3127', null), +('32', '4', '3127', null), +('128', '4', '3127', null), +('512', '4', '3127', null), +('1024', '4', '3127', null), +('512', '1', '78', 'Heroic Strike'), +('512', '1', '81', 'Dodge'), +('512', '1', '107', 'Block'), +('512', '1', '196', 'One-Handed Axes'), +('512', '1', '197', 'Two-Handed Axes'), +('512', '1', '201', 'One-Handed Swords'), +('512', '1', '203', 'Unarmed'), +('512', '1', '204', 'Defense'), +('512', '1', '522', 'SPELLDEFENSE(DND)'), +('512', '1', '669', 'Language Orcish'), +('512', '1', '2382', 'Generic'), +('512', '1', '2457', 'Battle Stance'), +('512', '1', '2479', 'Honorless Target'), +('512', '1', '3050', 'Detect'), +('512', '1', '3365', 'Opening'), +('512', '1', '5301', 'Defensive State(DND)'), +('512', '1', '6233', 'Closing'), +('512', '1', '6246', 'Closing'), +('512', '1', '6247', 'Opening'), +('512', '1', '6477', 'Opening'), +('512', '1', '6478', 'Opening'), +('512', '1', '6603', 'Attack'), +('512', '1', '7266', 'Duel'), +('512', '1', '7267', 'Grovel'), +('512', '1', '7355', 'Stuck'), +('512', '1', '7376', 'Defensive Stance Passive'), +('512', '1', '7381', 'Berserker Stance Passive'), +('512', '1', '8386', 'Attacking'), +('512', '1', '8737', 'Mail'), +('512', '1', '9077', 'Leather'), +('512', '1', '9078', 'Cloth'), +('512', '1', '9116', 'Shield'), +('512', '1', '9125', 'Generic'), +('512', '1', '21156', 'Battle Stance Passive'), +('512', '1', '21651', 'Opening'), +('512', '1', '21652', 'Closing'), +('512', '1', '22027', 'Remove Insignia'), +('512', '1', '22810', 'Opening - No Text'), +('512', '1', '32215', 'Victorious State'), +('512', '1', '202', 'Two-Handed Swords'), +('512', '1', '813', 'Language Thalassian'), +('512', '1', '822', 'Magic Resistance'), +('512', '1', '28730', 'Arcane Torrent'), +('512', '1', '28877', 'Arcane Affinity'), +('512', '1', '2048', null), +('512', '1', '30324', null), +('512', '1', '11578', null), +('512', '1', '25208', null), +('512', '1', '25264', null), +('512', '1', '2687', null), +('512', '1', '71', null), +('512', '1', '25225', null), +('512', '1', '355', null), +('512', '1', '11585', null), +('512', '1', '29704', null), +('512', '1', '25203', null), +('512', '1', '30357', null), +('512', '1', '25266', null), +('512', '1', '2565', null), +('512', '1', '676', null), +('512', '1', '25231', null), +('512', '1', '20230', null), +('512', '1', '5246', null), +('512', '1', '25236', null), +('512', '1', '1161', null), +('512', '1', '871', null), +('512', '1', '2458', null), +('512', '1', '25275', null), +('512', '1', '25242', null), +('512', '1', '18499', null), +('512', '1', '1680', null), +('512', '1', '6554', null), +('512', '1', '1719', null), +('512', '1', '34428', null), +('512', '1', '23920', null), +('512', '1', '469', null), +('512', '1', '3411', null), +('512', '64', '81', 'Dodge'), +('512', '64', '107', 'Block'), +('512', '64', '198', 'One-Handed Maces'), +('512', '64', '203', 'Unarmed'), +('512', '64', '204', 'Defense'), +('512', '64', '227', 'Staves'), +('512', '64', '331', 'Healing Wave'), +('512', '64', '403', 'Lightning Bolt'), +('512', '64', '522', 'SPELLDEFENSE(DND)'), +('512', '64', '669', 'Language Orcish'), +('512', '64', '2382', 'Generic'), +('512', '64', '2479', 'Honorless Target'), +('512', '64', '3050', 'Detect'), +('512', '64', '3365', 'Opening'), +('512', '64', '6233', 'Closing'), +('512', '64', '6246', 'Closing'), +('512', '64', '6247', 'Opening'), +('512', '64', '6477', 'Opening'), +('512', '64', '6478', 'Opening'), +('512', '64', '6603', 'Attack'), +('512', '64', '7266', 'Duel'), +('512', '64', '7267', 'Grovel'), +('512', '64', '7355', 'Stuck'), +('512', '64', '8386', 'Attacking'), +('512', '64', '9077', 'Leather'), +('512', '64', '9078', 'Cloth'), +('512', '64', '9116', 'Shield'), +('512', '64', '9125', 'Generic'), +('512', '64', '21651', 'Opening'), +('512', '64', '21652', 'Closing'), +('512', '64', '22027', 'Remove Insignia'), +('512', '64', '22810', 'Opening - No Text'), +('512', '64', '27763', 'Totem'), +('512', '64', '25396', null), +('512', '64', '25449', null), +('512', '64', '25485', null), +('512', '64', '25454', null), +('512', '64', '25509', null), +('512', '64', '2484', null), +('512', '64', '25472', null), +('512', '64', '25525', null), +('512', '64', '25457', null), +('512', '64', '25489', null), +('512', '64', '25533', null), +('512', '64', '25528', null), +('512', '64', '20777', null), +('512', '64', '25547', null), +('512', '64', '8012', null), +('512', '64', '526', null), +('512', '64', '8143', null), +('512', '64', '25464', null), +('512', '64', '25500', null), +('512', '64', '2645', null), +('512', '64', '25567', null), +('512', '64', '25420', null), +('512', '64', '2870', null), +('512', '64', '8166', null), +('512', '64', '131', null), +('512', '64', '25560', null), +('512', '64', '6196', null), +('512', '64', '25552', null), +('512', '64', '25570', null), +('512', '64', '25563', null), +('512', '64', '25557', null), +('512', '64', '546', null), +('512', '64', '556', null), +('512', '64', '8177', null), +('512', '64', '25574', null), +('512', '64', '36936', null), +('512', '64', '25505', null), +('512', '64', '421', null), +('512', '64', '25587', null), +('512', '64', '6495', null), +('512', '64', '25577', null), +('512', '64', '8170', null), +('512', '64', '25423', null), +('512', '64', '25359', null), +('512', '64', '25908', null), +('512', '64', '33736', null), +('512', '64', '3738', null), +('512', '64', '2062', null), +('512', '64', '2894', null), +('512', '64', '2825', null), +('512', '64', '25442', null), +('512', '64', '8737', null), +('512', '64', '20608', null), +('512', '64', '813', 'Language Thalassian'), +('512', '64', '822', 'Magic Resistance'), +('512', '64', '28730', 'Arcane Torrent'), +('512', '64', '28877', 'Arcane Affinity'), +('512', '1024', '20719', null), +('512', '1024', '26979', null), +('512', '1024', '26990', null), +('512', '1024', '26985', null), +('512', '1024', '26988', null), +('512', '1024', '26982', null), +('512', '1024', '26992', null), +('512', '1024', '26989', null), +('512', '1024', '26998', null), +('512', '1024', '6795', null), +('512', '1024', '26996', null), +('512', '1024', '18960', null), +('512', '1024', '9634', null), +('512', '1024', '768', null), +('512', '1024', '783', null), +('512', '1024', '1066', null), +('512', '1024', '40120', null), +('512', '1024', '5229', null), +('512', '1024', '26980', null), +('512', '1024', '8983', null), +('512', '1024', '8946', null), +('512', '1024', '26997', null), +('512', '1024', '26993', null), +('512', '1024', '18658', null), +('512', '1024', '27000', null), +('512', '1024', '9913', null), +('512', '1024', '26994', null), +('512', '1024', '27008', null), +('512', '1024', '26986', null), +('512', '1024', '27002', null), +('512', '1024', '26995', null), +('512', '1024', '27003', null), +('512', '1024', '2782', null), +('512', '1024', '9846', null), +('512', '1024', '2893', null), +('512', '1024', '33357', null), +('512', '1024', '5209', null), +('512', '1024', '27004', null), +('512', '1024', '26983', null), +('512', '1024', '24248', null), +('512', '1024', '27005', null), +('512', '1024', '5225', null), +('512', '1024', '26999', null), +('512', '1024', '27012', null), +('512', '1024', '27006', null), +('512', '1024', '29166', null), +('512', '1024', '22812', null), +('512', '1024', '26991', null), +('512', '1024', '22570', null), +('512', '1024', '33763', null), +('512', '1024', '33745', null), +('512', '1024', '33786', null), +('512', '1024', '813', 'Language Thalassian'), +('512', '1024', '822', 'Magic Resistance'), +('512', '1024', '28730', 'Arcane Torrent'), +('512', '1024', '28877', 'Arcane Affinity'), +('512', '1024', '81', 'Dodge'), +('512', '1024', '198', 'One-Handed Maces'), +('512', '1024', '203', 'Unarmed'), +('512', '1024', '204', 'Defense'), +('512', '1024', '227', 'Staves'), +('512', '1024', '522', 'SPELLDEFENSE(DND)'), +('512', '1024', '669', 'Language Orcish'), +('512', '1024', '1178', 'Bear Form(Passive)'), +('512', '1024', '2382', 'Generic'), +('512', '1024', '2479', 'Honorless Target'), +('512', '1024', '3025', 'Cat Form(Passive)'), +('512', '1024', '3050', 'Detect'), +('512', '1024', '3365', 'Opening'), +('512', '1024', '5176', 'Wrath'), +('512', '1024', '5185', 'Healing Touch'), +('512', '1024', '5419', 'Travel Form(Passive)'), +('512', '1024', '5420', 'Tree of Life'), +('512', '1024', '5421', 'Aquatic Form(Passive)'), +('512', '1024', '6233', 'Closing'), +('512', '1024', '6246', 'Closing'), +('512', '1024', '6247', 'Opening'), +('512', '1024', '6477', 'Opening'), +('512', '1024', '6478', 'Opening'), +('512', '1024', '6603', 'Attack'), +('512', '1024', '7266', 'Duel'), +('512', '1024', '7267', 'Grovel'), +('512', '1024', '7355', 'Stuck'), +('512', '1024', '8386', 'Attacking'), +('512', '1024', '9077', 'Leather'), +('512', '1024', '9078', 'Cloth'), +('512', '1024', '9125', 'Generic'), +('512', '1024', '9635', 'Dire Bear Form(Passive)'), +('512', '1024', '21178', 'Bear Form(Passive2)'), +('512', '1024', '21651', 'Opening'), +('512', '1024', '21652', 'Closing'), +('512', '1024', '22027', 'Remove Insignia'), +('512', '1024', '22810', 'Opening - No Text'), +('512', '1024', '24905', 'Moonkin Form(Passive)'), +('512', '1024', '27764', 'Fetish'), +('512', '1024', '33948', 'Flight Form(Passive)'), +('512', '1024', '34123', 'Tree of Life(Passive)'), +('512', '1024', '40121', 'Swift Flight Form(Passive)'), +('4', '64', '672', 'Language Dwarven'), +('4', '64', '2481', 'Find Treasure'), +('4', '64', '20594', 'Stoneform'), +('4', '64', '20595', 'Gun Specialization'), +('4', '64', '20596', 'Frost Resistance'), +('4', '64', '668', 'Language Common'), +('4', '64', '81', 'Dodge'), +('4', '64', '107', 'Block'), +('4', '64', '198', 'One-Handed Maces'), +('4', '64', '203', 'Unarmed'), +('4', '64', '204', 'Defense'), +('4', '64', '227', 'Staves'), +('4', '64', '331', 'Healing Wave'), +('4', '64', '403', 'Lightning Bolt'), +('4', '64', '522', 'SPELLDEFENSE(DND)'), +('4', '64', '2382', 'Generic'), +('4', '64', '2479', 'Honorless Target'), +('4', '64', '3050', 'Detect'), +('4', '64', '3365', 'Opening'), +('4', '64', '6233', 'Closing'), +('4', '64', '6246', 'Closing'), +('4', '64', '6247', 'Opening'), +('4', '64', '6477', 'Opening'), +('4', '64', '6478', 'Opening'), +('4', '64', '6603', 'Attack'), +('4', '64', '7266', 'Duel'), +('4', '64', '7267', 'Grovel'), +('4', '64', '7355', 'Stuck'), +('4', '64', '8386', 'Attacking'), +('4', '64', '9077', 'Leather'), +('4', '64', '9078', 'Cloth'), +('4', '64', '9116', 'Shield'), +('4', '64', '9125', 'Generic'), +('4', '64', '21651', 'Opening'), +('4', '64', '21652', 'Closing'), +('4', '64', '22027', 'Remove Insignia'), +('4', '64', '22810', 'Opening - No Text'), +('4', '64', '27763', 'Totem'), +('4', '64', '25396', null), +('4', '64', '25449', null), +('4', '64', '25485', null), +('4', '64', '25454', null), +('4', '64', '25509', null), +('4', '64', '2484', null), +('4', '64', '25472', null), +('4', '64', '25525', null), +('4', '64', '25457', null), +('4', '64', '25489', null), +('4', '64', '25533', null), +('4', '64', '25528', null), +('4', '64', '20777', null), +('4', '64', '25547', null), +('4', '64', '8012', null), +('4', '64', '526', null), +('4', '64', '8143', null), +('4', '64', '25464', null), +('4', '64', '25500', null), +('4', '64', '2645', null), +('4', '64', '25567', null), +('4', '64', '25420', null), +('4', '64', '2870', null), +('4', '64', '8166', null), +('4', '64', '131', null), +('4', '64', '25560', null), +('4', '64', '6196', null), +('4', '64', '25552', null), +('4', '64', '25570', null), +('4', '64', '25563', null), +('4', '64', '25557', null), +('4', '64', '546', null), +('4', '64', '556', null), +('4', '64', '8177', null), +('4', '64', '25574', null), +('4', '64', '36936', null), +('4', '64', '25505', null), +('4', '64', '421', null), +('4', '64', '25587', null), +('4', '64', '6495', null), +('4', '64', '25577', null), +('4', '64', '8170', null), +('4', '64', '25423', null), +('4', '64', '25359', null), +('4', '64', '25908', null), +('4', '64', '33736', null), +('4', '64', '3738', null), +('4', '64', '2062', null), +('4', '64', '2894', null), +('4', '64', '2825', null), +('4', '128', '672', 'Language Dwarven'), +('4', '128', '2481', 'Find Treasure'), +('4', '128', '20594', 'Stoneform'), +('4', '128', '20595', 'Gun Specialization'), +('4', '128', '20596', 'Frost Resistance'), +('4', '128', '81', 'Dodge'), +('4', '128', '133', 'Fireball'), +('4', '128', '168', 'Frost Armor'), +('4', '128', '203', 'Unarmed'), +('4', '128', '204', 'Defense'), +('4', '128', '227', 'Staves'), +('4', '128', '522', 'SPELLDEFENSE(DND)'), +('4', '128', '668', 'Language Common'), +('4', '128', '2382', 'Generic'), +('4', '128', '2479', 'Honorless Target'), +('4', '128', '3050', 'Detect'), +('4', '128', '3365', 'Opening'), +('4', '128', '5009', 'Wands'), +('4', '128', '5019', 'Shoot'), +('4', '128', '6233', 'Closing'), +('4', '128', '6246', 'Closing'), +('4', '128', '6247', 'Opening'), +('4', '128', '6477', 'Opening'), +('4', '128', '6478', 'Opening'), +('4', '128', '6603', 'Attack'), +('4', '128', '7266', 'Duel'), +('4', '128', '7267', 'Grovel'), +('4', '128', '7355', 'Stuck'), +('4', '128', '8386', 'Attacking'), +('4', '128', '9078', 'Cloth'), +('4', '128', '9125', 'Generic'), +('4', '128', '21651', 'Opening'), +('4', '128', '21652', 'Closing'), +('4', '128', '22027', 'Remove Insignia'), +('4', '128', '22810', 'Opening - No Text'), +('4', '128', '27126', null), +('4', '128', '27070', null), +('4', '128', '22018', null), +('4', '128', '27072', null), +('4', '128', '22019', null), +('4', '128', '27079', null), +('4', '128', '38704', null), +('4', '128', '28272', null), +('4', '128', '28271', null), +('4', '128', '12826', null), +('4', '128', '27088', null), +('4', '128', '33944', null), +('4', '128', '130', null), +('4', '128', '27082', null), +('4', '128', '27086', null), +('4', '128', '33946', null), +('4', '128', '475', null), +('4', '128', '1953', null), +('4', '128', '27085', null), +('4', '128', '12051', null), +('4', '128', '27128', null), +('4', '128', '27131', null), +('4', '128', '32796', null), +('4', '128', '27074', null), +('4', '128', '2139', null), +('4', '128', '27101', null), +('4', '128', '27124', null), +('4', '128', '45438', null), +('4', '128', '27125', null), +('4', '128', '27127', null), +('4', '128', '30482', null), +('4', '128', '30451', null), +('4', '128', '30455', null), +('4', '128', '66', null), +('4', '128', '43987', null), +('4', '128', '30449', null), +('4', '128', '27087', null), +('4', '256', '672', 'Language Dwarven'), +('4', '256', '2481', 'Find Treasure'), +('4', '256', '20594', 'Stoneform'), +('4', '256', '20595', 'Gun Specialization'), +('4', '256', '20596', 'Frost Resistance'), +('4', '256', '81', 'Dodge'), +('4', '256', '203', 'Unarmed'), +('4', '256', '204', 'Defense'), +('4', '256', '522', 'SPELLDEFENSE(DND)'), +('4', '256', '668', 'Language Common'), +('4', '256', '686', 'Shadow Bolt'), +('4', '256', '687', 'Demon Skin'), +('4', '256', '1180', 'Daggers'), +('4', '256', '2382', 'Generic'), +('4', '256', '2479', 'Honorless Target'), +('4', '256', '3050', 'Detect'), +('4', '256', '3365', 'Opening'), +('4', '256', '5009', 'Wands'), +('4', '256', '5019', 'Shoot'), +('4', '256', '6233', 'Closing'), +('4', '256', '6246', 'Closing'), +('4', '256', '6247', 'Opening'), +('4', '256', '6477', 'Opening'), +('4', '256', '6478', 'Opening'), +('4', '256', '6603', 'Attack'), +('4', '256', '7266', 'Duel'), +('4', '256', '7267', 'Grovel'), +('4', '256', '7355', 'Stuck'), +('4', '256', '8386', 'Attacking'), +('4', '256', '9078', 'Cloth'), +('4', '256', '9125', 'Generic'), +('4', '256', '21651', 'Opening'), +('4', '256', '21652', 'Closing'), +('4', '256', '22027', 'Remove Insignia'), +('4', '256', '22810', 'Opening - No Text'), +('4', '256', '27215', null), +('4', '256', '27209', null), +('4', '256', '27216', null), +('4', '256', '30909', null), +('4', '256', '27222', null), +('4', '256', '27218', null), +('4', '256', '6215', null), +('4', '256', '27230', null), +('4', '256', '27217', null), +('4', '256', '27259', null), +('4', '256', '27226', null), +('4', '256', '27220', null), +('4', '256', '5697', null), +('4', '256', '27238', null), +('4', '256', '30459', null), +('4', '256', '27260', null), +('4', '256', '27212', null), +('4', '256', '698', null), +('4', '256', '5500', null), +('4', '256', '30908', null), +('4', '256', '11719', null), +('4', '256', '132', null), +('4', '256', '18647', null), +('4', '256', '27213', null), +('4', '256', '11726', null), +('4', '256', '27228', null), +('4', '256', '28610', null), +('4', '256', '28172', null), +('4', '256', '27250', null), +('4', '256', '17928', null), +('4', '256', '27223', null), +('4', '256', '27229', null), +('4', '256', '30545', null), +('4', '256', '30910', null), +('4', '256', '18540', null), +('4', '256', '28189', null), +('4', '256', '32231', null), +('4', '256', '29858', null), +('4', '256', '29893', null), +('4', '256', '27243', null), +('4', '256', '23161', null), +('4', '256', '688', null), +('4', '256', '697', null), +('4', '256', '712', null), +('4', '256', '691', null), +('4', '256', '126', null), +('4', '1024', '672', 'Language Dwarven'), +('4', '1024', '2481', 'Find Treasure'), +('4', '1024', '20594', 'Stoneform'), +('4', '1024', '20595', 'Gun Specialization'), +('4', '1024', '20596', 'Frost Resistance'), +('4', '1024', '668', 'Language Common'), +('4', '1024', '81', 'Dodge'), +('4', '1024', '203', 'Unarmed'), +('4', '1024', '204', 'Defense'), +('4', '1024', '227', 'Staves'), +('4', '1024', '522', 'SPELLDEFENSE(DND)'), +('4', '1024', '1178', 'Bear Form(Passive)'), +('4', '1024', '1180', 'Daggers'), +('4', '1024', '2382', 'Generic'), +('4', '1024', '2479', 'Honorless Target'), +('4', '1024', '3025', 'Cat Form(Passive)'), +('4', '1024', '3050', 'Detect'), +('4', '1024', '3365', 'Opening'), +('4', '1024', '5176', 'Wrath'), +('4', '1024', '5185', 'Healing Touch'), +('4', '1024', '5419', 'Travel Form(Passive)'), +('4', '1024', '5420', 'Tree of Life'), +('4', '1024', '5421', 'Aquatic Form(Passive)'), +('4', '1024', '6233', 'Closing'), +('4', '1024', '6246', 'Closing'), +('4', '1024', '6247', 'Opening'), +('4', '1024', '6477', 'Opening'), +('4', '1024', '6478', 'Opening'), +('4', '1024', '6603', 'Attack'), +('4', '1024', '7266', 'Duel'), +('4', '1024', '7267', 'Grovel'), +('4', '1024', '7355', 'Stuck'), +('4', '1024', '8386', 'Attacking'), +('4', '1024', '9077', 'Leather'), +('4', '1024', '9078', 'Cloth'), +('4', '1024', '9125', 'Generic'), +('4', '1024', '9635', 'Dire Bear Form(Passive)'), +('4', '1024', '21178', 'Bear Form(Passive2)'), +('4', '1024', '21651', 'Opening'), +('4', '1024', '21652', 'Closing'), +('4', '1024', '22027', 'Remove Insignia'), +('4', '1024', '22810', 'Opening - No Text'), +('4', '1024', '24905', 'Moonkin Form(Passive)'), +('4', '1024', '27764', 'Fetish'), +('4', '1024', '33948', 'Flight Form(Passive)'), +('4', '1024', '34123', 'Tree of Life(Passive)'), +('4', '1024', '40121', 'Swift Flight Form(Passive)'), +('4', '1024', '26979', null), +('4', '1024', '26990', null), +('4', '1024', '26985', null), +('4', '1024', '26988', null), +('4', '1024', '26982', null), +('4', '1024', '26992', null), +('4', '1024', '26989', null), +('4', '1024', '26998', null), +('4', '1024', '6795', null), +('4', '1024', '26996', null), +('4', '1024', '18960', null), +('4', '1024', '9634', null), +('4', '1024', '768', null), +('4', '1024', '783', null), +('4', '1024', '1066', null), +('4', '1024', '40120', null), +('4', '1024', '5229', null), +('4', '1024', '26980', null), +('4', '1024', '8983', null), +('4', '1024', '8946', null), +('4', '1024', '26997', null), +('4', '1024', '26993', null), +('4', '1024', '18658', null), +('4', '1024', '27000', null), +('4', '1024', '9913', null), +('4', '1024', '26994', null), +('4', '1024', '27008', null), +('4', '1024', '26986', null), +('4', '1024', '27002', null), +('4', '1024', '26995', null), +('4', '1024', '27003', null), +('4', '1024', '2782', null), +('4', '1024', '9846', null), +('4', '1024', '2893', null), +('4', '1024', '33357', null), +('4', '1024', '5209', null), +('4', '1024', '27004', null), +('4', '1024', '26983', null), +('4', '1024', '24248', null), +('4', '1024', '27005', null), +('4', '1024', '5225', null), +('4', '1024', '26999', null), +('4', '1024', '27012', null), +('4', '1024', '27006', null), +('4', '1024', '29166', null), +('4', '1024', '22812', null), +('4', '1024', '26991', null), +('4', '1024', '22570', null), +('4', '1024', '33763', null), +('4', '1024', '33745', null), +('4', '1024', '33786', null), +('64', '2', '7340', 'Language Gnomish'), +('64', '2', '20589', 'Escape Artist'), +('64', '2', '20591', 'Expansive Mind'), +('64', '2', '20592', 'Arcane Resistance'), +('64', '2', '20593', 'Engineering Specialization'), +('64', '2', '81', 'Dodge'), +('64', '2', '107', 'Block'), +('64', '2', '201', 'One-Handed Swords'), +('64', '2', '198', 'One-Handed Maces'), +('64', '2', '199', 'Two-Handed Maces'), +('64', '2', '203', 'Unarmed'), +('64', '2', '204', 'Defense'), +('64', '2', '522', 'SPELLDEFENSE(DND)'), +('64', '2', '635', 'Holy Light'), +('64', '2', '668', 'Language Common'), +('64', '2', '2382', 'Generic'), +('64', '2', '2479', 'Honorless Target'), +('64', '2', '3050', 'Detect'), +('64', '2', '3365', 'Opening'), +('64', '2', '6233', 'Closing'), +('64', '2', '6246', 'Closing'), +('64', '2', '6247', 'Opening'), +('64', '2', '6477', 'Opening'), +('64', '2', '6478', 'Opening'), +('64', '2', '6603', 'Attack'), +('64', '2', '7266', 'Duel'), +('64', '2', '7267', 'Grovel'), +('64', '2', '7355', 'Stuck'), +('64', '2', '8386', 'Attacking'), +('64', '2', '8737', 'Mail'), +('64', '2', '9077', 'Leather'), +('64', '2', '9078', 'Cloth'), +('64', '2', '9116', 'Shield'), +('64', '2', '9125', 'Generic'), +('64', '2', '21084', 'Seal of Righteousness'), +('64', '2', '21651', 'Opening'), +('64', '2', '21652', 'Closing'), +('64', '2', '22027', 'Remove Insignia'), +('64', '2', '22810', 'Opening - No Text'), +('64', '2', '27762', 'Libram'), +('64', '2', '27149', null), +('64', '2', '27136', null), +('64', '2', '27155', null), +('64', '2', '27140', null), +('64', '2', '20271', null), +('64', '2', '27158', null), +('64', '2', '10308', null), +('64', '2', '10278', null), +('64', '2', '27154', null), +('64', '2', '20773', null), +('64', '2', '27142', null), +('64', '2', '31789', null), +('64', '2', '27150', null), +('64', '2', '25780', null), +('64', '2', '1044', null), +('64', '2', '33776', null), +('64', '2', '27173', null), +('64', '2', '27138', null), +('64', '2', '27137', null), +('64', '2', '5502', null), +('64', '2', '19746', null), +('64', '2', '31895', null), +('64', '2', '5627', null), +('64', '2', '1038', null), +('64', '2', '27151', null), +('64', '2', '19752', null), +('64', '2', '27160', null), +('64', '2', '27152', null), +('64', '2', '1020', null), +('64', '2', '27153', null), +('64', '2', '27166', null), +('64', '2', '27144', null), +('64', '2', '4987', null), +('64', '2', '27180', null), +('64', '2', '27148', null), +('64', '2', '27139', null), +('64', '2', '27141', null), +('64', '2', '10326', null), +('64', '2', '27143', null), +('64', '2', '25898', null), +('64', '2', '27145', null), +('64', '2', '25895', null), +('64', '2', '32223', null), +('64', '2', '27169', null), +('64', '2', '31884', null), +('64', '2', '750', null), +('64', '2', '3127', null), +('64', '2', '23214', null), +('64', '2', '31801', null), +('64', '4', '7340', 'Language Gnomish'), +('64', '4', '20589', 'Escape Artist'), +('64', '4', '20591', 'Expansive Mind'), +('64', '4', '20592', 'Arcane Resistance'), +('64', '4', '20593', 'Engineering Specialization'), +('64', '4', '668', 'Language Common'), +('64', '4', '75', 'Auto Shot'), +('64', '4', '81', 'Dodge'), +('64', '4', '196', 'One-Handed Axes'), +('64', '4', '203', 'Unarmed'), +('64', '4', '204', 'Defense'), +('64', '4', '264', 'Bows'), +('64', '4', '266', 'Guns'), +('64', '4', '522', 'SPELLDEFENSE(DND)'), +('64', '4', '2382', 'Generic'), +('64', '4', '2479', 'Honorless Target'), +('64', '4', '2973', 'Raptor Strike'), +('64', '4', '3050', 'Detect'), +('64', '4', '3365', 'Opening'), +('64', '4', '6233', 'Closing'), +('64', '4', '6246', 'Closing'), +('64', '4', '6247', 'Opening'), +('64', '4', '6477', 'Opening'), +('64', '4', '6478', 'Opening'), +('64', '4', '6603', 'Attack'), +('64', '4', '7266', 'Duel'), +('64', '4', '7267', 'Grovel'), +('64', '4', '7355', 'Stuck'), +('64', '4', '8386', 'Attacking'), +('64', '4', '9077', 'Leather'), +('64', '4', '9078', 'Cloth'), +('64', '4', '9125', 'Generic'), +('64', '4', '13358', 'Defensive State(DND)'), +('64', '4', '21651', 'Opening'), +('64', '4', '21652', 'Closing'), +('64', '4', '22027', 'Remove Insignia'), +('64', '4', '22810', 'Opening - No Text'), +('64', '4', '24949', 'Defensive State 2(DND)'), +('64', '4', '34082', 'Advantaged State(DND)'), +('64', '4', '27014', null), +('64', '4', '1494', null), +('64', '4', '13163', null), +('64', '4', '27016', null), +('64', '4', '27019', null), +('64', '4', '14325', null), +('64', '4', '5116', null), +('64', '4', '27044', null), +('64', '4', '883', null), +('64', '4', '2641', null), +('64', '4', '6991', null), +('64', '4', '982', null), +('64', '4', '1515', null), +('64', '4', '19883', null), +('64', '4', '27020', null), +('64', '4', '27046', null), +('64', '4', '14268', null), +('64', '4', '6197', null), +('64', '4', '1002', null), +('64', '4', '14327', null), +('64', '4', '27023', null), +('64', '4', '36916', null), +('64', '4', '27021', null), +('64', '4', '19884', null), +('64', '4', '5118', null), +('64', '4', '27015', null), +('64', '4', '14311', null), +('64', '4', '3043', null), +('64', '4', '1462', null), +('64', '4', '19885', null), +('64', '4', '3045', null), +('64', '4', '19880', null), +('64', '4', '13809', null), +('64', '4', '13161', null), +('64', '4', '5384', null), +('64', '4', '1543', null), +('64', '4', '19878', null), +('64', '4', '27025', null), +('64', '4', '27018', null), +('64', '4', '13159', null), +('64', '4', '19882', null), +('64', '4', '27022', null), +('64', '4', '27045', null), +('64', '4', '19879', null), +('64', '4', '19801', null), +('64', '4', '34120', null), +('64', '4', '34074', null), +('64', '4', '34026', null), +('64', '4', '34600', null), +('64', '4', '34477', null), +('64', '16', '7340', 'Language Gnomish'), +('64', '16', '20589', 'Escape Artist'), +('64', '16', '20591', 'Expansive Mind'), +('64', '16', '20592', 'Arcane Resistance'), +('64', '16', '20593', 'Engineering Specialization'), +('64', '16', '81', 'Dodge'), +('64', '16', '277', 'Staves'), +('64', '16', '203', 'Unarmed'), +('64', '16', '204', 'Defense'), +('64', '16', '522', 'SPELLDEFENSE(DND)'), +('64', '16', '585', 'Smite'), +('64', '16', '668', 'Language Common'), +('64', '16', '2050', 'Lesser Heal'), +('64', '16', '2382', 'Generic'), +('64', '16', '2479', 'Honorless Target'), +('64', '16', '3050', 'Detect'), +('64', '16', '3365', 'Opening'), +('64', '16', '5009', 'Wands'), +('64', '16', '5019', 'Shoot'), +('64', '16', '6233', 'Closing'), +('64', '16', '6246', 'Closing'), +('64', '16', '6247', 'Opening'), +('64', '16', '6477', 'Opening'), +('64', '16', '6478', 'Opening'), +('64', '16', '6603', 'Attack'), +('64', '16', '7266', 'Duel'), +('64', '16', '7267', 'Grovel'), +('64', '16', '7355', 'Stuck'), +('64', '16', '8386', 'Attacking'), +('64', '16', '9078', 'Cloth'), +('64', '16', '9125', 'Generic'), +('64', '16', '21651', 'Opening'), +('64', '16', '21652', 'Closing'), +('64', '16', '22027', 'Remove Insignia'), +('64', '16', '22810', 'Opening - No Text'), +('64', '16', '25389', null), +('64', '16', '25364', null), +('64', '16', '25368', null), +('64', '16', '25218', null), +('64', '16', '25429', null), +('64', '16', '25222', null), +('64', '16', '25375', null), +('64', '16', '25435', null), +('64', '16', '25431', null), +('64', '16', '528', null), +('64', '16', '10890', null), +('64', '16', '988', null), +('64', '16', '6346', null), +('64', '16', '25235', null), +('64', '16', '25384', null), +('64', '16', '25596', null), +('64', '16', '10955', null), +('64', '16', '10909', null), +('64', '16', '25380', null), +('64', '16', '10912', null), +('64', '16', '25308', null), +('64', '16', '25433', null), +('64', '16', '552', null), +('64', '16', '1706', null), +('64', '16', '25213', null), +('64', '16', '25392', null), +('64', '16', '39374', null), +('64', '16', '32999', null), +('64', '16', '32996', null), +('64', '16', '32546', null), +('64', '16', '34433', null), +('64', '16', '33076', null), +('64', '16', '32375', null), +('64', '16', '25441', null), +('64', '16', '25312', null), +('64', '16', '25437', null), +('64', '64', '7340', 'Language Gnomish'), +('64', '64', '20589', 'Escape Artist'), +('64', '64', '20591', 'Expansive Mind'), +('64', '64', '20592', 'Arcane Resistance'), +('64', '64', '20593', 'Engineering Specialization'), +('64', '64', '668', 'Language Common'), +('64', '64', '81', 'Dodge'), +('64', '64', '107', 'Block'), +('64', '64', '198', 'One-Handed Maces'), +('64', '64', '203', 'Unarmed'), +('64', '64', '204', 'Defense'), +('64', '64', '227', 'Staves'), +('64', '64', '331', 'Healing Wave'), +('64', '64', '403', 'Lightning Bolt'), +('64', '64', '522', 'SPELLDEFENSE(DND)'), +('64', '64', '2382', 'Generic'), +('64', '64', '2479', 'Honorless Target'), +('64', '64', '3050', 'Detect'), +('64', '64', '3365', 'Opening'), +('64', '64', '6233', 'Closing'), +('64', '64', '6246', 'Closing'), +('64', '64', '6247', 'Opening'), +('64', '64', '6477', 'Opening'), +('64', '64', '6478', 'Opening'), +('64', '64', '6603', 'Attack'), +('64', '64', '7266', 'Duel'), +('64', '64', '7267', 'Grovel'), +('64', '64', '7355', 'Stuck'), +('64', '64', '8386', 'Attacking'), +('64', '64', '9077', 'Leather'), +('64', '64', '9078', 'Cloth'), +('64', '64', '9116', 'Shield'), +('64', '64', '9125', 'Generic'), +('64', '64', '21651', 'Opening'), +('64', '64', '21652', 'Closing'), +('64', '64', '22027', 'Remove Insignia'), +('64', '64', '22810', 'Opening - No Text'), +('64', '64', '27763', 'Totem'), +('64', '64', '25396', null), +('64', '64', '25449', null), +('64', '64', '25485', null), +('64', '64', '25454', null), +('64', '64', '25509', null), +('64', '64', '2484', null), +('64', '64', '25472', null), +('64', '64', '25525', null), +('64', '64', '25457', null), +('64', '64', '25489', null), +('64', '64', '25533', null), +('64', '64', '25528', null), +('64', '64', '20777', null), +('64', '64', '25547', null), +('64', '64', '8012', null), +('64', '64', '526', null), +('64', '64', '8143', null), +('64', '64', '25464', null), +('64', '64', '25500', null), +('64', '64', '2645', null), +('64', '64', '25567', null), +('64', '64', '25420', null), +('64', '64', '2870', null), +('64', '64', '8166', null), +('64', '64', '131', null), +('64', '64', '25560', null), +('64', '64', '6196', null), +('64', '64', '25552', null), +('64', '64', '25570', null), +('64', '64', '25563', null), +('64', '64', '25557', null), +('64', '64', '546', null), +('64', '64', '556', null), +('64', '64', '8177', null), +('64', '64', '25574', null), +('64', '64', '36936', null), +('64', '64', '25505', null), +('64', '64', '421', null), +('64', '64', '25587', null), +('64', '64', '6495', null), +('64', '64', '25577', null), +('64', '64', '8170', null), +('64', '64', '25423', null), +('64', '64', '25359', null), +('64', '64', '25908', null), +('64', '64', '33736', null), +('64', '64', '3738', null), +('64', '64', '2062', null), +('64', '64', '2894', null), +('64', '64', '2825', null), +('64', '1024', '7340', 'Language Gnomish'), +('64', '1024', '20589', 'Escape Artist'), +('64', '1024', '20591', 'Expansive Mind'), +('64', '1024', '20592', 'Arcane Resistance'), +('64', '1024', '20593', 'Engineering Specialization'), +('64', '1024', '668', 'Language Common'), +('64', '1024', '81', 'Dodge'), +('64', '1024', '203', 'Unarmed'), +('64', '1024', '204', 'Defense'), +('64', '1024', '227', 'Staves'), +('64', '1024', '522', 'SPELLDEFENSE(DND)'), +('64', '1024', '1178', 'Bear Form(Passive)'), +('64', '1024', '1180', 'Daggers'), +('64', '1024', '2382', 'Generic'), +('64', '1024', '2479', 'Honorless Target'), +('64', '1024', '3025', 'Cat Form(Passive)'), +('64', '1024', '3050', 'Detect'), +('64', '1024', '3365', 'Opening'), +('64', '1024', '5176', 'Wrath'), +('64', '1024', '5185', 'Healing Touch'), +('64', '1024', '5419', 'Travel Form(Passive)'), +('64', '1024', '5420', 'Tree of Life'), +('64', '1024', '5421', 'Aquatic Form(Passive)'), +('64', '1024', '6233', 'Closing'), +('64', '1024', '6246', 'Closing'), +('64', '1024', '6247', 'Opening'), +('64', '1024', '6477', 'Opening'), +('64', '1024', '6478', 'Opening'), +('64', '1024', '6603', 'Attack'), +('64', '1024', '7266', 'Duel'), +('64', '1024', '7267', 'Grovel'), +('64', '1024', '7355', 'Stuck'), +('64', '1024', '8386', 'Attacking'), +('64', '1024', '9077', 'Leather'), +('64', '1024', '9078', 'Cloth'), +('64', '1024', '9125', 'Generic'), +('64', '1024', '9635', 'Dire Bear Form(Passive)'), +('64', '1024', '21178', 'Bear Form(Passive2)'), +('64', '1024', '21651', 'Opening'), +('64', '1024', '21652', 'Closing'), +('64', '1024', '22027', 'Remove Insignia'), +('64', '1024', '22810', 'Opening - No Text'), +('64', '1024', '24905', 'Moonkin Form(Passive)'), +('64', '1024', '27764', 'Fetish'), +('64', '1024', '33948', 'Flight Form(Passive)'), +('64', '1024', '34123', 'Tree of Life(Passive)'), +('64', '1024', '40121', 'Swift Flight Form(Passive)'), +('64', '1024', '26979', null), +('64', '1024', '26990', null), +('64', '1024', '26985', null), +('64', '1024', '26988', null), +('64', '1024', '26982', null), +('64', '1024', '26992', null), +('64', '1024', '26989', null), +('64', '1024', '26998', null), +('64', '1024', '6795', null), +('64', '1024', '26996', null), +('64', '1024', '18960', null), +('64', '1024', '9634', null), +('64', '1024', '768', null), +('64', '1024', '783', null), +('64', '1024', '1066', null), +('64', '1024', '40120', null), +('64', '1024', '5229', null), +('64', '1024', '26980', null), +('64', '1024', '8983', null), +('64', '1024', '8946', null), +('64', '1024', '26997', null), +('64', '1024', '26993', null), +('64', '1024', '18658', null), +('64', '1024', '27000', null), +('64', '1024', '9913', null), +('64', '1024', '26994', null), +('64', '1024', '27008', null), +('64', '1024', '26986', null), +('64', '1024', '27002', null), +('64', '1024', '26995', null), +('64', '1024', '27003', null), +('64', '1024', '2782', null), +('64', '1024', '9846', null), +('64', '1024', '2893', null), +('64', '1024', '33357', null), +('64', '1024', '5209', null), +('64', '1024', '27004', null), +('64', '1024', '26983', null), +('64', '1024', '24248', null), +('64', '1024', '27005', null), +('64', '1024', '5225', null), +('64', '1024', '26999', null), +('64', '1024', '27012', null), +('64', '1024', '27006', null), +('64', '1024', '29166', null), +('64', '1024', '22812', null), +('64', '1024', '26991', null), +('64', '1024', '22570', null), +('64', '1024', '33763', null), +('64', '1024', '33745', null), +('64', '1024', '33786', null), +('1', '4', '75', 'Auto Shot'), +('1', '4', '81', 'Dodge'), +('1', '4', '196', 'One-Handed Axes'), +('1', '4', '203', 'Unarmed'), +('1', '4', '204', 'Defense'), +('1', '4', '264', 'Bows'), +('1', '4', '266', 'Guns'), +('1', '4', '522', 'SPELLDEFENSE(DND)'), +('1', '4', '668', 'Language Common'), +('1', '4', '883', null), +('1', '4', '982', null), +('1', '4', '1002', null), +('1', '4', '1462', null), +('1', '4', '1494', null), +('1', '4', '1515', null), +('1', '4', '1543', null), +('1', '4', '2382', 'Generic'), +('1', '4', '2479', 'Honorless Target'), +('1', '4', '2641', null), +('1', '4', '2973', 'Raptor Strike'), +('1', '4', '3043', null), +('1', '4', '3045', null), +('1', '4', '3050', 'Detect'), +('1', '4', '3365', 'Opening'), +('1', '4', '5116', null), +('1', '4', '5118', null), +('1', '4', '5384', null), +('1', '4', '6197', null), +('1', '4', '6233', 'Closing'), +('1', '4', '6246', 'Closing'), +('1', '4', '6247', 'Opening'), +('1', '4', '6477', 'Opening'), +('1', '4', '6478', 'Opening'), +('1', '4', '6603', 'Attack'), +('1', '4', '6991', null), +('1', '4', '7266', 'Duel'), +('1', '4', '7267', 'Grovel'), +('1', '4', '7355', 'Stuck'), +('1', '4', '8386', 'Attacking'), +('1', '4', '9077', 'Leather'), +('1', '4', '9078', 'Cloth'), +('1', '4', '9125', 'Generic'), +('1', '4', '13159', null), +('1', '4', '13161', null), +('1', '4', '13163', null), +('1', '4', '13358', 'Defensive State(DND)'), +('1', '4', '13809', null), +('1', '4', '14268', null), +('1', '4', '14311', null), +('1', '4', '14325', null), +('1', '4', '14327', null), +('1', '4', '19801', null), +('1', '4', '19878', null), +('1', '4', '19879', null), +('1', '4', '19880', null), +('1', '4', '19882', null), +('1', '4', '19883', null), +('1', '4', '19884', null), +('1', '4', '19885', null), +('1', '4', '20597', 'Sword Specialization'), +('1', '4', '20598', 'The Human Spirit'), +('1', '4', '20599', 'Diplomacy'), +('1', '4', '20864', 'Mace Specialization'), +('1', '4', '21651', 'Opening'), +('1', '4', '21652', 'Closing'), +('1', '4', '22027', 'Remove Insignia'), +('1', '4', '22810', 'Opening - No Text'), +('1', '4', '24949', 'Defensive State 2(DND)'), +('1', '4', '27014', null), +('1', '4', '27015', null), +('1', '4', '27016', null), +('1', '4', '27018', null), +('1', '4', '27019', null), +('1', '4', '27020', null), +('1', '4', '27021', null), +('1', '4', '27022', null), +('1', '4', '27023', null), +('1', '4', '27025', null), +('1', '4', '27044', null), +('1', '4', '27045', null), +('1', '4', '27046', null), +('1', '4', '34026', null), +('1', '4', '34074', null), +('1', '4', '34082', 'Advantaged State(DND)'), +('1', '4', '34120', null), +('1', '4', '34477', null), +('1', '4', '34600', null), +('1', '4', '36916', null), +('1', '64', '81', 'Dodge'), +('1', '64', '107', 'Block'), +('1', '64', '131', null), +('1', '64', '198', 'One-Handed Maces'), +('1', '64', '203', 'Unarmed'), +('1', '64', '204', 'Defense'), +('1', '64', '227', 'Staves'), +('1', '64', '331', 'Healing Wave'), +('1', '64', '403', 'Lightning Bolt'), +('1', '64', '421', null), +('1', '64', '522', 'SPELLDEFENSE(DND)'), +('1', '64', '526', null), +('1', '64', '546', null), +('1', '64', '556', null), +('1', '64', '668', 'Language Common'), +('1', '64', '2062', null), +('1', '64', '2382', 'Generic'), +('1', '64', '2479', 'Honorless Target'), +('1', '64', '2484', null), +('1', '64', '2645', null), +('1', '64', '2825', null), +('1', '64', '2870', null), +('1', '64', '2894', null), +('1', '64', '3050', 'Detect'), +('1', '64', '3365', 'Opening'), +('1', '64', '3738', null), +('1', '64', '6196', null), +('1', '64', '6233', 'Closing'), +('1', '64', '6246', 'Closing'), +('1', '64', '6247', 'Opening'), +('1', '64', '6477', 'Opening'), +('1', '64', '6478', 'Opening'), +('1', '64', '6495', null), +('1', '64', '6603', 'Attack'), +('1', '64', '7266', 'Duel'), +('1', '64', '7267', 'Grovel'), +('1', '64', '7355', 'Stuck'), +('1', '64', '8012', null), +('1', '64', '8143', null), +('1', '64', '8166', null), +('1', '64', '8170', null), +('1', '64', '8177', null), +('1', '64', '8386', 'Attacking'), +('1', '64', '9077', 'Leather'), +('1', '64', '9078', 'Cloth'), +('1', '64', '9116', 'Shield'), +('1', '64', '9125', 'Generic'), +('1', '64', '20597', 'Sword Specialization'), +('1', '64', '20598', 'The Human Spirit'), +('1', '64', '20599', 'Diplomacy'), +('1', '64', '20777', null), +('1', '64', '20864', 'Mace Specialization'), +('1', '64', '21651', 'Opening'), +('1', '64', '21652', 'Closing'), +('1', '64', '22027', 'Remove Insignia'), +('1', '64', '22810', 'Opening - No Text'), +('1', '64', '25359', null), +('1', '64', '25396', null), +('1', '64', '25420', null), +('1', '64', '25423', null), +('1', '64', '25449', null), +('1', '64', '25454', null), +('1', '64', '25457', null), +('1', '64', '25464', null), +('1', '64', '25472', null), +('1', '64', '25485', null), +('1', '64', '25489', null), +('1', '64', '25500', null), +('1', '64', '25505', null), +('1', '64', '25509', null), +('1', '64', '25525', null), +('1', '64', '25528', null), +('1', '64', '25533', null), +('1', '64', '25547', null), +('1', '64', '25552', null), +('1', '64', '25557', null), +('1', '64', '25560', null), +('1', '64', '25563', null), +('1', '64', '25567', null), +('1', '64', '25570', null), +('1', '64', '25574', null), +('1', '64', '25577', null), +('1', '64', '25587', null), +('1', '64', '25908', null), +('1', '64', '27763', 'Totem'), +('1', '64', '33736', null), +('1', '64', '36936', null), +('1', '1024', '81', 'Dodge'), +('1', '1024', '203', 'Unarmed'), +('1', '1024', '204', 'Defense'), +('1', '1024', '227', 'Staves'), +('1', '1024', '522', 'SPELLDEFENSE(DND)'), +('1', '1024', '668', 'Language Common'), +('1', '1024', '768', null), +('1', '1024', '783', null), +('1', '1024', '1066', null), +('1', '1024', '1178', 'Bear Form(Passive)'), +('1', '1024', '1180', 'Daggers'), +('1', '1024', '2382', 'Generic'), +('1', '1024', '2479', 'Honorless Target'), +('1', '1024', '2782', null), +('1', '1024', '2893', null), +('1', '1024', '3025', 'Cat Form(Passive)'), +('1', '1024', '3050', 'Detect'), +('1', '1024', '3365', 'Opening'), +('1', '1024', '5176', 'Wrath'), +('1', '1024', '5185', 'Healing Touch'), +('1', '1024', '5209', null), +('1', '1024', '5225', null), +('1', '1024', '5229', null), +('1', '1024', '5419', 'Travel Form(Passive)'), +('1', '1024', '5420', 'Tree of Life'), +('1', '1024', '5421', 'Aquatic Form(Passive)'), +('1', '1024', '6233', 'Closing'), +('1', '1024', '6246', 'Closing'), +('1', '1024', '6247', 'Opening'), +('1', '1024', '6477', 'Opening'), +('1', '1024', '6478', 'Opening'), +('1', '1024', '6603', 'Attack'), +('1', '1024', '6795', null), +('1', '1024', '7266', 'Duel'), +('1', '1024', '7267', 'Grovel'), +('1', '1024', '7355', 'Stuck'), +('1', '1024', '8386', 'Attacking'), +('1', '1024', '8946', null), +('1', '1024', '8983', null), +('1', '1024', '9077', 'Leather'), +('1', '1024', '9078', 'Cloth'), +('1', '1024', '9125', 'Generic'), +('1', '1024', '9634', null), +('1', '1024', '9635', 'Dire Bear Form(Passive)'), +('1', '1024', '9846', null), +('1', '1024', '9913', null), +('1', '1024', '18658', null), +('1', '1024', '18960', null), +('1', '1024', '20597', 'Sword Specialization'), +('1', '1024', '20598', 'The Human Spirit'), +('1', '1024', '20599', 'Diplomacy'), +('1', '1024', '20864', 'Mace Specialization'), +('1', '1024', '21178', 'Bear Form(Passive2)'), +('1', '1024', '21651', 'Opening'), +('1', '1024', '21652', 'Closing'), +('1', '1024', '22027', 'Remove Insignia'), +('1', '1024', '22570', null), +('1', '1024', '22810', 'Opening - No Text'), +('1', '1024', '22812', null), +('1', '1024', '24248', null), +('1', '1024', '24905', 'Moonkin Form(Passive)'), +('1', '1024', '26979', null), +('1', '1024', '26980', null), +('1', '1024', '26982', null), +('1', '1024', '26983', null), +('1', '1024', '26985', null), +('1', '1024', '26986', null), +('1', '1024', '26988', null), +('1', '1024', '26989', null), +('1', '1024', '26990', null), +('1', '1024', '26991', null), +('1', '1024', '26992', null), +('1', '1024', '26993', null), +('1', '1024', '26994', null), +('1', '1024', '26995', null), +('1', '1024', '26996', null), +('1', '1024', '26997', null), +('1', '1024', '26998', null), +('1', '1024', '26999', null), +('1', '1024', '27000', null), +('1', '1024', '27002', null), +('1', '1024', '27003', null), +('1', '1024', '27004', null), +('1', '1024', '27005', null), +('1', '1024', '27006', null), +('1', '1024', '27008', null), +('1', '1024', '27012', null), +('1', '1024', '27764', 'Fetish'), +('1', '1024', '29166', null), +('1', '1024', '33357', null), +('1', '1024', '33745', null), +('1', '1024', '33763', null), +('1', '1024', '33786', null), +('1', '1024', '33948', 'Flight Form(Passive)'), +('1', '1024', '34123', 'Tree of Life(Passive)'), +('1', '1024', '40120', null), +('1', '1024', '40121', 'Swift Flight Form(Passive)'), +('8', '2', '671', 'Language Darnassian'), +('8', '2', '20580', 'Shadowmeld'), +('8', '2', '20582', 'Quickness'), +('8', '2', '20583', 'Nature Resistance'), +('8', '2', '20585', 'Wisp Spirit'), +('8', '2', '21009', 'Shadowmeld Passive'), +('8', '2', '81', 'Dodge'), +('8', '2', '107', 'Block'), +('8', '2', '198', 'One-Handed Maces'), +('8', '2', '199', 'Two-Handed Maces'), +('8', '2', '203', 'Unarmed'), +('8', '2', '204', 'Defense'), +('8', '2', '522', 'SPELLDEFENSE(DND)'), +('8', '2', '635', 'Holy Light'), +('8', '2', '668', 'Language Common'), +('8', '2', '2382', 'Generic'), +('8', '2', '2479', 'Honorless Target'), +('8', '2', '3050', 'Detect'), +('8', '2', '3365', 'Opening'), +('8', '2', '6233', 'Closing'), +('8', '2', '6246', 'Closing'), +('8', '2', '6247', 'Opening'), +('8', '2', '6477', 'Opening'), +('8', '2', '6478', 'Opening'), +('8', '2', '6603', 'Attack'), +('8', '2', '7266', 'Duel'), +('8', '2', '7267', 'Grovel'), +('8', '2', '7355', 'Stuck'), +('8', '2', '8386', 'Attacking'), +('8', '2', '8737', 'Mail'), +('8', '2', '9077', 'Leather'), +('8', '2', '9078', 'Cloth'), +('8', '2', '9116', 'Shield'), +('8', '2', '9125', 'Generic'), +('8', '2', '21084', 'Seal of Righteousness'), +('8', '2', '21651', 'Opening'), +('8', '2', '21652', 'Closing'), +('8', '2', '22027', 'Remove Insignia'), +('8', '2', '22810', 'Opening - No Text'), +('8', '2', '27762', 'Libram'), +('8', '2', '27149', null), +('8', '2', '27136', null), +('8', '2', '27155', null), +('8', '2', '27140', null), +('8', '2', '20271', null), +('8', '2', '27158', null), +('8', '2', '10308', null), +('8', '2', '10278', null), +('8', '2', '27154', null), +('8', '2', '20773', null), +('8', '2', '27142', null), +('8', '2', '31789', null), +('8', '2', '27150', null), +('8', '2', '25780', null), +('8', '2', '1044', null), +('8', '2', '33776', null), +('8', '2', '27173', null), +('8', '2', '27138', null), +('8', '2', '27137', null), +('8', '2', '5502', null), +('8', '2', '19746', null), +('8', '2', '31895', null), +('8', '2', '5627', null), +('8', '2', '1038', null), +('8', '2', '27151', null), +('8', '2', '19752', null), +('8', '2', '27160', null), +('8', '2', '27152', null), +('8', '2', '1020', null), +('8', '2', '27153', null), +('8', '2', '27166', null), +('8', '2', '27144', null), +('8', '2', '4987', null), +('8', '2', '27180', null), +('8', '2', '27148', null), +('8', '2', '27139', null), +('8', '2', '27141', null), +('8', '2', '10326', null), +('8', '2', '27143', null), +('8', '2', '25898', null), +('8', '2', '27145', null), +('8', '2', '25895', null), +('8', '2', '32223', null), +('8', '2', '27169', null), +('8', '2', '31884', null), +('8', '2', '750', null), +('8', '2', '3127', null), +('8', '2', '23214', null), +('8', '2', '31801', null), +('8', '64', '671', 'Language Darnassian'), +('8', '64', '20580', 'Shadowmeld'), +('8', '64', '20582', 'Quickness'), +('8', '64', '20583', 'Nature Resistance'), +('8', '64', '20585', 'Wisp Spirit'), +('8', '64', '21009', 'Shadowmeld Passive'), +('8', '64', '668', 'Language Common'), +('8', '64', '81', 'Dodge'), +('8', '64', '107', 'Block'), +('8', '64', '198', 'One-Handed Maces'), +('8', '64', '203', 'Unarmed'), +('8', '64', '204', 'Defense'), +('8', '64', '227', 'Staves'), +('8', '64', '331', 'Healing Wave'), +('8', '64', '403', 'Lightning Bolt'), +('8', '64', '522', 'SPELLDEFENSE(DND)'), +('8', '64', '2382', 'Generic'), +('8', '64', '2479', 'Honorless Target'), +('8', '64', '3050', 'Detect'), +('8', '64', '3365', 'Opening'), +('8', '64', '6233', 'Closing'), +('8', '64', '6246', 'Closing'), +('8', '64', '6247', 'Opening'), +('8', '64', '6477', 'Opening'), +('8', '64', '6478', 'Opening'), +('8', '64', '6603', 'Attack'), +('8', '64', '7266', 'Duel'), +('8', '64', '7267', 'Grovel'), +('8', '64', '7355', 'Stuck'), +('8', '64', '8386', 'Attacking'), +('8', '64', '9077', 'Leather'), +('8', '64', '9078', 'Cloth'), +('8', '64', '9116', 'Shield'), +('8', '64', '9125', 'Generic'), +('8', '64', '21651', 'Opening'), +('8', '64', '21652', 'Closing'), +('8', '64', '22027', 'Remove Insignia'), +('8', '64', '22810', 'Opening - No Text'), +('8', '64', '27763', 'Totem'), +('8', '64', '25396', null), +('8', '64', '25449', null), +('8', '64', '25485', null), +('8', '64', '25454', null), +('8', '64', '25509', null), +('8', '64', '2484', null), +('8', '64', '25472', null), +('8', '64', '25525', null), +('8', '64', '25457', null), +('8', '64', '25489', null), +('8', '64', '25533', null), +('8', '64', '25528', null), +('8', '64', '20777', null), +('8', '64', '25547', null), +('8', '64', '8012', null), +('8', '64', '526', null), +('8', '64', '8143', null), +('8', '64', '25464', null), +('8', '64', '25500', null), +('8', '64', '2645', null), +('8', '64', '25567', null), +('8', '64', '25420', null), +('8', '64', '2870', null), +('8', '64', '8166', null), +('8', '64', '131', null), +('8', '64', '25560', null), +('8', '64', '6196', null), +('8', '64', '25552', null), +('8', '64', '25570', null), +('8', '64', '25563', null), +('8', '64', '25557', null), +('8', '64', '546', null), +('8', '64', '556', null), +('8', '64', '8177', null), +('8', '64', '25574', null), +('8', '64', '36936', null), +('8', '64', '25505', null), +('8', '64', '421', null), +('8', '64', '25587', null), +('8', '64', '6495', null), +('8', '64', '25577', null), +('8', '64', '8170', null), +('8', '64', '25423', null), +('8', '64', '25359', null), +('8', '64', '25908', null), +('8', '64', '33736', null), +('8', '64', '3738', null), +('8', '64', '2062', null), +('8', '64', '2894', null), +('8', '64', '2825', null), +('8', '128', '81', 'Dodge'), +('8', '128', '133', 'Fireball'), +('8', '128', '168', 'Frost Armor'), +('8', '128', '203', 'Unarmed'), +('8', '128', '204', 'Defense'), +('8', '128', '227', 'Staves'), +('8', '128', '522', 'SPELLDEFENSE(DND)'), +('8', '128', '668', 'Language Common'), +('8', '128', '2382', 'Generic'), +('8', '128', '2479', 'Honorless Target'), +('8', '128', '3050', 'Detect'), +('8', '128', '3365', 'Opening'), +('8', '128', '5009', 'Wands'), +('8', '128', '5019', 'Shoot'), +('8', '128', '6233', 'Closing'), +('8', '128', '6246', 'Closing'), +('8', '128', '6247', 'Opening'), +('8', '128', '6477', 'Opening'), +('8', '128', '6478', 'Opening'), +('8', '128', '6603', 'Attack'), +('8', '128', '7266', 'Duel'), +('8', '128', '7267', 'Grovel'), +('8', '128', '7355', 'Stuck'), +('8', '128', '8386', 'Attacking'), +('8', '128', '9078', 'Cloth'), +('8', '128', '9125', 'Generic'), +('8', '128', '21651', 'Opening'), +('8', '128', '21652', 'Closing'), +('8', '128', '22027', 'Remove Insignia'), +('8', '128', '22810', 'Opening - No Text'), +('8', '128', '27126', null), +('8', '128', '27070', null), +('8', '128', '22018', null), +('8', '128', '27072', null), +('8', '128', '22019', null), +('8', '128', '27079', null), +('8', '128', '38704', null), +('8', '128', '28272', null), +('8', '128', '28271', null), +('8', '128', '12826', null), +('8', '128', '27088', null), +('8', '128', '33944', null), +('8', '128', '130', null), +('8', '128', '27082', null), +('8', '128', '27086', null), +('8', '128', '33946', null), +('8', '128', '475', null), +('8', '128', '1953', null), +('8', '128', '27085', null), +('8', '128', '12051', null), +('8', '128', '27128', null), +('8', '128', '27131', null), +('8', '128', '32796', null), +('8', '128', '27074', null), +('8', '128', '2139', null), +('8', '128', '27101', null), +('8', '128', '27124', null), +('8', '128', '45438', null), +('8', '128', '27125', null), +('8', '128', '27127', null), +('8', '128', '30482', null), +('8', '128', '30451', null), +('8', '128', '30455', null), +('8', '128', '66', null), +('8', '128', '43987', null), +('8', '128', '30449', null), +('8', '128', '27087', null), +('8', '128', '671', 'Language Darnassian'), +('8', '128', '20580', 'Shadowmeld'), +('8', '128', '20582', 'Quickness'), +('8', '128', '20583', 'Nature Resistance'), +('8', '128', '20585', 'Wisp Spirit'), +('8', '128', '21009', 'Shadowmeld Passive'), +('8', '256', '671', 'Language Darnassian'), +('8', '256', '20580', 'Shadowmeld'), +('8', '256', '20582', 'Quickness'), +('8', '256', '20583', 'Nature Resistance'), +('8', '256', '20585', 'Wisp Spirit'), +('8', '256', '21009', 'Shadowmeld Passive'), +('8', '256', '81', 'Dodge'), +('8', '256', '203', 'Unarmed'), +('8', '256', '204', 'Defense'), +('8', '256', '522', 'SPELLDEFENSE(DND)'), +('8', '256', '668', 'Language Common'), +('8', '256', '686', 'Shadow Bolt'), +('8', '256', '687', 'Demon Skin'), +('8', '256', '1180', 'Daggers'), +('8', '256', '2382', 'Generic'), +('8', '256', '2479', 'Honorless Target'), +('8', '256', '3050', 'Detect'), +('8', '256', '3365', 'Opening'), +('8', '256', '5009', 'Wands'), +('8', '256', '5019', 'Shoot'), +('8', '256', '6233', 'Closing'), +('8', '256', '6246', 'Closing'), +('8', '256', '6247', 'Opening'), +('8', '256', '6477', 'Opening'), +('8', '256', '6478', 'Opening'), +('8', '256', '6603', 'Attack'), +('8', '256', '7266', 'Duel'), +('8', '256', '7267', 'Grovel'), +('8', '256', '7355', 'Stuck'), +('8', '256', '8386', 'Attacking'), +('8', '256', '9078', 'Cloth'), +('8', '256', '9125', 'Generic'), +('8', '256', '21651', 'Opening'), +('8', '256', '21652', 'Closing'), +('8', '256', '22027', 'Remove Insignia'), +('8', '256', '22810', 'Opening - No Text'), +('8', '256', '27215', null), +('8', '256', '27209', null), +('8', '256', '27216', null), +('8', '256', '30909', null), +('8', '256', '27222', null), +('8', '256', '27218', null), +('8', '256', '6215', null), +('8', '256', '27230', null), +('8', '256', '27217', null), +('8', '256', '27259', null), +('8', '256', '27226', null), +('8', '256', '27220', null), +('8', '256', '5697', null), +('8', '256', '27238', null), +('8', '256', '30459', null), +('8', '256', '27260', null), +('8', '256', '27212', null), +('8', '256', '698', null), +('8', '256', '5500', null), +('8', '256', '30908', null), +('8', '256', '11719', null), +('8', '256', '132', null), +('8', '256', '18647', null), +('8', '256', '27213', null), +('8', '256', '11726', null), +('8', '256', '27228', null), +('8', '256', '28610', null), +('8', '256', '28172', null), +('8', '256', '27250', null), +('8', '256', '17928', null), +('8', '256', '27223', null), +('8', '256', '27229', null), +('8', '256', '30545', null), +('8', '256', '30910', null), +('8', '256', '18540', null), +('8', '256', '28189', null), +('8', '256', '32231', null), +('8', '256', '29858', null), +('8', '256', '29893', null), +('8', '256', '27243', null), +('8', '256', '23161', null), +('8', '256', '688', null), +('8', '256', '697', null), +('8', '256', '712', null), +('8', '256', '691', null), +('8', '256', '126', null), +('2', '2', '81', 'Dodge'), +('2', '2', '107', 'Block'), +('2', '2', '198', 'One-Handed Maces'), +('2', '2', '199', 'Two-Handed Maces'), +('2', '2', '203', 'Unarmed'), +('2', '2', '204', 'Defense'), +('2', '2', '522', 'SPELLDEFENSE(DND)'), +('2', '2', '635', 'Holy Light'), +('2', '2', '669', 'Language Orcish'), +('2', '2', '750', null), +('2', '2', '1020', null), +('2', '2', '1038', null), +('2', '2', '1044', null), +('2', '2', '2382', 'Generic'), +('2', '2', '2479', 'Honorless Target'), +('2', '2', '3050', 'Detect'), +('2', '2', '3127', null), +('2', '2', '3365', 'Opening'), +('2', '2', '4987', null), +('2', '2', '5502', null), +('2', '2', '5627', null), +('2', '2', '6233', 'Closing'), +('2', '2', '6246', 'Closing'), +('2', '2', '6247', 'Opening'), +('2', '2', '6477', 'Opening'), +('2', '2', '6478', 'Opening'), +('2', '2', '6603', 'Attack'), +('2', '2', '7266', 'Duel'), +('2', '2', '7267', 'Grovel'), +('2', '2', '7355', 'Stuck'), +('2', '2', '8386', 'Attacking'), +('2', '2', '8737', 'Mail'), +('2', '2', '9077', 'Leather'), +('2', '2', '9078', 'Cloth'), +('2', '2', '9116', 'Shield'), +('2', '2', '9125', 'Generic'), +('2', '2', '10278', null), +('2', '2', '10308', null), +('2', '2', '10326', null), +('2', '2', '19746', null), +('2', '2', '19752', null), +('2', '2', '20271', null), +('2', '2', '20572', 'Blood Fury'), +('2', '2', '20573', 'Hardiness'), +('2', '2', '20574', 'Axe Specialization'), +('2', '2', '20773', null), +('2', '2', '21084', 'Seal of Righteousness'), +('2', '2', '21651', 'Opening'), +('2', '2', '21652', 'Closing'), +('2', '2', '22027', 'Remove Insignia'), +('2', '2', '22810', 'Opening - No Text'), +('2', '2', '23214', null), +('2', '2', '25780', null), +('2', '2', '25895', null), +('2', '2', '25898', null), +('2', '2', '27136', null), +('2', '2', '27137', null), +('2', '2', '27138', null), +('2', '2', '27139', null), +('2', '2', '27140', null), +('2', '2', '27141', null), +('2', '2', '27142', null), +('2', '2', '27143', null), +('2', '2', '27144', null), +('2', '2', '27145', null), +('2', '2', '27148', null), +('2', '2', '27149', null), +('2', '2', '27150', null), +('2', '2', '27151', null), +('2', '2', '27152', null), +('2', '2', '27153', null), +('2', '2', '27154', null), +('2', '2', '27155', null), +('2', '2', '27158', null), +('2', '2', '27160', null), +('2', '2', '27166', null), +('2', '2', '27169', null), +('2', '2', '27173', null), +('2', '2', '27180', null), +('2', '2', '27762', 'Libram'), +('2', '2', '31789', null), +('2', '2', '31801', null), +('2', '2', '31884', null), +('2', '2', '31895', null), +('2', '2', '32223', null), +('2', '2', '33776', null), +('2', '16', '669', 'Language Orcish'), +('2', '16', '20572', 'Blood Fury'), +('2', '16', '20573', 'Hardiness'), +('2', '16', '20574', 'Axe Specialization'), +('2', '16', '81', 'Dodge'), +('2', '16', '198', 'One-Handed Maces'), +('2', '16', '203', 'Unarmed'), +('2', '16', '204', 'Defense'), +('2', '16', '522', 'SPELLDEFENSE(DND)'), +('2', '16', '585', 'Smite'), +('2', '16', '2050', 'Lesser Heal'), +('2', '16', '2382', 'Generic'), +('2', '16', '2479', 'Honorless Target'), +('2', '16', '3050', 'Detect'), +('2', '16', '3365', 'Opening'), +('2', '16', '5009', 'Wands'), +('2', '16', '5019', 'Shoot'), +('2', '16', '6233', 'Closing'), +('2', '16', '6246', 'Closing'), +('2', '16', '6247', 'Opening'), +('2', '16', '6477', 'Opening'), +('2', '16', '6478', 'Opening'), +('2', '16', '6603', 'Attack'), +('2', '16', '7266', 'Duel'), +('2', '16', '7267', 'Grovel'), +('2', '16', '7355', 'Stuck'), +('2', '16', '8386', 'Attacking'), +('2', '16', '9078', 'Cloth'), +('2', '16', '9125', 'Generic'), +('2', '16', '21651', 'Opening'), +('2', '16', '21652', 'Closing'), +('2', '16', '22027', 'Remove Insignia'), +('2', '16', '22810', 'Opening - No Text'), +('2', '16', '25389', null), +('2', '16', '25364', null), +('2', '16', '25368', null), +('2', '16', '25218', null), +('2', '16', '25429', null), +('2', '16', '25222', null), +('2', '16', '25375', null), +('2', '16', '25435', null), +('2', '16', '25431', null), +('2', '16', '528', null), +('2', '16', '10890', null), +('2', '16', '988', null), +('2', '16', '6346', null), +('2', '16', '25235', null), +('2', '16', '25384', null), +('2', '16', '25596', null), +('2', '16', '10955', null), +('2', '16', '10909', null), +('2', '16', '25380', null), +('2', '16', '10912', null), +('2', '16', '25308', null), +('2', '16', '25433', null), +('2', '16', '552', null), +('2', '16', '1706', null), +('2', '16', '25213', null), +('2', '16', '25392', null), +('2', '16', '39374', null), +('2', '16', '32999', null), +('2', '16', '32996', null), +('2', '16', '32546', null), +('2', '16', '34433', null), +('2', '16', '33076', null), +('2', '16', '32375', null), +('2', '16', '25441', null), +('2', '16', '25312', null), +('2', '16', '25437', null), +('2', '128', '669', 'Language Orcish'), +('2', '128', '20572', 'Blood Fury'), +('2', '128', '20573', 'Hardiness'), +('2', '128', '20574', 'Axe Specialization'), +('2', '128', '81', 'Dodge'), +('2', '128', '133', 'Fireball'), +('2', '128', '168', 'Frost Armor'), +('2', '128', '203', 'Unarmed'), +('2', '128', '204', 'Defense'), +('2', '128', '227', 'Staves'), +('2', '128', '522', 'SPELLDEFENSE(DND)'), +('2', '128', '2382', 'Generic'), +('2', '128', '2479', 'Honorless Target'), +('2', '128', '3050', 'Detect'), +('2', '128', '3365', 'Opening'), +('2', '128', '5009', 'Wands'), +('2', '128', '5019', 'Shoot'), +('2', '128', '6233', 'Closing'), +('2', '128', '6246', 'Closing'), +('2', '128', '6247', 'Opening'), +('2', '128', '6477', 'Opening'), +('2', '128', '6478', 'Opening'), +('2', '128', '6603', 'Attack'), +('2', '128', '7266', 'Duel'), +('2', '128', '7267', 'Grovel'), +('2', '128', '7355', 'Stuck'), +('2', '128', '8386', 'Attacking'), +('2', '128', '9078', 'Cloth'), +('2', '128', '9125', 'Generic'), +('2', '128', '21651', 'Opening'), +('2', '128', '21652', 'Closing'), +('2', '128', '22027', 'Remove Insignia'), +('2', '128', '22810', 'Opening - No Text'), +('2', '128', '27126', null), +('2', '128', '27070', null), +('2', '128', '22018', null), +('2', '128', '27072', null), +('2', '128', '22019', null), +('2', '128', '27079', null), +('2', '128', '38704', null), +('2', '128', '28272', null), +('2', '128', '28271', null), +('2', '128', '12826', null), +('2', '128', '27088', null), +('2', '128', '33944', null), +('2', '128', '130', null), +('2', '128', '27082', null), +('2', '128', '27086', null), +('2', '128', '33946', null), +('2', '128', '475', null), +('2', '128', '1953', null), +('2', '128', '27085', null), +('2', '128', '12051', null), +('2', '128', '27128', null), +('2', '128', '27131', null), +('2', '128', '32796', null), +('2', '128', '27074', null), +('2', '128', '2139', null), +('2', '128', '27101', null), +('2', '128', '27124', null), +('2', '128', '45438', null), +('2', '128', '27125', null), +('2', '128', '27127', null), +('2', '128', '30482', null), +('2', '128', '30451', null), +('2', '128', '30455', null), +('2', '128', '66', null), +('2', '128', '43987', null), +('2', '128', '30449', null), +('2', '128', '27087', null), +('2', '1024', '669', 'Language Orcish'), +('2', '1024', '20572', 'Blood Fury'), +('2', '1024', '20573', 'Hardiness'), +('2', '1024', '20574', 'Axe Specialization'), +('2', '1024', '81', 'Dodge'), +('2', '1024', '198', 'One-Handed Maces'), +('2', '1024', '203', 'Unarmed'), +('2', '1024', '204', 'Defense'), +('2', '1024', '227', 'Staves'), +('2', '1024', '522', 'SPELLDEFENSE(DND)'), +('2', '1024', '1178', 'Bear Form(Passive)'), +('2', '1024', '2382', 'Generic'), +('2', '1024', '2479', 'Honorless Target'), +('2', '1024', '3025', 'Cat Form(Passive)'), +('2', '1024', '3050', 'Detect'), +('2', '1024', '3365', 'Opening'), +('2', '1024', '5176', 'Wrath'), +('2', '1024', '5185', 'Healing Touch'), +('2', '1024', '5419', 'Travel Form(Passive)'), +('2', '1024', '5420', 'Tree of Life'), +('2', '1024', '5421', 'Aquatic Form(Passive)'), +('2', '1024', '6233', 'Closing'), +('2', '1024', '6246', 'Closing'), +('2', '1024', '6247', 'Opening'), +('2', '1024', '6477', 'Opening'), +('2', '1024', '6478', 'Opening'), +('2', '1024', '6603', 'Attack'), +('2', '1024', '7266', 'Duel'), +('2', '1024', '7267', 'Grovel'), +('2', '1024', '7355', 'Stuck'), +('2', '1024', '8386', 'Attacking'), +('2', '1024', '9077', 'Leather'), +('2', '1024', '9078', 'Cloth'), +('2', '1024', '9125', 'Generic'), +('2', '1024', '9635', 'Dire Bear Form(Passive)'), +('2', '1024', '21178', 'Bear Form(Passive2)'), +('2', '1024', '21651', 'Opening'), +('2', '1024', '21652', 'Closing'), +('2', '1024', '22027', 'Remove Insignia'), +('2', '1024', '22810', 'Opening - No Text'), +('2', '1024', '24905', 'Moonkin Form(Passive)'), +('2', '1024', '27764', 'Fetish'), +('2', '1024', '33948', 'Flight Form(Passive)'), +('2', '1024', '34123', 'Tree of Life(Passive)'), +('2', '1024', '40121', 'Swift Flight Form(Passive)'), +('2', '1024', '26979', null), +('2', '1024', '26990', null), +('2', '1024', '26985', null), +('2', '1024', '26988', null), +('2', '1024', '26982', null), +('2', '1024', '26992', null), +('2', '1024', '26989', null), +('2', '1024', '26998', null), +('2', '1024', '6795', null), +('2', '1024', '26996', null), +('2', '1024', '18960', null), +('2', '1024', '9634', null), +('2', '1024', '768', null), +('2', '1024', '783', null), +('2', '1024', '1066', null), +('2', '1024', '40120', null), +('2', '1024', '5229', null), +('2', '1024', '26980', null), +('2', '1024', '8983', null), +('2', '1024', '8946', null), +('2', '1024', '26997', null), +('2', '1024', '26993', null), +('2', '1024', '18658', null), +('2', '1024', '27000', null), +('2', '1024', '9913', null), +('2', '1024', '26994', null), +('2', '1024', '27008', null), +('2', '1024', '26986', null), +('2', '1024', '27002', null), +('2', '1024', '26995', null), +('2', '1024', '27003', null), +('2', '1024', '2782', null), +('2', '1024', '9846', null), +('2', '1024', '2893', null), +('2', '1024', '33357', null), +('2', '1024', '5209', null), +('2', '1024', '27004', null), +('2', '1024', '26983', null), +('2', '1024', '24248', null), +('2', '1024', '27005', null), +('2', '1024', '5225', null), +('2', '1024', '26999', null), +('2', '1024', '27012', null), +('2', '1024', '27006', null), +('2', '1024', '29166', null), +('2', '1024', '22812', null), +('2', '1024', '26991', null), +('2', '1024', '22570', null), +('2', '1024', '33763', null), +('2', '1024', '33745', null), +('2', '1024', '33786', null), +('2', '1024', '20719', null), +('128', '2', '7341', 'Language Troll'), +('128', '2', '20555', 'Regeneration'), +('128', '2', '20557', 'Beast Slaying'), +('128', '2', '20558', 'Throwing Specialization'), +('128', '2', '26290', 'Bow Specialization'), +('128', '2', '26296', 'Berserking'), +('128', '2', '669', 'Language Orcish'), +('128', '2', '81', 'Dodge'), +('128', '2', '107', 'Block'), +('128', '2', '198', 'One-Handed Maces'), +('128', '2', '199', 'Two-Handed Maces'), +('128', '2', '203', 'Unarmed'), +('128', '2', '204', 'Defense'), +('128', '2', '522', 'SPELLDEFENSE(DND)'), +('128', '2', '635', 'Holy Light'), +('128', '2', '2382', 'Generic'), +('128', '2', '2479', 'Honorless Target'), +('128', '2', '3050', 'Detect'), +('128', '2', '3365', 'Opening'), +('128', '2', '6233', 'Closing'), +('128', '2', '6246', 'Closing'), +('128', '2', '6247', 'Opening'), +('128', '2', '6477', 'Opening'), +('128', '2', '6478', 'Opening'), +('128', '2', '6603', 'Attack'), +('128', '2', '7266', 'Duel'), +('128', '2', '7267', 'Grovel'), +('128', '2', '7355', 'Stuck'), +('128', '2', '8386', 'Attacking'), +('128', '2', '8737', 'Mail'), +('128', '2', '9077', 'Leather'), +('128', '2', '9078', 'Cloth'), +('128', '2', '9116', 'Shield'), +('128', '2', '9125', 'Generic'), +('128', '2', '21084', 'Seal of Righteousness'), +('128', '2', '21651', 'Opening'), +('128', '2', '21652', 'Closing'), +('128', '2', '22027', 'Remove Insignia'), +('128', '2', '22810', 'Opening - No Text'), +('128', '2', '27762', 'Libram'), +('128', '2', '27149', null), +('128', '2', '27136', null), +('128', '2', '27155', null), +('128', '2', '27140', null), +('128', '2', '20271', null), +('128', '2', '27158', null), +('128', '2', '10308', null), +('128', '2', '10278', null), +('128', '2', '27154', null), +('128', '2', '20773', null), +('128', '2', '27142', null), +('128', '2', '31789', null), +('128', '2', '27150', null), +('128', '2', '25780', null), +('128', '2', '1044', null), +('128', '2', '33776', null), +('128', '2', '27173', null), +('128', '2', '27138', null), +('128', '2', '27137', null), +('128', '2', '5502', null), +('128', '2', '19746', null), +('128', '2', '31895', null), +('128', '2', '5627', null), +('128', '2', '1038', null), +('128', '2', '27151', null), +('128', '2', '19752', null), +('128', '2', '27160', null), +('128', '2', '27152', null), +('128', '2', '1020', null), +('128', '2', '27153', null), +('128', '2', '27166', null), +('128', '2', '27144', null), +('128', '2', '4987', null), +('128', '2', '27180', null), +('128', '2', '27148', null), +('128', '2', '27139', null), +('128', '2', '27141', null), +('128', '2', '10326', null), +('128', '2', '27143', null), +('128', '2', '25898', null), +('128', '2', '27145', null), +('128', '2', '25895', null), +('128', '2', '32223', null), +('128', '2', '27169', null), +('128', '2', '31884', null), +('128', '2', '750', null), +('128', '2', '3127', null), +('128', '2', '23214', null), +('128', '2', '31801', null), +('128', '256', '7341', 'Language Troll'), +('128', '256', '20555', 'Regeneration'), +('128', '256', '20557', 'Beast Slaying'), +('128', '256', '20558', 'Throwing Specialization'), +('128', '256', '26290', 'Bow Specialization'), +('128', '256', '26296', 'Berserking'), +('128', '256', '81', 'Dodge'), +('128', '256', '203', 'Unarmed'), +('128', '256', '204', 'Defense'), +('128', '256', '522', 'SPELLDEFENSE(DND)'), +('128', '256', '669', 'Language Orcish'), +('128', '256', '686', 'Shadow Bolt'), +('128', '256', '687', 'Demon Skin'), +('128', '256', '1180', 'Daggers'), +('128', '256', '2382', 'Generic'), +('128', '256', '2479', 'Honorless Target'), +('128', '256', '3050', 'Detect'), +('128', '256', '3365', 'Opening'), +('128', '256', '5009', 'Wands'), +('128', '256', '5019', 'Shoot'), +('128', '256', '6233', 'Closing'), +('128', '256', '6246', 'Closing'), +('128', '256', '6247', 'Opening'), +('128', '256', '6477', 'Opening'), +('128', '256', '6478', 'Opening'), +('128', '256', '6603', 'Attack'), +('128', '256', '7266', 'Duel'), +('128', '256', '7267', 'Grovel'), +('128', '256', '7355', 'Stuck'), +('128', '256', '8386', 'Attacking'), +('128', '256', '9078', 'Cloth'), +('128', '256', '9125', 'Generic'), +('128', '256', '21651', 'Opening'), +('128', '256', '21652', 'Closing'), +('128', '256', '22027', 'Remove Insignia'), +('128', '256', '22810', 'Opening - No Text'), +('128', '256', '27215', null), +('128', '256', '27209', null), +('128', '256', '27216', null), +('128', '256', '30909', null), +('128', '256', '27222', null), +('128', '256', '27218', null), +('128', '256', '6215', null), +('128', '256', '27230', null), +('128', '256', '27217', null), +('128', '256', '27259', null), +('128', '256', '27226', null), +('128', '256', '27220', null), +('128', '256', '5697', null), +('128', '256', '27238', null), +('128', '256', '30459', null), +('128', '256', '27260', null), +('128', '256', '27212', null), +('128', '256', '698', null), +('128', '256', '5500', null), +('128', '256', '30908', null), +('128', '256', '11719', null), +('128', '256', '132', null), +('128', '256', '18647', null), +('128', '256', '27213', null), +('128', '256', '11726', null), +('128', '256', '27228', null), +('128', '256', '28610', null), +('128', '256', '28172', null), +('128', '256', '27250', null), +('128', '256', '17928', null), +('128', '256', '27223', null), +('128', '256', '27229', null), +('128', '256', '30545', null), +('128', '256', '30910', null), +('128', '256', '18540', null), +('128', '256', '28189', null), +('128', '256', '32231', null), +('128', '256', '29858', null), +('128', '256', '29893', null), +('128', '256', '27243', null), +('128', '256', '23161', null), +('128', '256', '688', null), +('128', '256', '697', null), +('128', '256', '712', null), +('128', '256', '691', null), +('128', '256', '126', null), +('128', '1024', '7341', 'Language Troll'), +('128', '1024', '20555', 'Regeneration'), +('128', '1024', '20557', 'Beast Slaying'), +('128', '1024', '20558', 'Throwing Specialization'), +('128', '1024', '26290', 'Bow Specialization'), +('128', '1024', '26296', 'Berserking'), +('128', '1024', '669', 'Language Orcish'), +('128', '1024', '81', 'Dodge'), +('128', '1024', '198', 'One-Handed Maces'), +('128', '1024', '203', 'Unarmed'), +('128', '1024', '204', 'Defense'), +('128', '1024', '227', 'Staves'), +('128', '1024', '522', 'SPELLDEFENSE(DND)'), +('128', '1024', '1178', 'Bear Form(Passive)'), +('128', '1024', '2382', 'Generic'), +('128', '1024', '2479', 'Honorless Target'), +('128', '1024', '3025', 'Cat Form(Passive)'), +('128', '1024', '3050', 'Detect'), +('128', '1024', '3365', 'Opening'), +('128', '1024', '5176', 'Wrath'), +('128', '1024', '5185', 'Healing Touch'), +('128', '1024', '5419', 'Travel Form(Passive)'), +('128', '1024', '5420', 'Tree of Life'), +('128', '1024', '5421', 'Aquatic Form(Passive)'), +('128', '1024', '6233', 'Closing'), +('128', '1024', '6246', 'Closing'), +('128', '1024', '6247', 'Opening'), +('128', '1024', '6477', 'Opening'), +('128', '1024', '6478', 'Opening'), +('128', '1024', '6603', 'Attack'), +('128', '1024', '7266', 'Duel'), +('128', '1024', '7267', 'Grovel'), +('128', '1024', '7355', 'Stuck'), +('128', '1024', '8386', 'Attacking'), +('128', '1024', '9077', 'Leather'), +('128', '1024', '9078', 'Cloth'), +('128', '1024', '9125', 'Generic'), +('128', '1024', '9635', 'Dire Bear Form(Passive)'), +('128', '1024', '21178', 'Bear Form(Passive2)'), +('128', '1024', '21651', 'Opening'), +('128', '1024', '21652', 'Closing'), +('128', '1024', '22027', 'Remove Insignia'), +('128', '1024', '22810', 'Opening - No Text'), +('128', '1024', '24905', 'Moonkin Form(Passive)'), +('128', '1024', '27764', 'Fetish'), +('128', '1024', '33948', 'Flight Form(Passive)'), +('128', '1024', '34123', 'Tree of Life(Passive)'), +('128', '1024', '40121', 'Swift Flight Form(Passive)'), +('128', '1024', '26979', null), +('128', '1024', '26990', null), +('128', '1024', '26985', null), +('128', '1024', '26988', null), +('128', '1024', '26982', null), +('128', '1024', '26992', null), +('128', '1024', '26989', null), +('128', '1024', '26998', null), +('128', '1024', '6795', null), +('128', '1024', '26996', null), +('128', '1024', '18960', null), +('128', '1024', '9634', null), +('128', '1024', '768', null), +('128', '1024', '783', null), +('128', '1024', '1066', null), +('128', '1024', '40120', null), +('128', '1024', '5229', null), +('128', '1024', '26980', null), +('128', '1024', '8983', null), +('128', '1024', '8946', null), +('128', '1024', '26997', null), +('128', '1024', '26993', null), +('128', '1024', '18658', null), +('128', '1024', '27000', null), +('128', '1024', '9913', null), +('128', '1024', '26994', null), +('128', '1024', '27008', null), +('128', '1024', '26986', null), +('128', '1024', '27002', null), +('128', '1024', '26995', null), +('128', '1024', '27003', null), +('128', '1024', '2782', null), +('128', '1024', '9846', null), +('128', '1024', '2893', null), +('128', '1024', '33357', null), +('128', '1024', '5209', null), +('128', '1024', '27004', null), +('128', '1024', '26983', null), +('128', '1024', '24248', null), +('128', '1024', '27005', null), +('128', '1024', '5225', null), +('128', '1024', '26999', null), +('128', '1024', '27012', null), +('128', '1024', '27006', null), +('128', '1024', '29166', null), +('128', '1024', '22812', null), +('128', '1024', '26991', null), +('128', '1024', '22570', null), +('128', '1024', '33763', null), +('128', '1024', '33745', null), +('128', '1024', '33786', null), +('128', '1024', '20719', null), +('32', '2', '670', 'Language Taurahe'), +('32', '2', '20549', 'War Stomp'), +('32', '2', '20550', 'Endurance'), +('32', '2', '20551', 'Nature Resistance'), +('32', '2', '20552', 'Cultivation'), +('32', '2', '669', 'Language Orcish'), +('32', '2', '81', 'Dodge'), +('32', '2', '107', 'Block'), +('32', '2', '198', 'One-Handed Maces'), +('32', '2', '199', 'Two-Handed Maces'), +('32', '2', '203', 'Unarmed'), +('32', '2', '204', 'Defense'), +('32', '2', '522', 'SPELLDEFENSE(DND)'), +('32', '2', '635', 'Holy Light'), +('32', '2', '2382', 'Generic'), +('32', '2', '2479', 'Honorless Target'), +('32', '2', '3050', 'Detect'), +('32', '2', '3365', 'Opening'), +('32', '2', '6233', 'Closing'), +('32', '2', '6246', 'Closing'), +('32', '2', '6247', 'Opening'), +('32', '2', '6477', 'Opening'), +('32', '2', '6478', 'Opening'), +('32', '2', '6603', 'Attack'), +('32', '2', '7266', 'Duel'), +('32', '2', '7267', 'Grovel'), +('32', '2', '7355', 'Stuck'), +('32', '2', '8386', 'Attacking'), +('32', '2', '8737', 'Mail'), +('32', '2', '9077', 'Leather'), +('32', '2', '9078', 'Cloth'), +('32', '2', '9116', 'Shield'), +('32', '2', '9125', 'Generic'), +('32', '2', '21084', 'Seal of Righteousness'), +('32', '2', '21651', 'Opening'), +('32', '2', '21652', 'Closing'), +('32', '2', '22027', 'Remove Insignia'), +('32', '2', '22810', 'Opening - No Text'), +('32', '2', '27762', 'Libram'), +('32', '2', '27149', null), +('32', '2', '27136', null), +('32', '2', '27155', null), +('32', '2', '27140', null), +('32', '2', '20271', null), +('32', '2', '27158', null), +('32', '2', '10308', null), +('32', '2', '10278', null), +('32', '2', '27154', null), +('32', '2', '20773', null), +('32', '2', '27142', null), +('32', '2', '31789', null), +('32', '2', '27150', null), +('32', '2', '25780', null), +('32', '2', '1044', null), +('32', '2', '33776', null), +('32', '2', '27173', null), +('32', '2', '27138', null), +('32', '2', '27137', null), +('32', '2', '5502', null), +('32', '2', '19746', null), +('32', '2', '31895', null), +('32', '2', '5627', null), +('32', '2', '1038', null), +('32', '2', '27151', null), +('32', '2', '19752', null), +('32', '2', '27160', null), +('32', '2', '27152', null), +('32', '2', '1020', null), +('32', '2', '27153', null), +('32', '2', '27166', null), +('32', '2', '27144', null), +('32', '2', '4987', null), +('32', '2', '27180', null), +('32', '2', '27148', null), +('32', '2', '27139', null), +('32', '2', '27141', null), +('32', '2', '10326', null), +('32', '2', '27143', null), +('32', '2', '25898', null), +('32', '2', '27145', null), +('32', '2', '25895', null), +('32', '2', '32223', null), +('32', '2', '27169', null), +('32', '2', '31884', null), +('32', '2', '750', null), +('32', '2', '3127', null), +('32', '2', '23214', null), +('32', '2', '31801', null), +('32', '8', '670', 'Language Taurahe'), +('32', '8', '20549', 'War Stomp'), +('32', '8', '20550', 'Endurance'), +('32', '8', '20551', 'Nature Resistance'), +('32', '8', '20552', 'Cultivation'), +('32', '8', '81', 'Dodge'), +('32', '8', '203', 'Unarmed'), +('32', '8', '204', 'Defense'), +('32', '8', '522', 'SPELLDEFENSE(DND)'), +('32', '8', '669', 'Language Orcish'), +('32', '8', '1180', 'Daggers'), +('32', '8', '1752', 'Sinister Strike'), +('32', '8', '2098', 'Eviscerate'), +('32', '8', '2382', 'Generic'), +('32', '8', '2479', 'Honorless Target'), +('32', '8', '2567', 'Thrown'), +('32', '8', '2764', 'Throw'), +('32', '8', '3050', 'Detect'), +('32', '8', '3365', 'Opening'), +('32', '8', '6233', 'Closing'), +('32', '8', '6246', 'Closing'), +('32', '8', '6247', 'Opening'), +('32', '8', '6477', 'Opening'), +('32', '8', '6478', 'Opening'), +('32', '8', '6603', 'Attack'), +('32', '8', '7266', 'Duel'), +('32', '8', '7267', 'Grovel'), +('32', '8', '7355', 'Stuck'), +('32', '8', '8386', 'Attacking'), +('32', '8', '9077', 'Leather'), +('32', '8', '9078', 'Cloth'), +('32', '8', '9125', 'Generic'), +('32', '8', '16092', 'Defensive State(DND)'), +('32', '8', '21184', 'Rogue Passive(DND)'), +('32', '8', '21651', 'Opening'), +('32', '8', '21652', 'Closing'), +('32', '8', '22027', 'Remove Insignia'), +('32', '8', '22810', 'Opening - No Text'), +('32', '8', '26865', null), +('32', '8', '26862', null), +('32', '8', '1787', null), +('32', '8', '26863', null), +('32', '8', '921', null), +('32', '8', '38764', null), +('32', '8', '26669', null), +('32', '8', '11297', null), +('32', '8', '6774', null), +('32', '8', '11305', null), +('32', '8', '38768', null), +('32', '8', '26866', null), +('32', '8', '26884', null), +('32', '8', '27448', null), +('32', '8', '1804', null), +('32', '8', '27441', null), +('32', '8', '2842', null), +('32', '8', '1725', null), +('32', '8', '26867', null), +('32', '8', '26889', null), +('32', '8', '1833', null), +('32', '8', '1842', null), +('32', '8', '408', null), +('32', '8', '2094', null), +('32', '8', '32684', null), +('32', '8', '26679', null), +('32', '8', '31224', null), +('32', '8', '5938', null), +('32', '8', '8643', null), +('32', '8', '3127', null), +('32', '8', '674', null), +('32', '8', '3776', null), +('32', '8', '9186', null), +('32', '8', '21927', null), +('32', '8', '22054', null), +('32', '8', '22055', null), +('32', '8', '2836', null), +('32', '8', '1860', null), +('32', '16', '670', 'Language Taurahe'), +('32', '16', '20549', 'War Stomp'), +('32', '16', '20550', 'Endurance'), +('32', '16', '20551', 'Nature Resistance'), +('32', '16', '20552', 'Cultivation'), +('32', '16', '669', 'Language Orcish'), +('32', '16', '81', 'Dodge'), +('32', '16', '198', 'One-Handed Maces'), +('32', '16', '203', 'Unarmed'), +('32', '16', '204', 'Defense'), +('32', '16', '522', 'SPELLDEFENSE(DND)'), +('32', '16', '585', 'Smite'), +('32', '16', '2050', 'Lesser Heal'), +('32', '16', '2382', 'Generic'), +('32', '16', '2479', 'Honorless Target'), +('32', '16', '3050', 'Detect'), +('32', '16', '3365', 'Opening'), +('32', '16', '5009', 'Wands'), +('32', '16', '5019', 'Shoot'), +('32', '16', '6233', 'Closing'), +('32', '16', '6246', 'Closing'), +('32', '16', '6247', 'Opening'), +('32', '16', '6477', 'Opening'), +('32', '16', '6478', 'Opening'), +('32', '16', '6603', 'Attack'), +('32', '16', '7266', 'Duel'), +('32', '16', '7267', 'Grovel'), +('32', '16', '7355', 'Stuck'), +('32', '16', '8386', 'Attacking'), +('32', '16', '9078', 'Cloth'), +('32', '16', '9125', 'Generic'), +('32', '16', '21651', 'Opening'), +('32', '16', '21652', 'Closing'), +('32', '16', '22027', 'Remove Insignia'), +('32', '16', '22810', 'Opening - No Text'), +('32', '16', '25389', null), +('32', '16', '25364', null), +('32', '16', '25368', null), +('32', '16', '25218', null), +('32', '16', '25429', null), +('32', '16', '25222', null), +('32', '16', '25375', null), +('32', '16', '25435', null), +('32', '16', '25431', null), +('32', '16', '528', null), +('32', '16', '10890', null), +('32', '16', '988', null), +('32', '16', '6346', null), +('32', '16', '25235', null), +('32', '16', '25384', null), +('32', '16', '25596', null), +('32', '16', '10955', null), +('32', '16', '10909', null), +('32', '16', '25380', null), +('32', '16', '10912', null), +('32', '16', '25308', null), +('32', '16', '25433', null), +('32', '16', '552', null), +('32', '16', '1706', null), +('32', '16', '25213', null), +('32', '16', '25392', null), +('32', '16', '39374', null), +('32', '16', '32999', null), +('32', '16', '32996', null), +('32', '16', '32546', null), +('32', '16', '34433', null), +('32', '16', '33076', null), +('32', '16', '32375', null), +('32', '16', '25441', null), +('32', '16', '25312', null), +('32', '16', '25437', null), +('32', '128', '670', 'Language Taurahe'), +('32', '128', '20549', 'War Stomp'), +('32', '128', '20550', 'Endurance'), +('32', '128', '20551', 'Nature Resistance'), +('32', '128', '20552', 'Cultivation'), +('32', '128', '669', 'Language Orcish'), +('32', '128', '81', 'Dodge'), +('32', '128', '133', 'Fireball'), +('32', '128', '168', 'Frost Armor'), +('32', '128', '203', 'Unarmed'), +('32', '128', '204', 'Defense'), +('32', '128', '227', 'Staves'), +('32', '128', '522', 'SPELLDEFENSE(DND)'), +('32', '128', '2382', 'Generic'), +('32', '128', '2479', 'Honorless Target'), +('32', '128', '3050', 'Detect'), +('32', '128', '3365', 'Opening'), +('32', '128', '5009', 'Wands'), +('32', '128', '5019', 'Shoot'), +('32', '128', '6233', 'Closing'), +('32', '128', '6246', 'Closing'), +('32', '128', '6247', 'Opening'), +('32', '128', '6477', 'Opening'), +('32', '128', '6478', 'Opening'), +('32', '128', '6603', 'Attack'), +('32', '128', '7266', 'Duel'), +('32', '128', '7267', 'Grovel'), +('32', '128', '7355', 'Stuck'), +('32', '128', '8386', 'Attacking'), +('32', '128', '9078', 'Cloth'), +('32', '128', '9125', 'Generic'), +('32', '128', '21651', 'Opening'), +('32', '128', '21652', 'Closing'), +('32', '128', '22027', 'Remove Insignia'), +('32', '128', '22810', 'Opening - No Text'), +('32', '128', '27126', null), +('32', '128', '27070', null), +('32', '128', '22018', null), +('32', '128', '27072', null), +('32', '128', '22019', null), +('32', '128', '27079', null), +('32', '128', '38704', null), +('32', '128', '28272', null), +('32', '128', '28271', null), +('32', '128', '12826', null), +('32', '128', '27088', null), +('32', '128', '33944', null), +('32', '128', '130', null), +('32', '128', '27082', null), +('32', '128', '27086', null), +('32', '128', '33946', null), +('32', '128', '475', null), +('32', '128', '1953', null), +('32', '128', '27085', null), +('32', '128', '12051', null), +('32', '128', '27128', null), +('32', '128', '27131', null), +('32', '128', '32796', null), +('32', '128', '27074', null), +('32', '128', '2139', null), +('32', '128', '27101', null), +('32', '128', '27124', null), +('32', '128', '45438', null), +('32', '128', '27125', null), +('32', '128', '27127', null), +('32', '128', '30482', null), +('32', '128', '30451', null), +('32', '128', '30455', null), +('32', '128', '66', null), +('32', '128', '43987', null), +('32', '128', '30449', null), +('32', '128', '27087', null), +('32', '256', '670', 'Language Taurahe'), +('32', '256', '20549', 'War Stomp'), +('32', '256', '20550', 'Endurance'), +('32', '256', '20551', 'Nature Resistance'), +('32', '256', '20552', 'Cultivation'), +('32', '256', '81', 'Dodge'), +('32', '256', '203', 'Unarmed'), +('32', '256', '204', 'Defense'), +('32', '256', '522', 'SPELLDEFENSE(DND)'), +('32', '256', '669', 'Language Orcish'), +('32', '256', '686', 'Shadow Bolt'), +('32', '256', '687', 'Demon Skin'), +('32', '256', '1180', 'Daggers'), +('32', '256', '2382', 'Generic'), +('32', '256', '2479', 'Honorless Target'), +('32', '256', '3050', 'Detect'), +('32', '256', '3365', 'Opening'), +('32', '256', '5009', 'Wands'), +('32', '256', '5019', 'Shoot'), +('32', '256', '6233', 'Closing'), +('32', '256', '6246', 'Closing'), +('32', '256', '6247', 'Opening'), +('32', '256', '6477', 'Opening'), +('32', '256', '6478', 'Opening'), +('32', '256', '6603', 'Attack'), +('32', '256', '7266', 'Duel'), +('32', '256', '7267', 'Grovel'), +('32', '256', '7355', 'Stuck'), +('32', '256', '8386', 'Attacking'), +('32', '256', '9078', 'Cloth'), +('32', '256', '9125', 'Generic'), +('32', '256', '21651', 'Opening'), +('32', '256', '21652', 'Closing'), +('32', '256', '22027', 'Remove Insignia'), +('32', '256', '22810', 'Opening - No Text'), +('32', '256', '27215', null), +('32', '256', '27209', null), +('32', '256', '27216', null), +('32', '256', '30909', null), +('32', '256', '27222', null), +('32', '256', '27218', null), +('32', '256', '6215', null), +('32', '256', '27230', null), +('32', '256', '27217', null), +('32', '256', '27259', null), +('32', '256', '27226', null), +('32', '256', '27220', null), +('32', '256', '5697', null), +('32', '256', '27238', null), +('32', '256', '30459', null), +('32', '256', '27260', null), +('32', '256', '27212', null), +('32', '256', '698', null), +('32', '256', '5500', null), +('32', '256', '30908', null), +('32', '256', '11719', null), +('32', '256', '132', null), +('32', '256', '18647', null), +('32', '256', '27213', null), +('32', '256', '11726', null), +('32', '256', '27228', null), +('32', '256', '28610', null), +('32', '256', '28172', null), +('32', '256', '27250', null), +('32', '256', '17928', null), +('32', '256', '27223', null), +('32', '256', '27229', null), +('32', '256', '30545', null), +('32', '256', '30910', null), +('32', '256', '18540', null), +('32', '256', '28189', null), +('32', '256', '32231', null), +('32', '256', '29858', null), +('32', '256', '29893', null), +('32', '256', '27243', null), +('32', '256', '23161', null), +('32', '256', '688', null), +('32', '256', '697', null), +('32', '256', '712', null), +('32', '256', '691', null), +('32', '256', '126', null), +('16', '2', '5227', 'Underwater Breathing'), +('16', '2', '7744', 'Will of the Forsaken'), +('16', '2', '17737', 'Language Gutterspeak'), +('16', '2', '20577', 'Cannibalize'), +('16', '2', '20579', 'Shadow Resistance'), +('16', '2', '669', 'Language Orcish'), +('16', '2', '81', 'Dodge'), +('16', '2', '107', 'Block'), +('16', '2', '198', 'One-Handed Maces'), +('16', '2', '199', 'Two-Handed Maces'), +('16', '2', '203', 'Unarmed'), +('16', '2', '204', 'Defense'), +('16', '2', '522', 'SPELLDEFENSE(DND)'), +('16', '2', '635', 'Holy Light'), +('16', '2', '2382', 'Generic'), +('16', '2', '2479', 'Honorless Target'), +('16', '2', '3050', 'Detect'), +('16', '2', '3365', 'Opening'), +('16', '2', '6233', 'Closing'), +('16', '2', '6246', 'Closing'), +('16', '2', '6247', 'Opening'), +('16', '2', '6477', 'Opening'), +('16', '2', '6478', 'Opening'), +('16', '2', '6603', 'Attack'), +('16', '2', '7266', 'Duel'), +('16', '2', '7267', 'Grovel'), +('16', '2', '7355', 'Stuck'), +('16', '2', '8386', 'Attacking'), +('16', '2', '8737', 'Mail'), +('16', '2', '9077', 'Leather'), +('16', '2', '9078', 'Cloth'), +('16', '2', '9116', 'Shield'), +('16', '2', '9125', 'Generic'), +('16', '2', '21084', 'Seal of Righteousness'), +('16', '2', '21651', 'Opening'), +('16', '2', '21652', 'Closing'), +('16', '2', '22027', 'Remove Insignia'), +('16', '2', '22810', 'Opening - No Text'), +('16', '2', '27762', 'Libram'), +('16', '2', '27149', null), +('16', '2', '27136', null), +('16', '2', '27155', null), +('16', '2', '27140', null), +('16', '2', '20271', null), +('16', '2', '27158', null), +('16', '2', '10308', null), +('16', '2', '10278', null), +('16', '2', '27154', null), +('16', '2', '20773', null), +('16', '2', '27142', null), +('16', '2', '31789', null), +('16', '2', '27150', null), +('16', '2', '25780', null), +('16', '2', '1044', null), +('16', '2', '33776', null), +('16', '2', '27173', null), +('16', '2', '27138', null), +('16', '2', '27137', null), +('16', '2', '5502', null), +('16', '2', '19746', null), +('16', '2', '31895', null), +('16', '2', '5627', null), +('16', '2', '1038', null), +('16', '2', '27151', null), +('16', '2', '19752', null), +('16', '2', '27160', null), +('16', '2', '27152', null), +('16', '2', '1020', null), +('16', '2', '27153', null), +('16', '2', '27166', null), +('16', '2', '27144', null), +('16', '2', '4987', null), +('16', '2', '27180', null), +('16', '2', '27148', null), +('16', '2', '27139', null), +('16', '2', '27141', null), +('16', '2', '10326', null), +('16', '2', '27143', null), +('16', '2', '25898', null), +('16', '2', '27145', null), +('16', '2', '25895', null), +('16', '2', '32223', null), +('16', '2', '27169', null), +('16', '2', '31884', null), +('16', '2', '750', null), +('16', '2', '3127', null), +('16', '2', '23214', null), +('16', '2', '31801', null), +('16', '4', '5227', 'Underwater Breathing'), +('16', '4', '7744', 'Will of the Forsaken'), +('16', '4', '17737', 'Language Gutterspeak'), +('16', '4', '20577', 'Cannibalize'), +('16', '4', '20579', 'Shadow Resistance'), +('16', '4', '75', 'Auto Shot'), +('16', '4', '81', 'Dodge'), +('16', '4', '196', 'One-Handed Axes'), +('16', '4', '203', 'Unarmed'), +('16', '4', '204', 'Defense'), +('16', '4', '264', 'Bows'), +('16', '4', '266', 'Guns'), +('16', '4', '522', 'SPELLDEFENSE(DND)'), +('16', '4', '669', 'Language Orcish'), +('16', '4', '2382', 'Generic'), +('16', '4', '2479', 'Honorless Target'), +('16', '4', '2973', 'Raptor Strike'), +('16', '4', '3050', 'Detect'), +('16', '4', '3365', 'Opening'), +('16', '4', '6233', 'Closing'), +('16', '4', '6246', 'Closing'), +('16', '4', '6247', 'Opening'), +('16', '4', '6477', 'Opening'), +('16', '4', '6478', 'Opening'), +('16', '4', '6603', 'Attack'), +('16', '4', '7266', 'Duel'), +('16', '4', '7267', 'Grovel'), +('16', '4', '7355', 'Stuck'), +('16', '4', '8386', 'Attacking'), +('16', '4', '9077', 'Leather'), +('16', '4', '9078', 'Cloth'), +('16', '4', '9125', 'Generic'), +('16', '4', '13358', 'Defensive State(DND)'), +('16', '4', '21651', 'Opening'), +('16', '4', '21652', 'Closing'), +('16', '4', '22027', 'Remove Insignia'), +('16', '4', '22810', 'Opening - No Text'), +('16', '4', '24949', 'Defensive State 2(DND)'), +('16', '4', '34082', 'Advantaged State(DND)'), +('16', '4', '27014', null), +('16', '4', '1494', null), +('16', '4', '13163', null), +('16', '4', '27016', null), +('16', '4', '27019', null), +('16', '4', '14325', null), +('16', '4', '5116', null), +('16', '4', '27044', null), +('16', '4', '883', null), +('16', '4', '2641', null), +('16', '4', '6991', null), +('16', '4', '982', null), +('16', '4', '1515', null), +('16', '4', '19883', null), +('16', '4', '27020', null), +('16', '4', '27046', null), +('16', '4', '14268', null), +('16', '4', '6197', null), +('16', '4', '1002', null), +('16', '4', '14327', null), +('16', '4', '27023', null), +('16', '4', '36916', null), +('16', '4', '27021', null), +('16', '4', '19884', null), +('16', '4', '5118', null), +('16', '4', '27015', null), +('16', '4', '14311', null), +('16', '4', '3043', null), +('16', '4', '1462', null), +('16', '4', '19885', null), +('16', '4', '3045', null), +('16', '4', '19880', null), +('16', '4', '13809', null), +('16', '4', '13161', null), +('16', '4', '5384', null), +('16', '4', '1543', null), +('16', '4', '19878', null), +('16', '4', '27025', null), +('16', '4', '27018', null), +('16', '4', '13159', null), +('16', '4', '19882', null), +('16', '4', '27022', null), +('16', '4', '27045', null), +('16', '4', '19879', null), +('16', '4', '19801', null), +('16', '4', '34120', null), +('16', '4', '34074', null), +('16', '4', '34026', null), +('16', '4', '34600', null), +('16', '4', '34477', null), +('16', '4', '674', null), +('16', '4', '8737', null), +('16', '4', '5149', null), +('16', '4', '3127', null), +('16', '64', '5227', 'Underwater Breathing'), +('16', '64', '7744', 'Will of the Forsaken'), +('16', '64', '17737', 'Language Gutterspeak'), +('16', '64', '20577', 'Cannibalize'), +('16', '64', '20579', 'Shadow Resistance'), +('16', '64', '81', 'Dodge'), +('16', '64', '107', 'Block'), +('16', '64', '198', 'One-Handed Maces'), +('16', '64', '203', 'Unarmed'), +('16', '64', '204', 'Defense'), +('16', '64', '227', 'Staves'), +('16', '64', '331', 'Healing Wave'), +('16', '64', '403', 'Lightning Bolt'), +('16', '64', '522', 'SPELLDEFENSE(DND)'), +('16', '64', '669', 'Language Orcish'), +('16', '64', '2382', 'Generic'), +('16', '64', '2479', 'Honorless Target'), +('16', '64', '3050', 'Detect'), +('16', '64', '3365', 'Opening'), +('16', '64', '6233', 'Closing'), +('16', '64', '6246', 'Closing'), +('16', '64', '6247', 'Opening'), +('16', '64', '6477', 'Opening'), +('16', '64', '6478', 'Opening'), +('16', '64', '6603', 'Attack'), +('16', '64', '7266', 'Duel'), +('16', '64', '7267', 'Grovel'), +('16', '64', '7355', 'Stuck'), +('16', '64', '8386', 'Attacking'), +('16', '64', '9077', 'Leather'), +('16', '64', '9078', 'Cloth'), +('16', '64', '9116', 'Shield'), +('16', '64', '9125', 'Generic'), +('16', '64', '21651', 'Opening'), +('16', '64', '21652', 'Closing'), +('16', '64', '22027', 'Remove Insignia'), +('16', '64', '22810', 'Opening - No Text'), +('16', '64', '27763', 'Totem'), +('16', '64', '25396', null), +('16', '64', '25449', null), +('16', '64', '25485', null), +('16', '64', '25454', null), +('16', '64', '25509', null), +('16', '64', '2484', null), +('16', '64', '25472', null), +('16', '64', '25525', null), +('16', '64', '25457', null), +('16', '64', '25489', null), +('16', '64', '25533', null), +('16', '64', '25528', null), +('16', '64', '20777', null), +('16', '64', '25547', null), +('16', '64', '8012', null), +('16', '64', '526', null), +('16', '64', '8143', null), +('16', '64', '25464', null), +('16', '64', '25500', null), +('16', '64', '2645', null), +('16', '64', '25567', null), +('16', '64', '25420', null), +('16', '64', '2870', null), +('16', '64', '8166', null), +('16', '64', '131', null), +('16', '64', '25560', null), +('16', '64', '6196', null), +('16', '64', '25552', null), +('16', '64', '25570', null), +('16', '64', '25563', null), +('16', '64', '25557', null), +('16', '64', '546', null), +('16', '64', '556', null), +('16', '64', '8177', null), +('16', '64', '25574', null), +('16', '64', '36936', null), +('16', '64', '25505', null), +('16', '64', '421', null), +('16', '64', '25587', null), +('16', '64', '6495', null), +('16', '64', '25577', null), +('16', '64', '8170', null), +('16', '64', '25423', null), +('16', '64', '25359', null), +('16', '64', '25908', null), +('16', '64', '33736', null), +('16', '64', '3738', null), +('16', '64', '2062', null), +('16', '64', '2894', null), +('16', '64', '2825', null), +('16', '64', '25442', null), +('16', '64', '8737', null), +('16', '64', '20608', null), +('16', '1024', '5227', 'Underwater Breathing'), +('16', '1024', '7744', 'Will of the Forsaken'), +('16', '1024', '17737', 'Language Gutterspeak'), +('16', '1024', '20577', 'Cannibalize'), +('16', '1024', '20579', 'Shadow Resistance'), +('16', '1024', '669', 'Language Orcish'), +('16', '1024', '81', 'Dodge'), +('16', '1024', '198', 'One-Handed Maces'), +('16', '1024', '203', 'Unarmed'), +('16', '1024', '204', 'Defense'), +('16', '1024', '227', 'Staves'), +('16', '1024', '522', 'SPELLDEFENSE(DND)'), +('16', '1024', '1178', 'Bear Form(Passive)'), +('16', '1024', '2382', 'Generic'), +('16', '1024', '2479', 'Honorless Target'), +('16', '1024', '3025', 'Cat Form(Passive)'), +('16', '1024', '3050', 'Detect'), +('16', '1024', '3365', 'Opening'), +('16', '1024', '5176', 'Wrath'), +('16', '1024', '5185', 'Healing Touch'), +('16', '1024', '5419', 'Travel Form(Passive)'), +('16', '1024', '5420', 'Tree of Life'), +('16', '1024', '5421', 'Aquatic Form(Passive)'), +('16', '1024', '6233', 'Closing'), +('16', '1024', '6246', 'Closing'), +('16', '1024', '6247', 'Opening'), +('16', '1024', '6477', 'Opening'), +('16', '1024', '6478', 'Opening'), +('16', '1024', '6603', 'Attack'), +('16', '1024', '7266', 'Duel'), +('16', '1024', '7267', 'Grovel'), +('16', '1024', '7355', 'Stuck'), +('16', '1024', '8386', 'Attacking'), +('16', '1024', '9077', 'Leather'), +('16', '1024', '9078', 'Cloth'), +('16', '1024', '9125', 'Generic'), +('16', '1024', '9635', 'Dire Bear Form(Passive)'), +('16', '1024', '21178', 'Bear Form(Passive2)'), +('16', '1024', '21651', 'Opening'), +('16', '1024', '21652', 'Closing'), +('16', '1024', '22027', 'Remove Insignia'), +('16', '1024', '22810', 'Opening - No Text'), +('16', '1024', '24905', 'Moonkin Form(Passive)'), +('16', '1024', '27764', 'Fetish'), +('16', '1024', '33948', 'Flight Form(Passive)'), +('16', '1024', '34123', 'Tree of Life(Passive)'), +('16', '1024', '40121', 'Swift Flight Form(Passive)'), +('16', '1024', '26979', null), +('16', '1024', '26990', null), +('16', '1024', '26985', null), +('16', '1024', '26988', null), +('16', '1024', '26982', null), +('16', '1024', '26992', null), +('16', '1024', '26989', null), +('16', '1024', '26998', null), +('16', '1024', '6795', null), +('16', '1024', '26996', null), +('16', '1024', '18960', null), +('16', '1024', '9634', null), +('16', '1024', '768', null), +('16', '1024', '783', null), +('16', '1024', '1066', null), +('16', '1024', '40120', null), +('16', '1024', '5229', null), +('16', '1024', '26980', null), +('16', '1024', '8983', null), +('16', '1024', '8946', null), +('16', '1024', '26997', null), +('16', '1024', '26993', null), +('16', '1024', '18658', null), +('16', '1024', '27000', null), +('16', '1024', '9913', null), +('16', '1024', '26994', null), +('16', '1024', '27008', null), +('16', '1024', '26986', null), +('16', '1024', '27002', null), +('16', '1024', '26995', null), +('16', '1024', '27003', null), +('16', '1024', '2782', null), +('16', '1024', '9846', null), +('16', '1024', '2893', null), +('16', '1024', '33357', null), +('16', '1024', '5209', null), +('16', '1024', '27004', null), +('16', '1024', '26983', null), +('16', '1024', '24248', null), +('16', '1024', '27005', null), +('16', '1024', '5225', null), +('16', '1024', '26999', null), +('16', '1024', '27012', null), +('16', '1024', '27006', null), +('16', '1024', '29166', null), +('16', '1024', '22812', null), +('16', '1024', '26991', null), +('16', '1024', '22570', null), +('16', '1024', '33763', null), +('16', '1024', '33745', null), +('16', '1024', '33786', null), +('16', '1024', '20719', null); + +-- quest_template + +UPDATE `quest_template` INNER JOIN `quest_template_addon` + ON `quest_template_addon`.id = `quest_template`.id + SET AllowableRaces = 1791 + WHERE `quest_template_addon`.allowableclasses != 0 AND AllowableRaces != 0; \ No newline at end of file diff --git a/modules/mod-auto-resurrect/.editorconfig b/modules/mod-auto-resurrect/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/mod-auto-resurrect/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/mod-auto-resurrect/.git_commit_template.txt b/modules/mod-auto-resurrect/.git_commit_template.txt new file mode 100644 index 0000000..5c5d933 --- /dev/null +++ b/modules/mod-auto-resurrect/.git_commit_template.txt @@ -0,0 +1,45 @@ +### TITLE +## Type(Scope/Subscope): Commit ultra short explanation +## |---- Write below the examples with a maximum of 50 characters ----| +## Example 1: fix(DB/SAI): Missing spell to NPC Hogger +## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros +## Example 3: feat(CORE/Commands): New GM command to do something + +### DESCRIPTION +## Explain why this change is being made, what does it fix etc... +## |---- Write below the examples with a maximum of 72 characters per lines ----| +## Example: Hogger (id: 492) was not charging player when being engaged. + +## Provide links to any issue, commit, pull request or other resource +## Example 1: Closes issue #23 +## Example 2: Ported from other project's commit (link) +## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ + +## ======================================================= +## EXTRA INFOS +## ======================================================= +## "Type" can be: +## feat (new feature) +## fix (bug fix) +## refactor (refactoring production code) +## style (formatting, missing semi colons, etc; no code change) +## docs (changes to documentation) +## test (adding or refactoring tests; no production code change) +## chore (updating bash scripts, git files etc; no production code change) +## -------------------- +## Remember to +## Capitalize the subject line +## Use the imperative mood in the subject line +## Do not end the subject line with a period +## Separate subject from body with a blank line +## Use the body to explain what and why rather than how +## Can use multiple lines with "-" for bullet points in body +## -------------------- +## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ +## ======================================================= +## "Scope" can be: +## CORE (core related, c++) +## DB (database related, sql) +## ======================================================= +## "Subscope" is optional and depends on the nature of the commit. +## ======================================================= diff --git a/modules/mod-auto-resurrect/.gitattributes b/modules/mod-auto-resurrect/.gitattributes new file mode 100644 index 0000000..7ef9001 --- /dev/null +++ b/modules/mod-auto-resurrect/.gitattributes @@ -0,0 +1,105 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto eol=lf + +# Text +*.conf text +*.conf.dist text +*.cmake text + +## Scripts +*.sh text +*.fish text +*.lua text + +## SQL +*.sql text + +## C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + + +## ARCHIVES +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +## EXECUTABLES +*.exe binary +*.pyc binary diff --git a/modules/mod-auto-resurrect/.github/workflows/core-build.yml b/modules/mod-auto-resurrect/.github/workflows/core-build.yml new file mode 100644 index 0000000..f66f694 --- /dev/null +++ b/modules/mod-auto-resurrect/.github/workflows/core-build.yml @@ -0,0 +1,49 @@ +name: core-build +on: + push: + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + compiler: [clang] + runs-on: ubuntu-latest + name: ${{ matrix.compiler }} + env: + COMPILER: ${{ matrix.compiler }} + steps: + - uses: actions/checkout@v2 + with: + repository: 'azerothcore/azerothcore-wotlk' + ref: 'master' + submodules: 'recursive' + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + path: 'modules/skeleton-module' + - name: Cache + uses: actions/cache@v2 + with: + path: /home/runner/.ccache + key: ccache:${{ matrix.compiler }}:${{ github.ref }}:${{ github.sha }} + restore-keys: | + ccache:${{ matrix.compiler }}:${{ github.ref }} + ccache:${{ matrix.compiler }} + - name: Configure OS + run: source ./acore.sh install-deps + env: + CONTINUOUS_INTEGRATION: true + - name: Create conf/config.sh + run: source ./apps/ci/ci-conf.sh + - name: Import db + run: source ./apps/ci/ci-import-db.sh + - name: Build + run: source ./apps/ci/ci-compile.sh + - name: Dry run + run: source ./apps/ci/ci-worldserver-dry-run.sh + - name: Check startup errors + run: source ./apps/ci/ci-error-check.sh + - name: Run unit tests + run: source ./apps/ci/ci-run-unit-tests.sh diff --git a/modules/mod-auto-resurrect/.gitignore b/modules/mod-auto-resurrect/.gitignore new file mode 100644 index 0000000..c6e1299 --- /dev/null +++ b/modules/mod-auto-resurrect/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*.*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-auto-resurrect/LICENSE b/modules/mod-auto-resurrect/LICENSE new file mode 100644 index 0000000..9031171 --- /dev/null +++ b/modules/mod-auto-resurrect/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 AzerothCore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/modules/mod-auto-resurrect/README.md b/modules/mod-auto-resurrect/README.md new file mode 100644 index 0000000..c1310d0 --- /dev/null +++ b/modules/mod-auto-resurrect/README.md @@ -0,0 +1,22 @@ +# Auto Resurrect + +## Description + +This mod allows players to automatically resurrect at the start of an instance or raid when releasing their spirit. + +## Requirements + +- AzerothCore v4.0.0+ + +## Installation + +``` +1) Simply `git clone` the module under the `modules` directory of your AzerothCore source or copy paste it manually. +2) Re-run cmake and launch a clean build of AzerothCore. +3) Go to your server configuration directory (where your `worldserver` or `worldserver.exe` is), copy `mod-auto-resurrect.conf.dist` to `mod-auto-resurrect.conf` and edit that new file +``` + +## Credits + +- [Elmegaard](https://github.com/Elmegaard) (author of the module) +- AzerothCore: [repository](https://github.com/azerothcore) - [website](http://azerothcore.org/) - [discord chat community](https://discord.gg/PaqQRkd) diff --git a/modules/mod-auto-resurrect/conf/conf.sh.dist b/modules/mod-auto-resurrect/conf/conf.sh.dist new file mode 100644 index 0000000..e1a7693 --- /dev/null +++ b/modules/mod-auto-resurrect/conf/conf.sh.dist @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +## CUSTOM SQL - Important file used by the db_assembler.sh +## Keep only the required variables (base sql files or updates, depending on the DB) diff --git a/modules/mod-auto-resurrect/conf/mod-auto-resurrect.conf.dist b/modules/mod-auto-resurrect/conf/mod-auto-resurrect.conf.dist new file mode 100644 index 0000000..fa1a7a9 --- /dev/null +++ b/modules/mod-auto-resurrect/conf/mod-auto-resurrect.conf.dist @@ -0,0 +1,57 @@ +# +# Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 +# + +[worldserver] + +######################################## +# Auto Resurrect configuration +######################################## +# +# AutoResurrect.Enable +# Description: Enable or Disable the Auto Resurrect mod +# Default: 0 - Disabled +# 1 - Enabled +# + +AutoResurrect.Enable = 0 + +# +# AutoResurrect.Notification +# Description: Notify players about this module on login +# Default: 0 - Disabled +# 1 - Enabled +# +AutoResurrect.Notification = 0 + +# +# AutoResurrect.Dungeon +# Description: Auto resurrect in normal dungeons +# Default: 0 - Disabled +# 1 - Enabled +# +AutoResurrect.Dungeon = 0 + +# +# AutoResurrect.HeroicDungeon +# Description: Auto resurrect in heroic dungeons +# Default: 0 - Disabled +# 1 - Enabled +# +AutoResurrect.HeroicDungeon = 0 + +# +# AutoResurrect.Raid +# Description: Auto resurrect in raids +# Default: 0 - Disabled +# 1 - Enabled +# +AutoResurrect.Raid = 0 + +# +# AutoResurrect.HeroicRaid +# Description: Auto resurrect in heroic raids +# Default: 0 - Disabled +# 1 - Enabled +# +AutoResurrect.HeroicRaid = 0 diff --git a/modules/mod-auto-resurrect/include.sh b/modules/mod-auto-resurrect/include.sh new file mode 100644 index 0000000..08efb33 --- /dev/null +++ b/modules/mod-auto-resurrect/include.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +MOD_AUTO_RESURRECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" + +source $MOD_AUTO_RESURRECT_ROOT"/conf/conf.sh.dist" + +if [ -f $MOD_AUTO_RESURRECT_ROOT"/conf/conf.sh" ]; then + source $MOD_AUTO_RESURRECT_ROOT"/conf/conf.sh" +fi diff --git a/modules/mod-auto-resurrect/setup_git_commit_template.sh b/modules/mod-auto-resurrect/setup_git_commit_template.sh new file mode 100644 index 0000000..7b52062 --- /dev/null +++ b/modules/mod-auto-resurrect/setup_git_commit_template.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +## Set a local git commit template +git config --local commit.template ".git_commit_template.txt" ; diff --git a/modules/mod-auto-resurrect/src/AR_loader.cpp b/modules/mod-auto-resurrect/src/AR_loader.cpp new file mode 100644 index 0000000..a7883e4 --- /dev/null +++ b/modules/mod-auto-resurrect/src/AR_loader.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + +// From SC +void AddAutoResurrectScripts(); + +// Add all +// cf. the naming convention https://github.com/azerothcore/azerothcore-wotlk/blob/master/doc/changelog/master.md#how-to-upgrade-4 +// additionally replace all '-' in the module folder name with '_' here +void Addmod_auto_resurrectScripts() +{ + AddAutoResurrectScripts(); +} + diff --git a/modules/mod-auto-resurrect/src/mod_auto_resurrect.cpp b/modules/mod-auto-resurrect/src/mod_auto_resurrect.cpp new file mode 100644 index 0000000..0e80939 --- /dev/null +++ b/modules/mod-auto-resurrect/src/mod_auto_resurrect.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + +#include "ScriptMgr.h" +#include "Player.h" +#include "Config.h" +#include "Chat.h" + + // Add player scripts +class AutoResurrect : public PlayerScript +{ +public: + AutoResurrect() : PlayerScript("AutoResurrect") { } + std::map playerLocation = {}; + + void DebugLog(Player* player, std::string log) { + if (sConfigMgr->GetOption("AutoResurrect.Enable", false) && sConfigMgr->GetOption("AutoResurrect.Notification", false)) { + ChatHandler(player->GetSession()).SendSysMessage(log); + } + } + + void OnLogin(Player* player) override + { + if (sConfigMgr->GetOption("AutoResurrect.Enable", false) && sConfigMgr->GetOption("AutoResurrect.Notification", false)) + { + DebugLog(player, "Auto Resurrect module enabled"); + } + } + + void OnPlayerReleasedGhost(Player* player) override { + if (!sConfigMgr->GetOption("AutoResurrect.Enable", false)) { + return; + } + + Map* map = player->GetMap(); + + bool dungeons = sConfigMgr->GetOption("AutoResurrect.Dungeon", false); + bool heroics = sConfigMgr->GetOption("AutoResurrect.HeroicDungeon", false); + bool raids = sConfigMgr->GetOption("AutoResurrect.Raid", false); + bool heroicRaids = sConfigMgr->GetOption("AutoResurrect.HeroicRaid", false); + + if ((dungeons && !map->IsHeroic() && map->IsDungeon()) || + (heroics && map->IsHeroic() && map->IsDungeon()) || + (raids && !map->IsHeroic() && map->IsRaid()) || + (heroicRaids && map->IsHeroic() && map->IsRaid())) { + AreaTriggerTeleport const* at = sObjectMgr->GetMapEntranceTrigger(player->GetMapId()); + playerLocation[player->GetGUID()] = at; + } + } + + virtual void OnMapChanged(Player* player) override { + if (!sConfigMgr->GetOption("AutoResurrect.Enable", false)) { + return; + } + + if (!playerLocation.count(player->GetGUID())) { + return; + } + + AreaTriggerTeleport const* at = playerLocation[player->GetGUID()]; + if (at == NULL) { + return; + } + + player->ResurrectPlayer(1.0f); + player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation); + player->SaveToDB(false, false); + + playerLocation[player->GetGUID()] = NULL; + } +}; + +// Add all scripts in one +void AddAutoResurrectScripts() +{ + new AutoResurrect(); +} diff --git a/modules/mod-character-tools/.editorconfig b/modules/mod-character-tools/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/mod-character-tools/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/mod-character-tools/.git_commit_template.txt b/modules/mod-character-tools/.git_commit_template.txt new file mode 100644 index 0000000..708b551 --- /dev/null +++ b/modules/mod-character-tools/.git_commit_template.txt @@ -0,0 +1,49 @@ +### TITLE +## Type(Scope/Subscope): Commit ultra short explanation +## |---- Write below the examples with a maximum of 50 characters ----| +## Example 1: fix(DB/SAI): Missing spell to NPC Hogger +## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros +## Example 3: feat(CORE/Commands): New GM command to do something + + +### DESCRIPTION +## Explain why this change is being made, what does it fix etc... +## |---- Write below the examples with a maximum of 72 characters per lines ----| +## Example: Hogger (id: 492) was not charging player when being engaged. + + +## Provide links to any issue, commit, pull request or other resource +## Example 1: Closes issue #23 +## Example 2: Ported from other project's commit (link) +## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ + + + +## ======================================================= +## EXTRA INFOS +## ======================================================= +## "Type" can be: +## feat (new feature) +## fix (bug fix) +## refactor (refactoring production code) +## style (formatting, missing semi colons, etc; no code change) +## docs (changes to documentation) +## test (adding or refactoring tests; no production code change) +## chore (updating bash scripts, git files etc; no production code change) +## -------------------- +## Remember to +## Capitalize the subject line +## Use the imperative mood in the subject line +## Do not end the subject line with a period +## Separate subject from body with a blank line +## Use the body to explain what and why rather than how +## Can use multiple lines with "-" for bullet points in body +## -------------------- +## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ +## ======================================================= +## "Scope" can be: +## CORE (core related, c++) +## DB (database related, sql) +## ======================================================= +## "Subscope" is optional and depends on the nature of the commit. +## ======================================================= diff --git a/modules/mod-character-tools/.gitattributes b/modules/mod-character-tools/.gitattributes new file mode 100644 index 0000000..7ef9001 --- /dev/null +++ b/modules/mod-character-tools/.gitattributes @@ -0,0 +1,105 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto eol=lf + +# Text +*.conf text +*.conf.dist text +*.cmake text + +## Scripts +*.sh text +*.fish text +*.lua text + +## SQL +*.sql text + +## C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + + +## ARCHIVES +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +## EXECUTABLES +*.exe binary +*.pyc binary diff --git a/modules/mod-character-tools/.github/workflows/core-build.yml b/modules/mod-character-tools/.github/workflows/core-build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-character-tools/.github/workflows/core-build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-character-tools/.gitignore b/modules/mod-character-tools/.gitignore new file mode 100644 index 0000000..c6e1299 --- /dev/null +++ b/modules/mod-character-tools/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*.*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-character-tools/LICENSE b/modules/mod-character-tools/LICENSE new file mode 100644 index 0000000..dbbe355 --- /dev/null +++ b/modules/mod-character-tools/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/modules/mod-character-tools/README.md b/modules/mod-character-tools/README.md new file mode 100644 index 0000000..07cdaea --- /dev/null +++ b/modules/mod-character-tools/README.md @@ -0,0 +1,40 @@ +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore +## Character Tools +- Latest build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-character-tools/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-character-tools) + + +This is a module for [AzerothCore](http://www.azerothcore.org) + +Current features: + +-**This Module is for a item with a use function to show gossip menu to allow players to change faction/race/name or customise + +Upcoming features: + + +## Requirements + +Character tools Module currently requires: + +AzerothCore v1.0.1+ + +## How to install + +###1) Simply place the module under the `modules` folder of your AzerothCore source folder. + +###2) Input the SQL file to the world database. + +###3) Re-run cmake and launch a clean build of AzerothCore + +**That's it.** + +### (Optional) Edit module configuration + +If you need to change the module configuration, go to your server configuration folder (e.g. **etc**), copy `mod_charactertools.conf.dist` to `mod_charactertools.conf` and edit it as you prefer. + + +# Show your appreciation +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SBJFTAJKUNEXC) + + + diff --git a/modules/mod-character-tools/conf/conf.sh.dist b/modules/mod-character-tools/conf/conf.sh.dist new file mode 100644 index 0000000..6db05f9 --- /dev/null +++ b/modules/mod-character-tools/conf/conf.sh.dist @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# +# CUSTOM +# + + DB_WORLD_CUSTOM_PATHS+=( + $MOD_CHARACTER_TOOLS_ROOT"/sql/world" + ) diff --git a/modules/mod-character-tools/conf/mod_charactertools.conf.dist b/modules/mod-character-tools/conf/mod_charactertools.conf.dist new file mode 100644 index 0000000..a85e8c6 --- /dev/null +++ b/modules/mod-character-tools/conf/mod_charactertools.conf.dist @@ -0,0 +1,10 @@ +[worldserver] +##################################################################################################### +# # +# CharacterTools # +# Description: Enables of disable the script for character_tools # +# Default: 1 (Enable) # +# 0 (Disable) # +# # +CharacterTools = 1 # +##################################################################################################### \ No newline at end of file diff --git a/modules/mod-character-tools/include.sh b/modules/mod-character-tools/include.sh new file mode 100644 index 0000000..646951e --- /dev/null +++ b/modules/mod-character-tools/include.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + + MOD_CHARACTER_TOOLS_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" + + source $MOD_CHARACTER_TOOLS_ROOT"/conf/conf.sh.dist" + + if [ -f $MOD_CHARACTER_TOOLS_ROOT"/conf/conf.sh" ]; then + source $MOD_CHARACTER_TOOLS_ROOT"/conf/conf.sh" + fi diff --git a/modules/mod-character-tools/setup_git_commit_template.sh b/modules/mod-character-tools/setup_git_commit_template.sh new file mode 100644 index 0000000..7b52062 --- /dev/null +++ b/modules/mod-character-tools/setup_git_commit_template.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +## Set a local git commit template +git config --local commit.template ".git_commit_template.txt" ; diff --git a/modules/mod-character-tools/sql/world/world.sql b/modules/mod-character-tools/sql/world/world.sql new file mode 100644 index 0000000..d375a0a --- /dev/null +++ b/modules/mod-character-tools/sql/world/world.sql @@ -0,0 +1,2 @@ +-- Adding script to the Item 6948 ( Hearthstone ) +UPDATE `item_template` SET `ScriptName`='character_tools' WHERE `entry`=6948; diff --git a/modules/mod-character-tools/src/CT_loader.cpp b/modules/mod-character-tools/src/CT_loader.cpp new file mode 100644 index 0000000..f2c9d0f --- /dev/null +++ b/modules/mod-character-tools/src/CT_loader.cpp @@ -0,0 +1,6 @@ +void AddCharacterToolsScripts(); + +void Addmod_character_toolsScripts() +{ + AddCharacterToolsScripts(); +} diff --git a/modules/mod-character-tools/src/mod_charactertools.cpp b/modules/mod-character-tools/src/mod_charactertools.cpp new file mode 100644 index 0000000..a58b4a6 --- /dev/null +++ b/modules/mod-character-tools/src/mod_charactertools.cpp @@ -0,0 +1,64 @@ +#include "Define.h" +#include "GossipDef.h" +#include "Item.h" +#include "Player.h" +#include "ScriptedGossip.h" +#include "ScriptMgr.h" +#include "Spell.h" +#include "Configuration/Config.h" +#include "Chat.h" + +class character_tools : public ItemScript +{ +public: + character_tools() : ItemScript("character_tools") {} + + bool OnUse(Player* p, Item* i, SpellCastTargets const& /*targets*/) override + { + p->PlayerTalkClass->ClearMenus(); + + if (p->IsInCombat()) + return false; + + if (!sConfigMgr->GetOption("CharacterTools", true)) + return false; + + AddGossipItemFor(p, GOSSIP_ICON_CHAT, "|TInterface/Icons/Ability_Paladin_BeaconofLight:50:50|tChange My Race", GOSSIP_SENDER_MAIN, 1); + AddGossipItemFor(p, GOSSIP_ICON_CHAT, "|TInterface/Icons/INV_BannerPVP_01:50:50|tChange My Faction", GOSSIP_SENDER_MAIN, 2); + AddGossipItemFor(p, GOSSIP_ICON_CHAT, "|TInterface/Icons/Achievement_BG_returnXflags_def_WSG:50:50|tChange My Appearance", GOSSIP_SENDER_MAIN, 3); + AddGossipItemFor(p, GOSSIP_ICON_CHAT, "|TInterface/Icons/INV_Inscription_Scroll:50:50|tChange My Name", GOSSIP_SENDER_MAIN, 4); + SendGossipMenuFor(p, DEFAULT_GOSSIP_MESSAGE, i->GetGUID()); + + return false; // If item has spell cast it normal. + } + + void OnGossipSelect(Player* player, Item* /*item*/, uint32 /*sender*/, uint32 action) override + { + player->PlayerTalkClass->ClearMenus(); + switch (action) + { + case 1: + player->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE); + ChatHandler(player->GetSession()).PSendSysMessage("CHAT OUTPUT: Please log out for race change."); + break; + case 2: + player->SetAtLoginFlag(AT_LOGIN_CHANGE_FACTION); + ChatHandler(player->GetSession()).PSendSysMessage("CHAT OUTPUT: Please log out for faction change."); + break; + case 3: + player->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE); + ChatHandler(player->GetSession()).PSendSysMessage("CHAT OUTPUT: Please log out for Character Customize."); + break; + case 4: + player->SetAtLoginFlag(AT_LOGIN_RENAME); + ChatHandler(player->GetSession()).PSendSysMessage("CHAT OUTPUT: Please log out for name change."); + break; + } + } + +}; + +void AddCharacterToolsScripts() +{ + new character_tools(); +} diff --git a/modules/mod-dynamic-xp/.github/workflows/core-build.yml b/modules/mod-dynamic-xp/.github/workflows/core-build.yml new file mode 100644 index 0000000..c44f754 --- /dev/null +++ b/modules/mod-dynamic-xp/.github/workflows/core-build.yml @@ -0,0 +1,45 @@ +name: core-build +on: + push: + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + compiler: [clang] + runs-on: ubuntu-latest + name: ${{ matrix.compiler }} + env: + COMPILER: ${{ matrix.compiler }} + steps: + - uses: actions/checkout@v2 + with: + repository: 'azerothcore/azerothcore-wotlk' + ref: 'master' + submodules: 'recursive' + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + path: 'modules/mod-dynamic-xp' + - name: Cache + uses: actions/cache@v1.1.2 + with: + path: /home/runner/.ccache + key: ccache:${{ matrix.compiler }}:${{ github.ref }}:${{ github.sha }} + restore-keys: | + ccache:${{ matrix.compiler }}:${{ github.ref }} + ccache:${{ matrix.compiler }} + - name: Configure OS + run: source ./apps/ci/ci-install.sh + env: + CONTINUOUS_INTEGRATION: true + - name: Import db + run: source ./apps/ci/ci-import-db.sh + - name: Build + run: source ./apps/ci/ci-compile.sh + - name: Dry run + run: source ./apps/ci/ci-worldserver-dry-run.sh + - name: Check startup errors + run: source ./apps/ci/ci-error-check.sh \ No newline at end of file diff --git a/modules/mod-dynamic-xp/.gitignore b/modules/mod-dynamic-xp/.gitignore new file mode 100644 index 0000000..d011fdd --- /dev/null +++ b/modules/mod-dynamic-xp/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-dynamic-xp/LICENSE b/modules/mod-dynamic-xp/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/modules/mod-dynamic-xp/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/modules/mod-dynamic-xp/README.md b/modules/mod-dynamic-xp/README.md new file mode 100644 index 0000000..72dae1e --- /dev/null +++ b/modules/mod-dynamic-xp/README.md @@ -0,0 +1,22 @@ +# Dynamic XP +- Latest build status with azerothcore: [![Build Status](https://travis-ci.com/milestorme/mod-dynamic-xp.svg?branch=master)](https://travis-ci.com/milestorme/mod-dynamic-xp) + +## Description +Set xp per level range e.g in dynamicxp.conf. + +## Features + +* Dynamic.XP.Rate.1-9 = 1.0 +* Dynamic.XP.Rate.10-19 = 2.0 +* Dynamic.XP.Rate.20-29 = 3.0 +* Dynamic.XP.Rate.30-39 = 4.0 +* Dynamic.XP.Rate.40-49 = 5.0 +* Dynamic.XP.Rate.50-59 = 6.0 +* Dynamic.XP.Rate.60-69 = 7.0 +* Dynamic.XP.Rate.70-79 = 8.0 + + +## Credits +* [Micrah/Milestorme: Script/Module Creator](https://github.com/milestorme). +* [Poszer: Script Support](https://github.com/poszer) +* [Conan513: Original Script from AshmaneCore](https://github.com/conan513). diff --git a/modules/mod-dynamic-xp/conf/dynamicxp.conf.dist b/modules/mod-dynamic-xp/conf/dynamicxp.conf.dist new file mode 100644 index 0000000..5db58a5 --- /dev/null +++ b/modules/mod-dynamic-xp/conf/dynamicxp.conf.dist @@ -0,0 +1,28 @@ +[worldserver] + +################################################################################################################ +# Dynamic.XP.Rate +# Description: You can setup the personal XP rate for different level ranges. +# +# Dynamic.XP.Rate.Announce: 1 (Enable) Default +# 0 (Disable) +# +# Dynamic.XP.Rate: 1 (Enable) Default +# 0 (Disable) +# +# Dynamic.XP.Rate.X-X: 1+ (Set a custom XP rate on that level range) +# 0 (Reset custom XP rate to default on that level range) +# +Dynamic.XP.Rate.Announce = 1 + +Dynamic.XP.Rate = 1 + +Dynamic.XP.Rate.1-9 = 1 +Dynamic.XP.Rate.10-19 = 2 +Dynamic.XP.Rate.20-29 = 3 +Dynamic.XP.Rate.30-39 = 4 +Dynamic.XP.Rate.40-49 = 5 +Dynamic.XP.Rate.50-59 = 6 +Dynamic.XP.Rate.60-69 = 7 +Dynamic.XP.Rate.70-79 = 8 +################################################################################################################## diff --git a/modules/mod-dynamic-xp/include.sh b/modules/mod-dynamic-xp/include.sh new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-dynamic-xp/src/DXP_loader.cpp b/modules/mod-dynamic-xp/src/DXP_loader.cpp new file mode 100644 index 0000000..58c36a7 --- /dev/null +++ b/modules/mod-dynamic-xp/src/DXP_loader.cpp @@ -0,0 +1,5 @@ +void AddSC_dynamic_xp_rate(); + +void Addmod_dynamic_xpScripts() { + AddSC_dynamic_xp_rate(); +} diff --git a/modules/mod-dynamic-xp/src/dynamicxp.cpp b/modules/mod-dynamic-xp/src/dynamicxp.cpp new file mode 100644 index 0000000..5290e3a --- /dev/null +++ b/modules/mod-dynamic-xp/src/dynamicxp.cpp @@ -0,0 +1,63 @@ +/* +Credits +Script reworked by Micrah/Milestorme and Poszer (Poszer is the Best) +Module Created by Micrah/Milestorme +Original Script from AshmaneCore https://github.com/conan513 Single Player Project +*/ +#include "Configuration/Config.h" +#include "ScriptMgr.h" +#include "Player.h" +#include "Chat.h" + + +class spp_dynamic_xp_rate : public PlayerScript +{ + public: + spp_dynamic_xp_rate() : PlayerScript("spp_dynamic_xp_rate") { }; + + void OnLogin(Player* player) override + { + if (sConfigMgr->GetBoolDefault("Dynamic.XP.Rate.Announce", true)) + { + ChatHandler(player->GetSession()).SendSysMessage("This server is running the |cff4CFF00Level Dynamic XP |rmodule."); + } + } + void OnGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 xpSource) override + { + if (sConfigMgr->GetBoolDefault("Dynamic.XP.Rate", true)) + + { + if (player->getLevel() <= 9) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.1-9", 1); + + else if (player->getLevel() <= 19) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.10-19", 2); + + else if (player->getLevel() <= 29) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.20-29", 3); + + else if (player->getLevel() <= 39) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.30-39", 4); + + else if (player->getLevel() <= 49) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.40-49", 5); + + else if (player->getLevel() <= 59) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.50-59", 6); + + else if (player->getLevel() <= 69) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.60-69", 7); + + else if (player->getLevel() <= 79) + amount *= sConfigMgr->GetIntDefault("Dynamic.XP.Rate.70-79", 8); + + } + + } + +}; + +void AddSC_dynamic_xp_rate() +{ + new spp_dynamic_xp_rate(); +} diff --git a/modules/mod-eluna/.editorconfig b/modules/mod-eluna/.editorconfig new file mode 100644 index 0000000..eb64e2f --- /dev/null +++ b/modules/mod-eluna/.editorconfig @@ -0,0 +1,8 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 diff --git a/modules/mod-eluna/.git_commit_template.txt b/modules/mod-eluna/.git_commit_template.txt new file mode 100644 index 0000000..708b551 --- /dev/null +++ b/modules/mod-eluna/.git_commit_template.txt @@ -0,0 +1,49 @@ +### TITLE +## Type(Scope/Subscope): Commit ultra short explanation +## |---- Write below the examples with a maximum of 50 characters ----| +## Example 1: fix(DB/SAI): Missing spell to NPC Hogger +## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros +## Example 3: feat(CORE/Commands): New GM command to do something + + +### DESCRIPTION +## Explain why this change is being made, what does it fix etc... +## |---- Write below the examples with a maximum of 72 characters per lines ----| +## Example: Hogger (id: 492) was not charging player when being engaged. + + +## Provide links to any issue, commit, pull request or other resource +## Example 1: Closes issue #23 +## Example 2: Ported from other project's commit (link) +## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ + + + +## ======================================================= +## EXTRA INFOS +## ======================================================= +## "Type" can be: +## feat (new feature) +## fix (bug fix) +## refactor (refactoring production code) +## style (formatting, missing semi colons, etc; no code change) +## docs (changes to documentation) +## test (adding or refactoring tests; no production code change) +## chore (updating bash scripts, git files etc; no production code change) +## -------------------- +## Remember to +## Capitalize the subject line +## Use the imperative mood in the subject line +## Do not end the subject line with a period +## Separate subject from body with a blank line +## Use the body to explain what and why rather than how +## Can use multiple lines with "-" for bullet points in body +## -------------------- +## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ +## ======================================================= +## "Scope" can be: +## CORE (core related, c++) +## DB (database related, sql) +## ======================================================= +## "Subscope" is optional and depends on the nature of the commit. +## ======================================================= diff --git a/modules/mod-eluna/.gitattributes b/modules/mod-eluna/.gitattributes new file mode 100644 index 0000000..7ef9001 --- /dev/null +++ b/modules/mod-eluna/.gitattributes @@ -0,0 +1,105 @@ +## AUTO-DETECT +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto eol=lf + +# Text +*.conf text +*.conf.dist text +*.cmake text + +## Scripts +*.sh text +*.fish text +*.lua text + +## SQL +*.sql text + +## C++ +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.hpp text +*.h text +*.h++ text +*.hh text + + +## For documentation + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + + +## ARCHIVES +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +## EXECUTABLES +*.exe binary +*.pyc binary diff --git a/modules/mod-eluna/.github/workflows/core_build.yml b/modules/mod-eluna/.github/workflows/core_build.yml new file mode 100644 index 0000000..921c9eb --- /dev/null +++ b/modules/mod-eluna/.github/workflows/core_build.yml @@ -0,0 +1,12 @@ +name: core-build +on: + push: + branches: + - 'master' + pull_request: + +jobs: + build: + uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main + with: + module_repo: ${{ github.event.repository.name }} diff --git a/modules/mod-eluna/.github/workflows/create-pr.sh b/modules/mod-eluna/.github/workflows/create-pr.sh new file mode 100644 index 0000000..b84d341 --- /dev/null +++ b/modules/mod-eluna/.github/workflows/create-pr.sh @@ -0,0 +1,41 @@ +# Adapted from https://github.com/paygoc6/action-pull-request-another-repo + +CLONE_DIR=$(mktemp -d) + +echo "Setting git variables" +export GITHUB_TOKEN=$API_TOKEN_GITHUB +git config --global user.email "$USER_EMAIL" +git config --global user.name "$USER_NAME" + +date=$(date '+%Y-%m-%d_%H-%M') +DESTINATION_HEAD_BRANCH="$DESTINATION_HEAD_BRANCH-$date" + +echo "Cloning destination git repository" +git clone "https://$API_TOKEN_GITHUB@github.com/$DESTINATION_REPO.git" "$CLONE_DIR" +cd "$CLONE_DIR" +git checkout "$DESTINATION_BASE_BRANCH" +git pull origin "$DESTINATION_BASE_BRANCH" +git checkout -b "$DESTINATION_HEAD_BRANCH" + +echo "Copying contents to git repo" +mkdir -p "$CLONE_DIR/$DESTINATION_FOLDER" +cp -r "$SOURCE_FOLDER/." "$CLONE_DIR/$DESTINATION_FOLDER/" + +echo "Adding files" +git add . +echo "Git status:" +git status -- ":!pages/eluna/date.js" +if git status -- ":!pages/eluna/date.js" | grep -q "Changes to be committed" +then + echo "Adding git commit" + git commit -m "$COMMIT_MESSAGE" + echo "Pushing git commit" + git push -u origin "$DESTINATION_HEAD_BRANCH" + echo "Creating a pull request" + gh pr create -t "$PR_TITLE" \ + -B "$DESTINATION_BASE_BRANCH" \ + -b "" \ + -H "$DESTINATION_HEAD_BRANCH" +else + echo "No changes detected" +fi diff --git a/modules/mod-eluna/.github/workflows/documentation.yml b/modules/mod-eluna/.github/workflows/documentation.yml new file mode 100644 index 0000000..1fe2396 --- /dev/null +++ b/modules/mod-eluna/.github/workflows/documentation.yml @@ -0,0 +1,38 @@ +name: documentation +on: + push: + branches: + - 'main' + - 'master' +jobs: + Push-Docs-To-AzerothCore-Website: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + architecture: 'x64' + - name: Install Python dependencies + run: pip install jinja2 typedecorator markdown + - name: Compile documentation + run: | + cd ${{ github.workspace }}/src/LuaEngine/docs/ + python -m ElunaDoc + - name: Create pull request + run: | + chmod +x "${GITHUB_WORKSPACE}/.github/workflows/create-pr.sh" + "${GITHUB_WORKSPACE}/.github/workflows/create-pr.sh" + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + SOURCE_FOLDER: '${{ github.workspace }}/src/LuaEngine/docs/build' + DESTINATION_REPO: 'azerothcore/azerothcore.github.io' + DESTINATION_FOLDER: 'pages/eluna' + DESTINATION_BASE_BRANCH: 'master' + DESTINATION_HEAD_BRANCH: 'eluna-docs' + PR_TITLE: 'chore: update eluna documentation' + COMMIT_MESSAGE: 'chore: update eluna documentation' + USER_EMAIL: 'ax.cocat@gmail.com' + USER_NAME: 'r-o-b-o-t-o' diff --git a/modules/mod-eluna/.gitignore b/modules/mod-eluna/.gitignore new file mode 100644 index 0000000..c6e1299 --- /dev/null +++ b/modules/mod-eluna/.gitignore @@ -0,0 +1,48 @@ +!.gitignore + +# +#Generic +# + +.directory +.mailmap +*.orig +*.rej +*.*~ +.hg/ +*.kdev* +.DS_Store +CMakeLists.txt.user +*.bak +*.patch +*.diff +*.REMOTE.* +*.BACKUP.* +*.BASE.* +*.LOCAL.* + +# +# IDE & other softwares +# +/.settings/ +/.externalToolBuilders/* +# exclude in all levels +nbproject/ +.sync.ffs_db +*.kate-swp + +# +# Eclipse +# +*.pydevproject +.metadata +.gradle +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.cproject diff --git a/modules/mod-eluna/LICENSE b/modules/mod-eluna/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/modules/mod-eluna/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/modules/mod-eluna/README.md b/modules/mod-eluna/README.md new file mode 100644 index 0000000..d48c1ea --- /dev/null +++ b/modules/mod-eluna/README.md @@ -0,0 +1,137 @@ +### [![Eluna](src/LuaEngine/docs/Eluna.png)](https://github.com/ElunaLuaEngine/Eluna) + +## About + +Eluna Lua Engine © is a lua engine embedded to World of Warcraft emulators. Eluna supports MaNGOS, CMaNGOS, TrinityCore and AzerothCore. +We are currently working hard to make Eluna better from inside and outside. + +If you are having trouble with installation or scripts, please feel free to open an issue. +For documentation and reference see [Eluna API (AC version)](https://www.azerothcore.org/pages/eluna/index.html) and [Lua reference manual](http://www.lua.org/manual/5.2/). + + +## Community + +You can join the official Eluna Discord server, where you'll be able to find resources, releases and support provided by the community: + + + + +The official Azerothcore Discord server offers a channel dedicated to lua development as well: + + + + +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) mod-eluna for AzerothCore +- Latest build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-eluna/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-eluna) + +[english](README.md) | [中文说明](README_CN.md) | [Español](README_ES.md) + +An [Eluna](https://github.com/ElunaLuaEngine/Eluna) module for AzerothCore. + + +## How to install: + +### 1) Download the sources + +You can get the sources using git. + +#### download with git + +1. open a terminal inside your `azerothcore-wotlk` folder +2. go inside the **modules** folder: `cd modules` +3. download the module sources using: +``` +git clone https://github.com/azerothcore/mod-eluna.git mod-eluna +``` + +### 2) Build + +You need to run the cmake again and rebuild the project. + +Eluna API for AC: +[https://www.azerothcore.org/pages/eluna/index.html](https://www.azerothcore.org/pages/eluna/index.html) + + +## Documentation + +* [Getting started](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/USAGE.md) +* [Eluna features](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/IMPL_DETAILS.md) +* [Function documentation (AC version)](https://www.azerothcore.org/pages/eluna/index.html) +* [Hook documentation](https://github.com/ElunaLuaEngine/Eluna/blob/master/Hooks.h) +* [Lua reference manual](http://www.lua.org/manual/5.2/) +* [Forum - support, releases, guides](https://www.getmangos.eu/forums/forum/119-eluna-central/) +* [Example scripts](https://github.com/ElunaLuaEngine/Scripts) +* [Contributing](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/CONTRIBUTING.md) + + +## Links + +* [MaNGOS](http://getmangos.eu/) +* [cMaNGOS](http://cmangos.net/) +* [TrinityCore](http://www.trinitycore.org/) +* [AzerothCore](http://www.azerothcore.org/) +* [Lua.org](http://www.lua.org/) +* [License](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/LICENSE.md) + + +## Additions from Eluna/master + +### Player +- Added `RegisterPlayerEvent` `43` (`PLAYER_EVENT_ON_PET_ADDED_TO_WORLD`) fires for pets and summoned creatures: https://github.com/azerothcore/mod-eluna/pull/3 +- Added `RegisterPlayerEvent` `44` (`PLAYER_EVENT_ON_LEARN_SPELL`): https://github.com/azerothcore/mod-eluna/pull/46 +- Added `RegisterPlayerEvent` `45` (`PLAYER_ON_ACHIEVEMENT_COMPLETE`): https://github.com/azerothcore/mod-eluna/pull/47 +- Added `RegisterPlayerEvent` `46` (`PLAYER_EVENT_ON_FFAPVP_CHANGE`): https://github.com/azerothcore/mod-eluna/pull/63 +- Added `RegisterPlayerEvent` `47` (`PLAYER_EVENT_ON_UPDATE_AREA`): https://github.com/azerothcore/mod-eluna/pull/65 +- Added `RegisterPlayerEvent` `48` (`PLAYER_EVENT_ON_CAN_INIT_TRADE`): https://github.com/azerothcore/mod-eluna/pull/83 +- Added `RegisterPlayerEvent` `49` (`PLAYER_EVENT_ON_CAN_SEND_MAIL`): https://github.com/azerothcore/mod-eluna/pull/85 +- Added `RegisterPlayerEvent` `50` (`PLAYER_EVENT_ON_CAN_JOIN_LFG`): https://github.com/azerothcore/mod-eluna/pull/86 +- Added `RegisterPlayerEvent` `51` (`PLAYER_EVENT_ON_QUEST_REWARD_ITEM`): https://github.com/azerothcore/mod-eluna/pull/88 +- Added `RegisterPlayerEvent` `52` (`PLAYER_EVENT_ON_CREATE_ITEM`): https://github.com/azerothcore/mod-eluna/pull/88 +- Added `RegisterPlayerEvent` `53` (`PLAYER_EVENT_ON_STORE_NEW_ITEM`): https://github.com/azerothcore/mod-eluna/pull/88 +- Added `RegisterPlayerEvent` `54` (`PLAYER_EVENT_ON_COMPLETE_QUEST`): https://github.com/azerothcore/mod-eluna/pull/90 +- Added `RegisterPlayerEvent` `55` (`PLAYER_EVENT_ON_CAN_GROUP_INVITE`): https://github.com/azerothcore/mod-eluna/pull/100 +- Added `RegisterPlayerEvent` `56` (`PLAYER_EVENT_ON_GROUP_ROLL_REWARD_ITEM`): https://github.com/azerothcore/mod-eluna/pull/119 +- Added `RegisterPlayerEvent` `57` (`PLAYER_EVENT_ON_BG_DESERTION`): https://github.com/azerothcore/mod-eluna/pull/146 +- Added `Player:GetMailCount()`: https://github.com/azerothcore/mod-eluna/pull/76 +- Added `Player:GetXP()`: https://github.com/azerothcore/mod-eluna/pull/77 +- Added `Player:GetAchievementCriteriaProgress()`: https://github.com/azerothcore/mod-eluna/pull/78 +- Added vendor entry as argument to `Player:SendListInventory(object, vendorentry)`: https://github.com/azerothcore/mod-eluna/pull/48 +- Added `Player:GetPlayerSettingValue()` and `Player:UpdatePlayerSetting()`: https://github.com/azerothcore/mod-eluna/pull/125 +- Added `Player:GetTrader()`: https://github.com/azerothcore/mod-eluna/pull/126 +- Added `Player:CanCompleteRepeatableQuest(questId)`: https://github.com/azerothcore/mod-eluna/pull/141 +- Added `Player:CanRewardQuest(questId)`: https://github.com/azerothcore/mod-eluna/pull/141 +- Added `Player:SetGlyph(glyphId, slotIndex)`: https://github.com/azerothcore/mod-eluna/pull/152 + +### Group +- Added `Group:GetGroupType()`: https://github.com/azerothcore/mod-eluna/pull/82 +- Added `Group:SetMemberFlag()`: https://github.com/azerothcore/mod-eluna/pull/102 + +### Unit +- Added `Unit:ModifyThreatPct()`: https://github.com/azerothcore/mod-eluna/pull/25 +- Added `Unit:GetAttackers()`: https://github.com/azerothcore/mod-eluna/pull/116 +- Added `Unit:GetThreatList()`: https://github.com/azerothcore/mod-eluna/pull/117 +- Added `Unit:GetUnitFlags()`: https://github.com/azerothcore/mod-eluna/pull/137 +- Added `Unit:GetUnitFlagsTwo()`: https://github.com/azerothcore/mod-eluna/pull/137 +- Added `Unit:SetUnitFlags(flags)`: https://github.com/azerothcore/mod-eluna/pull/137 +- Added `Unit:SetUnitFlagsTwo(flags)`: https://github.com/azerothcore/mod-eluna/pull/137 +- Added `Unit:SetSpeedRate(unitMoveType, speed)`: https://github.com/azerothcore/mod-eluna/pull/155 +- Added `Unit:SetSpeedRate()`: https://github.com/azerothcore/mod-eluna/pull/155 + +### GameObject +- Added `GameObject:AddLoot()` to add loot at runtime to an **empty** container: https://github.com/azerothcore/mod-eluna/pull/52 + +### Object +- Added `Object:IsPlayer()`: https://github.com/azerothcore/mod-eluna/pull/42 + +### Item +- Added `Item:GetItemTemplate()`: https://github.com/azerothcore/mod-eluna/pull/84 + +### Misc +- Added `HttpRequest()`: https://github.com/azerothcore/mod-eluna/pull/2 +- Added `GetItemTemplate(itemEntry)`: https://github.com/azerothcore/mod-eluna/pull/84 +- Added `ChatHandler` methods: https://github.com/azerothcore/mod-eluna/pull/23 +- Added `ItemTemplate` methods: https://github.com/azerothcore/mod-eluna/pull/84 +- Added `Roll` methods: https://github.com/azerothcore/mod-eluna/pull/119 +- Added logging with `ELUNA_LOG_INFO` for `RunCommand()`: https://github.com/azerothcore/mod-eluna/pull/75 +- Added `GetOwnerHalaa` and `SetOwnerHalaa`: https://github.com/azerothcore/mod-eluna/pull/79 +- Added `WorldDBQueryAsync`, `CharDBQueryAsync` and `AuthDBQueryAsync`: https://github.com/azerothcore/mod-eluna/pull/113 diff --git a/modules/mod-eluna/README_CN.md b/modules/mod-eluna/README_CN.md new file mode 100644 index 0000000..1789c31 --- /dev/null +++ b/modules/mod-eluna/README_CN.md @@ -0,0 +1,92 @@ +### [![Eluna](src/LuaEngine/docs/Eluna.png)](https://github.com/ElunaLuaEngine/Eluna) + +## 关于 + +Eluna Lua Engine © 是嵌入到魔兽世界模拟器中的lua引擎。 Eluna支持MaNGOS,CMaNGOS,TrinityCore和AzerothCore。 +我们目前正在努力使Eluna从内到外变得更好。 + +如果您在安装或脚本方面遇到问题,请随时提出问题。 +有关文档和参考,请参阅[Eluna API (AC版)](https://www.azerothcore.org/pages/eluna/index.html) and [Lua 参考手册](http://www.lua.org/manual/5.2/). + + +## 社区 + +您可以加入官方的Eluna Discord服务器,在那里您将能够找到社区提供的资源,版本和支持: + + + + +官方的Azerothcore Discord服务器也提供了一个专门用于lua开发的通道: + + + + +# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) mod-eluna for AzerothCore +- azerothcore 的最新构建状态:[![Build Status](https://github.com/azerothcore/mod-eluna/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-eluna) + +[english](README.md) | [中文说明](README_CN.md) | [Español](README_ES.md) + +一个AzerothCore的[Eluna](https://github.com/ElunaLuaEngine/Eluna)模块。 + + +## 如何安装: + +### 1) 下载源代码 + +您可以使用 git 获取源代码。 + + +#### 使用 git 下载 + +1. 在命令行中打开 `azerothcore-wotlk` 的文件夹。 +2. 进入 **modules** 文件夹: `cd modules` +3. 使用以下命令下载模块源代码。 +``` +git clone https://github.com/azerothcore/mod-eluna.git mod-eluna +``` + +### 2) 构建 + +您需要再次运行 cmake 并重新生成项目。 + +AC版的Eluna API: +[https://www.azerothcore.org/pages/eluna/index.html](https://www.azerothcore.org/pages/eluna/index.html) + + +## 文档 + +* [入门指南](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/USAGE.md) +* [Eluna特性](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/IMPL_DETAILS.md) +* [功能文档(AC版本)](https://www.azerothcore.org/pages/eluna/index.html) +* [Hook文档](https://github.com/ElunaLuaEngine/Eluna/blob/master/Hooks.h) +* [Lua参考手册](http://www.lua.org/manual/5.2/) +* [论坛 - 支持, 发布, 指南](https://www.getmangos.eu/forums/forum/119-eluna-central/) +* [示例脚本](https://github.com/ElunaLuaEngine/Scripts) +* [贡献](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/CONTRIBUTING.md) + + +## 链接 + +* [MaNGOS](http://getmangos.eu/) +* [cMaNGOS](http://cmangos.net/) +* [TrinityCore](http://www.trinitycore.org/) +* [AzerothCore](http://www.azerothcore.org/) +* [Lua.org](http://www.lua.org/) +* [License](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/LICENSE.md) + + +## 来自Eluna/master的拓展 + +- 添加了 HttpRequest 方法. https://github.com/azerothcore/Eluna/pull/2 +- 添加玩家注册事件43(当宠物添加到世界中时): `PLAYER_EVENT_ON_PET_ADDED_TO_WORLD` https://github.com/azerothcore/Eluna/pull/3 +- 添加聊天处理方法到玩家事件中。 https://github.com/azerothcore/Eluna/pull/23 +- 暴露方法 `ModifyThreatPct()`. https://github.com/azerothcore/Eluna/pull/25 +- 暴露方法 `Object:IsPlayer()`. https://github.com/azerothcore/Eluna/pull/42 +- 添加玩家注册事件44(当玩家学习技能时): `PLAYER_EVENT_ON_LEARN_SPELL`. https://github.com/azerothcore/mod-eluna/pull/46 +- 添加玩家注册事件45(当玩家完成成就时): `PLAYER_ON_ACHIEVEMENT_COMPLETE`。 https://github.com/azerothcore/mod-eluna/pull/47 +- 添加玩家注册事件51(当玩家获得任务奖励时) `PLAYER_EVENT_ON_QUEST_REWARD_ITEM`。https://github.com/azerothcore/mod-eluna/pull/88 +- 添加玩家注册事件52(当玩家创建物品时) `PLAYER_EVENT_ON_CREATE_ITEM`。https://github.com/azerothcore/mod-eluna/pull/88 +- 添加玩家注册事件53(当玩家创建物品实例时) `PLAYER_EVENT_ON_STORE_NEW_ITEM`。https://github.com/azerothcore/mod-eluna/pull/88 +- 添加玩家注册事件54(当玩家完成任务时) `PLAYER_EVENT_ON_COMPLETE_QUEST`。https://github.com/azerothcore/mod-eluna/pull/90 +- 新增参数*商人Id*到方法player:SendListInventory(object, vendorentry)中。 https://github.com/azerothcore/mod-eluna/pull/48 +- 添加方法`gameobject:AddLoot()`, 可以在线给**空**的容器中添加战利品。 https://github.com/azerothcore/mod-eluna/pull/52 diff --git a/modules/mod-eluna/README_ES.md b/modules/mod-eluna/README_ES.md new file mode 100644 index 0000000..0be2db3 --- /dev/null +++ b/modules/mod-eluna/README_ES.md @@ -0,0 +1,26 @@ +# Esta traducción proviene de una versión desactualizada. +## +## +## +## + +# mod-LuaEngine + [English](README.md) | [中文说明](README_CN.md) | [Español](README_ES.md) + +Un módulo de Eluna para AzerothCore. + +Cómo instalar: + +1. Descargar o clonar este módulo: +> [Descargar archivo zip](https://github.com/azerothcore/mod-eluna-lua-engine/archive/master.zip) +> o clonar `git clone https://github.com/azerothcore/mod-eluna-lua-engine.git` +2. Póngalo en la carpeta de módulos del Azerothcore. +> $HOME/azerothcore/modules/ +3. Descargar o clonar el archivo central de ELUNA: +> [Descargar archivo zip](https://github.com/ElunaLuaEngine/Eluna/archive/master.zip) +> o clonar `git clone https://github.com/ElunaLuaEngine/Eluna.git .` +4. Dentro de la carpeta del módulo de Eluna de Azeroth, se encuentra una carpeta / directorio llamado: `LuaEngine` (mod-eluna-lua-engine/LuaEngine). Debe depositar los ficheros de lua, directamente dentro de esa carpeta. Los archivos directamente, no un directorio y luego los ficheros dentro. Por eso te utiliza el “.” cuando se está clonando, para que no genere un directorio nuevo. +5. Una vez copiado los ficheros y descargado el modulo, debes volver a compilar. Si seguiste la guía de instalación, debiste haber generado un directorio build, dentro de azerothcore. Dirígete a él y realiza la compilación como lo menciona en la guía. + +Eluna API : +[http://elunaluaengine.github.io/](http://elunaluaengine.github.io/) diff --git a/modules/mod-eluna/_config.yml b/modules/mod-eluna/_config.yml new file mode 100644 index 0000000..3397c9a --- /dev/null +++ b/modules/mod-eluna/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-architect \ No newline at end of file diff --git a/modules/mod-eluna/conf/mod_LuaEngine.conf.dist b/modules/mod-eluna/conf/mod_LuaEngine.conf.dist new file mode 100644 index 0000000..d94eb23 --- /dev/null +++ b/modules/mod-eluna/conf/mod_LuaEngine.conf.dist @@ -0,0 +1,120 @@ +[worldserver] + +################################################################################################### +# ELUNA SETTINGS +# +# Eluna.Enabled +# Description: Enable or disable Eluna LuaEngine +# Default: true - (enabled) +# false - (disabled) +# +# Eluna.TraceBack +# Description: Sets whether to use debug.traceback function on a lua error or not. +# Notice that you can redefine the function. +# Default: false - (use default error output) +# true - (use debug.traceback function) +# +# Eluna.ScriptPath +# Description: Sets the location of the script folder to load scripts from +# The path can be relative or absolute. +# Default: "lua_scripts" +# +# Eluna.PlayerAnnounceReload +# Description: Enable or disable whether the reload announcement is sent to players (Lowest security level). +# Default: false - (disabled) +# true - (enabled) +# + +Eluna.Enabled = true +Eluna.TraceBack = false +Eluna.ScriptPath = "lua_scripts" +Eluna.PlayerAnnounceReload = false + + +################################################################################################### +# LOGGING SYSTEM SETTINGS +# +# Appender config values: Given an appender "name" +# Appender.name +# Description: Defines 'where to log'. +# Format: Type,LogLevel,Flags,optional1,optional2,optional3 +# +# Type +# 0 - (None) +# 1 - (Console) +# 2 - (File) +# 3 - (DB) +# +# LogLevel +# 0 - (Disabled) +# 1 - (Fatal) +# 2 - (Error) +# 3 - (Warning) +# 4 - (Info) +# 5 - (Debug) +# 6 - (Trace) +# +# Flags: +# 0 - None +# 1 - Prefix Timestamp to the text +# 2 - Prefix Log Level to the text +# 4 - Prefix Log Filter type to the text +# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS +# (Only used with Type = 2) +# 16 - Make a backup of existing file before overwrite +# (Only used with Mode = w) +# +# Colors (read as optional1 if Type = Console) +# Format: "fatal error warn info debug trace" +# 0 - BLACK +# 1 - RED +# 2 - GREEN +# 3 - BROWN +# 4 - BLUE +# 5 - MAGENTA +# 6 - CYAN +# 7 - GREY +# 8 - YELLOW +# 9 - LRED +# 10 - LGREEN +# 11 - LBLUE +# 12 - LMAGENTA +# 13 - LCYAN +# 14 - WHITE +# Example: "1 9 3 6 5 8" +# +# File: Name of the file (read as optional1 if Type = File) +# Allows to use one "%s" to create dynamic files +# +# Mode: Mode to open the file (read as optional2 if Type = File) +# a - (Append) +# w - (Overwrite) +# +# MaxFileSize: Maximum file size of the log file before creating a new log file +# (read as optional3 if Type = File) +# Size is measured in bytes expressed in a 64-bit unsigned integer. +# Maximum value is 4294967295 (4 GB). Leave blank for no limit. +# NOTE: Does not work with dynamic filenames. +# Example: 536870912 (512 MB) +# +Appender.ElunaLog=2,5,0,eluna.log,w +Appender.ElunaConsole=1,4,0,"0 9 0 3 5 0" + +# Logger config values: Given a logger "name" +# Logger.name +# Description: Defines 'What to log' +# Format: LogLevel,AppenderList +# +# LogLevel +# 0 - (Disabled) +# 1 - (Fatal) +# 2 - (Error) +# 3 - (Warning) +# 4 - (Info) +# 5 - (Debug) +# 6 - (Trace) +# +# AppenderList: List of appenders linked to logger +# (Using spaces as separator). +# +Logger.eluna=6,ElunaLog ElunaConsole diff --git a/modules/mod-eluna/icon.png b/modules/mod-eluna/icon.png new file mode 100644 index 0000000..35e9047 Binary files /dev/null and b/modules/mod-eluna/icon.png differ diff --git a/modules/mod-eluna/include.sh b/modules/mod-eluna/include.sh new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-eluna/sql/README.md b/modules/mod-eluna/sql/README.md new file mode 100644 index 0000000..3afd348 --- /dev/null +++ b/modules/mod-eluna/sql/README.md @@ -0,0 +1,24 @@ +# BEST PRACTICES + +## Create a new table + +**Example:** +``` +CREATE TABLE IF NOT EXISTS `table`( + `id` int(11) unsigned NOT NULL, + `active` BOOLEAN DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +**Boolean datatype in mysql:** +Use "TinyInt(1)"" or "Boolean" (this is the same thing) + +"bit(1)" can also work, but it may require a syntax like b'(0) and b'(1) when inserting (not sure). + +If there are multiple booleans in the same table, bit(1) is better, otherwise it's the same result. + + +## Resources + +https://www.w3schools.com/sql/sql_datatypes.asp diff --git a/modules/mod-eluna/sql/auth/.gitkeep b/modules/mod-eluna/sql/auth/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-eluna/sql/characters/.gitkeep b/modules/mod-eluna/sql/characters/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-eluna/sql/world/.gitkeep b/modules/mod-eluna/sql/world/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-eluna/src/ElunaLuaEngine_SC.cpp b/modules/mod-eluna/src/ElunaLuaEngine_SC.cpp new file mode 100644 index 0000000..803044c --- /dev/null +++ b/modules/mod-eluna/src/ElunaLuaEngine_SC.cpp @@ -0,0 +1,1014 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Chat.h" +#include "ElunaEventMgr.h" +#include "Log.h" +#include "LuaEngine.h" +#include "Pet.h" +#include "Player.h" +#include "ScriptMgr.h" +#include "ScriptedGossip.h" + +class Eluna_AllCreatureScript : public AllCreatureScript +{ +public: + Eluna_AllCreatureScript() : AllCreatureScript("Eluna_AllCreatureScript") { } + + // Creature + bool CanCreatureGossipHello(Player* player, Creature* creature) override + { + if (sEluna->OnGossipHello(player, creature)) + return true; + + return false; + } + + bool CanCreatureGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override + { + if (sEluna->OnGossipSelect(player, creature, sender, action)) + return true; + + return false; + } + + bool CanCreatureGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) override + { + if (sEluna->OnGossipSelectCode(player, creature, sender, action, code)) + return true; + + return false; + } + + void OnCreatureAddWorld(Creature* creature) override + { + sEluna->OnAddToWorld(creature); + + if (creature->IsGuardian() && creature->ToTempSummon() && creature->ToTempSummon()->GetSummonerGUID().IsPlayer()) + sEluna->OnPetAddedToWorld(creature->ToTempSummon()->GetSummonerUnit()->ToPlayer(), creature); + } + + void OnCreatureRemoveWorld(Creature* creature) override + { + sEluna->OnRemoveFromWorld(creature); + } + + bool CanCreatureQuestAccept(Player* player, Creature* creature, Quest const* quest) override + { + sEluna->OnQuestAccept(player, creature, quest); + return false; + } + + bool CanCreatureQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt) override + { + if (sEluna->OnQuestReward(player, creature, quest, opt)) + { + ClearGossipMenuFor(player); + return true; + } + + return false; + } + + CreatureAI* GetCreatureAI(Creature* creature) const override + { + if (CreatureAI* luaAI = sEluna->GetAI(creature)) + return luaAI; + + return nullptr; + } +}; + +class Eluna_AllGameObjectScript : public AllGameObjectScript +{ +public: + Eluna_AllGameObjectScript() : AllGameObjectScript("Eluna_AllGameObjectScript") { } + + void OnGameObjectAddWorld(GameObject* go) override + { + sEluna->OnAddToWorld(go); + } + + void OnGameObjectRemoveWorld(GameObject* go) override + { + sEluna->OnRemoveFromWorld(go); + } + + void OnGameObjectUpdate(GameObject* go, uint32 diff) override + { + sEluna->UpdateAI(go, diff); + } + + bool CanGameObjectGossipHello(Player* player, GameObject* go) override + { + if (sEluna->OnGossipHello(player, go)) + return true; + + if (sEluna->OnGameObjectUse(player, go)) + return true; + + return false; + } + + void OnGameObjectDamaged(GameObject* go, Player* player) override + { + sEluna->OnDamaged(go, player); + } + + void OnGameObjectDestroyed(GameObject* go, Player* player) override + { + sEluna->OnDestroyed(go, player); + } + + void OnGameObjectLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override + { + sEluna->OnLootStateChanged(go, state); + } + + void OnGameObjectStateChanged(GameObject* go, uint32 state) override + { + sEluna->OnGameObjectStateChanged(go, state); + } + + bool CanGameObjectQuestAccept(Player* player, GameObject* go, Quest const* quest) override + { + sEluna->OnQuestAccept(player, go, quest); + return false; + } + + bool CanGameObjectGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) override + { + if (sEluna->OnGossipSelect(player, go, sender, action)) + return true; + + return false; + } + + bool CanGameObjectGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code) override + { + if (sEluna->OnGossipSelectCode(player, go, sender, action, code)) + return true; + + return false; + } + + bool CanGameObjectQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt) override + { + if (sEluna->OnQuestAccept(player, go, quest)) + return false; + + if (sEluna->OnQuestReward(player, go, quest, opt)) + return false; + + return true; + } + + GameObjectAI* GetGameObjectAI(GameObject* go) const override + { + sEluna->OnSpawn(go); + return nullptr; + } +}; + +class Eluna_AllItemScript : public AllItemScript +{ +public: + Eluna_AllItemScript() : AllItemScript("Eluna_AllItemScript") { } + + bool CanItemQuestAccept(Player* player, Item* item, Quest const* quest) override + { + if (sEluna->OnQuestAccept(player, item, quest)) + return false; + + return true; + } + + bool CanItemUse(Player* player, Item* item, SpellCastTargets const& targets) override + { + if (!sEluna->OnUse(player, item, targets)) + return true; + + return false; + } + + bool CanItemExpire(Player* player, ItemTemplate const* proto) override + { + if (sEluna->OnExpire(player, proto)) + return false; + + return true; + } + + bool CanItemRemove(Player* player, Item* item) override + { + if (sEluna->OnRemove(player, item)) + return false; + + return true; + } + + void OnItemGossipSelect(Player* player, Item* item, uint32 sender, uint32 action) override + { + sEluna->HandleGossipSelectOption(player, item, sender, action, ""); + } + + void OnItemGossipSelectCode(Player* player, Item* item, uint32 sender, uint32 action, const char* code) override + { + sEluna->HandleGossipSelectOption(player, item, sender, action, code); + } +}; + +class Eluna_AllMapScript : public AllMapScript +{ +public: + Eluna_AllMapScript() : AllMapScript("Eluna_AllMapScript") { } + + void OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript* instanceData, bool /*load*/, std::string /*data*/, uint32 /*completedEncounterMask*/) override + { + instanceData = sEluna->GetInstanceData(instanceMap); + } + + void OnDestroyInstance(MapInstanced* /*mapInstanced*/, Map* map) override + { + sEluna->FreeInstanceId(map->GetInstanceId()); + } + + void OnCreateMap(Map* map) override + { + sEluna->OnCreate(map); + } + + void OnDestroyMap(Map* map) override + { + sEluna->OnDestroy(map); + } + + void OnPlayerEnterAll(Map* map, Player* player) override + { + sEluna->OnPlayerEnter(map, player); + } + + void OnPlayerLeaveAll(Map* map, Player* player) override + { + sEluna->OnPlayerLeave(map, player); + } + + void OnMapUpdate(Map* map, uint32 diff) override + { + sEluna->OnUpdate(map, diff); + } +}; + +class Eluna_AuctionHouseScript : public AuctionHouseScript +{ +public: + Eluna_AuctionHouseScript() : AuctionHouseScript("Eluna_AuctionHouseScript") { } + + void OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry) override + { + sEluna->OnAdd(ah, entry); + } + + void OnAuctionRemove(AuctionHouseObject* ah, AuctionEntry* entry) override + { + sEluna->OnRemove(ah, entry); + } + + void OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry) override + { + sEluna->OnSuccessful(ah, entry); + } + + void OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry) override + { + sEluna->OnExpire(ah, entry); + } +}; + +class Eluna_BGScript : public BGScript +{ +public: + Eluna_BGScript() : BGScript("Eluna_BGScript") { } + + void OnBattlegroundStart(Battleground* bg) override + { + sEluna->OnBGStart(bg, bg->GetBgTypeID(), bg->GetInstanceID()); + } + + void OnBattlegroundEnd(Battleground* bg, TeamId winnerTeam) override + { + sEluna->OnBGEnd(bg, bg->GetBgTypeID(), bg->GetInstanceID(), winnerTeam); + } + + void OnBattlegroundDestroy(Battleground* bg) override + { + sEluna->OnBGDestroy(bg, bg->GetBgTypeID(), bg->GetInstanceID()); + } + + void OnBattlegroundCreate(Battleground* bg) override + { + sEluna->OnBGCreate(bg, bg->GetBgTypeID(), bg->GetInstanceID()); + } +}; + +class Eluna_CommandSC : public CommandSC +{ +public: + Eluna_CommandSC() : CommandSC("Eluna_CommandSC") { } + + bool CanExecuteCommand(ChatHandler& handler, std::string_view cmdStr) override + { + if (!sEluna->OnCommand(handler, std::string(cmdStr).c_str())) + { + return false; + } + + return true; + } +}; + +class Eluna_ElunaScript : public ElunaScript +{ +public: + Eluna_ElunaScript() : ElunaScript("Eluna_ElunaScript") { } + + // Weather + void OnWeatherChange(Weather* weather, WeatherState state, float grade) override + { + sEluna->OnChange(weather, weather->GetZone(), state, grade); + } + + // AreaTriger + bool CanAreaTrigger(Player* player, AreaTrigger const* trigger) override + { + if (sEluna->OnAreaTrigger(player, trigger)) + return true; + + return false; + } +}; + +class Eluna_GameEventScript : public GameEventScript +{ +public: + Eluna_GameEventScript() : GameEventScript("Eluna_GameEventScript") { } + + void OnStart(uint16 eventID) override + { + sEluna->OnGameEventStart(eventID); + } + + void OnStop(uint16 eventID) override + { + sEluna->OnGameEventStop(eventID); + } +}; + +class Eluna_GroupScript : public GroupScript +{ +public: + Eluna_GroupScript() : GroupScript("Eluna_GroupScript") { } + + void OnAddMember(Group* group, ObjectGuid guid) override + { + sEluna->OnAddMember(group, guid); + } + + void OnInviteMember(Group* group, ObjectGuid guid) override + { + sEluna->OnInviteMember(group, guid); + } + + void OnRemoveMember(Group* group, ObjectGuid guid, RemoveMethod method, ObjectGuid /* kicker */, const char* /* reason */) override + { + sEluna->OnRemoveMember(group, guid, method); + } + + void OnChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid) override + { + sEluna->OnChangeLeader(group, newLeaderGuid, oldLeaderGuid); + } + + void OnDisband(Group* group) override + { + sEluna->OnDisband(group); + } + + void OnCreate(Group* group, Player* leader) override + { + sEluna->OnCreate(group, leader->GetGUID(), group->GetGroupType()); + } +}; + +class Eluna_GuildScript : public GuildScript +{ +public: + Eluna_GuildScript() : GuildScript("Eluna_GuildScript") { } + + void OnAddMember(Guild* guild, Player* player, uint8& plRank) override + { + sEluna->OnAddMember(guild, player, plRank); + } + + void OnRemoveMember(Guild* guild, Player* player, bool isDisbanding, bool /*isKicked*/) override + { + sEluna->OnRemoveMember(guild, player, isDisbanding); + } + + void OnMOTDChanged(Guild* guild, const std::string& newMotd) override + { + sEluna->OnMOTDChanged(guild, newMotd); + } + + void OnInfoChanged(Guild* guild, const std::string& newInfo) override + { + sEluna->OnInfoChanged(guild, newInfo); + } + + void OnCreate(Guild* guild, Player* leader, const std::string& name) override + { + sEluna->OnCreate(guild, leader, name); + } + + void OnDisband(Guild* guild) override + { + sEluna->OnDisband(guild); + } + + void OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) override + { + sEluna->OnMemberWitdrawMoney(guild, player, amount, isRepair); + } + + void OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) override + { + sEluna->OnMemberDepositMoney(guild, player, amount); + } + + void OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, + bool isDestBank, uint8 destContainer, uint8 destSlotId) override + { + sEluna->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId); + } + + void OnEvent(Guild* guild, uint8 eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) override + { + sEluna->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank); + } + + void OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) override + { + sEluna->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId); + } +}; + +class Eluna_LootScript : public LootScript +{ +public: + Eluna_LootScript() : LootScript("Eluna_LootScript") { } + + void OnLootMoney(Player* player, uint32 gold) override + { + sEluna->OnLootMoney(player, gold); + } +}; + +class Eluna_MiscScript : public MiscScript +{ +public: + Eluna_MiscScript() : MiscScript("Eluna_MiscScript") { } + + void GetDialogStatus(Player* player, Object* questgiver) override + { + if (questgiver->GetTypeId() == TYPEID_GAMEOBJECT) + sEluna->GetDialogStatus(player, questgiver->ToGameObject()); + else if (questgiver->GetTypeId() == TYPEID_UNIT) + sEluna->GetDialogStatus(player, questgiver->ToCreature()); + } +}; + +class Eluna_PetScript : public PetScript +{ +public: + Eluna_PetScript() : PetScript("Eluna_PetScript") { } + + void OnPetAddToWorld(Pet* pet) override + { + sEluna->OnPetAddedToWorld(pet->GetOwner(), pet); + } +}; + +class Eluna_PlayerScript : public PlayerScript +{ +public: + Eluna_PlayerScript() : PlayerScript("Eluna_PlayerScript") { } + + void OnPlayerResurrect(Player* player, float /*restore_percent*/, bool /*applySickness*/) override + { + sEluna->OnResurrect(player); + } + + bool CanPlayerUseChat(Player* player, uint32 type, uint32 lang, std::string& msg) override + { + if (type != CHAT_MSG_SAY && type != CHAT_MSG_YELL && type != CHAT_MSG_EMOTE) + return true; + + if (!sEluna->OnChat(player, type, lang, msg)) + return false; + + return true; + } + + bool CanPlayerUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* target) override + { + if (!sEluna->OnChat(player, type, lang, msg, target)) + return false; + + return true; + } + + bool CanPlayerUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override + { + if (!sEluna->OnChat(player, type, lang, msg, group)) + return false; + + return true; + } + + bool CanPlayerUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override + { + if (!sEluna->OnChat(player, type, lang, msg, guild)) + return false; + + return true; + } + + bool CanPlayerUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel) override + { + if (!sEluna->OnChat(player, type, lang, msg, channel)) + return false; + + return true; + } + + void OnLootItem(Player* player, Item* item, uint32 count, ObjectGuid lootguid) override + { + sEluna->OnLootItem(player, item, count, lootguid); + } + + void OnPlayerLearnTalents(Player* player, uint32 talentId, uint32 talentRank, uint32 spellid) override + { + sEluna->OnLearnTalents(player, talentId, talentRank, spellid); + } + + bool CanUseItem(Player* player, ItemTemplate const* proto, InventoryResult& result) override + { + result = sEluna->OnCanUseItem(player, proto->ItemId); + return result != EQUIP_ERR_OK ? false : true; + } + + void OnEquip(Player* player, Item* it, uint8 bag, uint8 slot, bool /*update*/) override + { + sEluna->OnEquip(player, it, bag, slot); + } + + void OnPlayerEnterCombat(Player* player, Unit* enemy) override + { + sEluna->OnPlayerEnterCombat(player, enemy); + } + + void OnPlayerLeaveCombat(Player* player) override + { + sEluna->OnPlayerLeaveCombat(player); + } + + bool CanRepopAtGraveyard(Player* player) override + { + sEluna->OnRepop(player); + return true; + } + + void OnQuestAbandon(Player* player, uint32 questId) override + { + sEluna->OnQuestAbandon(player, questId); + } + + void OnMapChanged(Player* player) override + { + sEluna->OnMapChanged(player); + } + + void OnGossipSelect(Player* player, uint32 menu_id, uint32 sender, uint32 action) override + { + sEluna->HandleGossipSelectOption(player, menu_id, sender, action, ""); + } + + void OnGossipSelectCode(Player* player, uint32 menu_id, uint32 sender, uint32 action, const char* code) override + { + sEluna->HandleGossipSelectOption(player, menu_id, sender, action, code); + } + + void OnPVPKill(Player* killer, Player* killed) override + { + sEluna->OnPVPKill(killer, killed); + } + + void OnCreatureKill(Player* killer, Creature* killed) override + { + sEluna->OnCreatureKill(killer, killed); + } + + void OnPlayerKilledByCreature(Creature* killer, Player* killed) override + { + sEluna->OnPlayerKilledByCreature(killer, killed); + } + + void OnLevelChanged(Player* player, uint8 oldLevel) override + { + sEluna->OnLevelChanged(player, oldLevel); + } + + void OnFreeTalentPointsChanged(Player* player, uint32 points) override + { + sEluna->OnFreeTalentPointsChanged(player, points); + } + + void OnTalentsReset(Player* player, bool noCost) override + { + sEluna->OnTalentsReset(player, noCost); + } + + void OnMoneyChanged(Player* player, int32& amount) override + { + sEluna->OnMoneyChanged(player, amount); + } + + void OnGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) override + { + sEluna->OnGiveXP(player, amount, victim, xpSource); + } + + bool OnReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental) override + { + return sEluna->OnReputationChange(player, factionID, standing, incremental); + } + + void OnDuelRequest(Player* target, Player* challenger) override + { + sEluna->OnDuelRequest(target, challenger); + } + + void OnDuelStart(Player* player1, Player* player2) override + { + sEluna->OnDuelStart(player1, player2); + } + + void OnDuelEnd(Player* winner, Player* loser, DuelCompleteType type) override + { + sEluna->OnDuelEnd(winner, loser, type); + } + + void OnEmote(Player* player, uint32 emote) override + { + sEluna->OnEmote(player, emote); + } + + void OnTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, ObjectGuid guid) override + { + sEluna->OnTextEmote(player, textEmote, emoteNum, guid); + } + + void OnSpellCast(Player* player, Spell* spell, bool skipCheck) override + { + sEluna->OnSpellCast(player, spell, skipCheck); + } + + void OnLogin(Player* player) override + { + sEluna->OnLogin(player); + } + + void OnLogout(Player* player) override + { + sEluna->OnLogout(player); + } + + void OnCreate(Player* player) override + { + sEluna->OnCreate(player); + } + + void OnSave(Player* player) override + { + sEluna->OnSave(player); + } + + void OnDelete(ObjectGuid guid, uint32 /*accountId*/) override + { + sEluna->OnDelete(guid.GetCounter()); + } + + void OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent) override + { + sEluna->OnBindToInstance(player, difficulty, mapid, permanent); + } + + void OnUpdateArea(Player* player, uint32 oldArea, uint32 newArea) override + { + sEluna->OnUpdateArea(player, oldArea, newArea); + } + + void OnUpdateZone(Player* player, uint32 newZone, uint32 newArea) override + { + sEluna->OnUpdateZone(player, newZone, newArea); + } + + void OnFirstLogin(Player* player) override + { + sEluna->OnFirstLogin(player); + } + + void OnLearnSpell(Player* player, uint32 spellId) override + { + sEluna->OnLearnSpell(player, spellId); + } + + void OnAchiComplete(Player* player, AchievementEntry const* achievement) override + { + sEluna->OnAchiComplete(player, achievement); + } + + void OnFfaPvpStateUpdate(Player* player, bool IsFlaggedForFfaPvp) override + { + sEluna->OnFfaPvpStateUpdate(player, IsFlaggedForFfaPvp); + } + + bool CanInitTrade(Player* player, Player* target) override + { + return sEluna->OnCanInitTrade(player, target); + } + + bool CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 cod, Item* item) override + { + return sEluna->OnCanSendMail(player, receiverGuid, mailbox, subject, body, money, cod, item); + } + + bool CanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment) override + { + return sEluna->OnCanJoinLfg(player, roles, dungeons, comment); + } + + void OnQuestRewardItem(Player* player, Item* item, uint32 count) override + { + sEluna->OnQuestRewardItem(player, item, count); + } + + void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll) override + { + sEluna->OnGroupRollRewardItem(player, item, count, voteType, roll); + } + + void OnCreateItem(Player* player, Item* item, uint32 count) override + { + sEluna->OnCreateItem(player, item, count); + } + + void OnStoreNewItem(Player* player, Item* item, uint32 count) override + { + sEluna->OnStoreNewItem(player, item, count); + } + + void OnPlayerCompleteQuest(Player* player, Quest const* quest) override + { + sEluna->OnPlayerCompleteQuest(player, quest); + } + + bool CanGroupInvite(Player* player, std::string& memberName) override + { + return sEluna->OnCanGroupInvite(player, memberName); + } + + void OnBattlegroundDesertion(Player* player, const BattlegroundDesertionType type) override + { + sEluna->OnBattlegroundDesertion(player, type); + } +}; + +class Eluna_ServerScript : public ServerScript +{ +public: + Eluna_ServerScript() : ServerScript("Eluna_ServerScript") { } + + bool CanPacketSend(WorldSession* session, WorldPacket& packet) override + { + if (!sEluna->OnPacketSend(session, packet)) + return false; + + return true; + } + + bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override + { + if (!sEluna->OnPacketReceive(session, packet)) + return false; + + return true; + } +}; + +class Eluna_SpellSC : public SpellSC +{ +public: + Eluna_SpellSC() : SpellSC("Eluna_SpellSC") { } + + void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, GameObject* gameObjTarget) override + { + sEluna->OnDummyEffect(caster, spellID, effIndex, gameObjTarget); + } + + void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Creature* creatureTarget) override + { + sEluna->OnDummyEffect(caster, spellID, effIndex, creatureTarget); + } + + void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Item* itemTarget) override + { + sEluna->OnDummyEffect(caster, spellID, effIndex, itemTarget); + } +}; + +class Eluna_UnitScript : public UnitScript +{ +public: + Eluna_UnitScript() : UnitScript("Eluna_UnitScript") { } + + void OnUnitUpdate(Unit* unit, uint32 diff) override + { + unit->elunaEvents->Update(diff); + } +}; + +class Eluna_VehicleScript : public VehicleScript +{ +public: + Eluna_VehicleScript() : VehicleScript("Eluna_VehicleScript") { } + + void OnInstall(Vehicle* veh) override + { + sEluna->OnInstall(veh); + } + + void OnUninstall(Vehicle* veh) override + { + sEluna->OnUninstall(veh); + } + + void OnInstallAccessory(Vehicle* veh, Creature* accessory) override + { + sEluna->OnInstallAccessory(veh, accessory); + } + + void OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId) override + { + sEluna->OnAddPassenger(veh, passenger, seatId); + } + + void OnRemovePassenger(Vehicle* veh, Unit* passenger) override + { + sEluna->OnRemovePassenger(veh, passenger); + } +}; + +class Eluna_WorldObjectScript : public WorldObjectScript +{ +public: + Eluna_WorldObjectScript() : WorldObjectScript("Eluna_WorldObjectScript") { } + + void OnWorldObjectDestroy(WorldObject* object) override + { + delete object->elunaEvents; + object->elunaEvents = nullptr; + } + + void OnWorldObjectCreate(WorldObject* object) override + { + object->elunaEvents = nullptr; + } + + void OnWorldObjectSetMap(WorldObject* object, Map* /*map*/) override + { + if (!object->elunaEvents) + object->elunaEvents = new ElunaEventProcessor(&Eluna::GEluna, object); + } + + void OnWorldObjectUpdate(WorldObject* object, uint32 diff) override + { + object->elunaEvents->Update(diff); + } +}; + +class Eluna_WorldScript : public WorldScript +{ +public: + Eluna_WorldScript() : WorldScript("Eluna_WorldScript") { } + + void OnOpenStateChange(bool open) override + { + sEluna->OnOpenStateChange(open); + } + + void OnBeforeConfigLoad(bool reload) override + { + if (!reload) + { + ///- Initialize Lua Engine + LOG_INFO("eluna", "Initialize Eluna Lua Engine..."); + Eluna::Initialize(); + } + + sEluna->OnConfigLoad(reload, true); + } + + void OnAfterConfigLoad(bool reload) override + { + sEluna->OnConfigLoad(reload, false); + } + + void OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) override + { + sEluna->OnShutdownInitiate(code, mask); + } + + void OnShutdownCancel() override + { + sEluna->OnShutdownCancel(); + } + + void OnUpdate(uint32 diff) override + { + sEluna->OnWorldUpdate(diff); + } + + void OnStartup() override + { + sEluna->OnStartup(); + } + + void OnShutdown() override + { + sEluna->OnShutdown(); + } + + void OnAfterUnloadAllMaps() override + { + Eluna::Uninitialize(); + } + + void OnBeforeWorldInitialized() override + { + ///- Run eluna scripts. + // in multithread foreach: run scripts + sEluna->RunScripts(); + sEluna->OnConfigLoad(false, false); // Must be done after Eluna is initialized and scripts have run. + } +}; + +// Group all custom scripts +void AddSC_ElunaLuaEngine() +{ + new Eluna_AllCreatureScript(); + new Eluna_AllGameObjectScript(); + new Eluna_AllItemScript(); + new Eluna_AllMapScript(); + new Eluna_AuctionHouseScript(); + new Eluna_BGScript(); + new Eluna_CommandSC(); + new Eluna_ElunaScript(); + new Eluna_GameEventScript(); + new Eluna_GroupScript(); + new Eluna_GuildScript(); + new Eluna_LootScript(); + new Eluna_MiscScript(); + new Eluna_PetScript(); + new Eluna_PlayerScript(); + new Eluna_ServerScript(); + new Eluna_SpellSC(); + new Eluna_UnitScript(); + new Eluna_VehicleScript(); + new Eluna_WorldObjectScript(); + new Eluna_WorldScript(); +} diff --git a/modules/mod-eluna/src/LuaEngine/.editorconfig b/modules/mod-eluna/src/LuaEngine/.editorconfig new file mode 100644 index 0000000..a34283a --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/.editorconfig @@ -0,0 +1,7 @@ +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/modules/mod-eluna/src/LuaEngine/.github/workflows/build.yml b/modules/mod-eluna/src/LuaEngine/.github/workflows/build.yml new file mode 100644 index 0000000..f2bbef4 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/.github/workflows/build.yml @@ -0,0 +1,63 @@ +name: build + +on: + push: + pull_request: + +jobs: + + AC-Eluna: + strategy: + fail-fast: false + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + repository: azerothcore/azerothcore-wotlk + ref: 'master' + - uses: actions/checkout@v2 + with: + submodules: false + repository: azerothcore/mod-eluna-lua-engine + path: modules/mod-eluna-lua-engine + - uses: actions/checkout@v2 + with: + path: modules/mod-eluna-lua-engine/LuaEngine + - name: Configure OS + run: | + # Copy paste of https://github.com/azerothcore/azerothcore-wotlk/blob/master/apps/ci/ci-install.sh + + cat >>conf/config.sh <> ./conf/config.sh + echo "CCOMPILERCXX=\"clang++-11\"" >> ./conf/config.sh + - name: Import db + run: source ./apps/ci/ci-import-db.sh + - name: Build + run: source ./apps/ci/ci-compile.sh + - name: Dry run + run: source ./apps/ci/ci-worldserver-dry-run.sh + - name: Check startup errors + run: source ./apps/ci/ci-error-check.sh diff --git a/modules/mod-eluna/src/LuaEngine/.github/workflows/create-pr.sh b/modules/mod-eluna/src/LuaEngine/.github/workflows/create-pr.sh new file mode 100644 index 0000000..3788970 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/.github/workflows/create-pr.sh @@ -0,0 +1,36 @@ +# Adapted from https://github.com/paygoc6/action-pull-request-another-repo + +CLONE_DIR=$(mktemp -d) + +echo "Setting git variables" +export GITHUB_TOKEN=$API_TOKEN_GITHUB +git config --global user.email "$USER_EMAIL" +git config --global user.name "$USER_NAME" + +echo "Cloning destination git repository" +git clone "https://$API_TOKEN_GITHUB@github.com/$DESTINATION_REPO.git" "$CLONE_DIR" +cd "$CLONE_DIR" +git checkout "$DESTINATION_BASE_BRANCH" +git pull origin "$DESTINATION_BASE_BRANCH" +git checkout -b "$DESTINATION_HEAD_BRANCH" + +echo "Copying contents to git repo" +mkdir -p "$CLONE_DIR/$DESTINATION_FOLDER" +cp -r "$SOURCE_FOLDER/." "$CLONE_DIR/$DESTINATION_FOLDER/" + +echo "Adding files" +git add . +if git status | grep -q "Changes to be committed" +then + echo "Adding git commit" + git commit -m "$COMMIT_MESSAGE" + echo "Pushing git commit" + git push -u origin "$DESTINATION_HEAD_BRANCH" + echo "Creating a pull request" + gh pr create -t "$PR_TITLE" \ + -B "$DESTINATION_BASE_BRANCH" \ + -b "" \ + -H "$DESTINATION_HEAD_BRANCH" +else + echo "No changes detected" +fi diff --git a/modules/mod-eluna/src/LuaEngine/.github/workflows/documentation.yml b/modules/mod-eluna/src/LuaEngine/.github/workflows/documentation.yml new file mode 100644 index 0000000..9cdcdbd --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/.github/workflows/documentation.yml @@ -0,0 +1,38 @@ +name: Documentation +on: + push: + branches: + - 'main' + - 'master' +jobs: + Push-Docs-To-AzerothCore-Website: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + architecture: 'x64' + - name: Install Python dependencies + run: pip install jinja2 typedecorator markdown + - name: Compile documentation + run: | + cd ${{ github.workspace }}/docs/ + python -m ElunaDoc + - name: Create pull request + run: | + chmod +x "${GITHUB_WORKSPACE}/.github/workflows/create-pr.sh" + "${GITHUB_WORKSPACE}/.github/workflows/create-pr.sh" + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + SOURCE_FOLDER: '${{ github.workspace }}/docs/build' + DESTINATION_REPO: 'azerothcore/azerothcore.github.io' + DESTINATION_FOLDER: 'pages/eluna' + DESTINATION_BASE_BRANCH: 'master' + DESTINATION_HEAD_BRANCH: 'eluna-docs' + PR_TITLE: 'chore: update eluna documentation' + COMMIT_MESSAGE: 'chore: update eluna documentation' + USER_EMAIL: 'ax.cocat@gmail.com' + USER_NAME: 'r-o-b-o-t-o' diff --git a/modules/mod-eluna/src/LuaEngine/AchievementMethods.h b/modules/mod-eluna/src/LuaEngine/AchievementMethods.h new file mode 100644 index 0000000..e508f09 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/AchievementMethods.h @@ -0,0 +1,54 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef ACHIEVEMENTMETHODS_H +#define ACHIEVEMENTMETHODS_H + +namespace LuaAchievement +{ + /** + * Returns the [Achievement]'s ID. + * + * @return uint32 id + */ + int GetId(lua_State* L, AchievementEntry* const achievement) + { + Eluna::Push(L, achievement->ID); + return 1; + } + + /** + * Returns the [Achievement]'s name. + * + * enum LocaleConstant + * { + * LOCALE_enUS = 0, + * LOCALE_koKR = 1, + * LOCALE_frFR = 2, + * LOCALE_deDE = 3, + * LOCALE_zhCN = 4, + * LOCALE_zhTW = 5, + * LOCALE_esES = 6, + * LOCALE_esMX = 7, + * LOCALE_ruRU = 8 + * }; + * + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Achievement] name in + * @return string name + */ + int GetName(lua_State* L, AchievementEntry* const achievement) + { + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + { + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + } + + Eluna::Push(L, achievement->name[locale]); + return 1; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/AuraMethods.h b/modules/mod-eluna/src/LuaEngine/AuraMethods.h new file mode 100644 index 0000000..081da95 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/AuraMethods.h @@ -0,0 +1,211 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef AURAMETHODS_H +#define AURAMETHODS_H + +/*** + * The persistent effect of a [Spell] that remains on a [Unit] after the [Spell] + * has been cast. + * + * As an example, if you cast a damage-over-time spell on a target, an [Aura] is + * put on the target that deals damage continuously. + * + * [Aura]s on your player are displayed in-game as a series of icons to the left + * of the mini-map. + * + * Inherits all methods from: none + */ +namespace LuaAura +{ + /** + * Returns the [Unit] that casted the [Spell] that caused this [Aura] to be applied. + * + * @return [Unit] caster + */ + int GetCaster(lua_State* L, Aura* aura) + { + Eluna::Push(L, aura->GetCaster()); + return 1; + } + + /** + * Returns the GUID of the [Unit] that casted the [Spell] that caused this [Aura] to be applied. + * + * @return string caster_guid : the GUID of the Unit as a decimal string + */ + int GetCasterGUID(lua_State* L, Aura* aura) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, aura->GetCasterGUID()); +#else + Eluna::Push(L, aura->GetCasterGuid()); +#endif + return 1; + } + + /** + * Returns the level of the [Unit] that casted the [Spell] that caused this [Aura] to be applied. + * + * @return uint32 caster_level + */ + int GetCasterLevel(lua_State* L, Aura* aura) + { + Eluna::Push(L, aura->GetCaster()->GetLevel()); + return 1; + } + + /** + * Returns the amount of time left until the [Aura] expires. + * + * @return int32 duration : amount of time left in milliseconds + */ + int GetDuration(lua_State* L, Aura* aura) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, aura->GetDuration()); +#else + Eluna::Push(L, aura->GetAuraDuration()); +#endif + return 1; + } + + /** + * Returns the ID of the [Spell] that caused this [Aura] to be applied. + * + * @return uint32 aura_id + */ + int GetAuraId(lua_State* L, Aura* aura) + { + Eluna::Push(L, aura->GetId()); + return 1; + } + + /** + * Returns the amount of time this [Aura] lasts when applied. + * + * To determine how much time has passed since this Aura was applied, + * subtract the result of [Aura]:GetDuration from the result of this method. + * + * @return int32 max_duration : the maximum duration of the Aura, in milliseconds + */ + int GetMaxDuration(lua_State* L, Aura* aura) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, aura->GetMaxDuration()); +#else + Eluna::Push(L, aura->GetAuraMaxDuration()); +#endif + return 1; + } + + /** + * Returns the number of times the [Aura] has "stacked". + * + * This is the same as the number displayed on the [Aura]'s icon in-game. + * + * @return uint32 stack_amount + */ + int GetStackAmount(lua_State* L, Aura* aura) + { + Eluna::Push(L, aura->GetStackAmount()); + return 1; + } + + /** + * Returns the [Unit] that the [Aura] has been applied to. + * + * @return [Unit] owner + */ + int GetOwner(lua_State* L, Aura* aura) + { +#if defined TRINITY || defined AZEROTHCORE + Eluna::Push(L, aura->GetOwner()); +#else + Eluna::Push(L, aura->GetTarget()); +#endif + return 1; + } + + /** + * Change the amount of time before the [Aura] expires. + * + * @param int32 duration : the new duration of the Aura, in milliseconds + */ + int SetDuration(lua_State* L, Aura* aura) + { + int32 duration = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || defined AZEROTHCORE + aura->SetDuration(duration); +#else + aura->GetHolder()->SetAuraDuration(duration); +#if (defined(TBC) || defined(CLASSIC)) + aura->GetHolder()->UpdateAuraDuration(); +#else + aura->GetHolder()->SendAuraUpdate(false); +#endif +#endif + return 0; + } + + /** + * Change the maximum amount of time before the [Aura] expires. + * + * This does not affect the current duration of the [Aura], but if the [Aura] + * is reset to the maximum duration, it will instead change to `duration`. + * + * @param int32 duration : the new maximum duration of the Aura, in milliseconds + */ + int SetMaxDuration(lua_State* L, Aura* aura) + { + int32 duration = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || defined AZEROTHCORE + aura->SetMaxDuration(duration); +#else + aura->GetHolder()->SetAuraMaxDuration(duration); +#if (defined(TBC) || defined(CLASSIC)) + aura->GetHolder()->UpdateAuraDuration(); +#else + aura->GetHolder()->SendAuraUpdate(false); +#endif +#endif + return 0; + } + + /** + * Change the amount of times the [Aura] has "stacked" on the [Unit]. + * + * If `amount` is greater than or equal to the current number of stacks, + * then the [Aura] has its duration reset to the maximum duration. + * + * @param uint32 amount + */ + int SetStackAmount(lua_State* L, Aura* aura) + { + uint8 amount = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || defined AZEROTHCORE + aura->SetStackAmount(amount); +#else + aura->GetHolder()->SetStackAmount(amount); +#endif + return 0; + } + + /** + * Remove this [Aura] from the [Unit] it is applied to. + */ + int Remove(lua_State* L, Aura* aura) + { +#if defined TRINITY || defined AZEROTHCORE + aura->Remove(); +#else + aura->GetTarget()->RemoveSpellAuraHolder(aura->GetHolder(), AURA_REMOVE_BY_CANCEL); +#endif + Eluna::CHECKOBJ(L, 1)->Invalidate(); + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/BattleGroundHooks.cpp b/modules/mod-eluna/src/LuaEngine/BattleGroundHooks.cpp new file mode 100644 index 0000000..497256d --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/BattleGroundHooks.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!BGEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + START_HOOK(BG_EVENT_ON_START); + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, key); +} + +#if AZEROTHCORE +void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, TeamId winner) +#else +void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner) +#endif +{ + START_HOOK(BG_EVENT_ON_END); + Push(bg); + Push(bgId); + Push(instanceId); + Push(winner); + CallAllFunctions(BGEventBindings, key); +} + +void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + START_HOOK(BG_EVENT_ON_CREATE); + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, key); +} + +void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + START_HOOK(BG_EVENT_ON_PRE_DESTROY); + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/BattleGroundMethods.h b/modules/mod-eluna/src/LuaEngine/BattleGroundMethods.h new file mode 100644 index 0000000..98b4a8d --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/BattleGroundMethods.h @@ -0,0 +1,250 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef BATTLEGROUNDMETHODS_H +#define BATTLEGROUNDMETHODS_H + +/*** + * Contains the state of a battleground, e.g. Warsong Gulch, Arathi Basin, etc. + * + * Inherits all methods from: none + */ +namespace LuaBattleGround +{ + /** + * Returns the name of the [BattleGround]. + * + * @return string name + */ + int GetName(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetName()); + return 1; + } + + /** + * Returns the amount of alive players in the [BattleGround] by the team ID. + * + * @param [Team] team : team ID + * @return uint32 count + */ + int GetAlivePlayersCountByTeam(lua_State* L, BattleGround* bg) + { + uint32 team = Eluna::CHECKVAL(L, 2); + +#ifndef AZEROTHCORE + Eluna::Push(L, bg->GetAlivePlayersCountByTeam((Team)team)); +#else + Eluna::Push(L, bg->GetAlivePlayersCountByTeam((TeamId)team)); +#endif + return 1; + } + + /** + * Returns the [Map] of the [BattleGround]. + * + * @return [Map] map + */ + int GetMap(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetBgMap()); + return 1; + } + + /** + * Returns the bonus honor given by amount of kills in the specific [BattleGround]. + * + * @param uint32 kills : amount of kills + * @return uint32 bonusHonor + */ + int GetBonusHonorFromKillCount(lua_State* L, BattleGround* bg) + { + uint32 kills = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, bg->GetBonusHonorFromKill(kills)); + return 1; + } + +#ifndef AZEROTHCORE + /** + * Returns the bracket ID of the specific [BattleGround]. + * + * @return [BattleGroundBracketId] bracketId + */ + int GetBracketId(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetBracketId()); + return 1; + } +#endif + + /** + * Returns the end time of the [BattleGround]. + * + * @return uint32 endTime + */ + int GetEndTime(lua_State* L, BattleGround* bg) + { +#ifdef CATA + Eluna::Push(L, bg->GetRemainingTime()); +#else + Eluna::Push(L, bg->GetEndTime()); +#endif + return 1; + } + + /** + * Returns the amount of free slots for the selected team in the specific [BattleGround]. + * + * @param [Team] team : team ID + * @return uint32 freeSlots + */ + int GetFreeSlotsForTeam(lua_State* L, BattleGround* bg) + { + uint32 team = Eluna::CHECKVAL(L, 2); + +#ifndef AZEROTHCORE + Eluna::Push(L, bg->GetFreeSlotsForTeam((Team)team)); +#else + Eluna::Push(L, bg->GetFreeSlotsForTeam((TeamId)team)); +#endif + return 1; + } + + /** + * Returns the instance ID of the [BattleGround]. + * + * @return uint32 instanceId + */ + int GetInstanceId(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetInstanceID()); + return 1; + } + + /** + * Returns the map ID of the [BattleGround]. + * + * @return uint32 mapId + */ + int GetMapId(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetMapId()); + return 1; + } + + /** + * Returns the type ID of the [BattleGround]. + * + * @return [BattleGroundTypeId] typeId + */ + int GetTypeId(lua_State* L, BattleGround* bg) + { +#ifndef AZEROTHCORE + Eluna::Push(L, bg->GetTypeID()); +#else + Eluna::Push(L, bg->GetBgTypeID()); +#endif + return 1; + } + + /** + * Returns the max allowed [Player] level of the specific [BattleGround]. + * + * @return uint32 maxLevel + */ + int GetMaxLevel(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetMaxLevel()); + return 1; + } + + /** + * Returns the minimum allowed [Player] level of the specific [BattleGround]. + * + * @return uint32 minLevel + */ + int GetMinLevel(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetMinLevel()); + return 1; + } + + /** + * Returns the maximum allowed [Player] count of the specific [BattleGround]. + * + * @return uint32 maxPlayerCount + */ + int GetMaxPlayers(lua_State* L, BattleGround* bg) + { +#ifndef AZEROTHCORE + Eluna::Push(L, bg->GetMaxPlayers()); +#else + Eluna::Push(L, bg->GetMaxPlayersPerTeam() * 2); +#endif + return 1; + } + + /** + * Returns the minimum allowed [Player] count of the specific [BattleGround]. + * + * @return uint32 minPlayerCount + */ + int GetMinPlayers(lua_State* L, BattleGround* bg) + { +#ifndef AZEROTHCORE + Eluna::Push(L, bg->GetMinPlayers()); +#else + Eluna::Push(L, bg->GetMaxPlayersPerTeam() * 2); +#endif + return 1; + } + + /** + * Returns the maximum allowed [Player] count per team of the specific [BattleGround]. + * + * @return uint32 maxTeamPlayerCount + */ + int GetMaxPlayersPerTeam(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetMaxPlayersPerTeam()); + return 1; + } + + /** + * Returns the minimum allowed [Player] count per team of the specific [BattleGround]. + * + * @return uint32 minTeamPlayerCount + */ + int GetMinPlayersPerTeam(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetMinPlayersPerTeam()); + return 1; + } + + /** + * Returns the winning team of the specific [BattleGround]. + * + * @return [Team] team + */ + int GetWinner(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetWinner()); + return 1; + } + + /** + * Returns the status of the specific [BattleGround]. + * + * @return [BattleGroundStatus] status + */ + int GetStatus(lua_State* L, BattleGround* bg) + { + Eluna::Push(L, bg->GetStatus()); + return 1; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/BindingMap.h b/modules/mod-eluna/src/LuaEngine/BindingMap.h new file mode 100644 index 0000000..287d489 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/BindingMap.h @@ -0,0 +1,375 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _BINDING_MAP_H +#define _BINDING_MAP_H + +#include +#include "Common.h" +#include "ElunaUtility.h" +#include + +extern "C" +{ +#include "lua.h" +#include "lauxlib.h" +}; + + +/* + * A set of bindings from keys of type `K` to Lua references. + */ +template +class BindingMap : public ElunaUtil::Lockable +{ +private: + lua_State* L; + uint64 maxBindingID; + + struct Binding + { + uint64 id; + lua_State* L; + uint32 remainingShots; + int functionReference; + + Binding(lua_State* L, uint64 id, int functionReference, uint32 remainingShots) : + id(id), + L(L), + remainingShots(remainingShots), + functionReference(functionReference) + { } + + ~Binding() + { + luaL_unref(L, LUA_REGISTRYINDEX, functionReference); + } + }; + + typedef std::vector< std::unique_ptr > BindingList; + + std::unordered_map bindings; + /* + * This table is for fast removal of bindings by ID. + * + * Instead of having to look through (potentially) every BindingList to find + * the Binding with the right ID, this allows you to go directly to the + * BindingList that might have the Binding with that ID. + * + * However, you must be careful not to store pointers to BindingLists + * that no longer exist (see `void Clear(const K& key)` implementation). + */ + std::unordered_map id_lookup_table; + +public: + BindingMap(lua_State* L) : + L(L), + maxBindingID(0) + { } + + /* + * Insert a new binding from `key` to `ref`, which lasts for `shots`-many pushes. + * + * If `shots` is 0, it will never automatically expire, but can still be + * removed with `Clear` or `Remove`. + */ + uint64 Insert(const K& key, int ref, uint32 shots) + { + Guard guard(GetLock()); + + uint64 id = (++maxBindingID); + BindingList& list = bindings[key]; + list.push_back(std::unique_ptr(new Binding(L, id, ref, shots))); + id_lookup_table[id] = &list; + return id; + } + + /* + * Clear all bindings for `key`. + */ + void Clear(const K& key) + { + Guard guard(GetLock()); + + if (bindings.empty()) + return; + + auto iter = bindings.find(key); + if (iter == bindings.end()) + return; + + BindingList& list = iter->second; + + // Remove all pointers to `list` from `id_lookup_table`. + for (auto i = list.begin(); i != list.end(); ++i) + { + std::unique_ptr& binding = *i; + id_lookup_table.erase(binding->id); + } + + bindings.erase(key); + } + + /* + * Clear all bindings for all keys. + */ + void Clear() + { + Guard guard(GetLock()); + + if (bindings.empty()) + return; + + id_lookup_table.clear(); + bindings.clear(); + } + + /* + * Remove a specific binding identified by `id`. + * + * If `id` in invalid, nothing is removed. + */ + void Remove(uint64 id) + { + Guard guard(GetLock()); + + auto iter = id_lookup_table.find(id); + if (iter == id_lookup_table.end()) + return; + + BindingList* list = iter->second; + auto i = list->begin(); + + for (; i != list->end(); ++i) + { + std::unique_ptr& binding = *i; + if (binding->id == id) + break; + } + + if (i != list->end()) + list->erase(i); + + // Unconditionally erase the ID in the lookup table because + // it was either already invalid, or it's no longer valid. + id_lookup_table.erase(id); + } + + /* + * Check whether `key` has any bindings. + */ + bool HasBindingsFor(const K& key) + { + Guard guard(GetLock()); + + if (bindings.empty()) + return false; + + auto result = bindings.find(key); + if (result == bindings.end()) + return false; + + BindingList& list = result->second; + return !list.empty(); + } + + /* + * Push all Lua references for `key` onto the stack. + */ + void PushRefsFor(const K& key) + { + Guard guard(GetLock()); + + if (bindings.empty()) + return; + + auto result = bindings.find(key); + if (result == bindings.end()) + return; + + BindingList& list = result->second; + for (auto i = list.begin(); i != list.end();) + { + std::unique_ptr& binding = (*i); + auto i_prev = (i++); + + lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); + + if (binding->remainingShots > 0) + { + binding->remainingShots -= 1; + + if (binding->remainingShots == 0) + { + id_lookup_table.erase(binding->id); + list.erase(i_prev); + } + } + } + } +}; + + +/* + * A `BindingMap` key type for simple event ID bindings + * (ServerEvents, GuildEvents, etc.). + */ +template +struct EventKey +{ + T event_id; + + EventKey(T event_id) : + event_id(event_id) + { } +}; + +/* + * A `BindingMap` key type for event ID/Object entry ID bindings + * (CreatureEvents, GameObjectEvents, etc.). + */ +template +struct EntryKey +{ + T event_id; + uint32 entry; + + EntryKey(T event_id, uint32 entry) : + event_id(event_id), + entry(entry) + { } +}; + +/* + * A `BindingMap` key type for event ID/unique Object bindings + * (currently just CreatureEvents). + */ +template +struct UniqueObjectKey +{ + T event_id; + ObjectGuid guid; + uint32 instance_id; + + UniqueObjectKey(T event_id, ObjectGuid guid, uint32 instance_id) : + event_id(event_id), + guid(guid), + instance_id(instance_id) + { } +}; + +class hash_helper +{ +public: + typedef std::size_t result_type; + + template + static inline result_type hash(T1 const & t1, T2 const & t2, T const &... t) + { + result_type seed = 0; + _hash_combine(seed, t1, t2, t...); + return seed; + } + + template ::value>::type* = nullptr> + static inline result_type hash(T const & t) + { + return std::hash::type>()(t); + } + + template ::value>::type* = nullptr> + static inline result_type hash(T const & t) + { + return std::hash()(t); + } + +private: + template + static inline void _hash_combine(result_type& seed, T const & v) + { + // from http://www.boost.org/doc/libs/1_40_0/boost/functional/hash/hash.hpp + seed ^= hash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + + template + static inline void _hash_combine(result_type& seed, H const & h, T1 const & t1, T const &... t) + { + _hash_combine(seed, h); + _hash_combine(seed, t1, t...); + } +}; + +/* + * Implementations of various std functions on the above key types, + * so that they can be used within an unordered_map. + */ +namespace std +{ + template + struct equal_to < EventKey > + { + bool operator()(EventKey const& lhs, EventKey const& rhs) const + { + return lhs.event_id == rhs.event_id; + } + }; + + template + struct equal_to < EntryKey > + { + bool operator()(EntryKey const& lhs, EntryKey const& rhs) const + { + return lhs.event_id == rhs.event_id + && lhs.entry == rhs.entry; + } + }; + + template + struct equal_to < UniqueObjectKey > + { + bool operator()(UniqueObjectKey const& lhs, UniqueObjectKey const& rhs) const + { + return lhs.event_id == rhs.event_id + && lhs.guid == rhs.guid + && lhs.instance_id == rhs.instance_id; + } + }; + + template + struct hash < EventKey > + { + typedef EventKey argument_type; + + hash_helper::result_type operator()(argument_type const& k) const + { + return hash_helper::hash(k.event_id); + } + }; + + template + struct hash < EntryKey > + { + typedef EntryKey argument_type; + + hash_helper::result_type operator()(argument_type const& k) const + { + return hash_helper::hash(k.event_id, k.entry); + } + }; + + template + struct hash < UniqueObjectKey > + { + typedef UniqueObjectKey argument_type; + + hash_helper::result_type operator()(argument_type const& k) const + { + return hash_helper::hash(k.event_id, k.instance_id, k.guid.GetRawValue()); + } + }; +} + +#endif // _BINDING_MAP_H diff --git a/modules/mod-eluna/src/LuaEngine/CMakeLists.txt b/modules/mod-eluna/src/LuaEngine/CMakeLists.txt new file mode 100644 index 0000000..39483d6 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/CMakeLists.txt @@ -0,0 +1,80 @@ +# +# Copyright (C) 2010 - 2016 Eluna Lua Engine +# This program is free software licensed under GPL version 3 +# Please see the included DOCS/LICENSE.md for more information +# + +if( ${CMAKE_PROJECT_NAME} STREQUAL "MaNGOS" ) + + if ( USE_COREPCH ) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + include_directories(${CMAKE_SOURCE_DIR}) + endif () + + # Iterates through all the source files and adds them to the solution + file(GLOB sources_localdir *.cpp *.h) + + # Adds all the method headers to its own source group + file(GLOB method_headers *Methods.h) + source_group("Methods" FILES ${method_headers}) + + set(LuaEngine_STAT_SRCS + ${LuaEngine_STAT_SRCS} + ${sources_localdir} + ) + + include_directories( + ${CMAKE_SOURCE_DIR}/dep/zlib + ${CMAKE_SOURCE_DIR}/dep/lualib + ${CMAKE_BINARY_DIR} + ${ACE_INCLUDE_DIR} + ${MYSQL_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR} + ) + + add_library(LuaEngine STATIC + ${LuaEngine_STAT_SRCS} + ${game_STAT_SRCS} + ${game_STAT_PCH_SRC} + ) + + include_directories( + ${CMAKE_SOURCE_DIR}/dep/g3dlite + ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/shared/Common + ${CMAKE_SOURCE_DIR}/src/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/shared/Log + ${CMAKE_SOURCE_DIR}/src/shared/DataStores + ${CMAKE_SOURCE_DIR}/src/shared/Threading + ${CMAKE_SOURCE_DIR}/src/framework + ${CMAKE_SOURCE_DIR}/src/framework/Platform + ${CMAKE_SOURCE_DIR}/src/game/BattleGround + ${CMAKE_SOURCE_DIR}/src/game/Server + ${CMAKE_SOURCE_DIR}/src/game/vmap + ${CMAKE_SOURCE_DIR}/src/game/Maps + ${CMAKE_SOURCE_DIR}/src/game/MotionGenerators + ${CMAKE_SOURCE_DIR}/src/game/Tools + ${CMAKE_SOURCE_DIR}/src/game/References + ${CMAKE_SOURCE_DIR}/src/game/WorldHandlers + ${CMAKE_SOURCE_DIR}/src/game/Object + ) + + if( WIN32 ) + if ( MSVC ) + add_custom_command(TARGET LuaEngine + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/extensions" "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/" + ) + elseif ( MINGW ) + add_custom_command(TARGET LuaEngine + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/extensions" "${CMAKE_BINARY_DIR}/bin/ua_scripts/extensions/" + ) + endif() + endif() + + install(DIRECTORY extensions DESTINATION "${BIN_DIR}/lua_scripts/") + +endif() diff --git a/modules/mod-eluna/src/LuaEngine/ChatHandlerMethods.h b/modules/mod-eluna/src/LuaEngine/ChatHandlerMethods.h new file mode 100644 index 0000000..aa9f795 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ChatHandlerMethods.h @@ -0,0 +1,192 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef CHATHANDLERMETHODS_H +#define CHATHANDLERMETHODS_H + +#include "Chat.h" + +namespace LuaChatHandler +{ + /** + * Sends text to the chat handler + * + * @proto (text) + * @proto (entry) + * @param string text : text to display in chat or console + * @param uint32 entry : id of the string to display + */ + int SendSysMessage(lua_State* L, ChatHandler* handler) + { + if (lua_isnumber(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + handler->SendSysMessage(entry); + } + else + { + std::string text = Eluna::CHECKVAL(L, 2); + handler->SendSysMessage(text); + } + return 0; + } + + /** + * Returns `true` if the [ChatHandler] comes from the console, `false` if it comes from a player + * + * @return bool isConsole + */ + int IsConsole(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->IsConsole()); + return 1; + } + + /** + * Returns the [Player] associated with the handler. Returns `nil` in the case of a console handler + * + * @return [Player] player + */ + int GetPlayer(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->GetPlayer()); + return 1; + } + + /** + * Sends a message to all connected players + * + * @param string text : text to send + */ + int SendGlobalSysMessage(lua_State* L, ChatHandler* handler) + { + std::string text = Eluna::CHECKVAL(L, 2); + handler->SendGlobalSysMessage(text.c_str()); + return 0; + } + + /** + * Sends a message to all connected Game Masters + * + * @param string text : text to send + */ + int SendGlobalGMSysMessage(lua_State* L, ChatHandler* handler) + { + std::string text = Eluna::CHECKVAL(L, 2); + handler->SendGlobalGMSysMessage(text.c_str()); + return 0; + } + + /** + * Checks if the current security level is lower than the specified [Player]'s account + * + * @param [Player] player + * @param [bool] strong = false : Forces non-player accounts (security level greater than `0`) to go through the regular check if set to `true`.
Also, if set to `true`, the current security level will be considered as lower than the [Player]'s security level if the two levels are equal + * @return [bool] lower + */ + int HasLowerSecurity(lua_State* L, ChatHandler* handler) + { + Player* player = Eluna::CHECKOBJ(L, 2); + bool strong = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, handler->HasLowerSecurity(player, ObjectGuid::Empty, strong)); + return 1; + } + + /** + * Checks if the current security level is lower than the specified `account`'s level + * + * @param [uint32] account : the target account ID to compare security levels with + * @param [bool] strong = false : Forces non-player accounts (security level greater than `0`) to go through the regular check if set to `true`.
Also, if set to `true`, the current security level will be considered as lower than the `account`'s security level if the two levels are equal + * @return [bool] lower + */ + int HasLowerSecurityAccount(lua_State* L, ChatHandler* handler) + { + uint32 account = Eluna::CHECKVAL(L, 2); + bool strong = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, handler->HasLowerSecurityAccount(nullptr, account, strong)); + return 1; + } + + /** + * Returns the selected [Player] + * + * @return [Player] player + */ + int GetSelectedPlayer(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->getSelectedPlayer()); + return 1; + } + + /** + * Returns the selected [Creature] + * + * @return [Creature] creature + */ + int GetSelectedCreature(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->getSelectedCreature()); + return 1; + } + + /** + * Returns the selected [Unit] + * + * @return [Unit] unit + */ + int GetSelectedUnit(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->getSelectedUnit()); + return 1; + } + + /** + * Returns the selected [WorldObject] + * + * @return [WorldObject] object + */ + int GetSelectedObject(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->getSelectedObject()); + return 1; + } + + /** + * Returns the selected [Player] or the current [Player] if nothing is targeted or the target is not a player + * + * @return [Player] player + */ + int GetSelectedPlayerOrSelf(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->getSelectedPlayerOrSelf()); + return 1; + } + + /** + * Checks if the `securityLevel` is available + * + * @param [uint32] securityLevel + * @return [bool] isAvailable + */ + int IsAvailable(lua_State* L, ChatHandler* handler) + { + uint32 securityLevel = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, handler->IsAvailable(securityLevel)); + return 1; + } + + /** + * Returns `true` if other previously called [ChatHandler] methods sent an error + * + * @return [bool] sentErrorMessage + */ + int HasSentErrorMessage(lua_State* L, ChatHandler* handler) + { + Eluna::Push(L, handler->HasSentErrorMessage()); + return 1; + } +} +#endif diff --git a/modules/mod-eluna/src/LuaEngine/CorpseMethods.h b/modules/mod-eluna/src/LuaEngine/CorpseMethods.h new file mode 100644 index 0000000..aba7d20 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/CorpseMethods.h @@ -0,0 +1,81 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef CORPSEMETHODS_H +#define CORPSEMETHODS_H + +/*** + * The remains of a [Player] that has died. + * + * Inherits all methods from: [Object], [WorldObject] + */ +namespace LuaCorpse +{ + /** + * Returns the GUID of the [Player] that left the [Corpse] behind. + * + * @return ObjectGuid ownerGUID + */ + int GetOwnerGUID(lua_State* L, Corpse* corpse) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, corpse->GetOwnerGUID()); +#else + Eluna::Push(L, corpse->GetOwnerGuid()); +#endif + return 1; + } + + /** + * Returns the time when the [Player] became a ghost and spawned this [Corpse]. + * + * @return uint32 ghostTime + */ + int GetGhostTime(lua_State* L, Corpse* corpse) + { + Eluna::Push(L, corpse->GetGhostTime()); + return 1; + } + + /** + * Returns the [CorpseType] of a [Corpse]. + * + * enum CorpseType + * { + * CORPSE_BONES = 0, + * CORPSE_RESURRECTABLE_PVE = 1, + * CORPSE_RESURRECTABLE_PVP = 2 + * }; + * + * @return [CorpseType] corpseType + */ + int GetType(lua_State* L, Corpse* corpse) + { + Eluna::Push(L, corpse->GetType()); + return 1; + } + + /** + * Sets the "ghost time" to the current time. + * + * See [Corpse:GetGhostTime]. + */ + int ResetGhostTime(lua_State* /*L*/, Corpse* corpse) + { + corpse->ResetGhostTime(); + return 0; + } + + /** + * Saves the [Corpse] to the database. + */ + int SaveToDB(lua_State* /*L*/, Corpse* corpse) + { + corpse->SaveToDB(); + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/CreatureHooks.cpp b/modules/mod-eluna/src/LuaEngine/CreatureHooks.cpp new file mode 100644 index 0000000..e2bd6d1 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/CreatureHooks.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT, CREATURE) \ + if (!IsEnabled())\ + return;\ + auto entry_key = EntryKey(EVENT, CREATURE->GetEntry());\ + auto unique_key = UniqueObjectKey(EVENT, CREATURE->GET_GUID(), CREATURE->GetInstanceId());\ + if (!CreatureEventBindings->HasBindingsFor(entry_key))\ + if (!CreatureUniqueBindings->HasBindingsFor(unique_key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, CREATURE, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto entry_key = EntryKey(EVENT, CREATURE->GetEntry());\ + auto unique_key = UniqueObjectKey(EVENT, CREATURE->GET_GUID(), CREATURE->GetInstanceId());\ + if (!CreatureEventBindings->HasBindingsFor(entry_key))\ + if (!CreatureUniqueBindings->HasBindingsFor(unique_key))\ + return RETVAL;\ + LOCK_ELUNA + +void Eluna::OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) +{ + START_HOOK(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget); + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature, false); + Push(pPlayer); + Push(pCreature); + Push(pQuest); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_QUEST_REWARD, pCreature, false); + Push(pPlayer); + Push(pCreature); + Push(pQuest); + Push(opt); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +void Eluna::GetDialogStatus(const Player* pPlayer, const Creature* pCreature) +{ + START_HOOK(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature); + Push(pPlayer); + Push(pCreature); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +void Eluna::OnAddToWorld(Creature* pCreature) +{ + START_HOOK(CREATURE_EVENT_ON_ADD, pCreature); + Push(pCreature); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +void Eluna::OnRemoveFromWorld(Creature* pCreature) +{ + START_HOOK(CREATURE_EVENT_ON_REMOVE, pCreature); + Push(pCreature); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED, pCreature, false); + Push(pCreature); + Push(pSummoner); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +bool Eluna::UpdateAI(Creature* me, const uint32 diff) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_AIUPDATE, me, false); + Push(me); + Push(diff); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +//Called for reaction at enter to combat if not in combat yet (enemy can be NULL) +//Called at creature aggro either by MoveInLOS or Attack Start +bool Eluna::EnterCombat(Creature* me, Unit* target) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_ENTER_COMBAT, me, false); + Push(me); + Push(target); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called at any Damage from any attacker (before damage apply) +bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DAMAGE_TAKEN, me, false); + bool result = false; + Push(me); + Push(attacker); + Push(damage); + int damageIndex = lua_gettop(L); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key, 3); + + while (n > 0) + { + int r = CallOneFunction(n--, 3, 2); + + if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) + result = true; + + if (lua_isnumber(L, r + 1)) + { + damage = Eluna::CHECKVAL(L, r + 1); + // Update the stack for subsequent calls. + ReplaceArgument(damage, damageIndex); + } + + lua_pop(L, 2); + } + + CleanUpStack(3); + return result; +} + +//Called at creature death +bool Eluna::JustDied(Creature* me, Unit* killer) +{ + On_Reset(me); + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_DIED, me, false); + Push(me); + Push(killer); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +//Called at creature killing another unit +bool Eluna::KilledUnit(Creature* me, Unit* victim) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_TARGET_DIED, me, false); + Push(me); + Push(victim); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when the creature summon successfully other creature +bool Eluna::JustSummoned(Creature* me, Creature* summon) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me, false); + Push(me); + Push(summon); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when a summoned creature is despawned +bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me, false); + Push(me); + Push(summon); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +//Called at waypoint reached or PointMovement end +bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_WP, me, false); + Push(me); + Push(type); + Push(id); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called before EnterCombat even before the creature is in combat. +bool Eluna::AttackStart(Creature* me, Unit* target) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_PRE_COMBAT, me, false); + Push(me); + Push(target); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called for reaction at stopping attack at no attackers or targets +bool Eluna::EnterEvadeMode(Creature* me) +{ + On_Reset(me); + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_LEAVE_COMBAT, me, false); + Push(me); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when creature is spawned or respawned (for reseting variables) +bool Eluna::JustRespawned(Creature* me) +{ + On_Reset(me); + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPAWN, me, false); + Push(me); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called at reaching home after evade +bool Eluna::JustReachedHome(Creature* me) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_REACH_HOME, me, false); + Push(me); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called at text emote receive from player +bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_RECEIVE_EMOTE, me, false); + Push(me); + Push(player); + Push(emoteId); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// called when the corpse of this creature gets removed +bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_CORPSE_REMOVED, me, false); + bool result = false; + Push(me); + Push(respawnDelay); + int respawnDelayIndex = lua_gettop(L); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) + result = true; + + if (lua_isnumber(L, r + 1)) + { + respawnDelay = Eluna::CHECKVAL(L, r + 1); + // Update the stack for subsequent calls. + ReplaceArgument(respawnDelay, respawnDelayIndex); + } + + lua_pop(L, 2); + } + + CleanUpStack(2); + return result; +} + +bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_MOVE_IN_LOS, me, false); + Push(me); + Push(who); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called on creature initial spawn, respawn, death, evade (leave combat) +void Eluna::On_Reset(Creature* me) // Not an override, custom +{ + START_HOOK(CREATURE_EVENT_ON_RESET, me); + Push(me); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when hit by a spell +bool Eluna::SpellHit(Creature* me, WorldObject* caster, SpellInfo const* spell) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_HIT_BY_SPELL, me, false); + Push(me); + Push(caster); + Push(spell->Id); // Pass spell object? + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when spell hits a target +bool Eluna::SpellHitTarget(Creature* me, WorldObject* target, SpellInfo const* spell) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me, false); + Push(me); + Push(target); + Push(spell->Id); // Pass spell object? + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +#if defined TRINITY || AZEROTHCORE + +bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me, false); + Push(me); + Push(summon); + Push(killer); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when owner takes damage +bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me, false); + Push(me); + Push(attacker); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +// Called when owner attacks something +bool Eluna::OwnerAttacked(Creature* me, Unit* target) +{ + START_HOOK_WITH_RETVAL(CREATURE_EVENT_ON_OWNER_ATTACKED, me, false); + Push(me); + Push(target); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, entry_key, unique_key); +} + +#endif // TRINITY diff --git a/modules/mod-eluna/src/LuaEngine/CreatureMethods.h b/modules/mod-eluna/src/LuaEngine/CreatureMethods.h new file mode 100644 index 0000000..cb85860 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/CreatureMethods.h @@ -0,0 +1,1531 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef CREATUREMETHODS_H +#define CREATUREMETHODS_H + +/*** + * Non-[Player] controlled [Unit]s (i.e. NPCs). + * + * Inherits all methods from: [Object], [WorldObject], [Unit] + */ +namespace LuaCreature +{ + /** + * Returns `true` if the [Creature] can regenerate health, + * and returns `false` otherwise. + * + * @return bool isRegenerating + */ + int IsRegeneratingHealth(lua_State* L, Creature* creature) + { +#if defined(AZEROTHCORE) + Eluna::Push(L, creature->isRegeneratingHealth()); +#elif defined(TRINITY) + Eluna::Push(L, creature->CanRegenerateHealth()); +#else + Eluna::Push(L, creature->IsRegeneratingHealth()); +#endif + return 1; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Sets whether the [Creature] can regenerate health or not. + * + * @param bool enable = true : `true` to enable health regeneration, `false` to disable it + */ + int SetRegeneratingHealth(lua_State* L, Creature* creature) + { + bool enable = Eluna::CHECKVAL(L, 2, true); + +#if defined(AZEROTHCORE) + creature->SetRegeneratingHealth(enable); +#else + creature->SetRegenerateHealth(enable); +#endif + return 0; + } +#endif + + /** + * Returns `true` if the [Creature] is set to not give reputation when killed, + * and returns `false` otherwise. + * + * @return bool reputationDisabled + */ + int IsReputationGainDisabled(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsReputationGainDisabled()); + return 1; + } + + /** + * Returns `true` if the [Creature] completes the [Quest] with the ID `questID`, + * and returns `false` otherwise. + * + * @param uint32 questID : the ID of a [Quest] + * @return bool completesQuest + */ + int CanCompleteQuest(lua_State* L, Creature* creature) + { + uint32 quest_id = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->hasInvolvedQuest(quest_id)); +#else + Eluna::Push(L, creature->HasInvolvedQuest(quest_id)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can be targeted for attack, + * and returns `false` otherwise. + * + * @param bool mustBeDead = false : if `true`, only returns `true` if the [Creature] is also dead. Otherwise, it must be alive. + * @return bool targetable + */ + int IsTargetableForAttack(lua_State* L, Creature* creature) + { + bool mustBeDead = Eluna::CHECKVAL(L, 2, false); + +#ifdef MANGOS + Eluna::Push(L, creature->IsTargetableForAttack(mustBeDead)); +#else + Eluna::Push(L, creature->isTargetableForAttack(mustBeDead)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can assist `friend` in combat against `enemy`, + * and returns `false` otherwise. + * + * @param [Unit] friend : the Unit we will be assisting + * @param [Unit] enemy : the Unit that we would attack if we assist `friend` + * @param bool checkFaction = true : if `true`, the [Creature] must be the same faction as `friend` to assist + * @return bool canAssist + */ + int CanAssistTo(lua_State* L, Creature* creature) + { + Unit* u = Eluna::CHECKOBJ(L, 2); + Unit* enemy = Eluna::CHECKOBJ(L, 3); + bool checkfaction = Eluna::CHECKVAL(L, 4, true); + + Eluna::Push(L, creature->CanAssistTo(u, enemy, checkfaction)); + return 1; + } + + /** + * Returns `true` if the [Creature] has searched for combat assistance already, + * and returns `false` otherwise. + * + * @return bool searchedForAssistance + */ + int HasSearchedAssistance(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->HasSearchedAssistance()); + return 1; + } + + /** + * Returns `true` if the [Creature] will give its loot to `player`, + * and returns `false` otherwise. + * + * @return bool tapped + */ + int IsTappedBy(lua_State* L, Creature* creature) + { + Player* player = Eluna::CHECKOBJ(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->isTappedBy(player)); +#else + Eluna::Push(L, creature->IsTappedBy(player)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] will give its loot to a [Player] or [Group], + * and returns `false` otherwise. + * + * @return bool hasLootRecipient + */ + int HasLootRecipient(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->hasLootRecipient()); +#else + Eluna::Push(L, creature->HasLootRecipient()); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can start attacking nearby hostile [Unit]s, + * and returns `false` otherwise. + * + * @return bool canAggro + */ + int CanAggro(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, !creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC)); +#else + // Eluna::Push(L, creature->CanInitiateAttack()); + Eluna::Push(L, !creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can move through deep water, + * and returns `false` otherwise. + * + * @return bool canSwim + */ + int CanSwim(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->CanSwim()); + return 1; + } + + /** + * Returns `true` if the [Creature] can move on land, + * and returns `false` otherwise. + * + * @return bool canWalk + */ + int CanWalk(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->CanWalk()); + return 1; + } + + /** + * Returns `true` if the [Creature] is returning to its spawn position from combat, + * and returns `false` otherwise. + * + * @return bool inEvadeMode + */ + int IsInEvadeMode(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsInEvadeMode()); + return 1; + } + + /** + * Returns `true` if the [Creature]'s rank is Elite or Rare Elite, + * and returns `false` otherwise. + * + * @return bool isElite + */ + int IsElite(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->isElite()); +#else + Eluna::Push(L, creature->IsElite()); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] is a city guard, + * and returns `false` otherwise. + * + * @return bool isGuard + */ + int IsGuard(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsGuard()); + return 1; + } + + /** + * Returns `true` if the [Creature] is a civilian, + * and returns `false` otherwise. + * + * @return bool isCivilian + */ + int IsCivilian(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsCivilian()); + return 1; + } + + /** + * Returns `true` if the [Creature] is the leader of a player faction, + * and returns `false` otherwise. + * + * @return bool isLeader + */ + int IsRacialLeader(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsRacialLeader()); + return 1; + } + + /** + * Returns `true` if the [Creature]'s flags_extra includes Dungeon Boss (0x1000000), + * and returns `false` otherwise. + * + * @return bool isDungeonBoss + */ +#if defined(TRINITY) || defined(AZEROTHCORE) + int IsDungeonBoss(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsDungeonBoss()); + return 1; + } +#endif + + /** + * Returns `true` if the [Creature]'s rank is Boss, + * and returns `false` otherwise. + * + * @return bool isWorldBoss + */ + int IsWorldBoss(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->isWorldBoss()); +#else + Eluna::Push(L, creature->IsWorldBoss()); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] cannot cast `spellId` due to a category cooldown, + * and returns `false` otherwise. + * + * @param uint32 spellId : the ID of a [Spell] + * @return bool hasCooldown + */ + int HasCategoryCooldown(lua_State* L, Creature* creature) + { + uint32 spell = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) + if (const SpellInfo* info = sSpellMgr->GetSpellInfo(spell)) + Eluna::Push(L, info->GetCategory() && creature->GetSpellHistory()->HasCooldown(spell)); + else + Eluna::Push(L, false); +#elif defined(AZEROTHCORE) + if (const SpellInfo* info = sSpellMgr->GetSpellInfo(spell)) + Eluna::Push(L, info->GetCategory() && creature->HasSpellCooldown(spell)); + else + Eluna::Push(L, false); +#else + Eluna::Push(L, creature->HasCategoryCooldown(spell)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can cast `spellId` when mind-controlled, + * and returns `false` otherwise. + * + * @param uint32 spellId : the ID of a [Spell] + * @return bool hasSpell + */ + int HasSpell(lua_State* L, Creature* creature) + { + uint32 id = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, creature->HasSpell(id)); + return 1; + } + + /** + * Returns `true` if the [Creature] starts the [Quest] `questId`, + * and returns `false` otherwise. + * + * @param uint32 questId : the ID of a [Quest] + * @return bool hasQuest + */ + int HasQuest(lua_State* L, Creature* creature) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->hasQuest(questId)); +#else + Eluna::Push(L, creature->HasQuest(questId)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] has `spellId` on cooldown, + * and returns `false` otherwise. + * + * @param uint32 spellId : the ID of a [Spell] + * @return bool hasCooldown + */ + int HasSpellCooldown(lua_State* L, Creature* creature) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) + Eluna::Push(L, creature->GetSpellHistory()->HasCooldown(spellId)); +#else + Eluna::Push(L, creature->HasSpellCooldown(spellId)); +#endif + return 1; + } + + /** + * Returns `true` if the [Creature] can fly, + * and returns `false` otherwise. + * + * @return bool canFly + */ + int CanFly(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->CanFly()); + return 1; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Returns `true` if the [Creature] is an invisible trigger, + * and returns `false` otherwise. + * + * @return bool canFly + */ + int IsTrigger(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsTrigger()); + return 1; + } + + /** + * Returns true if the [Creature] is damaged enough for looting + * + * @return bool isDamagedEnough + */ + int IsDamageEnoughForLootingAndReward(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->IsDamageEnoughForLootingAndReward()); + return 1; + } + + /** + * Returns true if the [Creature] can start attacking specified target + * + * Does not work on most targets + * + * @param [Unit] target + * @param bool force = true : force [Creature] to attack + */ + int CanStartAttack(lua_State* L, Creature* creature) // TODO: Implement core side + { + Unit* target = Eluna::CHECKOBJ(L, 2); +#ifndef AZEROTHCORE + bool force = Eluna::CHECKVAL(L, 3, true); + Eluna::Push(L, creature->CanStartAttack(target, force)); +#else + Eluna::Push(L, creature->CanStartAttack(target)); +#endif + return 1; + } + + /** + * Returns true if [Creature] has the specified loot mode + * + * @param uint16 lootMode + * @return bool hasLootMode + */ + int HasLootMode(lua_State* L, Creature* creature) // TODO: Implement LootMode features + { + uint16 lootMode = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, creature->HasLootMode(lootMode)); + return 1; + } +#endif + + /** + * Returns the time it takes for this [Creature] to respawn once killed. + * + * This value does not usually change over a [Creature]'s lifespan, + * but can be modified by [Creature:SetRespawnDelay]. + * + * @return uint32 respawnDelay : the respawn delay, in seconds + */ + int GetRespawnDelay(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetRespawnDelay()); + return 1; + } + + /** + * Returns the radius the [Creature] is permitted to wander from its + * respawn point. + * + * @return float wanderRadius + */ + int GetWanderRadius(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->GetWanderDistance()); +#else + Eluna::Push(L, creature->GetRespawnRadius()); +#endif + return 1; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Returns the current waypoint path ID of the [Creature]. + * + * @return uint32 pathId + */ + int GetWaypointPath(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetWaypointPath()); + return 1; + } +#endif + + /** + * Returns the current waypoint ID of the [Creature]. + * + * @return uint32 wpId + */ + int GetCurrentWaypointId(lua_State* L, Creature* creature) + { +#if defined(TRINITY) + Eluna::Push(L, creature->GetCurrentWaypointInfo().first); +#elif defined(AZEROTHCORE) + Eluna::Push(L, creature->GetCurrentWaypointID()); +#else + Eluna::Push(L, creature->GetMotionMaster()->getLastReachedWaypoint()); +#endif + return 1; + } + + /** + * Returns the default movement type for this [Creature]. + * + * @return [MovementGeneratorType] defaultMovementType + */ + int GetDefaultMovementType(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetDefaultMovementType()); + return 1; + } + + /** + * Returns the aggro range of the [Creature] for `target`. + * + * @param [Unit] target + * @return float aggroRange + */ + int GetAggroRange(lua_State* L, Creature* creature) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->GetAggroRange(target)); +#else + float AttackDist = creature->GetAttackDistance(target); + float ThreatRadius = sWorld.getConfig(CONFIG_FLOAT_THREAT_RADIUS); + Eluna::Push(L, ThreatRadius > AttackDist ? ThreatRadius : AttackDist); +#endif + return 1; + } + +#ifndef AZEROTHCORE + /** + * Returns the effective aggro range of the [Creature] for `target`. + * + * If this is smaller than the minimum aggro range set in the config file, + * that is used as the aggro range instead. + * + * @param [Unit] target + * @return float attackDistance + */ + int GetAttackDistance(lua_State* L, Creature* creature) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + + Eluna::Push(L, creature->GetAttackDistance(target)); + return 1; + } +#endif + + /** + * Returns the [Group] that can loot this [Creature]. + * + * @return [Group] lootRecipientGroup : the group or `nil` + */ + int GetLootRecipientGroup(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->GetLootRecipientGroup()); +#else + Eluna::Push(L, creature->GetGroupLootRecipient()); +#endif + return 1; + } + + /** + * Returns the [Player] that can loot this [Creature]. + * + * @return [Player] lootRecipient : the player or `nil` + */ + int GetLootRecipient(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetLootRecipient()); + return 1; + } + + /** + * Returns the [Creature]'s script name. + * + * This is used by the core to apply C++ scripts to the Creature. + * + * It is not used by Eluna. Eluna will override AI scripts. + * + * @return string scriptName + */ + int GetScriptName(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetScriptName()); + return 1; + } + + /** + * Returns the [Creature]'s AI name. + * + * This is used by the core to assign the Creature's default AI. + * + * If the Creature is scripted by Eluna, the AI is overriden. + * + * @return string AIName + */ + int GetAIName(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetAIName()); + return 1; + } + + /** + * Returns the [Creature]'s script ID. + * + * Every C++ script name is assigned a unique ID by the core. + * This returns the ID for this [Creature]'s script name. + * + * @return uint32 scriptID + */ + int GetScriptId(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetScriptId()); + return 1; + } + + /** + * Returns the [Creature]'s cooldown for `spellID`. + * + * @param uint32 spellID + * @return uint32 cooldown : the cooldown, in milliseconds + */ + int GetCreatureSpellCooldownDelay(lua_State* L, Creature* creature) + { + uint32 spell = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell)) + Eluna::Push(L, creature->GetSpellHistory()->GetRemainingCooldown(spellInfo)); + else + Eluna::Push(L, 0); +#elif defined(AZEROTHCORE) + if (sSpellMgr->GetSpellInfo(spell)) + Eluna::Push(L, creature->GetSpellCooldown(spell)); + else + Eluna::Push(L, 0); +#else + Eluna::Push(L, creature->GetCreatureSpellCooldownDelay(spell)); +#endif + return 1; + } + + /** + * Returns the delay between when the [Creature] dies and when its body despawns. + * + * @return uint32 corpseDelay : the delay, in seconds + */ + int GetCorpseDelay(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetCorpseDelay()); + return 1; + } + + /** + * Returns position the [Creature] returns to when evading from combat + * or respawning. + * + * @return float x + * @return float y + * @return float z + * @return float o + */ + int GetHomePosition(lua_State* L, Creature* creature) + { + float x, y, z, o; +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->GetHomePosition(x, y, z, o); +#else + creature->GetRespawnCoord(x, y, z, &o); +#endif + + Eluna::Push(L, x); + Eluna::Push(L, y); + Eluna::Push(L, z); + Eluna::Push(L, o); + return 4; + } + + /** + * Sets the position the [Creature] returns to when evading from combat + * or respawning. + * + * @param float x + * @param float y + * @param float z + * @param float o + */ + int SetHomePosition(lua_State* L, Creature* creature) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + float o = Eluna::CHECKVAL(L, 5); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->SetHomePosition(x, y, z, o); +#else + creature->SetRespawnCoord(x, y, z, o); +#endif + + return 0; + } + + enum SelectAggroTarget + { + SELECT_TARGET_RANDOM = 0, // Just selects a random target + SELECT_TARGET_TOPAGGRO, // Selects targes from top aggro to bottom + SELECT_TARGET_BOTTOMAGGRO, // Selects targets from bottom aggro to top + SELECT_TARGET_NEAREST, + SELECT_TARGET_FARTHEST + }; + + /** + * Returns a target from the [Creature]'s threat list based on the + * supplied arguments. + * + * enum SelectAggroTarget + * { + * SELECT_TARGET_RANDOM = 0, //Just selects a random target + * SELECT_TARGET_TOPAGGRO, //Selects targets from top aggro to bottom + * SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top + * SELECT_TARGET_NEAREST, + * SELECT_TARGET_FARTHEST + * }; + * + * For example, if you wanted to select the third-farthest [Player] + * within 50 yards that has the [Aura] "Corrupted Blood" (ID 24328), + * you could use this function like so: + * + * target = creature:GetAITarget(4, true, 3, 50, 24328) + * + * @param [SelectAggroTarget] targetType : how the threat list should be sorted + * @param bool playerOnly = false : if `true`, skips targets that aren't [Player]s + * @param uint32 position = 0 : used as an offset into the threat list. If `targetType` is random, used as the number of players from top of aggro to choose from + * @param float distance = 0.0 : if positive, the maximum distance for the target. If negative, the minimum distance + * @param int32 aura = 0 : if positive, the target must have this [Aura]. If negative, the the target must not have this Aura + * @return [Unit] target : the target, or `nil` + */ + int GetAITarget(lua_State* L, Creature* creature) + { + uint32 targetType = Eluna::CHECKVAL(L, 2); + bool playerOnly = Eluna::CHECKVAL(L, 3, false); + uint32 position = Eluna::CHECKVAL(L, 4, 0); + float dist = Eluna::CHECKVAL(L, 5, 0.0f); + int32 aura = Eluna::CHECKVAL(L, 6, 0); + +#if defined(CMANGOS) + ThreatList const& threatlist = creature->getThreatManager().getThreatList(); +#elif defined(MANGOS) + ThreatList const& threatlist = creature->GetThreatManager().getThreatList(); +#elif defined(TRINITY) + auto const& threatlist = creature->GetThreatManager().GetSortedThreatList(); +#elif defined(AZEROTHCORE) + auto const& threatlist = creature->GetThreatMgr().GetThreatList(); +#endif +#ifndef TRINITY + if (threatlist.empty()) + return 1; + if (position >= threatlist.size()) + return 1; +#endif + std::list targetList; +#if defined(TRINITY) + for (ThreatReference const* itr : threatlist) +#else + for (auto itr = threatlist.begin(); itr != threatlist.end(); ++itr) +#endif + { +#if defined(TRINITY) + Unit* target = itr->GetVictim(); +#else + Unit* target = (*itr)->getTarget(); +#endif + if (!target) + continue; + if (playerOnly && target->GetTypeId() != TYPEID_PLAYER) + continue; + if (aura > 0 && !target->HasAura(aura)) + continue; + else if (aura < 0 && target->HasAura(-aura)) + continue; + if (dist > 0.0f && !creature->IsWithinDist(target, dist)) + continue; + else if (dist < 0.0f && creature->IsWithinDist(target, -dist)) + continue; + targetList.push_back(target); + } + + if (targetList.empty()) + return 1; + if (position >= targetList.size()) + return 1; + + if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + targetList.sort(ElunaUtil::ObjectDistanceOrderPred(creature)); + + switch (targetType) + { + case SELECT_TARGET_NEAREST: + case SELECT_TARGET_TOPAGGRO: + { + std::list::const_iterator itr = targetList.begin(); + if (position) + std::advance(itr, position); + Eluna::Push(L, *itr); + } + break; + case SELECT_TARGET_FARTHEST: + case SELECT_TARGET_BOTTOMAGGRO: + { + std::list::reverse_iterator ritr = targetList.rbegin(); + if (position) + std::advance(ritr, position); + Eluna::Push(L, *ritr); + } + break; + case SELECT_TARGET_RANDOM: + { + std::list::const_iterator itr = targetList.begin(); + if (position) + std::advance(itr, urand(0, position)); + else + std::advance(itr, urand(0, targetList.size() - 1)); + Eluna::Push(L, *itr); + } + break; + default: + luaL_argerror(L, 2, "SelectAggroTarget expected"); + break; + } + + return 1; + } + + /** + * Returns all [Unit]s in the [Creature]'s threat list. + * + * @return table targets + */ + int GetAITargets(lua_State* L, Creature* creature) + { +#if defined(TRINITY) + auto const& threatlist = creature->GetThreatManager().GetThreatenedByMeList(); +#elif defined(AZEROTHCORE) +auto const& threatlist = creature->GetThreatMgr().GetThreatList(); +#else + ThreatList const& threatlist = creature->GetThreatManager().getThreatList(); +#endif + lua_createtable(L, threatlist.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + for (auto itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { +#if defined(TRINITY) + Unit* target = itr->second->GetOwner(); +#else + Unit* target = (*itr)->getTarget(); +#endif + if (!target) + continue; + Eluna::Push(L, target); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns the number of [Unit]s in this [Creature]'s threat list. + * + * @return int targetsCount + */ + int GetAITargetsCount(lua_State* L, Creature* creature) + { +#if defined(TRINITY) + Eluna::Push(L, creature->GetThreatManager().GetThreatenedByMeList().size()); +#elif defined(AZEROTHCORE) + Eluna::Push(L, creature->GetThreatMgr().GetThreatListSize()); +#else + Eluna::Push(L, creature->GetThreatManager().getThreatList().size()); +#endif + return 1; + } + + /** + * Returns the [Creature]'s NPC flags. + * + * These are used to control whether the NPC is a vendor, can repair items, + * can give quests, etc. + * + * @return [NPCFlags] npcFlags + */ + int GetNPCFlags(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetUInt32Value(UNIT_NPC_FLAGS)); + return 1; + } + + /** + * Returns the [Creature]'s Unit flags. + * + * These are used to control whether the NPC is attackable or not, among other things. + * + * @return [UnitFlags] unitFlags + */ + int GetUnitFlags(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetUInt32Value(UNIT_FIELD_FLAGS)); + return 1; + } + + /** + * Returns the [Creature]'s Unit flags 2. + * + * @return [UnitFlags2] unitFlags2 + */ + int GetUnitFlagsTwo(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetUInt32Value(UNIT_FIELD_FLAGS_2)); + return 1; + } + + /** + * Returns the [Creature]'s Extra flags. + * + * These are used to control whether the NPC is a civilian, uses pathfinding, + * if it's a guard, etc. + * + * @return [ExtraFlags] extraFlags + */ + int GetExtraFlags(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->GetCreatureTemplate()->flags_extra); +#else + Eluna::Push(L, creature->GetCreatureInfo()->ExtraFlags); +#endif + return 1; + } + +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + /** + * Returns the [Creature]'s shield block value. + * + * @return uint32 shieldBlockValue + */ + int GetShieldBlockValue(lua_State* L, Creature* creature) + { + Eluna::Push(L, creature->GetShieldBlockValue()); + return 1; + } +#endif + +#if defined(TRINITY) || defined(AZEROTHCORE) + int GetLootMode(lua_State* L, Creature* creature) // TODO: Implement LootMode features + { + Eluna::Push(L, creature->GetLootMode()); + return 1; + } +#endif + + /** + * Returns the guid of the [Creature] that is used as the ID in the database + * + * @return uint32 dbguid + */ + int GetDBTableGUIDLow(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->GetSpawnId()); +#else + // on mangos based this is same as lowguid + Eluna::Push(L, creature->GetGUIDLow()); +#endif + return 1; + } + + /** + * Sets the [Creature]'s NPC flags to `flags`. + * + * @param [NPCFlags] flags + */ + int SetNPCFlags(lua_State* L, Creature* creature) + { + uint32 flags = Eluna::CHECKVAL(L, 2); + + creature->SetUInt32Value(UNIT_NPC_FLAGS, flags); + return 0; + } + + /** + * Sets the [Creature]'s Unit flags to `flags`. + * + * @param [UnitFlags] flags + */ + int SetUnitFlags(lua_State* L, Creature* creature) + { + uint32 flags = Eluna::CHECKVAL(L, 2); + creature->SetUInt32Value(UNIT_FIELD_FLAGS, flags); + return 0; + } + + /** + * Sets the [Creature]'s Unit flags2 to `flags`. + * + * @param [UnitFlags2] flags + */ + int SetUnitFlagsTwo(lua_State* L, Creature* creature) + { + uint32 flags = Eluna::CHECKVAL(L, 2); + creature->SetUInt32Value(UNIT_FIELD_FLAGS_2, flags); + return 0; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Sets the [Creature]'s ReactState to `state`. + * + * @param [ReactState] state + */ + int SetReactState(lua_State* L, Creature* creature) + { + uint32 state = Eluna::CHECKVAL(L, 2); + + creature->SetReactState((ReactStates)state); + return 0; + } +#endif + + /** + * Makes the [Creature] able to fly if enabled. + * + * @param bool disable + */ + int SetDisableGravity(lua_State* L, Creature* creature) + { + bool disable = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->SetDisableGravity(disable); +#else + creature->SetLevitate(disable); +#endif + return 0; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + int SetLootMode(lua_State* L, Creature* creature) // TODO: Implement LootMode features + { + uint16 lootMode = Eluna::CHECKVAL(L, 2); + + creature->SetLootMode(lootMode); + return 0; + } +#endif + + /** + * Sets the [Creature]'s death state to `deathState`. + * + * @param [DeathState] deathState + */ + int SetDeathState(lua_State* L, Creature* creature) + { + int32 state = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->setDeathState((DeathState)state); +#else + creature->SetDeathState((DeathState)state); +#endif + return 0; + } + + /** + * Sets whether the [Creature] is currently walking or running. + * + * @param bool enable = true : `true` to enable walking, `false` for running + */ + int SetWalk(lua_State* L, Creature* creature) // TODO: Move same to Player ? + { + bool enable = Eluna::CHECKVAL(L, 2, true); + + creature->SetWalk(enable); + return 0; + } + + /** + * Equips given [Item]s to the [Unit]. Using 0 removes the equipped [Item] + * + * @param uint32 main_hand : main hand [Item]'s entry + * @param uint32 off_hand : off hand [Item]'s entry + * @param uint32 ranged : ranged [Item]'s entry + */ + int SetEquipmentSlots(lua_State* L, Creature* creature) + { + uint32 main_hand = Eluna::CHECKVAL(L, 2); + uint32 off_hand = Eluna::CHECKVAL(L, 3); + uint32 ranged = Eluna::CHECKVAL(L, 4); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, main_hand); + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, off_hand); + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, ranged); +#else + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, main_hand); + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, off_hand); + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, ranged); +#endif + return 0; + } + + /** + * Sets whether the [Creature] can be aggroed. + * + * @param bool allow = true : `true` to allow aggro, `false` to disable aggro + */ + int SetAggroEnabled(lua_State* L, Creature* creature) + { + bool allow = Eluna::CHECKVAL(L, 2, true); + +#if defined(TRINITY) || defined(AZEROTHCORE) + if (allow) + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); + else + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); +#else + if (allow) + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + else + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); +#endif + + return 0; + } + + /** + * Sets whether the [Creature] gives reputation or not. + * + * @param bool disable = true : `true` to disable reputation, `false` to enable + */ + int SetDisableReputationGain(lua_State* L, Creature* creature) + { + bool disable = Eluna::CHECKVAL(L, 2, true); + + creature->SetDisableReputationGain(disable); + return 0; + } + + /** + * Sets the [Creature] as in combat with all [Player]s in the dungeon instance. + * + * This is used by raid bosses to prevent Players from using out-of-combat + * actions once the encounter has begun. + */ + int SetInCombatWithZone(lua_State* /*L*/, Creature* creature) + { +#if defined(AZEROTHCORE) + if (creature->IsAIEnabled) + creature->AI()->DoZoneInCombat(); +#elif defined(TRINITY) + if (creature->IsAIEnabled()) + creature->AI()->DoZoneInCombat(); +#else + creature->SetInCombatWithZone(); +#endif + return 0; + } + + /** + * Sets the distance the [Creature] can wander from it's spawn point. + * + * @param float distance + */ + int SetWanderRadius(lua_State* L, Creature* creature) + { + float dist = Eluna::CHECKVAL(L, 2); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->SetWanderDistance(dist); +#else + creature->SetRespawnRadius(dist); +#endif + return 0; + } + + /** + * Sets the time it takes for the [Creature] to respawn when killed. + * + * @param uint32 delay : the delay, in seconds + */ + int SetRespawnDelay(lua_State* L, Creature* creature) + { + uint32 delay = Eluna::CHECKVAL(L, 2); + + creature->SetRespawnDelay(delay); + return 0; + } + + /** + * Sets the default movement type of the [Creature]. + * + * @param [MovementGeneratorType] type + */ + int SetDefaultMovementType(lua_State* L, Creature* creature) + { + int32 type = Eluna::CHECKVAL(L, 2); + + creature->SetDefaultMovementType((MovementGeneratorType)type); + return 0; + } + + /** + * Sets whether the [Creature] can search for assistance at low health or not. + * + * @param bool enable = true : `true` to disable searching, `false` to allow + */ + int SetNoSearchAssistance(lua_State* L, Creature* creature) + { + bool val = Eluna::CHECKVAL(L, 2, true); + + creature->SetNoSearchAssistance(val); + return 0; + } + + /** + * Sets whether the [Creature] can call nearby enemies for help in combat or not. + * + * @param bool enable = true : `true` to disable calling for help, `false` to enable + */ + int SetNoCallAssistance(lua_State* L, Creature* creature) + { + bool val = Eluna::CHECKVAL(L, 2, true); + + creature->SetNoCallAssistance(val); + return 0; + } + + /** + * Sets whether the creature is hovering / levitating or not. + * + * @param bool enable = true : `true` to enable hovering, `false` to disable + */ + int SetHover(lua_State* L, Creature* creature) + { + bool enable = Eluna::CHECKVAL(L, 2, true); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->SetHover(enable); +#else + // Copy paste from Aura::HandleAuraHover + // TODO: implement core side properly + WorldPacket data; + if (enable) + data.Initialize(SMSG_MOVE_SET_HOVER, 8 + 4); + else + data.Initialize(SMSG_MOVE_UNSET_HOVER, 8 + 4); + data << creature->GetPackGUID(); + data << uint32(0); +#if defined(CMANGOS) + creature->SendMessageToSet(data, true); +#else + creature->SendMessageToSet(&data, true); +#endif +#endif + return 0; + } + + /** + * Despawn this [Creature]. + * + * @param uint32 delay = 0 : dely to despawn in milliseconds + */ + int DespawnOrUnsummon(lua_State* L, Creature* creature) + { + uint32 msTimeToDespawn = Eluna::CHECKVAL(L, 2, 0); + +#if defined(TRINITY) + creature->DespawnOrUnsummon(Milliseconds(msTimeToDespawn)); +#elif defined(AZEROTHCORE) + creature->DespawnOrUnsummon(msTimeToDespawn); +#else + creature->ForcedDespawn(msTimeToDespawn); +#endif + return 0; + } + + /** + * Respawn this [Creature]. + */ + int Respawn(lua_State* /*L*/, Creature* creature) + { + creature->Respawn(); + return 0; + } + + /** + * Remove this [Creature]'s corpse. + */ + int RemoveCorpse(lua_State* /*L*/, Creature* creature) + { + creature->RemoveCorpse(); + return 0; + } + + /** + * Make the [Creature] start following its waypoint path. + */ + int MoveWaypoint(lua_State* /*L*/, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->GetMotionMaster()->MovePath(creature->GetWaypointPath(), true); +#else + creature->GetMotionMaster()->MoveWaypoint(); +#endif + return 0; + } + + /** + * Make the [Creature] call for assistance in combat from other nearby [Creature]s. + */ + int CallAssistance(lua_State* /*L*/, Creature* creature) + { + creature->CallAssistance(); + return 0; + } + + /** + * Make the [Creature] call for help in combat from friendly [Creature]s within `radius`. + * + * @param float radius + */ + int CallForHelp(lua_State* L, Creature* creature) + { + float radius = Eluna::CHECKVAL(L, 2); + + creature->CallForHelp(radius); + return 0; + } + + /** + * Make the [Creature] flee combat to get assistance from a nearby friendly [Creature]. + */ + int FleeToGetAssistance(lua_State* /*L*/, Creature* creature) + { + creature->DoFleeToGetAssistance(); + return 0; + } + + /** + * Make the [Creature] attack `target`. + * + * @param [Unit] target + */ + int AttackStart(lua_State* L, Creature* creature) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + + creature->AI()->AttackStart(target); + return 0; + } + + /** + * Save the [Creature] in the database. + */ + int SaveToDB(lua_State* /*L*/, Creature* creature) + { + creature->SaveToDB(); + return 0; + } + + /** + * Make the [Creature] try to find a new target. + * + * This should be called every update cycle for the Creature's AI. + */ + int SelectVictim(lua_State* L, Creature* creature) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, creature->SelectVictim()); +#else + Eluna::Push(L, creature->SelectHostileTarget()); +#endif + return 1; + } + + /** + * Transform the [Creature] into another Creature. + * + * @param uint32 entry : the Creature ID to transform into + * @param uint32 dataGUIDLow = 0 : use this Creature's model and equipment instead of the defaults + */ + int UpdateEntry(lua_State* L, Creature* creature) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + uint32 dataGuidLow = Eluna::CHECKVAL(L, 3, 0); + +#if defined(TRINITY) || defined(AZEROTHCORE) + creature->UpdateEntry(entry, dataGuidLow ? eObjectMgr->GetCreatureData(dataGuidLow) : NULL); +#else + creature->UpdateEntry(entry, ALLIANCE, dataGuidLow ? eObjectMgr->GetCreatureData(dataGuidLow) : NULL); +#endif + return 0; + } + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Resets [Creature]'s loot mode to default + */ + int ResetLootMode(lua_State* /*L*/, Creature* creature) // TODO: Implement LootMode features + { + creature->ResetLootMode(); + return 0; + } + + /** + * Removes specified loot mode from [Creature] + * + * @param uint16 lootMode + */ + int RemoveLootMode(lua_State* L, Creature* creature) // TODO: Implement LootMode features + { + uint16 lootMode = Eluna::CHECKVAL(L, 2); + + creature->RemoveLootMode(lootMode); + return 0; + } + + /** + * Adds a loot mode to the [Creature] + * + * @param uint16 lootMode + */ + int AddLootMode(lua_State* L, Creature* creature) // TODO: Implement LootMode features + { + uint16 lootMode = Eluna::CHECKVAL(L, 2); + + creature->AddLootMode(lootMode); + return 0; + } +#endif + + /** + * Returns the [Creature]'s creature family ID (enumerated in CreatureFamily.dbc). + * + *
+     * enum CreatureFamily
+     * {
+     *     CREATURE_FAMILY_NONE                = 0,    // TrinityCore only
+     *     CREATURE_FAMILY_WOLF                = 1,
+     *     CREATURE_FAMILY_CAT                 = 2,
+     *     CREATURE_FAMILY_SPIDER              = 3,
+     *     CREATURE_FAMILY_BEAR                = 4,
+     *     CREATURE_FAMILY_BOAR                = 5,
+     *     CREATURE_FAMILY_CROCOLISK           = 6,
+     *     CREATURE_FAMILY_CARRION_BIRD        = 7,
+     *     CREATURE_FAMILY_CRAB                = 8,
+     *     CREATURE_FAMILY_GORILLA             = 9,
+     *     CREATURE_FAMILY_HORSE_CUSTOM        = 10,   // Does not exist in DBC but used for horse like beasts in DB
+     *     CREATURE_FAMILY_RAPTOR              = 11,
+     *     CREATURE_FAMILY_TALLSTRIDER         = 12,
+     *     CREATURE_FAMILY_FELHUNTER           = 15,
+     *     CREATURE_FAMILY_VOIDWALKER          = 16,
+     *     CREATURE_FAMILY_SUCCUBUS            = 17,
+     *     CREATURE_FAMILY_DOOMGUARD           = 19,
+     *     CREATURE_FAMILY_SCORPID             = 20,
+     *     CREATURE_FAMILY_TURTLE              = 21,
+     *     CREATURE_FAMILY_IMP                 = 23,
+     *     CREATURE_FAMILY_BAT                 = 24,
+     *     CREATURE_FAMILY_HYENA               = 25,
+     *     CREATURE_FAMILY_BIRD_OF_PREY        = 26,   // Named CREATURE_FAMILY_OWL in Mangos
+     *     CREATURE_FAMILY_WIND_SERPENT        = 27,
+     *     CREATURE_FAMILY_REMOTE_CONTROL      = 28,
+     *     CREATURE_FAMILY_FELGUARD            = 29,   // This and below is TBC+
+     *     CREATURE_FAMILY_DRAGONHAWK          = 30,
+     *     CREATURE_FAMILY_RAVAGER             = 31,
+     *     CREATURE_FAMILY_WARP_STALKER        = 32,
+     *     CREATURE_FAMILY_SPOREBAT            = 33,
+     *     CREATURE_FAMILY_NETHER_RAY          = 34,
+     *     CREATURE_FAMILY_SERPENT             = 35,
+     *     CREATURE_FAMILY_SEA_LION            = 36,   // TBC only
+     *     CREATURE_FAMILY_MOTH                = 37,   // This and below is WotLK+
+     *     CREATURE_FAMILY_CHIMAERA            = 38,
+     *     CREATURE_FAMILY_DEVILSAUR           = 39,
+     *     CREATURE_FAMILY_GHOUL               = 40,
+     *     CREATURE_FAMILY_SILITHID            = 41,
+     *     CREATURE_FAMILY_WORM                = 42,
+     *     CREATURE_FAMILY_RHINO               = 43,
+     *     CREATURE_FAMILY_WASP                = 44,
+     *     CREATURE_FAMILY_CORE_HOUND          = 45,
+     *     CREATURE_FAMILY_SPIRIT_BEAST        = 46
+     * };
+     * 
+ * + * @return [CreatureFamily] creatureFamily + */ + int GetCreatureFamily(lua_State* L, Creature* creature) + { + uint32 entry = creature->GetEntry(); + +#if defined(TRINITY) || defined(AZEROTHCORE) + CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry); + if (cInfo) + Eluna::Push(L, cInfo->family); +#else + CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(entry); + if (cInfo) + Eluna::Push(L, cInfo->Family); +#endif + return 1; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ElunaCreatureAI.h b/modules/mod-eluna/src/LuaEngine/ElunaCreatureAI.h new file mode 100644 index 0000000..b03cbae --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaCreatureAI.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _ELUNA_CREATURE_AI_H +#define _ELUNA_CREATURE_AI_H + +#include "LuaEngine.h" + +#if defined TRINITY || AZEROTHCORE +struct ScriptedAI; +#else +class AggressorAI; +typedef AggressorAI ScriptedAI; +#endif + +struct ElunaCreatureAI : ScriptedAI +{ + // used to delay the spawn hook triggering on AI creation + bool justSpawned; + // used to delay movementinform hook (WP hook) + std::vector< std::pair > movepoints; +#if defined MANGOS || defined CMANGOS +#define me m_creature +#endif + + ElunaCreatureAI(Creature* creature) : ScriptedAI(creature), justSpawned(true) + { + } + ~ElunaCreatureAI() { } + + //Called at World update tick +#ifndef TRINITY + void UpdateAI(const uint32 diff) override +#else + void UpdateAI(uint32 diff) override +#endif + { +#ifdef TRINITY + //Spawns are handled by Creature.cpp - in function Creature::Update() +#else + if (justSpawned) + { + justSpawned = false; + + JustRespawned(); + } +#endif + + if (!movepoints.empty()) + { + for (auto& point : movepoints) + { + if (!sEluna->MovementInform(me, point.first, point.second)) + ScriptedAI::MovementInform(point.first, point.second); + } + movepoints.clear(); + } + + if (!sEluna->UpdateAI(me, diff)) + { +#if defined TRINITY || AZEROTHCORE + if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC)) + ScriptedAI::UpdateAI(diff); +#else + if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)) + ScriptedAI::UpdateAI(diff); +#endif + } + } + +#if defined TRINITY || AZEROTHCORE + // Called for reaction when initially engaged - this will always happen _after_ JustEnteredCombat + // Called at creature aggro either by MoveInLOS or Attack Start + void JustEngagedWith(Unit* target) override + { + if (!sEluna->EnterCombat(me, target)) + ScriptedAI::JustEngagedWith(target); + } +#else + //Called for reaction at enter to combat if not in combat yet (enemy can be NULL) + //Called at creature aggro either by MoveInLOS or Attack Start + void EnterCombat(Unit* target) override + { + if (!sEluna->EnterCombat(me, target)) + ScriptedAI::EnterCombat(target); + } +#endif + + // Called at any Damage from any attacker (before damage apply) +#if defined AZEROTHCORE + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override +#elif defined TRINITY + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damageType, SpellInfo const* spellInfo) override +#else + void DamageTaken(Unit* attacker, uint32& damage) override +#endif + { + if (!sEluna->DamageTaken(me, attacker, damage)) + { +#if defined AZEROTHCORE + ScriptedAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask); +#elif defined TRINITY + ScriptedAI::DamageTaken(attacker, damage, damageType, spellInfo); +#else + ScriptedAI::DamageTaken(attacker, damage); +#endif + } + } + + //Called at creature death + void JustDied(Unit* killer) override + { + if (!sEluna->JustDied(me, killer)) + ScriptedAI::JustDied(killer); + } + + //Called at creature killing another unit + void KilledUnit(Unit* victim) override + { + if (!sEluna->KilledUnit(me, victim)) + ScriptedAI::KilledUnit(victim); + } + + // Called when the creature summon successfully other creature + void JustSummoned(Creature* summon) override + { + if (!sEluna->JustSummoned(me, summon)) + ScriptedAI::JustSummoned(summon); + } + + // Called when a summoned creature is despawned + void SummonedCreatureDespawn(Creature* summon) override + { + if (!sEluna->SummonedCreatureDespawn(me, summon)) + ScriptedAI::SummonedCreatureDespawn(summon); + } + + //Called at waypoint reached or PointMovement end + void MovementInform(uint32 type, uint32 id) override + { + // delayed since hook triggers before actually reaching the point + // and starting new movement would bug + movepoints.push_back(std::make_pair(type, id)); + } + + // Called before EnterCombat even before the creature is in combat. + void AttackStart(Unit* target) override + { + if (!sEluna->AttackStart(me, target)) + ScriptedAI::AttackStart(target); + } + + // Called for reaction at stopping attack at no attackers or targets + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (!sEluna->EnterEvadeMode(me)) + ScriptedAI::EnterEvadeMode(); + } + +#ifdef TRINITY + // Called when creature appears in the world (spawn, respawn, grid load etc...) + void JustAppeared() override + { + if (!sEluna->JustRespawned(me)) + ScriptedAI::JustAppeared(); + } +#else + // Called when creature is spawned or respawned (for reseting variables) + void JustRespawned() override + { + if (!sEluna->JustRespawned(me)) + ScriptedAI::JustRespawned(); + } +#endif + + // Called at reaching home after evade + void JustReachedHome() override + { + if (!sEluna->JustReachedHome(me)) + ScriptedAI::JustReachedHome(); + } + + // Called at text emote receive from player + void ReceiveEmote(Player* player, uint32 emoteId) override + { + if (!sEluna->ReceiveEmote(me, player, emoteId)) + ScriptedAI::ReceiveEmote(player, emoteId); + } + + // called when the corpse of this creature gets removed + void CorpseRemoved(uint32& respawnDelay) override + { + if (!sEluna->CorpseRemoved(me, respawnDelay)) + ScriptedAI::CorpseRemoved(respawnDelay); + } + +#if !defined TRINITY && !AZEROTHCORE + // Enables use of MoveInLineOfSight + bool IsVisible(Unit* who) const override + { + return true; + } +#endif + + void MoveInLineOfSight(Unit* who) override + { + if (!sEluna->MoveInLineOfSight(me, who)) + ScriptedAI::MoveInLineOfSight(who); + } + + // Called when hit by a spell +#if defined TRINITY + void SpellHit(WorldObject* caster, SpellInfo const* spell) override +#else + void SpellHit(Unit* caster, SpellInfo const* spell) override +#endif + { + if (!sEluna->SpellHit(me, caster, spell)) + ScriptedAI::SpellHit(caster, spell); + } + + // Called when spell hits a target +#if defined TRINITY + void SpellHitTarget(WorldObject* target, SpellInfo const* spell) override +#else + void SpellHitTarget(Unit* target, SpellInfo const* spell) override +#endif + { + if (!sEluna->SpellHitTarget(me, target, spell)) + ScriptedAI::SpellHitTarget(target, spell); + } + +#if defined TRINITY || AZEROTHCORE + +#if defined TRINITY || AZEROTHCORE + // Called when the creature is summoned successfully by other creature + void IsSummonedBy(WorldObject* summoner) override + { + if (!summoner->ToUnit() || !sEluna->OnSummoned(me, summoner->ToUnit())) + ScriptedAI::IsSummonedBy(summoner); + } +#else + // Called when the creature is summoned successfully by other creature + void IsSummonedBy(Unit* summoner) override + { + if (!sEluna->OnSummoned(me, summoner)) + ScriptedAI::IsSummonedBy(summoner); + } +#endif + + void SummonedCreatureDies(Creature* summon, Unit* killer) override + { + if (!sEluna->SummonedCreatureDies(me, summon, killer)) + ScriptedAI::SummonedCreatureDies(summon, killer); + } + + // Called when owner takes damage + void OwnerAttackedBy(Unit* attacker) override + { + if (!sEluna->OwnerAttackedBy(me, attacker)) + ScriptedAI::OwnerAttackedBy(attacker); + } + + // Called when owner attacks something + void OwnerAttacked(Unit* target) override + { + if (!sEluna->OwnerAttacked(me, target)) + ScriptedAI::OwnerAttacked(target); + } +#endif + +#if defined MANGOS || defined CMANGOS +#undef me +#endif +}; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.cpp b/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.cpp new file mode 100644 index 0000000..c5309a8 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.cpp @@ -0,0 +1,160 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#include "ElunaEventMgr.h" +#include "LuaEngine.h" +#include "Object.h" + +extern "C" +{ +#include "lua.h" +#include "lauxlib.h" +}; + +ElunaEventProcessor::ElunaEventProcessor(Eluna** _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E) +{ + // can be called from multiple threads + if (obj) + { + EventMgr::Guard guard((*E)->eventMgr->GetLock()); + (*E)->eventMgr->processors.insert(this); + } +} + +ElunaEventProcessor::~ElunaEventProcessor() +{ + // can be called from multiple threads + { + LOCK_ELUNA; + RemoveEvents_internal(); + } + + if (obj && Eluna::IsInitialized()) + { + EventMgr::Guard guard((*E)->eventMgr->GetLock()); + (*E)->eventMgr->processors.erase(this); + } +} + +void ElunaEventProcessor::Update(uint32 diff) +{ + m_time += diff; + for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin()) + { + LuaEvent* luaEvent = it->second; + eventList.erase(it); + + if (luaEvent->state != LUAEVENT_STATE_ERASE) + eventMap.erase(luaEvent->funcRef); + + if (luaEvent->state == LUAEVENT_STATE_RUN) + { + uint32 delay = luaEvent->delay; + bool remove = luaEvent->repeats == 1; + if (!remove) + AddEvent(luaEvent); // Reschedule before calling incase RemoveEvents used + + // Call the timed event + (*E)->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj); + + if (!remove) + continue; + } + + // Event should be deleted (executed last time or set to be aborted) + RemoveEvent(luaEvent); + } +} + +void ElunaEventProcessor::SetStates(LuaEventState state) +{ + for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) + it->second->SetState(state); + if (state == LUAEVENT_STATE_ERASE) + eventMap.clear(); +} + +void ElunaEventProcessor::RemoveEvents_internal() +{ + //if (!final) + //{ + // for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) + // it->second->to_Abort = true; + // return; + //} + + for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) + RemoveEvent(it->second); + + eventList.clear(); + eventMap.clear(); +} + +void ElunaEventProcessor::SetState(int eventId, LuaEventState state) +{ + if (eventMap.find(eventId) != eventMap.end()) + eventMap[eventId]->SetState(state); + if (state == LUAEVENT_STATE_ERASE) + eventMap.erase(eventId); +} + +void ElunaEventProcessor::AddEvent(LuaEvent* luaEvent) +{ + luaEvent->GenerateDelay(); + eventList.insert(std::pair(m_time + luaEvent->delay, luaEvent)); + eventMap[luaEvent->funcRef] = luaEvent; +} + +void ElunaEventProcessor::AddEvent(int funcRef, uint32 min, uint32 max, uint32 repeats) +{ + AddEvent(new LuaEvent(funcRef, min, max, repeats)); +} + +void ElunaEventProcessor::RemoveEvent(LuaEvent* luaEvent) +{ + // Unreference if should and if Eluna was not yet uninitialized and if the lua state still exists + if (luaEvent->state != LUAEVENT_STATE_ERASE && Eluna::IsInitialized() && (*E)->HasLuaState()) + { + // Free lua function ref + luaL_unref((*E)->L, LUA_REGISTRYINDEX, luaEvent->funcRef); + } + delete luaEvent; +} + +EventMgr::EventMgr(Eluna** _E) : globalProcessor(new ElunaEventProcessor(_E, NULL)), E(_E) +{ +} + +EventMgr::~EventMgr() +{ + { + Guard guard(GetLock()); + if (!processors.empty()) + for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors + (*it)->RemoveEvents_internal(); + globalProcessor->RemoveEvents_internal(); + } + delete globalProcessor; + globalProcessor = NULL; +} + +void EventMgr::SetStates(LuaEventState state) +{ + Guard guard(GetLock()); + if (!processors.empty()) + for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors + (*it)->SetStates(state); + globalProcessor->SetStates(state); +} + +void EventMgr::SetState(int eventId, LuaEventState state) +{ + Guard guard(GetLock()); + if (!processors.empty()) + for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors + (*it)->SetState(eventId, state); + globalProcessor->SetState(eventId, state); +} diff --git a/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.h b/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.h new file mode 100644 index 0000000..013c8ea --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaEventMgr.h @@ -0,0 +1,112 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _ELUNA_EVENT_MGR_H +#define _ELUNA_EVENT_MGR_H + +#include "ElunaUtility.h" +#include "Common.h" +#ifdef TRINITY +#include "Random.h" +#else +#include "Util.h" +#endif +#include + +#if defined(TRINITY) || AZEROTHCORE +#include "Define.h" +#else +#include "Platform/Define.h" +#endif + +class Eluna; +class EventMgr; +class ElunaEventProcessor; +class WorldObject; + +enum LuaEventState +{ + LUAEVENT_STATE_RUN, // On next call run the function normally + LUAEVENT_STATE_ABORT, // On next call unregisters reffed function and erases the data + LUAEVENT_STATE_ERASE, // On next call just erases the data +}; + +struct LuaEvent +{ + LuaEvent(int _funcRef, uint32 _min, uint32 _max, uint32 _repeats) : + min(_min), max(_max), delay(0), repeats(_repeats), funcRef(_funcRef), state(LUAEVENT_STATE_RUN) + { + } + + void SetState(LuaEventState _state) + { + if (state != LUAEVENT_STATE_ERASE) + state = _state; + } + + void GenerateDelay() + { + delay = urand(min, max); + } + + uint32 min; // Minimum delay between event calls + uint32 max; // Maximum delay between event calls + uint32 delay; // The currently used waiting time + uint32 repeats; // Amount of repeats to make, 0 for infinite + int funcRef; // Lua function reference ID, also used as event ID + LuaEventState state; // State for next call +}; + +class ElunaEventProcessor +{ + friend class EventMgr; + +public: + typedef std::multimap EventList; + typedef std::unordered_map EventMap; + + ElunaEventProcessor(Eluna** _E, WorldObject* _obj); + ~ElunaEventProcessor(); + + void Update(uint32 diff); + // removes all timed events on next tick or at tick end + void SetStates(LuaEventState state); + // set the event to be removed when executing + void SetState(int eventId, LuaEventState state); + void AddEvent(int funcRef, uint32 min, uint32 max, uint32 repeats); + EventMap eventMap; + +private: + void RemoveEvents_internal(); + void AddEvent(LuaEvent* luaEvent); + void RemoveEvent(LuaEvent* luaEvent); + EventList eventList; + uint64 m_time; + WorldObject* obj; + Eluna** E; +}; + +class EventMgr : public ElunaUtil::Lockable +{ +public: + typedef std::unordered_set ProcessorSet; + ProcessorSet processors; + ElunaEventProcessor* globalProcessor; + Eluna** E; + + EventMgr(Eluna** _E); + ~EventMgr(); + + // Set the state of all timed events + // Execute only in safe env + void SetStates(LuaEventState state); + + // Sets the eventId's state in all processors + // Execute only in safe env + void SetState(int eventId, LuaEventState state); +}; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ElunaIncludes.h b/modules/mod-eluna/src/LuaEngine/ElunaIncludes.h new file mode 100644 index 0000000..26f8c0c --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaIncludes.h @@ -0,0 +1,159 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _ELUNA_INCLUDES_H +#define _ELUNA_INCLUDES_H + +// Required +#include "AccountMgr.h" +#include "AuctionHouseMgr.h" +#include "Cell.h" +#include "CellImpl.h" +#include "Chat.h" +#include "Channel.h" +#include "DBCStores.h" +#include "GameEventMgr.h" +#include "GossipDef.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "Group.h" +#include "Guild.h" +#include "GuildMgr.h" +#include "Language.h" +#include "Mail.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Opcodes.h" +#include "Player.h" +#include "Pet.h" +#include "ReputationMgr.h" +#include "ScriptMgr.h" +#include "Spell.h" +#include "SpellAuras.h" +#include "SpellMgr.h" +#include "TemporarySummon.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#if defined TRINITY +#include "SpellHistory.h" +#endif + +#if defined AZEROTHCORE +#include "MapMgr.h" +#else +#include "MapManager.h" +#endif + +#if defined TRINITY || defined AZEROTHCORE +#include "Config.h" +#include "GameEventMgr.h" +#include "GitRevision.h" +#include "GroupMgr.h" +#include "ScriptedCreature.h" +#include "SpellInfo.h" +#include "WeatherMgr.h" +#include "Battleground.h" +#include "MotionMaster.h" +#include "DatabaseEnv.h" +#include "Bag.h" +#else +#include "Config/Config.h" +#ifdef CMANGOS +#include "AI/AggressorAI.h" +#else +#include "AggressorAI.h" +#endif +#include "BattleGroundMgr.h" +#include "SQLStorages.h" +#include "revision.h" +#endif + +#if (!defined(TBC) && !defined(CLASSIC)) +#include "Vehicle.h" +#endif + +#ifndef CLASSIC +#include "ArenaTeam.h" +#endif + +#ifndef CLASSIC +typedef Opcodes OpcodesList; +#endif + +/* + * Note: if you add or change a CORE_NAME or CORE_VERSION #define, + * please update LuaGlobalFunctions::GetCoreName or LuaGlobalFunctions::GetCoreVersion documentation example string. + */ +#ifdef MANGOS +#define CORE_NAME "MaNGOS" +#define CORE_VERSION REVISION_NR +#endif + +#ifdef CMANGOS +#define CORE_NAME "cMaNGOS" +#define CORE_VERSION REVISION_DATE " " REVISION_TIME +#endif + +#ifdef TRINITY +#define CORE_NAME "TrinityCore" +#define REGEN_TIME_FULL +#endif + +#ifdef AZEROTHCORE +#define CORE_NAME "AzerothCore" +#endif + +#if defined TRINITY || defined AZEROTHCORE +#define CORE_VERSION (GitRevision::GetFullVersion()) +#define eWorld (sWorld) +#define eMapMgr (sMapMgr) +#define eConfigMgr (sConfigMgr) +#define eGuildMgr (sGuildMgr) +#define eObjectMgr (sObjectMgr) +#define eAccountMgr (sAccountMgr) +#define eAuctionMgr (sAuctionMgr) +#define eGameEventMgr (sGameEventMgr) +#define eObjectAccessor() ObjectAccessor:: +#endif + +#ifdef CATA +#define NUM_MSG_TYPES NUM_OPCODE_HANDLERS +#endif + +#if !defined TRINITY && !AZEROTHCORE +#define eWorld (&sWorld) +#define eMapMgr (&sMapMgr) +#define eConfigMgr (&sConfig) +#define eGuildMgr (&sGuildMgr) +#define eObjectMgr (&sObjectMgr) +#define eAccountMgr (&sAccountMgr) +#define eAuctionMgr (&sAuctionMgr) +#define eGameEventMgr (&sGameEventMgr) +#define eObjectAccessor() sObjectAccessor. +#define SERVER_MSG_STRING SERVER_MSG_CUSTOM +#define TOTAL_LOCALES MAX_LOCALE +#define TARGETICONCOUNT TARGET_ICON_COUNT +#define MAX_TALENT_SPECS MAX_TALENT_SPEC_COUNT +#define TEAM_NEUTRAL TEAM_INDEX_NEUTRAL + +#if defined(TBC) || defined(WOTLK) || defined(CATA) +#define PLAYER_FIELD_LIFETIME_HONORABLE_KILLS PLAYER_FIELD_LIFETIME_HONORBALE_KILLS +#endif + +#ifdef TBC +#define SPELL_AURA_MOD_KILL_XP_PCT SPELL_AURA_MOD_XP_PCT +#endif + +#if defined(CATA) || defined(MISTS) || (defined(WOTLK) && !defined(MANGOS)) +#define UNIT_BYTE2_FLAG_SANCTUARY UNIT_BYTE2_FLAG_SUPPORTABLE +#endif + +typedef TemporarySummon TempSummon; +typedef SpellEntry SpellInfo; +#endif // TRINITY + +#endif // _ELUNA_INCLUDES_H diff --git a/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.cpp b/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.cpp new file mode 100644 index 0000000..3f58012 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "ElunaInstanceAI.h" +#include "ElunaUtility.h" +#include "lmarshal.h" + + +#ifndef TRINITY +void ElunaInstanceAI::Initialize() +{ + LOCK_ELUNA; + + ASSERT(!sEluna->HasInstanceData(instance)); + + // Create a new table for instance data. + lua_State* L = sEluna->L; + lua_newtable(L); + sEluna->CreateInstanceData(instance); + + sEluna->OnInitialize(this); +} +#endif + +void ElunaInstanceAI::Load(const char* data) +{ + LOCK_ELUNA; + + // If we get passed NULL (i.e. `Reload` was called) then use + // the last known save data (or maybe just an empty string). + if (!data) + { + data = lastSaveData.c_str(); + } + else // Otherwise, copy the new data into our buffer. + { + lastSaveData.assign(data); + } + + if (data[0] == '\0') + { + ASSERT(!sEluna->HasInstanceData(instance)); + + // Create a new table for instance data. + lua_State* L = sEluna->L; + lua_newtable(L); + sEluna->CreateInstanceData(instance); + + sEluna->OnLoad(this); + // Stack: (empty) + return; + } + + size_t decodedLength; + const unsigned char* decodedData = ElunaUtil::DecodeData(data, &decodedLength); + lua_State* L = sEluna->L; + + if (decodedData) + { + // Stack: (empty) + + lua_pushcfunction(L, mar_decode); + lua_pushlstring(L, (const char*)decodedData, decodedLength); + // Stack: mar_decode, decoded_data + + // Call `mar_decode` and check for success. + if (lua_pcall(L, 1, 1, 0) == 0) + { + // Stack: data + // Only use the data if it's a table. + if (lua_istable(L, -1)) + { + sEluna->CreateInstanceData(instance); + // Stack: (empty) + sEluna->OnLoad(this); + // WARNING! lastSaveData might be different after `OnLoad` if the Lua code saved data. + } + else + { + ELUNA_LOG_ERROR("Error while loading instance data: Expected data to be a table (type 5), got type {} instead", lua_type(L, -1)); + lua_pop(L, 1); + // Stack: (empty) + +#ifndef TRINITY + Initialize(); +#endif + } + } + else + { + // Stack: error_message + ELUNA_LOG_ERROR("Error while parsing instance data with lua-marshal: {}", lua_tostring(L, -1)); + lua_pop(L, 1); + // Stack: (empty) + +#ifndef TRINITY + Initialize(); +#endif + } + + delete[] decodedData; + } + else + { + ELUNA_LOG_ERROR("Error while decoding instance data: Data is not valid base-64"); + +#ifndef TRINITY + Initialize(); +#endif + } +} + +const char* ElunaInstanceAI::Save() const +{ + LOCK_ELUNA; + lua_State* L = sEluna->L; + // Stack: (empty) + + /* + * Need to cheat because this method actually does modify this instance, + * even though it's declared as `const`. + * + * Declaring virtual methods as `const` is BAD! + * Don't dictate to children that their methods must be pure. + */ + ElunaInstanceAI* self = const_cast(this); + + lua_pushcfunction(L, mar_encode); + sEluna->PushInstanceData(L, self, false); + // Stack: mar_encode, instance_data + + if (lua_pcall(L, 1, 1, 0) != 0) + { + // Stack: error_message + ELUNA_LOG_ERROR("Error while saving: {}", lua_tostring(L, -1)); + lua_pop(L, 1); + return NULL; + } + + // Stack: data + size_t dataLength; + const unsigned char* data = (const unsigned char*)lua_tolstring(L, -1, &dataLength); + ElunaUtil::EncodeData(data, dataLength, self->lastSaveData); + + lua_pop(L, 1); + // Stack: (empty) + + return lastSaveData.c_str(); +} + +uint32 ElunaInstanceAI::GetData(uint32 key) const +{ + LOCK_ELUNA; + lua_State* L = sEluna->L; + // Stack: (empty) + + sEluna->PushInstanceData(L, const_cast(this), false); + // Stack: instance_data + + Eluna::Push(L, key); + // Stack: instance_data, key + + lua_gettable(L, -2); + // Stack: instance_data, value + + uint32 value = Eluna::CHECKVAL(L, -1, 0); + lua_pop(L, 2); + // Stack: (empty) + + return value; +} + +void ElunaInstanceAI::SetData(uint32 key, uint32 value) +{ + LOCK_ELUNA; + lua_State* L = sEluna->L; + // Stack: (empty) + + sEluna->PushInstanceData(L, this, false); + // Stack: instance_data + + Eluna::Push(L, key); + Eluna::Push(L, value); + // Stack: instance_data, key, value + + lua_settable(L, -3); + // Stack: instance_data + + lua_pop(L, 1); + // Stack: (empty) +} + +uint64 ElunaInstanceAI::GetData64(uint32 key) const +{ + LOCK_ELUNA; + lua_State* L = sEluna->L; + // Stack: (empty) + + sEluna->PushInstanceData(L, const_cast(this), false); + // Stack: instance_data + + Eluna::Push(L, key); + // Stack: instance_data, key + + lua_gettable(L, -2); + // Stack: instance_data, value + + uint64 value = Eluna::CHECKVAL(L, -1, 0); + lua_pop(L, 2); + // Stack: (empty) + + return value; +} + +void ElunaInstanceAI::SetData64(uint32 key, uint64 value) +{ + LOCK_ELUNA; + lua_State* L = sEluna->L; + // Stack: (empty) + + sEluna->PushInstanceData(L, this, false); + // Stack: instance_data + + Eluna::Push(L, key); + Eluna::Push(L, value); + // Stack: instance_data, key, value + + lua_settable(L, -3); + // Stack: instance_data + + lua_pop(L, 1); + // Stack: (empty) +} diff --git a/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.h b/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.h new file mode 100644 index 0000000..4da8323 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaInstanceAI.h @@ -0,0 +1,157 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _ELUNA_INSTANCE_DATA_H +#define _ELUNA_INSTANCE_DATA_H + +#include "LuaEngine.h" +#if defined(TRINITY) || AZEROTHCORE +#include "InstanceScript.h" +#else +#include "InstanceData.h" +#endif + +#ifdef TRINITY +#include "Map.h" +#endif + +/* + * This class is a small wrapper around `InstanceData`, + * allowing instances to be scripted with Eluna. + * + * + * Note 1 + * ====== + * + * Instances of `ElunaInstanceAI` are owned by the core, so they + * are not deleted when Eluna is reloaded. Thus `Load` is only called + * by the core once, no matter how many times Eluna is reloaded. + * + * However, when Eluna reloads, all instance data in Eluna is lost. + * So the solution is as follows: + * + * 1. Store the last save data in the member var `lastSaveData`. + * + * At first this is just the data given to us by the core when it calls `Load`, + * but later on once we start saving new data this is from Eluna. + * + * 2. When retrieving instance data from Eluna, check if it's missing. + * + * The data will be missing if Eluna is reloaded, since a new Lua state is created. + * + * 3. If it *is* missing, call `Reload`. + * + * This reloads the last known instance save data into Eluna, and calls the appropriate hooks. + * + * + * Note 2 + * ====== + * + * CMaNGOS expects some of these methods to be `const`. However, any of these + * methods are free to call `Save`, resulting in mutation of `lastSaveData`. + * + * Therefore, none of the hooks are `const`-safe, and `const_cast` is used + * to escape from these restrictions. + */ +class ElunaInstanceAI : public InstanceData +{ +private: + // The last save data to pass through this class, + // either through `Load` or `Save`. + std::string lastSaveData; + +public: +#ifdef TRINITY + ElunaInstanceAI(Map* map) : InstanceData(map->ToInstanceMap()) + { + } +#else + ElunaInstanceAI(Map* map) : InstanceData(map) + { + } +#endif + +#ifndef TRINITY + void Initialize() override; +#endif + + /* + * These are responsible for serializing/deserializing the instance's + * data table to/from the core. + */ + void Load(const char* data) override; +#if defined TRINITY || AZEROTHCORE + // Simply calls Save, since the functions are a bit different in name and data types on different cores + std::string GetSaveData() override + { + return Save(); + } + const char* Save() const; +#else + const char* Save() const override; +#endif + + + /* + * Calls `Load` with the last save data that was passed to + * or from Eluna. + * + * See: big documentation blurb at the top of this class. + */ + void Reload() + { + Load(NULL); + } + + /* + * These methods allow non-Lua scripts (e.g. DB, C++) to get/set instance data. + */ + uint32 GetData(uint32 key) const override; + void SetData(uint32 key, uint32 value) override; + + uint64 GetData64(uint32 key) const override; + void SetData64(uint32 key, uint64 value) override; + + /* + * These methods are just thin wrappers around Eluna. + */ + void Update(uint32 diff) override + { + // If Eluna is reloaded, it will be missing our instance data. + // Reload here instead of waiting for the next hook call (possibly never). + // This avoids having to have an empty Update hook handler just to trigger the reload. + if (!sEluna->HasInstanceData(instance)) + Reload(); + + sEluna->OnUpdateInstance(this, diff); + } + + bool IsEncounterInProgress() const override + { + return sEluna->OnCheckEncounterInProgress(const_cast(this)); + } + + void OnPlayerEnter(Player* player) override + { + sEluna->OnPlayerEnterInstance(this, player); + } + +#if defined TRINITY || AZEROTHCORE + void OnGameObjectCreate(GameObject* gameobject) override +#else + void OnObjectCreate(GameObject* gameobject) override +#endif + { + sEluna->OnGameObjectCreate(this, gameobject); + } + + void OnCreatureCreate(Creature* creature) override + { + sEluna->OnCreatureCreate(this, creature); + } +}; + +#endif // _ELUNA_INSTANCE_DATA_H diff --git a/modules/mod-eluna/src/LuaEngine/ElunaQueryMethods.h b/modules/mod-eluna/src/LuaEngine/ElunaQueryMethods.h new file mode 100644 index 0000000..17da0ee --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaQueryMethods.h @@ -0,0 +1,369 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef QUERYMETHODS_H +#define QUERYMETHODS_H + +#if defined TRINITY || defined AZEROTHCORE +#define RESULT (*result) +#else +#define RESULT result +#endif + +/*** + * The result of a database query. + * + * E.g. the return value of [Global:WorldDBQuery]. + * + * Inherits all methods from: none + */ +namespace LuaQuery +{ + static void CheckFields(lua_State* L, ElunaQuery* result) + { + uint32 field = Eluna::CHECKVAL(L, 2); + uint32 count = RESULT->GetFieldCount(); + if (field >= count) + { + char arr[256]; + sprintf(arr, "trying to access invalid field index %u. There are %u fields available and the indexes start from 0", field, count); + luaL_argerror(L, 2, arr); + } + } + + /** + * Returns `true` if the specified column of the current row is `NULL`, otherwise `false`. + * + * @param uint32 column + * @return bool isNull + */ + int IsNull(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, RESULT->Fetch()[col].IsNull()); +#else + Eluna::Push(L, RESULT->Fetch()[col].IsNULL()); +#endif + return 1; + } + + /** + * Returns the number of columns in the result set. + * + * @return uint32 columnCount + */ + int GetColumnCount(lua_State* L, ElunaQuery* result) + { + Eluna::Push(L, RESULT->GetFieldCount()); + return 1; + } + + /** + * Returns the number of rows in the result set. + * + * @return uint32 rowCount + */ + int GetRowCount(lua_State* L, ElunaQuery* result) + { + if (RESULT->GetRowCount() > (uint32)-1) + Eluna::Push(L, (uint32)-1); + else + Eluna::Push(L, (uint32)(RESULT->GetRowCount())); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a boolean. + * + * @param uint32 column + * @return bool data + */ + int GetBool(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to an unsigned 8-bit integer. + * + * @param uint32 column + * @return uint8 data + */ + int GetUInt8(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to an unsigned 16-bit integer. + * + * @param uint32 column + * @return uint16 data + */ + int GetUInt16(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to an unsigned 32-bit integer. + * + * @param uint32 column + * @return uint32 data + */ + int GetUInt32(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to an unsigned 64-bit integer. + * + * @param uint32 column + * @return uint64 data + */ + int GetUInt64(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a signed 8-bit integer. + * + * @param uint32 column + * @return int8 data + */ + int GetInt8(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a signed 16-bit integer. + * + * @param uint32 column + * @return int16 data + */ + int GetInt16(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a signed 32-bit integer. + * + * @param uint32 column + * @return int32 data + */ + int GetInt32(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a signed 64-bit integer. + * + * @param uint32 column + * @return int64 data + */ + int GetInt64(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a 32-bit floating point value. + * + * @param uint32 column + * @return float data + */ + int GetFloat(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a 64-bit floating point value. + * + * @param uint32 column + * @return double data + */ + int GetDouble(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Returns the data in the specified column of the current row, casted to a string. + * + * @param uint32 column + * @return string data + */ + int GetString(lua_State* L, ElunaQuery* result) + { + uint32 col = Eluna::CHECKVAL(L, 2); + CheckFields(L, result); + Eluna::Push(L, RESULT->Fetch()[col].Get()); + return 1; + } + + /** + * Advances the [ElunaQuery] to the next row in the result set. + * + * *Do not* call this immediately after a query, or you'll skip the first row. + * + * Returns `false` if there was no new row, otherwise `true`. + * + * @return bool hadNextRow + */ + int NextRow(lua_State* L, ElunaQuery* result) + { + Eluna::Push(L, RESULT->NextRow()); + return 1; + } + + /** + * Returns a table from the current row where keys are field names and values are the row's values. + * + * All numerical values will be numbers and everything else is returned as a string. + * + * **For example,** the query: + * + * SELECT entry, name FROM creature_template + * + * would result in a table like: + * + * { entry = 123, name = "some creature name" } + * + * To move to next row use [ElunaQuery:NextRow]. + * + * @return table rowData : table filled with row columns and data where `T[column] = data` + */ + int GetRow(lua_State* L, ElunaQuery* result) + { + uint32 col = RESULT->GetFieldCount(); + Field* row = RESULT->Fetch(); + + lua_createtable(L, 0, col); + int tbl = lua_gettop(L); + +#if !defined TRINITY && !AZEROTHCORE + const QueryFieldNames& names = RESULT->GetFieldNames(); +#endif + + for (uint32 i = 0; i < col; ++i) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, RESULT->GetFieldName(i)); + + std::string _str = row[i].Get(); + const char* str = _str.c_str(); + if (row[i].IsNull() || !str) + Eluna::Push(L); + else + { + // MYSQL_TYPE_LONGLONG Interpreted as string for lua + switch (row[i].GetType()) + { +#if defined TRINITY || AZEROTHCORE + case DatabaseFieldTypes::Int8: + case DatabaseFieldTypes::Int16: + case DatabaseFieldTypes::Int32: + case DatabaseFieldTypes::Int64: + case DatabaseFieldTypes::Float: + case DatabaseFieldTypes::Double: +#else + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: +#endif + Eluna::Push(L, strtod(str, NULL)); + break; + default: + Eluna::Push(L, str); + break; + } + } +#else + Eluna::Push(L, names[i]); + + const char* str = row[i].GetString(); + if (row[i].IsNULL() || !str) + Eluna::Push(L); + else + { + // MYSQL_TYPE_LONGLONG Interpreted as string for lua + switch (row[i].GetType()) + { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + Eluna::Push(L, strtod(str, NULL)); + break; + default: + Eluna::Push(L, str); + break; + } + } +#endif + + lua_rawset(L, tbl); + } + + lua_settop(L, tbl); + return 1; + } +}; +#undef RESULT + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ElunaTemplate.h b/modules/mod-eluna/src/LuaEngine/ElunaTemplate.h new file mode 100644 index 0000000..95dbacb --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaTemplate.h @@ -0,0 +1,388 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _ELUNA_TEMPLATE_H +#define _ELUNA_TEMPLATE_H + +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +}; +#include "LuaEngine.h" +#include "ElunaUtility.h" +#include "SharedDefines.h" + +class ElunaGlobal +{ +public: + static int thunk(lua_State* L) + { + luaL_Reg* l = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + int top = lua_gettop(L); + int expected = l->func(L); + int args = lua_gettop(L) - top; + if (args < 0 || args > expected) + { + ELUNA_LOG_ERROR("[Eluna]: {} returned unexpected amount of arguments {} out of {}. Report to devs", l->name, args, expected); + ASSERT(false); + } + lua_settop(L, top + expected); + return expected; + } + + static void SetMethods(Eluna* E, luaL_Reg* methodTable) + { + ASSERT(E); + ASSERT(methodTable); + + lua_pushglobaltable(E->L); + + for (; methodTable && methodTable->name && methodTable->func; ++methodTable) + { + lua_pushstring(E->L, methodTable->name); + lua_pushlightuserdata(E->L, (void*)methodTable); + lua_pushcclosure(E->L, thunk, 1); + lua_rawset(E->L, -3); + } + + lua_remove(E->L, -1); + } +}; + +class ElunaObject +{ +public: + template + ElunaObject(T * obj, bool manageMemory); + + ~ElunaObject() + { + } + + // Get wrapped object pointer + void* GetObj() const { return object; } + // Returns whether the object is valid or not + bool IsValid() const { return !callstackid || callstackid == sEluna->GetCallstackId(); } + // Returns whether the object can be invalidated or not + bool CanInvalidate() const { return _invalidate; } + // Returns pointer to the wrapped object's type name + const char* GetTypeName() const { return type_name; } + + // Sets the object pointer that is wrapped + void SetObj(void* obj) + { + ASSERT(obj); + object = obj; + SetValid(true); + } + // Sets the object pointer to valid or invalid + void SetValid(bool valid) + { + ASSERT(!valid || (valid && object)); + if (valid) + if (CanInvalidate()) + callstackid = sEluna->GetCallstackId(); + else + callstackid = 0; + else + callstackid = 1; + } + // Sets whether the pointer will be invalidated at end of calls + void SetValidation(bool invalidate) + { + _invalidate = invalidate; + } + // Invalidates the pointer if it should be invalidated + void Invalidate() + { + if (CanInvalidate()) + callstackid = 1; + } + +private: + uint64 callstackid; + bool _invalidate; + void* object; + const char* type_name; +}; + +template +struct ElunaRegister +{ + const char* name; + int(*mfunc)(lua_State*, T*); +}; + +template +class ElunaTemplate +{ +public: + static const char* tname; + static bool manageMemory; + + // name will be used as type name + // If gc is true, lua will handle the memory management for object pushed + // gc should be used if pushing for example WorldPacket, + // that will only be needed on lua side and will not be managed by TC/mangos/ + static void Register(Eluna* E, const char* name, bool gc = false) + { + ASSERT(E); + ASSERT(name); + + // check that metatable isn't already there + lua_getglobal(E->L, name); + ASSERT(lua_isnoneornil(E->L, -1)); + + // pop nil + lua_pop(E->L, 1); + + tname = name; + manageMemory = gc; + + // create metatable for userdata of this type + luaL_newmetatable(E->L, tname); + int metatable = lua_gettop(E->L); + + // push methodtable to stack to be accessed and modified by users + lua_pushvalue(E->L, metatable); + lua_setglobal(E->L, tname); + + // tostring + lua_pushcfunction(E->L, ToString); + lua_setfield(E->L, metatable, "__tostring"); + + // garbage collecting + lua_pushcfunction(E->L, CollectGarbage); + lua_setfield(E->L, metatable, "__gc"); + + // make methods accessible through metatable + lua_pushvalue(E->L, metatable); + lua_setfield(E->L, metatable, "__index"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Add); + lua_setfield(E->L, metatable, "__add"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Substract); + lua_setfield(E->L, metatable, "__sub"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Multiply); + lua_setfield(E->L, metatable, "__mul"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Divide); + lua_setfield(E->L, metatable, "__div"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Mod); + lua_setfield(E->L, metatable, "__mod"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Pow); + lua_setfield(E->L, metatable, "__pow"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, UnaryMinus); + lua_setfield(E->L, metatable, "__unm"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Concat); + lua_setfield(E->L, metatable, "__concat"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Length); + lua_setfield(E->L, metatable, "__len"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Equal); + lua_setfield(E->L, metatable, "__eq"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Less); + lua_setfield(E->L, metatable, "__lt"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, LessOrEqual); + lua_setfield(E->L, metatable, "__le"); + + // make new indexes saved to methods + lua_pushcfunction(E->L, Call); + lua_setfield(E->L, metatable, "__call"); + + // special method to get the object type + lua_pushcfunction(E->L, GetType); + lua_setfield(E->L, metatable, "GetObjectType"); + + // special method to decide object invalidation at end of call + lua_pushcfunction(E->L, SetInvalidation); + lua_setfield(E->L, metatable, "SetInvalidation"); + + // pop metatable + lua_pop(E->L, 1); + } + + template + static void SetMethods(Eluna* E, ElunaRegister* methodTable) + { + ASSERT(E); + ASSERT(tname); + ASSERT(methodTable); + + // get metatable + lua_pushstring(E->L, tname); + lua_rawget(E->L, LUA_REGISTRYINDEX); + ASSERT(lua_istable(E->L, -1)); + + for (; methodTable && methodTable->name && methodTable->mfunc; ++methodTable) + { + lua_pushstring(E->L, methodTable->name); + lua_pushlightuserdata(E->L, (void*)methodTable); + lua_pushcclosure(E->L, CallMethod, 1); + lua_rawset(E->L, -3); + } + + lua_pop(E->L, 1); + } + + static int Push(lua_State* L, T const* obj) + { + if (!obj) + { + lua_pushnil(L); + return 1; + } + + // Create new userdata + ElunaObject** ptrHold = static_cast(lua_newuserdata(L, sizeof(ElunaObject*))); + if (!ptrHold) + { + ELUNA_LOG_ERROR("{} could not create new userdata", tname); + lua_pushnil(L); + return 1; + } + *ptrHold = new ElunaObject(const_cast(obj), manageMemory); + + // Set metatable for it + lua_pushstring(L, tname); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) + { + ELUNA_LOG_ERROR("{} missing metatable", tname); + lua_pop(L, 2); + lua_pushnil(L); + return 1; + } + lua_setmetatable(L, -2); + return 1; + } + + static T* Check(lua_State* L, int narg, bool error = true) + { + ElunaObject* elunaObj = Eluna::CHECKTYPE(L, narg, tname, error); + if (!elunaObj) + return NULL; + + if (!elunaObj->IsValid()) + { + char buff[256]; + snprintf(buff, 256, "%s expected, got pointer to nonexisting (invalidated) object (%s). Check your code.", tname, luaL_typename(L, narg)); + if (error) + { + luaL_argerror(L, narg, buff); + } + else + { + ELUNA_LOG_ERROR("{}", buff); + } + return NULL; + } + return static_cast(elunaObj->GetObj()); + } + + static int GetType(lua_State* L) + { + lua_pushstring(L, tname); + return 1; + } + + static int SetInvalidation(lua_State* L) + { + ElunaObject* elunaObj = Eluna::CHECKOBJ(L, 1); + bool invalidate = Eluna::CHECKVAL(L, 2); + + elunaObj->SetValidation(invalidate); + return 0; + } + + static int CallMethod(lua_State* L) + { + T* obj = Eluna::CHECKOBJ(L, 1); // get self + if (!obj) + return 0; + ElunaRegister* l = static_cast*>(lua_touserdata(L, lua_upvalueindex(1))); + int top = lua_gettop(L); + int expected = l->mfunc(L, obj); + int args = lua_gettop(L) - top; + if (args < 0 || args > expected) + { + ELUNA_LOG_ERROR("[Eluna]: {} returned unexpected amount of arguments {} out of {}. Report to devs", l->name, args, expected); + ASSERT(false); + } + lua_settop(L, top + expected); + return expected; + } + + // Metamethods ("virtual") + + // Remember special cases like ElunaTemplate::CollectGarbage + static int CollectGarbage(lua_State* L) + { + // Get object pointer (and check type, no error) + ElunaObject* obj = Eluna::CHECKOBJ(L, 1, false); + if (obj && manageMemory) + delete static_cast(obj->GetObj()); + delete obj; + return 0; + } + + static int ToString(lua_State* L) + { + T* obj = Eluna::CHECKOBJ(L, 1, true); // get self + lua_pushfstring(L, "%s: %p", tname, obj); + return 1; + } + + static int ArithmeticError(lua_State* L) { return luaL_error(L, "attempt to perform arithmetic on a %s value", tname); } + static int CompareError(lua_State* L) { return luaL_error(L, "attempt to compare %s", tname); } + static int Add(lua_State* L) { return ArithmeticError(L); } + static int Substract(lua_State* L) { return ArithmeticError(L); } + static int Multiply(lua_State* L) { return ArithmeticError(L); } + static int Divide(lua_State* L) { return ArithmeticError(L); } + static int Mod(lua_State* L) { return ArithmeticError(L); } + static int Pow(lua_State* L) { return ArithmeticError(L); } + static int UnaryMinus(lua_State* L) { return ArithmeticError(L); } + static int Concat(lua_State* L) { return luaL_error(L, "attempt to concatenate a %s value", tname); } + static int Length(lua_State* L) { return luaL_error(L, "attempt to get length of a %s value", tname); } + static int Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKOBJ(L, 1) == Eluna::CHECKOBJ(L, 2)); return 1; } + static int Less(lua_State* L) { return CompareError(L); } + static int LessOrEqual(lua_State* L) { return CompareError(L); } + static int Call(lua_State* L) { return luaL_error(L, "attempt to call a %s value", tname); } +}; + +template +ElunaObject::ElunaObject(T * obj, bool manageMemory) : callstackid(1), _invalidate(!manageMemory), object(obj), type_name(ElunaTemplate::tname) +{ + SetValid(true); +} + +template const char* ElunaTemplate::tname = NULL; +template bool ElunaTemplate::manageMemory = false; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ElunaUtility.cpp b/modules/mod-eluna/src/LuaEngine/ElunaUtility.cpp new file mode 100644 index 0000000..9f436d6 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaUtility.cpp @@ -0,0 +1,200 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#include "ElunaUtility.h" +#include "World.h" +#include "Object.h" +#include "Unit.h" +#include "GameObject.h" +#include "DBCStores.h" +#ifdef MANGOS +#include "Timer.h" +#endif + +uint32 ElunaUtil::GetCurrTime() +{ + return getMSTime(); +} + +uint32 ElunaUtil::GetTimeDiff(uint32 oldMSTime) +{ + return GetMSTimeDiffToNow(oldMSTime); +} + +ElunaUtil::ObjectGUIDCheck::ObjectGUIDCheck(ObjectGuid guid) : _guid(guid) +{ +} + +bool ElunaUtil::ObjectGUIDCheck::operator()(WorldObject* object) +{ + return object->GET_GUID() == _guid; +} + +ElunaUtil::ObjectDistanceOrderPred::ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending) : m_refObj(pRefObj), m_ascending(ascending) +{ +} +bool ElunaUtil::ObjectDistanceOrderPred::operator()(WorldObject const* pLeft, WorldObject const* pRight) const +{ + return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight); +} + +ElunaUtil::WorldObjectInRangeCheck::WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range, + uint16 typeMask, uint32 entry, uint32 hostile, uint32 dead) : + i_obj(obj), i_obj_unit(nullptr), i_obj_fact(nullptr), i_hostile(hostile), i_entry(entry), i_range(range), i_typeMask(typeMask), i_dead(dead), i_nearest(nearest) +{ + i_obj_unit = i_obj->ToUnit(); + if (!i_obj_unit) + if (GameObject const* go = i_obj->ToGameObject()) + i_obj_unit = go->GetOwner(); + if (!i_obj_unit) + i_obj_fact = sFactionTemplateStore.LookupEntry(14); +} +WorldObject const& ElunaUtil::WorldObjectInRangeCheck::GetFocusObject() const +{ + return *i_obj; +} +bool ElunaUtil::WorldObjectInRangeCheck::operator()(WorldObject* u) +{ + if (i_typeMask && !u->isType(TypeMask(i_typeMask))) + return false; + if (i_entry && u->GetEntry() != i_entry) + return false; + if (i_obj->GET_GUID() == u->GET_GUID()) + return false; + if (!i_obj->IsWithinDistInMap(u, i_range)) + return false; + Unit const* target = u->ToUnit(); + if (!target) + if (GameObject const* go = u->ToGameObject()) + target = go->GetOwner(); + if (target) + { +#ifdef CMANGOS + if (i_dead && (i_dead == 1) != target->isAlive()) + return false; +#else + if (i_dead && (i_dead == 1) != target->IsAlive()) + return false; +#endif + if (i_hostile) + { + if (!i_obj_unit) + { + if (i_obj_fact) + { +#if defined TRINITY || AZEROTHCORE + if ((i_obj_fact->IsHostileTo(*target->GetFactionTemplateEntry())) != (i_hostile == 1)) + return false; +#else + if ((i_obj_fact->IsHostileTo(*target->getFactionTemplateEntry())) != (i_hostile == 1)) + return false; +#endif + } + else if (i_hostile == 1) + return false; + } + else if ((i_hostile == 1) != i_obj_unit->IsHostileTo(target)) + return false; + } + } + if (i_nearest) + i_range = i_obj->GetDistance(u); + return true; +} + +static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; +static char decoding_table[256]; +static int mod_table[] = {0, 2, 1}; + +static void build_decoding_table() +{ + for (int i = 0; i < 64; i++) + decoding_table[(unsigned char)encoding_table[i]] = i; +} + +void ElunaUtil::EncodeData(const unsigned char* data, size_t input_length, std::string& output) +{ + size_t output_length = 4 * ((input_length + 2) / 3); + char* buffer = new char[output_length]; + + for (size_t i = 0, j = 0; i < input_length;) + { + uint32 octet_a = i < input_length ? (unsigned char)data[i++] : 0; + uint32 octet_b = i < input_length ? (unsigned char)data[i++] : 0; + uint32 octet_c = i < input_length ? (unsigned char)data[i++] : 0; + + uint32 triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + buffer[j++] = encoding_table[(triple >> (3 * 6)) & 0x3F]; + buffer[j++] = encoding_table[(triple >> (2 * 6)) & 0x3F]; + buffer[j++] = encoding_table[(triple >> (1 * 6)) & 0x3F]; + buffer[j++] = encoding_table[(triple >> (0 * 6)) & 0x3F]; + } + + for (int i = 0; i < mod_table[input_length % 3]; i++) + buffer[output_length - 1 - i] = '='; + + output.assign(buffer, output_length); // Need length because `buffer` is not terminated! + delete[] buffer; +} + +unsigned char* ElunaUtil::DecodeData(const char *data, size_t *output_length) +{ + if (decoding_table[(unsigned char)'B'] == 0) + build_decoding_table(); + + size_t input_length = strlen(data); + + if (input_length % 4 != 0) + return NULL; + + // Make sure there's no invalid characters in the data. + for (size_t i = 0; i < input_length; ++i) + { + unsigned char byte = data[i]; + + if (byte == '=') + continue; + + // Every invalid character (and 'A') will map to 0 (due to `calloc`). + if (decoding_table[byte] == 0 && byte != 'A') + return NULL; + } + + *output_length = input_length / 4 * 3; + if (data[input_length - 1] == '=') (*output_length)--; + if (data[input_length - 2] == '=') (*output_length)--; + + unsigned char *decoded_data = new unsigned char[*output_length]; + if (!decoded_data) + return NULL; + + for (size_t i = 0, j = 0; i < input_length;) + { + uint32 sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)data[i++]]; + uint32 sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)data[i++]]; + uint32 sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)data[i++]]; + uint32 sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(unsigned char)data[i++]]; + + uint32 triple = (sextet_a << (3 * 6)) + + (sextet_b << (2 * 6)) + + (sextet_c << (1 * 6)) + + (sextet_d << (0 * 6)); + + if (j < *output_length) decoded_data[j++] = (triple >> (2 * 8)) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> (1 * 8)) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> (0 * 8)) & 0xFF; + } + + return decoded_data; +} diff --git a/modules/mod-eluna/src/LuaEngine/ElunaUtility.h b/modules/mod-eluna/src/LuaEngine/ElunaUtility.h new file mode 100644 index 0000000..ba6a5f8 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ElunaUtility.h @@ -0,0 +1,163 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _ELUNA_UTIL_H +#define _ELUNA_UTIL_H + +#include +#include +#include +#include +#include "Common.h" +#include "SharedDefines.h" +#include "ObjectGuid.h" +#ifdef TRINITY +#include "QueryResult.h" +#include "Log.h" +#ifdef CATA +#include "Object.h" +#endif +#else +#include "Database/QueryResult.h" +#include "Log.h" +#endif + +#if defined(TRINITY) || defined(AZEROTHCORE) +typedef QueryResult ElunaQuery; +#define GET_GUID GetGUID +#define HIGHGUID_PLAYER HighGuid::Player +#define HIGHGUID_UNIT HighGuid::Unit +#define HIGHGUID_ITEM HighGuid::Item +#define HIGHGUID_GAMEOBJECT HighGuid::GameObject +#define HIGHGUID_PET HighGuid::Pet +#define HIGHGUID_TRANSPORT HighGuid::Transport +#define HIGHGUID_VEHICLE HighGuid::Vehicle +#define HIGHGUID_CONTAINER HighGuid::Container +#define HIGHGUID_DYNAMICOBJECT HighGuid::DynamicObject +#define HIGHGUID_CORPSE HighGuid::Corpse +#define HIGHGUID_MO_TRANSPORT HighGuid::Mo_Transport +#define HIGHGUID_INSTANCE HighGuid::Instance +#define HIGHGUID_GROUP HighGuid::Group +#endif + +#ifdef TRINITY +#define ELUNA_LOG_INFO(...) TC_LOG_INFO("eluna", __VA_ARGS__); +#define ELUNA_LOG_ERROR(...) TC_LOG_ERROR("eluna", __VA_ARGS__); +#define ELUNA_LOG_DEBUG(...) TC_LOG_DEBUG("eluna", __VA_ARGS__); +#elif defined(AZEROTHCORE) +#define ELUNA_LOG_INFO(...) LOG_INFO("eluna", __VA_ARGS__); +#define ELUNA_LOG_ERROR(...) LOG_ERROR("eluna", __VA_ARGS__); +#define ELUNA_LOG_DEBUG(...) LOG_DEBUG("eluna", __VA_ARGS__); +#else +typedef QueryNamedResult ElunaQuery; +#define ASSERT MANGOS_ASSERT +#define ELUNA_LOG_INFO(...) sLog.outString(__VA_ARGS__); +#define ELUNA_LOG_ERROR(...) sLog.outErrorEluna(__VA_ARGS__); +#define ELUNA_LOG_DEBUG(...) sLog.outDebug(__VA_ARGS__); +#define GET_GUID GetObjectGuid +#define GetGameObjectTemplate GetGameObjectInfo +#define GetItemTemplate GetItemPrototype +#define GetTemplate GetProto +#endif + +#if defined(TRINITY) || defined(AZEROTHCORE) || defined(MANGOS) +#ifndef MAKE_NEW_GUID +#define MAKE_NEW_GUID(l, e, h) ObjectGuid(h, e, l) +#endif +#ifndef GUID_ENPART +#define GUID_ENPART(guid) ObjectGuid(guid).GetEntry() +#endif +#ifndef GUID_LOPART +#define GUID_LOPART(guid) ObjectGuid(guid).GetCounter() +#endif +#ifndef GUID_HIPART +#define GUID_HIPART(guid) ObjectGuid(guid).GetHigh() +#endif +#endif + +class Unit; +class WorldObject; +struct FactionTemplateEntry; + +namespace ElunaUtil +{ + uint32 GetCurrTime(); + + uint32 GetTimeDiff(uint32 oldMSTime); + + class ObjectGUIDCheck + { + public: + ObjectGUIDCheck(ObjectGuid guid); + bool operator()(WorldObject* object); + + ObjectGuid _guid; + }; + + // Binary predicate to sort WorldObjects based on the distance to a reference WorldObject + class ObjectDistanceOrderPred + { + public: + ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending = true); + bool operator()(WorldObject const* pLeft, WorldObject const* pRight) const; + + WorldObject const* m_refObj; + const bool m_ascending; + }; + + // Doesn't get self + class WorldObjectInRangeCheck + { + public: + WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range, + uint16 typeMask = 0, uint32 entry = 0, uint32 hostile = 0, uint32 dead = 0); + WorldObject const& GetFocusObject() const; + bool operator()(WorldObject* u); + + WorldObject const* const i_obj; + Unit const* i_obj_unit; + FactionTemplateEntry const* i_obj_fact; + uint32 const i_hostile; // 0 both, 1 hostile, 2 friendly + uint32 const i_entry; + float i_range; + uint16 const i_typeMask; + uint32 const i_dead; // 0 both, 1 alive, 2 dead + bool const i_nearest; + }; + + /* + * Usage: + * Inherit this class, then when needing lock, use + * Guard guard(GetLock()); + * + * The lock is automatically released at end of scope + */ + class Lockable + { + public: + typedef std::mutex LockType; + typedef std::lock_guard Guard; + + LockType& GetLock() { return _lock; } + + private: + LockType _lock; + }; + + /* + * Encodes `data` in Base-64 and store the result in `output`. + */ + void EncodeData(const unsigned char* data, size_t input_length, std::string& output); + + /* + * Decodes `data` from Base-64 and returns a pointer to the result, or `NULL` on error. + * + * The returned result buffer must be `delete[]`ed by the caller. + */ + unsigned char* DecodeData(const char* data, size_t *output_length); +}; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/GameObjectHooks.cpp b/modules/mod-eluna/src/LuaEngine/GameObjectHooks.cpp new file mode 100644 index 0000000..e463220 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GameObjectHooks.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaEventMgr.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT, ENTRY) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!GameObjectEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!GameObjectEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +void Eluna::OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) +{ + pGameObject->elunaEvents->Update(diff); + START_HOOK(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()); + Push(pGameObject); + Push(diff); + CallAllFunctions(GameObjectEventBindings, key); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) +{ + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry(), false); + Push(pPlayer); + Push(pGameObject); + Push(pQuest); + return CallAllFunctionsBool(GameObjectEventBindings, key); +} + +bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt) +{ + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry(), false); + Push(pPlayer); + Push(pGameObject); + Push(pQuest); + Push(opt); + return CallAllFunctionsBool(GameObjectEventBindings, key); +} + +void Eluna::GetDialogStatus(const Player* pPlayer, const GameObject* pGameObject) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()); + Push(pPlayer); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); +} + +#ifndef CLASSIC +#ifndef TBC +void Eluna::OnDestroyed(GameObject* pGameObject, WorldObject* attacker) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); + Push(pGameObject); + Push(attacker); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::OnDamaged(GameObject* pGameObject, WorldObject* attacker) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); + Push(pGameObject); + Push(attacker); + CallAllFunctions(GameObjectEventBindings, key); +} +#endif +#endif + +void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); + Push(pGameObject); + Push(state); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()); + Push(pGameObject); + Push(state); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::OnSpawn(GameObject* pGameObject) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_SPAWN, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::OnAddToWorld(GameObject* pGameObject) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_ADD, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); +} + +void Eluna::OnRemoveFromWorld(GameObject* pGameObject) +{ + START_HOOK(GAMEOBJECT_EVENT_ON_REMOVE, pGameObject->GetEntry()); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, key); +} + +bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) +{ + START_HOOK_WITH_RETVAL(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry(), false); + Push(pGameObject); + Push(pPlayer); + return CallAllFunctionsBool(GameObjectEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/GameObjectMethods.h b/modules/mod-eluna/src/LuaEngine/GameObjectMethods.h new file mode 100644 index 0000000..ccb0ce1 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GameObjectMethods.h @@ -0,0 +1,401 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef GAMEOBJECTMETHODS_H +#define GAMEOBJECTMETHODS_H + +/*** + * Inherits all methods from: [Object], [WorldObject] + */ +namespace LuaGameObject +{ + /** + * Returns 'true' if the [GameObject] can give the specified [Quest] + * + * @param uint32 questId : quest entry Id to check + * @return bool hasQuest + */ + int HasQuest(lua_State* L, GameObject* go) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, go->hasQuest(questId)); +#else + Eluna::Push(L, go->HasQuest(questId)); +#endif + return 1; + } + + /** + * Returns 'true' if the [GameObject] is spawned + * + * @return bool isSpawned + */ + int IsSpawned(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->isSpawned()); + return 1; + } + + /** + * Returns 'true' if the [GameObject] is a transport + * + * @return bool isTransport + */ + int IsTransport(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->IsTransport()); + return 1; + } + + /** + * Returns 'true' if the [GameObject] is active + * + * @return bool isActive + */ + int IsActive(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->isActiveObject()); + return 1; + } + + /*int IsDestructible(lua_State* L, GameObject* go) // TODO: Implementation core side + { + Eluna::Push(L, go->IsDestructibleBuilding()); + return 1; + }*/ + + /** + * Returns display ID of the [GameObject] + * + * @return uint32 displayId + */ + int GetDisplayId(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->GetDisplayId()); + return 1; + } + + /** + * Returns the state of a [GameObject] + * Below are client side [GOState]s off of 3.3.5a + * + *
+     * enum GOState
+     * {
+     *     GO_STATE_ACTIVE             = 0,                        // show in world as used and not reset (closed door open)
+     *     GO_STATE_READY              = 1,                        // show in world as ready (closed door close)
+     *     GO_STATE_ACTIVE_ALTERNATIVE = 2                         // show in world as used in alt way and not reset (closed door open by cannon fire)
+     * };
+     * 
+ * + * @return [GOState] goState + */ + int GetGoState(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->GetGoState()); + return 1; + } + + /** + * Returns the [LootState] of a [GameObject] + * Below are [LootState]s off of 3.3.5a + * + *
+     * enum LootState
+     * {
+     *     GO_NOT_READY = 0,
+     *     GO_READY,                                               // can be ready but despawned, and then not possible activate until spawn
+     *     GO_ACTIVATED,
+     *     GO_JUST_DEACTIVATED
+     * };
+     * 
+ * + * @return [LootState] lootState + */ + int GetLootState(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->getLootState()); + return 1; + } + + /** + * Returns the [Player] that can loot the [GameObject] + * + * Not the original looter and may be nil. + * + * @return [Player] player + */ + int GetLootRecipient(lua_State* L, GameObject* go) + { + Eluna::Push(L, go->GetLootRecipient()); + return 1; + } + + /** + * Returns the [Group] that can loot the [GameObject] + * + * Not the original looter and may be nil. + * + * @return [Group] group + */ + int GetLootRecipientGroup(lua_State* L, GameObject* go) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, go->GetLootRecipientGroup()); +#else + Eluna::Push(L, go->GetGroupLootRecipient()); +#endif + return 1; + } + + /** + * Returns the guid of the [GameObject] that is used as the ID in the database + * + * @return uint32 dbguid + */ + int GetDBTableGUIDLow(lua_State* L, GameObject* go) + { +#if defined(TRINITY) || defined(AZEROTHCORE) + Eluna::Push(L, go->GetSpawnId()); +#else + // on mangos based this is same as lowguid + Eluna::Push(L, go->GetGUIDLow()); +#endif + return 1; + } + + /** + * Sets the state of a [GameObject] + * + *
+     * enum GOState
+     * {
+     *     GO_STATE_ACTIVE             = 0,                        // show in world as used and not reset (closed door open)
+     *     GO_STATE_READY              = 1,                        // show in world as ready (closed door close)
+     *     GO_STATE_ACTIVE_ALTERNATIVE = 2                         // show in world as used in alt way and not reset (closed door open by cannon fire)
+     * };
+     * 
+ * + * @param [GOState] state : all available go states can be seen above + */ + int SetGoState(lua_State* L, GameObject* go) + { + uint32 state = Eluna::CHECKVAL(L, 2, 0); + + if (state == 0) + go->SetGoState(GO_STATE_ACTIVE); + else if (state == 1) + go->SetGoState(GO_STATE_READY); + else if (state == 2) + { +#ifdef TRINITY + go->SetGoState(GO_STATE_DESTROYED); +#else + go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); +#endif + } + + return 0; + } + + /** + * Sets the [LootState] of a [GameObject] + * Below are [LootState]s off of 3.3.5a + * + *
+     * enum LootState
+     * {
+     *     GO_NOT_READY = 0,
+     *     GO_READY,                                               // can be ready but despawned, and then not possible activate until spawn
+     *     GO_ACTIVATED,
+     *     GO_JUST_DEACTIVATED
+     * };
+     * 
+ * + * @param [LootState] state : all available loot states can be seen above + */ + int SetLootState(lua_State* L, GameObject* go) + { + uint32 state = Eluna::CHECKVAL(L, 2, 0); + + if (state == 0) + go->SetLootState(GO_NOT_READY); + else if (state == 1) + go->SetLootState(GO_READY); + else if (state == 2) + go->SetLootState(GO_ACTIVATED); + else if (state == 3) + go->SetLootState(GO_JUST_DEACTIVATED); + + return 0; + } + + /** + * Adds an [Item] to the loot of a [GameObject] + * Requires an gameobject with loot_template set to 0. + * + * @param uint32 entry : The entry of the [Item] + * @param uint32 amount = 1 : amount of the [Item] to add to the loot + * @return uint32 itemGUIDlow : low GUID of the [Item] + */ + + int AddLoot(lua_State* L, GameObject* go) + { + int i = 1; + int argAmount = lua_gettop(L); + +#if defined TRINITY || defined AZEROTHCORE + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); +#endif + uint8 addedItems = 0; + while (i + 2 <= argAmount) + { + uint32 entry = Eluna::CHECKVAL(L, ++i); + uint32 amount = Eluna::CHECKVAL(L, ++i); + +#if defined TRINITY || AZEROTHCORE + ItemTemplate const* item_proto = eObjectMgr->GetItemTemplate(entry); +#else + ItemTemplate const* item_proto = ObjectMgr::GetItemPrototype(entry); +#endif + if (!item_proto) + { + luaL_error(L, "Item entry %d does not exist", entry); + continue; + } + if (amount < 1 || (item_proto->MaxCount > 0 && amount > uint32(item_proto->MaxCount))) + { + luaL_error(L, "Item entry %d has invalid amount %d", entry, amount); + continue; + } + if (Item* item = Item::CreateItem(entry, amount)) + { +#if defined TRINITY || AZEROTHCORE + item->SaveToDB(trans); +#else + item->SaveToDB(); +#endif + LootStoreItem storeItem(item->GetEntry(), 0, 100, 0, LOOT_MODE_DEFAULT, 0, item->GetCount(), item->GetCount()); + go->loot.AddItem(storeItem); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, item->GetGUID().GetCounter()); +#else + Eluna::Push(L, item->GetGUIDLow()); +#endif + ++addedItems; + } + } + +#if defined TRINITY || AZEROTHCORE + CharacterDatabase.CommitTransaction(trans); +#endif + + return addedItems; + } + + /** + * Saves [GameObject] to the database + * + */ + int SaveToDB(lua_State* /*L*/, GameObject* go) + { + go->SaveToDB(); + return 0; + } + + /** + * Removes [GameObject] from the world + * + * The object is no longer reachable after this and it is not respawned. + * + * @param bool deleteFromDB : if true, it will delete the [GameObject] from the database + */ + int RemoveFromWorld(lua_State* L, GameObject* go) + { + bool deldb = Eluna::CHECKVAL(L, 2, false); + + // cs_gobject.cpp copy paste +#if defined TRINITY || AZEROTHCORE + ObjectGuid ownerGuid = go->GetOwnerGUID(); +#else + ObjectGuid ownerGuid = go->GetOwnerGuid(); +#endif + if (ownerGuid) + { + Unit* owner = eObjectAccessor()GetUnit(*go, ownerGuid); + if (!owner || !ownerGuid.IsPlayer()) + return 0; + + owner->RemoveGameObject(go, false); + } + + if (deldb) + { +#ifdef TRINITY + GameObject::DeleteFromDB(go->GetSpawnId()); +#else + go->DeleteFromDB(); +#endif + } + + go->SetRespawnTime(0); + go->Delete(); + + Eluna::CHECKOBJ(L, 1)->Invalidate(); + return 0; + } + + /** + * Activates a door or a button/lever + * + * @param uint32 delay = 0 : cooldown time in seconds to restore the [GameObject] back to normal. 0 for infinite duration + */ + int UseDoorOrButton(lua_State* L, GameObject* go) + { + uint32 delay = Eluna::CHECKVAL(L, 2, 0); + + go->UseDoorOrButton(delay); + return 0; + } + + /** + * Despawns a [GameObject] + * + * The gameobject may be automatically respawned by the core + */ + int Despawn(lua_State* /*L*/, GameObject* go) + { + go->SetLootState(GO_JUST_DEACTIVATED); + return 0; + } + + /** + * Respawns a [GameObject] + */ + int Respawn(lua_State* /*L*/, GameObject* go) + { + go->Respawn(); + return 0; + } + + /** + * Sets the respawn or despawn time for the gameobject. + * + * Respawn time is also used as despawn time depending on gameobject settings + * + * @param int32 delay = 0 : cooldown time in seconds to respawn or despawn the object. 0 means never + */ + int SetRespawnTime(lua_State* L, GameObject* go) + { + int32 respawn = Eluna::CHECKVAL(L, 2); + + go->SetRespawnTime(respawn); + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/GlobalMethods.h b/modules/mod-eluna/src/LuaEngine/GlobalMethods.h new file mode 100644 index 0000000..b0e1bdb --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GlobalMethods.h @@ -0,0 +1,3496 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef GLOBALMETHODS_H +#define GLOBALMETHODS_H + +#include "BindingMap.h" + +#ifdef AZEROTHCORE + +#include "BanMgr.h" +#include "GameTime.h" +#include "SharedDefines.h" +#include "OutdoorPvPMgr.h" +#include "../../../../src/server/scripts/OutdoorPvP/OutdoorPvPNA.h" + +enum BanMode +{ + BAN_ACCOUNT = 1, + BAN_CHARACTER = 2, + BAN_IP = 3 +}; + +#endif + +/*** + * These functions can be used anywhere at any time, including at start-up. + */ +namespace LuaGlobalFunctions +{ + /** + * Returns Lua engine's name. + * + * Always returns "ElunaEngine" on Eluna. + * + * @return string engineName + */ + int GetLuaEngine(lua_State* L) + { + Eluna::Push(L, "ElunaEngine"); + return 1; + } + + /** + * Returns emulator's name. + * + * The result will be either `MaNGOS`, `cMaNGOS`, or `TrinityCore`. + * + * @return string coreName + */ + int GetCoreName(lua_State* L) + { + Eluna::Push(L, CORE_NAME); + return 1; + } + + /** + * Returns emulator .conf RealmID + * + * - for MaNGOS returns the realmID as it is stored in the core. + * - for TrinityCore returns the realmID as it is in the conf file. + * @return uint32 realm ID + */ + + int GetRealmID(lua_State* L) + { +#ifdef MANGOS + Eluna::Push(L, realmID); +#elif defined(AZEROTHCORE) + Eluna::Push(L, sConfigMgr->GetOption("RealmID", 1)); +#else + Eluna::Push(L, sConfigMgr->GetIntDefault("RealmID", 1)); +#endif + return 1; + } + + /** + * Returns emulator version + * + * - For TrinityCore returns the date of the last revision, e.g. `2015-08-26 22:53:12 +0300` + * - For cMaNGOS returns the date and time of the last revision, e.g. `2015-09-06 13:18:50` + * - for MaNGOS returns the version number as string, e.g. `21000` + * + * @return string version + */ + int GetCoreVersion(lua_State* L) + { + Eluna::Push(L, CORE_VERSION); + return 1; + } + + /** + * Returns emulator's supported expansion. + * + * Expansion is 0 for pre-TBC, 1 for TBC, 2 for WotLK, and 3 for Cataclysm. + * + * @return int32 expansion + */ + int GetCoreExpansion(lua_State* L) + { +#ifdef CLASSIC + Eluna::Push(L, 0); +#elif defined(TBC) + Eluna::Push(L, 1); +#elif defined(WOTLK) + Eluna::Push(L, 2); +#elif defined(CATA) + Eluna::Push(L, 3); +#endif + return 1; + } + + /** + * Returns [Quest] template + * + * @param uint32 questId : [Quest] entry ID + * @return [Quest] quest + */ + int GetQuest(lua_State* L) + { + uint32 questId = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, eObjectMgr->GetQuestTemplate(questId)); + return 1; + } + + /** + * Finds and Returns [Player] by guid if found + * + * @param ObjectGuid guid : guid of the [Player], you can get it with [Object:GetGUID] + * @return [Player] player + */ + int GetPlayerByGUID(lua_State* L) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, eObjectAccessor()FindPlayer(guid)); + return 1; + } + + /** + * Finds and Returns [Player] by name if found + * + * @param string name : name of the [Player] + * @return [Player] player + */ + int GetPlayerByName(lua_State* L) + { + const char* name = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, eObjectAccessor()FindPlayerByName(name)); + return 1; + } + + /** + * Returns game time in seconds + * + * @return uint32 time + */ + int GetGameTime(lua_State* L) + { +#ifdef TRINITY + Eluna::Push(L, GameTime::GetGameTime()); +#elif AZEROTHCORE + Eluna::Push(L, GameTime::GetGameTime().count()); +#else + Eluna::Push(L, eWorld->GetGameTime()); +#endif + return 1; + } + + /** + * Returns a table with all the current [Player]s in the world + * + * Does not return players that may be teleporting or otherwise not on any map. + * + * enum TeamId + * { + * TEAM_ALLIANCE = 0, + * TEAM_HORDE = 1, + * TEAM_NEUTRAL = 2 + * }; + * + * @param [TeamId] team = TEAM_NEUTRAL : optional check team of the [Player], Alliance, Horde or Neutral (All) + * @param bool onlyGM = false : optional check if GM only + * @return table worldPlayers + */ + int GetPlayersInWorld(lua_State* L) + { + uint32 team = Eluna::CHECKVAL(L, 1, TEAM_NEUTRAL); + bool onlyGM = Eluna::CHECKVAL(L, 2, false); + + lua_newtable(L); + int tbl = lua_gettop(L); + uint32 i = 0; + +#if defined(MANGOS) + eObjectAccessor()DoForAllPlayers([&](Player* player){ + if(player->IsInWorld()) + { + if ((team == TEAM_NEUTRAL || player->GetTeamId() == team) && (!onlyGM || player->isGameMaster())) + { + Eluna::Push(L, player); + lua_rawseti(L, tbl, ++i); + } + } + }); +#else + { +#if defined TRINITY || AZEROTHCORE + std::shared_lock lock(*HashMapHolder::GetLock()); +#else + HashMapHolder::ReadGuard g(HashMapHolder::GetLock()); +#endif + const HashMapHolder::MapType& m = eObjectAccessor()GetPlayers(); + for (HashMapHolder::MapType::const_iterator it = m.begin(); it != m.end(); ++it) + { + if (Player* player = it->second) + { + if (!player->IsInWorld()) + continue; +#if defined TRINITY || AZEROTHCORE + if ((team == TEAM_NEUTRAL || player->GetTeamId() == team) && (!onlyGM || player->IsGameMaster())) +#else + if ((team == TEAM_NEUTRAL || player->GetTeamId() == team) && (!onlyGM || player->isGameMaster())) +#endif + { + Eluna::Push(L, player); + lua_rawseti(L, tbl, ++i); + } + } + } + } +#endif + lua_settop(L, tbl); // push table to top of stack + return 1; + } + + /** + * Returns a [Guild] by name. + * + * @param string name + * @return [Guild] guild : the Guild, or `nil` if it doesn't exist + */ + int GetGuildByName(lua_State* L) + { + const char* name = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, eGuildMgr->GetGuildByName(name)); + return 1; + } + + /** + * Returns a [Map] by ID. + * + * @param uint32 mapId : see [Map.dbc](https://github.com/cmangos/issues/wiki/Map.dbc) + * @param uint32 instanceId = 0 : required if the map is an instance, otherwise don't pass anything + * @return [Map] map : the Map, or `nil` if it doesn't exist + */ + int GetMapById(lua_State* L) + { + uint32 mapid = Eluna::CHECKVAL(L, 1); + uint32 instance = Eluna::CHECKVAL(L, 2, 0); + + Eluna::Push(L, eMapMgr->FindMap(mapid, instance)); + return 1; + } + + /** + * Returns [Guild] by the leader's GUID + * + * @param ObjectGuid guid : the guid of a [Guild] leader + * @return [Guild] guild, or `nil` if it doesn't exist + */ + int GetGuildByLeaderGUID(lua_State* L) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, eGuildMgr->GetGuildByLeader(guid)); + return 1; + } + + /** + * Returns the amount of [Player]s in the world. + * + * @return uint32 count + */ + int GetPlayerCount(lua_State* L) + { + Eluna::Push(L, eWorld->GetActiveSessionCount()); + return 1; + } + + /** + * Builds a [Player]'s GUID + * + * [Player] GUID consist of low GUID and type ID + * + * [Player] and [Creature] for example can have the same low GUID but not GUID. + * + * @param uint32 lowguid : low GUID of the [Player] + * @return ObjectGuid guid + */ + int GetPlayerGUID(lua_State* L) + { + uint32 lowguid = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER)); + return 1; + } + + /** + * Builds an [Item]'s GUID. + * + * [Item] GUID consist of low GUID and type ID + * [Player] and [Item] for example can have the same low GUID but not GUID. + * + * @param uint32 lowguid : low GUID of the [Item] + * @return ObjectGuid guid + */ + int GetItemGUID(lua_State* L) + { + uint32 lowguid = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, MAKE_NEW_GUID(lowguid, 0, HIGHGUID_ITEM)); + return 1; + } + + int GetItemTemplate(lua_State* L) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, eObjectMgr->GetItemTemplate(entry)); + return 1; + } + + /** + * Builds a [GameObject]'s GUID. + * + * A GameObject's GUID consist of entry ID, low GUID and type ID + * + * A [Player] and GameObject for example can have the same low GUID but not GUID. + * + * @param uint32 lowguid : low GUID of the [GameObject] + * @param uint32 entry : entry ID of the [GameObject] + * @return ObjectGuid guid + */ + int GetObjectGUID(lua_State* L) + { + uint32 lowguid = Eluna::CHECKVAL(L, 1); + uint32 entry = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT)); + return 1; + } + + /** + * Builds a [Creature]'s GUID. + * + * [Creature] GUID consist of entry ID, low GUID and type ID + * + * [Player] and [Creature] for example can have the same low GUID but not GUID. + * + * @param uint32 lowguid : low GUID of the [Creature] + * @param uint32 entry : entry ID of the [Creature] + * @return ObjectGuid guid + */ + int GetUnitGUID(lua_State* L) + { + uint32 lowguid = Eluna::CHECKVAL(L, 1); + uint32 entry = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, MAKE_NEW_GUID(lowguid, entry, HIGHGUID_UNIT)); + return 1; + } + + /** + * Returns the low GUID from a GUID. + * + * A GUID consists of a low GUID, type ID, and possibly an entry ID depending on the type ID. + * + * Low GUID is an ID to distinct the objects of the same type. + * + * [Player] and [Creature] for example can have the same low GUID but not GUID. + * + * On TrinityCore all low GUIDs are different for all objects of the same type. + * For example creatures in instances are assigned new GUIDs when the Map is created. + * + * On MaNGOS and cMaNGOS low GUIDs are unique only on the same map. + * For example creatures in instances use the same low GUID assigned for that spawn in the database. + * This is why to identify a creature you have to know the instanceId and low GUID. See [Map:GetIntstanceId] + * + * @param ObjectGuid guid : GUID of an [Object] + * @return uint32 lowguid : low GUID of the [Object] + */ + int GetGUIDLow(lua_State* L) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, guid.GetCounter()); + return 1; + } + + /** + * Returns an chat link for an [Item]. + * + * enum LocaleConstant + * { + * LOCALE_enUS = 0, + * LOCALE_koKR = 1, + * LOCALE_frFR = 2, + * LOCALE_deDE = 3, + * LOCALE_zhCN = 4, + * LOCALE_zhTW = 5, + * LOCALE_esES = 6, + * LOCALE_esMX = 7, + * LOCALE_ruRU = 8 + * }; + * + * @param uint32 entry : entry ID of an [Item] + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Item] name in + * @return string itemLink + */ + int GetItemLink(lua_State* L) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + + const ItemTemplate* temp = eObjectMgr->GetItemTemplate(entry); + if (!temp) + return luaL_argerror(L, 1, "valid ItemEntry expected"); + + std::string name = temp->Name1; + if (ItemLocale const* il = eObjectMgr->GetItemLocale(entry)) + ObjectMgr::GetLocaleString(il->Name, static_cast(locale), name); + + std::ostringstream oss; + oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec << + "|Hitem:" << entry << ":0:" << +#ifndef CLASSIC + "0:0:0:0:" << +#endif + "0:0:0:0|h[" << name << "]|h|r"; + + Eluna::Push(L, oss.str()); + return 1; + } + + /** + * Returns the type ID from a GUID. + * + * Type ID is different for each type ([Player], [Creature], [GameObject], etc.). + * + * GUID consist of entry ID, low GUID, and type ID. + * + * @param ObjectGuid guid : GUID of an [Object] + * @return int32 typeId : type ID of the [Object] + */ + int GetGUIDType(lua_State* L) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, static_cast(guid.GetHigh())); + return 1; + } + + /** + * Returns the entry ID from a GUID. + * + * GUID consist of entry ID, low GUID, and type ID. + * + * @param ObjectGuid guid : GUID of an [Creature] or [GameObject] + * @return uint32 entry : entry ID, or `0` if `guid` is not a [Creature] or [GameObject] + */ + int GetGUIDEntry(lua_State* L) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, guid.GetEntry()); + return 1; + } + + /** + * Returns the area or zone's name. + * + * enum LocaleConstant + * { + * LOCALE_enUS = 0, + * LOCALE_koKR = 1, + * LOCALE_frFR = 2, + * LOCALE_deDE = 3, + * LOCALE_zhCN = 4, + * LOCALE_zhTW = 5, + * LOCALE_esES = 6, + * LOCALE_esMX = 7, + * LOCALE_ruRU = 8 + * }; + * + * @param uint32 areaOrZoneId : area ID or zone ID + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the name in + * @return string areaOrZoneName + */ + int GetAreaName(lua_State* L) + { + uint32 areaOrZoneId = Eluna::CHECKVAL(L, 1); + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + +#if defined TRINITY || AZEROTHCORE + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaOrZoneId); +#else + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaOrZoneId); +#endif + if (!areaEntry) + return luaL_argerror(L, 1, "valid Area or Zone ID expected"); + +#if defined(TRINITY) + Eluna::Push(L, areaEntry->AreaName[locale]); +#else + Eluna::Push(L, areaEntry->area_name[locale]); +#endif + return 1; + } + + /** + * Returns the currently active game events. + * + * @return table activeEvents + */ + int GetActiveGameEvents(lua_State* L) + { + lua_newtable(L); + int tbl = lua_gettop(L); + uint32 counter = 1; + GameEventMgr::ActiveEvents const& activeEvents = eGameEventMgr->GetActiveEventList(); + + for (GameEventMgr::ActiveEvents::const_iterator i = activeEvents.begin(); i != activeEvents.end(); ++i) + { + Eluna::Push(L, *i); + lua_rawseti(L, tbl, counter); + + counter++; + } + + lua_settop(L, tbl); + return 1; + } + + static int RegisterEntryHelper(lua_State* L, int regtype) + { + uint32 id = Eluna::CHECKVAL(L, 1); + uint32 ev = Eluna::CHECKVAL(L, 2); + luaL_checktype(L, 3, LUA_TFUNCTION); + uint32 shots = Eluna::CHECKVAL(L, 4, 0); + + lua_pushvalue(L, 3); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef >= 0) + return Eluna::GetEluna(L)->Register(L, regtype, id, ObjectGuid(), 0, ev, functionRef, shots); + else + luaL_argerror(L, 3, "unable to make a ref to function"); + return 0; + } + + static int RegisterEventHelper(lua_State* L, int regtype) + { + uint32 ev = Eluna::CHECKVAL(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + uint32 shots = Eluna::CHECKVAL(L, 3, 0); + + lua_pushvalue(L, 2); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef >= 0) + return Eluna::GetEluna(L)->Register(L, regtype, 0, ObjectGuid(), 0, ev, functionRef, shots); + else + luaL_argerror(L, 2, "unable to make a ref to function"); + return 0; + } + + static int RegisterUniqueHelper(lua_State* L, int regtype) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + uint32 instanceId = Eluna::CHECKVAL(L, 2); + uint32 ev = Eluna::CHECKVAL(L, 3); + luaL_checktype(L, 4, LUA_TFUNCTION); + uint32 shots = Eluna::CHECKVAL(L, 5, 0); + + lua_pushvalue(L, 4); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef >= 0) + return Eluna::GetEluna(L)->Register(L, regtype, 0, guid, instanceId, ev, functionRef, shots); + else + luaL_argerror(L, 4, "unable to make a ref to function"); + return 0; + } + + /** + * Registers a server event handler. + * + * enum ServerEvents + * { + * // Server + * SERVER_EVENT_ON_NETWORK_START = 1, // Not Implemented + * SERVER_EVENT_ON_NETWORK_STOP = 2, // Not Implemented + * SERVER_EVENT_ON_SOCKET_OPEN = 3, // Not Implemented + * SERVER_EVENT_ON_SOCKET_CLOSE = 4, // Not Implemented + * SERVER_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket + * SERVER_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented + * SERVER_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false, newPacket + * + * // World + * WORLD_EVENT_ON_OPEN_STATE_CHANGE = 8, // (event, open) - Needs core support on Mangos + * WORLD_EVENT_ON_CONFIG_LOAD = 9, // (event, reload) + * // UNUSED = 10, + * WORLD_EVENT_ON_SHUTDOWN_INIT = 11, // (event, code, mask) + * WORLD_EVENT_ON_SHUTDOWN_CANCEL = 12, // (event) + * WORLD_EVENT_ON_UPDATE = 13, // (event, diff) + * WORLD_EVENT_ON_STARTUP = 14, // (event) + * WORLD_EVENT_ON_SHUTDOWN = 15, // (event) + * + * // Eluna + * ELUNA_EVENT_ON_LUA_STATE_CLOSE = 16, // (event) - triggers just before shutting down eluna (on shutdown and restart) + * + * // Map + * MAP_EVENT_ON_CREATE = 17, // (event, map) + * MAP_EVENT_ON_DESTROY = 18, // (event, map) + * MAP_EVENT_ON_GRID_LOAD = 19, // Not Implemented + * MAP_EVENT_ON_GRID_UNLOAD = 20, // Not Implemented + * MAP_EVENT_ON_PLAYER_ENTER = 21, // (event, map, player) + * MAP_EVENT_ON_PLAYER_LEAVE = 22, // (event, map, player) + * MAP_EVENT_ON_UPDATE = 23, // (event, map, diff) + * + * // Area trigger + * TRIGGER_EVENT_ON_TRIGGER = 24, // (event, player, triggerId) - Can return true + * + * // Weather + * WEATHER_EVENT_ON_CHANGE = 25, // (event, zoneId, state, grade) + * + * // Auction house + * AUCTION_EVENT_ON_ADD = 26, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + * AUCTION_EVENT_ON_REMOVE = 27, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + * AUCTION_EVENT_ON_SUCCESSFUL = 28, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + * AUCTION_EVENT_ON_EXPIRE = 29, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + * + * // AddOns + * ADDON_EVENT_ON_MESSAGE = 30, // (event, sender, type, prefix, msg, target) - target can be nil/whisper_target/guild/group/channel. Can return false + * + * WORLD_EVENT_ON_DELETE_CREATURE = 31, // (event, creature) + * WORLD_EVENT_ON_DELETE_GAMEOBJECT = 32, // (event, gameobject) + * + * // Eluna + * ELUNA_EVENT_ON_LUA_STATE_OPEN = 33, // (event) - triggers after all scripts are loaded + * + * GAME_EVENT_START = 34, // (event, gameeventid) + * GAME_EVENT_STOP = 35, // (event, gameeventid) + * }; + * + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) + * + * @param uint32 event : server event ID, refer to ServerEvents above + * @param function function : function that will be called when the event occurs + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterServerEvent(lua_State* L) + { + return RegisterEventHelper(L, Hooks::REGTYPE_SERVER); + } + + /** + * Registers a [Player] event handler. + * + *
+     * enum PlayerEvents
+     * {
+     *     PLAYER_EVENT_ON_CHARACTER_CREATE        =     1,        // (event, player)
+     *     PLAYER_EVENT_ON_CHARACTER_DELETE        =     2,        // (event, guid)
+     *     PLAYER_EVENT_ON_LOGIN                   =     3,        // (event, player)
+     *     PLAYER_EVENT_ON_LOGOUT                  =     4,        // (event, player)
+     *     PLAYER_EVENT_ON_SPELL_CAST              =     5,        // (event, player, spell, skipCheck)
+     *     PLAYER_EVENT_ON_KILL_PLAYER             =     6,        // (event, killer, killed)
+     *     PLAYER_EVENT_ON_KILL_CREATURE           =     7,        // (event, killer, killed)
+     *     PLAYER_EVENT_ON_KILLED_BY_CREATURE      =     8,        // (event, killer, killed)
+     *     PLAYER_EVENT_ON_DUEL_REQUEST            =     9,        // (event, target, challenger)
+     *     PLAYER_EVENT_ON_DUEL_START              =     10,       // (event, player1, player2)
+     *     PLAYER_EVENT_ON_DUEL_END                =     11,       // (event, winner, loser, type)
+     *     PLAYER_EVENT_ON_GIVE_XP                 =     12,       // (event, player, amount, victim, source) - Can return new XP amount
+     *     PLAYER_EVENT_ON_LEVEL_CHANGE            =     13,       // (event, player, oldLevel)
+     *     PLAYER_EVENT_ON_MONEY_CHANGE            =     14,       // (event, player, amount) - Can return new money amount
+     *     PLAYER_EVENT_ON_REPUTATION_CHANGE       =     15,       // (event, player, factionId, standing, incremental) - Can return new standing -> if standing == -1, it will prevent default action (rep gain)
+     *     PLAYER_EVENT_ON_TALENTS_CHANGE          =     16,       // (event, player, points)
+     *     PLAYER_EVENT_ON_TALENTS_RESET           =     17,       // (event, player, noCost)
+     *     PLAYER_EVENT_ON_CHAT                    =     18,       // (event, player, msg, Type, lang) - Can return false, newMessage
+     *     PLAYER_EVENT_ON_WHISPER                 =     19,       // (event, player, msg, Type, lang, receiver) - Can return false, newMessage
+     *     PLAYER_EVENT_ON_GROUP_CHAT              =     20,       // (event, player, msg, Type, lang, group) - Can return false, newMessage
+     *     PLAYER_EVENT_ON_GUILD_CHAT              =     21,       // (event, player, msg, Type, lang, guild) - Can return false, newMessage
+     *     PLAYER_EVENT_ON_CHANNEL_CHAT            =     22,       // (event, player, msg, Type, lang, channel) - channel is negative for custom channels. Can return false, newMessage
+     *     PLAYER_EVENT_ON_EMOTE                   =     23,       // (event, player, emote) - Not triggered on any known emote
+     *     PLAYER_EVENT_ON_TEXT_EMOTE              =     24,       // (event, player, textEmote, emoteNum, guid)
+     *     PLAYER_EVENT_ON_SAVE                    =     25,       // (event, player)
+     *     PLAYER_EVENT_ON_BIND_TO_INSTANCE        =     26,       // (event, player, difficulty, mapid, permanent)
+     *     PLAYER_EVENT_ON_UPDATE_ZONE             =     27,       // (event, player, newZone, newArea)
+     *     PLAYER_EVENT_ON_MAP_CHANGE              =     28,       // (event, player)
+     *
+     *     // Custom
+     *     PLAYER_EVENT_ON_EQUIP                   =     29,       // (event, player, item, bag, slot)
+     *     PLAYER_EVENT_ON_FIRST_LOGIN             =     30,       // (event, player)
+     *     PLAYER_EVENT_ON_CAN_USE_ITEM            =     31,       // (event, player, itemEntry) - Can return InventoryResult enum value
+     *     PLAYER_EVENT_ON_LOOT_ITEM               =     32,       // (event, player, item, count)
+     *     PLAYER_EVENT_ON_ENTER_COMBAT            =     33,       // (event, player, enemy)
+     *     PLAYER_EVENT_ON_LEAVE_COMBAT            =     34,       // (event, player)
+     *     PLAYER_EVENT_ON_REPOP                   =     35,       // (event, player)
+     *     PLAYER_EVENT_ON_RESURRECT               =     36,       // (event, player)
+     *     PLAYER_EVENT_ON_LOOT_MONEY              =     37,       // (event, player, amount)
+     *     PLAYER_EVENT_ON_QUEST_ABANDON           =     38,       // (event, player, questId)
+     *     PLAYER_EVENT_ON_LEARN_TALENTS           =     39,       // (event, player, talentId, talentRank, spellid)
+     *     // UNUSED                               =     40,       // (event, player)
+     *     // UNUSED                               =     41,       // (event, player)
+     *     PLAYER_EVENT_ON_COMMAND                 =     42,       // (event, player, command, chatHandler) - player is nil if command used from console. Can return false
+     *     PLAYER_EVENT_ON_PET_ADDED_TO_WORLD      =     43,       // (event, player, pet)
+     *     PLAYER_EVENT_ON_LEARN_SPELL             =     44,       // (event, player, spellId)
+     *     PLAYER_EVENT_ON_ACHIEVEMENT_COMPLETE    =     45,       // (event, player, achievement)
+     *     PLAYER_EVENT_ON_FFAPVP_CHANGE           =     46,       // (event, player, hasFfaPvp)
+     *     PLAYER_EVENT_ON_UPDATE_AREA             =     47,       // (event, player, oldArea, newArea)
+     *     PLAYER_EVENT_ON_CAN_INIT_TRADE          =     48,       // (event, player, target) - Can return false to prevent the trade
+     *     PLAYER_EVENT_ON_CAN_SEND_MAIL           =     49,       // (event, player, receiverGuid, mailbox, subject, body, money, cod, item) - Can return false to prevent sending the mail
+     *     PLAYER_EVENT_ON_CAN_JOIN_LFG            =     50,       // (event, player, roles, dungeons, comment) - Can return false to prevent queueing
+     *     PLAYER_EVENT_ON_QUEST_REWARD_ITEM       =     51,       //  (event, player, item, count)
+     *     PLAYER_EVENT_ON_CREATE_ITEM             =     52,       //  (event, player, item, count)
+     *     PLAYER_EVENT_ON_STORE_NEW_ITEM          =     53,       //  (event, player, item, count)
+     *     PLAYER_EVENT_ON_COMPLETE_QUEST          =     54,       // (event, player, quest)
+     *     PLAYER_EVENT_ON_CAN_GROUP_INVITE        =     55,       // (event, player, memberName) - Can return false to prevent inviting
+     *     PLAYER_EVENT_ON_GROUP_ROLL_REWARD_ITEM  =     56,       // (event, player, item, count, voteType, roll)
+     *     PLAYER_EVENT_ON_BG_DESERTION            =     57,       // (event, player, type)
+     * };
+     * 
+ * + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) + * + * @param uint32 event : [Player] event Id, refer to PlayerEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterPlayerEvent(lua_State* L) + { + return RegisterEventHelper(L, Hooks::REGTYPE_PLAYER); + } + + /** + * Registers a [Guild] event handler. + * + *
+     * enum GuildEvents
+     * {
+     *     // Guild
+     *     GUILD_EVENT_ON_ADD_MEMBER               =     1,       // (event, guild, player, rank)
+     *     GUILD_EVENT_ON_REMOVE_MEMBER            =     2,       // (event, guild, player, isDisbanding)
+     *     GUILD_EVENT_ON_MOTD_CHANGE              =     3,       // (event, guild, newMotd)
+     *     GUILD_EVENT_ON_INFO_CHANGE              =     4,       // (event, guild, newInfo)
+     *     GUILD_EVENT_ON_CREATE                   =     5,       // (event, guild, leader, name)  // Not on TC
+     *     GUILD_EVENT_ON_DISBAND                  =     6,       // (event, guild)
+     *     GUILD_EVENT_ON_MONEY_WITHDRAW           =     7,       // (event, guild, player, amount, isRepair) - Can return new money amount
+     *     GUILD_EVENT_ON_MONEY_DEPOSIT            =     8,       // (event, guild, player, amount) - Can return new money amount
+     *     GUILD_EVENT_ON_ITEM_MOVE                =     9,       // (event, guild, player, item, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId)   // TODO
+     *     GUILD_EVENT_ON_EVENT                    =     10,      // (event, guild, eventType, plrGUIDLow1, plrGUIDLow2, newRank)  // TODO
+     *     GUILD_EVENT_ON_BANK_EVENT               =     11,      // (event, guild, eventType, tabId, playerGUIDLow, itemOrMoney, itemStackCount, destTabId)
+     *
+     *     GUILD_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) + * + * @param uint32 event : [Guild] event Id, refer to GuildEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterGuildEvent(lua_State* L) + { + return RegisterEventHelper(L, Hooks::REGTYPE_GUILD); + } + + /** + * Registers a [Group] event handler. + * + *
+     * enum GroupEvents
+     * {
+     *     // Group
+     *     GROUP_EVENT_ON_MEMBER_ADD               =     1,       // (event, group, guid)
+     *     GROUP_EVENT_ON_MEMBER_INVITE            =     2,       // (event, group, guid)
+     *     GROUP_EVENT_ON_MEMBER_REMOVE            =     3,       // (event, group, guid, method, kicker, reason)
+     *     GROUP_EVENT_ON_LEADER_CHANGE            =     4,       // (event, group, newLeaderGuid, oldLeaderGuid)
+     *     GROUP_EVENT_ON_DISBAND                  =     5,       // (event, group)
+     *     GROUP_EVENT_ON_CREATE                   =     6,       // (event, group, leaderGuid, groupType)
+     *
+     *     GROUP_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) + * + * @param uint32 event : [Group] event Id, refer to GroupEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterGroupEvent(lua_State* L) + { + return RegisterEventHelper(L, Hooks::REGTYPE_GROUP); + } + + /** + * Registers a [BattleGround] event handler. + * + *
+     * enum BGEvents
+     * {
+     *     BG_EVENT_ON_START                               = 1,    // (event, bg, bgId, instanceId) - Needs to be added to TC
+     *     BG_EVENT_ON_END                                 = 2,    // (event, bg, bgId, instanceId, winner) - Needs to be added to TC
+     *     BG_EVENT_ON_CREATE                              = 3,    // (event, bg, bgId, instanceId) - Needs to be added to TC
+     *     BG_EVENT_ON_PRE_DESTROY                         = 4,    // (event, bg, bgId, instanceId) - Needs to be added to TC
+     *     BG_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (event, function) + * @proto cancel = (event, function, shots) + * + * @param uint32 event : [BattleGround] event Id, refer to BGEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterBGEvent(lua_State* L) + { + return RegisterEventHelper(L, Hooks::REGTYPE_BG); + } + + /** + * Registers a [WorldPacket] event handler. + * + *
+     * enum PacketEvents
+     * {
+     *     PACKET_EVENT_ON_PACKET_RECEIVE          =     5,       // (event, packet, player) - Player only if accessible. Can return false, newPacket
+     *     PACKET_EVENT_ON_PACKET_RECEIVE_UNKNOWN  =     6,       // Not Implemented
+     *     PACKET_EVENT_ON_PACKET_SEND             =     7,       // (event, packet, player) - Player only if accessible. Can return false, newPacket
+     *
+     *     PACKET_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : opcode + * @param uint32 event : packet event Id, refer to PacketEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterPacketEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_PACKET); + } + + /** + * Registers a [Creature] gossip event handler. + * + *
+     * enum GossipEvents
+     * {
+     *     GOSSIP_EVENT_ON_HELLO                           = 1,    // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting.
+     *     GOSSIP_EVENT_ON_SELECT                          = 2,    // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action.
+     *     GOSSIP_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : [Creature] entry Id + * @param uint32 event : [Creature] gossip event Id, refer to GossipEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterCreatureGossipEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_CREATURE_GOSSIP); + } + + /** + * Registers a [GameObject] gossip event handler. + * + *
+     * enum GossipEvents
+     * {
+     *     GOSSIP_EVENT_ON_HELLO                           = 1,    // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting.
+     *     GOSSIP_EVENT_ON_SELECT                          = 2,    // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action.
+     *     GOSSIP_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : [GameObject] entry Id + * @param uint32 event : [GameObject] gossip event Id, refer to GossipEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterGameObjectGossipEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_GAMEOBJECT_GOSSIP); + } + + /** + * Registers an [Item] event handler. + * + *
+     * enum ItemEvents
+     * {
+     *     ITEM_EVENT_ON_DUMMY_EFFECT                      = 1,    // (event, caster, spellid, effindex, item)
+     *     ITEM_EVENT_ON_USE                               = 2,    // (event, player, item, target) - Can return false to stop the spell casting
+     *     ITEM_EVENT_ON_QUEST_ACCEPT                      = 3,    // (event, player, item, quest) - Can return true
+     *     ITEM_EVENT_ON_EXPIRE                            = 4,    // (event, player, itemid) - Can return true
+     *     ITEM_EVENT_ON_REMOVE                            = 5,    // (event, player, item) - Can return true
+     *     ITEM_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : [Item] entry Id + * @param uint32 event : [Item] event Id, refer to ItemEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterItemEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_ITEM); + } + + /** + * Registers an [Item] gossip event handler. + * + *
+     * enum GossipEvents
+     * {
+     *     GOSSIP_EVENT_ON_HELLO                           = 1,    // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting.
+     *     GOSSIP_EVENT_ON_SELECT                          = 2,    // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action.
+     *     GOSSIP_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : [Item] entry Id + * @param uint32 event : [Item] gossip event Id, refer to GossipEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterItemGossipEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_ITEM_GOSSIP); + } + + /** + * Registers a [Map] event handler for all instance of a [Map]. + * + *
+     * enum InstanceEvents
+     * {
+     *     INSTANCE_EVENT_ON_INITIALIZE                    = 1,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_ON_LOAD                          = 2,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_ON_UPDATE                        = 3,    // (event, instance_data, map, diff)
+     *     INSTANCE_EVENT_ON_PLAYER_ENTER                  = 4,    // (event, instance_data, map, player)
+     *     INSTANCE_EVENT_ON_CREATURE_CREATE               = 5,    // (event, instance_data, map, creature)
+     *     INSTANCE_EVENT_ON_GAMEOBJECT_CREATE             = 6,    // (event, instance_data, map, go)
+     *     INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS   = 7,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_COUNT
+     * };
+     * 
+ * + * @param uint32 map_id : ID of a [Map] + * @param uint32 event : [Map] event ID, refer to MapEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + */ + int RegisterMapEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_MAP); + } + + /** + * Registers a [Map] event handler for one instance of a [Map]. + * + *
+     * enum InstanceEvents
+     * {
+     *     INSTANCE_EVENT_ON_INITIALIZE                    = 1,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_ON_LOAD                          = 2,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_ON_UPDATE                        = 3,    // (event, instance_data, map, diff)
+     *     INSTANCE_EVENT_ON_PLAYER_ENTER                  = 4,    // (event, instance_data, map, player)
+     *     INSTANCE_EVENT_ON_CREATURE_CREATE               = 5,    // (event, instance_data, map, creature)
+     *     INSTANCE_EVENT_ON_GAMEOBJECT_CREATE             = 6,    // (event, instance_data, map, go)
+     *     INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS   = 7,    // (event, instance_data, map)
+     *     INSTANCE_EVENT_COUNT
+     * };
+     * 
+ * + * @param uint32 instance_id : ID of an instance of a [Map] + * @param uint32 event : [Map] event ID, refer to MapEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + */ + int RegisterInstanceEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_INSTANCE); + } + + /** + * Registers a [Player] gossip event handler. + * + * Note that you can not use `GOSSIP_EVENT_ON_HELLO` with this hook. It does nothing since players dont have an "on hello". + * + *
+     * enum GossipEvents
+     * {
+     *     GOSSIP_EVENT_ON_HELLO                           = 1,    // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting.
+     *     GOSSIP_EVENT_ON_SELECT                          = 2,    // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action.
+     *     GOSSIP_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (menu_id, event, function) + * @proto cancel = (menu_id, event, function, shots) + * + * @param uint32 menu_id : [Player] gossip menu Id + * @param uint32 event : [Player] gossip event Id, refer to GossipEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterPlayerGossipEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_PLAYER_GOSSIP); + } + + /** + * Registers a [Creature] event handler. + * + *
+     * enum CreatureEvents
+     * {
+     *     CREATURE_EVENT_ON_ENTER_COMBAT                    = 1,  // (event, creature, target) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_LEAVE_COMBAT                    = 2,  // (event, creature) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_TARGET_DIED                     = 3,  // (event, creature, victim) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_DIED                            = 4,  // (event, creature, killer) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SPAWN                           = 5,  // (event, creature) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_REACH_WP                        = 6,  // (event, creature, type, id) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_AIUPDATE                        = 7,  // (event, creature, diff) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_RECEIVE_EMOTE                   = 8,  // (event, creature, player, emoteid) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_DAMAGE_TAKEN                    = 9,  // (event, creature, attacker, damage) - Can return true to stop normal action, can return new damage as second return value.
+     *     CREATURE_EVENT_ON_PRE_COMBAT                      = 10, // (event, creature, target) - Can return true to stop normal action
+     *     // UNUSED
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED                  = 12, // (event, creature, target) - Can return true to stop normal action            // Not on mangos
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED_AT               = 13, // (event, creature, attacker) - Can return true to stop normal action          // Not on mangos
+     *     CREATURE_EVENT_ON_HIT_BY_SPELL                    = 14, // (event, creature, caster, spellid) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SPELL_HIT_TARGET                = 15, // (event, creature, target, spellid) - Can return true to stop normal action
+     *     // UNUSED                                         = 16, // (event, creature)
+     *     // UNUSED                                         = 17, // (event, creature)
+     *     // UNUSED                                         = 18, // (event, creature)
+     *     CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE          = 19, // (event, creature, summon) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN       = 20, // (event, creature, summon) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED          = 21, // (event, creature, summon, killer) - Can return true to stop normal action    // Not on mangos
+     *     CREATURE_EVENT_ON_SUMMONED                        = 22, // (event, creature, summoner) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_RESET                           = 23, // (event, creature)
+     *     CREATURE_EVENT_ON_REACH_HOME                      = 24, // (event, creature) - Can return true to stop normal action
+     *     // UNUSED                                         = 25, // (event, creature)
+     *     CREATURE_EVENT_ON_CORPSE_REMOVED                  = 26, // (event, creature, respawndelay) - Can return true to stop normal action, can return new respawndelay as second return value
+     *     CREATURE_EVENT_ON_MOVE_IN_LOS                     = 27, // (event, creature, unit) - Can return true to stop normal action. Does not actually check LOS, just uses the sight range
+     *     // UNUSED                                         = 28, // (event, creature)
+     *     // UNUSED                                         = 29, // (event, creature)
+     *     CREATURE_EVENT_ON_DUMMY_EFFECT                    = 30, // (event, caster, spellid, effindex, creature)
+     *     CREATURE_EVENT_ON_QUEST_ACCEPT                    = 31, // (event, player, creature, quest) - Can return true
+     *     // UNUSED                                         = 32, // (event, creature)
+     *     // UNUSED                                         = 33, // (event, creature)
+     *     CREATURE_EVENT_ON_QUEST_REWARD                    = 34, // (event, player, creature, quest, opt) - Can return true
+     *     CREATURE_EVENT_ON_DIALOG_STATUS                   = 35, // (event, player, creature)
+     *     CREATURE_EVENT_ON_ADD                             = 36, // (event, creature)
+     *     CREATURE_EVENT_ON_REMOVE                          = 37, // (event, creature)
+     *     CREATURE_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : the ID of one or more [Creature]s + * @param uint32 event : refer to CreatureEvents above + * @param function function : function that will be called when the event occurs + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterCreatureEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_CREATURE); + } + + /** + * Registers a [Creature] event handler for a *single* [Creature]. + * + *
+     * enum CreatureEvents
+     * {
+     *     CREATURE_EVENT_ON_ENTER_COMBAT                    = 1,  // (event, creature, target) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_LEAVE_COMBAT                    = 2,  // (event, creature) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_TARGET_DIED                     = 3,  // (event, creature, victim) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_DIED                            = 4,  // (event, creature, killer) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SPAWN                           = 5,  // (event, creature) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_REACH_WP                        = 6,  // (event, creature, type, id) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_AIUPDATE                        = 7,  // (event, creature, diff) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_RECEIVE_EMOTE                   = 8,  // (event, creature, player, emoteid) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_DAMAGE_TAKEN                    = 9,  // (event, creature, attacker, damage) - Can return true to stop normal action, can return new damage as second return value.
+     *     CREATURE_EVENT_ON_PRE_COMBAT                      = 10, // (event, creature, target) - Can return true to stop normal action
+     *     // UNUSED
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED                  = 12, // (event, creature, target) - Can return true to stop normal action            // Not on mangos
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED_AT               = 13, // (event, creature, attacker) - Can return true to stop normal action          // Not on mangos
+     *     CREATURE_EVENT_ON_HIT_BY_SPELL                    = 14, // (event, creature, caster, spellid) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SPELL_HIT_TARGET                = 15, // (event, creature, target, spellid) - Can return true to stop normal action
+     *     // UNUSED                                         = 16, // (event, creature)
+     *     // UNUSED                                         = 17, // (event, creature)
+     *     // UNUSED                                         = 18, // (event, creature)
+     *     CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE          = 19, // (event, creature, summon) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN       = 20, // (event, creature, summon) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED          = 21, // (event, creature, summon, killer) - Can return true to stop normal action    // Not on mangos
+     *     CREATURE_EVENT_ON_SUMMONED                        = 22, // (event, creature, summoner) - Can return true to stop normal action
+     *     CREATURE_EVENT_ON_RESET                           = 23, // (event, creature)
+     *     CREATURE_EVENT_ON_REACH_HOME                      = 24, // (event, creature) - Can return true to stop normal action
+     *     // UNUSED                                         = 25, // (event, creature)
+     *     CREATURE_EVENT_ON_CORPSE_REMOVED                  = 26, // (event, creature, respawndelay) - Can return true to stop normal action, can return new respawndelay as second return value
+     *     CREATURE_EVENT_ON_MOVE_IN_LOS                     = 27, // (event, creature, unit) - Can return true to stop normal action. Does not actually check LOS, just uses the sight range
+     *     // UNUSED                                         = 28, // (event, creature)
+     *     // UNUSED                                         = 29, // (event, creature)
+     *     CREATURE_EVENT_ON_DUMMY_EFFECT                    = 30, // (event, caster, spellid, effindex, creature)
+     *     CREATURE_EVENT_ON_QUEST_ACCEPT                    = 31, // (event, player, creature, quest) - Can return true
+     *     // UNUSED                                         = 32, // (event, creature)
+     *     // UNUSED                                         = 33, // (event, creature)
+     *     CREATURE_EVENT_ON_QUEST_REWARD                    = 34, // (event, player, creature, quest, opt) - Can return true
+     *     CREATURE_EVENT_ON_DIALOG_STATUS                   = 35, // (event, player, creature)
+     *     CREATURE_EVENT_ON_ADD                             = 36, // (event, creature)
+     *     CREATURE_EVENT_ON_REMOVE                          = 37, // (event, creature)
+     *     CREATURE_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (guid, instance_id, event, function) + * @proto cancel = (guid, instance_id, event, function, shots) + * + * @param ObjectGuid guid : the GUID of a single [Creature] + * @param uint32 instance_id : the instance ID of a single [Creature] + * @param uint32 event : refer to CreatureEvents above + * @param function function : function that will be called when the event occurs + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterUniqueCreatureEvent(lua_State* L) + { + return RegisterUniqueHelper(L, Hooks::REGTYPE_CREATURE); + } + + /** + * Registers a [GameObject] event handler. + * + *
+     * enum GameObjectEvents
+     * {
+     *     GAMEOBJECT_EVENT_ON_AIUPDATE                    = 1,    // (event, go, diff)
+     *     GAMEOBJECT_EVENT_ON_SPAWN                       = 2,    // (event, go)
+     *     GAMEOBJECT_EVENT_ON_DUMMY_EFFECT                = 3,    // (event, caster, spellid, effindex, go) - Can return true to stop normal action
+     *     GAMEOBJECT_EVENT_ON_QUEST_ACCEPT                = 4,    // (event, player, go, quest) - Can return true to stop normal action
+     *     GAMEOBJECT_EVENT_ON_QUEST_REWARD                = 5,    // (event, player, go, quest, opt) - Can return true to stop normal action
+     *     GAMEOBJECT_EVENT_ON_DIALOG_STATUS               = 6,    // (event, player, go)
+     *     GAMEOBJECT_EVENT_ON_DESTROYED                   = 7,    // (event, go, attacker)
+     *     GAMEOBJECT_EVENT_ON_DAMAGED                     = 8,    // (event, go, attacker)
+     *     GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE           = 9,    // (event, go, state)
+     *     GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED            = 10,   // (event, go, state)
+     *     // UNUSED                                       = 11,   // (event, gameobject)
+     *     GAMEOBJECT_EVENT_ON_ADD                         = 12,   // (event, gameobject)
+     *     GAMEOBJECT_EVENT_ON_REMOVE                      = 13,   // (event, gameobject)
+     *     GAMEOBJECT_EVENT_ON_USE                         = 14,   // (event, go, player) - Can return true to stop normal action
+     *     GAMEOBJECT_EVENT_COUNT
+     * };
+     * 
+ * + * @proto cancel = (entry, event, function) + * @proto cancel = (entry, event, function, shots) + * + * @param uint32 entry : [GameObject] entry Id + * @param uint32 event : [GameObject] event Id, refer to GameObjectEvents above + * @param function function : function to register + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + * + * @return function cancel : a function that cancels the binding when called + */ + int RegisterGameObjectEvent(lua_State* L) + { + return RegisterEntryHelper(L, Hooks::REGTYPE_GAMEOBJECT); + } + + /** + * Reloads the Lua engine. + */ + int ReloadEluna(lua_State* /*L*/) + { + Eluna::ReloadEluna(); + return 0; + } + + /** + * Runs a command. + * + * @param string command : the command to run + */ + int RunCommand(lua_State* L) + { + const char* command = Eluna::CHECKVAL(L, 1); +#if defined TRINITY || AZEROTHCORE + eWorld->QueueCliCommand(new CliCommandHolder(nullptr, command, [](void*, std::string_view view) + { + std::string str = { view.begin(), view.end() }; + str.erase(std::find_if(str.rbegin(), str.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), str.end()); // Remove trailing spaces and line breaks + ELUNA_LOG_INFO("{}", str); + }, nullptr)); +#elif defined MANGOS + eWorld->QueueCliCommand(new CliCommandHolder(0, SEC_CONSOLE, nullptr, command, nullptr, nullptr)); +#endif + return 0; + } + + /** + * Sends a message to all [Player]s online. + * + * @param string message : message to send + */ + int SendWorldMessage(lua_State* L) + { + const char* message = Eluna::CHECKVAL(L, 1); + eWorld->SendServerMessage(SERVER_MSG_STRING, message); + return 0; + } + + template + static int DBQueryAsync(lua_State* L, DatabaseWorkerPool& db) + { + const char* query = Eluna::CHECKVAL(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushvalue(L, 2); + int funcRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (funcRef == LUA_REFNIL || funcRef == LUA_NOREF) + { + luaL_argerror(L, 2, "unable to make a ref to function"); + return 0; + } + + Eluna::GEluna->queryProcessor.AddCallback(db.AsyncQuery(query).WithCallback([L, funcRef](QueryResult result) + { + ElunaQuery* eq = result ? new ElunaQuery(result) : nullptr; + + LOCK_ELUNA; + + // Get function + lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef); + + // Push parameters + Eluna::Push(L, eq); + + // Call function + Eluna::GEluna->ExecuteCall(1, 0); + + luaL_unref(L, LUA_REGISTRYINDEX, funcRef); + })); + + return 0; + } + + /** + * Executes a SQL query on the world database and returns an [ElunaQuery]. + * + * The query is always executed synchronously + * (i.e. execution halts until the query has finished and then results are returned). + * If you need to execute the query asynchronously, use [Global:WorldDBQueryAsync] instead. + * + * local Q = WorldDBQuery("SELECT entry, name FROM creature_template LIMIT 10") + * if Q then + * repeat + * local entry, name = Q:GetUInt32(0), Q:GetString(1) + * print(entry, name) + * until not Q:NextRow() + * end + * + * @param string sql : query to execute + * @return [ElunaQuery] results or nil if no rows found or nil if no rows found + */ + int WorldDBQuery(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + +#if defined TRINITY || AZEROTHCORE + ElunaQuery result = WorldDatabase.Query(query); + if (result) + Eluna::Push(L, new ElunaQuery(result)); + else + Eluna::Push(L); +#else + ElunaQuery* result = WorldDatabase.QueryNamed(query); + if (result) + Eluna::Push(L, result); + else + Eluna::Push(L); +#endif + return 1; + } + + /** + * Executes an asynchronous SQL query on the world database and passes an [ElunaQuery] to a callback function. + * + * The query is executed asynchronously + * (i.e. the server keeps running while the query is executed in parallel, and results are passed to a callback function). + * If you need to execute the query synchronously, use [Global:WorldDBQuery] instead. + * + * WorldDBQueryAsync("SELECT entry, name FROM creature_template LIMIT 10", function(Q) + * if Q then + * repeat + * local entry, name = Q:GetUInt32(0), Q:GetString(1) + * print(entry, name) + * until not Q:NextRow() + * end + * end) + * + * @param string sql : query to execute + * @param function callback : function that will be called when the results are available + */ + int WorldDBQueryAsync(lua_State* L) + { + return DBQueryAsync(L, WorldDatabase); + } + + /** + * Executes a SQL query on the world database. + * + * The query may be executed *asynchronously* (at a later, unpredictable time). + * If you need to execute the query synchronously, use [Global:WorldDBQuery] instead. + * + * Any results produced are ignored. + * If you need results from the query, use [Global:WorldDBQuery] or [Global:WorldDBQueryAsync] instead. + * + * WorldDBExecute("DELETE FROM my_table") + * + * @param string sql : query to execute + */ + int WorldDBExecute(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + WorldDatabase.Execute(query); + return 0; + } + + /** + * Executes a SQL query on the character database and returns an [ElunaQuery]. + * + * The query is always executed synchronously + * (i.e. execution halts until the query has finished and then results are returned). + * If you need to execute the query asynchronously, use [Global:CharDBQueryAsync] instead. + * + * For an example see [Global:WorldDBQuery]. + * + * @param string sql : query to execute + * @return [ElunaQuery] results or nil if no rows found + */ + int CharDBQuery(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + +#if defined TRINITY || AZEROTHCORE + QueryResult result = CharacterDatabase.Query(query); + if (result) + Eluna::Push(L, new QueryResult(result)); + else + Eluna::Push(L); +#else + QueryNamedResult* result = CharacterDatabase.QueryNamed(query); + if (result) + Eluna::Push(L, result); + else + Eluna::Push(L); +#endif + return 1; + } + + /** + * Executes an asynchronous SQL query on the character database and passes an [ElunaQuery] to a callback function. + * + * The query is executed asynchronously + * (i.e. the server keeps running while the query is executed in parallel, and results are passed to a callback function). + * If you need to execute the query synchronously, use [Global:CharDBQuery] instead. + * + * For an example see [Global:WorldDBQueryAsync]. + * + * @param string sql : query to execute + * @param function callback : function that will be called when the results are available + */ + int CharDBQueryAsync(lua_State* L) + { + return DBQueryAsync(L, CharacterDatabase); + } + + /** + * Executes a SQL query on the character database. + * + * The query may be executed *asynchronously* (at a later, unpredictable time). + * If you need to execute the query synchronously, use [Global:CharDBQuery] instead. + * + * Any results produced are ignored. + * If you need results from the query, use [Global:CharDBQuery] or [Global:CharDBQueryAsync] instead. + * + * CharDBExecute("DELETE FROM my_table") + * + * @param string sql : query to execute + */ + int CharDBExecute(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + CharacterDatabase.Execute(query); + return 0; + } + + /** + * Executes a SQL query on the login database and returns an [ElunaQuery]. + * + * The query is always executed synchronously + * (i.e. execution halts until the query has finished and then results are returned). + * If you need to execute the query asynchronously, use [Global:AuthDBQueryAsync] instead. + * + * For an example see [Global:WorldDBQuery]. + * + * @param string sql : query to execute + * @return [ElunaQuery] results or nil if no rows found + */ + int AuthDBQuery(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + +#if defined TRINITY || AZEROTHCORE + QueryResult result = LoginDatabase.Query(query); + if (result) + Eluna::Push(L, new QueryResult(result)); + else + Eluna::Push(L); +#else + QueryNamedResult* result = LoginDatabase.QueryNamed(query); + if (result) + Eluna::Push(L, result); + else + Eluna::Push(L); +#endif + return 1; + } + + /** + * Executes an asynchronous SQL query on the character database and passes an [ElunaQuery] to a callback function. + * + * The query is executed asynchronously + * (i.e. the server keeps running while the query is executed in parallel, and results are passed to a callback function). + * If you need to execute the query synchronously, use [Global:AuthDBQuery] instead. + * + * For an example see [Global:WorldDBQueryAsync]. + * + * @param string sql : query to execute + * @param function callback : function that will be called when the results are available + */ + int AuthDBQueryAsync(lua_State* L) + { + return DBQueryAsync(L, LoginDatabase); + } + + /** + * Executes a SQL query on the login database. + * + * The query may be executed *asynchronously* (at a later, unpredictable time). + * If you need to execute the query synchronously, use [Global:AuthDBQuery] instead. + * + * Any results produced are ignored. + * If you need results from the query, use [Global:AuthDBQuery] or [Global:AuthDBQueryAsync] instead. + * + * AuthDBExecute("DELETE FROM my_table") + * + * @param string sql : query to execute + */ + int AuthDBExecute(lua_State* L) + { + const char* query = Eluna::CHECKVAL(L, 1); + LoginDatabase.Execute(query); + return 0; + } + + /** + * Registers a global timed event. + * + * When the passed function is called, the parameters `(eventId, delay, repeats)` are passed to it. + * + * Repeats will decrease on each call if the event does not repeat indefinitely + * + * @proto eventId = (function, delay) + * @proto eventId = (function, delaytable) + * @proto eventId = (function, delay, repeats) + * @proto eventId = (function, delaytable, repeats) + * + * @param function function : function to trigger when the time has passed + * @param uint32 delay : set time in milliseconds for the event to trigger + * @param table delaytable : a table `{min, max}` containing the minimum and maximum delay time + * @param uint32 repeats = 1 : how many times for the event to repeat, 0 is infinite + * @return int eventId : unique ID for the timed event used to cancel it or nil + */ + int CreateLuaEvent(lua_State* L) + { + luaL_checktype(L, 1, LUA_TFUNCTION); + uint32 min, max; + if (lua_istable(L, 2)) + { + Eluna::Push(L, 1); + lua_gettable(L, 2); + min = Eluna::CHECKVAL(L, -1); + Eluna::Push(L, 2); + lua_gettable(L, 2); + max = Eluna::CHECKVAL(L, -1); + lua_pop(L, 2); + } + else + min = max = Eluna::CHECKVAL(L, 2); + uint32 repeats = Eluna::CHECKVAL(L, 3, 1); + + if (min > max) + return luaL_argerror(L, 2, "min is bigger than max delay"); + + lua_pushvalue(L, 1); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) + { + Eluna::GetEluna(L)->eventMgr->globalProcessor->AddEvent(functionRef, min, max, repeats); + Eluna::Push(L, functionRef); + } + return 1; + } + + /** + * Removes a global timed event specified by ID. + * + * @param int eventId : event Id to remove + * @param bool all_Events = false : remove from all events, not just global + */ + int RemoveEventById(lua_State* L) + { + int eventId = Eluna::CHECKVAL(L, 1); + bool all_Events = Eluna::CHECKVAL(L, 1, false); + + // not thread safe + if (all_Events) + Eluna::GetEluna(L)->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); + else + Eluna::GetEluna(L)->eventMgr->globalProcessor->SetState(eventId, LUAEVENT_STATE_ABORT); + return 0; + } + + /** + * Removes all global timed events. + * + * @param bool all_Events = false : remove all events, not just global + */ + int RemoveEvents(lua_State* L) + { + bool all_Events = Eluna::CHECKVAL(L, 1, false); + + // not thread safe + if (all_Events) + Eluna::GetEluna(L)->eventMgr->SetStates(LUAEVENT_STATE_ABORT); + else + Eluna::GetEluna(L)->eventMgr->globalProcessor->SetStates(LUAEVENT_STATE_ABORT); + return 0; + } + + /** + * Performs an in-game spawn and returns the [Creature] or [GameObject] spawned. + * + * @param int32 spawnType : type of object to spawn, 1 = [Creature], 2 = [GameObject] + * @param uint32 entry : entry ID of the [Creature] or [GameObject] + * @param uint32 mapId : map ID to spawn the [Creature] or [GameObject] in + * @param uint32 instanceId : instance ID to put the [Creature] or [GameObject] in. Non instance is 0 + * @param float x : x coordinate of the [Creature] or [GameObject] + * @param float y : y coordinate of the [Creature] or [GameObject] + * @param float z : z coordinate of the [Creature] or [GameObject] + * @param float o : o facing/orientation of the [Creature] or [GameObject] + * @param bool save = false : optional to save the [Creature] or [GameObject] to the database + * @param uint32 durorresptime = 0 : despawn time of the [Creature] if it's not saved or respawn time of [GameObject] + * @param uint32 phase = 1 : phase to put the [Creature] or [GameObject] in + * @return [WorldObject] worldObject : returns [Creature] or [GameObject] + */ + int PerformIngameSpawn(lua_State* L) + { + int spawntype = Eluna::CHECKVAL(L, 1); + uint32 entry = Eluna::CHECKVAL(L, 2); + uint32 mapID = Eluna::CHECKVAL(L, 3); + uint32 instanceID = Eluna::CHECKVAL(L, 4); + float x = Eluna::CHECKVAL(L, 5); + float y = Eluna::CHECKVAL(L, 6); + float z = Eluna::CHECKVAL(L, 7); + float o = Eluna::CHECKVAL(L, 8); + bool save = Eluna::CHECKVAL(L, 9, false); + uint32 durorresptime = Eluna::CHECKVAL(L, 10, 0); +#if (!defined(TBC) && !defined(CLASSIC)) + uint32 phase = Eluna::CHECKVAL(L, 11, PHASEMASK_NORMAL); + if (!phase) + { + Eluna::Push(L); + return 1; + } +#endif + +#if !defined TRINITY && !AZEROTHCORE + Map* map = eMapMgr->FindMap(mapID, instanceID); + if (!map) + { + Eluna::Push(L); + return 1; + } + + if (spawntype == 1) // spawn creature + { + if (save) + { + CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(entry); + if (!cinfo) + { + Eluna::Push(L); + return 1; + } + +#if (defined(TBC) || defined(CLASSIC)) + CreatureCreatePos pos(map, x, y, z, o); +#else + CreatureCreatePos pos(map, x, y, z, o, phase); +#endif + Creature* pCreature = new Creature; + // used guids from specially reserved range (can be 0 if no free values) + uint32 lowguid = eObjectMgr->GenerateStaticCreatureLowGuid(); + if (!lowguid) + { + Eluna::Push(L); + return 1; + } + + if (!pCreature->Create(lowguid, pos, cinfo)) + { + delete pCreature; + Eluna::Push(L); + return 1; + } + +#ifdef TBC + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); +#elif defined(CLASSIC) + pCreature->SaveToDB(map->GetId()); +#else + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), phase); +#endif + + uint32 db_guid = pCreature->GetGUIDLow(); + + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + pCreature->LoadFromDB(db_guid, map); + + map->Add(pCreature); + eObjectMgr->AddCreatureToGrid(db_guid, eObjectMgr->GetCreatureData(db_guid)); + if (durorresptime) + pCreature->ForcedDespawn(durorresptime); + + Eluna::Push(L, pCreature); + } + else + { + CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(entry); + if (!cinfo) + { + Eluna::Push(L); + return 1; + } + + TemporarySummon* pCreature = new TemporarySummon(ObjectGuid(uint64(0))); +#if (defined(TBC) || defined(CLASSIC)) + CreatureCreatePos pos(map, x, y, z, o); +#else + CreatureCreatePos pos(map, x, y, z, o, phase); +#endif + + if (!pCreature->Create(map->GenerateLocalLowGuid(cinfo->GetHighGuid()), pos, cinfo, TEAM_NONE)) + { + delete pCreature; + { + Eluna::Push(L); + return 1; + } + } + + pCreature->SetRespawnCoord(pos); + + // Active state set before added to map + pCreature->SetActiveObjectState(false); + + // Also initializes the AI and MMGen + pCreature->Summon(durorresptime ? TEMPSPAWN_TIMED_OR_DEAD_DESPAWN : TEMPSPAWN_MANUAL_DESPAWN, durorresptime); + + // Creature Linking, Initial load is handled like respawn + if (pCreature->IsLinkingEventTrigger()) + map->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_RESPAWN, pCreature); + + Eluna::Push(L, pCreature); + } + + return 1; + } + + if (spawntype == 2) // Spawn object + { + if (save) + { + const GameObjectInfo* gInfo = ObjectMgr::GetGameObjectInfo(entry); + if (!gInfo) + { + Eluna::Push(L); + return 1; + } + + // used guids from specially reserved range (can be 0 if no free values) + uint32 db_lowGUID = eObjectMgr->GenerateStaticGameObjectLowGuid(); + if (!db_lowGUID) + { + Eluna::Push(L); + return 1; + } + + GameObject* pGameObj = new GameObject; +#if (defined(TBC) || defined(CLASSIC)) + if (!pGameObj->Create(db_lowGUID, gInfo->id, map, x, y, z, o)) +#else + if (!pGameObj->Create(db_lowGUID, gInfo->id, map, phase, x, y, z, o)) +#endif + { + delete pGameObj; + Eluna::Push(L); + return 1; + } + + if (durorresptime) + pGameObj->SetRespawnTime(durorresptime); + + // fill the gameobject data and save to the db +#ifdef TBC + pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); +#elif defined(CLASSIC) + pGameObj->SaveToDB(map->GetId()); +#else + pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), phase); +#endif + + // this will generate a new guid if the object is in an instance + if (!pGameObj->LoadFromDB(db_lowGUID, map)) + { + delete pGameObj; + Eluna::Push(L); + return 1; + } + + // DEBUG_LOG(GetMangosString(LANG_GAMEOBJECT_CURRENT), gInfo->name, db_lowGUID, x, y, z, o); + + map->Add(pGameObj); + pGameObj->AIM_Initialize(); + + eObjectMgr->AddGameobjectToGrid(db_lowGUID, eObjectMgr->GetGOData(db_lowGUID)); + + Eluna::Push(L, pGameObj); + } + else + { + GameObject* pGameObj = new GameObject; + +#if (defined(TBC) || defined(CLASSIC)) + if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), entry, map, x, y, z, o)) +#else + if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), entry, map, phase, x, y, z, o)) +#endif + { + delete pGameObj; + Eluna::Push(L); + return 1; + } + + pGameObj->SetRespawnTime(durorresptime / IN_MILLISECONDS); + + map->Add(pGameObj); + pGameObj->AIM_Initialize(); + + Eluna::Push(L, pGameObj); + } + return 1; + } +#else + Map* map = eMapMgr->FindMap(mapID, instanceID); + if (!map) + { + Eluna::Push(L); + return 1; + } + + Position pos = { x, y, z, o }; + + if (spawntype == 1) // spawn creature + { + if (save) + { + Creature* creature = new Creature(); +#ifndef AZEROTHCORE + if (!creature->Create(map->GenerateLowGuid(), map, phase, entry, pos)) +#else + if (!creature->Create(map->GenerateLowGuid(), map, phase, entry, 0, x, y, z, o)) +#endif + { + delete creature; + Eluna::Push(L); + return 1; + } + + creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), phase); + + uint32 db_guid = creature->GetSpawnId(); + + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells() + // current "creature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior + creature->CleanupsBeforeDelete(); + delete creature; + creature = new Creature(); +#ifndef AZEROTHCORE + if (!creature->LoadFromDB(db_guid, map, true, true)) +#else + if (!creature->LoadFromDB(db_guid, map, true)) +#endif + { + delete creature; + Eluna::Push(L); + return 1; + } + + eObjectMgr->AddCreatureToGrid(db_guid, eObjectMgr->GetCreatureData(db_guid)); + Eluna::Push(L, creature); + } + else + { + TempSummon* creature = map->SummonCreature(entry, pos, NULL, durorresptime); + if (!creature) + { + Eluna::Push(L); + return 1; + } + + if (durorresptime) + creature->SetTempSummonType(TEMPSUMMON_TIMED_OR_DEAD_DESPAWN); + else + creature->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); + + Eluna::Push(L, creature); + } + + return 1; + } + + if (spawntype == 2) // Spawn object + { + const GameObjectTemplate* objectInfo = eObjectMgr->GetGameObjectTemplate(entry); + if (!objectInfo) + { + Eluna::Push(L); + return 1; + } + + if (objectInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(objectInfo->displayId)) + { + Eluna::Push(L); + return 1; + } + + GameObject* object = new GameObject; +#ifndef AZEROTHCORE + uint32 guidLow = map->GenerateLowGuid(); + QuaternionData rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f); + if (!object->Create(guidLow, objectInfo->entry, map, phase, Position(x, y, z, o), rot, 0, GO_STATE_READY)) +#else + uint32 guidLow = map->GenerateLowGuid(); + if (!object->Create(guidLow, entry, map, phase, x, y, z, o, G3D::Quat(0.0f, 0.0f, 0.0f, 0.0f), 100, GO_STATE_READY)) +#endif + { + delete object; + Eluna::Push(L); + return 1; + } + + if (durorresptime) + object->SetRespawnTime(durorresptime); + + if (save) + { + // fill the gameobject data and save to the db + object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), phase); + guidLow = object->GetSpawnId(); + + // delete the old object and do a clean load from DB with a fresh new GameObject instance. + // this is required to avoid weird behavior and memory leaks + delete object; + + object = new GameObject(); + // this will generate a new lowguid if the object is in an instance +#ifndef AZEROTHCORE + if (!object->LoadFromDB(guidLow, map, true)) +#else + if (!object->LoadFromDB(guidLow, map)) +#endif + { + delete object; + Eluna::Push(L); + return 1; + } + + eObjectMgr->AddGameobjectToGrid(guidLow, eObjectMgr->GetGameObjectData(guidLow)); + } + else + map->AddToMap(object); + Eluna::Push(L, object); + return 1; + } +#endif + Eluna::Push(L); + return 1; + } + + /** + * Creates a [WorldPacket]. + * + * @param [Opcodes] opcode : the opcode of the packet + * @param uint32 size : the size of the packet + * @return [WorldPacket] packet + */ + int CreatePacket(lua_State* L) + { + uint32 opcode = Eluna::CHECKVAL(L, 1); + size_t size = Eluna::CHECKVAL(L, 2); + if (opcode >= NUM_MSG_TYPES) + return luaL_argerror(L, 1, "valid opcode expected"); + + Eluna::Push(L, new WorldPacket((OpcodesList)opcode, size)); + return 1; + } + + /** + * Adds an [Item] to a vendor and updates the world database. + * + * @param uint32 entry : [Creature] entry Id + * @param uint32 item : [Item] entry Id + * @param int32 maxcount : max [Item] stack count + * @param uint32 incrtime : combined with maxcount, incrtime tells how often (in seconds) the vendor list is refreshed and the limited [Item] copies are restocked + * @param uint32 extendedcost : unique cost of an [Item], such as conquest points for example + */ + int AddVendorItem(lua_State* L) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 item = Eluna::CHECKVAL(L, 2); + int maxcount = Eluna::CHECKVAL(L, 3); + uint32 incrtime = Eluna::CHECKVAL(L, 4); + uint32 extendedcost = Eluna::CHECKVAL(L, 5); + +#if defined TRINITY || AZEROTHCORE +#ifdef CATA + if (!eObjectMgr->IsVendorItemValid(entry, item, maxcount, incrtime, extendedcost, 1)) + return 0; + eObjectMgr->AddVendorItem(entry, item, maxcount, incrtime, extendedcost, 1); +#else + if (!eObjectMgr->IsVendorItemValid(entry, item, maxcount, incrtime, extendedcost)) + return 0; + eObjectMgr->AddVendorItem(entry, item, maxcount, incrtime, extendedcost); +#endif +#else + if (!eObjectMgr->IsVendorItemValid(false, "npc_vendor", entry, item, maxcount, incrtime, extendedcost, 0)) + return 0; +#ifndef CLASSIC + eObjectMgr->AddVendorItem(entry, item, maxcount, incrtime, extendedcost); +#else + eObjectMgr->AddVendorItem(entry, item, maxcount, incrtime); +#endif +#endif//TRINITY + return 0; + } + + /** + * Removes an [Item] from a vendor and updates the database. + * + * @param uint32 entry : [Creature] entry Id + * @param uint32 item : [Item] entry Id + */ + int VendorRemoveItem(lua_State* L) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 item = Eluna::CHECKVAL(L, 2); + if (!eObjectMgr->GetCreatureTemplate(entry)) + return luaL_argerror(L, 1, "valid CreatureEntry expected"); + +#if defined(CATA) || defined(MISTS) + eObjectMgr->RemoveVendorItem(entry, item, 1); +#else + eObjectMgr->RemoveVendorItem(entry, item); +#endif + return 0; + } + + /** + * Removes all [Item]s from a vendor and updates the database. + * + * @param uint32 entry : [Creature] entry Id + */ + int VendorRemoveAllItems(lua_State* L) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + VendorItemData const* items = eObjectMgr->GetNpcVendorItemList(entry); + if (!items || items->Empty()) + return 0; + + auto const& itemlist = items->m_items; + for (auto itr = itemlist.rbegin(); itr != itemlist.rend(); ++itr) +#if defined(CATA) || defined(MISTS) + eObjectMgr->RemoveVendorItem(entry, (*itr)->item, 1); +#else +#ifdef TRINITY + eObjectMgr->RemoveVendorItem(entry, itr->item); +#else + eObjectMgr->RemoveVendorItem(entry, (*itr)->item); +#endif +#endif + return 0; + } + + /** + * Kicks a [Player] from the server. + * + * @param [Player] player : [Player] to kick + */ + int Kick(lua_State* L) + { + Player* player = Eluna::CHECKOBJ(L, 1); +#ifdef TRINITY + player->GetSession()->KickPlayer("GlobalMethods::Kick Kick the player"); +#else + player->GetSession()->KickPlayer(); +#endif + return 0; + } + + /** + * Ban's a [Player]'s account, character or IP + * + * enum BanMode + * { + * BAN_ACCOUNT = 0, + * BAN_CHARACTER = 1, + * BAN_IP = 2 + * }; + * + * @param [BanMode] banMode : method of ban, refer to BanMode above + * @param string nameOrIP : If BanMode is 0 then accountname, if 1 then charactername if 2 then ip + * @param uint32 duration : duration (in seconds) of the ban + * @param string reason = "" : ban reason, this is optional + * @param string whoBanned = "" : the [Player]'s name that banned the account, character or IP, this is optional + * @return int result : status of the ban. 0 if success, 1 if syntax error, 2 if target not found, 3 if a longer ban already exists, nil if unknown result + */ + int Ban(lua_State* L) + { + int banMode = Eluna::CHECKVAL(L, 1); + std::string nameOrIP = Eluna::CHECKVAL(L, 2); + uint32 duration = Eluna::CHECKVAL(L, 3); + const char* reason = Eluna::CHECKVAL(L, 4, ""); + const char* whoBanned = Eluna::CHECKVAL(L, 5, ""); + + const int BAN_ACCOUNT = 0; + const int BAN_CHARACTER = 1; + const int BAN_IP = 2; + + BanMode mode = BanMode::BAN_ACCOUNT; + + switch (banMode) + { + case BAN_ACCOUNT: +#if defined TRINITY || AZEROTHCORE + if (!Utf8ToUpperOnlyLatin(nameOrIP)) + return luaL_argerror(L, 2, "invalid account name"); +#else + if (!AccountMgr::normalizeString(nameOrIP)) + return luaL_argerror(L, 2, "invalid account name"); +#endif + mode = BanMode::BAN_ACCOUNT; + break; + case BAN_CHARACTER: + if (!normalizePlayerName(nameOrIP)) + return luaL_argerror(L, 2, "invalid character name"); + mode = BanMode::BAN_CHARACTER; + break; + case BAN_IP: + if (!IsIPAddress(nameOrIP.c_str())) + return luaL_argerror(L, 2, "invalid ip"); + mode = BanMode::BAN_IP; + break; + default: + return luaL_argerror(L, 1, "unknown banmode"); + } + + BanReturn result; +#ifndef AZEROTHCORE + result = eWorld->BanAccount(mode, nameOrIP, duration, reason, whoBanned); +#else + switch (banMode) + { + case BAN_ACCOUNT: + result = sBan->BanAccount(nameOrIP, std::to_string(duration) + "s", reason, whoBanned); + break; + case BAN_CHARACTER: + result = sBan->BanCharacter(nameOrIP, std::to_string(duration) + "s", reason, whoBanned); + break; + case BAN_IP: + result = sBan->BanIP(nameOrIP, std::to_string(duration) + "s", reason, whoBanned); + break; + } +#endif + + switch (result) + { + case BanReturn::BAN_SUCCESS: + Eluna::Push(L, 0); + break; + case BanReturn::BAN_SYNTAX_ERROR: + Eluna::Push(L, 1); + break; + case BanReturn::BAN_NOTFOUND: + Eluna::Push(L, 2); + break; +#ifdef AZEROTHCORE + case BanReturn::BAN_LONGER_EXISTS: + Eluna::Push(L, 3); + break; +#elif TRINITY + case BanReturn::BAN_EXISTS: + Eluna::Push(L, 3); + break; +#endif + } + return 1; + } + + /** + * Saves all [Player]s. + */ + int SaveAllPlayers(lua_State* /*L*/) + { + eObjectAccessor()SaveAllPlayers(); + return 0; + } + + /** + * Sends mail to a [Player]. + * + * There can be several item entry-amount pairs at the end of the function. + * There can be maximum of 12 different items. + * + * enum MailStationery + * { + * MAIL_STATIONERY_TEST = 1, + * MAIL_STATIONERY_DEFAULT = 41, + * MAIL_STATIONERY_GM = 61, + * MAIL_STATIONERY_AUCTION = 62, + * MAIL_STATIONERY_VAL = 64, // Valentine + * MAIL_STATIONERY_CHR = 65, // Christmas + * MAIL_STATIONERY_ORP = 67 // Orphan + * }; + * + * @param string subject : title (subject) of the mail + * @param string text : contents of the mail + * @param uint32 receiverGUIDLow : low GUID of the receiver + * @param uint32 senderGUIDLow = 0 : low GUID of the sender + * @param [MailStationery] stationary = MAIL_STATIONERY_DEFAULT : type of mail that is being sent as, refer to MailStationery above + * @param uint32 delay = 0 : mail send delay in milliseconds + * @param uint32 money = 0 : money to send + * @param uint32 cod = 0 : cod money amount + * @param uint32 entry = 0 : entry of an [Item] to send with mail + * @param uint32 amount = 0 : amount of the [Item] to send with mail + * @return uint32 itemGUIDlow : low GUID of the item. Up to 12 values returned, returns nil if no further items are sent + */ + int SendMail(lua_State* L) + { + int i = 0; + std::string subject = Eluna::CHECKVAL(L, ++i); + std::string text = Eluna::CHECKVAL(L, ++i); + uint32 receiverGUIDLow = Eluna::CHECKVAL(L, ++i); + uint32 senderGUIDLow = Eluna::CHECKVAL(L, ++i, 0); + uint32 stationary = Eluna::CHECKVAL(L, ++i, MAIL_STATIONERY_DEFAULT); + uint32 delay = Eluna::CHECKVAL(L, ++i, 0); + uint32 money = Eluna::CHECKVAL(L, ++i, 0); + uint32 cod = Eluna::CHECKVAL(L, ++i, 0); + int argAmount = lua_gettop(L); + + MailSender sender(MAIL_NORMAL, senderGUIDLow, (MailStationery)stationary); + MailDraft draft(subject, text); + +#if defined TRINITY || AZEROTHCORE + if (cod) + draft.AddCOD(cod); + if (money) + draft.AddMoney(money); +#else + if (cod) + draft.SetCOD(cod); + if (money) + draft.SetMoney(money); +#endif + +#if defined TRINITY || defined AZEROTHCORE + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); +#endif + uint8 addedItems = 0; + while (addedItems <= MAX_MAIL_ITEMS && i + 2 <= argAmount) + { + uint32 entry = Eluna::CHECKVAL(L, ++i); + uint32 amount = Eluna::CHECKVAL(L, ++i); + +#if defined TRINITY || AZEROTHCORE + ItemTemplate const* item_proto = eObjectMgr->GetItemTemplate(entry); +#else + ItemTemplate const* item_proto = ObjectMgr::GetItemPrototype(entry); +#endif + if (!item_proto) + { + luaL_error(L, "Item entry %d does not exist", entry); + continue; + } + if (amount < 1 || (item_proto->MaxCount > 0 && amount > uint32(item_proto->MaxCount))) + { + luaL_error(L, "Item entry %d has invalid amount %d", entry, amount); + continue; + } + if (Item* item = Item::CreateItem(entry, amount)) + { +#if defined TRINITY || AZEROTHCORE + item->SaveToDB(trans); +#else + item->SaveToDB(); +#endif + draft.AddItem(item); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, item->GetGUID().GetCounter()); +#else + Eluna::Push(L, item->GetGUIDLow()); +#endif + ++addedItems; + } + } + + Player* receiverPlayer = eObjectAccessor()FindPlayer(MAKE_NEW_GUID(receiverGUIDLow, 0, HIGHGUID_PLAYER)); +#if defined TRINITY || AZEROTHCORE + draft.SendMailTo(trans, MailReceiver(receiverPlayer, receiverGUIDLow), sender, MAIL_CHECK_MASK_NONE, delay); + CharacterDatabase.CommitTransaction(trans); +#else + draft.SendMailTo(MailReceiver(receiverPlayer, MAKE_NEW_GUID(receiverGUIDLow, 0, HIGHGUID_PLAYER)), sender); +#endif + return addedItems; + } + + /** + * Performs a bitwise AND (a & b). + * + * @param uint32 a + * @param uint32 b + * @return uint32 result + */ + int bit_and(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + uint32 b = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, a & b); + return 1; + } + + /** + * Performs a bitwise OR (a | b). + * + * @param uint32 a + * @param uint32 b + * @return uint32 result + */ + int bit_or(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + uint32 b = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, a | b); + return 1; + } + + /** + * Performs a bitwise left-shift (a << b). + * + * @param uint32 a + * @param uint32 b + * @return uint32 result + */ + int bit_lshift(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + uint32 b = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, a << b); + return 1; + } + + /** + * Performs a bitwise right-shift (a >> b). + * + * @param uint32 a + * @param uint32 b + * @return uint32 result + */ + int bit_rshift(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + uint32 b = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, a >> b); + return 1; + } + + /** + * Performs a bitwise XOR (a ^ b). + * + * @param uint32 a + * @param uint32 b + * @return uint32 result + */ + int bit_xor(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + uint32 b = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, a ^ b); + return 1; + } + + /** + * Performs a bitwise NOT (~a). + * + * @param uint32 a + * @return uint32 result + */ + int bit_not(lua_State* L) + { + uint32 a = Eluna::CHECKVAL(L, 1); + Eluna::Push(L, ~a); + return 1; + } + + /** + * Adds a taxi path to a specified map, returns the used pathId. + * + * Note that the first taxi point needs to be near the player when he starts the taxi path. + * The function should also be used only **once** per path added so use it on server startup for example. + * + * Related function: [Player:StartTaxi] + * + * -- Execute on startup + * local pathTable = {{mapid, x, y, z}, {mapid, x, y, z}} + * local path = AddTaxiPath(pathTable, 28135, 28135) + * + * -- Execute when the player should fly + * player:StartTaxi(path) + * + * @param table waypoints : table containing waypoints: {map, x, y, z[, actionFlag, delay]} + * @param uint32 mountA : alliance [Creature] entry + * @param uint32 mountH : horde [Creature] entry + * @param uint32 price = 0 : price of the taxi path + * @param uint32 pathId = 0 : path Id of the taxi path + * @return uint32 actualPathId + */ + int AddTaxiPath(lua_State* L) + { + luaL_checktype(L, 1, LUA_TTABLE); + uint32 mountA = Eluna::CHECKVAL(L, 2); + uint32 mountH = Eluna::CHECKVAL(L, 3); + uint32 price = Eluna::CHECKVAL(L, 4, 0); + uint32 pathId = Eluna::CHECKVAL(L, 5, 0); + lua_pushvalue(L, 1); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes} + + std::list nodes; + + int start = lua_gettop(L); + int end = start; + + Eluna::Push(L); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, nil + while (lua_next(L, -2) != 0) + { + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, key, value + luaL_checktype(L, -1, LUA_TTABLE); + Eluna::Push(L); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, key, value, nil + while (lua_next(L, -2) != 0) + { + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, key, value, key2, value2 + lua_insert(L, end++); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, value2, key, value, key2 + } + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, value2, key, value + if (start == end) + continue; + if (end - start < 4) // no mandatory args, dont add + return luaL_argerror(L, 1, "all waypoints do not have mandatory arguments"); + + while (end - start < 8) // fill optional args with 0 + { + Eluna::Push(L, 0); + lua_insert(L, end++); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, node, key, value + } + TaxiPathNodeEntry entry; +#ifdef TRINITY + // mandatory + entry.ContinentID = Eluna::CHECKVAL(L, start); + entry.Loc.X = Eluna::CHECKVAL(L, start + 1); + entry.Loc.Y = Eluna::CHECKVAL(L, start + 2); + entry.Loc.Z = Eluna::CHECKVAL(L, start + 3); + // optional + entry.Flags = Eluna::CHECKVAL(L, start + 4, 0); + entry.Delay = Eluna::CHECKVAL(L, start + 5, 0); +#else + // mandatory + entry.mapid = Eluna::CHECKVAL(L, start); + entry.x = Eluna::CHECKVAL(L, start + 1); + entry.y = Eluna::CHECKVAL(L, start + 2); + entry.z = Eluna::CHECKVAL(L, start + 3); + // optional + entry.actionFlag = Eluna::CHECKVAL(L, start + 4, 0); + entry.delay = Eluna::CHECKVAL(L, start + 5, 0); +#endif + + nodes.push_back(entry); + + while (end != start) // remove args + if (!lua_isnone(L, --end)) + lua_remove(L, end); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, key, value + + lua_pop(L, 1); + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes}, key + } + // Stack: {nodes}, mountA, mountH, price, pathid, {nodes} + lua_pop(L, 1); + // Stack: {nodes}, mountA, mountH, price, pathid + + if (nodes.size() < 2) + return 1; + if (!pathId) + pathId = sTaxiPathNodesByPath.size(); + if (sTaxiPathNodesByPath.size() <= pathId) + sTaxiPathNodesByPath.resize(pathId + 1); + sTaxiPathNodesByPath[pathId].clear(); + sTaxiPathNodesByPath[pathId].resize(nodes.size()); + static uint32 nodeId = 500; + uint32 startNode = nodeId; + uint32 index = 0; + for (std::list::iterator it = nodes.begin(); it != nodes.end(); ++it) + { + TaxiPathNodeEntry& entry = *it; + TaxiNodesEntry* nodeEntry = new TaxiNodesEntry(); +#ifdef TRINITY + entry.PathID = pathId; + entry.NodeIndex = nodeId; + nodeEntry->ID = index; + nodeEntry->ContinentID = entry.ContinentID; + nodeEntry->Pos.X = entry.Loc.X; + nodeEntry->Pos.Y = entry.Loc.Y; + nodeEntry->Pos.Z = entry.Loc.Z; + nodeEntry->MountCreatureID[0] = mountH; + nodeEntry->MountCreatureID[1] = mountA; + sTaxiNodesStore.SetEntry(nodeId++, nodeEntry); + sTaxiPathNodesByPath[pathId][index++] = new TaxiPathNodeEntry(entry); +#else + entry.path = pathId; + entry.index = nodeId; + nodeEntry->ID = index; + nodeEntry->map_id = entry.mapid; + nodeEntry->x = entry.x; + nodeEntry->y = entry.y; + nodeEntry->z = entry.z; + nodeEntry->MountCreatureID[0] = mountH; + nodeEntry->MountCreatureID[1] = mountA; + sTaxiNodesStore.SetEntry(nodeId++, nodeEntry); +#ifndef AZEROTHCORE + sTaxiPathNodesByPath[pathId].set(index++, new TaxiPathNodeEntry(entry)); +#else + sTaxiPathNodesByPath[pathId][index++] = new TaxiPathNodeEntry(entry); +#endif +#endif + } + if (startNode >= nodeId) + return 1; +#ifndef AZEROTHCORE + sTaxiPathSetBySource[startNode][nodeId - 1] = TaxiPathBySourceAndDestination(pathId, price); +#endif + TaxiPathEntry* pathEntry = new TaxiPathEntry(); +#ifdef TRINITY + pathEntry->FromTaxiNode = startNode; + pathEntry->ToTaxiNode = nodeId - 1; + pathEntry->Cost = price; +#else + pathEntry->from = startNode; + pathEntry->to = nodeId - 1; + pathEntry->price = price; +#endif + pathEntry->ID = pathId; + sTaxiPathStore.SetEntry(pathId, pathEntry); +#ifdef AZEROTHCORE + sTaxiPathSetBySource[startNode][nodeId - 1] = pathEntry; +#endif + Eluna::Push(L, pathId); + return 1; + } + + /** + * Returns `true` if the bag and slot is a valid inventory position, otherwise `false`. + * + * Some commonly used combinations: + * + * *Bag 255 (common character inventory)* + * + * - Slots 0-18: equipment + * - Slots 19-22: bag slots + * - Slots 23-38: backpack + * - Slots 39-66: bank main slots + * - Slots 67-74: bank bag slots + * - Slots 86-117: keyring + * + * *Bags 19-22 (equipped bags)* + * + * - Slots 0-35 + * + * *Bags 67-74 (bank bags)* + * + * - Slots 0-35 + * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isInventoryPos + */ + int IsInventoryPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsInventoryPos(bag, slot)); + return 1; + } + + /** + * Returns `true` if the bag and slot is a valid equipment position, otherwise `false`. + * + * See [Global:IsInventoryPos] for bag/slot combination examples. + * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isEquipmentPosition + */ + int IsEquipmentPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsEquipmentPos(bag, slot)); + return 1; + } + + /** + * Returns `true` if the bag and slot is a valid bank position, otherwise `false`. + * + * See [Global:IsInventoryPos] for bag/slot combination examples. + * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isBankPosition + */ + int IsBankPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsBankPos(bag, slot)); + return 1; + } + + /** + * Returns `true` if the bag and slot is a valid bag position, otherwise `false`. + * + * See [Global:IsInventoryPos] for bag/slot combination examples. + * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isBagPosition + */ + int IsBagPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsBagPos((bag << 8) + slot)); + return 1; + } + + /** + * Returns `true` if the event is currently active, otherwise `false`. + * + * @param uint16 eventId : the event id to check. + * @return bool isActive + */ + int IsGameEventActive(lua_State* L) + { + uint16 eventId = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, eGameEventMgr->IsActiveEvent(eventId)); + return 1; + } + + /** + * Returns the server's current time. + * + * @return uint32 currTime : the current time, in milliseconds + */ + int GetCurrTime(lua_State* L) + { + Eluna::Push(L, ElunaUtil::GetCurrTime()); + return 1; + } + + /** + * Returns the difference between an old timestamp and the current time. + * + * @param uint32 oldTime : an old timestamp, in milliseconds + * @return uint32 timeDiff : the difference, in milliseconds + */ + int GetTimeDiff(lua_State* L) + { + uint32 oldtimems = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, ElunaUtil::GetTimeDiff(oldtimems)); + return 1; + } + + static std::string GetStackAsString(lua_State* L) + { + std::ostringstream oss; + int top = lua_gettop(L); + for (int i = 1; i <= top; ++i) + { + oss << luaL_tolstring(L, i, NULL); + lua_pop(L, 1); + } + return oss.str(); + } + + /** + * Prints given parameters to the info log. + * + * @param ... + */ + int PrintInfo(lua_State* L) + { + ELUNA_LOG_INFO("{}", GetStackAsString(L)); + return 0; + } + + /** + * Prints given parameters to the error log. + * + * @param ... + */ + int PrintError(lua_State* L) + { + ELUNA_LOG_ERROR("{}", GetStackAsString(L)); + return 0; + } + + /** + * Prints given parameters to the debug log. + * + * @param ... + */ + int PrintDebug(lua_State* L) + { + ELUNA_LOG_DEBUG("{}", GetStackAsString(L)); + return 0; + } + + /** + * Starts the event by eventId, if force is set, the event will force start regardless of previous event state. + * + * @param uint16 eventId : the event id to start. + * @param bool force = false : set `true` to force start the event. + */ + int StartGameEvent(lua_State* L) + { + uint16 eventId = Eluna::CHECKVAL(L, 1); + bool force = Eluna::CHECKVAL(L, 2, false); + + eGameEventMgr->StartEvent(eventId, force); + return 0; + } + + /** + * Stops the event by eventId, if force is set, the event will force stop regardless of previous event state. + * + * @param uint16 eventId : the event id to stop. + * @param bool force = false : set `true` to force stop the event. + */ + int StopGameEvent(lua_State* L) + { + uint16 eventId = Eluna::CHECKVAL(L, 1); + bool force = Eluna::CHECKVAL(L, 2, false); + + eGameEventMgr->StopEvent(eventId, force); + return 0; + } + + /** + * Performs a non-blocking HTTP request. + * + * When the passed callback function is called, the parameters `(status, body, headers)` are passed to it. + * + * -- GET example (prints a random word) + * HttpRequest("GET", "https://random-word-api.herokuapp.com/word", function(status, body, headers) + * print("Random word: " .. string.sub(body, 3, body:len() - 2)) + * end) + * + * -- POST example with JSON request body + * HttpRequest("POST", "https://jsonplaceholder.typicode.com/posts", '{"userId": 1,"title": "Foo","body": "Bar!"}', "application/json", function(status, body, headers) + * print(body) + * end) + * + * -- Example with request headers + * HttpRequest("GET", "https://postman-echo.com/headers", { Accept = "application/json", ["User-Agent"] = "Eluna Lua Engine" }, function(status, body, headers) + * print(body) + * end) + * + * @proto (httpMethod, url, function) + * @proto (httpMethod, url, headers, function) + * @proto (httpMethod, url, body, contentType, function) + * @proto (httpMethod, url, body, contentType, headers, function) + * + * @param string httpMethod : the HTTP method to use (possible values are: `"GET"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, `"DELETE"`, `"OPTIONS"`) + * @param string url : the URL to query + * @param table headers : a table with string key-value pairs containing the request headers + * @param string body : the request's body (only used for POST, PUT and PATCH requests) + * @param string contentType : the body's content-type + * @param function function : function that will be called when the request is executed + */ + int HttpRequest(lua_State* L) + { + std::string httpVerb = Eluna::CHECKVAL(L, 1); + std::string url = Eluna::CHECKVAL(L, 2); + std::string body; + std::string bodyContentType; + httplib::Headers headers; + + int headersIdx = 3; + int callbackIdx = 3; + + if (!lua_istable(L, headersIdx) && lua_isstring(L, headersIdx) && lua_isstring(L, headersIdx + 1)) + { + body = Eluna::CHECKVAL(L, 3); + bodyContentType = Eluna::CHECKVAL(L, 4); + headersIdx = 5; + callbackIdx = 5; + } + + if (lua_istable(L, headersIdx)) + { + ++callbackIdx; + + lua_pushnil(L); // First key + while (lua_next(L, headersIdx) != 0) + { + // Uses 'key' (at index -2) and 'value' (at index -1) + if (lua_isstring(L, -2)) + { + std::string key(lua_tostring(L, -2)); + std::string value(lua_tostring(L, -1)); + headers.insert(std::pair(key, value)); + } + // Removes 'value'; keeps 'key' for next iteration + lua_pop(L, 1); + } + } + + lua_pushvalue(L, callbackIdx); + int funcRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (funcRef >= 0) + { + Eluna::GEluna->httpManager.PushRequest(new HttpWorkItem(funcRef, httpVerb, url, body, bodyContentType, headers)); + } + else + { + luaL_argerror(L, callbackIdx, "unable to make a ref to function"); + } + + return 0; + } + + /** + * Returns an object representing a `long long` (64-bit) value. + * + * The value by default is 0, but can be initialized to a value by passing a number or long long as a string. + * + * @proto value = () + * @proto value = (n) + * @proto value = (n_ll) + * @proto value = (n_str) + * @param int32 n + * @param int64 n_ll + * @param string n_str + * @return int64 value + */ + int CreateLongLong(lua_State* L) + { + long long init = 0; + if (lua_isstring(L, 1)) + { + std::string str = Eluna::CHECKVAL(L, 1); + std::istringstream iss(str); + iss >> init; + if (iss.bad()) + return luaL_argerror(L, 1, "long long (as string) could not be converted"); + } + else if (!lua_isnoneornil(L, 1)) + init = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, init); + return 1; + } + + /** + * Returns an object representing an `unsigned long long` (64-bit) value. + * + * The value by default is 0, but can be initialized to a value by passing a number or unsigned long long as a string. + * + * @proto value = () + * @proto value = (n) + * @proto value = (n_ull) + * @proto value = (n_str) + * @param uint32 n + * @param uint64 n_ull + * @param string n_str + * @return uint64 value + */ + int CreateULongLong(lua_State* L) + { + unsigned long long init = 0; + if (lua_isstring(L, 1)) + { + std::string str = Eluna::CHECKVAL(L, 1); + std::istringstream iss(str); + iss >> init; + if (iss.bad()) + return luaL_argerror(L, 1, "unsigned long long (as string) could not be converted"); + } + else if (!lua_isnoneornil(L, 1)) + init = Eluna::CHECKVAL(L, 1); + + Eluna::Push(L, init); + return 1; + } + + /** + * Unbinds event handlers for either all [BattleGround] events, or one type of event. + * + * If `event_type` is `nil`, all [BattleGround] event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto () + * @proto (event_type) + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterBGEvent] + */ + int ClearBattleGroundEvents(lua_State* L) + { + typedef EventKey Key; + + if (lua_isnoneornil(L, 1)) + { + Eluna::GetEluna(L)->BGEventBindings->Clear(); + } + else + { + uint32 event_type = Eluna::CHECKVAL(L, 1); + Eluna::GetEluna(L)->BGEventBindings->Clear(Key((Hooks::BGEvents)event_type)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [Creature]'s events, or one type of event. + * + * If `event_type` is `nil`, all the [Creature]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [Creature], not just one. + * To bind and unbind events to a single [Creature], see [Global:RegisterUniqueCreatureEvent] and [Global:ClearUniqueCreatureEvents]. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of one or more [Creature]s whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureEvent] + */ + int ClearCreatureEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + E->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->CreatureEventBindings->Clear(Key((Hooks::CreatureEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [Creature]'s events, or one type of event. + * + * If `event_type` is `nil`, all the [Creature]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect only a single [Creature]. + * To bind and unbind events to all instances of a [Creature], see [Global:RegisterCreatureEvent] and [Global:ClearCreatureEvent]. + * + * @proto (entry) + * @proto (entry, event_type) + * @param ObjectGuid guid : the GUID of a single [Creature] whose handlers will be cleared + * @param uint32 instance_id : the instance ID of a single [Creature] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureEvent] + */ + int ClearUniqueCreatureEvents(lua_State* L) + { + typedef UniqueObjectKey Key; + + if (lua_isnoneornil(L, 3)) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + uint32 instanceId = Eluna::CHECKVAL(L, 2); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + E->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)i, guid, instanceId)); + } + else + { + ObjectGuid guid = Eluna::CHECKVAL(L, 1); + uint32 instanceId = Eluna::CHECKVAL(L, 2); + uint32 event_type = Eluna::CHECKVAL(L, 3); + Eluna::GetEluna(L)->CreatureUniqueBindings->Clear(Key((Hooks::CreatureEvents)event_type, guid, instanceId)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [Creature]'s gossip events, or one type of event. + * + * If `event_type` is `nil`, all the [Creature]'s gossip event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [Creature], not just one. + * To bind and unbind gossip events to a single [Creature], tell the Eluna developers to implement that. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of a [Creature] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureGossipEvent] + */ + int ClearCreatureGossipEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->CreatureGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [GameObject]'s events, or one type of event. + * + * If `event_type` is `nil`, all the [GameObject]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [GameObject], not just one. + * To bind and unbind events to a single [GameObject], tell the Eluna developers to implement that. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of a [GameObject] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterGameObjectEvent] + */ + int ClearGameObjectEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::GAMEOBJECT_EVENT_COUNT; ++i) + E->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->GameObjectEventBindings->Clear(Key((Hooks::GameObjectEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [GameObject]'s gossip events, or one type of event. + * + * If `event_type` is `nil`, all the [GameObject]'s gossip event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [GameObject], not just one. + * To bind and unbind gossip events to a single [GameObject], tell the Eluna developers to implement that. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of a [GameObject] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterGameObjectGossipEvent] + */ + int ClearGameObjectGossipEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->GameObjectGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all [Group] events, or one type of [Group] event. + * + * If `event_type` is `nil`, all [Group] event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto () + * @proto (event_type) + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterGroupEvent] + */ + int ClearGroupEvents(lua_State* L) + { + typedef EventKey Key; + + if (lua_isnoneornil(L, 1)) + { + Eluna::GetEluna(L)->GroupEventBindings->Clear(); + } + else + { + uint32 event_type = Eluna::CHECKVAL(L, 1); + Eluna::GetEluna(L)->GroupEventBindings->Clear(Key((Hooks::GroupEvents)event_type)); + } + return 0; + } + + /** + * Unbinds event handlers for either all [Guild] events, or one type of [Guild] event. + * + * If `event_type` is `nil`, all [Guild] event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto () + * @proto (event_type) + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterGuildEvent] + */ + int ClearGuildEvents(lua_State* L) + { + typedef EventKey Key; + + if (lua_isnoneornil(L, 1)) + { + Eluna::GetEluna(L)->GuildEventBindings->Clear(); + } + else + { + uint32 event_type = Eluna::CHECKVAL(L, 1); + Eluna::GetEluna(L)->GuildEventBindings->Clear(Key((Hooks::GuildEvents)event_type)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of an [Item]'s events, or one type of event. + * + * If `event_type` is `nil`, all the [Item]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [Item], not just one. + * To bind and unbind events to a single [Item], tell the Eluna developers to implement that. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of an [Item] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterItemEvent] + */ + int ClearItemEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::ITEM_EVENT_COUNT; ++i) + E->ItemEventBindings->Clear(Key((Hooks::ItemEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->ItemEventBindings->Clear(Key((Hooks::ItemEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of an [Item]'s gossip events, or one type of event. + * + * If `event_type` is `nil`, all the [Item]'s gossip event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * **NOTE:** this will affect all instances of the [Item], not just one. + * To bind and unbind gossip events to a single [Item], tell the Eluna developers to implement that. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the ID of an [Item] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterItemGossipEvent] + */ + int ClearItemGossipEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->ItemGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [WorldPacket] opcode's events, or one type of event. + * + * If `event_type` is `nil`, all the [WorldPacket] opcode's event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto (opcode) + * @proto (opcode, event_type) + * @param uint32 opcode : the type of [WorldPacket] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPacketEvent] + */ + int ClearPacketEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::PACKET_EVENT_COUNT; ++i) + E->PacketEventBindings->Clear(Key((Hooks::PacketEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->PacketEventBindings->Clear(Key((Hooks::PacketEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all [Player] events, or one type of [Player] event. + * + * If `event_type` is `nil`, all [Player] event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto () + * @proto (event_type) + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPlayerEvent] + */ + int ClearPlayerEvents(lua_State* L) + { + typedef EventKey Key; + + if (lua_isnoneornil(L, 1)) + { + Eluna::GetEluna(L)->PlayerEventBindings->Clear(); + } + else + { + uint32 event_type = Eluna::CHECKVAL(L, 1); + Eluna::GetEluna(L)->PlayerEventBindings->Clear(Key((Hooks::PlayerEvents)event_type)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a [Player]'s gossip events, or one type of event. + * + * If `event_type` is `nil`, all the [Player]'s gossip event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto (entry) + * @proto (entry, event_type) + * @param uint32 entry : the low GUID of a [Player] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPlayerGossipEvent] + */ + int ClearPlayerGossipEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::GOSSIP_EVENT_COUNT; ++i) + E->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->PlayerGossipBindings->Clear(Key((Hooks::GossipEvents)event_type, entry)); + } + return 0; + } + + /** + * Unbinds event handlers for either all server events, or one type of event. + * + * If `event_type` is `nil`, all server event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto () + * @proto (event_type) + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterServerEvent] + */ + int ClearServerEvents(lua_State* L) + { + typedef EventKey Key; + + if (lua_isnoneornil(L, 1)) + { + Eluna::GetEluna(L)->ServerEventBindings->Clear(); + } + else + { + uint32 event_type = Eluna::CHECKVAL(L, 1); + Eluna::GetEluna(L)->ServerEventBindings->Clear(Key((Hooks::ServerEvents)event_type)); + } + return 0; + } + + /** + * Unbinds event handlers for either all of a non-instanced [Map]'s events, or one type of event. + * + * If `event_type` is `nil`, all the non-instanced [Map]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto (map_id) + * @proto (map_id, event_type) + * @param uint32 map_id : the ID of a [Map] + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPlayerGossipEvent] + */ + int ClearMapEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i) + E->MapEventBindings->Clear(Key((Hooks::InstanceEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->MapEventBindings->Clear(Key((Hooks::InstanceEvents)event_type, entry)); + } + + return 0; + } + + /** + * Unbinds event handlers for either all of an instanced [Map]'s events, or one type of event. + * + * If `event_type` is `nil`, all the instanced [Map]'s event handlers are cleared. + * + * Otherwise, only event handlers for `event_type` are cleared. + * + * @proto (instance_id) + * @proto (instance_id, event_type) + * @param uint32 entry : the ID of an instance of a [Map] + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterInstanceEvent] + */ + int ClearInstanceEvents(lua_State* L) + { + typedef EntryKey Key; + + if (lua_isnoneornil(L, 2)) + { + uint32 entry = Eluna::CHECKVAL(L, 1); + + Eluna* E = Eluna::GetEluna(L); + for (uint32 i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i) + E->InstanceEventBindings->Clear(Key((Hooks::InstanceEvents)i, entry)); + } + else + { + uint32 entry = Eluna::CHECKVAL(L, 1); + uint32 event_type = Eluna::CHECKVAL(L, 2); + Eluna::GetEluna(L)->InstanceEventBindings->Clear(Key((Hooks::InstanceEvents)event_type, entry)); + } + + return 0; + } + + #ifdef AZEROTHCORE + /** + * Gets the faction which is the current owner of Halaa in Nagrand + * 0 = Alliance + * 1 = Horde + * + * 600 = slider max Alliance + * -600 = slider max Horde + * + * @return int16 the ID of the team to own Halaa + * @return float the slider position. + */ + int GetOwnerHalaa(lua_State* L) + { + OutdoorPvPNA* nagrandPvp = (OutdoorPvPNA*)sOutdoorPvPMgr->GetOutdoorPvPToZoneId(3518); + OPvPCapturePointNA* halaa = nagrandPvp->GetCapturePoint(); + Eluna::Push(L, halaa->GetControllingFaction()); + Eluna::Push(L, halaa->GetSlider()); + + return 2; + } + + /** + * Sets the owner of Halaa in Nagrand to the respective faction + * 0 = Alliance + * 1 = Horde + * + * @param uint16 teamId : the ID of the team to own Halaa + */ + int SetOwnerHalaa(lua_State* L) + { + uint16 teamId = Eluna::CHECKVAL(L, 1); + + OutdoorPvPNA* nagrandPvp = (OutdoorPvPNA*)sOutdoorPvPMgr->GetOutdoorPvPToZoneId(3518); + OPvPCapturePointNA* halaa = nagrandPvp->GetCapturePoint(); + + if (teamId == 0) + { + halaa->SetSlider(599); + } + else if (teamId == 1) + { + halaa->SetSlider(-599); + } + else + { + return luaL_argerror(L, 1, "0 for Alliance or 1 for Horde expected"); + } + + return 0; + } + #endif +} +#endif diff --git a/modules/mod-eluna/src/LuaEngine/GossipHooks.cpp b/modules/mod-eluna/src/LuaEngine/GossipHooks.cpp new file mode 100644 index 0000000..e9b58e6 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GossipHooks.cpp @@ -0,0 +1,147 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(BINDINGS, EVENT, ENTRY) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!BINDINGS->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(BINDINGS, EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!BINDINGS->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) +{ + START_HOOK_WITH_RETVAL(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + Push(code); + return CallAllFunctionsBool(GameObjectGossipBindings, key, true); +} + +void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code) +{ + START_HOOK(PlayerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId); + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); // receiver + Push(pPlayer); // sender, just not to mess up the amount of args. + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(PlayerGossipBindings, key); +} + +bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/) +{ + START_HOOK_WITH_RETVAL(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pItem); + return CallAllFunctionsBool(ItemGossipBindings, key, true); +} + +void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* pItem, uint32 sender, uint32 action, const std::string& code) +{ + START_HOOK(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, pItem->GetEntry()); + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); + Push(pItem); + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(ItemGossipBindings, key); +} + +bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), false); + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + return CallAllFunctionsBool(CreatureGossipBindings, key, true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), false); + auto originalMenu = *pPlayer->PlayerTalkClass; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + auto preventDefault = CallAllFunctionsBool(CreatureGossipBindings, key, true); + if (!preventDefault) { + *pPlayer->PlayerTalkClass = originalMenu; + } + return preventDefault; +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) +{ + START_HOOK_WITH_RETVAL(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), false); + auto originalMenu = *pPlayer->PlayerTalkClass; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + Push(code); + auto preventDefault = CallAllFunctionsBool(CreatureGossipBindings, key, true); + if (!preventDefault) { + *pPlayer->PlayerTalkClass = originalMenu; + } + return preventDefault; +} diff --git a/modules/mod-eluna/src/LuaEngine/GroupHooks.cpp b/modules/mod-eluna/src/LuaEngine/GroupHooks.cpp new file mode 100644 index 0000000..f674957 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GroupHooks.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!GroupEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +void Eluna::OnAddMember(Group* group, ObjectGuid guid) +{ + START_HOOK(GROUP_EVENT_ON_MEMBER_ADD); + Push(group); + Push(guid); + CallAllFunctions(GroupEventBindings, key); +} + +void Eluna::OnInviteMember(Group* group, ObjectGuid guid) +{ + START_HOOK(GROUP_EVENT_ON_MEMBER_INVITE); + Push(group); + Push(guid); + CallAllFunctions(GroupEventBindings, key); +} + +void Eluna::OnRemoveMember(Group* group, ObjectGuid guid, uint8 method) +{ + START_HOOK(GROUP_EVENT_ON_MEMBER_REMOVE); + Push(group); + Push(guid); + Push(method); + CallAllFunctions(GroupEventBindings, key); +} + +void Eluna::OnChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid) +{ + START_HOOK(GROUP_EVENT_ON_LEADER_CHANGE); + Push(group); + Push(newLeaderGuid); + Push(oldLeaderGuid); + CallAllFunctions(GroupEventBindings, key); +} + +void Eluna::OnDisband(Group* group) +{ + START_HOOK(GROUP_EVENT_ON_DISBAND); + Push(group); + CallAllFunctions(GroupEventBindings, key); +} + +void Eluna::OnCreate(Group* group, ObjectGuid leaderGuid, GroupType groupType) +{ + START_HOOK(GROUP_EVENT_ON_CREATE); + Push(group); + Push(leaderGuid); + Push(groupType); + CallAllFunctions(GroupEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/GroupMethods.h b/modules/mod-eluna/src/LuaEngine/GroupMethods.h new file mode 100644 index 0000000..763c18a --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GroupMethods.h @@ -0,0 +1,464 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef GROUPMETHODS_H +#define GROUPMETHODS_H + +/*** + * Inherits all methods from: none + */ +namespace LuaGroup +{ + /** + * Returns 'true' if the [Player] is the [Group] leader + * + * @param ObjectGuid guid : guid of a possible leader + * @return bool isLeader + */ + int IsLeader(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, group->IsLeader(guid)); + return 1; + } + + /** + * Returns 'true' if the [Group] is full + * + * @return bool isFull + */ + int IsFull(lua_State* L, Group* group) + { + Eluna::Push(L, group->IsFull()); + return 1; + } + + /** + * Returns 'true' if the [Group] is a LFG group + * + * @return bool isLFGGroup + */ + int IsLFGGroup(lua_State* L, Group* group) + { + Eluna::Push(L, group->isLFGGroup()); + return 1; + } + + /** + * Returns 'true' if the [Group] is a raid [Group] + * + * @return bool isRaid + */ + int IsRaidGroup(lua_State* L, Group* group) + { + Eluna::Push(L, group->isRaidGroup()); + return 1; + } + + /** + * Returns 'true' if the [Group] is a battleground [Group] + * + * @return bool isBG + */ + int IsBGGroup(lua_State* L, Group* group) + { + Eluna::Push(L, group->isBGGroup()); + return 1; + } + + /** + * Returns 'true' if the [Player] is a member of this [Group] + * + * @param ObjectGuid guid : guid of a player + * @return bool isMember + */ + int IsMember(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, group->IsMember(guid)); + return 1; + } + + /** + * Returns 'true' if the [Player] is an assistant of this [Group] + * + * @param ObjectGuid guid : guid of a player + * @return bool isAssistant + */ + int IsAssistant(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, group->IsAssistant(guid)); + return 1; + } + + /** + * Returns 'true' if the [Player]s are in the same subgroup in this [Group] + * + * @param [Player] player1 : first [Player] to check + * @param [Player] player2 : second [Player] to check + * @return bool sameSubGroup + */ + int SameSubGroup(lua_State* L, Group* group) + { + Player* player1 = Eluna::CHECKOBJ(L, 2); + Player* player2 = Eluna::CHECKOBJ(L, 3); + Eluna::Push(L, group->SameSubGroup(player1, player2)); + return 1; + } + + /** + * Returns 'true' if the subgroup has free slots in this [Group] + * + * @param uint8 subGroup : subGroup ID to check + * @return bool hasFreeSlot + */ + int HasFreeSlotSubGroup(lua_State* L, Group* group) + { + uint8 subGroup = Eluna::CHECKVAL(L, 2); + + if (subGroup >= MAX_RAID_SUBGROUPS) + { + luaL_argerror(L, 2, "valid subGroup ID expected"); + return 0; + } + + Eluna::Push(L, group->HasFreeSlotSubGroup(subGroup)); + return 1; + } + + /** + * Adds a new member to the [Group] + * + * @param [Player] player : [Player] to add to the group + * @return bool added : true if member was added + */ + int AddMember(lua_State* L, Group* group) + { + Player* player = Eluna::CHECKOBJ(L, 2); + + if (player->GetGroup() || !group->IsCreated() || group->IsFull()) + { + Eluna::Push(L, false); + return 1; + } + + if (player->GetGroupInvite()) + player->UninviteFromGroup(); + +#if defined TRINITY || AZEROTHCORE + bool success = group->AddMember(player); + if (success) + group->BroadcastGroupUpdate(); +#else + bool success = group->AddMember(player->GetObjectGuid(), player->GetName()); +#endif + + Eluna::Push(L, success); + return 1; + } + + /*int IsLFGGroup(lua_State* L, Group* group) // TODO: Implementation + { + Eluna::Push(L, group->isLFGGroup()); + return 1; + }*/ + + /*int IsBFGroup(lua_State* L, Group* group) // TODO: Implementation + { + Eluna::Push(L, group->isBFGroup()); + return 1; + }*/ + + /** + * Returns a table with the [Player]s in this [Group] + * + * @return table groupPlayers : table of [Player]s + */ + int GetMembers(lua_State* L, Group* group) + { + lua_newtable(L); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (GroupReference* itr = group->GetFirstMember(); itr; itr = itr->next()) + { +#if defined TRINITY || AZEROTHCORE + Player* member = itr->GetSource(); +#else + Player* member = itr->getSource(); +#endif + + if (!member || !member->GetSession()) + continue; + + Eluna::Push(L, member); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); // push table to top of stack + return 1; + } + + /** + * Returns [Group] leader GUID + * + * @return ObjectGuid leaderGUID + */ + int GetLeaderGUID(lua_State* L, Group* group) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, group->GetLeaderGUID()); +#else + Eluna::Push(L, group->GetLeaderGuid()); +#endif + return 1; + } + + /** + * Returns the [Group]'s GUID + * + * @return ObjectGuid groupGUID + */ + int GetGUID(lua_State* L, Group* group) + { +#ifdef CLASSIC + Eluna::Push(L, group->GetId()); +#else + Eluna::Push(L, group->GET_GUID()); +#endif + return 1; + } + + /** + * Returns a [Group] member's GUID by their name + * + * @param string name : the [Player]'s name + * @return ObjectGuid memberGUID + */ + int GetMemberGUID(lua_State* L, Group* group) + { + const char* name = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, group->GetMemberGUID(name)); +#else + Eluna::Push(L, group->GetMemberGuid(name)); +#endif + return 1; + } + + /** + * Returns the member count of this [Group] + * + * @return uint32 memberCount + */ + int GetMembersCount(lua_State* L, Group* group) + { + Eluna::Push(L, group->GetMembersCount()); + return 1; + } + + /** + * Returns the type of this [Group] + * + *
+     * enum GroupType
+     * {
+     *     GROUPTYPE_NORMAL         = 0,
+     *     GROUPTYPE_BG             = 1,
+     *     GROUPTYPE_RAID           = 2,
+     *     GROUPTYPE_LFG_RESTRICTED = 4,
+     *     GROUPTYPE_LFG            = 8
+     * };
+     * 
+ * + * @return [GroupType] groupType + */ + int GetGroupType(lua_State* L, Group* group) + { + Eluna::Push(L, group->GetGroupType()); + return 1; + } + + /** + * Returns the [Player]'s subgroup ID of this [Group] + * + * @param ObjectGuid guid : guid of the player + * @return uint8 subGroupID : a valid subgroup ID or MAX_RAID_SUBGROUPS+1 + */ + int GetMemberGroup(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, group->GetMemberGroup(guid)); + return 1; + } + + /** + * Sets the leader of this [Group] + * + * @param ObjectGuid guid : guid of the new leader + */ + int SetLeader(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + group->ChangeLeader(guid); + group->SendUpdate(); + return 0; + } + + /** + * Sends a specified [WorldPacket] to this [Group] + * + * @param [WorldPacket] packet : the [WorldPacket] to send + * @param bool ignorePlayersInBg : ignores [Player]s in a battleground + * @param ObjectGuid ignore : ignore a [Player] by their GUID + */ + int SendPacket(lua_State* L, Group* group) + { + WorldPacket* data = Eluna::CHECKOBJ(L, 2); + bool ignorePlayersInBg = Eluna::CHECKVAL(L, 3); + ObjectGuid ignore = Eluna::CHECKVAL(L, 4); + +#ifdef CMANGOS + group->BroadcastPacket(*data, ignorePlayersInBg, -1, ignore); +#else + group->BroadcastPacket(data, ignorePlayersInBg, -1, ignore); +#endif + return 0; + } + + /** + * Removes a [Player] from this [Group] and returns 'true' if successful + * + *
+     * enum RemoveMethod
+     * {
+     *     GROUP_REMOVEMETHOD_DEFAULT  = 0,
+     *     GROUP_REMOVEMETHOD_KICK     = 1,
+     *     GROUP_REMOVEMETHOD_LEAVE    = 2,
+     *     GROUP_REMOVEMETHOD_KICK_LFG = 3
+     * };
+     * 
+ * + * @param ObjectGuid guid : guid of the player to remove + * @param [RemoveMethod] method : method used to remove the player + * @return bool removed + */ + int RemoveMember(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + uint32 method = Eluna::CHECKVAL(L, 3, 0); + +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, group->RemoveMember(guid, (RemoveMethod)method)); +#else + Eluna::Push(L, group->RemoveMember(guid, method)); +#endif + return 1; + } + + /** + * Disbands this [Group] + * + */ + int Disband(lua_State* /*L*/, Group* group) + { + group->Disband(); + return 0; + } + + /** + * Converts this [Group] to a raid [Group] + * + */ + int ConvertToRaid(lua_State* /*L*/, Group* group) + { + group->ConvertToRaid(); + return 0; + } + + /** + * Sets the member's subGroup + * + * @param ObjectGuid guid : guid of the player to move + * @param uint8 groupID : the subGroup's ID + */ + int SetMembersGroup(lua_State* L, Group* group) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + uint8 subGroup = Eluna::CHECKVAL(L, 3); + + if (subGroup >= MAX_RAID_SUBGROUPS) + { + luaL_argerror(L, 3, "valid subGroup ID expected"); + return 0; + } + + if (!group->HasFreeSlotSubGroup(subGroup)) + return 0; + + group->ChangeMembersGroup(guid, subGroup); + return 0; + } + + /** + * Sets the target icon of an object for the [Group] + * + * @param uint8 icon : the icon (Skull, Square, etc) + * @param ObjectGuid target : GUID of the icon target, 0 is to clear the icon + * @param ObjectGuid setter : GUID of the icon setter + */ + int SetTargetIcon(lua_State* L, Group* group) + { + uint8 icon = Eluna::CHECKVAL(L, 2); + ObjectGuid target = Eluna::CHECKVAL(L, 3); + ObjectGuid setter = Eluna::CHECKVAL(L, 4, ObjectGuid()); + + if (icon >= TARGETICONCOUNT) + return luaL_argerror(L, 2, "valid target icon expected"); + +#if (defined(CLASSIC) || defined(TBC)) + group->SetTargetIcon(icon, target); +#else + group->SetTargetIcon(icon, setter, target); +#endif + return 0; + } + + /** + * Sets or removes a flag for a [Group] member + * + *
+     * enum GroupMemberFlags
+     * {
+     *     MEMBER_FLAG_ASSISTANT   = 0x01,
+     *     MEMBER_FLAG_MAINTANK    = 0x02,
+     *     MEMBER_FLAG_MAINASSIST  = 0x04,
+     * };
+     * 
+ * + * @param ObjectGuid target : GUID of the target + * @param bool apply : add the `flag` if `true`, remove the `flag` otherwise + * @param [GroupMemberFlags] flag : the flag to set or unset + */ + int SetMemberFlag(lua_State* L, Group* group) + { + ObjectGuid target = Eluna::CHECKVAL(L, 2); + bool apply = Eluna::CHECKVAL(L, 3); + GroupMemberFlags flag = static_cast(Eluna::CHECKVAL(L, 4)); + + group->SetGroupMemberFlag(target, apply, flag); + return 0; + } + + /*int ConvertToLFG(lua_State* L, Group* group) // TODO: Implementation + { + group->ConvertToLFG(); + return 0; + }*/ +}; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/GuildHooks.cpp b/modules/mod-eluna/src/LuaEngine/GuildHooks.cpp new file mode 100644 index 0000000..3662ef1 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GuildHooks.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!GuildEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank) +{ + START_HOOK(GUILD_EVENT_ON_ADD_MEMBER); + Push(guild); + Push(player); + Push(plRank); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding) +{ + START_HOOK(GUILD_EVENT_ON_REMOVE_MEMBER); + Push(guild); + Push(player); + Push(isDisbanding); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd) +{ + START_HOOK(GUILD_EVENT_ON_MOTD_CHANGE); + Push(guild); + Push(newMotd); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo) +{ + START_HOOK(GUILD_EVENT_ON_INFO_CHANGE); + Push(guild); + Push(newInfo); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name) +{ + START_HOOK(GUILD_EVENT_ON_CREATE); + Push(guild); + Push(leader); + Push(name); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnDisband(Guild* guild) +{ + START_HOOK(GUILD_EVENT_ON_DISBAND); + Push(guild); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) +{ + START_HOOK(GUILD_EVENT_ON_MONEY_WITHDRAW); + Push(guild); + Push(player); + Push(amount); + Push(isRepair); // isRepair not a part of Mangos, implement? + int amountIndex = lua_gettop(L) - 1; + int n = SetupStack(GuildEventBindings, key, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(4); +} + +void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) +{ + START_HOOK(GUILD_EVENT_ON_MONEY_DEPOSIT); + Push(guild); + Push(player); + Push(amount); + int amountIndex = lua_gettop(L); + int n = SetupStack(GuildEventBindings, key, 3); + + while (n > 0) + { + int r = CallOneFunction(n--, 3, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(3); +} + +void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, + bool isDestBank, uint8 destContainer, uint8 destSlotId) +{ + START_HOOK(GUILD_EVENT_ON_ITEM_MOVE); + Push(guild); + Push(player); + Push(pItem); + Push(isSrcBank); + Push(srcContainer); + Push(srcSlotId); + Push(isDestBank); + Push(destContainer); + Push(destSlotId); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) +{ + START_HOOK(GUILD_EVENT_ON_EVENT); + Push(guild); + Push(eventType); + Push(playerGuid1); + Push(playerGuid2); + Push(newRank); + CallAllFunctions(GuildEventBindings, key); +} + +void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) +{ + START_HOOK(GUILD_EVENT_ON_BANK_EVENT); + Push(guild); + Push(eventType); + Push(tabId); + Push(playerGuid); + Push(itemOrMoney); + Push(itemStackCount); + Push(destTabId); + CallAllFunctions(GuildEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/GuildMethods.h b/modules/mod-eluna/src/LuaEngine/GuildMethods.h new file mode 100644 index 0000000..ba9863f --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/GuildMethods.h @@ -0,0 +1,305 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef GUILDMETHODS_H +#define GUILDMETHODS_H + +/*** + * Inherits all methods from: none + */ +namespace LuaGuild +{ + /** + * Returns a table with the [Player]s in this [Guild] + * + * Only the players that are online and on some map. + * + * @return table guildPlayers : table of [Player]s + */ + int GetMembers(lua_State* L, Guild* guild) + { + lua_newtable(L); + int tbl = lua_gettop(L); + uint32 i = 0; + +#if defined(MANGOS) + eObjectAccessor()DoForAllPlayers([&](Player* player) + { + if (player->IsInWorld() && player->GetGuildId() == guild->GetId()) + { + Eluna::Push(L, player); + lua_rawseti(L, tbl, ++i); + } + }); +#else + { +#if defined TRINITY || AZEROTHCORE + std::shared_lock lock(*HashMapHolder::GetLock()); +#else + HashMapHolder::ReadGuard g(HashMapHolder::GetLock()); +#endif + const HashMapHolder::MapType& m = eObjectAccessor()GetPlayers(); + for (HashMapHolder::MapType::const_iterator it = m.begin(); it != m.end(); ++it) + { + if (Player* player = it->second) + { + if (player->IsInWorld() && player->GetGuildId() == guild->GetId()) + { + Eluna::Push(L, player); + lua_rawseti(L, tbl, ++i); + } + } + } + } +#endif + lua_settop(L, tbl); // push table to top of stack + return 1; + } + + /** + * Returns the member count of this [Guild] + * + * @return uint32 memberCount + */ + int GetMemberCount(lua_State* L, Guild* guild) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, guild->GetMemberCount()); +#else + Eluna::Push(L, guild->GetMemberSize()); +#endif + return 1; + } + + /** + * Finds and returns the [Guild] leader by their GUID if logged in + * + * @return [Player] leader + */ + int GetLeader(lua_State* L, Guild* guild) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, eObjectAccessor()FindPlayer(guild->GetLeaderGUID())); +#else + Eluna::Push(L, eObjectAccessor()FindPlayer(guild->GetLeaderGuid())); +#endif + return 1; + } + + /** + * Returns [Guild] leader GUID + * + * @return ObjectGuid leaderGUID + */ + int GetLeaderGUID(lua_State* L, Guild* guild) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, guild->GetLeaderGUID()); +#else + Eluna::Push(L, guild->GetLeaderGuid()); +#endif + return 1; + } + + /** + * Returns the [Guild]s entry ID + * + * @return uint32 entryId + */ + int GetId(lua_State* L, Guild* guild) + { + Eluna::Push(L, guild->GetId()); + return 1; + } + + /** + * Returns the [Guild]s name + * + * @return string guildName + */ + int GetName(lua_State* L, Guild* guild) + { + Eluna::Push(L, guild->GetName()); + return 1; + } + + /** + * Returns the [Guild]s current Message Of The Day + * + * @return string guildMOTD + */ + int GetMOTD(lua_State* L, Guild* guild) + { + Eluna::Push(L, guild->GetMOTD()); + return 1; + } + + /** + * Returns the [Guild]s current info + * + * @return string guildInfo + */ + int GetInfo(lua_State* L, Guild* guild) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, guild->GetInfo()); +#else + Eluna::Push(L, guild->GetGINFO()); +#endif + return 1; + } + +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + /** + * Sets the leader of this [Guild] + * + * @param [Player] leader : the [Player] leader to change + */ + int SetLeader(lua_State* L, Guild* guild) + { + Player* player = Eluna::CHECKOBJ(L, 2); + +#if defined TRINITY || AZEROTHCORE + guild->HandleSetLeader(player->GetSession(), player->GetName()); +#else + guild->SetLeader(player->GET_GUID()); +#endif + return 0; + } +#endif + +#ifndef CLASSIC + /** + * Sets the information of the bank tab specified + * + * @param uint8 tabId : the ID of the tab specified + * @param string info : the information to be set to the bank tab + */ + int SetBankTabText(lua_State* L, Guild* guild) + { + uint8 tabId = Eluna::CHECKVAL(L, 2); + const char* text = Eluna::CHECKVAL(L, 3); +#if defined TRINITY || AZEROTHCORE + guild->SetBankTabText(tabId, text); +#else + guild->SetGuildBankTabText(tabId, text); +#endif + return 0; + } +#endif + + // SendPacketToGuild(packet) + /** + * Sends a [WorldPacket] to all the [Player]s in the [Guild] + * + * @param [WorldPacket] packet : the [WorldPacket] to be sent to the [Player]s + */ + int SendPacket(lua_State* L, Guild* guild) + { + WorldPacket* data = Eluna::CHECKOBJ(L, 2); + +#ifdef CMANGOS + guild->BroadcastPacket(*data); +#else + guild->BroadcastPacket(data); +#endif + return 0; + } + + // SendPacketToRankedInGuild(packet, rankId) + /** + * Sends a [WorldPacket] to all the [Player]s at the specified rank in the [Guild] + * + * @param [WorldPacket] packet : the [WorldPacket] to be sent to the [Player]s + * @param uint8 rankId : the rank ID + */ + int SendPacketToRanked(lua_State* L, Guild* guild) + { + WorldPacket* data = Eluna::CHECKOBJ(L, 2); + uint8 ranked = Eluna::CHECKVAL(L, 3); + +#ifdef CMANGOS + guild->BroadcastPacketToRank(*data, ranked); +#else + guild->BroadcastPacketToRank(data, ranked); +#endif + return 0; + } + + /** + * Disbands the [Guild] + */ + int Disband(lua_State* /*L*/, Guild* guild) + { + guild->Disband(); + return 0; + } + + /** + * Adds the specified [Player] to the [Guild] at the specified rank. + * + * If no rank is specified, defaults to none. + * + * @param [Player] player : the [Player] to be added to the guild + * @param uint8 rankId : the rank ID + */ + int AddMember(lua_State* L, Guild* guild) + { + Player* player = Eluna::CHECKOBJ(L, 2); + uint8 rankId = Eluna::CHECKVAL(L, 3, GUILD_RANK_NONE); + +#ifdef TRINITY + CharacterDatabaseTransaction trans(nullptr); + guild->AddMember(trans, player->GET_GUID(), rankId); +#else + guild->AddMember(player->GET_GUID(), rankId); +#endif + return 0; + } + + /** + * Removes the specified [Player] from the [Guild]. + * + * @param [Player] player : the [Player] to be removed from the guild + * @param bool isDisbanding : default 'false', should only be set to 'true' if the guild is triggered to disband + */ + int DeleteMember(lua_State* L, Guild* guild) + { + Player* player = Eluna::CHECKOBJ(L, 2); + bool isDisbanding = Eluna::CHECKVAL(L, 3, false); + +#if defined TRINITY + CharacterDatabaseTransaction trans(nullptr); + guild->DeleteMember(trans, player->GET_GUID(), isDisbanding); +#elif defined AZEROTHCORE + guild->DeleteMember(player->GET_GUID(), isDisbanding); +#else + guild->DelMember(player->GET_GUID(), isDisbanding); +#endif + return 0; + } + + /** + * Promotes/demotes the [Player] to the specified rank. + * + * @param [Player] player : the [Player] to be promoted/demoted + * @param uint8 rankId : the rank ID + */ + int SetMemberRank(lua_State* L, Guild* guild) + { + Player* player = Eluna::CHECKOBJ(L, 2); + uint8 newRank = Eluna::CHECKVAL(L, 3); + +#ifdef TRINITY + CharacterDatabaseTransaction trans(nullptr); + guild->ChangeMemberRank(trans, player->GET_GUID(), newRank); +#else + guild->ChangeMemberRank(player->GET_GUID(), newRank); +#endif + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/HookHelpers.h b/modules/mod-eluna/src/LuaEngine/HookHelpers.h new file mode 100644 index 0000000..9dd0f26 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/HookHelpers.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _HOOK_HELPERS_H +#define _HOOK_HELPERS_H + +#include "LuaEngine.h" +#include "ElunaUtility.h" + +/* + * Sets up the stack so that event handlers can be called. + * + * Returns the number of functions that were pushed onto the stack. + */ +template +int Eluna::SetupStack(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, int number_of_arguments) +{ + ASSERT(number_of_arguments == this->push_counter); + ASSERT(key1.event_id == key2.event_id); + // Stack: [arguments] + + Push(key1.event_id); + this->push_counter = 0; + ++number_of_arguments; + // Stack: [arguments], event_id + + int arguments_top = lua_gettop(L); + int first_argument_index = arguments_top - number_of_arguments + 1; + ASSERT(arguments_top >= number_of_arguments); + + lua_insert(L, first_argument_index); + // Stack: event_id, [arguments] + + bindings1->PushRefsFor(key1); + if (bindings2) + bindings2->PushRefsFor(key2); + // Stack: event_id, [arguments], [functions] + + int number_of_functions = lua_gettop(L) - arguments_top; + return number_of_functions; +} + +/* + * Replace one of the arguments pushed before `SetupStack` with a new value. + */ +template +void Eluna::ReplaceArgument(T value, uint8 index) +{ + ASSERT(index < lua_gettop(L) && index > 0); + // Stack: event_id, [arguments], [functions], [results] + + Eluna::Push(L, value); + // Stack: event_id, [arguments], [functions], [results], value + + lua_replace(L, index + 1); + // Stack: event_id, [arguments and value], [functions], [results] +} + +/* + * Call all event handlers registered to the event ID/entry combination and ignore any results. + */ +template +void Eluna::CallAllFunctions(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2) +{ + int number_of_arguments = this->push_counter; + // Stack: [arguments] + + int number_of_functions = SetupStack(bindings1, bindings2, key1, key2, number_of_arguments); + // Stack: event_id, [arguments], [functions] + + while (number_of_functions > 0) + { + CallOneFunction(number_of_functions, number_of_arguments, 0); + --number_of_functions; + // Stack: event_id, [arguments], [functions - 1] + } + // Stack: event_id, [arguments] + + CleanUpStack(number_of_arguments); + // Stack: (empty) +} + +/* + * Call all event handlers registered to the event ID/entry combination, + * and returns `default_value` if ALL event handlers returned `default_value`, + * otherwise returns the opposite of `default_value`. + */ +template +bool Eluna::CallAllFunctionsBool(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, bool default_value/* = false*/) +{ + bool result = default_value; + // Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack + int number_of_arguments = this->push_counter; + // Stack: [arguments] + + int number_of_functions = SetupStack(bindings1, bindings2, key1, key2, number_of_arguments); + // Stack: event_id, [arguments], [functions] + + while (number_of_functions > 0) + { + int r = CallOneFunction(number_of_functions, number_of_arguments, 1); + --number_of_functions; + // Stack: event_id, [arguments], [functions - 1], result + + if (lua_isboolean(L, r) && (lua_toboolean(L, r) == 1) != default_value) + result = !default_value; + + lua_pop(L, 1); + // Stack: event_id, [arguments], [functions - 1] + } + // Stack: event_id, [arguments] + + CleanUpStack(number_of_arguments); + // Stack: (empty) + return result; +} + +#endif // _HOOK_HELPERS_H diff --git a/modules/mod-eluna/src/LuaEngine/Hooks.h b/modules/mod-eluna/src/LuaEngine/Hooks.h new file mode 100644 index 0000000..f368317 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/Hooks.h @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _HOOKS_H +#define _HOOKS_H + +/* + * A hook should be written in one of the following forms: + * + * A. If results will be IGNORED: + * + * // Return early if there are no bindings. + * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE)) + * return; + * + * // Lock out any other threads. + * LOCK_ELUNA; + * + * // Push extra arguments, if any. + * Push(a); + * Push(b); + * Push(c); + * + * // Call all event handlers. + * CallAllFunctions(WhateverBindings, SOME_EVENT_TYPE); + * + * + * B. If results will be USED: + * + * // Return early if there are no bindings. + * if (!WhateverBindings->HasBindingsFor(SOME_EVENT_TYPE)) + * return; + * + * // Lock out any other threads. + * LOCK_ELUNA; + * + * // Push extra arguments, if any. + * Push(a); + * Push(b); + * Push(c); + * + * // Setup the stack and get the number of functions pushed. + * // Last argument is 3 because we did 3 Pushes. + * int n = SetupStack(WhateverBindings, SOME_EVENT_TYPE, 3); + * + * // Call each event handler in order and check results. + * while (n > 0) + * { + * // Call an event handler and decrement the function counter afterward. + * // Second-last argument is 3 because we did 3 Pushes. + * // Last argument is 2 because we want 2 results. + * int r = CallOneFunction(n--, 3, 2); + * + * // Results can be popped using `r`. + * int first = CHECKVAL(L, r + 0); + * int second = CHECKVAL(L, r + 1); + * + * // Pop the results off the stack. + * lua_pop(L, 2); + * } + * + * // Clean-up the stack. Argument is 3 because we did 3 Pushes. + * CleanUpStack(3); + */ + +namespace Hooks +{ + enum RegisterTypes + { + REGTYPE_PACKET, + REGTYPE_SERVER, + REGTYPE_PLAYER, + REGTYPE_GUILD, + REGTYPE_GROUP, + REGTYPE_CREATURE, + REGTYPE_VEHICLE, + REGTYPE_CREATURE_GOSSIP, + REGTYPE_GAMEOBJECT, + REGTYPE_GAMEOBJECT_GOSSIP, + REGTYPE_ITEM, + REGTYPE_ITEM_GOSSIP, + REGTYPE_PLAYER_GOSSIP, + REGTYPE_BG, + REGTYPE_MAP, + REGTYPE_INSTANCE, + REGTYPE_COUNT + }; + + enum PacketEvents + { + PACKET_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket + PACKET_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented + PACKET_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false, newPacket + + PACKET_EVENT_COUNT + }; + + enum ServerEvents + { + // Server + SERVER_EVENT_ON_NETWORK_START = 1, // Not Implemented + SERVER_EVENT_ON_NETWORK_STOP = 2, // Not Implemented + SERVER_EVENT_ON_SOCKET_OPEN = 3, // Not Implemented + SERVER_EVENT_ON_SOCKET_CLOSE = 4, // Not Implemented + SERVER_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket + SERVER_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented + SERVER_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false, newPacket + + // World + WORLD_EVENT_ON_OPEN_STATE_CHANGE = 8, // (event, open) - Needs core support on Mangos + WORLD_EVENT_ON_CONFIG_LOAD = 9, // (event, reload) + // UNUSED = 10, + WORLD_EVENT_ON_SHUTDOWN_INIT = 11, // (event, code, mask) + WORLD_EVENT_ON_SHUTDOWN_CANCEL = 12, // (event) + WORLD_EVENT_ON_UPDATE = 13, // (event, diff) + WORLD_EVENT_ON_STARTUP = 14, // (event) + WORLD_EVENT_ON_SHUTDOWN = 15, // (event) + + // Eluna + ELUNA_EVENT_ON_LUA_STATE_CLOSE = 16, // (event) - triggers just before shutting down eluna (on shutdown and restart) + + // Map + MAP_EVENT_ON_CREATE = 17, // (event, map) + MAP_EVENT_ON_DESTROY = 18, // (event, map) + MAP_EVENT_ON_GRID_LOAD = 19, // Not Implemented + MAP_EVENT_ON_GRID_UNLOAD = 20, // Not Implemented + MAP_EVENT_ON_PLAYER_ENTER = 21, // (event, map, player) + MAP_EVENT_ON_PLAYER_LEAVE = 22, // (event, map, player) + MAP_EVENT_ON_UPDATE = 23, // (event, map, diff) + + // Area trigger + TRIGGER_EVENT_ON_TRIGGER = 24, // (event, player, triggerId) - Can return true + + // Weather + WEATHER_EVENT_ON_CHANGE = 25, // (event, zoneId, state, grade) + + // Auction house + AUCTION_EVENT_ON_ADD = 26, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + AUCTION_EVENT_ON_REMOVE = 27, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + AUCTION_EVENT_ON_SUCCESSFUL = 28, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + AUCTION_EVENT_ON_EXPIRE = 29, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow) + + // AddOns + ADDON_EVENT_ON_MESSAGE = 30, // (event, sender, type, prefix, msg, target) - target can be nil/whisper_target/guild/group/channel. Can return false + + WORLD_EVENT_ON_DELETE_CREATURE = 31, // (event, creature) + WORLD_EVENT_ON_DELETE_GAMEOBJECT = 32, // (event, gameobject) + + // Eluna + ELUNA_EVENT_ON_LUA_STATE_OPEN = 33, // (event) - triggers after all scripts are loaded + + GAME_EVENT_START = 34, // (event, gameeventid) + GAME_EVENT_STOP = 35, // (event, gameeventid) + + SERVER_EVENT_COUNT + }; + + enum PlayerEvents + { + PLAYER_EVENT_ON_CHARACTER_CREATE = 1, // (event, player) + PLAYER_EVENT_ON_CHARACTER_DELETE = 2, // (event, guid) + PLAYER_EVENT_ON_LOGIN = 3, // (event, player) + PLAYER_EVENT_ON_LOGOUT = 4, // (event, player) + PLAYER_EVENT_ON_SPELL_CAST = 5, // (event, player, spell, skipCheck) + PLAYER_EVENT_ON_KILL_PLAYER = 6, // (event, killer, killed) + PLAYER_EVENT_ON_KILL_CREATURE = 7, // (event, killer, killed) + PLAYER_EVENT_ON_KILLED_BY_CREATURE = 8, // (event, killer, killed) + PLAYER_EVENT_ON_DUEL_REQUEST = 9, // (event, target, challenger) + PLAYER_EVENT_ON_DUEL_START = 10, // (event, player1, player2) + PLAYER_EVENT_ON_DUEL_END = 11, // (event, winner, loser, type) + PLAYER_EVENT_ON_GIVE_XP = 12, // (event, player, amount, victim, source) - Can return new XP amount + PLAYER_EVENT_ON_LEVEL_CHANGE = 13, // (event, player, oldLevel) + PLAYER_EVENT_ON_MONEY_CHANGE = 14, // (event, player, amount) - Can return new money amount + PLAYER_EVENT_ON_REPUTATION_CHANGE = 15, // (event, player, factionId, standing, incremental) - Can return new standing -> if standing == -1, it will prevent default action (rep gain) + PLAYER_EVENT_ON_TALENTS_CHANGE = 16, // (event, player, points) + PLAYER_EVENT_ON_TALENTS_RESET = 17, // (event, player, noCost) + PLAYER_EVENT_ON_CHAT = 18, // (event, player, msg, Type, lang) - Can return false, newMessage + PLAYER_EVENT_ON_WHISPER = 19, // (event, player, msg, Type, lang, receiver) - Can return false, newMessage + PLAYER_EVENT_ON_GROUP_CHAT = 20, // (event, player, msg, Type, lang, group) - Can return false, newMessage + PLAYER_EVENT_ON_GUILD_CHAT = 21, // (event, player, msg, Type, lang, guild) - Can return false, newMessage + PLAYER_EVENT_ON_CHANNEL_CHAT = 22, // (event, player, msg, Type, lang, channel) - channel is negative for custom channels. Can return false, newMessage + PLAYER_EVENT_ON_EMOTE = 23, // (event, player, emote) - Not triggered on any known emote + PLAYER_EVENT_ON_TEXT_EMOTE = 24, // (event, player, textEmote, emoteNum, guid) + PLAYER_EVENT_ON_SAVE = 25, // (event, player) + PLAYER_EVENT_ON_BIND_TO_INSTANCE = 26, // (event, player, difficulty, mapid, permanent) + PLAYER_EVENT_ON_UPDATE_ZONE = 27, // (event, player, newZone, newArea) + PLAYER_EVENT_ON_MAP_CHANGE = 28, // (event, player) + + // Custom + PLAYER_EVENT_ON_EQUIP = 29, // (event, player, item, bag, slot) + PLAYER_EVENT_ON_FIRST_LOGIN = 30, // (event, player) + PLAYER_EVENT_ON_CAN_USE_ITEM = 31, // (event, player, itemEntry) - Can return InventoryResult enum value + PLAYER_EVENT_ON_LOOT_ITEM = 32, // (event, player, item, count) + PLAYER_EVENT_ON_ENTER_COMBAT = 33, // (event, player, enemy) + PLAYER_EVENT_ON_LEAVE_COMBAT = 34, // (event, player) + PLAYER_EVENT_ON_REPOP = 35, // (event, player) + PLAYER_EVENT_ON_RESURRECT = 36, // (event, player) + PLAYER_EVENT_ON_LOOT_MONEY = 37, // (event, player, amount) + PLAYER_EVENT_ON_QUEST_ABANDON = 38, // (event, player, questId) + PLAYER_EVENT_ON_LEARN_TALENTS = 39, // (event, player, talentId, talentRank, spellid) + // UNUSED = 40, // (event, player) + // UNUSED = 41, // (event, player) + PLAYER_EVENT_ON_COMMAND = 42, // (event, player, command, chatHandler) - player is nil if command used from console. Can return false + PLAYER_EVENT_ON_PET_ADDED_TO_WORLD = 43, // (event, player, pet) + PLAYER_EVENT_ON_LEARN_SPELL = 44, // (event, player, spellId) + PLAYER_EVENT_ON_ACHIEVEMENT_COMPLETE = 45, // (event, player, achievement) + PLAYER_EVENT_ON_FFAPVP_CHANGE = 46, // (event, player, hasFfaPvp) + PLAYER_EVENT_ON_UPDATE_AREA = 47, // (event, player, oldArea, newArea) + PLAYER_EVENT_ON_CAN_INIT_TRADE = 48, // (event, player, target) - Can return false to prevent the trade + PLAYER_EVENT_ON_CAN_SEND_MAIL = 49, // (event, player, receiverGuid, mailbox, subject, body, money, cod, item) - Can return false to prevent sending the mail + PLAYER_EVENT_ON_CAN_JOIN_LFG = 50, // (event, player, roles, dungeons, comment) - Can return false to prevent queueing + PLAYER_EVENT_ON_QUEST_REWARD_ITEM = 51, // (event, player, item, count) + PLAYER_EVENT_ON_CREATE_ITEM = 52, // (event, player, item, count) + PLAYER_EVENT_ON_STORE_NEW_ITEM = 53, // (event, player, item, count) + PLAYER_EVENT_ON_COMPLETE_QUEST = 54, // (event, player, quest) + PLAYER_EVENT_ON_CAN_GROUP_INVITE = 55, // (event, player, memberName) - Can return false to prevent inviting + PLAYER_EVENT_ON_GROUP_ROLL_REWARD_ITEM = 56, // (event, player, item, count, voteType, roll) + PLAYER_EVENT_ON_BG_DESERTION = 57, // (event, player, type) + + PLAYER_EVENT_COUNT + }; + + enum GuildEvents + { + // Guild + GUILD_EVENT_ON_ADD_MEMBER = 1, // (event, guild, player, rank) + GUILD_EVENT_ON_REMOVE_MEMBER = 2, // (event, guild, player, isDisbanding) + GUILD_EVENT_ON_MOTD_CHANGE = 3, // (event, guild, newMotd) + GUILD_EVENT_ON_INFO_CHANGE = 4, // (event, guild, newInfo) + GUILD_EVENT_ON_CREATE = 5, // (event, guild, leader, name) // Not on TC + GUILD_EVENT_ON_DISBAND = 6, // (event, guild) + GUILD_EVENT_ON_MONEY_WITHDRAW = 7, // (event, guild, player, amount, isRepair) - Can return new money amount + GUILD_EVENT_ON_MONEY_DEPOSIT = 8, // (event, guild, player, amount) - Can return new money amount + GUILD_EVENT_ON_ITEM_MOVE = 9, // (event, guild, player, item, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId) // TODO + GUILD_EVENT_ON_EVENT = 10, // (event, guild, eventType, plrGUIDLow1, plrGUIDLow2, newRank) // TODO + GUILD_EVENT_ON_BANK_EVENT = 11, // (event, guild, eventType, tabId, playerGUIDLow, itemOrMoney, itemStackCount, destTabId) + + GUILD_EVENT_COUNT + }; + + enum GroupEvents + { + // Group + GROUP_EVENT_ON_MEMBER_ADD = 1, // (event, group, guid) + GROUP_EVENT_ON_MEMBER_INVITE = 2, // (event, group, guid) + GROUP_EVENT_ON_MEMBER_REMOVE = 3, // (event, group, guid, method, kicker, reason) + GROUP_EVENT_ON_LEADER_CHANGE = 4, // (event, group, newLeaderGuid, oldLeaderGuid) + GROUP_EVENT_ON_DISBAND = 5, // (event, group) + GROUP_EVENT_ON_CREATE = 6, // (event, group, leaderGuid, groupType) + + GROUP_EVENT_COUNT + }; + + enum VehicleEvents + { + VEHICLE_EVENT_ON_INSTALL = 1, // (event, vehicle) + VEHICLE_EVENT_ON_UNINSTALL = 2, // (event, vehicle) + // UNUSED = 3, // (event, vehicle) + VEHICLE_EVENT_ON_INSTALL_ACCESSORY = 4, // (event, vehicle, creature) + VEHICLE_EVENT_ON_ADD_PASSENGER = 5, // (event, vehicle, unit, seatId) + VEHICLE_EVENT_ON_REMOVE_PASSENGER = 6, // (event, vehicle, unit) + + VEHICLE_EVENT_COUNT + }; + + enum CreatureEvents + { + CREATURE_EVENT_ON_ENTER_COMBAT = 1, // (event, creature, target) - Can return true to stop normal action + CREATURE_EVENT_ON_LEAVE_COMBAT = 2, // (event, creature) - Can return true to stop normal action + CREATURE_EVENT_ON_TARGET_DIED = 3, // (event, creature, victim) - Can return true to stop normal action + CREATURE_EVENT_ON_DIED = 4, // (event, creature, killer) - Can return true to stop normal action + CREATURE_EVENT_ON_SPAWN = 5, // (event, creature) - Can return true to stop normal action + CREATURE_EVENT_ON_REACH_WP = 6, // (event, creature, type, id) - Can return true to stop normal action + CREATURE_EVENT_ON_AIUPDATE = 7, // (event, creature, diff) - Can return true to stop normal action + CREATURE_EVENT_ON_RECEIVE_EMOTE = 8, // (event, creature, player, emoteid) - Can return true to stop normal action + CREATURE_EVENT_ON_DAMAGE_TAKEN = 9, // (event, creature, attacker, damage) - Can return true to stop normal action, can return new damage as second return value. + CREATURE_EVENT_ON_PRE_COMBAT = 10, // (event, creature, target) - Can return true to stop normal action + // UNUSED + CREATURE_EVENT_ON_OWNER_ATTACKED = 12, // (event, creature, target) - Can return true to stop normal action // Not on mangos + CREATURE_EVENT_ON_OWNER_ATTACKED_AT = 13, // (event, creature, attacker) - Can return true to stop normal action // Not on mangos + CREATURE_EVENT_ON_HIT_BY_SPELL = 14, // (event, creature, caster, spellid) - Can return true to stop normal action + CREATURE_EVENT_ON_SPELL_HIT_TARGET = 15, // (event, creature, target, spellid) - Can return true to stop normal action + // UNUSED = 16, // (event, creature) + // UNUSED = 17, // (event, creature) + // UNUSED = 18, // (event, creature) + CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE = 19, // (event, creature, summon) - Can return true to stop normal action + CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN = 20, // (event, creature, summon) - Can return true to stop normal action + CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED = 21, // (event, creature, summon, killer) - Can return true to stop normal action // Not on mangos + CREATURE_EVENT_ON_SUMMONED = 22, // (event, creature, summoner) - Can return true to stop normal action + CREATURE_EVENT_ON_RESET = 23, // (event, creature) + CREATURE_EVENT_ON_REACH_HOME = 24, // (event, creature) - Can return true to stop normal action + // UNUSED = 25, // (event, creature) + CREATURE_EVENT_ON_CORPSE_REMOVED = 26, // (event, creature, respawndelay) - Can return true to stop normal action, can return new respawndelay as second return value + CREATURE_EVENT_ON_MOVE_IN_LOS = 27, // (event, creature, unit) - Can return true to stop normal action. Does not actually check LOS, just uses the sight range + // UNUSED = 28, // (event, creature) + // UNUSED = 29, // (event, creature) + CREATURE_EVENT_ON_DUMMY_EFFECT = 30, // (event, caster, spellid, effindex, creature) + CREATURE_EVENT_ON_QUEST_ACCEPT = 31, // (event, player, creature, quest) - Can return true + // UNUSED = 32, // (event, creature) + // UNUSED = 33, // (event, creature) + CREATURE_EVENT_ON_QUEST_REWARD = 34, // (event, player, creature, quest, opt) - Can return true + CREATURE_EVENT_ON_DIALOG_STATUS = 35, // (event, player, creature) + CREATURE_EVENT_ON_ADD = 36, // (event, creature) + CREATURE_EVENT_ON_REMOVE = 37, // (event, creature) + CREATURE_EVENT_COUNT + }; + + enum GameObjectEvents + { + GAMEOBJECT_EVENT_ON_AIUPDATE = 1, // (event, go, diff) + GAMEOBJECT_EVENT_ON_SPAWN = 2, // (event, go) + GAMEOBJECT_EVENT_ON_DUMMY_EFFECT = 3, // (event, caster, spellid, effindex, go) - Can return true to stop normal action + GAMEOBJECT_EVENT_ON_QUEST_ACCEPT = 4, // (event, player, go, quest) - Can return true to stop normal action + GAMEOBJECT_EVENT_ON_QUEST_REWARD = 5, // (event, player, go, quest, opt) - Can return true to stop normal action + GAMEOBJECT_EVENT_ON_DIALOG_STATUS = 6, // (event, player, go) + GAMEOBJECT_EVENT_ON_DESTROYED = 7, // (event, go, attacker) + GAMEOBJECT_EVENT_ON_DAMAGED = 8, // (event, go, attacker) + GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE = 9, // (event, go, state) + GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED = 10, // (event, go, state) + // UNUSED = 11, // (event, gameobject) + GAMEOBJECT_EVENT_ON_ADD = 12, // (event, gameobject) + GAMEOBJECT_EVENT_ON_REMOVE = 13, // (event, gameobject) + GAMEOBJECT_EVENT_ON_USE = 14, // (event, go, player) - Can return true to stop normal action + GAMEOBJECT_EVENT_COUNT + }; + + enum ItemEvents + { + ITEM_EVENT_ON_DUMMY_EFFECT = 1, // (event, caster, spellid, effindex, item) + ITEM_EVENT_ON_USE = 2, // (event, player, item, target) - Can return false to stop the spell casting + ITEM_EVENT_ON_QUEST_ACCEPT = 3, // (event, player, item, quest) - Can return true + ITEM_EVENT_ON_EXPIRE = 4, // (event, player, itemid) - Can return true + ITEM_EVENT_ON_REMOVE = 5, // (event, player, item) - Can return true + ITEM_EVENT_COUNT + }; + + enum GossipEvents + { + GOSSIP_EVENT_ON_HELLO = 1, // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting. + GOSSIP_EVENT_ON_SELECT = 2, // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action. + GOSSIP_EVENT_COUNT + }; + + enum BGEvents + { + BG_EVENT_ON_START = 1, // (event, bg, bgId, instanceId) - Needs to be added to TC + BG_EVENT_ON_END = 2, // (event, bg, bgId, instanceId, winner) - Needs to be added to TC + BG_EVENT_ON_CREATE = 3, // (event, bg, bgId, instanceId) - Needs to be added to TC + BG_EVENT_ON_PRE_DESTROY = 4, // (event, bg, bgId, instanceId) - Needs to be added to TC + BG_EVENT_COUNT + }; + + enum InstanceEvents + { + INSTANCE_EVENT_ON_INITIALIZE = 1, // (event, instance_data, map) + INSTANCE_EVENT_ON_LOAD = 2, // (event, instance_data, map) + INSTANCE_EVENT_ON_UPDATE = 3, // (event, instance_data, map, diff) + INSTANCE_EVENT_ON_PLAYER_ENTER = 4, // (event, instance_data, map, player) + INSTANCE_EVENT_ON_CREATURE_CREATE = 5, // (event, instance_data, map, creature) + INSTANCE_EVENT_ON_GAMEOBJECT_CREATE = 6, // (event, instance_data, map, go) + INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS = 7, // (event, instance_data, map) + INSTANCE_EVENT_COUNT + }; +}; + +#endif // _HOOKS_H diff --git a/modules/mod-eluna/src/LuaEngine/HttpManager.cpp b/modules/mod-eluna/src/LuaEngine/HttpManager.cpp new file mode 100644 index 0000000..80d6b29 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/HttpManager.cpp @@ -0,0 +1,276 @@ +#include +extern "C" +{ +#include "lua.h" +#include "lauxlib.h" +}; + +#if defined TRINITY || defined AZEROTHCORE +#define CPPHTTPLIB_OPENSSL_SUPPORT +#endif +#include "libs/httplib.h" +#include "HttpManager.h" +#include "LuaEngine.h" + +HttpWorkItem::HttpWorkItem(int funcRef, const std::string& httpVerb, const std::string& url, const std::string& body, const std::string& contentType, const httplib::Headers& headers) + : funcRef(funcRef), + httpVerb(httpVerb), + url(url), + body(body), + contentType(contentType), + headers(headers) +{ } + +HttpResponse::HttpResponse(int funcRef, int statusCode, const std::string& body, const httplib::Headers& headers) + : funcRef(funcRef), + statusCode(statusCode), + body(body), + headers(headers) +{ } + +HttpManager::HttpManager() + : workQueue(16), + responseQueue(16), + startedWorkerThread(false), + cancelationToken(false), + condVar(), + condVarMutex(), + parseUrlRegex("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?") +{ + StartHttpWorker(); +} + +HttpManager::~HttpManager() +{ + StopHttpWorker(); +} + +void HttpManager::PushRequest(HttpWorkItem* item) +{ + std::unique_lock lock(condVarMutex); + workQueue.push(item); + condVar.notify_one(); +} + +void HttpManager::StartHttpWorker() +{ + ClearQueues(); + + if (!startedWorkerThread) + { + cancelationToken.store(false); + workerThread = std::thread(&HttpManager::HttpWorkerThread, this); + startedWorkerThread = true; + } +} + +void HttpManager::ClearQueues() +{ + while (workQueue.front()) + { + HttpWorkItem* item = *workQueue.front(); + if (item != nullptr) + { + delete item; + } + workQueue.pop(); + } + + while (responseQueue.front()) + { + HttpResponse* item = *responseQueue.front(); + if (item != nullptr) + { + delete item; + } + responseQueue.pop(); + } +} + +void HttpManager::StopHttpWorker() +{ + if (!startedWorkerThread) + { + return; + } + + cancelationToken.store(true); + condVar.notify_one(); + workerThread.join(); + ClearQueues(); + startedWorkerThread = false; +} + +void HttpManager::HttpWorkerThread() +{ + while (true) + { + { + std::unique_lock lock(condVarMutex); + condVar.wait(lock, [&] { return workQueue.front() != nullptr || cancelationToken.load(); }); + } + + if (cancelationToken.load()) + { + break; + } + if (!workQueue.front()) + { + continue; + } + + HttpWorkItem* req = *workQueue.front(); + workQueue.pop(); + if (!req) + { + continue; + } + + try + { + std::string host; + std::string path; + + if (!ParseUrl(req->url, host, path)) { + ELUNA_LOG_ERROR("[Eluna]: Could not parse URL {}", req->url); + continue; + } + + httplib::Client cli(host); + cli.set_connection_timeout(0, 3000000); // 3 seconds + cli.set_read_timeout(5, 0); // 5 seconds + cli.set_write_timeout(5, 0); // 5 seconds + + httplib::Result res = DoRequest(cli, req, path); + httplib::Error err = res.error(); + if (err != httplib::Error::Success) + { + ELUNA_LOG_ERROR("[Eluna]: HTTP request error: {}", httplib::to_string(err)); + continue; + } + + if (res->status == 301) + { + std::string location = res->get_header_value("Location"); + std::string host; + std::string path; + + if (!ParseUrl(location, host, path)) + { + ELUNA_LOG_ERROR("[Eluna]: Could not parse URL after redirect: {}", location); + continue; + } + httplib::Client cli2(host); + cli2.set_connection_timeout(0, 3000000); // 3 seconds + cli2.set_read_timeout(5, 0); // 5 seconds + cli2.set_write_timeout(5, 0); // 5 seconds + res = DoRequest(cli2, req, path); + } + + responseQueue.push(new HttpResponse(req->funcRef, res->status, res->body, res->headers)); + } + catch (const std::exception& ex) + { + ELUNA_LOG_ERROR("[Eluna]: HTTP request error: {}", ex.what()); + } + + delete req; + } +} + +httplib::Result HttpManager::DoRequest(httplib::Client& client, HttpWorkItem* req, const std::string& urlPath) +{ + const char* path = urlPath.c_str(); + if (req->httpVerb == "GET") + { + return client.Get(path, req->headers); + } + if (req->httpVerb == "HEAD") + { + return client.Head(path, req->headers); + } + if (req->httpVerb == "POST") + { + return client.Post(path, req->headers, req->body, req->contentType.c_str()); + } + if (req->httpVerb == "PUT") + { + return client.Put(path, req->headers, req->body, req->contentType.c_str()); + } + if (req->httpVerb == "PATCH") + { + return client.Patch(path, req->headers, req->body, req->contentType.c_str()); + } + if (req->httpVerb == "DELETE") + { + return client.Delete(path, req->headers); + } + if (req->httpVerb == "OPTIONS") + { + return client.Options(path, req->headers); + } + + ELUNA_LOG_ERROR("[Eluna]: HTTP request error: invalid HTTP verb {}", req->httpVerb); + return client.Get(path, req->headers); +} + +bool HttpManager::ParseUrl(const std::string& url, std::string& host, std::string& path) +{ + std::smatch matches; + + if (!std::regex_search(url, matches, parseUrlRegex)) + { + return false; + } + + std::string scheme = matches[2]; + std::string authority = matches[4]; + std::string query = matches[7]; + host = scheme + "://" + authority; + path = matches[5]; + if (path.empty()) + { + path = "/"; + } + path += (query.empty() ? "" : "?") + query; + + return true; +} + +void HttpManager::HandleHttpResponses() +{ + while (!responseQueue.empty()) + { + HttpResponse* res = *responseQueue.front(); + responseQueue.pop(); + + if (res == nullptr) + { + continue; + } + + LOCK_ELUNA; + + lua_State* L = Eluna::GEluna->L; + + // Get function + lua_rawgeti(L, LUA_REGISTRYINDEX, res->funcRef); + + // Push parameters + Eluna::Push(L, res->statusCode); + Eluna::Push(L, res->body); + lua_newtable(L); + for (const auto& item : res->headers) { + Eluna::Push(L, item.first); + Eluna::Push(L, item.second); + lua_settable(L, -3); + } + + // Call function + Eluna::GEluna->ExecuteCall(3, 0); + + luaL_unref(L, LUA_REGISTRYINDEX, res->funcRef); + + delete res; + } +} diff --git a/modules/mod-eluna/src/LuaEngine/HttpManager.h b/modules/mod-eluna/src/LuaEngine/HttpManager.h new file mode 100644 index 0000000..2a77c1e --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/HttpManager.h @@ -0,0 +1,61 @@ +#ifndef ELUNA_HTTP_MANAGER_H +#define ELUNA_HTTP_MANAGER_H + +#include + +#include "libs/httplib.h" +#include "libs/rigtorp/SPSCQueue.h" + +struct HttpWorkItem +{ +public: + HttpWorkItem(int funcRef, const std::string& httpVerb, const std::string& url, const std::string& body, const std::string &contentType, const httplib::Headers& headers); + + int funcRef; + std::string httpVerb; + std::string url; + std::string body; + std::string contentType; + httplib::Headers headers; +}; + +struct HttpResponse +{ +public: + HttpResponse(int funcRef, int statusCode, const std::string& body, const httplib::Headers& headers); + + int funcRef; + int statusCode; + std::string body; + httplib::Headers headers; +}; + + +class HttpManager +{ +public: + HttpManager(); + ~HttpManager(); + + void StartHttpWorker(); + void StopHttpWorker(); + void PushRequest(HttpWorkItem* item); + void HandleHttpResponses(); + +private: + void ClearQueues(); + void HttpWorkerThread(); + bool ParseUrl(const std::string& url, std::string& host, std::string& path); + httplib::Result DoRequest(httplib::Client& client, HttpWorkItem* req, const std::string& path); + + rigtorp::SPSCQueue workQueue; + rigtorp::SPSCQueue responseQueue; + std::thread workerThread; + bool startedWorkerThread; + std::atomic_bool cancelationToken; + std::condition_variable condVar; + std::mutex condVarMutex; + std::regex parseUrlRegex; +}; + +#endif // #ifndef ELUNA_HTTP_MANAGER_H diff --git a/modules/mod-eluna/src/LuaEngine/InstanceHooks.cpp b/modules/mod-eluna/src/LuaEngine/InstanceHooks.cpp new file mode 100644 index 0000000..29b2607 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/InstanceHooks.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" +#include "ElunaInstanceAI.h" + +using namespace Hooks; + +#define START_HOOK(EVENT, AI) \ + if (!IsEnabled())\ + return;\ + auto mapKey = EntryKey(EVENT, AI->instance->GetId());\ + auto instanceKey = EntryKey(EVENT, AI->instance->GetInstanceId());\ + if (!MapEventBindings->HasBindingsFor(mapKey) && !InstanceEventBindings->HasBindingsFor(instanceKey))\ + return;\ + LOCK_ELUNA;\ + PushInstanceData(L, AI);\ + Push(AI->instance) + +#define START_HOOK_WITH_RETVAL(EVENT, AI, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto mapKey = EntryKey(EVENT, AI->instance->GetId());\ + auto instanceKey = EntryKey(EVENT, AI->instance->GetInstanceId());\ + if (!MapEventBindings->HasBindingsFor(mapKey) && !InstanceEventBindings->HasBindingsFor(instanceKey))\ + return RETVAL;\ + LOCK_ELUNA;\ + PushInstanceData(L, AI);\ + Push(AI->instance) + +void Eluna::OnInitialize(ElunaInstanceAI* ai) +{ + START_HOOK(INSTANCE_EVENT_ON_INITIALIZE, ai); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +void Eluna::OnLoad(ElunaInstanceAI* ai) +{ + START_HOOK(INSTANCE_EVENT_ON_LOAD, ai); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +void Eluna::OnUpdateInstance(ElunaInstanceAI* ai, uint32 diff) +{ + START_HOOK(INSTANCE_EVENT_ON_UPDATE, ai); + Push(diff); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +void Eluna::OnPlayerEnterInstance(ElunaInstanceAI* ai, Player* player) +{ + START_HOOK(INSTANCE_EVENT_ON_PLAYER_ENTER, ai); + Push(player); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +void Eluna::OnCreatureCreate(ElunaInstanceAI* ai, Creature* creature) +{ + START_HOOK(INSTANCE_EVENT_ON_CREATURE_CREATE, ai); + Push(creature); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +void Eluna::OnGameObjectCreate(ElunaInstanceAI* ai, GameObject* gameobject) +{ + START_HOOK(INSTANCE_EVENT_ON_GAMEOBJECT_CREATE, ai); + Push(gameobject); + CallAllFunctions(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} + +bool Eluna::OnCheckEncounterInProgress(ElunaInstanceAI* ai) +{ + START_HOOK_WITH_RETVAL(INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS, ai, false); + return CallAllFunctionsBool(MapEventBindings, InstanceEventBindings, mapKey, instanceKey); +} diff --git a/modules/mod-eluna/src/LuaEngine/ItemHooks.cpp b/modules/mod-eluna/src/LuaEngine/ItemHooks.cpp new file mode 100644 index 0000000..ddd0223 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ItemHooks.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT, ENTRY) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!ItemEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, ENTRY, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EntryKey(EVENT, ENTRY);\ + if (!ItemEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +void Eluna::OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget) +{ + START_HOOK(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + CallAllFunctions(ItemEventBindings, key); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) +{ + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry(), false); + Push(pPlayer); + Push(pItem); + Push(pQuest); + return CallAllFunctionsBool(ItemEventBindings, key); +} + +bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +{ + ObjectGuid guid = pItem->GET_GUID(); + bool castSpell = true; + + if (!OnItemUse(pPlayer, pItem, targets)) + castSpell = false; + + pItem = pPlayer->GetItemByGuid(guid); + if (pItem) + { + if (!OnItemGossip(pPlayer, pItem, targets)) + castSpell = false; + pItem = pPlayer->GetItemByGuid(guid); + } + + if (pItem && castSpell) + return true; + + // Send equip error that shows no message + // This is a hack fix to stop spell casting visual bug when a spell is not cast on use + WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, 18); + data << uint8(59); // EQUIP_ERR_NONE / EQUIP_ERR_CANT_BE_DISENCHANTED + data << guid; + data << ObjectGuid(uint64(0)); + data << uint8(0); +#ifdef CMANGOS + pPlayer->GetSession()->SendPacket(data); +#else + pPlayer->GetSession()->SendPacket(&data); +#endif + return false; +} + +bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +{ + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_USE, pItem->GetEntry(), true); + Push(pPlayer); + Push(pItem); +#if defined TRINITY || AZEROTHCORE + if (GameObject* target = targets.GetGOTarget()) + Push(target); + else if (Item* target = targets.GetItemTarget()) + Push(target); + else if (Corpse* target = targets.GetCorpseTarget()) + Push(target); + else if (Unit* target = targets.GetUnitTarget()) + Push(target); + else if (WorldObject* target = targets.GetObjectTarget()) + Push(target); + else + Push(); +#else + if (GameObject* target = targets.getGOTarget()) + Push(target); + else if (Item* target = targets.getItemTarget()) + Push(target); + else if (Corpse* target = pPlayer->GetMap()->GetCorpse(targets.getCorpseTargetGuid())) + Push(target); + else if (Unit* target = targets.getUnitTarget()) + Push(target); + else + Push(); +#endif + + return CallAllFunctionsBool(ItemEventBindings, key, true); +} + +bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto) +{ + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_EXPIRE, pProto->ItemId, false); + Push(pPlayer); + Push(pProto->ItemId); + return CallAllFunctionsBool(ItemEventBindings, key); +} + +bool Eluna::OnRemove(Player* pPlayer, Item* pItem) +{ + START_HOOK_WITH_RETVAL(ITEM_EVENT_ON_REMOVE, pItem->GetEntry(), false); + Push(pPlayer); + Push(pItem); + return CallAllFunctionsBool(ItemEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/ItemMethods.h b/modules/mod-eluna/src/LuaEngine/ItemMethods.h new file mode 100644 index 0000000..9c85551 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ItemMethods.h @@ -0,0 +1,786 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef ITEMMETHODS_H +#define ITEMMETHODS_H + +/*** + * Inherits all methods from: [Object] + */ +namespace LuaItem +{ + /** + * Returns 'true' if the [Item] is soulbound, 'false' otherwise + * + * @return bool isSoulBound + */ + int IsSoulBound(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsSoulBound()); + return 1; + } + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Returns 'true' if the [Item] is account bound, 'false' otherwise + * + * @return bool isAccountBound + */ + int IsBoundAccountWide(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsBoundAccountWide()); + return 1; + } +#endif + + /** + * Returns 'true' if the [Item] is bound to a [Player] by an enchant, 'false' otehrwise + * + * @return bool isBoundByEnchant + */ + int IsBoundByEnchant(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsBoundByEnchant()); + return 1; + } + + /** + * Returns 'true' if the [Item] is not bound to the [Player] specified, 'false' otherwise + * + * @param [Player] player : the [Player] object to check the item against + * @return bool isNotBound + */ + int IsNotBoundToPlayer(lua_State* L, Item* item) + { + Player* player = Eluna::CHECKOBJ(L, 2); + + Eluna::Push(L, item->IsBindedNotWith(player)); + return 1; + } + + /** + * Returns 'true' if the [Item] is locked, 'false' otherwise + * + * @return bool isLocked + */ + int IsLocked(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsLocked()); + return 1; + } + + /** + * Returns 'true' if the [Item] is a bag, 'false' otherwise + * + * @return bool isBag + */ + int IsBag(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsBag()); + return 1; + } + +#ifndef CLASSIC + /** + * Returns 'true' if the [Item] is a currency token, 'false' otherwise + * + * @return bool isCurrencyToken + */ + int IsCurrencyToken(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsCurrencyToken()); + return 1; + } +#endif + + /** + * Returns 'true' if the [Item] is a not an empty bag, 'false' otherwise + * + * @return bool isNotEmptyBag + */ + int IsNotEmptyBag(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsNotEmptyBag()); + return 1; + } + + /** + * Returns 'true' if the [Item] is broken, 'false' otherwise + * + * @return bool isBroken + */ + int IsBroken(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsBroken()); + return 1; + } + + /** + * Returns 'true' if the [Item] can be traded, 'false' otherwise + * + * @return bool isTradeable + */ + int CanBeTraded(lua_State* L, Item* item) + { +#if (defined(TBC) || defined(CLASSIC)) + Eluna::Push(L, item->CanBeTraded()); +#else + bool mail = Eluna::CHECKVAL(L, 2, false); + Eluna::Push(L, item->CanBeTraded(mail)); +#endif + return 1; + } + + /** + * Returns 'true' if the [Item] is currently in a trade window, 'false' otherwise + * + * @return bool isInTrade + */ + int IsInTrade(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsInTrade()); + return 1; + } + + /** + * Returns 'true' if the [Item] is currently in a bag, 'false' otherwise + * + * @return bool isInBag + */ + int IsInBag(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsInBag()); + return 1; + } + + /** + * Returns 'true' if the [Item] is currently equipped, 'false' otherwise + * + * @return bool isEquipped + */ + int IsEquipped(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsEquipped()); + return 1; + } + + /** + * Returns 'true' if the [Item] has the [Quest] specified tied to it, 'false' otherwise + * + * @param uint32 questId : the [Quest] id to be checked + * @return bool hasQuest + */ + int HasQuest(lua_State* L, Item* item) + { + uint32 quest = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, item->hasQuest(quest)); +#else + Eluna::Push(L, item->HasQuest(quest)); +#endif + return 1; + } + + /** + * Returns 'true' if the [Item] is a potion, 'false' otherwise + * + * @return bool isPotion + */ + int IsPotion(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsPotion()); + return 1; + } + +#if defined CLASSIC || defined(TBC) || defined(WOTLK) + /** + * Returns 'true' if the [Item] is a weapon vellum, 'false' otherwise + * + * @return bool isWeaponVellum + */ + int IsWeaponVellum(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsWeaponVellum()); + return 1; + } + + /** + * Returns 'true' if the [Item] is an armor vellum, 'false' otherwise + * + * @return bool isArmorVellum + */ + int IsArmorVellum(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsArmorVellum()); + return 1; + } +#endif + + /** + * Returns 'true' if the [Item] is a conjured consumable, 'false' otherwise + * + * @return bool isConjuredConsumable + */ + int IsConjuredConsumable(lua_State* L, Item* item) + { + Eluna::Push(L, item->IsConjuredConsumable()); + return 1; + } + + /*int IsRefundExpired(lua_State* L, Item* item)// TODO: Implement core support + { + Eluna::Push(L, item->IsRefundExpired()); + return 1; + }*/ + + /** + * Returns the chat link of the [Item] + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Item]'s name in + * @return string itemLink + */ + int GetItemLink(lua_State* L, Item* item) + { + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + + const ItemTemplate* temp = item->GetTemplate(); + std::string name = temp->Name1; + if (ItemLocale const* il = eObjectMgr->GetItemLocale(temp->ItemId)) + { + ObjectMgr::GetLocaleString(il->Name, static_cast(locale), name); + } + +#ifndef CLASSIC + if (int32 itemRandPropId = item->GetItemRandomPropertyId()) + { +#if defined(CATA) || defined (MISTS) + char* suffix = NULL; +#else +#if TRINITY || AZEROTHCORE + std::array const* suffix = NULL; +#else + char* const* suffix = NULL; +#endif +#endif + if (itemRandPropId < 0) + { + const ItemRandomSuffixEntry* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId()); + if (itemRandEntry) + { +#if TRINITY || AZEROTHCORE + suffix = &itemRandEntry->Name; +#else + suffix = itemRandEntry->nameSuffix; +#endif + } + } + else + { + const ItemRandomPropertiesEntry* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId()); + if (itemRandEntry) + { +#if TRINITY || AZEROTHCORE + suffix = &itemRandEntry->Name; +#else + suffix = itemRandEntry->nameSuffix; +#endif + } + } + if (suffix) + { +#if TRINITY || AZEROTHCORE + const char* suffixName = (*suffix)[(name != temp->Name1) ? locale : uint8(DEFAULT_LOCALE)]; +#else + const char* suffixName = suffix[(name != temp->Name1) ? locale : uint8(DEFAULT_LOCALE)]; +#endif + if (strcmp(suffixName, "") != 0) + { + name += ' '; + name += suffixName; + } + } + } +#endif + + Player* owner = item->GetOwner(); + std::ostringstream oss; + oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec << + "|Hitem:" << temp->ItemId << ":" << + item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) << ":" << +#ifndef CLASSIC + item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT) << ":" << + item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_2) << ":" << + item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_3) << ":" << + item->GetEnchantmentId(BONUS_ENCHANTMENT_SLOT) << ":" << +#endif + item->GetItemRandomPropertyId() << ":" << item->GetItemSuffixFactor() << ":" << + (uint32)(owner ? owner->GetLevel() : 0) << "|h[" << name << "]|h|r"; + + Eluna::Push(L, oss.str()); + return 1; + } + + int GetOwnerGUID(lua_State* L, Item* item) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, item->GetOwnerGUID()); +#else + Eluna::Push(L, item->GetOwnerGuid()); +#endif + return 1; + } + + /** + * Returns the [Player] who currently owns the [Item] + * + * @return [Player] player : the [Player] who owns the [Item] + */ + int GetOwner(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetOwner()); + return 1; + } + + /** + * Returns the [Item]s stack count + * + * @return uint32 count + */ + int GetCount(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetCount()); + return 1; + } + + /** + * Returns the [Item]s max stack count + * + * @return uint32 maxCount + */ + int GetMaxStackCount(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetMaxStackCount()); + return 1; + } + + /** + * Returns the [Item]s current slot + * + * @return uint8 slot + */ + int GetSlot(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetSlot()); + return 1; + } + + /** + * Returns the [Item]s current bag slot + * + * @return uint8 bagSlot + */ + int GetBagSlot(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetBagSlot()); + return 1; + } + + /** + * Returns the [Item]s enchantment ID by enchant slot specified + * + * @param [EnchantmentSlot] enchantSlot : the enchant slot specified + * @return uint32 enchantId : the id of the enchant slot specified + */ + int GetEnchantmentId(lua_State* L, Item* item) + { + uint32 enchant_slot = Eluna::CHECKVAL(L, 2); + + if (enchant_slot >= MAX_INSPECTED_ENCHANTMENT_SLOT) + return luaL_argerror(L, 2, "valid EnchantmentSlot expected"); + + Eluna::Push(L, item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); + return 1; + } + + /** + * Returns the spell ID tied to the [Item] by spell index + * + * @param uint32 spellIndex : the spell index specified + * @return uint32 spellId : the id of the spell + */ + int GetSpellId(lua_State* L, Item* item) + { + uint32 index = Eluna::CHECKVAL(L, 2); + if (index >= MAX_ITEM_PROTO_SPELLS) + return luaL_argerror(L, 2, "valid SpellIndex expected"); + + Eluna::Push(L, item->GetTemplate()->Spells[index].SpellId); + return 1; + } + + /** + * Returns the spell trigger tied to the [Item] by spell index + * + * @param uint32 spellIndex : the spell index specified + * @return uint32 spellTrigger : the spell trigger of the specified index + */ + int GetSpellTrigger(lua_State* L, Item* item) + { + uint32 index = Eluna::CHECKVAL(L, 2); + if (index >= MAX_ITEM_PROTO_SPELLS) + return luaL_argerror(L, 2, "valid SpellIndex expected"); + + Eluna::Push(L, item->GetTemplate()->Spells[index].SpellTrigger); + return 1; + } + + /** + * Returns class of the [Item] + * + * @return uint32 class + */ + int GetClass(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->Class); + return 1; + } + + /** + * Returns subclass of the [Item] + * + * @return uint32 subClass + */ + int GetSubClass(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->SubClass); + return 1; + } + + /** + * Returns the name of the [Item] + * + * @return string name + */ + int GetName(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->Name1); + return 1; + } + + /** + * Returns the display ID of the [Item] + * + * @return uint32 displayId + */ + int GetDisplayId(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->DisplayInfoID); + return 1; + } + + /** + * Returns the quality of the [Item] + * + * @return uint32 quality + */ + int GetQuality(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->Quality); + return 1; + } + + /** + * Returns the default purchase count of the [Item] + * + * @return uint32 count + */ + int GetBuyCount(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->BuyCount); + return 1; + } + + /** + * Returns the purchase price of the [Item] + * + * @return uint32 price + */ + int GetBuyPrice(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->BuyPrice); + return 1; + } + + /** + * Returns the sell price of the [Item] + * + * @return uint32 price + */ + int GetSellPrice(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->SellPrice); + return 1; + } + + /** + * Returns the inventory type of the [Item] + * + * @return uint32 inventoryType + */ + int GetInventoryType(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->InventoryType); + return 1; + } + + /** + * Returns the [Player] classes allowed to use this [Item] + * + * @return uint32 allowableClass + */ + int GetAllowableClass(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->AllowableClass); + return 1; + } + + /** + * Returns the [Player] races allowed to use this [Item] + * + * @return uint32 allowableRace + */ + int GetAllowableRace(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->AllowableRace); + return 1; + } + + /** + * Returns the [Item]s level + * + * @return uint32 itemLevel + */ + int GetItemLevel(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->ItemLevel); + return 1; + } + + /** + * Returns the minimum level required to use this [Item] + * + * @return uint32 requiredLevel + */ + int GetRequiredLevel(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->RequiredLevel); + return 1; + } + +#ifdef WOTLK + int GetStatsCount(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->StatsCount); + return 1; + } +#endif + + /** + * Returns the random property ID of this [Item] + * + * @return uint32 randomPropertyId + */ + int GetRandomProperty(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->RandomProperty); + return 1; + } + +#ifndef CLASSIC + int GetRandomSuffix(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->RandomSuffix); + return 1; + } +#endif + + /** + * Returns the item set ID of this [Item] + * + * @return uint32 itemSetId + */ + int GetItemSet(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()->ItemSet); + return 1; + } + + /** + * Returns the bag size of this [Item], 0 if [Item] is not a bag + * + * @return uint32 bagSize + */ + int GetBagSize(lua_State* L, Item* item) + { + if (Bag* bag = item->ToBag()) + Eluna::Push(L, bag->GetBagSize()); + else + Eluna::Push(L, 0); + return 1; + } + + /** + * Returns the [ItemTemplate] for this [Item]. + * + * @return [ItemTemplate] itemTemplate + */ + int GetItemTemplate(lua_State* L, Item* item) + { + Eluna::Push(L, item->GetTemplate()); + return 1; + } + + /** + * Sets the [Player] specified as the owner of the [Item] + * + * @param [Player] player : the [Player] specified + */ + int SetOwner(lua_State* L, Item* item) + { + Player* player = Eluna::CHECKOBJ(L, 2); +#if defined TRINITY || AZEROTHCORE + item->SetOwnerGUID(player->GET_GUID()); +#else + item->SetOwnerGuid(player->GET_GUID()); +#endif + return 0; + } + + /** + * Sets the binding of the [Item] to 'true' or 'false' + * + * @param bool setBinding + */ + int SetBinding(lua_State* L, Item* item) + { + bool soulbound = Eluna::CHECKVAL(L, 2); + + item->SetBinding(soulbound); + item->SetState(ITEM_CHANGED, item->GetOwner()); + + return 0; + } + + /** + * Sets the stack count of the [Item] + * + * @param uint32 count + */ + int SetCount(lua_State* L, Item* item) + { + uint32 count = Eluna::CHECKVAL(L, 2); + item->SetCount(count); + return 0; + } + + /** + * Sets the specified enchantment of the [Item] to the specified slot + * + * @param uint32 enchantId : the ID of the enchant to be applied + * @param uint32 enchantSlot : the slot for the enchant to be applied to + * @return bool enchantmentSuccess : if enchantment is successfully set to specified slot, returns 'true', otherwise 'false' + */ + int SetEnchantment(lua_State* L, Item* item) + { + Player* owner = item->GetOwner(); + if (!owner) + { + Eluna::Push(L, false); + return 1; + } + + uint32 enchant = Eluna::CHECKVAL(L, 2); + if (!sSpellItemEnchantmentStore.LookupEntry(enchant)) + { + Eluna::Push(L, false); + return 1; + } + + EnchantmentSlot slot = (EnchantmentSlot)Eluna::CHECKVAL(L, 3); + if (slot >= MAX_INSPECTED_ENCHANTMENT_SLOT) + return luaL_argerror(L, 2, "valid EnchantmentSlot expected"); + + owner->ApplyEnchantment(item, slot, false); + item->SetEnchantment(slot, enchant, 0, 0); + owner->ApplyEnchantment(item, slot, true); + Eluna::Push(L, true); + return 1; + } + + /* OTHER */ + /** + * Removes an enchant from the [Item] by the specified slot + * + * @param uint32 enchantSlot : the slot for the enchant to be removed from + * @return bool enchantmentRemoved : if enchantment is successfully removed from specified slot, returns 'true', otherwise 'false' + */ + int ClearEnchantment(lua_State* L, Item* item) + { + Player* owner = item->GetOwner(); + if (!owner) + { + Eluna::Push(L, false); + return 1; + } + + EnchantmentSlot slot = (EnchantmentSlot)Eluna::CHECKVAL(L, 2); + if (slot >= MAX_INSPECTED_ENCHANTMENT_SLOT) + return luaL_argerror(L, 2, "valid EnchantmentSlot expected"); + + if (!item->GetEnchantmentId(slot)) + { + Eluna::Push(L, false); + return 1; + } + + owner->ApplyEnchantment(item, slot, false); + item->ClearEnchantment(slot); + Eluna::Push(L, true); + return 1; + } + + /** + * Saves the [Item] to the database + */ + int SaveToDB(lua_State* /*L*/, Item* item) + { +#if defined TRINITY || defined AZEROTHCORE + CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr); + item->SaveToDB(trans); +#else + item->SaveToDB(); +#endif + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ItemTemplateMethods.h b/modules/mod-eluna/src/LuaEngine/ItemTemplateMethods.h new file mode 100644 index 0000000..401572c --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ItemTemplateMethods.h @@ -0,0 +1,191 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef ITEMTEMPLATEMETHODS_H +#define ITEMTEMPLATEMETHODS_H + +#include "Chat.h" + +namespace LuaItemTemplate +{ + /** + * Returns the [ItemTemplate]'s ID. + * + * @return uint32 itemId + */ + int GetItemId(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->ItemId); + return 1; + } + + /** + * Returns the [ItemTemplate]'s class. + * + * @return uint32 class + */ + int GetClass(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->Class); + return 1; + } + + /** + * Returns the [ItemTemplate]'s subclass. + * + * @return uint32 subClass + */ + int GetSubClass(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->SubClass); + return 1; + } + + /** + * Returns the [ItemTemplate]'s name. + * + * @return string name + */ + int GetName(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->Name1); + return 1; + } + + /** + * Returns the [ItemTemplate]'s display ID. + * + * @return uint32 displayId + */ + int GetDisplayId(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->DisplayInfoID); + return 1; + } + + /** + * Returns the [ItemTemplate]'s quality. + * + * @return uint32 quality + */ + int GetQuality(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->Quality); + return 1; + } + + /** + * Returns the [ItemTemplate]'s flags. + * + * @return uint32 flags + */ + int GetFlags(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->Flags); + return 1; + } + + /** + * Returns the [ItemTemplate]'s extra flags. + * + * @return uint32 flags + */ + int GetExtraFlags(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->Flags2); + return 1; + } + + /** + * Returns the [ItemTemplate]'s default purchase count. + * + * @return uint32 buyCount + */ + int GetBuyCount(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->BuyCount); + return 1; + } + + /** + * Returns the [ItemTemplate]'s purchase price. + * + * @return int32 buyPrice + */ + int GetBuyPrice(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->BuyPrice); + return 1; + } + + /** + * Returns the [ItemTemplate]'s sell price. + * + * @return uint32 sellPrice + */ + int GetSellPrice(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->SellPrice); + return 1; + } + + /** + * Returns the [ItemTemplate]'s inventory type. + * + * @return uint32 inventoryType + */ + int GetInventoryType(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->InventoryType); + return 1; + } + + /** + * Returns the [Player] classes allowed to use this [ItemTemplate]. + * + * @return uint32 allowableClass + */ + int GetAllowableClass(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->AllowableClass); + return 1; + } + + /** + * Returns the [Player] races allowed to use this [ItemTemplate]. + * + * @return uint32 allowableRace + */ + int GetAllowableRace(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->AllowableRace); + return 1; + } + + /** + * Returns the [ItemTemplate]'s item level. + * + * @return uint32 itemLevel + */ + int GetItemLevel(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->ItemLevel); + return 1; + } + + /** + * Returns the minimum level required to use this [ItemTemplate]. + * + * @return uint32 requiredLevel + */ + int GetRequiredLevel(lua_State* L, ItemTemplate* itemTemplate) + { + Eluna::Push(L, itemTemplate->RequiredLevel); + return 1; + } +} + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/LuaEngine.cpp b/modules/mod-eluna/src/LuaEngine/LuaEngine.cpp new file mode 100644 index 0000000..b238504 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/LuaEngine.cpp @@ -0,0 +1,1373 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#include "Hooks.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaEventMgr.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" +#include "ElunaUtility.h" +#include "ElunaCreatureAI.h" +#include "ElunaInstanceAI.h" + +#if defined(TRINITY_PLATFORM) && defined(TRINITY_PLATFORM_WINDOWS) +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS +#define ELUNA_WINDOWS +#endif +#elif defined(AC_PLATFORM) && defined(AC_PLATFORM_WINDOWS) +#if AC_PLATFORM == AC_PLATFORM_WINDOWS +#define ELUNA_WINDOWS +#endif +#elif defined(PLATFORM) && defined(PLATFORM_WINDOWS) +#if PLATFORM == PLATFORM_WINDOWS +#define ELUNA_WINDOWS +#endif +#else +#error Eluna could not determine platform +#endif + +// Some dummy includes containing BOOST_VERSION: +// ObjectAccessor.h Config.h Log.h +#if !defined MANGOS +#define USING_BOOST +#endif + +#ifdef USING_BOOST +#include +#else +#include +#include +#include +#endif + +extern "C" +{ +// Base lua libraries +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +// Additional lua libraries +}; + +Eluna::ScriptList Eluna::lua_scripts; +Eluna::ScriptList Eluna::lua_extensions; +std::string Eluna::lua_folderpath; +std::string Eluna::lua_requirepath; +Eluna* Eluna::GEluna = NULL; +bool Eluna::reload = false; +bool Eluna::initialized = false; +Eluna::LockType Eluna::lock; + +extern void RegisterFunctions(Eluna* E); + +void Eluna::Initialize() +{ + LOCK_ELUNA; + ASSERT(!IsInitialized()); + +#if defined TRINITY || AZEROTHCORE + // For instance data the data column needs to be able to hold more than 255 characters (tinytext) + // so we change it to TEXT automatically on startup + CharacterDatabase.DirectExecute("ALTER TABLE `instance` CHANGE COLUMN `data` `data` TEXT NOT NULL"); +#endif + + LoadScriptPaths(); + + // Must be before creating GEluna + // This is checked on Eluna creation + initialized = true; + + // Create global eluna + GEluna = new Eluna(); +} + +void Eluna::Uninitialize() +{ + LOCK_ELUNA; + ASSERT(IsInitialized()); + + delete GEluna; + GEluna = NULL; + + lua_scripts.clear(); + lua_extensions.clear(); + + initialized = false; +} + +void Eluna::LoadScriptPaths() +{ + uint32 oldMSTime = ElunaUtil::GetCurrTime(); + + lua_scripts.clear(); + lua_extensions.clear(); + +#if defined(AZEROTHCORE) + lua_folderpath = eConfigMgr->GetOption("Eluna.ScriptPath", "lua_scripts"); +#else + lua_folderpath = eConfigMgr->GetStringDefault("Eluna.ScriptPath", "lua_scripts"); +#endif + +#ifndef ELUNA_WINDOWS + if (lua_folderpath[0] == '~') + if (const char* home = getenv("HOME")) + lua_folderpath.replace(0, 1, home); +#endif + ELUNA_LOG_INFO("[Eluna]: Searching scripts from `{}`", lua_folderpath); + lua_requirepath.clear(); + GetScripts(lua_folderpath); + // Erase last ; + if (!lua_requirepath.empty()) + lua_requirepath.erase(lua_requirepath.end() - 1); + + ELUNA_LOG_DEBUG("[Eluna]: Loaded {} scripts in {} ms", lua_scripts.size() + lua_extensions.size(), ElunaUtil::GetTimeDiff(oldMSTime)); +} + +void Eluna::_ReloadEluna() +{ + LOCK_ELUNA; + ASSERT(IsInitialized()); + + if (eConfigMgr->GetOption("Eluna.PlayerAnnounceReload", false)) + eWorld->SendServerMessage(SERVER_MSG_STRING, "Reloading Eluna..."); + else + eWorld->SendGMText(SERVER_MSG_STRING, "Reloading Eluna..."); + + // Remove all timed events + sEluna->eventMgr->SetStates(LUAEVENT_STATE_ERASE); + + // Close lua + sEluna->CloseLua(); + + // Reload script paths + LoadScriptPaths(); + + // Open new lua and libaraies + sEluna->OpenLua(); + + // Run scripts from laoded paths + sEluna->RunScripts(); + + reload = false; +} + +Eluna::Eluna() : +event_level(0), +push_counter(0), +enabled(false), + +L(NULL), +eventMgr(NULL), +httpManager(), +queryProcessor(), + +ServerEventBindings(NULL), +PlayerEventBindings(NULL), +GuildEventBindings(NULL), +GroupEventBindings(NULL), +VehicleEventBindings(NULL), +BGEventBindings(NULL), + +PacketEventBindings(NULL), +CreatureEventBindings(NULL), +CreatureGossipBindings(NULL), +GameObjectEventBindings(NULL), +GameObjectGossipBindings(NULL), +ItemEventBindings(NULL), +ItemGossipBindings(NULL), +PlayerGossipBindings(NULL), +MapEventBindings(NULL), +InstanceEventBindings(NULL), + +CreatureUniqueBindings(NULL) +{ + ASSERT(IsInitialized()); + + OpenLua(); + + // Replace this with map insert if making multithread version + + // Set event manager. Must be after setting sEluna + // on multithread have a map of state pointers and here insert this pointer to the map and then save a pointer of that pointer to the EventMgr + eventMgr = new EventMgr(&Eluna::GEluna); +} + +Eluna::~Eluna() +{ + ASSERT(IsInitialized()); + + CloseLua(); + + delete eventMgr; + eventMgr = NULL; +} + +void Eluna::CloseLua() +{ + OnLuaStateClose(); + + DestroyBindStores(); + + // Must close lua state after deleting stores and mgr + if (L) + lua_close(L); + L = NULL; + + instanceDataRefs.clear(); + continentDataRefs.clear(); +} + +void Eluna::OpenLua() +{ +#if defined(AZEROTHCORE) + enabled = eConfigMgr->GetOption("Eluna.Enabled", true); +#else + enabled = eConfigMgr->GetBoolDefault("Eluna.Enabled", true); +#endif + + if (!IsEnabled()) + { + ELUNA_LOG_INFO("[Eluna]: Eluna is disabled in config"); + return; + } + + L = luaL_newstate(); + + lua_pushlightuserdata(L, this); + lua_setfield(L, LUA_REGISTRYINDEX, ELUNA_STATE_PTR); + + CreateBindStores(); + + // open base lua libraries + luaL_openlibs(L); + + // open additional lua libraries + + // Register methods and functions + RegisterFunctions(this); + + // Set lua require folder paths (scripts folder structure) + lua_getglobal(L, "package"); + lua_pushstring(L, lua_requirepath.c_str()); + lua_setfield(L, -2, "path"); + lua_pushstring(L, ""); // erase cpath + lua_setfield(L, -2, "cpath"); + lua_pop(L, 1); +} + +void Eluna::CreateBindStores() +{ + DestroyBindStores(); + + ServerEventBindings = new BindingMap< EventKey >(L); + PlayerEventBindings = new BindingMap< EventKey >(L); + GuildEventBindings = new BindingMap< EventKey >(L); + GroupEventBindings = new BindingMap< EventKey >(L); + VehicleEventBindings = new BindingMap< EventKey >(L); + BGEventBindings = new BindingMap< EventKey >(L); + + PacketEventBindings = new BindingMap< EntryKey >(L); + CreatureEventBindings = new BindingMap< EntryKey >(L); + CreatureGossipBindings = new BindingMap< EntryKey >(L); + GameObjectEventBindings = new BindingMap< EntryKey >(L); + GameObjectGossipBindings = new BindingMap< EntryKey >(L); + ItemEventBindings = new BindingMap< EntryKey >(L); + ItemGossipBindings = new BindingMap< EntryKey >(L); + PlayerGossipBindings = new BindingMap< EntryKey >(L); + MapEventBindings = new BindingMap< EntryKey >(L); + InstanceEventBindings = new BindingMap< EntryKey >(L); + + CreatureUniqueBindings = new BindingMap< UniqueObjectKey >(L); +} + +void Eluna::DestroyBindStores() +{ + delete ServerEventBindings; + delete PlayerEventBindings; + delete GuildEventBindings; + delete GroupEventBindings; + delete VehicleEventBindings; + + delete PacketEventBindings; + delete CreatureEventBindings; + delete CreatureGossipBindings; + delete GameObjectEventBindings; + delete GameObjectGossipBindings; + delete ItemEventBindings; + delete ItemGossipBindings; + delete PlayerGossipBindings; + delete BGEventBindings; + delete MapEventBindings; + delete InstanceEventBindings; + + delete CreatureUniqueBindings; + + ServerEventBindings = NULL; + PlayerEventBindings = NULL; + GuildEventBindings = NULL; + GroupEventBindings = NULL; + VehicleEventBindings = NULL; + + PacketEventBindings = NULL; + CreatureEventBindings = NULL; + CreatureGossipBindings = NULL; + GameObjectEventBindings = NULL; + GameObjectGossipBindings = NULL; + ItemEventBindings = NULL; + ItemGossipBindings = NULL; + PlayerGossipBindings = NULL; + BGEventBindings = NULL; + MapEventBindings = NULL; + InstanceEventBindings = NULL; + + CreatureUniqueBindings = NULL; +} + +void Eluna::AddScriptPath(std::string filename, const std::string& fullpath) +{ + ELUNA_LOG_DEBUG("[Eluna]: AddScriptPath Checking file `{}`", fullpath); + + // split file name + std::size_t extDot = filename.find_last_of('.'); + if (extDot == std::string::npos) + return; + std::string ext = filename.substr(extDot); + filename = filename.substr(0, extDot); + + // check extension and add path to scripts to load + if (ext != ".lua" && ext != ".dll" && ext != ".so" && ext != ".ext") + return; + bool extension = ext == ".ext"; + + LuaScript script; + script.fileext = ext; + script.filename = filename; + script.filepath = fullpath; + script.modulepath = fullpath.substr(0, fullpath.length() - filename.length() - ext.length()); + if (extension) + lua_extensions.push_back(script); + else + lua_scripts.push_back(script); + ELUNA_LOG_DEBUG("[Eluna]: AddScriptPath add path `{}`", fullpath); +} + +// Finds lua script files from given path (including subdirectories) and pushes them to scripts +void Eluna::GetScripts(std::string path) +{ + ELUNA_LOG_DEBUG("[Eluna]: GetScripts from path `{}`", path); + +#ifdef USING_BOOST + boost::filesystem::path someDir(path); + boost::filesystem::directory_iterator end_iter; + + if (boost::filesystem::exists(someDir) && boost::filesystem::is_directory(someDir)) + { + lua_requirepath += + path + "/?.lua;" + + path + "/?.ext;" + + path + "/?.dll;" + + path + "/?.so;"; + + for (boost::filesystem::directory_iterator dir_iter(someDir); dir_iter != end_iter; ++dir_iter) + { + std::string fullpath = dir_iter->path().generic_string(); + + // Check if file is hidden +#ifdef ELUNA_WINDOWS + DWORD dwAttrib = GetFileAttributes(fullpath.c_str()); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_HIDDEN)) + continue; +#else + std::string name = dir_iter->path().filename().generic_string().c_str(); + if (name[0] == '.') + continue; +#endif + + // load subfolder + if (boost::filesystem::is_directory(dir_iter->status())) + { + GetScripts(fullpath); + continue; + } + + if (boost::filesystem::is_regular_file(dir_iter->status())) + { + // was file, try add + std::string filename = dir_iter->path().filename().generic_string(); + AddScriptPath(filename, fullpath); + } + } + } +#else + ACE_Dirent dir; + if (dir.open(path.c_str()) == -1) // Error opening directory, return + return; + + lua_requirepath += + path + "/?.lua;" + + path + "/?.ext;" + + path + "/?.dll;" + + path + "/?.so;"; + + ACE_DIRENT *directory = 0; + while ((directory = dir.read())) + { + // Skip the ".." and "." files. + if (ACE::isdotdir(directory->d_name)) + continue; + + std::string fullpath = path + "/" + directory->d_name; + + // Check if file is hidden +#ifdef ELUNA_WINDOWS + DWORD dwAttrib = GetFileAttributes(fullpath.c_str()); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_HIDDEN)) + continue; +#else + std::string name = directory->d_name; + if (name[0] == '.') + continue; +#endif + + ACE_stat stat_buf; + if (ACE_OS::lstat(fullpath.c_str(), &stat_buf) == -1) + continue; + + // load subfolder + if ((stat_buf.st_mode & S_IFMT) == (S_IFDIR)) + { + GetScripts(fullpath); + continue; + } + + // was file, try add + std::string filename = directory->d_name; + AddScriptPath(filename, fullpath); + } +#endif +} + +static bool ScriptPathComparator(const LuaScript& first, const LuaScript& second) +{ + return first.filepath < second.filepath; +} + +void Eluna::RunScripts() +{ + LOCK_ELUNA; + if (!IsEnabled()) + return; + + uint32 oldMSTime = ElunaUtil::GetCurrTime(); + uint32 count = 0; + + ScriptList scripts; + lua_extensions.sort(ScriptPathComparator); + lua_scripts.sort(ScriptPathComparator); + scripts.insert(scripts.end(), lua_extensions.begin(), lua_extensions.end()); + scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end()); + + std::unordered_map loaded; // filename, path + + lua_getglobal(L, "package"); + // Stack: package + luaL_getsubtable(L, -1, "loaded"); + // Stack: package, modules + int modules = lua_gettop(L); + for (ScriptList::const_iterator it = scripts.begin(); it != scripts.end(); ++it) + { + // Check that no duplicate names exist + if (loaded.find(it->filename) != loaded.end()) + { + ELUNA_LOG_ERROR("[Eluna]: Error loading `{}`. File with same name already loaded from `{}`, rename either file", it->filepath, loaded[it->filename]); + continue; + } + loaded[it->filename] = it->filepath; + + lua_getfield(L, modules, it->filename.c_str()); + // Stack: package, modules, module + if (!lua_isnoneornil(L, -1)) + { + lua_pop(L, 1); + ELUNA_LOG_DEBUG("[Eluna]: `{}` was already loaded or required", it->filepath); + continue; + } + lua_pop(L, 1); + // Stack: package, modules + + if (luaL_loadfile(L, it->filepath.c_str())) + { + // Stack: package, modules, errmsg + ELUNA_LOG_ERROR("[Eluna]: Error loading `{}`", it->filepath); + Report(L); + // Stack: package, modules + continue; + } + // Stack: package, modules, filefunc + + if (ExecuteCall(0, 1)) + { + // Stack: package, modules, result + if (lua_isnoneornil(L, -1) || (lua_isboolean(L, -1) && !lua_toboolean(L, -1))) + { + // if result evaluates to false, change it to true + lua_pop(L, 1); + Push(L, true); + } + lua_setfield(L, modules, it->filename.c_str()); + // Stack: package, modules + + // successfully loaded and ran file + ELUNA_LOG_DEBUG("[Eluna]: Successfully loaded `{}`", it->filepath); + ++count; + continue; + } + } + // Stack: package, modules + lua_pop(L, 2); + ELUNA_LOG_INFO("[Eluna]: Executed {} Lua scripts in {} ms", count, ElunaUtil::GetTimeDiff(oldMSTime)); + + OnLuaStateOpen(); +} + +void Eluna::InvalidateObjects() +{ + ++callstackid; +#ifdef TRINITY + ASSERT(callstackid, "Callstackid overflow"); +#else + ASSERT(callstackid && "Callstackid overflow"); +#endif +} + +void Eluna::Report(lua_State* _L) +{ + const char* msg = lua_tostring(_L, -1); + ELUNA_LOG_ERROR("{}", msg); + lua_pop(_L, 1); +} + +// Borrowed from http://stackoverflow.com/questions/12256455/print-stacktrace-from-c-code-with-embedded-lua +int Eluna::StackTrace(lua_State *_L) +{ + // Stack: errmsg + if (!lua_isstring(_L, -1)) /* 'message' not a string? */ + return 1; /* keep it intact */ + // Stack: errmsg, debug + lua_getglobal(_L, "debug"); + if (!lua_istable(_L, -1)) + { + lua_pop(_L, 1); + return 1; + } + // Stack: errmsg, debug, traceback + lua_getfield(_L, -1, "traceback"); + if (!lua_isfunction(_L, -1)) + { + lua_pop(_L, 2); + return 1; + } + lua_pushvalue(_L, -3); /* pass error message */ + lua_pushinteger(_L, 1); /* skip this function and traceback */ + // Stack: errmsg, debug, traceback, errmsg, 2 + lua_call(_L, 2, 1); /* call debug.traceback */ + + // dirty stack? + // Stack: errmsg, debug, tracemsg + sEluna->OnError(std::string(lua_tostring(_L, -1))); + return 1; +} + +bool Eluna::ExecuteCall(int params, int res) +{ + int top = lua_gettop(L); + int base = top - params; + + // Expected: function, [parameters] + ASSERT(base > 0); + + // Check function type + if (!lua_isfunction(L, base)) + { + ELUNA_LOG_ERROR("[Eluna]: Cannot execute call: registered value is {}, not a function.", luaL_tolstring(L, base, NULL)); + ASSERT(false); // stack probably corrupt + } + +#if defined(AZEROTHCORE) + bool usetrace = eConfigMgr->GetOption("Eluna.TraceBack", false); +#else + bool usetrace = eConfigMgr->GetBoolDefault("Eluna.TraceBack", false); +#endif + + if (usetrace) + { + lua_pushcfunction(L, &StackTrace); + // Stack: function, [parameters], traceback + lua_insert(L, base); + // Stack: traceback, function, [parameters] + } + + // Objects are invalidated when event_level hits 0 + ++event_level; + int result = lua_pcall(L, params, res, usetrace ? base : 0); + --event_level; + + if (usetrace) + { + // Stack: traceback, [results or errmsg] + lua_remove(L, base); + } + // Stack: [results or errmsg] + + // lua_pcall returns 0 on success. + // On error print the error and push nils for expected amount of returned values + if (result) + { + // Stack: errmsg + Report(L); + + // Force garbage collect + lua_gc(L, LUA_GCCOLLECT, 0); + + // Push nils for expected amount of results + for (int i = 0; i < res; ++i) + lua_pushnil(L); + // Stack: [nils] + return false; + } + + // Stack: [results] + return true; +} + +void Eluna::Push(lua_State* luastate) +{ + lua_pushnil(luastate); +} +void Eluna::Push(lua_State* luastate, const long long l) +{ + ElunaTemplate::Push(luastate, new long long(l)); +} +void Eluna::Push(lua_State* luastate, const unsigned long long l) +{ + ElunaTemplate::Push(luastate, new unsigned long long(l)); +} +void Eluna::Push(lua_State* luastate, const long l) +{ + Push(luastate, static_cast(l)); +} +void Eluna::Push(lua_State* luastate, const unsigned long l) +{ + Push(luastate, static_cast(l)); +} +void Eluna::Push(lua_State* luastate, const int i) +{ + lua_pushinteger(luastate, i); +} +void Eluna::Push(lua_State* luastate, const unsigned int u) +{ + lua_pushunsigned(luastate, u); +} +void Eluna::Push(lua_State* luastate, const double d) +{ + lua_pushnumber(luastate, d); +} +void Eluna::Push(lua_State* luastate, const float f) +{ + lua_pushnumber(luastate, f); +} +void Eluna::Push(lua_State* luastate, const bool b) +{ + lua_pushboolean(luastate, b); +} +void Eluna::Push(lua_State* luastate, const std::string& str) +{ + lua_pushstring(luastate, str.c_str()); +} +void Eluna::Push(lua_State* luastate, const char* str) +{ + lua_pushstring(luastate, str); +} +void Eluna::Push(lua_State* luastate, Pet const* pet) +{ + Push(luastate, pet); +} +void Eluna::Push(lua_State* luastate, TempSummon const* summon) +{ + Push(luastate, summon); +} +void Eluna::Push(lua_State* luastate, Unit const* unit) +{ + if (!unit) + { + Push(luastate); + return; + } + switch (unit->GetTypeId()) + { + case TYPEID_UNIT: + Push(luastate, unit->ToCreature()); + break; + case TYPEID_PLAYER: + Push(luastate, unit->ToPlayer()); + break; + default: + ElunaTemplate::Push(luastate, unit); + } +} +void Eluna::Push(lua_State* luastate, WorldObject const* obj) +{ + if (!obj) + { + Push(luastate); + return; + } + switch (obj->GetTypeId()) + { + case TYPEID_UNIT: + Push(luastate, obj->ToCreature()); + break; + case TYPEID_PLAYER: + Push(luastate, obj->ToPlayer()); + break; + case TYPEID_GAMEOBJECT: + Push(luastate, obj->ToGameObject()); + break; + case TYPEID_CORPSE: + Push(luastate, obj->ToCorpse()); + break; + default: + ElunaTemplate::Push(luastate, obj); + } +} +void Eluna::Push(lua_State* luastate, Object const* obj) +{ + if (!obj) + { + Push(luastate); + return; + } + switch (obj->GetTypeId()) + { + case TYPEID_UNIT: + Push(luastate, obj->ToCreature()); + break; + case TYPEID_PLAYER: + Push(luastate, obj->ToPlayer()); + break; + case TYPEID_GAMEOBJECT: + Push(luastate, obj->ToGameObject()); + break; + case TYPEID_CORPSE: + Push(luastate, obj->ToCorpse()); + break; + default: + ElunaTemplate::Push(luastate, obj); + } +} +void Eluna::Push(lua_State* luastate, ObjectGuid const guid) +{ + ElunaTemplate::Push(luastate, new unsigned long long(guid.GetRawValue())); +} + +static int CheckIntegerRange(lua_State* luastate, int narg, int min, int max) +{ + double value = luaL_checknumber(luastate, narg); + char error_buffer[64]; + + if (value > max) + { + snprintf(error_buffer, 64, "value must be less than or equal to %i", max); + return luaL_argerror(luastate, narg, error_buffer); + } + + if (value < min) + { + snprintf(error_buffer, 64, "value must be greater than or equal to %i", min); + return luaL_argerror(luastate, narg, error_buffer); + } + + return static_cast(value); +} + +static unsigned int CheckUnsignedRange(lua_State* luastate, int narg, unsigned int max) +{ + double value = luaL_checknumber(luastate, narg); + + if (value < 0) + return luaL_argerror(luastate, narg, "value must be greater than or equal to 0"); + + if (value > max) + { + char error_buffer[64]; + snprintf(error_buffer, 64, "value must be less than or equal to %u", max); + return luaL_argerror(luastate, narg, error_buffer); + } + + return static_cast(value); +} + +template<> bool Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return lua_toboolean(luastate, narg) != 0; +} +template<> float Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return static_cast(luaL_checknumber(luastate, narg)); +} +template<> double Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return luaL_checknumber(luastate, narg); +} +template<> signed char Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckIntegerRange(luastate, narg, SCHAR_MIN, SCHAR_MAX); +} +template<> unsigned char Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckUnsignedRange(luastate, narg, UCHAR_MAX); +} +template<> short Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckIntegerRange(luastate, narg, SHRT_MIN, SHRT_MAX); +} +template<> unsigned short Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckUnsignedRange(luastate, narg, USHRT_MAX); +} +template<> int Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckIntegerRange(luastate, narg, INT_MIN, INT_MAX); +} +template<> unsigned int Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return CheckUnsignedRange(luastate, narg, UINT_MAX); +} +template<> const char* Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return luaL_checkstring(luastate, narg); +} +template<> std::string Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return luaL_checkstring(luastate, narg); +} +template<> long long Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + if (lua_isnumber(luastate, narg)) + return static_cast(CHECKVAL(luastate, narg)); + return *(Eluna::CHECKOBJ(luastate, narg, true)); +} +template<> unsigned long long Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + if (lua_isnumber(luastate, narg)) + return static_cast(CHECKVAL(luastate, narg)); + return *(Eluna::CHECKOBJ(luastate, narg, true)); +} +template<> long Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return static_cast(CHECKVAL(luastate, narg)); +} +template<> unsigned long Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return static_cast(CHECKVAL(luastate, narg)); +} +template<> ObjectGuid Eluna::CHECKVAL(lua_State* luastate, int narg) +{ + return ObjectGuid(uint64((CHECKVAL(luastate, narg)))); +} + +template<> Object* Eluna::CHECKOBJ(lua_State* luastate, int narg, bool error) +{ + Object* obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = ElunaTemplate::Check(luastate, narg, error); + return obj; +} +template<> WorldObject* Eluna::CHECKOBJ(lua_State* luastate, int narg, bool error) +{ + WorldObject* obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = ElunaTemplate::Check(luastate, narg, error); + return obj; +} +template<> Unit* Eluna::CHECKOBJ(lua_State* luastate, int narg, bool error) +{ + Unit* obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = CHECKOBJ(luastate, narg, false); + if (!obj) + obj = ElunaTemplate::Check(luastate, narg, error); + return obj; +} + +template<> ElunaObject* Eluna::CHECKOBJ(lua_State* luastate, int narg, bool error) +{ + return CHECKTYPE(luastate, narg, NULL, error); +} + +ElunaObject* Eluna::CHECKTYPE(lua_State* luastate, int narg, const char* tname, bool error) +{ + if (lua_islightuserdata(luastate, narg)) + { + if (error) + luaL_argerror(luastate, narg, "bad argument : userdata expected, got lightuserdata"); + return NULL; + } + + ElunaObject** ptrHold = static_cast(lua_touserdata(luastate, narg)); + + if (!ptrHold || (tname && (*ptrHold)->GetTypeName() != tname)) + { + if (error) + { + char buff[256]; + snprintf(buff, 256, "bad argument : %s expected, got %s", tname ? tname : "ElunaObject", ptrHold ? (*ptrHold)->GetTypeName() : luaL_typename(luastate, narg)); + luaL_argerror(luastate, narg, buff); + } + return NULL; + } + return *ptrHold; +} + +template +static int cancelBinding(lua_State *L) +{ + uint64 bindingID = Eluna::CHECKVAL(L, lua_upvalueindex(1)); + + BindingMap* bindings = (BindingMap*)lua_touserdata(L, lua_upvalueindex(2)); + ASSERT(bindings != NULL); + + bindings->Remove(bindingID); + + return 0; +} + +template +static void createCancelCallback(lua_State* L, uint64 bindingID, BindingMap* bindings) +{ + Eluna::Push(L, bindingID); + lua_pushlightuserdata(L, bindings); + // Stack: bindingID, bindings + + lua_pushcclosure(L, &cancelBinding, 2); + // Stack: cancel_callback +} + +// Saves the function reference ID given to the register type's store for given entry under the given event +int Eluna::Register(lua_State* L, uint8 regtype, uint32 entry, ObjectGuid guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots) +{ + uint64 bindingID; + + switch (regtype) + { + case Hooks::REGTYPE_SERVER: + if (event_id < Hooks::SERVER_EVENT_COUNT) + { + auto key = EventKey((Hooks::ServerEvents)event_id); + bindingID = ServerEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ServerEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_PLAYER: + if (event_id < Hooks::PLAYER_EVENT_COUNT) + { + auto key = EventKey((Hooks::PlayerEvents)event_id); + bindingID = PlayerEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PlayerEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_GUILD: + if (event_id < Hooks::GUILD_EVENT_COUNT) + { + auto key = EventKey((Hooks::GuildEvents)event_id); + bindingID = GuildEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GuildEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_GROUP: + if (event_id < Hooks::GROUP_EVENT_COUNT) + { + auto key = EventKey((Hooks::GroupEvents)event_id); + bindingID = GroupEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GroupEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_VEHICLE: + if (event_id < Hooks::VEHICLE_EVENT_COUNT) + { + auto key = EventKey((Hooks::VehicleEvents)event_id); + bindingID = VehicleEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, VehicleEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_BG: + if (event_id < Hooks::BG_EVENT_COUNT) + { + auto key = EventKey((Hooks::BGEvents)event_id); + bindingID = BGEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, BGEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_PACKET: + if (event_id < Hooks::PACKET_EVENT_COUNT) + { + if (entry >= NUM_MSG_TYPES) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::PacketEvents)event_id, entry); + bindingID = PacketEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PacketEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_CREATURE: + if (event_id < Hooks::CREATURE_EVENT_COUNT) + { + if (entry != 0) + { + if (!eObjectMgr->GetCreatureTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::CreatureEvents)event_id, entry); + bindingID = CreatureEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureEventBindings); + } + else + { + if (guid.IsEmpty()) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "guid was 0!"); + return 0; // Stack: (empty) + } + + auto key = UniqueObjectKey((Hooks::CreatureEvents)event_id, guid, instanceId); + bindingID = CreatureUniqueBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureUniqueBindings); + } + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_CREATURE_GOSSIP: + if (event_id < Hooks::GOSSIP_EVENT_COUNT) + { + if (!eObjectMgr->GetCreatureTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = CreatureGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, CreatureGossipBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_GAMEOBJECT: + if (event_id < Hooks::GAMEOBJECT_EVENT_COUNT) + { + if (!eObjectMgr->GetGameObjectTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::GameObjectEvents)event_id, entry); + bindingID = GameObjectEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GameObjectEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_GAMEOBJECT_GOSSIP: + if (event_id < Hooks::GOSSIP_EVENT_COUNT) + { + if (!eObjectMgr->GetGameObjectTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a gameobject with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = GameObjectGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, GameObjectGossipBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_ITEM: + if (event_id < Hooks::ITEM_EVENT_COUNT) + { + if (!eObjectMgr->GetItemTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a item with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::ItemEvents)event_id, entry); + bindingID = ItemEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ItemEventBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_ITEM_GOSSIP: + if (event_id < Hooks::GOSSIP_EVENT_COUNT) + { + if (!eObjectMgr->GetItemTemplate(entry)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a item with (ID: %d)!", entry); + return 0; // Stack: (empty) + } + + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = ItemGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, ItemGossipBindings); + return 1; // Stack: callback + } + break; + + case Hooks::REGTYPE_PLAYER_GOSSIP: + if (event_id < Hooks::GOSSIP_EVENT_COUNT) + { + auto key = EntryKey((Hooks::GossipEvents)event_id, entry); + bindingID = PlayerGossipBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, PlayerGossipBindings); + return 1; // Stack: callback + } + break; + case Hooks::REGTYPE_MAP: + if (event_id < Hooks::INSTANCE_EVENT_COUNT) + { + auto key = EntryKey((Hooks::InstanceEvents)event_id, entry); + bindingID = MapEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, MapEventBindings); + return 1; // Stack: callback + } + break; + case Hooks::REGTYPE_INSTANCE: + if (event_id < Hooks::INSTANCE_EVENT_COUNT) + { + auto key = EntryKey((Hooks::InstanceEvents)event_id, entry); + bindingID = InstanceEventBindings->Insert(key, functionRef, shots); + createCancelCallback(L, bindingID, InstanceEventBindings); + return 1; // Stack: callback + } + break; + } + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + std::ostringstream oss; + oss << "regtype " << static_cast(regtype) << ", event " << event_id << ", entry " << entry << ", guid " << guid.GetRawValue() << ", instance " << instanceId; + luaL_error(L, "Unknown event type (%s)", oss.str().c_str()); + return 0; +} + +/* + * Cleans up the stack, effectively undoing all Push calls and the Setup call. + */ +void Eluna::CleanUpStack(int number_of_arguments) +{ + // Stack: event_id, [arguments] + + lua_pop(L, number_of_arguments + 1); // Add 1 because the caller doesn't know about `event_id`. + // Stack: (empty) + + if (event_level == 0) + InvalidateObjects(); +} + +/* + * Call a single event handler that was put on the stack with `Setup` and removes it from the stack. + * + * The caller is responsible for keeping track of how many times this should be called. + */ +int Eluna::CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results) +{ + ++number_of_arguments; // Caller doesn't know about `event_id`. + ASSERT(number_of_functions > 0 && number_of_arguments > 0 && number_of_results >= 0); + // Stack: event_id, [arguments], [functions] + + int functions_top = lua_gettop(L); + int first_function_index = functions_top - number_of_functions + 1; + int arguments_top = first_function_index - 1; + int first_argument_index = arguments_top - number_of_arguments + 1; + + // Copy the arguments from the bottom of the stack to the top. + for (int argument_index = first_argument_index; argument_index <= arguments_top; ++argument_index) + { + lua_pushvalue(L, argument_index); + } + // Stack: event_id, [arguments], [functions], event_id, [arguments] + + ExecuteCall(number_of_arguments, number_of_results); + --functions_top; + // Stack: event_id, [arguments], [functions - 1], [results] + + return functions_top + 1; // Return the location of the first result (if any exist). +} + +CreatureAI* Eluna::GetAI(Creature* creature) +{ + if (!IsEnabled()) + return NULL; + + for (int i = 1; i < Hooks::CREATURE_EVENT_COUNT; ++i) + { + Hooks::CreatureEvents event_id = (Hooks::CreatureEvents)i; + + auto entryKey = EntryKey(event_id, creature->GetEntry()); + auto uniqueKey = UniqueObjectKey(event_id, creature->GET_GUID(), creature->GetInstanceId()); + + if (CreatureEventBindings->HasBindingsFor(entryKey) || + CreatureUniqueBindings->HasBindingsFor(uniqueKey)) + return new ElunaCreatureAI(creature); + } + + return NULL; +} + +InstanceData* Eluna::GetInstanceData(Map* map) +{ + if (!IsEnabled()) + return NULL; + + for (int i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i) + { + Hooks::InstanceEvents event_id = (Hooks::InstanceEvents)i; + + auto key = EntryKey(event_id, map->GetId()); + + if (MapEventBindings->HasBindingsFor(key) || + InstanceEventBindings->HasBindingsFor(key)) + return new ElunaInstanceAI(map); + } + + return NULL; +} + +bool Eluna::HasInstanceData(Map const* map) +{ + if (!map->Instanceable()) + return continentDataRefs.find(map->GetId()) != continentDataRefs.end(); + else + return instanceDataRefs.find(map->GetInstanceId()) != instanceDataRefs.end(); +} + +void Eluna::CreateInstanceData(Map const* map) +{ + ASSERT(lua_istable(L, -1)); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if (!map->Instanceable()) + { + uint32 mapId = map->GetId(); + + // If there's another table that was already stored for the map, unref it. + auto mapRef = continentDataRefs.find(mapId); + if (mapRef != continentDataRefs.end()) + { + luaL_unref(L, LUA_REGISTRYINDEX, mapRef->second); + } + + continentDataRefs[mapId] = ref; + } + else + { + uint32 instanceId = map->GetInstanceId(); + + // If there's another table that was already stored for the instance, unref it. + auto instRef = instanceDataRefs.find(instanceId); + if (instRef != instanceDataRefs.end()) + { + luaL_unref(L, LUA_REGISTRYINDEX, instRef->second); + } + + instanceDataRefs[instanceId] = ref; + } +} + +/* + * Unrefs the instanceId related events and data + * Does all required actions for when an instance is freed. + */ +void Eluna::FreeInstanceId(uint32 instanceId) +{ + LOCK_ELUNA; + + if (!IsEnabled()) + return; + + for (int i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i) + { + auto key = EntryKey((Hooks::InstanceEvents)i, instanceId); + + if (MapEventBindings->HasBindingsFor(key)) + MapEventBindings->Clear(key); + + if (InstanceEventBindings->HasBindingsFor(key)) + InstanceEventBindings->Clear(key); + + if (instanceDataRefs.find(instanceId) != instanceDataRefs.end()) + { + luaL_unref(L, LUA_REGISTRYINDEX, instanceDataRefs[instanceId]); + instanceDataRefs.erase(instanceId); + } + } +} + +void Eluna::PushInstanceData(lua_State* L, ElunaInstanceAI* ai, bool incrementCounter) +{ + // Check if the instance data is missing (i.e. someone reloaded Eluna). + if (!HasInstanceData(ai->instance)) + ai->Reload(); + + // Get the instance data table from the registry. + if (!ai->instance->Instanceable()) + lua_rawgeti(L, LUA_REGISTRYINDEX, continentDataRefs[ai->instance->GetId()]); + else + lua_rawgeti(L, LUA_REGISTRYINDEX, instanceDataRefs[ai->instance->GetInstanceId()]); + + ASSERT(lua_istable(L, -1)); + + if (incrementCounter) + ++push_counter; +} diff --git a/modules/mod-eluna/src/LuaEngine/LuaEngine.h b/modules/mod-eluna/src/LuaEngine/LuaEngine.h new file mode 100644 index 0000000..6955356 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/LuaEngine.h @@ -0,0 +1,590 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef _LUA_ENGINE_H +#define _LUA_ENGINE_H + +#include "Common.h" +#include "SharedDefines.h" +#include "DBCEnums.h" + +#include "Group.h" +#include "Item.h" +#include "Chat.h" +#ifndef TRINITY +#include "Player.h" +#endif +#include "Weather.h" +#include "World.h" +#include "Hooks.h" +#include "LFG.h" +#include "ElunaUtility.h" +#include "HttpManager.h" +#include "EventEmitter.h" +#include +#include + +extern "C" +{ +#include "lua.h" +}; + +#if defined(TRINITY) || AZEROTHCORE +struct ItemTemplate; +typedef BattlegroundTypeId BattleGroundTypeId; +#else +struct ItemPrototype; +typedef ItemPrototype ItemTemplate; +typedef SpellEffectIndex SpellEffIndex; +struct SpellEntry; +typedef SpellEntry SpellInfo; +#ifdef CLASSIC +typedef int Difficulty; +#endif +#endif +#ifndef AZEROTHCORE +struct AreaTriggerEntry; +#else +typedef AreaTrigger AreaTriggerEntry; +#endif +class AuctionHouseObject; +struct AuctionEntry; +#if defined(TRINITY) || AZEROTHCORE +class Battleground; +typedef Battleground BattleGround; +#endif +class Channel; +class Corpse; +class Creature; +class CreatureAI; +class GameObject; +#if defined(TRINITY) || AZEROTHCORE +class GameObjectAI; +#endif +class Guild; +class Group; +#if defined(TRINITY) || AZEROTHCORE +class InstanceScript; +typedef InstanceScript InstanceData; +#else +class InstanceData; +#endif +class ElunaInstanceAI; +class Item; +class Pet; +class Player; +class Quest; +class Spell; +class SpellCastTargets; +#if defined(TRINITY) || AZEROTHCORE +class TempSummon; +#else +class TemporarySummon; +typedef TemporarySummon TempSummon; +#endif +// class Transport; +class Unit; +class Weather; +class WorldPacket; +#ifndef CLASSIC +#ifndef TBC +#if defined(TRINITY) || AZEROTHCORE +class Vehicle; +#else +class VehicleInfo; +typedef VehicleInfo Vehicle; +#endif +#endif +#endif + +struct lua_State; +class EventMgr; +class ElunaObject; +template class ElunaTemplate; + +template class BindingMap; +template struct EventKey; +template struct EntryKey; +template struct UniqueObjectKey; + +struct LuaScript +{ + std::string fileext; + std::string filename; + std::string filepath; + std::string modulepath; +}; + +#define ELUNA_STATE_PTR "Eluna State Ptr" +#define LOCK_ELUNA Eluna::Guard __guard(Eluna::GetLock()) + +#if defined(TRINITY) +#define ELUNA_GAME_API TC_GAME_API +#elif defined(AZEROTHCORE) +#define ELUNA_GAME_API AC_GAME_API +#else +#define ELUNA_GAME_API +#endif + +class ELUNA_GAME_API Eluna +{ +public: + typedef std::list ScriptList; + + typedef std::recursive_mutex LockType; + typedef std::lock_guard Guard; + +private: + static bool reload; + static bool initialized; + static LockType lock; + + // Lua script locations + static ScriptList lua_scripts; + static ScriptList lua_extensions; + + // Lua script folder path + static std::string lua_folderpath; + // lua path variable for require() function + static std::string lua_requirepath; + + // A counter for lua event stacks that occur (see event_level). + // This is used to determine whether an object belongs to the current call stack or not. + // 0 is reserved for always belonging to the call stack + // 1 is reserved for a non valid callstackid + uint64 callstackid = 2; + // A counter for the amount of nested events. When the event_level + // reaches 0 we are about to return back to C++. At this point the + // objects used during the event stack are invalidated. + uint32 event_level; + // When a hook pushes arguments to be passed to event handlers, + // this is used to keep track of how many arguments were pushed. + uint8 push_counter; + bool enabled; + + // Map from instance ID -> Lua table ref + std::unordered_map instanceDataRefs; + // Map from map ID -> Lua table ref + std::unordered_map continentDataRefs; + + Eluna(); + ~Eluna(); + + // Prevent copy + Eluna(Eluna const&) = delete; + Eluna& operator=(const Eluna&) = delete; + + void OpenLua(); + void CloseLua(); + void DestroyBindStores(); + void CreateBindStores(); + void InvalidateObjects(); + + // Use ReloadEluna() to make eluna reload + // This is called on world update to reload eluna + static void _ReloadEluna(); + static void LoadScriptPaths(); + static void GetScripts(std::string path); + static void AddScriptPath(std::string filename, const std::string& fullpath); + + static int StackTrace(lua_State *_L); + static void Report(lua_State* _L); + + // Some helpers for hooks to call event handlers. + // The bodies of the templates are in HookHelpers.h, so if you want to use them you need to #include "HookHelpers.h". + template int SetupStack(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, int number_of_arguments); + int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); + void CleanUpStack(int number_of_arguments); + template void ReplaceArgument(T value, uint8 index); + template void CallAllFunctions(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2); + template bool CallAllFunctionsBool(BindingMap* bindings1, BindingMap* bindings2, const K1& key1, const K2& key2, bool default_value = false); + + // Same as above but for only one binding instead of two. + // `key` is passed twice because there's no NULL for references, but it's not actually used if `bindings2` is NULL. + template int SetupStack(BindingMap* bindings, const K& key, int number_of_arguments) + { + return SetupStack(bindings, NULL, key, key, number_of_arguments); + } + template void CallAllFunctions(BindingMap* bindings, const K& key) + { + CallAllFunctions(bindings, NULL, key, key); + } + template bool CallAllFunctionsBool(BindingMap* bindings, const K& key, bool default_value = false) + { + return CallAllFunctionsBool(bindings, NULL, key, key, default_value); + } + + // Non-static pushes, to be used in hooks. + // These just call the correct static version with the main thread's Lua state. + void Push() { Push(L); ++push_counter; } + void Push(const long long value) { Push(L, value); ++push_counter; } + void Push(const unsigned long long value) { Push(L, value); ++push_counter; } + void Push(const long value) { Push(L, value); ++push_counter; } + void Push(const unsigned long value) { Push(L, value); ++push_counter; } + void Push(const int value) { Push(L, value); ++push_counter; } + void Push(const unsigned int value) { Push(L, value); ++push_counter; } + void Push(const bool value) { Push(L, value); ++push_counter; } + void Push(const float value) { Push(L, value); ++push_counter; } + void Push(const double value) { Push(L, value); ++push_counter; } + void Push(const std::string& value) { Push(L, value); ++push_counter; } + void Push(const char* value) { Push(L, value); ++push_counter; } + void Push(ObjectGuid const value) { Push(L, value); ++push_counter; } + template + void Push(T const* ptr) { Push(L, ptr); ++push_counter; } + +public: + static Eluna* GEluna; + + lua_State* L; + EventMgr* eventMgr; + HttpManager httpManager; + QueryCallbackProcessor queryProcessor; + EventEmitter OnError; + + BindingMap< EventKey >* ServerEventBindings; + BindingMap< EventKey >* PlayerEventBindings; + BindingMap< EventKey >* GuildEventBindings; + BindingMap< EventKey >* GroupEventBindings; + BindingMap< EventKey >* VehicleEventBindings; + BindingMap< EventKey >* BGEventBindings; + + BindingMap< EntryKey >* PacketEventBindings; + BindingMap< EntryKey >* CreatureEventBindings; + BindingMap< EntryKey >* CreatureGossipBindings; + BindingMap< EntryKey >* GameObjectEventBindings; + BindingMap< EntryKey >* GameObjectGossipBindings; + BindingMap< EntryKey >* ItemEventBindings; + BindingMap< EntryKey >* ItemGossipBindings; + BindingMap< EntryKey >* PlayerGossipBindings; + BindingMap< EntryKey >* MapEventBindings; + BindingMap< EntryKey >* InstanceEventBindings; + + BindingMap< UniqueObjectKey >* CreatureUniqueBindings; + + static void Initialize(); + static void Uninitialize(); + // This function is used to make eluna reload + static void ReloadEluna() { LOCK_ELUNA; reload = true; } + static LockType& GetLock() { return lock; }; + static bool IsInitialized() { return initialized; } + // Never returns nullptr + static Eluna* GetEluna(lua_State* L) + { + lua_pushstring(L, ELUNA_STATE_PTR); + lua_rawget(L, LUA_REGISTRYINDEX); + ASSERT(lua_islightuserdata(L, -1)); + Eluna* E = static_cast(lua_touserdata(L, -1)); + lua_pop(L, 1); + ASSERT(E); + return E; + } + + // Static pushes, can be used by anything, including methods. + static void Push(lua_State* luastate); // nil + static void Push(lua_State* luastate, const long long); + static void Push(lua_State* luastate, const unsigned long long); + static void Push(lua_State* luastate, const long); + static void Push(lua_State* luastate, const unsigned long); + static void Push(lua_State* luastate, const int); + static void Push(lua_State* luastate, const unsigned int); + static void Push(lua_State* luastate, const bool); + static void Push(lua_State* luastate, const float); + static void Push(lua_State* luastate, const double); + static void Push(lua_State* luastate, const std::string&); + static void Push(lua_State* luastate, const char*); + static void Push(lua_State* luastate, Object const* obj); + static void Push(lua_State* luastate, WorldObject const* obj); + static void Push(lua_State* luastate, Unit const* unit); + static void Push(lua_State* luastate, Pet const* pet); + static void Push(lua_State* luastate, TempSummon const* summon); + static void Push(lua_State* luastate, ObjectGuid const guid); + template + static void Push(lua_State* luastate, T const* ptr) + { + ElunaTemplate::Push(luastate, ptr); + } + + bool ExecuteCall(int params, int res); + + /* + * Returns `true` if Eluna has instance data for `map`. + */ + bool HasInstanceData(Map const* map); + + /* + * Use the top element of the stack as the instance data table for `map`, + * then pops it off the stack. + */ + void CreateInstanceData(Map const* map); + + /* + * Retrieve the instance data for the `Map` scripted by `ai` and push it + * onto the stack. + * + * An `ElunaInstanceAI` is needed because the instance data might + * not exist (i.e. Eluna has been reloaded). + * + * In that case, the AI is "reloaded" (new instance data table is created + * and loaded with the last known save state, and `Load`/`Initialize` + * hooks are called). + */ + void PushInstanceData(lua_State* L, ElunaInstanceAI* ai, bool incrementCounter = true); + + void RunScripts(); + bool ShouldReload() const { return reload; } + bool IsEnabled() const { return enabled && IsInitialized(); } + bool HasLuaState() const { return L != NULL; } + uint64 GetCallstackId() const { return callstackid; } + int Register(lua_State* L, uint8 reg, uint32 entry, ObjectGuid guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots); + + // Checks + template static T CHECKVAL(lua_State* luastate, int narg); + template static T CHECKVAL(lua_State* luastate, int narg, T def) + { + return lua_isnoneornil(luastate, narg) ? def : CHECKVAL(luastate, narg); + } + template static T* CHECKOBJ(lua_State* luastate, int narg, bool error = true) + { + return ElunaTemplate::Check(luastate, narg, error); + } + static ElunaObject* CHECKTYPE(lua_State* luastate, int narg, const char *tname, bool error = true); + + CreatureAI* GetAI(Creature* creature); + InstanceData* GetInstanceData(Map* map); + void FreeInstanceId(uint32 instanceId); + + /* Custom */ + void OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj); + bool OnCommand(ChatHandler& handler, const char* text); + void OnWorldUpdate(uint32 diff); + void OnLootItem(Player* pPlayer, Item* pItem, uint32 count, ObjectGuid guid); + void OnLootMoney(Player* pPlayer, uint32 amount); + void OnFirstLogin(Player* pPlayer); + void OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot); + void OnRepop(Player* pPlayer); + void OnResurrect(Player* pPlayer); + void OnQuestAbandon(Player* pPlayer, uint32 questId); + void OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid); + InventoryResult OnCanUseItem(const Player* pPlayer, uint32 itemEntry); + void OnLuaStateClose(); + void OnLuaStateOpen(); + bool OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel); + void OnPetAddedToWorld(Player* player, Creature* pet); + void OnQuestRewardItem(Player* player, Item* item, uint32 count); + void OnCreateItem(Player* player, Item* item, uint32 count); + void OnStoreNewItem(Player* player, Item* item, uint32 count); + void OnPlayerCompleteQuest(Player* player, Quest const* quest); + + /* Item */ + void OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget); + bool OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest); + bool OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); + bool OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); + bool OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); + bool OnExpire(Player* pPlayer, ItemTemplate const* pProto); + bool OnRemove(Player* pPlayer, Item* item); + void HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code); + + /* Creature */ + void OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget); + bool OnGossipHello(Player* pPlayer, Creature* pCreature); + bool OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action); + bool OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code); + bool OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest); + bool OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt); + void GetDialogStatus(const Player* pPlayer, const Creature* pCreature); + + bool OnSummoned(Creature* creature, Unit* summoner); + bool UpdateAI(Creature* me, const uint32 diff); + bool EnterCombat(Creature* me, Unit* target); + bool DamageTaken(Creature* me, Unit* attacker, uint32& damage); + bool JustDied(Creature* me, Unit* killer); + bool KilledUnit(Creature* me, Unit* victim); + bool JustSummoned(Creature* me, Creature* summon); + bool SummonedCreatureDespawn(Creature* me, Creature* summon); + bool MovementInform(Creature* me, uint32 type, uint32 id); + bool AttackStart(Creature* me, Unit* target); + bool EnterEvadeMode(Creature* me); + bool JustRespawned(Creature* me); + bool JustReachedHome(Creature* me); + bool ReceiveEmote(Creature* me, Player* player, uint32 emoteId); + bool CorpseRemoved(Creature* me, uint32& respawnDelay); + bool MoveInLineOfSight(Creature* me, Unit* who); + bool SpellHit(Creature* me, WorldObject* caster, SpellInfo const* spell); + bool SpellHitTarget(Creature* me, WorldObject* target, SpellInfo const* spell); + bool SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer); + bool OwnerAttackedBy(Creature* me, Unit* attacker); + bool OwnerAttacked(Creature* me, Unit* target); + void On_Reset(Creature* me); + + /* GameObject */ + void OnDummyEffect(WorldObject* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget); + bool OnGameObjectUse(Player* pPlayer, GameObject* pGameObject); + bool OnGossipHello(Player* pPlayer, GameObject* pGameObject); + bool OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action); + bool OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code); + bool OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest); + bool OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt); + void GetDialogStatus(const Player* pPlayer, const GameObject* pGameObject); +#ifndef CLASSIC +#ifndef TBC + void OnDestroyed(GameObject* pGameObject, WorldObject* attacker); + void OnDamaged(GameObject* pGameObject, WorldObject* attacker); +#endif +#endif + void OnLootStateChanged(GameObject* pGameObject, uint32 state); + void OnGameObjectStateChanged(GameObject* pGameObject, uint32 state); + void UpdateAI(GameObject* pGameObject, uint32 diff); + void OnSpawn(GameObject* gameobject); + + /* Packet */ + bool OnPacketSend(WorldSession* session, const WorldPacket& packet); + void OnPacketSendAny(Player* player, const WorldPacket& packet, bool& result); + void OnPacketSendOne(Player* player, const WorldPacket& packet, bool& result); + bool OnPacketReceive(WorldSession* session, WorldPacket& packet); + void OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result); + void OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result); + + /* Player */ + void OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy); + void OnPlayerLeaveCombat(Player* pPlayer); + void OnPVPKill(Player* pKiller, Player* pKilled); + void OnCreatureKill(Player* pKiller, Creature* pKilled); + void OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled); + void OnLevelChanged(Player* pPlayer, uint8 oldLevel); + void OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints); + void OnTalentsReset(Player* pPlayer, bool noCost); + void OnMoneyChanged(Player* pPlayer, int32& amount); + void OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim, uint8 xpSource); + bool OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental); + void OnDuelRequest(Player* pTarget, Player* pChallenger); + void OnDuelStart(Player* pStarter, Player* pChallenger); + void OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type); + bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg); + bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup); + bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild); + bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel); + bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver); + void OnEmote(Player* pPlayer, uint32 emote); + void OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, ObjectGuid guid); + void OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck); + void OnLogin(Player* pPlayer); + void OnLogout(Player* pPlayer); + void OnCreate(Player* pPlayer); + void OnDelete(uint32 guid); + void OnSave(Player* pPlayer); + void OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent); + void OnUpdateArea(Player* pPlayer, uint32 oldArea, uint32 newArea); + void OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea); + void OnMapChanged(Player* pPlayer); + void HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code); + void OnLearnSpell(Player* player, uint32 spellId); + void OnAchiComplete(Player* player, AchievementEntry const* achievement); + void OnFfaPvpStateUpdate(Player* player, bool hasFfaPvp); + bool OnCanInitTrade(Player* player, Player* target); + bool OnCanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 cod, Item* item); + bool OnCanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment); + bool OnCanGroupInvite(Player* player, std::string& memberName); + void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll); + void OnBattlegroundDesertion(Player* player, const BattlegroundDesertionType type); + +#ifndef CLASSIC +#ifndef TBC + /* Vehicle */ + void OnInstall(Vehicle* vehicle); + void OnUninstall(Vehicle* vehicle); + void OnInstallAccessory(Vehicle* vehicle, Creature* accessory); + void OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId); + void OnRemovePassenger(Vehicle* vehicle, Unit* passenger); +#endif +#endif + + /* AreaTrigger */ + bool OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger); + + /* Weather */ + void OnChange(Weather* weather, uint32 zone, WeatherState state, float grade); + + /* Auction House */ + void OnAdd(AuctionHouseObject* ah, AuctionEntry* entry); + void OnRemove(AuctionHouseObject* ah, AuctionEntry* entry); + void OnSuccessful(AuctionHouseObject* ah, AuctionEntry* entry); + void OnExpire(AuctionHouseObject* ah, AuctionEntry* entry); + + /* Guild */ + void OnAddMember(Guild* guild, Player* player, uint32 plRank); + void OnRemoveMember(Guild* guild, Player* player, bool isDisbanding); + void OnMOTDChanged(Guild* guild, const std::string& newMotd); + void OnInfoChanged(Guild* guild, const std::string& newInfo); + void OnCreate(Guild* guild, Player* leader, const std::string& name); + void OnDisband(Guild* guild); + void OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair); + void OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount); + void OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, bool isDestBank, uint8 destContainer, uint8 destSlotId); + void OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank); + void OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId); + + /* Group */ + void OnAddMember(Group* group, ObjectGuid guid); + void OnInviteMember(Group* group, ObjectGuid guid); + void OnRemoveMember(Group* group, ObjectGuid guid, uint8 method); + void OnChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid); + void OnDisband(Group* group); + void OnCreate(Group* group, ObjectGuid leaderGuid, GroupType groupType); + + /* Map */ + void OnCreate(Map* map); + void OnDestroy(Map* map); + void OnPlayerEnter(Map* map, Player* player); + void OnPlayerLeave(Map* map, Player* player); + void OnUpdate(Map* map, uint32 diff); + void OnAddToWorld(Creature* creature); + void OnRemoveFromWorld(Creature* creature); + void OnAddToWorld(GameObject* gameobject); + void OnRemoveFromWorld(GameObject* gameobject); + void OnRemove(Creature* creature); + void OnRemove(GameObject* gameobject); + + /* Instance */ + void OnInitialize(ElunaInstanceAI* ai); + void OnLoad(ElunaInstanceAI* ai); + void OnUpdateInstance(ElunaInstanceAI* ai, uint32 diff); + void OnPlayerEnterInstance(ElunaInstanceAI* ai, Player* player); + void OnCreatureCreate(ElunaInstanceAI* ai, Creature* creature); + void OnGameObjectCreate(ElunaInstanceAI* ai, GameObject* gameobject); + bool OnCheckEncounterInProgress(ElunaInstanceAI* ai); + + /* World */ + void OnOpenStateChange(bool open); +#ifndef AZEROTHCORE + void OnConfigLoad(bool reload); +#else + void OnConfigLoad(bool reload, bool isBefore); +#endif + void OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask); + void OnShutdownCancel(); + void OnStartup(); + void OnShutdown(); + void OnGameEventStart(uint32 eventid); + void OnGameEventStop(uint32 eventid); + + /* Battle Ground */ + void OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId); +#if AZEROTHCORE + void OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, TeamId winner); +#else + void OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner); +#endif + void OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId); + void OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId); +}; +template<> Unit* Eluna::CHECKOBJ(lua_State* L, int narg, bool error); +template<> Object* Eluna::CHECKOBJ(lua_State* L, int narg, bool error); +template<> WorldObject* Eluna::CHECKOBJ(lua_State* L, int narg, bool error); +template<> ElunaObject* Eluna::CHECKOBJ(lua_State* L, int narg, bool error); + +#define sEluna Eluna::GEluna +#endif diff --git a/modules/mod-eluna/src/LuaEngine/LuaFunctions.cpp b/modules/mod-eluna/src/LuaEngine/LuaFunctions.cpp new file mode 100644 index 0000000..ebf32d8 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/LuaFunctions.cpp @@ -0,0 +1,1554 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +extern "C" +{ +#include "lua.h" +}; + +// Eluna +#include "LuaEngine.h" +#include "ElunaEventMgr.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" +#include "ElunaUtility.h" + +// Method includes +#include "GlobalMethods.h" +#include "ObjectMethods.h" +#include "WorldObjectMethods.h" +#include "UnitMethods.h" +#include "PlayerMethods.h" +#include "CreatureMethods.h" +#include "GroupMethods.h" +#include "GuildMethods.h" +#include "GameObjectMethods.h" +#include "ElunaQueryMethods.h" +#include "AuraMethods.h" +#include "ItemMethods.h" +#include "WorldPacketMethods.h" +#include "SpellMethods.h" +#include "QuestMethods.h" +#include "MapMethods.h" +#include "CorpseMethods.h" +#include "VehicleMethods.h" +#include "BattleGroundMethods.h" +#include "ChatHandlerMethods.h" +#include "AchievementMethods.h" +#include "ItemTemplateMethods.h" +#include "RollMethods.h" + +luaL_Reg GlobalMethods[] = +{ + // Hooks + { "RegisterPacketEvent", &LuaGlobalFunctions::RegisterPacketEvent }, + { "RegisterServerEvent", &LuaGlobalFunctions::RegisterServerEvent }, + { "RegisterPlayerEvent", &LuaGlobalFunctions::RegisterPlayerEvent }, + { "RegisterGuildEvent", &LuaGlobalFunctions::RegisterGuildEvent }, + { "RegisterGroupEvent", &LuaGlobalFunctions::RegisterGroupEvent }, + { "RegisterCreatureEvent", &LuaGlobalFunctions::RegisterCreatureEvent }, + { "RegisterUniqueCreatureEvent", &LuaGlobalFunctions::RegisterUniqueCreatureEvent }, + { "RegisterCreatureGossipEvent", &LuaGlobalFunctions::RegisterCreatureGossipEvent }, + { "RegisterGameObjectEvent", &LuaGlobalFunctions::RegisterGameObjectEvent }, + { "RegisterGameObjectGossipEvent", &LuaGlobalFunctions::RegisterGameObjectGossipEvent }, + { "RegisterItemEvent", &LuaGlobalFunctions::RegisterItemEvent }, + { "RegisterItemGossipEvent", &LuaGlobalFunctions::RegisterItemGossipEvent }, + { "RegisterPlayerGossipEvent", &LuaGlobalFunctions::RegisterPlayerGossipEvent }, + { "RegisterBGEvent", &LuaGlobalFunctions::RegisterBGEvent }, + { "RegisterMapEvent", &LuaGlobalFunctions::RegisterMapEvent }, + { "RegisterInstanceEvent", &LuaGlobalFunctions::RegisterInstanceEvent }, + + { "ClearBattleGroundEvents", &LuaGlobalFunctions::ClearBattleGroundEvents }, + { "ClearCreatureEvents", &LuaGlobalFunctions::ClearCreatureEvents }, + { "ClearUniqueCreatureEvents", &LuaGlobalFunctions::ClearUniqueCreatureEvents }, + { "ClearCreatureGossipEvents", &LuaGlobalFunctions::ClearCreatureGossipEvents }, + { "ClearGameObjectEvents", &LuaGlobalFunctions::ClearGameObjectEvents }, + { "ClearGameObjectGossipEvents", &LuaGlobalFunctions::ClearGameObjectGossipEvents }, + { "ClearGroupEvents", &LuaGlobalFunctions::ClearGroupEvents }, + { "ClearGuildEvents", &LuaGlobalFunctions::ClearGuildEvents }, + { "ClearItemEvents", &LuaGlobalFunctions::ClearItemEvents }, + { "ClearItemGossipEvents", &LuaGlobalFunctions::ClearItemGossipEvents }, + { "ClearPacketEvents", &LuaGlobalFunctions::ClearPacketEvents }, + { "ClearPlayerEvents", &LuaGlobalFunctions::ClearPlayerEvents }, + { "ClearPlayerGossipEvents", &LuaGlobalFunctions::ClearPlayerGossipEvents }, + { "ClearServerEvents", &LuaGlobalFunctions::ClearServerEvents }, + { "ClearMapEvents", &LuaGlobalFunctions::ClearMapEvents }, + { "ClearInstanceEvents", &LuaGlobalFunctions::ClearInstanceEvents }, + + // Getters + { "GetLuaEngine", &LuaGlobalFunctions::GetLuaEngine }, + { "GetCoreName", &LuaGlobalFunctions::GetCoreName }, + { "GetRealmID", &LuaGlobalFunctions::GetRealmID }, + { "GetCoreVersion", &LuaGlobalFunctions::GetCoreVersion }, + { "GetCoreExpansion", &LuaGlobalFunctions::GetCoreExpansion }, + { "GetQuest", &LuaGlobalFunctions::GetQuest }, + { "GetPlayerByGUID", &LuaGlobalFunctions::GetPlayerByGUID }, + { "GetPlayerByName", &LuaGlobalFunctions::GetPlayerByName }, + { "GetGameTime", &LuaGlobalFunctions::GetGameTime }, + { "GetPlayersInWorld", &LuaGlobalFunctions::GetPlayersInWorld }, + { "GetGuildByName", &LuaGlobalFunctions::GetGuildByName }, + { "GetGuildByLeaderGUID", &LuaGlobalFunctions::GetGuildByLeaderGUID }, + { "GetPlayerCount", &LuaGlobalFunctions::GetPlayerCount }, + { "GetPlayerGUID", &LuaGlobalFunctions::GetPlayerGUID }, + { "GetItemGUID", &LuaGlobalFunctions::GetItemGUID }, + { "GetItemTemplate", &LuaGlobalFunctions::GetItemTemplate }, + { "GetObjectGUID", &LuaGlobalFunctions::GetObjectGUID }, + { "GetUnitGUID", &LuaGlobalFunctions::GetUnitGUID }, + { "GetGUIDLow", &LuaGlobalFunctions::GetGUIDLow }, + { "GetGUIDType", &LuaGlobalFunctions::GetGUIDType }, + { "GetGUIDEntry", &LuaGlobalFunctions::GetGUIDEntry }, + { "GetAreaName", &LuaGlobalFunctions::GetAreaName }, + { "GetOwnerHalaa", &LuaGlobalFunctions::GetOwnerHalaa }, + { "bit_not", &LuaGlobalFunctions::bit_not }, + { "bit_xor", &LuaGlobalFunctions::bit_xor }, + { "bit_rshift", &LuaGlobalFunctions::bit_rshift }, + { "bit_lshift", &LuaGlobalFunctions::bit_lshift }, + { "bit_or", &LuaGlobalFunctions::bit_or }, + { "bit_and", &LuaGlobalFunctions::bit_and }, + { "GetItemLink", &LuaGlobalFunctions::GetItemLink }, + { "GetMapById", &LuaGlobalFunctions::GetMapById }, + { "GetCurrTime", &LuaGlobalFunctions::GetCurrTime }, + { "GetTimeDiff", &LuaGlobalFunctions::GetTimeDiff }, + { "PrintInfo", &LuaGlobalFunctions::PrintInfo }, + { "PrintError", &LuaGlobalFunctions::PrintError }, + { "PrintDebug", &LuaGlobalFunctions::PrintDebug }, + { "GetActiveGameEvents", &LuaGlobalFunctions::GetActiveGameEvents }, + + // Boolean + { "IsInventoryPos", &LuaGlobalFunctions::IsInventoryPos }, + { "IsEquipmentPos", &LuaGlobalFunctions::IsEquipmentPos }, + { "IsBankPos", &LuaGlobalFunctions::IsBankPos }, + { "IsBagPos", &LuaGlobalFunctions::IsBagPos }, + { "IsGameEventActive", &LuaGlobalFunctions::IsGameEventActive }, + + // Other + { "ReloadEluna", &LuaGlobalFunctions::ReloadEluna }, + { "RunCommand", &LuaGlobalFunctions::RunCommand }, + { "SendWorldMessage", &LuaGlobalFunctions::SendWorldMessage }, + { "WorldDBQuery", &LuaGlobalFunctions::WorldDBQuery }, + { "WorldDBQueryAsync", &LuaGlobalFunctions::WorldDBQueryAsync }, + { "WorldDBExecute", &LuaGlobalFunctions::WorldDBExecute }, + { "CharDBQuery", &LuaGlobalFunctions::CharDBQuery }, + { "CharDBQueryAsync", &LuaGlobalFunctions::CharDBQueryAsync }, + { "CharDBExecute", &LuaGlobalFunctions::CharDBExecute }, + { "AuthDBQuery", &LuaGlobalFunctions::AuthDBQuery }, + { "AuthDBQueryAsync", &LuaGlobalFunctions::AuthDBQueryAsync }, + { "AuthDBExecute", &LuaGlobalFunctions::AuthDBExecute }, + { "CreateLuaEvent", &LuaGlobalFunctions::CreateLuaEvent }, + { "RemoveEventById", &LuaGlobalFunctions::RemoveEventById }, + { "RemoveEvents", &LuaGlobalFunctions::RemoveEvents }, + { "PerformIngameSpawn", &LuaGlobalFunctions::PerformIngameSpawn }, + { "CreatePacket", &LuaGlobalFunctions::CreatePacket }, + { "AddVendorItem", &LuaGlobalFunctions::AddVendorItem }, + { "VendorRemoveItem", &LuaGlobalFunctions::VendorRemoveItem }, + { "VendorRemoveAllItems", &LuaGlobalFunctions::VendorRemoveAllItems }, + { "Kick", &LuaGlobalFunctions::Kick }, + { "Ban", &LuaGlobalFunctions::Ban }, + { "SaveAllPlayers", &LuaGlobalFunctions::SaveAllPlayers }, + { "SendMail", &LuaGlobalFunctions::SendMail }, + { "AddTaxiPath", &LuaGlobalFunctions::AddTaxiPath }, + { "CreateInt64", &LuaGlobalFunctions::CreateLongLong }, + { "CreateUint64", &LuaGlobalFunctions::CreateULongLong }, + { "StartGameEvent", &LuaGlobalFunctions::StartGameEvent }, + { "StopGameEvent", &LuaGlobalFunctions::StopGameEvent }, + { "HttpRequest", &LuaGlobalFunctions::HttpRequest }, + { "SetOwnerHalaa", &LuaGlobalFunctions::SetOwnerHalaa }, + + { NULL, NULL } +}; + +ElunaRegister ObjectMethods[] = +{ + // Getters + { "GetEntry", &LuaObject::GetEntry }, + { "GetGUID", &LuaObject::GetGUID }, + { "GetGUIDLow", &LuaObject::GetGUIDLow }, + { "GetInt32Value", &LuaObject::GetInt32Value }, + { "GetUInt32Value", &LuaObject::GetUInt32Value }, + { "GetFloatValue", &LuaObject::GetFloatValue }, + { "GetByteValue", &LuaObject::GetByteValue }, + { "GetUInt16Value", &LuaObject::GetUInt16Value }, + { "GetUInt64Value", &LuaObject::GetUInt64Value }, + { "GetScale", &LuaObject::GetScale }, + { "GetTypeId", &LuaObject::GetTypeId }, + + // Setters + { "SetInt32Value", &LuaObject::SetInt32Value }, + { "SetUInt32Value", &LuaObject::SetUInt32Value }, + { "UpdateUInt32Value", &LuaObject::UpdateUInt32Value }, + { "SetFloatValue", &LuaObject::SetFloatValue }, + { "SetByteValue", &LuaObject::SetByteValue }, + { "SetUInt16Value", &LuaObject::SetUInt16Value }, + { "SetInt16Value", &LuaObject::SetInt16Value }, + { "SetUInt64Value", &LuaObject::SetUInt64Value }, + { "SetScale", &LuaObject::SetScale }, + { "SetFlag", &LuaObject::SetFlag }, + + // Boolean + { "IsInWorld", &LuaObject::IsInWorld }, + { "IsPlayer", &LuaObject::IsPlayer }, + { "HasFlag", &LuaObject::HasFlag }, + + // Other + { "ToGameObject", &LuaObject::ToGameObject }, + { "ToUnit", &LuaObject::ToUnit }, + { "ToCreature", &LuaObject::ToCreature }, + { "ToPlayer", &LuaObject::ToPlayer }, + { "ToCorpse", &LuaObject::ToCorpse }, + { "RemoveFlag", &LuaObject::RemoveFlag }, + + { NULL, NULL } +}; + +ElunaRegister WorldObjectMethods[] = +{ + // Getters + { "GetName", &LuaWorldObject::GetName }, + { "GetMap", &LuaWorldObject::GetMap }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "GetPhaseMask", &LuaWorldObject::GetPhaseMask }, + { "SetPhaseMask", &LuaWorldObject::SetPhaseMask }, +#endif + { "GetInstanceId", &LuaWorldObject::GetInstanceId }, + { "GetAreaId", &LuaWorldObject::GetAreaId }, + { "GetZoneId", &LuaWorldObject::GetZoneId }, + { "GetMapId", &LuaWorldObject::GetMapId }, + { "GetX", &LuaWorldObject::GetX }, + { "GetY", &LuaWorldObject::GetY }, + { "GetZ", &LuaWorldObject::GetZ }, + { "GetO", &LuaWorldObject::GetO }, + { "GetLocation", &LuaWorldObject::GetLocation }, + { "GetPlayersInRange", &LuaWorldObject::GetPlayersInRange }, + { "GetCreaturesInRange", &LuaWorldObject::GetCreaturesInRange }, + { "GetGameObjectsInRange", &LuaWorldObject::GetGameObjectsInRange }, + { "GetNearestPlayer", &LuaWorldObject::GetNearestPlayer }, + { "GetNearestGameObject", &LuaWorldObject::GetNearestGameObject }, + { "GetNearestCreature", &LuaWorldObject::GetNearestCreature }, + { "GetNearObject", &LuaWorldObject::GetNearObject }, + { "GetNearObjects", &LuaWorldObject::GetNearObjects }, + { "GetDistance", &LuaWorldObject::GetDistance }, + { "GetExactDistance", &LuaWorldObject::GetExactDistance }, + { "GetDistance2d", &LuaWorldObject::GetDistance2d }, + { "GetExactDistance2d", &LuaWorldObject::GetExactDistance2d }, + { "GetRelativePoint", &LuaWorldObject::GetRelativePoint }, + { "GetAngle", &LuaWorldObject::GetAngle }, + + // Boolean + { "IsWithinLoS", &LuaWorldObject::IsWithinLoS }, + { "IsInMap", &LuaWorldObject::IsInMap }, + { "IsWithinDist3d", &LuaWorldObject::IsWithinDist3d }, + { "IsWithinDist2d", &LuaWorldObject::IsWithinDist2d }, + { "IsWithinDist", &LuaWorldObject::IsWithinDist }, + { "IsWithinDistInMap", &LuaWorldObject::IsWithinDistInMap }, + { "IsInRange", &LuaWorldObject::IsInRange }, + { "IsInRange2d", &LuaWorldObject::IsInRange2d }, + { "IsInRange3d", &LuaWorldObject::IsInRange3d }, + { "IsInFront", &LuaWorldObject::IsInFront }, + { "IsInBack", &LuaWorldObject::IsInBack }, + + // Other + { "SummonGameObject", &LuaWorldObject::SummonGameObject }, + { "SpawnCreature", &LuaWorldObject::SpawnCreature }, + { "SendPacket", &LuaWorldObject::SendPacket }, + { "RegisterEvent", &LuaWorldObject::RegisterEvent }, + { "RemoveEventById", &LuaWorldObject::RemoveEventById }, + { "RemoveEvents", &LuaWorldObject::RemoveEvents }, + { "PlayMusic", &LuaWorldObject::PlayMusic }, + { "PlayDirectSound", &LuaWorldObject::PlayDirectSound }, + { "PlayDistanceSound", &LuaWorldObject::PlayDistanceSound }, + + { NULL, NULL } +}; + +ElunaRegister UnitMethods[] = +{ + // Getters + { "GetLevel", &LuaUnit::GetLevel }, + { "GetHealth", &LuaUnit::GetHealth }, + { "GetDisplayId", &LuaUnit::GetDisplayId }, + { "GetNativeDisplayId", &LuaUnit::GetNativeDisplayId }, + { "GetPower", &LuaUnit::GetPower }, + { "GetMaxPower", &LuaUnit::GetMaxPower }, + { "GetPowerType", &LuaUnit::GetPowerType }, + { "GetMaxHealth", &LuaUnit::GetMaxHealth }, + { "GetHealthPct", &LuaUnit::GetHealthPct }, + { "GetPowerPct", &LuaUnit::GetPowerPct }, + { "GetGender", &LuaUnit::GetGender }, + { "GetRace", &LuaUnit::GetRace }, + { "GetClass", &LuaUnit::GetClass }, + { "GetRaceMask", &LuaUnit::GetRaceMask }, + { "GetClassMask", &LuaUnit::GetClassMask }, + { "GetRaceAsString", &LuaUnit::GetRaceAsString }, + { "GetClassAsString", &LuaUnit::GetClassAsString }, + { "GetAura", &LuaUnit::GetAura }, + { "GetFaction", &LuaUnit::GetFaction }, + { "GetCurrentSpell", &LuaUnit::GetCurrentSpell }, + { "GetCreatureType", &LuaUnit::GetCreatureType }, + { "GetMountId", &LuaUnit::GetMountId }, + { "GetOwner", &LuaUnit::GetOwner }, + { "GetFriendlyUnitsInRange", &LuaUnit::GetFriendlyUnitsInRange }, + { "GetUnfriendlyUnitsInRange", &LuaUnit::GetUnfriendlyUnitsInRange }, + { "GetOwnerGUID", &LuaUnit::GetOwnerGUID }, + { "GetCreatorGUID", &LuaUnit::GetCreatorGUID }, + { "GetMinionGUID", &LuaUnit::GetPetGUID }, + { "GetCharmerGUID", &LuaUnit::GetCharmerGUID }, + { "GetCharmGUID", &LuaUnit::GetCharmGUID }, + { "GetPetGUID", &LuaUnit::GetPetGUID }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "GetCritterGUID", &LuaUnit::GetCritterGUID }, +#endif + { "GetControllerGUID", &LuaUnit::GetControllerGUID }, + { "GetControllerGUIDS", &LuaUnit::GetControllerGUIDS }, + { "GetStandState", &LuaUnit::GetStandState }, + { "GetVictim", &LuaUnit::GetVictim }, + { "GetSpeed", &LuaUnit::GetSpeed }, + { "GetSpeedRate", &LuaUnit::GetSpeedRate }, + { "GetStat", &LuaUnit::GetStat }, + { "GetBaseSpellPower", &LuaUnit::GetBaseSpellPower }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "GetVehicleKit", &LuaUnit::GetVehicleKit }, + // {"GetVehicle", &LuaUnit::GetVehicle}, // :GetVehicle() - UNDOCUMENTED - Gets the Vehicle kit of the vehicle the unit is on +#endif + { "GetMovementType", &LuaUnit::GetMovementType }, + { "GetAttackers", &LuaUnit::GetAttackers }, + + // Setters + { "SetFaction", &LuaUnit::SetFaction }, + { "SetLevel", &LuaUnit::SetLevel }, + { "SetHealth", &LuaUnit::SetHealth }, + { "SetMaxHealth", &LuaUnit::SetMaxHealth }, + { "SetPower", &LuaUnit::SetPower }, + { "SetMaxPower", &LuaUnit::SetMaxPower }, + { "SetPowerType", &LuaUnit::SetPowerType }, + { "SetDisplayId", &LuaUnit::SetDisplayId }, + { "SetNativeDisplayId", &LuaUnit::SetNativeDisplayId }, + { "SetFacing", &LuaUnit::SetFacing }, + { "SetFacingToObject", &LuaUnit::SetFacingToObject }, + { "SetSpeed", &LuaUnit::SetSpeed }, + { "SetSpeedRate", &LuaUnit::SetSpeedRate }, + // {"SetStunned", &LuaUnit::SetStunned}, // :SetStunned([enable]) - UNDOCUMENTED - Stuns or removes stun + {"SetRooted", &LuaUnit::SetRooted}, + {"SetConfused", &LuaUnit::SetConfused}, + {"SetFeared", &LuaUnit::SetFeared}, + { "SetPvP", &LuaUnit::SetPvP }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "SetFFA", &LuaUnit::SetFFA }, + { "SetSanctuary", &LuaUnit::SetSanctuary }, +#endif + // {"SetCanFly", &LuaUnit::SetCanFly}, // :SetCanFly(apply) - UNDOCUMENTED + // {"SetVisible", &LuaUnit::SetVisible}, // :SetVisible(x) - UNDOCUMENTED + { "SetOwnerGUID", &LuaUnit::SetOwnerGUID }, + { "SetName", &LuaUnit::SetName }, + { "SetSheath", &LuaUnit::SetSheath }, + { "SetCreatorGUID", &LuaUnit::SetCreatorGUID }, + { "SetMinionGUID", &LuaUnit::SetPetGUID }, + { "SetPetGUID", &LuaUnit::SetPetGUID }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "SetCritterGUID", &LuaUnit::SetCritterGUID }, +#endif + { "SetWaterWalk", &LuaUnit::SetWaterWalk }, + { "SetStandState", &LuaUnit::SetStandState }, + { "SetInCombatWith", &LuaUnit::SetInCombatWith }, + { "ModifyPower", &LuaUnit::ModifyPower }, + + // Boolean + { "IsAlive", &LuaUnit::IsAlive }, + { "IsDead", &LuaUnit::IsDead }, + { "IsDying", &LuaUnit::IsDying }, + { "IsPvPFlagged", &LuaUnit::IsPvPFlagged }, + { "IsInCombat", &LuaUnit::IsInCombat }, + { "IsBanker", &LuaUnit::IsBanker }, + { "IsBattleMaster", &LuaUnit::IsBattleMaster }, + { "IsCharmed", &LuaUnit::IsCharmed }, + { "IsArmorer", &LuaUnit::IsArmorer }, + { "IsAttackingPlayer", &LuaUnit::IsAttackingPlayer }, + { "IsInWater", &LuaUnit::IsInWater }, + { "IsUnderWater", &LuaUnit::IsUnderWater }, + { "IsAuctioneer", &LuaUnit::IsAuctioneer }, + { "IsGuildMaster", &LuaUnit::IsGuildMaster }, + { "IsInnkeeper", &LuaUnit::IsInnkeeper }, + { "IsTrainer", &LuaUnit::IsTrainer }, + { "IsGossip", &LuaUnit::IsGossip }, + { "IsTaxi", &LuaUnit::IsTaxi }, + { "IsSpiritHealer", &LuaUnit::IsSpiritHealer }, + { "IsSpiritGuide", &LuaUnit::IsSpiritGuide }, + { "IsTabardDesigner", &LuaUnit::IsTabardDesigner }, + { "IsServiceProvider", &LuaUnit::IsServiceProvider }, + { "IsSpiritService", &LuaUnit::IsSpiritService }, + { "HealthBelowPct", &LuaUnit::HealthBelowPct }, + { "HealthAbovePct", &LuaUnit::HealthAbovePct }, + { "IsMounted", &LuaUnit::IsMounted }, + { "AttackStop", &LuaUnit::AttackStop }, + { "Attack", &LuaUnit::Attack }, + // {"IsVisible", &LuaUnit::IsVisible}, // :IsVisible() - UNDOCUMENTED + // {"IsMoving", &LuaUnit::IsMoving}, // :IsMoving() - UNDOCUMENTED + // {"IsFlying", &LuaUnit::IsFlying}, // :IsFlying() - UNDOCUMENTED + { "IsStopped", &LuaUnit::IsStopped }, + { "HasUnitState", &LuaUnit::HasUnitState }, + { "IsQuestGiver", &LuaUnit::IsQuestGiver }, + { "IsInAccessiblePlaceFor", &LuaUnit::IsInAccessiblePlaceFor }, + { "IsVendor", &LuaUnit::IsVendor }, + { "IsRooted", &LuaUnit::IsRooted }, + { "IsFullHealth", &LuaUnit::IsFullHealth }, + { "HasAura", &LuaUnit::HasAura }, + { "IsCasting", &LuaUnit::IsCasting }, + { "IsStandState", &LuaUnit::IsStandState }, +#ifndef CLASSIC + { "IsOnVehicle", &LuaUnit::IsOnVehicle }, +#endif + + // Other + { "AddAura", &LuaUnit::AddAura }, + { "RemoveAura", &LuaUnit::RemoveAura }, + { "RemoveAllAuras", &LuaUnit::RemoveAllAuras }, +#if !defined(CLASSIC) + { "RemoveArenaAuras", &LuaUnit::RemoveArenaAuras }, +#endif + { "ClearInCombat", &LuaUnit::ClearInCombat }, + { "DeMorph", &LuaUnit::DeMorph }, + { "SendUnitWhisper", &LuaUnit::SendUnitWhisper }, + { "SendUnitEmote", &LuaUnit::SendUnitEmote }, + { "SendUnitSay", &LuaUnit::SendUnitSay }, + { "SendUnitYell", &LuaUnit::SendUnitYell }, + { "CastSpell", &LuaUnit::CastSpell }, + { "CastCustomSpell", &LuaUnit::CastCustomSpell }, + { "CastSpellAoF", &LuaUnit::CastSpellAoF }, + { "Kill", &LuaUnit::Kill }, + { "StopSpellCast", &LuaUnit::StopSpellCast }, + { "InterruptSpell", &LuaUnit::InterruptSpell }, + { "SendChatMessageToPlayer", &LuaUnit::SendChatMessageToPlayer }, + { "PerformEmote", &LuaUnit::PerformEmote }, + { "EmoteState", &LuaUnit::EmoteState }, + { "CountPctFromCurHealth", &LuaUnit::CountPctFromCurHealth }, + { "CountPctFromMaxHealth", &LuaUnit::CountPctFromMaxHealth }, + { "Dismount", &LuaUnit::Dismount }, + { "Mount", &LuaUnit::Mount }, + // {"RestoreDisplayId", &LuaUnit::RestoreDisplayId}, // :RestoreDisplayId() - UNDOCUMENTED + // {"RestoreFaction", &LuaUnit::RestoreFaction}, // :RestoreFaction() - UNDOCUMENTED + // {"RemoveBindSightAuras", &LuaUnit::RemoveBindSightAuras}, // :RemoveBindSightAuras() - UNDOCUMENTED + // {"RemoveCharmAuras", &LuaUnit::RemoveCharmAuras}, // :RemoveCharmAuras() - UNDOCUMENTED + { "ClearThreatList", &LuaUnit::ClearThreatList }, + { "GetThreatList", &LuaUnit::GetThreatList }, + { "ClearUnitState", &LuaUnit::ClearUnitState }, + { "AddUnitState", &LuaUnit::AddUnitState }, + // {"DisableMelee", &LuaUnit::DisableMelee}, // :DisableMelee([disable]) - UNDOCUMENTED - if true, enables + // {"SummonGuardian", &LuaUnit::SummonGuardian}, // :SummonGuardian(entry, x, y, z, o[, duration]) - UNDOCUMENTED - summons a guardian to location. Scales with summoner, is friendly to him and guards him. + { "NearTeleport", &LuaUnit::NearTeleport }, + { "MoveIdle", &LuaUnit::MoveIdle }, + { "MoveRandom", &LuaUnit::MoveRandom }, + { "MoveHome", &LuaUnit::MoveHome }, + { "MoveFollow", &LuaUnit::MoveFollow }, + { "MoveChase", &LuaUnit::MoveChase }, + { "MoveConfused", &LuaUnit::MoveConfused }, + { "MoveFleeing", &LuaUnit::MoveFleeing }, + { "MoveTo", &LuaUnit::MoveTo }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "MoveJump", &LuaUnit::MoveJump }, +#endif + { "MoveStop", &LuaUnit::MoveStop }, + { "MoveExpire", &LuaUnit::MoveExpire }, + { "MoveClear", &LuaUnit::MoveClear }, + { "DealDamage", &LuaUnit::DealDamage }, + { "DealHeal", &LuaUnit::DealHeal }, + { "AddThreat", &LuaUnit::AddThreat }, + { "ModifyThreatPct", &LuaUnit::ModifyThreatPct }, + + { NULL, NULL } +}; + +ElunaRegister PlayerMethods[] = +{ + // Getters + { "GetSelection", &LuaPlayer::GetSelection }, + { "GetGMRank", &LuaPlayer::GetGMRank }, + { "GetGuildId", &LuaPlayer::GetGuildId }, + { "GetCoinage", &LuaPlayer::GetCoinage }, + { "GetTeam", &LuaPlayer::GetTeam }, + { "GetItemCount", &LuaPlayer::GetItemCount }, + { "GetGroup", &LuaPlayer::GetGroup }, + { "GetGuild", &LuaPlayer::GetGuild }, + { "GetAccountId", &LuaPlayer::GetAccountId }, + { "GetAccountName", &LuaPlayer::GetAccountName }, +#if defined (TBC) || defined (WOTLK) + { "GetArenaPoints", &LuaPlayer::GetArenaPoints }, + { "GetHonorPoints", &LuaPlayer::GetHonorPoints }, +#endif + { "GetLifetimeKills", &LuaPlayer::GetLifetimeKills }, + { "GetPlayerIP", &LuaPlayer::GetPlayerIP }, + { "GetLevelPlayedTime", &LuaPlayer::GetLevelPlayedTime }, + { "GetTotalPlayedTime", &LuaPlayer::GetTotalPlayedTime }, + { "GetItemByPos", &LuaPlayer::GetItemByPos }, + { "GetItemByEntry", &LuaPlayer::GetItemByEntry }, + { "GetItemByGUID", &LuaPlayer::GetItemByGUID }, + { "GetMailCount", &LuaPlayer::GetMailCount }, + { "GetMailItem", &LuaPlayer::GetMailItem }, + { "GetReputation", &LuaPlayer::GetReputation }, + { "GetEquippedItemBySlot", &LuaPlayer::GetEquippedItemBySlot }, + { "GetQuestLevel", &LuaPlayer::GetQuestLevel }, + { "GetChatTag", &LuaPlayer::GetChatTag }, + { "GetRestBonus", &LuaPlayer::GetRestBonus }, +#ifdef WOTLK + { "GetPhaseMaskForSpawn", &LuaPlayer::GetPhaseMaskForSpawn }, +#endif + { "GetReqKillOrCastCurrentCount", &LuaPlayer::GetReqKillOrCastCurrentCount }, + { "GetQuestStatus", &LuaPlayer::GetQuestStatus }, + { "GetInGameTime", &LuaPlayer::GetInGameTime }, + { "GetComboPoints", &LuaPlayer::GetComboPoints }, + { "GetComboTarget", &LuaPlayer::GetComboTarget }, + { "GetGuildName", &LuaPlayer::GetGuildName }, + { "GetFreeTalentPoints", &LuaPlayer::GetFreeTalentPoints }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "GetActiveSpec", &LuaPlayer::GetActiveSpec }, + { "GetSpecsCount", &LuaPlayer::GetSpecsCount }, +#endif + { "GetSpellCooldownDelay", &LuaPlayer::GetSpellCooldownDelay }, + { "GetGuildRank", &LuaPlayer::GetGuildRank }, + { "GetDifficulty", &LuaPlayer::GetDifficulty }, + { "GetHealthBonusFromStamina", &LuaPlayer::GetHealthBonusFromStamina }, + { "GetManaBonusFromIntellect", &LuaPlayer::GetManaBonusFromIntellect }, + { "GetMaxSkillValue", &LuaPlayer::GetMaxSkillValue }, + { "GetPureMaxSkillValue", &LuaPlayer::GetPureMaxSkillValue }, + { "GetSkillValue", &LuaPlayer::GetSkillValue }, + { "GetBaseSkillValue", &LuaPlayer::GetBaseSkillValue }, + { "GetPureSkillValue", &LuaPlayer::GetPureSkillValue }, + { "GetSkillPermBonusValue", &LuaPlayer::GetSkillPermBonusValue }, + { "GetSkillTempBonusValue", &LuaPlayer::GetSkillTempBonusValue }, + { "GetReputationRank", &LuaPlayer::GetReputationRank }, + { "GetDrunkValue", &LuaPlayer::GetDrunkValue }, + { "GetBattlegroundId", &LuaPlayer::GetBattlegroundId }, + { "GetBattlegroundTypeId", &LuaPlayer::GetBattlegroundTypeId }, + { "GetXP", &LuaPlayer::GetXP }, + { "GetXPRestBonus", &LuaPlayer::GetXPRestBonus }, + { "GetGroupInvite", &LuaPlayer::GetGroupInvite }, + { "GetSubGroup", &LuaPlayer::GetSubGroup }, + { "GetNextRandomRaidMember", &LuaPlayer::GetNextRandomRaidMember }, + { "GetOriginalGroup", &LuaPlayer::GetOriginalGroup }, + { "GetOriginalSubGroup", &LuaPlayer::GetOriginalSubGroup }, +#if defined(TRINITY) || AZEROTHCORE + { "GetChampioningFaction", &LuaPlayer::GetChampioningFaction }, +#endif + { "GetLatency", &LuaPlayer::GetLatency }, + // {"GetRecruiterId", &LuaPlayer::GetRecruiterId}, // :GetRecruiterId() - UNDOCUMENTED - Returns player's recruiter's ID + { "GetDbLocaleIndex", &LuaPlayer::GetDbLocaleIndex }, + { "GetDbcLocale", &LuaPlayer::GetDbcLocale }, + { "GetCorpse", &LuaPlayer::GetCorpse }, + { "GetGossipTextId", &LuaPlayer::GetGossipTextId }, + { "GetQuestRewardStatus", &LuaPlayer::GetQuestRewardStatus }, +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + { "GetShieldBlockValue", &LuaPlayer::GetShieldBlockValue }, +#endif +#ifdef CLASSIC + { "GetHonorStoredKills", &LuaPlayer::GetHonorStoredKills }, + { "GetRankPoints", &LuaPlayer::GetRankPoints }, + { "GetHonorLastWeekStandingPos", &LuaPlayer::GetHonorLastWeekStandingPos }, +#endif + { "GetPlayerSettingValue", &LuaPlayer::GetPlayerSettingValue }, + { "GetTrader", &LuaPlayer::GetTrader }, + + // Setters + { "AdvanceSkillsToMax", &LuaPlayer::AdvanceSkillsToMax }, + { "AdvanceSkill", &LuaPlayer::AdvanceSkill }, + { "AdvanceAllSkills", &LuaPlayer::AdvanceAllSkills }, + { "AddLifetimeKills", &LuaPlayer::AddLifetimeKills }, + { "SetCoinage", &LuaPlayer::SetCoinage }, +#ifndef CLASSIC + { "SetKnownTitle", &LuaPlayer::SetKnownTitle }, + { "UnsetKnownTitle", &LuaPlayer::UnsetKnownTitle }, +#endif + { "SetBindPoint", &LuaPlayer::SetBindPoint }, +#if defined(TBC) || defined(WOTLK) + { "SetArenaPoints", &LuaPlayer::SetArenaPoints }, + { "SetHonorPoints", &LuaPlayer::SetHonorPoints }, +#endif +#ifdef CLASSIC + { "SetHonorStoredKills", &LuaPlayer::SetHonorStoredKills }, + { "SetRankPoints", &LuaPlayer::SetRankPoints }, + { "SetHonorLastWeekStandingPos", &LuaPlayer::SetHonorLastWeekStandingPos }, +#endif + { "SetLifetimeKills", &LuaPlayer::SetLifetimeKills }, + { "SetGameMaster", &LuaPlayer::SetGameMaster }, + { "SetGMChat", &LuaPlayer::SetGMChat }, + { "SetTaxiCheat", &LuaPlayer::SetTaxiCheat }, + { "SetGMVisible", &LuaPlayer::SetGMVisible }, + { "SetPvPDeath", &LuaPlayer::SetPvPDeath }, + { "SetAcceptWhispers", &LuaPlayer::SetAcceptWhispers }, + { "SetRestBonus", &LuaPlayer::SetRestBonus }, + { "SetQuestStatus", &LuaPlayer::SetQuestStatus }, + { "SetReputation", &LuaPlayer::SetReputation }, + { "SetFreeTalentPoints", &LuaPlayer::SetFreeTalentPoints }, + { "SetGuildRank", &LuaPlayer::SetGuildRank }, + // {"SetMovement", &LuaPlayer::SetMovement}, // :SetMovement(type) - UNDOCUMENTED - Sets player's movement type + { "SetSkill", &LuaPlayer::SetSkill }, + { "SetFactionForRace", &LuaPlayer::SetFactionForRace }, + { "SetDrunkValue", &LuaPlayer::SetDrunkValue }, + { "SetAtLoginFlag", &LuaPlayer::SetAtLoginFlag }, + { "SetPlayerLock", &LuaPlayer::SetPlayerLock }, + { "SetGender", &LuaPlayer::SetGender }, + { "SetSheath", &LuaPlayer::SetSheath }, +#if !defined TRINITY && !AZEROTHCORE + { "SetFFA", &LuaPlayer::SetFFA }, +#endif + + // Boolean + { "IsInGroup", &LuaPlayer::IsInGroup }, + { "IsInGuild", &LuaPlayer::IsInGuild }, + { "IsGM", &LuaPlayer::IsGM }, + { "IsImmuneToDamage", &LuaPlayer::IsImmuneToDamage }, + { "IsAlliance", &LuaPlayer::IsAlliance }, + { "IsHorde", &LuaPlayer::IsHorde }, +#ifndef CLASSIC + { "HasTitle", &LuaPlayer::HasTitle }, +#endif + { "HasItem", &LuaPlayer::HasItem }, + { "Teleport", &LuaPlayer::Teleport }, + { "AddItem", &LuaPlayer::AddItem }, +#ifndef CLASSIC + { "IsInArenaTeam", &LuaPlayer::IsInArenaTeam }, +#endif + { "CanRewardQuest", &LuaPlayer::CanRewardQuest }, + { "CanCompleteRepeatableQuest", &LuaPlayer::CanCompleteRepeatableQuest }, + { "CanCompleteQuest", &LuaPlayer::CanCompleteQuest }, + { "CanEquipItem", &LuaPlayer::CanEquipItem }, + { "IsFalling", &LuaPlayer::IsFalling }, + { "ToggleAFK", &LuaPlayer::ToggleAFK }, + { "ToggleDND", &LuaPlayer::ToggleDND }, + { "IsAFK", &LuaPlayer::IsAFK }, + { "IsDND", &LuaPlayer::IsDND }, + { "IsAcceptingWhispers", &LuaPlayer::IsAcceptingWhispers }, + { "IsGMChat", &LuaPlayer::IsGMChat }, + { "IsTaxiCheater", &LuaPlayer::IsTaxiCheater }, + { "IsGMVisible", &LuaPlayer::IsGMVisible }, + { "HasQuest", &LuaPlayer::HasQuest }, + { "InBattlegroundQueue", &LuaPlayer::InBattlegroundQueue }, + // {"IsImmuneToEnvironmentalDamage", &LuaPlayer::IsImmuneToEnvironmentalDamage}, // :IsImmuneToEnvironmentalDamage() - UNDOCUMENTED - Returns true if the player is immune to environmental damage + { "CanSpeak", &LuaPlayer::CanSpeak }, + { "HasAtLoginFlag", &LuaPlayer::HasAtLoginFlag }, + // {"InRandomLfgDungeon", &LuaPlayer::InRandomLfgDungeon}, // :InRandomLfgDungeon() - UNDOCUMENTED - Returns true if the player is in a random LFG dungeon + // {"HasPendingBind", &LuaPlayer::HasPendingBind}, // :HasPendingBind() - UNDOCUMENTED - Returns true if the player has a pending instance bind +#if (!defined(TBC) && !defined(CLASSIC)) + { "HasAchieved", &LuaPlayer::HasAchieved }, + { "GetAchievementCriteriaProgress", &LuaPlayer::GetAchievementCriteriaProgress }, +#if defined(TRINITY) || defined(AZEROTHCORE) + { "SetAchievement", &LuaPlayer::SetAchievement }, +#endif +#endif + { "CanUninviteFromGroup", &LuaPlayer::CanUninviteFromGroup }, + { "IsRested", &LuaPlayer::IsRested }, + // {"CanFlyInZone", &LuaPlayer::CanFlyInZone}, // :CanFlyInZone(mapid, zone) - UNDOCUMENTED - Returns true if the player can fly in the area + // {"IsNeverVisible", &LuaPlayer::IsNeverVisible}, // :IsNeverVisible() - UNDOCUMENTED - Returns true if the player is never visible + { "IsVisibleForPlayer", &LuaPlayer::IsVisibleForPlayer }, + // {"IsUsingLfg", &LuaPlayer::IsUsingLfg}, // :IsUsingLfg() - UNDOCUMENTED - Returns true if the player is using LFG + { "HasQuestForItem", &LuaPlayer::HasQuestForItem }, + { "HasQuestForGO", &LuaPlayer::HasQuestForGO }, + { "CanShareQuest", &LuaPlayer::CanShareQuest }, + // {"HasReceivedQuestReward", &LuaPlayer::HasReceivedQuestReward}, // :HasReceivedQuestReward(entry) - UNDOCUMENTED - Returns true if the player has recieved the quest's reward +#if (!defined(TBC) && !defined(CLASSIC)) + { "HasTalent", &LuaPlayer::HasTalent }, +#endif + { "IsInSameGroupWith", &LuaPlayer::IsInSameGroupWith }, + { "IsInSameRaidWith", &LuaPlayer::IsInSameRaidWith }, + { "IsGroupVisibleFor", &LuaPlayer::IsGroupVisibleFor }, + { "HasSkill", &LuaPlayer::HasSkill }, + { "IsHonorOrXPTarget", &LuaPlayer::IsHonorOrXPTarget }, + { "CanParry", &LuaPlayer::CanParry }, + { "CanBlock", &LuaPlayer::CanBlock }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "CanTitanGrip", &LuaPlayer::CanTitanGrip }, +#endif + { "InBattleground", &LuaPlayer::InBattleground }, +#ifndef CLASSIC + { "InArena", &LuaPlayer::InArena }, +#endif + // {"IsOutdoorPvPActive", &LuaPlayer::IsOutdoorPvPActive}, // :IsOutdoorPvPActive() - UNDOCUMENTED - Returns true if the player is outdoor pvp active + // {"IsARecruiter", &LuaPlayer::IsARecruiter}, // :IsARecruiter() - UNDOCUMENTED - Returns true if the player is a recruiter + { "CanUseItem", &LuaPlayer::CanUseItem }, + { "HasSpell", &LuaPlayer::HasSpell }, + { "HasSpellCooldown", &LuaPlayer::HasSpellCooldown }, + { "IsInWater", &LuaPlayer::IsInWater }, +#ifndef CLASSIC + { "CanFly", &LuaPlayer::CanFly }, +#endif + { "IsMoving", &LuaPlayer::IsMoving }, +#ifndef CLASSIC + { "IsFlying", &LuaPlayer::IsFlying }, +#endif + + // Gossip + { "GossipMenuAddItem", &LuaPlayer::GossipMenuAddItem }, + { "GossipSendMenu", &LuaPlayer::GossipSendMenu }, + { "GossipComplete", &LuaPlayer::GossipComplete }, + { "GossipClearMenu", &LuaPlayer::GossipClearMenu }, + + // Other + { "SendBroadcastMessage", &LuaPlayer::SendBroadcastMessage }, + { "SendAreaTriggerMessage", &LuaPlayer::SendAreaTriggerMessage }, + { "SendNotification", &LuaPlayer::SendNotification }, + { "SendPacket", &LuaPlayer::SendPacket }, + { "SendAddonMessage", &LuaPlayer::SendAddonMessage }, + { "ModifyMoney", &LuaPlayer::ModifyMoney }, + { "LearnSpell", &LuaPlayer::LearnSpell }, + { "LearnTalent", &LuaPlayer::LearnTalent }, + { "SetGlyph", &LuaPlayer::SetGlyph }, +#if !defined(CLASSIC) + { "RemoveArenaSpellCooldowns", &LuaPlayer::RemoveArenaSpellCooldowns }, +#endif + { "RemoveItem", &LuaPlayer::RemoveItem }, + { "RemoveLifetimeKills", &LuaPlayer::RemoveLifetimeKills }, + { "ResurrectPlayer", &LuaPlayer::ResurrectPlayer }, + { "EquipItem", &LuaPlayer::EquipItem }, + { "ResetSpellCooldown", &LuaPlayer::ResetSpellCooldown }, + { "ResetTypeCooldowns", &LuaPlayer::ResetTypeCooldowns }, + { "ResetAllCooldowns", &LuaPlayer::ResetAllCooldowns }, + { "GiveXP", &LuaPlayer::GiveXP }, // :GiveXP(xp[, victim, pureXP, triggerHook]) - UNDOCUMENTED - Gives XP to the player. If pure is false, bonuses are count in. If triggerHook is false, GiveXp hook is not triggered. + // {"RemovePet", &LuaPlayer::RemovePet}, // :RemovePet([mode, returnreagent]) - UNDOCUMENTED - Removes the player's pet. Mode determines if the pet is saved and how + // {"SummonPet", &LuaPlayer::SummonPet}, // :SummonPet(entry, x, y, z, o, petType, despwtime) - Summons a pet for the player + { "Say", &LuaPlayer::Say }, + { "Yell", &LuaPlayer::Yell }, + { "TextEmote", &LuaPlayer::TextEmote }, + { "Whisper", &LuaPlayer::Whisper }, + { "CompleteQuest", &LuaPlayer::CompleteQuest }, + { "IncompleteQuest", &LuaPlayer::IncompleteQuest }, + { "FailQuest", &LuaPlayer::FailQuest }, + { "AddQuest", &LuaPlayer::AddQuest }, + { "RemoveQuest", &LuaPlayer::RemoveQuest }, + // {"RemoveActiveQuest", &LuaPlayer::RemoveActiveQuest}, // :RemoveActiveQuest(entry) - UNDOCUMENTED - Removes an active quest + // {"RemoveRewardedQuest", &LuaPlayer::RemoveRewardedQuest}, // :RemoveRewardedQuest(entry) - UNDOCUMENTED - Removes a rewarded quest + { "AreaExploredOrEventHappens", &LuaPlayer::AreaExploredOrEventHappens }, + { "GroupEventHappens", &LuaPlayer::GroupEventHappens }, + { "KilledMonsterCredit", &LuaPlayer::KilledMonsterCredit }, + // {"KilledPlayerCredit", &LuaPlayer::KilledPlayerCredit}, // :KilledPlayerCredit() - UNDOCUMENTED - Satisfies a player kill for the player + // {"KillGOCredit", &LuaPlayer::KillGOCredit}, // :KillGOCredit(GOEntry[, GUID]) - UNDOCUMENTED - Credits the player for destroying a GO, guid is optional + { "TalkedToCreature", &LuaPlayer::TalkedToCreature }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "ResetPetTalents", &LuaPlayer::ResetPetTalents }, +#endif + { "AddComboPoints", &LuaPlayer::AddComboPoints }, + // {"GainSpellComboPoints", &LuaPlayer::GainSpellComboPoints}, // :GainSpellComboPoints(amount) - UNDOCUMENTED - Player gains spell combo points + { "ClearComboPoints", &LuaPlayer::ClearComboPoints }, + { "RemoveSpell", &LuaPlayer::RemoveSpell }, + { "ResetTalents", &LuaPlayer::ResetTalents }, + { "ResetTalentsCost", &LuaPlayer::ResetTalentsCost }, + // {"AddTalent", &LuaPlayer::AddTalent}, // :AddTalent(spellid, spec, learning) - UNDOCUMENTED - Adds a talent spell for the player to given spec + { "RemoveFromGroup", &LuaPlayer::RemoveFromGroup }, + { "KillPlayer", &LuaPlayer::KillPlayer }, + { "DurabilityLossAll", &LuaPlayer::DurabilityLossAll }, + { "DurabilityLoss", &LuaPlayer::DurabilityLoss }, + { "DurabilityPointsLoss", &LuaPlayer::DurabilityPointsLoss }, + { "DurabilityPointsLossAll", &LuaPlayer::DurabilityPointsLossAll }, + { "DurabilityPointLossForEquipSlot", &LuaPlayer::DurabilityPointLossForEquipSlot }, + { "DurabilityRepairAll", &LuaPlayer::DurabilityRepairAll }, + { "DurabilityRepair", &LuaPlayer::DurabilityRepair }, +#if defined(TBC) || defined(WOTLK) + { "ModifyHonorPoints", &LuaPlayer::ModifyHonorPoints }, + { "ModifyArenaPoints", &LuaPlayer::ModifyArenaPoints }, +#endif + { "LeaveBattleground", &LuaPlayer::LeaveBattleground }, + // {"BindToInstance", &LuaPlayer::BindToInstance}, // :BindToInstance() - UNDOCUMENTED - Binds the player to the current instance + { "UnbindInstance", &LuaPlayer::UnbindInstance }, + { "UnbindAllInstances", &LuaPlayer::UnbindAllInstances }, + { "RemoveFromBattlegroundRaid", &LuaPlayer::RemoveFromBattlegroundRaid }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "ResetAchievements", &LuaPlayer::ResetAchievements }, +#endif + { "KickPlayer", &LuaPlayer::KickPlayer }, + { "LogoutPlayer", &LuaPlayer::LogoutPlayer }, + { "SendTrainerList", &LuaPlayer::SendTrainerList }, + { "SendListInventory", &LuaPlayer::SendListInventory }, + { "SendShowBank", &LuaPlayer::SendShowBank }, + { "SendTabardVendorActivate", &LuaPlayer::SendTabardVendorActivate }, + { "SendSpiritResurrect", &LuaPlayer::SendSpiritResurrect }, + { "SendTaxiMenu", &LuaPlayer::SendTaxiMenu }, + { "SendUpdateWorldState", &LuaPlayer::SendUpdateWorldState }, + { "RewardQuest", &LuaPlayer::RewardQuest }, + { "SendAuctionMenu", &LuaPlayer::SendAuctionMenu }, + { "SendShowMailBox", &LuaPlayer::SendShowMailBox }, + { "StartTaxi", &LuaPlayer::StartTaxi }, + { "GossipSendPOI", &LuaPlayer::GossipSendPOI }, + { "GossipAddQuests", &LuaPlayer::GossipAddQuests }, + { "SendQuestTemplate", &LuaPlayer::SendQuestTemplate }, + { "SpawnBones", &LuaPlayer::SpawnBones }, + { "RemovedInsignia", &LuaPlayer::RemovedInsignia }, + { "SendGuildInvite", &LuaPlayer::SendGuildInvite }, + { "Mute", &LuaPlayer::Mute }, + { "SummonPlayer", &LuaPlayer::SummonPlayer }, + { "SaveToDB", &LuaPlayer::SaveToDB }, + { "GroupInvite", &LuaPlayer::GroupInvite }, + { "GroupCreate", &LuaPlayer::GroupCreate }, + { "SendCinematicStart", &LuaPlayer::SendCinematicStart }, +#if !defined(CLASSIC) && !defined(TBC) + { "SendMovieStart", &LuaPlayer::SendMovieStart }, +#endif +#ifdef CLASSIC + { "UpdateHonor", &LuaPlayer::UpdateHonor }, + { "ResetHonor", &LuaPlayer::ResetHonor }, + { "ClearHonorInfo", &LuaPlayer::ClearHonorInfo }, +#endif + { "UpdatePlayerSetting", &LuaPlayer::UpdatePlayerSetting }, + + { NULL, NULL } +}; + +ElunaRegister CreatureMethods[] = +{ + // Getters + { "GetAITarget", &LuaCreature::GetAITarget }, + { "GetAITargets", &LuaCreature::GetAITargets }, + { "GetAITargetsCount", &LuaCreature::GetAITargetsCount }, + { "GetHomePosition", &LuaCreature::GetHomePosition }, + { "GetCorpseDelay", &LuaCreature::GetCorpseDelay }, + { "GetCreatureSpellCooldownDelay", &LuaCreature::GetCreatureSpellCooldownDelay }, + { "GetScriptId", &LuaCreature::GetScriptId }, + { "GetAIName", &LuaCreature::GetAIName }, + { "GetScriptName", &LuaCreature::GetScriptName }, +#ifndef AZEROTHCORE + { "GetAttackDistance", &LuaCreature::GetAttackDistance }, +#endif + { "GetAggroRange", &LuaCreature::GetAggroRange }, + { "GetDefaultMovementType", &LuaCreature::GetDefaultMovementType }, + { "GetRespawnDelay", &LuaCreature::GetRespawnDelay }, + { "GetWanderRadius", &LuaCreature::GetWanderRadius }, + { "GetCurrentWaypointId", &LuaCreature::GetCurrentWaypointId }, +#if defined(TRINITY) || AZEROTHCORE + { "GetWaypointPath", &LuaCreature::GetWaypointPath }, + { "GetLootMode", &LuaCreature::GetLootMode }, +#endif + { "GetLootRecipient", &LuaCreature::GetLootRecipient }, + { "GetLootRecipientGroup", &LuaCreature::GetLootRecipientGroup }, + { "GetNPCFlags", &LuaCreature::GetNPCFlags }, + { "GetUnitFlags", &LuaCreature::GetUnitFlags }, + { "GetUnitFlagsTwo", &LuaCreature::GetUnitFlagsTwo }, + { "GetExtraFlags", &LuaCreature::GetExtraFlags }, +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + { "GetShieldBlockValue", &LuaCreature::GetShieldBlockValue }, +#endif + { "GetDBTableGUIDLow", &LuaCreature::GetDBTableGUIDLow }, + { "GetCreatureFamily", &LuaCreature::GetCreatureFamily }, + + // Setters +#if defined(TRINITY) || defined(AZEROTHCORE) + { "SetRegeneratingHealth", &LuaCreature::SetRegeneratingHealth }, +#endif + { "SetHover", &LuaCreature::SetHover }, + { "SetDisableGravity", &LuaCreature::SetDisableGravity }, + { "SetAggroEnabled", &LuaCreature::SetAggroEnabled }, + { "SetNoCallAssistance", &LuaCreature::SetNoCallAssistance }, + { "SetNoSearchAssistance", &LuaCreature::SetNoSearchAssistance }, + { "SetDefaultMovementType", &LuaCreature::SetDefaultMovementType }, + { "SetRespawnDelay", &LuaCreature::SetRespawnDelay }, + { "SetWanderRadius", &LuaCreature::SetWanderRadius }, + { "SetInCombatWithZone", &LuaCreature::SetInCombatWithZone }, + { "SetDisableReputationGain", &LuaCreature::SetDisableReputationGain }, +#if defined(TRINITY) || AZEROTHCORE + { "SetLootMode", &LuaCreature::SetLootMode }, +#endif + { "SetNPCFlags", &LuaCreature::SetNPCFlags }, + { "SetUnitFlags", &LuaCreature::SetUnitFlags }, + { "SetUnitFlagsTwo", &LuaCreature::SetUnitFlagsTwo }, +#if defined(TRINITY) || AZEROTHCORE + { "SetReactState", &LuaCreature::SetReactState }, +#endif + { "SetDeathState", &LuaCreature::SetDeathState }, + { "SetWalk", &LuaCreature::SetWalk }, + { "SetHomePosition", &LuaCreature::SetHomePosition }, + { "SetEquipmentSlots", &LuaCreature::SetEquipmentSlots }, + + // Boolean + { "IsRegeneratingHealth", &LuaCreature::IsRegeneratingHealth }, +#if defined(TRINITY) || defined(AZEROTHCORE) + { "IsDungeonBoss", &LuaCreature::IsDungeonBoss }, +#endif + { "IsWorldBoss", &LuaCreature::IsWorldBoss }, + { "IsRacialLeader", &LuaCreature::IsRacialLeader }, + { "IsCivilian", &LuaCreature::IsCivilian }, +#if defined(TRINITY) || AZEROTHCORE + { "IsTrigger", &LuaCreature::IsTrigger }, +#endif + { "IsGuard", &LuaCreature::IsGuard }, + { "IsElite", &LuaCreature::IsElite }, + { "IsInEvadeMode", &LuaCreature::IsInEvadeMode }, + { "HasCategoryCooldown", &LuaCreature::HasCategoryCooldown }, + { "CanWalk", &LuaCreature::CanWalk }, + { "CanSwim", &LuaCreature::CanSwim }, + { "CanAggro", &LuaCreature::CanAggro }, +#if defined(TRINITY) || AZEROTHCORE + { "CanStartAttack", &LuaCreature::CanStartAttack }, +#endif + { "HasSearchedAssistance", &LuaCreature::HasSearchedAssistance }, + { "IsTappedBy", &LuaCreature::IsTappedBy }, + { "HasLootRecipient", &LuaCreature::HasLootRecipient }, + { "CanAssistTo", &LuaCreature::CanAssistTo }, + { "IsTargetableForAttack", &LuaCreature::IsTargetableForAttack }, + { "CanCompleteQuest", &LuaCreature::CanCompleteQuest }, + { "IsReputationGainDisabled", &LuaCreature::IsReputationGainDisabled }, +#if defined(TRINITY) || AZEROTHCORE + { "IsDamageEnoughForLootingAndReward", &LuaCreature::IsDamageEnoughForLootingAndReward }, + { "HasLootMode", &LuaCreature::HasLootMode }, +#endif + { "HasSpell", &LuaCreature::HasSpell }, + { "HasQuest", &LuaCreature::HasQuest }, + { "HasSpellCooldown", &LuaCreature::HasSpellCooldown }, + { "CanFly", &LuaCreature::CanFly }, + + // Other + { "FleeToGetAssistance", &LuaCreature::FleeToGetAssistance }, + { "CallForHelp", &LuaCreature::CallForHelp }, + { "CallAssistance", &LuaCreature::CallAssistance }, + { "RemoveCorpse", &LuaCreature::RemoveCorpse }, + { "DespawnOrUnsummon", &LuaCreature::DespawnOrUnsummon }, + { "Respawn", &LuaCreature::Respawn }, + { "AttackStart", &LuaCreature::AttackStart }, +#if defined(TRINITY) || AZEROTHCORE + { "AddLootMode", &LuaCreature::AddLootMode }, + { "ResetLootMode", &LuaCreature::ResetLootMode }, + { "RemoveLootMode", &LuaCreature::RemoveLootMode }, +#endif + { "SaveToDB", &LuaCreature::SaveToDB }, + { "SelectVictim", &LuaCreature::SelectVictim }, + { "MoveWaypoint", &LuaCreature::MoveWaypoint }, + { "UpdateEntry", &LuaCreature::UpdateEntry }, + + { NULL, NULL } +}; + +ElunaRegister GameObjectMethods[] = +{ + // Getters + { "GetDisplayId", &LuaGameObject::GetDisplayId }, + { "GetGoState", &LuaGameObject::GetGoState }, + { "GetLootState", &LuaGameObject::GetLootState }, + { "GetLootRecipient", &LuaGameObject::GetLootRecipient }, + { "GetLootRecipientGroup", &LuaGameObject::GetLootRecipientGroup }, + { "GetDBTableGUIDLow", &LuaGameObject::GetDBTableGUIDLow }, + + // Setters + { "SetGoState", &LuaGameObject::SetGoState }, + { "SetLootState", &LuaGameObject::SetLootState }, + { "SetRespawnTime", &LuaGameObject::SetRespawnTime }, + + // Boolean + { "IsTransport", &LuaGameObject::IsTransport }, + // {"IsDestructible", &LuaGameObject::IsDestructible}, // :IsDestructible() - UNDOCUMENTED + { "IsActive", &LuaGameObject::IsActive }, + { "HasQuest", &LuaGameObject::HasQuest }, + { "IsSpawned", &LuaGameObject::IsSpawned }, + + // Other + { "RemoveFromWorld", &LuaGameObject::RemoveFromWorld }, + { "UseDoorOrButton", &LuaGameObject::UseDoorOrButton }, + { "Despawn", &LuaGameObject::Despawn }, + { "Respawn", &LuaGameObject::Respawn }, + { "SaveToDB", &LuaGameObject::SaveToDB }, + { "AddLoot", &LuaGameObject::AddLoot }, + + { NULL, NULL } +}; + +ElunaRegister ItemMethods[] = +{ + // Getters + { "GetOwnerGUID", &LuaItem::GetOwnerGUID }, + { "GetOwner", &LuaItem::GetOwner }, + { "GetCount", &LuaItem::GetCount }, + { "GetMaxStackCount", &LuaItem::GetMaxStackCount }, + { "GetSlot", &LuaItem::GetSlot }, + { "GetBagSlot", &LuaItem::GetBagSlot }, + { "GetEnchantmentId", &LuaItem::GetEnchantmentId }, + { "GetSpellId", &LuaItem::GetSpellId }, + { "GetSpellTrigger", &LuaItem::GetSpellTrigger }, + { "GetItemLink", &LuaItem::GetItemLink }, + { "GetClass", &LuaItem::GetClass }, + { "GetSubClass", &LuaItem::GetSubClass }, + { "GetName", &LuaItem::GetName }, + { "GetDisplayId", &LuaItem::GetDisplayId }, + { "GetQuality", &LuaItem::GetQuality }, + { "GetBuyCount", &LuaItem::GetBuyCount }, + { "GetBuyPrice", &LuaItem::GetBuyPrice }, + { "GetSellPrice", &LuaItem::GetSellPrice }, + { "GetInventoryType", &LuaItem::GetInventoryType }, + { "GetAllowableClass", &LuaItem::GetAllowableClass }, + { "GetAllowableRace", &LuaItem::GetAllowableRace }, + { "GetItemLevel", &LuaItem::GetItemLevel }, + { "GetRequiredLevel", &LuaItem::GetRequiredLevel }, +#ifdef WOTLK + { "GetStatsCount", &LuaItem::GetStatsCount }, +#endif + { "GetRandomProperty", &LuaItem::GetRandomProperty }, +#ifndef CLASSIC + { "GetRandomSuffix", &LuaItem::GetRandomSuffix }, +#endif + { "GetItemSet", &LuaItem::GetItemSet }, + { "GetBagSize", &LuaItem::GetBagSize }, + { "GetItemTemplate", &LuaItem::GetItemTemplate }, + + // Setters + { "SetOwner", &LuaItem::SetOwner }, + { "SetBinding", &LuaItem::SetBinding }, + { "SetCount", &LuaItem::SetCount }, + + // Boolean + { "IsSoulBound", &LuaItem::IsSoulBound }, +#if (!defined(TBC) && !defined(CLASSIC)) + { "IsBoundAccountWide", &LuaItem::IsBoundAccountWide }, +#endif + { "IsBoundByEnchant", &LuaItem::IsBoundByEnchant }, + { "IsNotBoundToPlayer", &LuaItem::IsNotBoundToPlayer }, + { "IsLocked", &LuaItem::IsLocked }, + { "IsBag", &LuaItem::IsBag }, +#ifndef CLASSIC + { "IsCurrencyToken", &LuaItem::IsCurrencyToken }, +#endif + { "IsNotEmptyBag", &LuaItem::IsNotEmptyBag }, + { "IsBroken", &LuaItem::IsBroken }, + { "CanBeTraded", &LuaItem::CanBeTraded }, + { "IsInTrade", &LuaItem::IsInTrade }, + { "IsInBag", &LuaItem::IsInBag }, + { "IsEquipped", &LuaItem::IsEquipped }, + { "HasQuest", &LuaItem::HasQuest }, + { "IsPotion", &LuaItem::IsPotion }, +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + { "IsWeaponVellum", &LuaItem::IsWeaponVellum }, + { "IsArmorVellum", &LuaItem::IsArmorVellum }, +#endif + { "IsConjuredConsumable", &LuaItem::IsConjuredConsumable }, + //{"IsRefundExpired", &LuaItem::IsRefundExpired}, // :IsRefundExpired() - UNDOCUMENTED - Returns true if the item's refund time has expired + { "SetEnchantment", &LuaItem::SetEnchantment }, + { "ClearEnchantment", &LuaItem::ClearEnchantment }, + + // Other + { "SaveToDB", &LuaItem::SaveToDB }, + + { NULL, NULL } +}; + +ElunaRegister ItemTemplateMethods[] = +{ + { "GetItemId", &LuaItemTemplate::GetItemId }, + { "GetClass", &LuaItemTemplate::GetClass }, + { "GetSubClass", &LuaItemTemplate::GetSubClass }, + { "GetName", &LuaItemTemplate::GetName }, + { "GetDisplayId", &LuaItemTemplate::GetDisplayId }, + { "GetQuality", &LuaItemTemplate::GetQuality }, + { "GetFlags", &LuaItemTemplate::GetFlags }, + { "GetExtraFlags", &LuaItemTemplate::GetExtraFlags }, + { "GetBuyCount", &LuaItemTemplate::GetBuyCount }, + { "GetBuyPrice", &LuaItemTemplate::GetBuyPrice }, + { "GetSellPrice", &LuaItemTemplate::GetSellPrice }, + { "GetInventoryType", &LuaItemTemplate::GetInventoryType }, + { "GetAllowableClass", &LuaItemTemplate::GetAllowableClass }, + { "GetAllowableRace", &LuaItemTemplate::GetAllowableRace }, + { "GetItemLevel", &LuaItemTemplate::GetItemLevel }, + { "GetRequiredLevel", &LuaItemTemplate::GetRequiredLevel }, + { NULL, NULL } +}; + +ElunaRegister AuraMethods[] = +{ + // Getters + { "GetCaster", &LuaAura::GetCaster }, + { "GetCasterGUID", &LuaAura::GetCasterGUID }, + { "GetCasterLevel", &LuaAura::GetCasterLevel }, + { "GetDuration", &LuaAura::GetDuration }, + { "GetMaxDuration", &LuaAura::GetMaxDuration }, + { "GetAuraId", &LuaAura::GetAuraId }, + { "GetStackAmount", &LuaAura::GetStackAmount }, + { "GetOwner", &LuaAura::GetOwner }, + + // Setters + { "SetDuration", &LuaAura::SetDuration }, + { "SetMaxDuration", &LuaAura::SetMaxDuration }, + { "SetStackAmount", &LuaAura::SetStackAmount }, + + // Other + { "Remove", &LuaAura::Remove }, + + { NULL, NULL } +}; + +ElunaRegister SpellMethods[] = +{ + // Getters + { "GetCaster", &LuaSpell::GetCaster }, + { "GetCastTime", &LuaSpell::GetCastTime }, + { "GetEntry", &LuaSpell::GetEntry }, + { "GetDuration", &LuaSpell::GetDuration }, + { "GetPowerCost", &LuaSpell::GetPowerCost }, + { "GetTargetDest", &LuaSpell::GetTargetDest }, + { "GetTarget", &LuaSpell::GetTarget }, + + // Setters + { "SetAutoRepeat", &LuaSpell::SetAutoRepeat }, + + // Boolean + { "IsAutoRepeat", &LuaSpell::IsAutoRepeat }, + + // Other + { "Cancel", &LuaSpell::Cancel }, + { "Cast", &LuaSpell::Cast }, + { "Finish", &LuaSpell::Finish }, + + { NULL, NULL } +}; + +ElunaRegister QuestMethods[] = +{ + // Getters + { "GetId", &LuaQuest::GetId }, + { "GetLevel", &LuaQuest::GetLevel }, + // {"GetMaxLevel", &LuaQuest::GetMaxLevel}, // :GetMaxLevel() - UNDOCUMENTED - Returns the quest's max level + { "GetMinLevel", &LuaQuest::GetMinLevel }, + { "GetNextQuestId", &LuaQuest::GetNextQuestId }, + { "GetPrevQuestId", &LuaQuest::GetPrevQuestId }, + { "GetNextQuestInChain", &LuaQuest::GetNextQuestInChain }, + { "GetFlags", &LuaQuest::GetFlags }, + { "GetType", &LuaQuest::GetType }, + + // Boolean + { "HasFlag", &LuaQuest::HasFlag }, +#ifndef CLASSIC + { "IsDaily", &LuaQuest::IsDaily }, +#endif + { "IsRepeatable", &LuaQuest::IsRepeatable }, + + { NULL, NULL } +}; + +ElunaRegister GroupMethods[] = +{ + // Getters + { "GetMembers", &LuaGroup::GetMembers }, + { "GetLeaderGUID", &LuaGroup::GetLeaderGUID }, + { "GetGUID", &LuaGroup::GetGUID }, + { "GetMemberGroup", &LuaGroup::GetMemberGroup }, + { "GetMemberGUID", &LuaGroup::GetMemberGUID }, + { "GetMembersCount", &LuaGroup::GetMembersCount }, + { "GetGroupType", &LuaGroup::GetGroupType }, + + // Setters + { "SetLeader", &LuaGroup::SetLeader }, + { "SetMembersGroup", &LuaGroup::SetMembersGroup }, + { "SetTargetIcon", &LuaGroup::SetTargetIcon }, + { "SetMemberFlag", &LuaGroup::SetMemberFlag }, + + // Boolean + { "IsLeader", &LuaGroup::IsLeader }, + { "AddMember", &LuaGroup::AddMember }, + { "RemoveMember", &LuaGroup::RemoveMember }, + { "Disband", &LuaGroup::Disband }, + { "IsFull", &LuaGroup::IsFull }, + { "IsLFGGroup", &LuaGroup::IsLFGGroup }, + { "IsRaidGroup", &LuaGroup::IsRaidGroup }, + { "IsBGGroup", &LuaGroup::IsBGGroup }, + // {"IsBFGroup", &LuaGroup::IsBFGroup}, // :IsBFGroup() - UNDOCUMENTED - Returns true if the group is a battlefield group + { "IsMember", &LuaGroup::IsMember }, + { "IsAssistant", &LuaGroup::IsAssistant }, + { "SameSubGroup", &LuaGroup::SameSubGroup }, + { "HasFreeSlotSubGroup", &LuaGroup::HasFreeSlotSubGroup }, + + // Other + { "SendPacket", &LuaGroup::SendPacket }, + // {"ConvertToLFG", &LuaGroup::ConvertToLFG}, // :ConvertToLFG() - UNDOCUMENTED - Converts the group to an LFG group + { "ConvertToRaid", &LuaGroup::ConvertToRaid }, + + { NULL, NULL } +}; + +ElunaRegister GuildMethods[] = +{ + // Getters + { "GetMembers", &LuaGuild::GetMembers }, + { "GetLeader", &LuaGuild::GetLeader }, + { "GetLeaderGUID", &LuaGuild::GetLeaderGUID }, + { "GetId", &LuaGuild::GetId }, + { "GetName", &LuaGuild::GetName }, + { "GetMOTD", &LuaGuild::GetMOTD }, + { "GetInfo", &LuaGuild::GetInfo }, + { "GetMemberCount", &LuaGuild::GetMemberCount }, + + // Setters +#ifndef CLASSIC + { "SetBankTabText", &LuaGuild::SetBankTabText }, +#endif + { "SetMemberRank", &LuaGuild::SetMemberRank }, +#if defined(CLASSIC) || defined(TBC) || defined(WOTLK) + { "SetLeader", &LuaGuild::SetLeader }, +#endif + + // Other + { "SendPacket", &LuaGuild::SendPacket }, + { "SendPacketToRanked", &LuaGuild::SendPacketToRanked }, + { "Disband", &LuaGuild::Disband }, + { "AddMember", &LuaGuild::AddMember }, + { "DeleteMember", &LuaGuild::DeleteMember }, + + { NULL, NULL } +}; + +#ifndef CLASSIC +#ifndef TBC +ElunaRegister VehicleMethods[] = +{ + // Getters + { "GetOwner", &LuaVehicle::GetOwner }, + { "GetEntry", &LuaVehicle::GetEntry }, + { "GetPassenger", &LuaVehicle::GetPassenger }, + + // Boolean + { "IsOnBoard", &LuaVehicle::IsOnBoard }, + + // Other + { "AddPassenger", &LuaVehicle::AddPassenger }, + { "RemovePassenger", &LuaVehicle::RemovePassenger }, + + { NULL, NULL } +}; +#endif +#endif + +ElunaRegister QueryMethods[] = +{ + // Getters + { "GetColumnCount", &LuaQuery::GetColumnCount }, + { "GetRowCount", &LuaQuery::GetRowCount }, + { "GetRow", &LuaQuery::GetRow }, + { "GetBool", &LuaQuery::GetBool }, + { "GetUInt8", &LuaQuery::GetUInt8 }, + { "GetUInt16", &LuaQuery::GetUInt16 }, + { "GetUInt32", &LuaQuery::GetUInt32 }, + { "GetUInt64", &LuaQuery::GetUInt64 }, + { "GetInt8", &LuaQuery::GetInt8 }, + { "GetInt16", &LuaQuery::GetInt16 }, + { "GetInt32", &LuaQuery::GetInt32 }, + { "GetInt64", &LuaQuery::GetInt64 }, + { "GetFloat", &LuaQuery::GetFloat }, + { "GetDouble", &LuaQuery::GetDouble }, + { "GetString", &LuaQuery::GetString }, + + // Boolean + { "NextRow", &LuaQuery::NextRow }, + { "IsNull", &LuaQuery::IsNull }, + + { NULL, NULL } +}; + +ElunaRegister PacketMethods[] = +{ + // Getters + { "GetOpcode", &LuaPacket::GetOpcode }, + { "GetSize", &LuaPacket::GetSize }, + + // Setters + { "SetOpcode", &LuaPacket::SetOpcode }, + + // Readers + { "ReadByte", &LuaPacket::ReadByte }, + { "ReadUByte", &LuaPacket::ReadUByte }, + { "ReadShort", &LuaPacket::ReadShort }, + { "ReadUShort", &LuaPacket::ReadUShort }, + { "ReadLong", &LuaPacket::ReadLong }, + { "ReadULong", &LuaPacket::ReadULong }, + { "ReadGUID", &LuaPacket::ReadGUID }, + { "ReadString", &LuaPacket::ReadString }, + { "ReadFloat", &LuaPacket::ReadFloat }, + { "ReadDouble", &LuaPacket::ReadDouble }, + + // Writers + { "WriteByte", &LuaPacket::WriteByte }, + { "WriteUByte", &LuaPacket::WriteUByte }, + { "WriteShort", &LuaPacket::WriteShort }, + { "WriteUShort", &LuaPacket::WriteUShort }, + { "WriteLong", &LuaPacket::WriteLong }, + { "WriteULong", &LuaPacket::WriteULong }, + { "WriteGUID", &LuaPacket::WriteGUID }, + { "WriteString", &LuaPacket::WriteString }, + { "WriteFloat", &LuaPacket::WriteFloat }, + { "WriteDouble", &LuaPacket::WriteDouble }, + + { NULL, NULL } +}; + +ElunaRegister MapMethods[] = +{ + // Getters + { "GetName", &LuaMap::GetName }, + { "GetDifficulty", &LuaMap::GetDifficulty }, + { "GetInstanceId", &LuaMap::GetInstanceId }, + { "GetInstanceData", &LuaMap::GetInstanceData }, + { "GetPlayerCount", &LuaMap::GetPlayerCount }, + { "GetPlayers", &LuaMap::GetPlayers }, + { "GetMapId", &LuaMap::GetMapId }, + { "GetAreaId", &LuaMap::GetAreaId }, + { "GetHeight", &LuaMap::GetHeight }, + { "GetWorldObject", &LuaMap::GetWorldObject }, + + // Setters + { "SetWeather", &LuaMap::SetWeather }, + + // Boolean +#ifndef CLASSIC + { "IsArena", &LuaMap::IsArena }, +#endif + { "IsBattleground", &LuaMap::IsBattleground }, + { "IsDungeon", &LuaMap::IsDungeon }, + { "IsEmpty", &LuaMap::IsEmpty }, +#ifndef CLASSIC + { "IsHeroic", &LuaMap::IsHeroic }, +#endif + { "IsRaid", &LuaMap::IsRaid }, + + // Other + { "SaveInstanceData", &LuaMap::SaveInstanceData }, + + { NULL, NULL } +}; + +ElunaRegister CorpseMethods[] = +{ + // Getters + { "GetOwnerGUID", &LuaCorpse::GetOwnerGUID }, + { "GetGhostTime", &LuaCorpse::GetGhostTime }, + { "GetType", &LuaCorpse::GetType }, + + // Other + { "ResetGhostTime", &LuaCorpse::ResetGhostTime }, + { "SaveToDB", &LuaCorpse::SaveToDB }, + + { NULL, NULL } +}; + +ElunaRegister AuctionMethods[] = +{ + { NULL, NULL } +}; + +ElunaRegister BattleGroundMethods[] = +{ + // Getters + { "GetName", &LuaBattleGround::GetName }, + { "GetAlivePlayersCountByTeam", &LuaBattleGround::GetAlivePlayersCountByTeam }, + { "GetMap", &LuaBattleGround::GetMap }, + { "GetBonusHonorFromKillCount", &LuaBattleGround::GetBonusHonorFromKillCount }, +#ifndef AZEROTHCORE + { "GetBracketId", &LuaBattleGround::GetBracketId }, +#endif + { "GetEndTime", &LuaBattleGround::GetEndTime }, + { "GetFreeSlotsForTeam", &LuaBattleGround::GetFreeSlotsForTeam }, + { "GetInstanceId", &LuaBattleGround::GetInstanceId }, + { "GetMapId", &LuaBattleGround::GetMapId }, + { "GetTypeId", &LuaBattleGround::GetTypeId }, + { "GetMaxLevel", &LuaBattleGround::GetMaxLevel }, + { "GetMinLevel", &LuaBattleGround::GetMinLevel }, + { "GetMaxPlayers", &LuaBattleGround::GetMaxPlayers }, + { "GetMinPlayers", &LuaBattleGround::GetMinPlayers }, + { "GetMaxPlayersPerTeam", &LuaBattleGround::GetMaxPlayersPerTeam }, + { "GetMinPlayersPerTeam", &LuaBattleGround::GetMinPlayersPerTeam }, + { "GetWinner", &LuaBattleGround::GetWinner }, + { "GetStatus", &LuaBattleGround::GetStatus }, + + { NULL, NULL } +}; + +ElunaRegister ChatHandlerMethods[] = +{ + { "SendSysMessage", &LuaChatHandler::SendSysMessage }, + { "IsConsole", &LuaChatHandler::IsConsole }, + { "GetPlayer", &LuaChatHandler::GetPlayer }, + { "SendGlobalSysMessage", &LuaChatHandler::SendGlobalSysMessage }, + { "SendGlobalGMSysMessage", &LuaChatHandler::SendGlobalGMSysMessage }, + { "HasLowerSecurity", &LuaChatHandler::HasLowerSecurity }, + { "HasLowerSecurityAccount", &LuaChatHandler::HasLowerSecurityAccount }, + { "GetSelectedPlayer", &LuaChatHandler::GetSelectedPlayer }, + { "GetSelectedCreature", &LuaChatHandler::GetSelectedCreature }, + { "GetSelectedUnit", &LuaChatHandler::GetSelectedUnit }, + { "GetSelectedObject", &LuaChatHandler::GetSelectedObject }, + { "GetSelectedPlayerOrSelf", &LuaChatHandler::GetSelectedPlayerOrSelf }, + { "IsAvailable", &LuaChatHandler::IsAvailable }, + { "HasSentErrorMessage", &LuaChatHandler::HasSentErrorMessage }, + + { NULL, NULL } +}; + +ElunaRegister AchievementMethods[] = +{ + { "GetId", &LuaAchievement::GetId }, + { "GetName", &LuaAchievement::GetName }, + + { NULL, NULL } +}; + +ElunaRegister RollMethods[] = +{ + { "GetItemGUID", &LuaRoll::GetItemGUID }, + { "GetItemId", &LuaRoll::GetItemId }, + { "GetItemRandomPropId", &LuaRoll::GetItemRandomPropId }, + { "GetItemRandomSuffix", &LuaRoll::GetItemRandomSuffix }, + { "GetItemCount", &LuaRoll::GetItemCount }, + { "GetPlayerVote", &LuaRoll::GetPlayerVote }, + { "GetPlayerVoteGUIDs", &LuaRoll::GetPlayerVoteGUIDs }, + { "GetTotalPlayersRolling", &LuaRoll::GetTotalPlayersRolling }, + { "GetTotalNeed", &LuaRoll::GetTotalNeed }, + { "GetTotalGreed", &LuaRoll::GetTotalGreed }, + { "GetTotalPass", &LuaRoll::GetTotalPass }, + { "GetItemSlot", &LuaRoll::GetItemSlot }, + { "GetRollVoteMask", &LuaRoll::GetRollVoteMask }, + + { NULL, NULL } +}; + +#if (!defined(TBC) && !defined(CLASSIC)) +// fix compile error about accessing vehicle destructor +template<> int ElunaTemplate::CollectGarbage(lua_State* L) +{ + ASSERT(!manageMemory); + + // Get object pointer (and check type, no error) + ElunaObject* obj = Eluna::CHECKOBJ(L, 1, false); + delete obj; + return 0; +} +#endif + +// Template by Mud from http://stackoverflow.com/questions/4484437/lua-integer-type/4485511#4485511 +template<> int ElunaTemplate::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) + Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) - Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) * Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) / Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) % Eluna::CHECKVAL(L, 2)); return 1; } +// template<> int ElunaTemplate::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL(L, 1)); return 1; } +template<> int ElunaTemplate::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) == Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) < Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) <= Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Pow(lua_State* L) +{ + Eluna::Push(L, static_cast(powl(static_cast(Eluna::CHECKVAL(L, 1)), static_cast(Eluna::CHECKVAL(L, 2))))); + return 1; +} +template<> int ElunaTemplate::ToString(lua_State* L) +{ + unsigned long long l = Eluna::CHECKVAL(L, 1); + std::ostringstream ss; + ss << l; + Eluna::Push(L, ss.str()); + return 1; +} + +template<> int ElunaTemplate::Add(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) + Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Substract(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) - Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Multiply(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) * Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Divide(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) / Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Mod(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) % Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::UnaryMinus(lua_State* L) { Eluna::Push(L, -Eluna::CHECKVAL(L, 1)); return 1; } +template<> int ElunaTemplate::Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) == Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Less(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) < Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::LessOrEqual(lua_State* L) { Eluna::Push(L, Eluna::CHECKVAL(L, 1) <= Eluna::CHECKVAL(L, 2)); return 1; } +template<> int ElunaTemplate::Pow(lua_State* L) +{ + Eluna::Push(L, static_cast(powl(static_cast(Eluna::CHECKVAL(L, 1)), static_cast(Eluna::CHECKVAL(L, 2))))); + return 1; +} +template<> int ElunaTemplate::ToString(lua_State* L) +{ + long long l = Eluna::CHECKVAL(L, 1); + std::ostringstream ss; + ss << l; + Eluna::Push(L, ss.str()); + return 1; +} + +void RegisterFunctions(Eluna* E) +{ + ElunaGlobal::SetMethods(E, GlobalMethods); + + ElunaTemplate::Register(E, "Object"); + ElunaTemplate::SetMethods(E, ObjectMethods); + + ElunaTemplate::Register(E, "WorldObject"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + + ElunaTemplate::Register(E, "Unit"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + ElunaTemplate::SetMethods(E, UnitMethods); + + ElunaTemplate::Register(E, "Player"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + ElunaTemplate::SetMethods(E, UnitMethods); + ElunaTemplate::SetMethods(E, PlayerMethods); + + ElunaTemplate::Register(E, "Creature"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + ElunaTemplate::SetMethods(E, UnitMethods); + ElunaTemplate::SetMethods(E, CreatureMethods); + + ElunaTemplate::Register(E, "GameObject"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + ElunaTemplate::SetMethods(E, GameObjectMethods); + + ElunaTemplate::Register(E, "Corpse"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, WorldObjectMethods); + ElunaTemplate::SetMethods(E, CorpseMethods); + + ElunaTemplate::Register(E, "Item"); + ElunaTemplate::SetMethods(E, ObjectMethods); + ElunaTemplate::SetMethods(E, ItemMethods); + + ElunaTemplate::Register(E, "ItemTemplate"); + ElunaTemplate::SetMethods(E, ItemTemplateMethods); + +#ifndef CLASSIC +#ifndef TBC + ElunaTemplate::Register(E, "Vehicle"); + ElunaTemplate::SetMethods(E, VehicleMethods); +#endif +#endif + + ElunaTemplate::Register(E, "Group"); + ElunaTemplate::SetMethods(E, GroupMethods); + + ElunaTemplate::Register(E, "Guild"); + ElunaTemplate::SetMethods(E, GuildMethods); + + ElunaTemplate::Register(E, "Aura"); + ElunaTemplate::SetMethods(E, AuraMethods); + + ElunaTemplate::Register(E, "Spell"); + ElunaTemplate::SetMethods(E, SpellMethods); + + ElunaTemplate::Register(E, "Quest"); + ElunaTemplate::SetMethods(E, QuestMethods); + + ElunaTemplate::Register(E, "Map"); + ElunaTemplate::SetMethods(E, MapMethods); + + ElunaTemplate::Register(E, "AuctionHouseEntry"); + ElunaTemplate::SetMethods(E, AuctionMethods); + + ElunaTemplate::Register(E, "BattleGround"); + ElunaTemplate::SetMethods(E, BattleGroundMethods); + + ElunaTemplate::Register(E, "ChatHandler"); + ElunaTemplate::SetMethods(E, ChatHandlerMethods); + + ElunaTemplate::Register(E, "WorldPacket", true); + ElunaTemplate::SetMethods(E, PacketMethods); + + ElunaTemplate::Register(E, "ElunaQuery", true); + ElunaTemplate::SetMethods(E, QueryMethods); + + ElunaTemplate::Register(E, "AchievementEntry"); + ElunaTemplate::SetMethods(E, AchievementMethods); + + ElunaTemplate::Register(E, "Roll"); + ElunaTemplate::SetMethods(E, RollMethods); + + ElunaTemplate::Register(E, "long long", true); + + ElunaTemplate::Register(E, "unsigned long long", true); +} diff --git a/modules/mod-eluna/src/LuaEngine/MapMethods.h b/modules/mod-eluna/src/LuaEngine/MapMethods.h new file mode 100644 index 0000000..aa85ecc --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/MapMethods.h @@ -0,0 +1,373 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef MAPMETHODS_H +#define MAPMETHODS_H + +#include "ElunaInstanceAI.h" + +/*** + * A game map, e.g. Azeroth, Eastern Kingdoms, the Molten Core, etc. + * + * Inherits all methods from: none + */ +namespace LuaMap +{ + +#ifndef CLASSIC + /** + * Returns `true` if the [Map] is an arena [BattleGround], `false` otherwise. + * + * @return bool isArena + */ + int IsArena(lua_State* L, Map* map) + { + Eluna::Push(L, map->IsBattleArena()); + return 1; + } +#endif + + /** + * Returns `true` if the [Map] is a non-arena [BattleGround], `false` otherwise. + * + * @return bool isBattleGround + */ + int IsBattleground(lua_State* L, Map* map) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, map->IsBattleground()); +#else + Eluna::Push(L, map->IsBattleGround()); +#endif + return 1; + } + + /** + * Returns `true` if the [Map] is a dungeon, `false` otherwise. + * + * @return bool isDungeon + */ + int IsDungeon(lua_State* L, Map* map) + { + Eluna::Push(L, map->IsDungeon()); + return 1; + } + + /** + * Returns `true` if the [Map] has no [Player]s, `false` otherwise. + * + * @return bool IsEmpty + */ + int IsEmpty(lua_State* L, Map* map) + { + Eluna::Push(L, map->IsEmpty()); + return 1; + } + +#ifndef CLASSIC + /** + * Returns `true` if the [Map] is a heroic, `false` otherwise. + * + * @return bool isHeroic + */ + int IsHeroic(lua_State* L, Map* map) + { + Eluna::Push(L, map->IsHeroic()); + return 1; + } +#endif + + /** + * Returns `true` if the [Map] is a raid, `false` otherwise. + * + * @return bool isRaid + */ + int IsRaid(lua_State* L, Map* map) + { + Eluna::Push(L, map->IsRaid()); + return 1; + } + + /** + * Returns the name of the [Map]. + * + * @return string mapName + */ + int GetName(lua_State* L, Map* map) + { + Eluna::Push(L, map->GetMapName()); + return 1; + } + + /** + * Returns the height of the [Map] at the given X and Y coordinates. + * + * In case of no height found nil is returned + * + * @param float x + * @param float y + * @return float z + */ + int GetHeight(lua_State* L, Map* map) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); +#if (defined(TBC) || defined(CLASSIC)) + float z = map->GetHeight(x, y, MAX_HEIGHT); +#else + uint32 phasemask = Eluna::CHECKVAL(L, 4, 1); + float z = map->GetHeight(phasemask, x, y, MAX_HEIGHT); +#endif + if (z != INVALID_HEIGHT) + Eluna::Push(L, z); + return 1; + } + + /** + * Returns the difficulty of the [Map]. + * + * Always returns 0 if the expansion is pre-TBC. + * + * @return int32 difficulty + */ + int GetDifficulty(lua_State* L, Map* map) + { +#ifndef CLASSIC + Eluna::Push(L, map->GetDifficulty()); +#else + Eluna::Push(L, (Difficulty)0); +#endif + return 1; + } + + /** + * Returns the instance ID of the [Map]. + * + * @return uint32 instanceId + */ + int GetInstanceId(lua_State* L, Map* map) + { + Eluna::Push(L, map->GetInstanceId()); + return 1; + } + + /** + * Returns the player count currently on the [Map] (excluding GMs). + * + * @return uint32 playerCount + */ + int GetPlayerCount(lua_State* L, Map* map) + { + Eluna::Push(L, map->GetPlayersCountExceptGMs()); + return 1; + } + + /** + * Returns the ID of the [Map]. + * + * @return uint32 mapId + */ + int GetMapId(lua_State* L, Map* map) + { + Eluna::Push(L, map->GetId()); + return 1; + } + + /** + * Returns the area ID of the [Map] at the specified X, Y, and Z coordinates. + * + * @param float x + * @param float y + * @param float z + * @param uint32 phasemask = PHASEMASK_NORMAL + * @return uint32 areaId + */ + int GetAreaId(lua_State* L, Map* map) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); +#if defined TRINITY || defined AZEROTHCORE + float phasemask = Eluna::CHECKVAL(L, 5, PHASEMASK_NORMAL); + + Eluna::Push(L, map->GetAreaId(phasemask, x, y, z)); +#else + Eluna::Push(L, map->GetTerrain()->GetAreaId(x, y, z)); +#endif + return 1; + } + + /** + * Returns a [WorldObject] by its GUID from the map if it is spawned. + * + * @param ObjectGuid guid + * @return [WorldObject] object + */ + int GetWorldObject(lua_State* L, Map* map) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + +#if defined TRINITY || AZEROTHCORE + switch (guid.GetHigh()) + { + case HIGHGUID_PLAYER: + Eluna::Push(L, eObjectAccessor()GetPlayer(map, guid)); + break; + case HIGHGUID_TRANSPORT: + case HIGHGUID_MO_TRANSPORT: + case HIGHGUID_GAMEOBJECT: + Eluna::Push(L, map->GetGameObject(guid)); + break; + case HIGHGUID_VEHICLE: + case HIGHGUID_UNIT: + Eluna::Push(L, map->GetCreature(guid)); + break; + case HIGHGUID_PET: + Eluna::Push(L, map->GetPet(guid)); + break; + case HIGHGUID_DYNAMICOBJECT: + Eluna::Push(L, map->GetDynamicObject(guid)); + break; + case HIGHGUID_CORPSE: + Eluna::Push(L, map->GetCorpse(guid)); + break; + default: + break; + } +#else + Eluna::Push(L, map->GetWorldObject(guid)); +#endif + return 1; + } + + /** + * Sets the [Weather] type based on [WeatherType] and grade supplied. + * + * enum WeatherType + * { + * WEATHER_TYPE_FINE = 0, + * WEATHER_TYPE_RAIN = 1, + * WEATHER_TYPE_SNOW = 2, + * WEATHER_TYPE_STORM = 3, + * WEATHER_TYPE_THUNDERS = 86, + * WEATHER_TYPE_BLACKRAIN = 90 + * }; + * + * @param uint32 zone : id of the zone to set the weather for + * @param [WeatherType] type : the [WeatherType], see above available weather types + * @param float grade : the intensity/grade of the [Weather], ranges from 0 to 1 + */ + int SetWeather(lua_State* L, Map* map) + { + (void)map; // ensure that the variable is referenced in order to pass compiler checks + uint32 zoneId = Eluna::CHECKVAL(L, 2); + uint32 weatherType = Eluna::CHECKVAL(L, 3); + float grade = Eluna::CHECKVAL(L, 4); + +#if defined TRINITY + if (Weather * weather = map->GetOrGenerateZoneDefaultWeather(zoneId)) + weather->SetWeather((WeatherType)weatherType, grade); +#elif defined AZEROTHCORE + Weather* weather = WeatherMgr::FindWeather(zoneId); + if (!weather) + weather = WeatherMgr::AddWeather(zoneId); + if (weather) + weather->SetWeather((WeatherType)weatherType, grade); +#else + if (Weather::IsValidWeatherType(weatherType)) + map->SetWeather(zoneId, (WeatherType)weatherType, grade, false); +#endif + return 0; + } + + /** + * Gets the instance data table for the [Map], if it exists. + * + * The instance must be scripted using Eluna for this to succeed. + * If the instance is scripted in C++ this will return `nil`. + * + * @return table instance_data : instance data table, or `nil` + */ + int GetInstanceData(lua_State* L, Map* map) + { +#if defined TRINITY || AZEROTHCORE + ElunaInstanceAI* iAI = NULL; + if (InstanceMap* inst = map->ToInstanceMap()) + iAI = dynamic_cast(inst->GetInstanceScript()); +#else + ElunaInstanceAI* iAI = dynamic_cast(map->GetInstanceData()); +#endif + + if (iAI) + Eluna::GetEluna(L)->PushInstanceData(L, iAI, false); + else + Eluna::Push(L); // nil + + return 1; + } + + /** + * Saves the [Map]'s instance data to the database. + */ + int SaveInstanceData(lua_State* /*L*/, Map* map) + { +#if defined TRINITY || AZEROTHCORE + ElunaInstanceAI* iAI = NULL; + if (InstanceMap* inst = map->ToInstanceMap()) + iAI = dynamic_cast(inst->GetInstanceScript()); +#else + ElunaInstanceAI* iAI = dynamic_cast(map->GetInstanceData()); +#endif + + if (iAI) + iAI->SaveToDB(); + + return 0; + } + + /** + * Returns a table with all the current [Player]s in the map + * + * enum TeamId + * { + * TEAM_ALLIANCE = 0, + * TEAM_HORDE = 1, + * TEAM_NEUTRAL = 2 + * }; + * + * @param [TeamId] team : optional check team of the [Player], Alliance, Horde or Neutral (All) + * @return table mapPlayers + */ + int GetPlayers(lua_State* L, Map* map) + { + uint32 team = Eluna::CHECKVAL(L, 2, TEAM_NEUTRAL); + + lua_newtable(L); + int tbl = lua_gettop(L); + uint32 i = 0; + + Map::PlayerList const& players = map->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { +#if defined TRINITY || AZEROTHCORE + Player* player = itr->GetSource(); +#else + Player* player = itr->getSource(); +#endif + if (!player) + continue; + if (player->GetSession() && (team >= TEAM_NEUTRAL || player->GetTeamId() == team)) + { + Eluna::Push(L, player); + lua_rawseti(L, tbl, ++i); + } + } + + lua_settop(L, tbl); + return 1; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ObjectMethods.h b/modules/mod-eluna/src/LuaEngine/ObjectMethods.h new file mode 100644 index 0000000..d96fbdf --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ObjectMethods.h @@ -0,0 +1,477 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef OBJECTMETHODS_H +#define OBJECTMETHODS_H + +/*** + * A basic game object (either an [Item] or a [WorldObject]). + * + * Objects in MaNGOS/Trinity are stored an a giant block of "values". + * Subclasses of Object, like [WorldObject], extend the block with more data specific to that subclass. + * Further subclasses, like [Player], extend it even further. + * + * A detailed map of all the fields in this data block can be found in the UpdateFields.h file of your emulator + * (it varies depending on the expansion supported). + * + * The GetValue methods in this class (e.g. [Object:GetInt32Value]) provide low-level access to the data block. + * Other methods, like [Object:HasFlag] and [Object:GetScale], merely wrap the GetValue methods and provide a simpler interface. + * + * Inherits all methods from: none + */ +namespace LuaObject +{ + /** + * Returns `true` if the specified flag is set, otherwise `false`. + * + * @param uint16 index : the index of the flags data in the [Object] + * @param uint32 flag : the flag to check for in the flags data + * @return bool hasFlag + */ + int HasFlag(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint32 flag = Eluna::CHECKVAL(L, 3); + + Eluna::Push(L, obj->HasFlag(index, flag)); + return 1; + } + + /** + * Returns `true` if the [Object] has been added to its [Map], otherwise `false`. + * + * @return bool inWorld + */ + int IsInWorld(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->IsInWorld()); + return 1; + } + + /** + * Returns 'true' if the [Object] is a player, 'false' otherwise. + * + * @return bool IsPlayer + */ + int IsPlayer(lua_State* L, Object* obj) + { +#ifdef AZEROTHCORE //AC-only + Eluna::Push(L, obj->IsPlayer()); +#endif + return 1; + } + + /** + * Returns the data at the specified index, casted to a signed 32-bit integer. + * + * @param uint16 index + * @return int32 value + */ + int GetInt32Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, obj->GetInt32Value(index)); + return 1; + } + + /** + * Returns the data at the specified index, casted to a unsigned 32-bit integer. + * + * @param uint16 index + * @return uint32 value + */ + int GetUInt32Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, obj->GetUInt32Value(index)); + return 1; + } + + /** + * Returns the data at the specified index, casted to a single-precision floating point value. + * + * @param uint16 index + * @return float value + */ + int GetFloatValue(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, obj->GetFloatValue(index)); + return 1; + } + + /** + * Returns the data at the specified index and offset, casted to an unsigned 8-bit integer. + * + * E.g. if you want the second byte at index 10, you would pass in 1 as the offset. + * + * @param uint16 index + * @param uint8 offset : should be 0, 1, 2, or 3 + * @return uint8 value + */ + int GetByteValue(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint8 offset = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, obj->GetByteValue(index, offset)); + return 1; + } + + /** + * Returns the data at the specified index and offset, casted to a signed 16-bit integer. + * + * E.g. if you want the second half-word at index 10, you would pass in 1 as the offset. + * + * @param uint16 index + * @param uint8 offset : should be 0 or 1 + * @return uint16 value + */ + int GetUInt16Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint8 offset = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, obj->GetUInt16Value(index, offset)); + return 1; + } + + /** + * Returns the scale/size of the [Object]. + * + * This affects the size of a [WorldObject] in-game, but [Item]s don't have a "scale". + * + * @return float scale + */ + int GetScale(lua_State* L, Object* obj) + { +#ifndef AZEROTHCORE + Eluna::Push(L, obj->GetObjectScale()); +#else + Eluna::Push(L, obj->GetFloatValue(OBJECT_FIELD_SCALE_X)); +#endif + return 1; + } + + /** + * Returns the entry of the [Object]. + * + * [Player]s do not have an "entry". + * + * @return uint32 entry + */ + int GetEntry(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->GetEntry()); + return 1; + } + + /** + * Returns the GUID of the [Object]. + * + * GUID is an unique identifier for the object. + * + * However on MaNGOS and cMangos creatures and gameobjects inside different maps can share + * the same GUID but not on the same map. + * + * On TrinityCore this value is unique across all maps + * + * @return ObjectGuid guid + */ + int GetGUID(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->GET_GUID()); + return 1; + } + + /** + * Returns the low-part of the [Object]'s GUID. + * + * On TrinityCore all low GUIDs are different for all objects of the same type. + * For example creatures in instances are assigned new GUIDs when the Map is created. + * + * On MaNGOS and cMaNGOS low GUIDs are unique only on the same map. + * For example creatures in instances use the same low GUID assigned for that spawn in the database. + * This is why to identify a creature you have to know the instanceId and low GUID. See [Map:GetIntstanceId] + * + * @return uint32 guidLow + */ + int GetGUIDLow(lua_State* L, Object* obj) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, obj->GetGUID().GetCounter()); +#else + Eluna::Push(L, obj->GetGUIDLow()); +#endif + return 1; + } + + /** + * Returns the TypeId of the [Object]. + * + * enum TypeID + * { + * TYPEID_OBJECT = 0, + * TYPEID_ITEM = 1, + * TYPEID_CONTAINER = 2, + * TYPEID_UNIT = 3, + * TYPEID_PLAYER = 4, + * TYPEID_GAMEOBJECT = 5, + * TYPEID_DYNAMICOBJECT = 6, + * TYPEID_CORPSE = 7 + * }; + * + * @return uint8 typeID + */ + int GetTypeId(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->GetTypeId()); + return 1; + } + + /** + * Returns the data at the specified index, casted to an unsigned 64-bit integer. + * + * @param uint16 index + * @return uint64 value + */ + int GetUInt64Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, obj->GetUInt64Value(index)); + return 1; + } + + /** + * Sets the specified flag in the data value at the specified index. + * + * If the flag was already set, it remains set. + * + * To remove a flag, use [Object:RemoveFlag]. + * + * @param uint16 index + * @param uint32 value + */ + int SetFlag(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint32 flag = Eluna::CHECKVAL(L, 3); + + obj->SetFlag(index, flag); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to a signed 32-bit integer. + * + * @param uint16 index + * @param int32 value + */ + int SetInt32Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + int32 value = Eluna::CHECKVAL(L, 3); + obj->SetInt32Value(index, value); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to an unsigned 32-bit integer. + * + * @param uint16 index + * @param uint32 value + */ + int SetUInt32Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint32 value = Eluna::CHECKVAL(L, 3); + obj->SetUInt32Value(index, value); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to an unsigned 32-bit integer. + * + * @param uint16 index + * @param uint32 value + */ + int UpdateUInt32Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint32 value = Eluna::CHECKVAL(L, 3); + obj->UpdateUInt32Value(index, value); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to a single-precision floating point value. + * + * @param uint16 index + * @param float value + */ + int SetFloatValue(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + float value = Eluna::CHECKVAL(L, 3); + + obj->SetFloatValue(index, value); + return 0; + } + + /** + * Sets the data at the specified index and offset to the given value, converted to an unsigned 8-bit integer. + * + * @param uint16 index + * @param uint8 offset : should be 0, 1, 2, or 3 + * @param uint8 value + */ + int SetByteValue(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint8 offset = Eluna::CHECKVAL(L, 3); + uint8 value = Eluna::CHECKVAL(L, 4); + obj->SetByteValue(index, offset, value); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to an unsigned 16-bit integer. + * + * @param uint16 index + * @param uint8 offset : should be 0 or 1 + * @param uint16 value + */ + int SetUInt16Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint8 offset = Eluna::CHECKVAL(L, 3); + uint16 value = Eluna::CHECKVAL(L, 4); + obj->SetUInt16Value(index, offset, value); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to a signed 16-bit integer. + * + * @param uint16 index + * @param uint8 offset : should be 0 or 1 + * @param int16 value + */ + int SetInt16Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint8 offset = Eluna::CHECKVAL(L, 3); + int16 value = Eluna::CHECKVAL(L, 4); + obj->SetInt16Value(index, offset, value); + return 0; + } + + /** + * Sets the [Object]'s scale/size to the given value. + * + * @param float scale + */ + int SetScale(lua_State* L, Object* obj) + { + float size = Eluna::CHECKVAL(L, 2); + + obj->SetObjectScale(size); + return 0; + } + + /** + * Sets the data at the specified index to the given value, converted to an unsigned 64-bit integer. + * + * @param uint16 index + * @param uint64 value + */ + int SetUInt64Value(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint64 value = Eluna::CHECKVAL(L, 3); + obj->SetUInt64Value(index, value); + return 0; + } + + /** + * Removes a flag from the value at the specified index. + * + * @param uint16 index + * @param uint32 flag + */ + int RemoveFlag(lua_State* L, Object* obj) + { + uint16 index = Eluna::CHECKVAL(L, 2); + uint32 flag = Eluna::CHECKVAL(L, 3); + + obj->RemoveFlag(index, flag); + return 0; + } + + /** + * Attempts to convert the [Object] to a [Corpse]. + * + * If the [Object] is not a [Corpse], returns `nil`. + * + * @return [Corpse] corpse : the [Object] as a [Corpse], or `nil` + */ + int ToCorpse(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->ToCorpse()); + return 1; + } + + /** + * Attempts to convert the [Object] to a [GameObject]. + * + * If the [Object] is not a [GameObject], returns `nil`. + * + * @return [GameObject] gameObject : the [Object] as a [GameObject], or `nil` + */ + int ToGameObject(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->ToGameObject()); + return 1; + } + + /** + * Attempts to convert the [Object] to a [Unit]. + * + * If the [Object] is not a [Unit], returns `nil`. + * + * @return [Unit] unit : the [Object] as a [Unit], or `nil` + */ + int ToUnit(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->ToUnit()); + return 1; + } + + /** + * Attempts to convert the [Object] to a [Creature]. + * + * If the [Object] is not a [Creature], returns `nil`. + * + * @return [Creature] creature : the [Object] as a [Creature], or `nil` + */ + int ToCreature(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->ToCreature()); + return 1; + } + + /** + * Attempts to convert the [Object] to a [Player]. + * + * If the [Object] is not a [Player], returns `nil`. + * + * @return [Player] player : the [Object] as a [Player], or `nil` + */ + int ToPlayer(lua_State* L, Object* obj) + { + Eluna::Push(L, obj->ToPlayer()); + return 1; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/PacketHooks.cpp b/modules/mod-eluna/src/LuaEngine/PacketHooks.cpp new file mode 100644 index 0000000..d11f3fa --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/PacketHooks.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK_SERVER(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_PACKET(EVENT, OPCODE) \ + if (!IsEnabled())\ + return;\ + auto key = EntryKey(EVENT, OPCODE);\ + if (!PacketEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +bool Eluna::OnPacketSend(WorldSession* session, const WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketSendAny(player, packet, result); + OnPacketSendOne(player, packet, result); + return result; +} +void Eluna::OnPacketSendAny(Player* player, const WorldPacket& packet, bool& result) +{ + START_HOOK_SERVER(SERVER_EVENT_ON_PACKET_SEND); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + lua_pop(L, 1); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketSendOne(Player* player, const WorldPacket& packet, bool& result) +{ + START_HOOK_PACKET(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode()); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + lua_pop(L, 1); + } + + CleanUpStack(2); +} + +bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketReceiveAny(player, packet, result); + OnPacketReceiveOne(player, packet, result); + return result; +} + +void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_SERVER(SERVER_EVENT_ON_PACKET_RECEIVE); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) +{ + START_HOOK_PACKET(PACKET_EVENT_ON_PACKET_RECEIVE, packet.GetOpcode()); + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} diff --git a/modules/mod-eluna/src/LuaEngine/PlayerHooks.cpp b/modules/mod-eluna/src/LuaEngine/PlayerHooks.cpp new file mode 100644 index 0000000..6d30434 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/PlayerHooks.cpp @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!PlayerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EventKey(EVENT);\ + if (!PlayerEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +void Eluna::OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid) +{ + START_HOOK(PLAYER_EVENT_ON_LEARN_TALENTS); + Push(pPlayer); + Push(talentId); + Push(talentRank); + Push(spellid); + CallAllFunctions(PlayerEventBindings, key); +} + +bool Eluna::OnCommand(ChatHandler& handler, const char* text) +{ + Player* player = handler.IsConsole() ? nullptr : handler.GetSession()->GetPlayer(); + // If from console, player is NULL + if (!player || player->GetSession()->GetSecurity() >= SEC_ADMINISTRATOR) + { + std::string reload = text; + std::transform(reload.begin(), reload.end(), reload.begin(), ::tolower); + if (reload.find("reload eluna") == 0) + { + ReloadEluna(); + return false; + } + } + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_COMMAND, true); + Push(player); + Push(text); + Push(&handler); + return CallAllFunctionsBool(PlayerEventBindings, key, true); +} + +void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, ObjectGuid guid) +{ + START_HOOK(PLAYER_EVENT_ON_LOOT_ITEM); + Push(pPlayer); + Push(pItem); + Push(count); + Push(guid); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnLootMoney(Player* pPlayer, uint32 amount) +{ + START_HOOK(PLAYER_EVENT_ON_LOOT_MONEY); + Push(pPlayer); + Push(amount); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnFirstLogin(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_FIRST_LOGIN); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnRepop(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_REPOP); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnResurrect(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_RESURRECT); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId) +{ + START_HOOK(PLAYER_EVENT_ON_QUEST_ABANDON); + Push(pPlayer); + Push(questId); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot) +{ + START_HOOK(PLAYER_EVENT_ON_EQUIP); + Push(pPlayer); + Push(pItem); + Push(bag); + Push(slot); + CallAllFunctions(PlayerEventBindings, key); +} + +InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_USE_ITEM, EQUIP_ERR_OK); + InventoryResult result = EQUIP_ERR_OK; + Push(pPlayer); + Push(itemEntry); + int n = SetupStack(PlayerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isnumber(L, r)) + result = (InventoryResult)CHECKVAL(L, r); + + lua_pop(L, 1); + } + + CleanUpStack(2); + return result; +} +void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy) +{ + START_HOOK(PLAYER_EVENT_ON_ENTER_COMBAT); + Push(pPlayer); + Push(pEnemy); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnPlayerLeaveCombat(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_LEAVE_COMBAT); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnPVPKill(Player* pKiller, Player* pKilled) +{ + START_HOOK(PLAYER_EVENT_ON_KILL_PLAYER); + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled) +{ + START_HOOK(PLAYER_EVENT_ON_KILL_CREATURE); + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled) +{ + START_HOOK(PLAYER_EVENT_ON_KILLED_BY_CREATURE); + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel) +{ + START_HOOK(PLAYER_EVENT_ON_LEVEL_CHANGE); + Push(pPlayer); + Push(oldLevel); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints) +{ + START_HOOK(PLAYER_EVENT_ON_TALENTS_CHANGE); + Push(pPlayer); + Push(newPoints); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnTalentsReset(Player* pPlayer, bool noCost) +{ + START_HOOK(PLAYER_EVENT_ON_TALENTS_RESET); + Push(pPlayer); + Push(noCost); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) +{ + START_HOOK(PLAYER_EVENT_ON_MONEY_CHANGE); + Push(pPlayer); + Push(amount); + int amountIndex = lua_gettop(L); + int n = SetupStack(PlayerEventBindings, key, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(2); +} + +void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim, uint8 xpSource) +{ + START_HOOK(PLAYER_EVENT_ON_GIVE_XP); + Push(pPlayer); + Push(amount); + Push(pVictim); + Push(xpSource); + int amountIndex = lua_gettop(L) - 1; + int n = SetupStack(PlayerEventBindings, key, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(4); +} + +bool Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_REPUTATION_CHANGE, true); + bool result = true; + Push(pPlayer); + Push(factionID); + Push(standing); + Push(incremental); + int standingIndex = lua_gettop(L) - 1; + int n = SetupStack(PlayerEventBindings, key, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 1); + + if (lua_isnumber(L, r)) + { + standing = CHECKVAL(L, r); + if (standing == -1) + result = false; + // Update the stack for subsequent calls. + ReplaceArgument(standing, standingIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(4); + return result; +} + +void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger) +{ + START_HOOK(PLAYER_EVENT_ON_DUEL_REQUEST); + Push(pTarget); + Push(pChallenger); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger) +{ + START_HOOK(PLAYER_EVENT_ON_DUEL_START); + Push(pStarter); + Push(pChallenger); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type) +{ + START_HOOK(PLAYER_EVENT_ON_DUEL_END); + Push(pWinner); + Push(pLoser); + Push(type); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnEmote(Player* pPlayer, uint32 emote) +{ + START_HOOK(PLAYER_EVENT_ON_EMOTE); + Push(pPlayer); + Push(emote); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, ObjectGuid guid) +{ + START_HOOK(PLAYER_EVENT_ON_TEXT_EMOTE); + Push(pPlayer); + Push(textEmote); + Push(emoteNum); + Push(guid); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck) +{ + START_HOOK(PLAYER_EVENT_ON_SPELL_CAST); + Push(pPlayer); + Push(pSpell); + Push(skipCheck); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnLogin(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_LOGIN); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnLogout(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_LOGOUT); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnCreate(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_CHARACTER_CREATE); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnDelete(uint32 guidlow) +{ + START_HOOK(PLAYER_EVENT_ON_CHARACTER_DELETE); + Push(guidlow); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnSave(Player* pPlayer) +{ + START_HOOK(PLAYER_EVENT_ON_SAVE); + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent) +{ + START_HOOK(PLAYER_EVENT_ON_BIND_TO_INSTANCE); + Push(pPlayer); + Push(difficulty); + Push(mapid); + Push(permanent); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnUpdateArea(Player* pPlayer, uint32 oldArea, uint32 newArea) +{ + START_HOOK(PLAYER_EVENT_ON_UPDATE_AREA); + Push(pPlayer); + Push(oldArea); + Push(newArea); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea) +{ + START_HOOK(PLAYER_EVENT_ON_UPDATE_ZONE); + Push(pPlayer); + Push(newZone); + Push(newArea); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnMapChanged(Player* player) +{ + START_HOOK(PLAYER_EVENT_ON_MAP_CHANGE); + Push(player); + CallAllFunctions(PlayerEventBindings, key); +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL); + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHAT, true); + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + int n = SetupStack(PlayerEventBindings, key, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(4); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL); + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GROUP_CHAT, true); + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pGroup); + int n = SetupStack(PlayerEventBindings, key, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL); + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_GUILD_CHAT, true); + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pGuild); + int n = SetupStack(PlayerEventBindings, key, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel); + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CHANNEL_CHAT, true); + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pChannel->IsConstant() ? static_cast(pChannel->GetChannelId()) : -static_cast(pChannel->GetChannelDBId())); + int n = SetupStack(PlayerEventBindings, key, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL); + + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_WHISPER, true); + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pReceiver); + int n = SetupStack(PlayerEventBindings, key, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +void Eluna::OnPetAddedToWorld(Player* player, Creature* pet) +{ + START_HOOK(PLAYER_EVENT_ON_PET_ADDED_TO_WORLD); + Push(player); + Push(pet); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnLearnSpell(Player* player, uint32 spellId) +{ + START_HOOK(PLAYER_EVENT_ON_LEARN_SPELL); + Push(player); + Push(spellId); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnAchiComplete(Player* player, AchievementEntry const* achievement) +{ + START_HOOK(PLAYER_EVENT_ON_ACHIEVEMENT_COMPLETE); + Push(player); + Push(achievement); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnFfaPvpStateUpdate(Player* player, bool hasFfaPvp) +{ + START_HOOK(PLAYER_EVENT_ON_FFAPVP_CHANGE); + Push(player); + Push(hasFfaPvp); + CallAllFunctions(PlayerEventBindings, key); +} + +bool Eluna::OnCanInitTrade(Player* player, Player* target) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_INIT_TRADE, true); + Push(player); + Push(target); + return CallAllFunctionsBool(PlayerEventBindings, key); +} + +bool Eluna::OnCanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 cod, Item* item) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_SEND_MAIL, true); + Push(player); + Push(receiverGuid); + Push(mailbox); + Push(subject); + Push(body); + Push(money); + Push(cod); + Push(item); + return CallAllFunctionsBool(PlayerEventBindings, key); +} + +bool Eluna::OnCanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_JOIN_LFG, true); + Push(player); + Push(roles); + + lua_newtable(L); + int table = lua_gettop(L); + uint32 counter = 1; + for (uint32 dungeon : dungeons) + { + Eluna::Push(L, dungeon); + lua_rawseti(L, table, counter); + ++counter; + } + lua_settop(L, table); + ++push_counter; + + Push(comment); + return CallAllFunctionsBool(PlayerEventBindings, key); +} + +void Eluna::OnQuestRewardItem(Player* player, Item* item, uint32 count) +{ + START_HOOK(PLAYER_EVENT_ON_QUEST_REWARD_ITEM); + Push(player); + Push(item); + Push(count); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnCreateItem(Player* player, Item* item, uint32 count) +{ + START_HOOK(PLAYER_EVENT_ON_CREATE_ITEM); + Push(player); + Push(item); + Push(count); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnStoreNewItem(Player* player, Item* item, uint32 count) +{ + START_HOOK(PLAYER_EVENT_ON_STORE_NEW_ITEM); + Push(player); + Push(item); + Push(count); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnPlayerCompleteQuest(Player* player, Quest const* quest) +{ + START_HOOK(PLAYER_EVENT_ON_COMPLETE_QUEST); + Push(player); + Push(quest); + CallAllFunctions(PlayerEventBindings, key); +} + +bool Eluna::OnCanGroupInvite(Player* player, std::string& memberName) +{ + START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_CAN_GROUP_INVITE, true); + Push(player); + Push(memberName); + return CallAllFunctionsBool(PlayerEventBindings, key); +} + +void Eluna::OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll) +{ + START_HOOK(PLAYER_EVENT_ON_GROUP_ROLL_REWARD_ITEM); + Push(player); + Push(item); + Push(count); + Push(voteType); + Push(roll); + CallAllFunctions(PlayerEventBindings, key); +} + +void Eluna::OnBattlegroundDesertion(Player* player, const BattlegroundDesertionType type) +{ + START_HOOK(PLAYER_EVENT_ON_BG_DESERTION); + Push(player); + Push(type); + CallAllFunctions(PlayerEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/PlayerMethods.h b/modules/mod-eluna/src/LuaEngine/PlayerMethods.h new file mode 100644 index 0000000..c7737c6 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/PlayerMethods.h @@ -0,0 +1,4355 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef PLAYERMETHODS_H +#define PLAYERMETHODS_H + +#include "GameTime.h" + +/*** + * Inherits all methods from: [Object], [WorldObject], [Unit] + */ +namespace LuaPlayer +{ +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Returns `true` if the [Player] can Titan Grip, `false` otherwise. + * + * @return bool canTitanGrip + */ + int CanTitanGrip(lua_State* L, Player* player) + { + Eluna::Push(L, player->CanTitanGrip()); + return 1; + } + + /** + * Returns `true` if the [Player] has a talent by ID in specified spec, `false` otherwise. + * + * @param uint32 spellId : talent spellId to check + * @param uint8 spec : specified spec. 0 for primary, 1 for secondary. + * @return bool hasTalent + */ + int HasTalent(lua_State* L, Player* player) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); +#ifdef MANGOS + uint8 maxSpecs = MAX_TALENT_SPEC_COUNT; +#else + uint8 maxSpecs = MAX_TALENT_SPECS; +#endif + uint8 spec = Eluna::CHECKVAL(L, 3); + if (spec >= maxSpecs) + return 1; + Eluna::Push(L, player->HasTalent(spellId, spec)); + return 1; + } + + /** + * Returns `true` if the [Player] has completed the specified achievement, `false` otherwise. + * + * @param uint32 achievementId + * @return bool hasAchieved + */ + int HasAchieved(lua_State* L, Player* player) + { + uint32 achievementId = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->HasAchieved(achievementId)); +#else + Eluna::Push(L, player->GetAchievementMgr().HasAchievement(achievementId)); +#endif + return 1; + } + + /** + * Returns the progress of the [Player] for the specified achievement criteria. + * + * @param uint32 criteriaId + * @return uint32 progress : progress value or nil + */ + int GetAchievementCriteriaProgress(lua_State* L, Player* player) + { + uint32 criteriaId = Eluna::CHECKVAL(L, 2); + const AchievementCriteriaEntry* criteria = sAchievementCriteriaStore.LookupEntry(criteriaId); + CriteriaProgress* progress = player->GetAchievementMgr()->GetCriteriaProgress(criteria); + if (progress) + { + Eluna::Push(L, progress->counter); + } + else + { + Eluna::Push(L, (void*)nullptr); + } + return 1; + } +#endif + + /** + * Returns `true` if the [Player] has an active [Quest] by specific ID, `false` otherwise. + * + * @param uint32 questId + * @return bool hasQuest + */ + int HasQuest(lua_State* L, Player* player) + { + uint32 quest = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->IsActiveQuest(quest)); + return 1; + } + + /** + * Returns `true` if the [Player] has a skill by specific ID, `false` otherwise. + * + * @param uint32 skill + * @return bool hasSkill + */ + int HasSkill(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->HasSkill(skill)); + return 1; + } + + /** + * Returns `true` if the [Player] has a [Spell] by specific ID, `false` otherwise. + * + * @param uint32 spellId + * @return bool hasSpell + */ + int HasSpell(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->HasSpell(id)); + return 1; + } + + /** + * Returns true if [Player] has specified login flag + * + * @param uint32 flag + * @return bool hasLoginFlag + */ + int HasAtLoginFlag(lua_State* L, Player* player) + { + uint32 flag = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->HasAtLoginFlag((AtLoginFlags)flag)); + return 1; + } + + /** + * Returns true if [Player] has [Quest] for [GameObject] + * + * @param int32 entry : entry of a [GameObject] + * @return bool hasQuest + */ + int HasQuestForGO(lua_State* L, Player* player) + { + int32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->HasQuestForGO(entry)); + return 1; + } + +#ifndef CLASSIC + /** + * Returns `true` if the [Player] has a title by specific ID, `false` otherwise. + * + * @param uint32 titleId + * @return bool hasTitle + */ + int HasTitle(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); + if (titleInfo) + Eluna::Push(L, player->HasTitle(titleInfo)); + return 1; + } +#endif + + /** + * Returns `true` if the [Player] has the given amount of item entry specified, `false` otherwise. + * + * @param uint32 itemId : entry of the item + * @param uint32 count = 1 : amount of items the player needs should have + * @param bool check_bank = false : determines if the item can be in player bank + * @return bool hasItem + */ + int HasItem(lua_State* L, Player* player) + { + uint32 itemId = Eluna::CHECKVAL(L, 2); + uint32 count = Eluna::CHECKVAL(L, 3, 1); + bool check_bank = Eluna::CHECKVAL(L, 4, false); + Eluna::Push(L, player->HasItemCount(itemId, count, check_bank)); + return 1; + } + + /** + * Returns `true` if the [Player] has a quest for the item entry specified, `false` otherwise. + * + * @param uint32 entry : entry of the item + * @return bool hasQuest + */ + int HasQuestForItem(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->HasQuestForItem(entry)); + return 1; + } + + /** + * Returns `true` if the [Player] can use the item or item entry specified, `false` otherwise. + * + * @proto canUse = (item) + * @proto canUse = (entry) + * @param [Item] item : an instance of an item + * @param uint32 entry : entry of the item + * @return bool canUse + */ + int CanUseItem(lua_State* L, Player* player) + { + Item* item = Eluna::CHECKOBJ(L, 2, false); + if (item) + Eluna::Push(L, player->CanUseItem(item) == EQUIP_ERR_OK); + else + { + uint32 entry = Eluna::CHECKVAL(L, 2); + const ItemTemplate* temp = eObjectMgr->GetItemTemplate(entry); + if (temp) + Eluna::Push(L, player->CanUseItem(temp) == EQUIP_ERR_OK); + else + Eluna::Push(L, false); + } + return 1; + } + + /** + * Returns `true` if the [Spell] specified by ID is currently on cooldown for the [Player], `false` otherwise. + * + * @param uint32 spellId + * @return bool hasSpellCooldown + */ + int HasSpellCooldown(lua_State* L, Player* player) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + +#ifdef TRINITY + Eluna::Push(L, player->GetSpellHistory()->HasCooldown(spellId)); +#else + Eluna::Push(L, player->HasSpellCooldown(spellId)); +#endif + return 1; + } + + /** + * Returns `true` if the [Player] can share [Quest] specified by ID, `false` otherwise. + * + * @param uint32 entryId + * @return bool hasSpellCooldown + */ + int CanShareQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->CanShareQuest(entry)); + return 1; + } + + /** + * Returns `true` if the [Player] can currently communicate through chat, `false` otherwise. + * + * @return bool canSpeak + */ + int CanSpeak(lua_State* L, Player* player) + { +#ifdef TRINITY + Eluna::Push(L, player->GetSession()->CanSpeak()); +#else + Eluna::Push(L, player->CanSpeak()); +#endif + return 1; + } + + /** + * Returns `true` if the [Player] has permission to uninvite others from the current group, `false` otherwise. + * + * @return bool canUninviteFromGroup + */ + int CanUninviteFromGroup(lua_State* L, Player* player) + { + Eluna::Push(L, player->CanUninviteFromGroup() == ERR_PARTY_RESULT_OK); + return 1; + } + +#ifndef CLASSIC + /** + * Returns `true` if the [Player] can fly, `false` otherwise. + * + * @return bool canFly + */ + int CanFly(lua_State* L, Player* player) + { + Eluna::Push(L, player->CanFly()); + return 1; + } +#endif + +#ifdef CLASSIC + /** + * Returns [Player] kills + * + * @param bool honorable = true : if victims are honorable + * @return uint32 kills + */ + int GetHonorStoredKills(lua_State* L, Player* player) + { + bool honorable = Eluna::CHECKVAL(L, 2, true); + + Eluna::Push(L, player->GetHonorStoredKills(honorable)); + return 1; + } + + /** + * Returns rank points + * + * @return float rankPoints + */ + int GetRankPoints(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetRankPoints()); + return 1; + } + + /** + * Returns last week's standing position + * + * @return int32 standingPos + */ + int GetHonorLastWeekStandingPos(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetHonorLastWeekStandingPos()); + return 1; + } +#endif + + /** + * Returns `true` if the [Player] is currently in water, `false` otherwise. + * + * @return bool isInWater + */ + int IsInWater(lua_State* L, Player* player) + { + Eluna::Push(L, player->IsInWater()); + return 1; + } + + /** + * Returns `true` if the [Player] is currently moving, `false` otherwise. + * + * @return bool isMoving + */ + int IsMoving(lua_State* L, Player* player) // enable for unit when mangos support it + { + Eluna::Push(L, player->isMoving()); + return 1; + } + +#ifdef CLASSIC + /** + * Updates the [Player]s weekly honor status + */ + int UpdateHonor(lua_State* L, Player* player) + { + player->UpdateHonor(); + return 0; + } + + /** + * Resets the [Player]s weekly honor status + */ + int ResetHonor(lua_State* L, Player* player) + { + player->ResetHonor(); + return 0; + } + + /** + * Clears all of [Player]s weekly honor status + */ + int ClearHonorInfo(lua_State* L, Player* player) + { + player->ClearHonorInfo(); + return 0; + } +#endif + +#ifndef CLASSIC + /** + * Returns `true` if the [Player] is currently flying, `false` otherwise. + * + * @return bool isFlying + */ + int IsFlying(lua_State* L, Player* player) // enable for unit when mangos support it + { + Eluna::Push(L, player->IsFlying()); + return 1; + } +#endif + + /** + * Returns `true` if the [Player] is in a [Group], `false` otherwise. + * + * @return bool isInGroup + */ + int IsInGroup(lua_State* L, Player* player) + { + Eluna::Push(L, (player->GetGroup() != NULL)); + return 1; + } + + /** + * Returns `true` if the [Player] is in a [Guild], `false` otherwise. + * + * @return bool isInGuild + */ + int IsInGuild(lua_State* L, Player* player) + { + Eluna::Push(L, (player->GetGuildId() != 0)); + return 1; + } + + /** + * Returns `true` if the [Player] is a Game Master, `false` otherwise. + * + * Note: This is only true when GM tag is activated! For alternative see [Player:GetGMRank] + * + * @return bool isGM + */ + int IsGM(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->IsGameMaster()); +#else + Eluna::Push(L, player->isGameMaster()); +#endif + return 1; + } + +#ifndef CLASSIC + /** + * Returns `true` if the [Player] is in an arena team specified by type, `false` otherwise. + * + * @param uint32 type + * @return bool isInArenaTeam + */ + int IsInArenaTeam(lua_State* L, Player* player) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type < MAX_ARENA_SLOT && player->GetArenaTeamId(type)) + Eluna::Push(L, true); + else + Eluna::Push(L, false); + return 1; + } +#endif + + /** + * Returns `true` if the [Player] is immune to everything. + * + * @return bool isImmune + */ + int IsImmuneToDamage(lua_State* L, Player* player) + { + Eluna::Push(L, player->isTotalImmune()); + return 1; + } + + /** + * Returns `true` if the [Player] satisfies all requirements to complete the quest entry. + * + * @param uint32 questId + * @return bool canCompleteRepeatableQuest + */ + int CanCompleteRepeatableQuest(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + const Quest* quest = sObjectMgr->GetQuestTemplate(questId); // Retrieve the Quest object + if (!quest) + { + Eluna::Push(L, false); + return 1; + } + + Eluna::Push(L, player->CanCompleteRepeatableQuest(quest)); + return 1; + } + + /** + * Returns `true` if the [Player] satisfies all requirements to reward the quest entry. + * + * @param uint32 questId + * @return bool canRewardQuest + */ + int CanRewardQuest(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + const Quest* quest = sObjectMgr->GetQuestTemplate(questId); // Retrieve the Quest object + if (!quest) + { + Eluna::Push(L, false); + return 1; + } + + Eluna::Push(L, player->CanRewardQuest(quest, true)); // Modify the second argument as needed + return 1; + } + + /** + * Returns `true` if the [Player] satisfies all requirements to complete the quest entry. + * + * @param uint32 entry + * @return bool canComplete + */ + int CanCompleteQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->CanCompleteQuest(entry)); + return 1; + } + + /** + * Returns `true` if the [Player] is a part of the Horde faction, `false` otherwise. + * + * @return bool isHorde + */ + int IsHorde(lua_State* L, Player* player) + { +#ifdef AZEROTHCORE + Eluna::Push(L, (player->GetTeamId() == TEAM_HORDE)); +#else + Eluna::Push(L, (player->GetTeam() == HORDE)); +#endif + return 1; + } + + /** + * Returns `true` if the [Player] is a part of the Alliance faction, `false` otherwise. + * + * @return bool isAlliance + */ + int IsAlliance(lua_State* L, Player* player) + { +#ifdef AZEROTHCORE + Eluna::Push(L, (player->GetTeamId() == TEAM_ALLIANCE)); +#else + Eluna::Push(L, (player->GetTeam() == ALLIANCE)); +#endif + return 1; + } + + /** + * Returns `true` if the [Player] is 'Do Not Disturb' flagged, `false` otherwise. + * + * @return bool isDND + */ + int IsDND(lua_State* L, Player* player) + { + Eluna::Push(L, player->isDND()); + return 1; + } + + /** + * Returns `true` if the [Player] is 'Away From Keyboard' flagged, `false` otherwise. + * + * @return bool isAFK + */ + int IsAFK(lua_State* L, Player* player) + { + Eluna::Push(L, player->isAFK()); + return 1; + } + + /** + * Returns `true` if the [Player] is currently falling, `false` otherwise. + * + * @return bool isFalling + */ + int IsFalling(lua_State* L, Player* player) + { + Eluna::Push(L, player->IsFalling()); + return 1; + } + + int IsGroupVisibleFor(lua_State* L, Player* player) + { + Player* target = Eluna::CHECKOBJ(L, 2); + Eluna::Push(L, player->IsGroupVisibleFor(target)); + return 1; + } + + /** + * Returns `true` if the [Player] is currently in the same raid as another [Player] by object, `false` otherwise. + * + * @param [Player] player + * @return bool isInSameRaidWith + */ + int IsInSameRaidWith(lua_State* L, Player* player) + { + Player* target = Eluna::CHECKOBJ(L, 2); + Eluna::Push(L, player->IsInSameRaidWith(target)); + return 1; + } + + /** + * Returns `true` if the [Player] is currently in the same [Group] as another [Player] by object, `false` otherwise. + * + * @param [Player] player + * @return bool isInSameGroupWith + */ + int IsInSameGroupWith(lua_State* L, Player* player) + { + Player* target = Eluna::CHECKOBJ(L, 2); + Eluna::Push(L, player->IsInSameGroupWith(target)); + return 1; + } + + /** + * Returns `true` if the [Player] is eligible for Honor or XP gain by [Unit] specified, `false` otherwise. + * + * @param [Unit] unit + * @return bool isHonorOrXPTarget + */ + int IsHonorOrXPTarget(lua_State* L, Player* player) + { + Unit* victim = Eluna::CHECKOBJ(L, 2); + + Eluna::Push(L, player->isHonorOrXPTarget(victim)); + return 1; + } + + /** + * Returns `true` if the [Player] can see anoter [Player] specified by object, `false` otherwise. + * + * @param [Player] player + * @return bool isVisibleForPlayer + */ + int IsVisibleForPlayer(lua_State* L, Player* player) + { + Player* target = Eluna::CHECKOBJ(L, 2); + + Eluna::Push(L, player->IsVisibleGloballyFor(target)); + return 1; + } + + int IsGMVisible(lua_State* L, Player* player) + { + Eluna::Push(L, player->isGMVisible()); + return 1; + } + + /** + * Returns `true` if the [Player] has taxi cheat activated, `false` otherwise. + * + * @return bool isTaxiCheater + */ + int IsTaxiCheater(lua_State* L, Player* player) + { +#ifdef MANGOS + Eluna::Push(L, player->IsTaxiCheater()); +#else + Eluna::Push(L, player->isTaxiCheater()); +#endif + return 1; + } + + int IsGMChat(lua_State* L, Player* player) + { + Eluna::Push(L, player->isGMChat()); + return 1; + } + + /** + * Returns `true` if the [Player] is accepting whispers, `false` otherwise. + * + * @return bool isAcceptingWhispers + */ + int IsAcceptingWhispers(lua_State* L, Player* player) + { + Eluna::Push(L, player->isAcceptWhispers()); + return 1; + } + + /** + * Returns `true` if the [Player] is currently rested, `false` otherwise. + * + * @return bool isRested + */ + int IsRested(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetRestBonus() > 0.0f); + return 1; + } + + /** + * Returns `true` if the [Player] is currently in a [BattleGround] queue, `false` otherwise. + * + * @return bool inBattlegroundQueue + */ + int InBattlegroundQueue(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->InBattlegroundQueue()); +#else + Eluna::Push(L, player->InBattleGroundQueue()); +#endif + return 1; + } + +#ifndef CLASSIC + /** + * Returns `true` if the [Player] is currently in an arena, `false` otherwise. + * + * @return bool inArena + */ + int InArena(lua_State* L, Player* player) + { + Eluna::Push(L, player->InArena()); + return 1; + } +#endif + + /** + * Returns `true` if the [Player] is currently in a [BattleGround], `false` otherwise. + * + * @return bool inBattleGround + */ + int InBattleground(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->InBattleground()); +#else + Eluna::Push(L, player->InBattleGround()); +#endif + return 1; + } + + /** + * Returns `true` if the [Player] can block incomming attacks, `false` otherwise. + * + * @return bool canBlock + */ + int CanBlock(lua_State* L, Player* player) + { + Eluna::Push(L, player->CanBlock()); + return 1; + } + + /** + * Returns `true` if the [Player] can parry incomming attacks, `false` otherwise. + * + * @return bool canParry + */ + int CanParry(lua_State* L, Player* player) + { + Eluna::Push(L, player->CanParry()); + return 1; + } + + /*int HasReceivedQuestReward(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->IsQuestRewarded(entry)); + return 1; + }*/ + + /*int IsOutdoorPvPActive(lua_State* L, Player* player) + { + Eluna::Push(L, player->IsOutdoorPvPActive()); + return 1; + }*/ + + /*int IsImmuneToEnvironmentalDamage(lua_State* L, Player* player) + { + Eluna::Push(L, player->IsImmuneToEnvironmentalDamage()); + return 1; + }*/ + + /*int InRandomLfgDungeon(lua_State* L, Player* player) + { + Eluna::Push(L, player->inRandomLfgDungeon()); + return 1; + }*/ + + /*int IsUsingLfg(lua_State* L, Player* player) + { + Eluna::Push(L, player->isUsingLfg()); + return 1; + }*/ + + /*int IsNeverVisible(lua_State* L, Player* player) + { + Eluna::Push(L, player->IsNeverVisible()); + return 1; + }*/ + + /*int CanFlyInZone(lua_State* L, Player* player) + { + uint32 mapid = Eluna::CHECKVAL(L, 2); + uint32 zone = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->IsKnowHowFlyIn(mapid, zone)); + return 1; + }*/ + + /*int HasPendingBind(lua_State* L, Player* player) + { + Eluna::Push(L, player->PendingHasPendingBind()); + return 1; + }*/ + + /*int IsARecruiter(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->IsARecruiter() || (player->GetSession()->GetRecruiterId() != 0)); + return 1; + }*/ + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Returns the amount of available specs the [Player] currently has + * + * @return uint8 specCount + */ + int GetSpecsCount(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSpecsCount()); + return 1; + } + + /** + * Returns the [Player]s active spec ID + * + * @return uint32 specId + */ + int GetActiveSpec(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetActiveSpec()); + return 1; + } +#endif + +#ifdef WOTLK + /** + * Returns the normal phase of the player instead of the actual phase possibly containing GM phase + * + * @return uint32 phasemask + */ + int GetPhaseMaskForSpawn(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetPhaseMaskForSpawn()); + return 1; + } +#endif + +#if defined(TBC) || defined (WOTLK) + /** + * Returns the [Player]s current amount of Arena Points + * + * @return uint32 arenaPoints + */ + int GetArenaPoints(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetArenaPoints()); + return 1; + } + + /** + * Returns the [Player]s current amount of Honor Points + * + * @return uint32 honorPoints + */ + int GetHonorPoints(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetHonorPoints()); + return 1; + } +#endif +#if defined(CLASSIC) || defined(TBC) || defined (WOTLK) + /** + * Returns the [Player]s current shield block value + * + * @return uint32 blockValue + */ + int GetShieldBlockValue(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetShieldBlockValue()); + return 1; + } +#endif + + /** + * Returns the [Player]s cooldown delay by specified [Spell] ID + * + * @param uint32 spellId + * @return uint32 spellCooldownDelay + */ + int GetSpellCooldownDelay(lua_State* L, Player* player) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + +#ifdef TRINITY + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + Eluna::Push(L, player->GetSpellHistory()->GetRemainingCooldown(spellInfo)); + else + Eluna::Push(L, 0); +#else + Eluna::Push(L, uint32(player->GetSpellCooldownDelay(spellId))); +#endif + return 1; + } + + /** + * Returns the [Player]s current latency in MS + * + * @return uint32 latency + */ + int GetLatency(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetLatency()); + return 1; + } + +#if defined TRINITY || AZEROTHCORE + /** + * Returns the faction ID the [Player] is currently flagged as champion for + * + * @return uint32 championingFaction + */ + int GetChampioningFaction(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetChampioningFaction()); + return 1; + } +#endif + + /** + * Returns [Player]s original sub group + * + * @return uint8 subGroup + */ + int GetOriginalSubGroup(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetOriginalSubGroup()); + return 1; + } + + /** + * Returns [Player]s original [Group] object + * + * @return [Group] group + */ + int GetOriginalGroup(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetOriginalGroup()); + return 1; + } + + /** + * Returns a random Raid Member [Player] object within radius specified of [Player] + * + * @param float radius + * @return [Player] player + */ + int GetNextRandomRaidMember(lua_State* L, Player* player) + { + float radius = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetNextRandomRaidMember(radius)); + return 1; + } + + /** + * Returns [Player]s current sub group + * + * @return uint8 subGroup + */ + int GetSubGroup(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSubGroup()); + return 1; + } + + /** + * Returns [Group] invitation + * + * @return [Group] group + */ + int GetGroupInvite(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetGroupInvite()); + return 1; + } + + /** + * Returns the [Player]'s experience points + * + * @return uint32 xp + */ + int GetXP(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetUInt32Value(PLAYER_XP)); + return 1; + } + + /** + * Returns rested experience bonus + * + * @param uint32 xp + * @return uint32 xpBonus + */ + int GetXPRestBonus(lua_State* L, Player* player) + { + uint32 xp = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetXPRestBonus(xp)); + return 1; + } + + /** + * Returns the [Player]s current [BattleGround] type ID + * + * @return [BattleGroundTypeId] typeId + */ + int GetBattlegroundTypeId(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->GetBattlegroundTypeId()); +#else + Eluna::Push(L, player->GetBattleGroundTypeId()); +#endif + return 1; + } + + /** + * Returns the [Player]s current [BattleGround] ID + * + * @return uint32 battleGroundId + */ + int GetBattlegroundId(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->GetBattlegroundId()); +#else + Eluna::Push(L, player->GetBattleGroundId()); +#endif + return 1; + } + + /** + * Returns the [Player]s reputation rank of faction specified + * + * @param uint32 faction + * @return [ReputationRank] rank + */ + int GetReputationRank(lua_State* L, Player* player) + { + uint32 faction = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetReputationRank(faction)); + return 1; + } + + /** + * Returns the [Player]s current level of intoxication + * + * @return uint16 drunkValue + */ + int GetDrunkValue(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetDrunkValue()); + return 1; + } + + /** + * Returns skill temporary bonus value + * + * @param uint32 skill + * @param int16 bonusVal + */ + int GetSkillTempBonusValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetSkillTempBonusValue(skill)); + return 1; + } + + /** + * Returns skill permanent bonus value + * + * @param uint32 skill + * @param int16 bonusVal + */ + int GetSkillPermBonusValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetSkillPermBonusValue(skill)); + return 1; + } + + /** + * Returns skill value without bonus' + * + * @param uint32 skill + * @return uint16 pureVal + */ + int GetPureSkillValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetPureSkillValue(skill)); + return 1; + } + + /** + * Returns base skill value + * + * @param uint32 skill + * @return uint16 baseVal + */ + int GetBaseSkillValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetBaseSkillValue(skill)); + return 1; + } + + /** + * Returns skill value + * + * @param uint32 skill + * @return uint16 val + */ + int GetSkillValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetSkillValue(skill)); + return 1; + } + + /** + * Returns max value of specified skill without bonus' + * + * @param uint32 skill + * @return uint16 pureVal + */ + int GetPureMaxSkillValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetPureMaxSkillValue(skill)); + return 1; + } + + /** + * Returns max value of specified skill + * + * @param uint32 skill + * @return uint16 val + */ + int GetMaxSkillValue(lua_State* L, Player* player) + { + uint32 skill = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetMaxSkillValue(skill)); + return 1; + } + + /** + * Returns mana bonus from amount of intellect + * + * @return float bonus + */ + int GetManaBonusFromIntellect(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetManaBonusFromIntellect()); + return 1; + } + + /** + * Returns health bonus from amount of stamina + * + * @return float bonus + */ + int GetHealthBonusFromStamina(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetHealthBonusFromStamina()); + return 1; + } + + /** + * Returns raid or dungeon difficulty + * + * @param bool isRaid = true : argument is TrinityCore only + * @return int32 difficulty + */ + int GetDifficulty(lua_State* L, Player* player) + { +#ifdef TBC + Eluna::Push(L, player->GetDifficulty()); +#elif defined(CLASSIC) + Eluna::Push(L, (Difficulty)0); +#else + bool isRaid = Eluna::CHECKVAL(L, 2, true); + Eluna::Push(L, player->GetDifficulty(isRaid)); +#endif + return 1; + } + + /** + * Returns the [Player]s current guild rank + * + * @return uint32 guildRank + */ + int GetGuildRank(lua_State* L, Player* player) // TODO: Move to Guild Methods + { + Eluna::Push(L, player->GetRank()); + return 1; + } + + /** + * Returns the [Player]s free talent point amount + * + * @return uint32 freeTalentPointAmt + */ + int GetFreeTalentPoints(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetFreeTalentPoints()); + return 1; + } + + /** + * Returns the name of the [Player]s current [Guild] + * + * @return string guildName + */ + int GetGuildName(lua_State* L, Player* player) + { + if (!player->GetGuildId()) + return 1; + Eluna::Push(L, eGuildMgr->GetGuildNameById(player->GetGuildId())); + return 1; + } + + /** + * Returns the amount of reputation the [Player] has with the faction specified + * + * @param uint32 faction + * @return int32 reputationAmt + */ + int GetReputation(lua_State* L, Player* player) + { + uint32 faction = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetReputationMgr().GetReputation(faction)); + return 1; + } + + /** + * Returns [Unit] target combo points are on + * + * @return [Unit] target + */ + int GetComboTarget(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->GetComboTarget()); +#else + Eluna::Push(L, player->GetMap()->GetUnit(player->GetComboTargetGuid())); +#endif + return 1; + } + + /** + * Returns [Player]'s combo points + * + * @return uint8 comboPoints + */ + int GetComboPoints(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetComboPoints()); + return 1; + } + + /** + * Returns the amount of time the [Player] has spent ingame + * + * @return uint32 inGameTime + */ + int GetInGameTime(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetInGameTime()); + return 1; + } + + /** + * Returns the status of the [Player]s [Quest] specified by entry ID + * + * @param uint32 questId + * @return [QuestStatus] questStatus + */ + int GetQuestStatus(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetQuestStatus(entry)); + return 1; + } + + /** + * Returns `true` if the [Player]s [Quest] specified by entry ID has been rewarded, `false` otherwise. + * + * @param uint32 questId + * @return bool questRewardStatus + */ + int GetQuestRewardStatus(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetQuestRewardStatus(questId)); + return 1; + } + + /** + * Returns [Quest] required [Creature] or [GameObject] count + * + * @param uint32 quest : entry of a quest + * @param int32 entry : entry of required [Creature] + * @return uint16 count + */ + int GetReqKillOrCastCurrentCount(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + int32 entry = Eluna::CHECKVAL(L, 3); + + Eluna::Push(L, player->GetReqKillOrCastCurrentCount(questId, entry)); + return 1; + } + + /** + * Returns the quest level of the [Player]s [Quest] specified by object + * + * @param uint32 questId + * @return [QuestStatus] questRewardStatus + */ + int GetQuestLevel(lua_State* L, Player* player) + { + Quest* quest = Eluna::CHECKOBJ(L, 2); + +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->GetQuestLevel(quest)); +#else + Eluna::Push(L, player->GetQuestLevelForPlayer(quest)); +#endif + return 1; + } + + /** + * Returns a [Player]s [Item] object by gear slot specified + * + * @param uint8 slot + * @return [Item] item + */ + int GetEquippedItemBySlot(lua_State* L, Player* player) + { + uint8 slot = Eluna::CHECKVAL(L, 2); + if (slot >= EQUIPMENT_SLOT_END) + return 1; + + Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + Eluna::Push(L, item); + return 1; + } + + /** + * Returns the [Player]s current resting bonus + * + * @return float restBonus + */ + int GetRestBonus(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetRestBonus()); + return 1; + } + + /** + * Returns active GM chat tag + * + * @return uint8 tag + */ + int GetChatTag(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetChatTag()); + return 1; + } + + /** + * Returns an item in given bag on given slot. + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return [Item] item : [Item] or nil + */ + int GetItemByPos(lua_State* L, Player* player) + { + uint8 bag = Eluna::CHECKVAL(L, 2); + uint8 slot = Eluna::CHECKVAL(L, 3); + + Eluna::Push(L, player->GetItemByPos(bag, slot)); + return 1; + } + + /** + * Returns an [Item] from the player by guid. + * + * The item can be equipped, in bags or in bank. + * + * @param ObjectGuid guid : an item guid + * @return [Item] item + */ + int GetItemByGUID(lua_State* L, Player* player) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetItemByGuid(guid)); + return 1; + } + + /** + * Returns the amount of mails in the player's mailbox. + * + * @return uint32 mailCount + */ + int GetMailCount(lua_State* L, Player* player) + { + const CharacterCacheEntry* cache = sCharacterCache->GetCharacterCacheByGuid(player->GetGUID()); + if (cache) + { + Eluna::Push(L, static_cast(cache->MailCount)); + } + else + { + Eluna::Push(L, player->GetMailSize()); + } + + return 1; + } + + /** + * Returns a mailed [Item] by guid. + * + * @param ObjectGuid guid : an item guid + * @return [Item] item + */ + int GetMailItem(lua_State* L, Player* player) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetMItem(guid.GetCounter())); + return 1; + } + + /** + * Returns an [Item] from the player by entry. + * + * The item can be equipped, in bags or in bank. + * + * @param uint32 entryId + * @return [Item] item + */ + int GetItemByEntry(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, player->GetItemByEntry(entry)); + return 1; + } + + /** + * Returns the database textID of the [WorldObject]'s gossip header text for the [Player] + * + * @param [WorldObject] object + * @return uint32 textId : key to npc_text database table + */ + int GetGossipTextId(lua_State* L, Player* player) + { + WorldObject* obj = Eluna::CHECKOBJ(L, 2); + Eluna::Push(L, player->GetGossipTextId(obj)); + return 1; + } + + /** + * Returns the [Player]s currently selected [Unit] object + * + * @return [Unit] unit + */ + int GetSelection(lua_State* L, Player* player) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, player->GetSelectedUnit()); +#else + Eluna::Push(L, player->GetMap()->GetUnit(player->GetSelectionGuid())); +#endif + return 1; + } + + /** + * Returns the [Player]s GM Rank + * + * @return [AccountTypes] gmRank + */ + int GetGMRank(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetSecurity()); + return 1; + } + + /** + * Returns the [Player]s amount of money in copper + * + * @return uint32 coinage + */ + int GetCoinage(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetMoney()); + return 1; + } + + /** + * Returns the [Player]s current [Guild] ID + * + * @return uint32 guildId + */ + int GetGuildId(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetGuildId()); + return 1; + } + + /** + * Returns the [Player]s [TeamId] + * + * @return [TeamId] teamId + */ + int GetTeam(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetTeamId()); + return 1; + } + + /** + * Returns amount of the specified [Item] the [Player] has. + * + * @param uint32 entry : entry of the item + * @param bool checkinBank = false : also counts the items in player's bank if true + * @return uint32 itemamount + */ + int GetItemCount(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + bool checkinBank = Eluna::CHECKVAL(L, 3, false); + Eluna::Push(L, player->GetItemCount(entry, checkinBank)); + return 1; + } + + /** + * Returns the [Player]s lifetime Honorable Kills + * + * @return uint32 lifeTimeKils + */ + int GetLifetimeKills(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); + return 1; + } + + /** + * Returns the [Player]s IP address + * + * @return string ip + */ + int GetPlayerIP(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetRemoteAddress()); + return 1; + } + + /** + * Returns the [Player]s time played at current level + * + * @return uint32 currLevelPlayTime + */ + int GetLevelPlayedTime(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetLevelPlayedTime()); + return 1; + } + + /** + * Returns the [Player]s total time played + * + * @return uint32 totalPlayTime + */ + int GetTotalPlayedTime(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetTotalPlayedTime()); + return 1; + } + + /** + * Returns the [Player]s [Guild] object + * + * @return [Guild] guild + */ + int GetGuild(lua_State* L, Player* player) + { + Eluna::Push(L, eGuildMgr->GetGuildById(player->GetGuildId())); + return 1; + } + + /** + * Returns the [Player]s [Group] object + * + * @return [Group] group + */ + int GetGroup(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetGroup()); + return 1; + } + + /** + * Returns the [Player]s account ID + * + * @return uint32 accountId + */ + int GetAccountId(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetAccountId()); + return 1; + } + + /** + * Returns the [Player]s account name + * + * @return string accountName + */ + int GetAccountName(lua_State* L, Player* player) + { + std::string accName; +#ifndef AZEROTHCORE + if (eAccountMgr->GetName(player->GetSession()->GetAccountId(), accName)) +#else + if (AccountMgr::GetName(player->GetSession()->GetAccountId(), accName)) +#endif + Eluna::Push(L, accName); + return 1; + } + + /** + * Returns the [Player]s [Corpse] object + * + * @return [Corpse] corpse + */ + int GetCorpse(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetCorpse()); + return 1; + } + + /** + * Returns the [Player]s database locale index + * + * @return int localeIndex + */ + int GetDbLocaleIndex(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetSessionDbLocaleIndex()); + return 1; + } + + /** + * Returns the [Player]s game client locale + * + * @return [LocaleConstant] locale + */ + int GetDbcLocale(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetSessionDbcLocale()); + return 1; + } + + /*int GetRecruiterId(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSession()->GetRecruiterId()); + return 1; + }*/ + + /*int GetSelectedPlayer(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSelectedPlayer()); + return 1; + }*/ + + /*int GetSelectedUnit(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetSelectedUnit()); + return 1; + }*/ + + /*int GetNearbyGameObject(lua_State* L, Player* player) + { + Eluna::Push(L, ChatHandler(player->GetSession()).GetNearbyGameObject()); + return 1; + }*/ + + /** + * Locks the player controls and disallows all movement and casting. + * + * @param bool apply = true : lock if true and unlock if false + */ + int SetPlayerLock(lua_State* L, Player* player) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + if (apply) + { + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED | UNIT_FLAG_SILENCED); + player->SetClientControl(player, 0); + } + else + { + player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED | UNIT_FLAG_SILENCED); + player->SetClientControl(player, 1); + } + return 0; + } + + /** + * Sets the [Player]s login flag to the flag specified + * + * @param uint32 flag + */ + int SetAtLoginFlag(lua_State* L, Player* player) + { + uint32 flag = Eluna::CHECKVAL(L, 2); + + player->SetAtLoginFlag((AtLoginFlags)flag); + return 0; + } + + /** + * Sets the [Player]s sheathe state to the state specified + * + * @param uint32 sheatheState + */ + int SetSheath(lua_State* L, Player* player) + { + uint32 sheathed = Eluna::CHECKVAL(L, 2); + if (sheathed >= MAX_SHEATH_STATE) + return 0; + + player->SetSheath((SheathState)sheathed); + return 0; + } + + /** + * Sets the [Player]s intoxication level to the level specified + * + * @param uint8 drunkValue + */ + int SetDrunkValue(lua_State* L, Player* player) + { + uint8 newDrunkValue = Eluna::CHECKVAL(L, 2); + + player->SetDrunkValue(newDrunkValue); + return 0; + } + + /** + * Sets the [Player]s faction standing to that of the race specified + * + * @param uint8 raceId + */ + int SetFactionForRace(lua_State* L, Player* player) + { + uint8 race = Eluna::CHECKVAL(L, 2); + +#if defined TRINITY || AZEROTHCORE + player->SetFactionForRace(race); +#else + player->setFactionForRace(race); +#endif + return 0; + } + + /** + * Sets (increases) skill of the [Player] + * + * @param uint16 id + * @param uint16 step + * @param uint16 currVal + * @param uint16 maxVal + */ + int SetSkill(lua_State* L, Player* player) + { + uint16 id = Eluna::CHECKVAL(L, 2); + uint16 step = Eluna::CHECKVAL(L, 3); + uint16 currVal = Eluna::CHECKVAL(L, 4); + uint16 maxVal = Eluna::CHECKVAL(L, 5); + +#ifdef TRINITY + player->SetSkill(id, step, currVal, maxVal); +#else + player->SetSkill(id, currVal, maxVal, step); +#endif + return 0; + } + + /** + * Sets the [Player]s guild rank to the rank specified + * + * @param uint8 rank + */ + int SetGuildRank(lua_State* L, Player* player) // TODO: Move to Guild Methods + { + uint8 rank = Eluna::CHECKVAL(L, 2); + + if (!player->GetGuildId()) + return 0; + + player->SetRank(rank); + return 0; + } + + /** + * Sets the [Player]s free talent points to the amount specified for the current spec + * + * @param uint32 talentPointAmt + */ + int SetFreeTalentPoints(lua_State* L, Player* player) + { + uint32 points = Eluna::CHECKVAL(L, 2); + + player->SetFreeTalentPoints(points); +#if (!defined(TBC) && !defined(CLASSIC)) + player->SendTalentsInfoData(false); +#endif + return 0; + } + + /** + * Sets the [Player]s reputation amount for the faction specified + * + * @param uint32 factionId + * @param int32 reputationValue + */ + int SetReputation(lua_State* L, Player* player) + { + uint32 faction = Eluna::CHECKVAL(L, 2); + int32 value = Eluna::CHECKVAL(L, 3); + + FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction); + player->GetReputationMgr().SetReputation(factionEntry, value); + return 0; + } + + /** + * Sets [Quest] state + * + * @param uint32 entry : entry of a quest + * @param uint32 status + */ + int SetQuestStatus(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + uint32 status = Eluna::CHECKVAL(L, 3); + if (status >= MAX_QUEST_STATUS) + return 0; + + player->SetQuestStatus(entry, (QuestStatus)status); + return 0; + } + + /** + * Sets the [Player]s rest bonus to the amount specified + * + * @param float restBonus + */ + int SetRestBonus(lua_State* L, Player* player) + { + float bonus = Eluna::CHECKVAL(L, 2); + + player->SetRestBonus(bonus); + return 0; + } + + /** + * Toggles whether the [Player] accepts whispers or not + * + * @param bool acceptWhispers = true + */ + int SetAcceptWhispers(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetAcceptWhispers(on); + return 0; + } + + /** + * Toggles PvP Death + * + * @param bool on = true + */ + int SetPvPDeath(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetPvPDeath(on); + return 0; + } + + /** + * Toggles whether the [Player] has GM visibility on or off + * + * @param bool gmVisible = true + */ + int SetGMVisible(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetGMVisible(on); + return 0; + } + + /** + * Toggles whether the [Player] has taxi cheat enabled or not + * + * @param bool taxiCheat = true + */ + int SetTaxiCheat(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetTaxiCheater(on); + return 0; + } + + /** + * Toggle Blizz (GM) tag + * + * @param bool on = true + */ + int SetGMChat(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetGMChat(on); + return 0; + } + + /** + * Toggles the [Player]s GM mode on or off + * + * @param bool setGmMode = true + */ + int SetGameMaster(lua_State* L, Player* player) + { + bool on = Eluna::CHECKVAL(L, 2, true); + + player->SetGameMaster(on); + return 0; + } + + /** + * Sets the [Player]s gender to gender specified + * + * - GENDER_MALE = 0 + * - GENDER_FEMALE = 1 + * + * @param [Gender] gender + */ + int SetGender(lua_State* L, Player* player) + { + uint32 _gender = Eluna::CHECKVAL(L, 2); + + Gender gender; + switch (_gender) + { + case 0: + gender = GENDER_MALE; + break; + case 1: + gender = GENDER_FEMALE; + break; + default: + return luaL_argerror(L, 2, "valid Gender expected"); + } + + player->SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); + player->SetByteValue(PLAYER_BYTES_3, 0, gender); + player->InitDisplayIds(); + return 0; + } + +#if defined(TBC) || defined(WOTLK) + /** + * Sets the [Player]s Arena Points to the amount specified + * + * @param uint32 arenaPoints + */ + int SetArenaPoints(lua_State* L, Player* player) + { + uint32 arenaP = Eluna::CHECKVAL(L, 2); + player->SetArenaPoints(arenaP); + return 0; + } + + /** + * Sets the [Player]s Honor Points to the amount specified + * + * @param uint32 honorPoints + */ + int SetHonorPoints(lua_State* L, Player* player) + { + uint32 honorP = Eluna::CHECKVAL(L, 2); + player->SetHonorPoints(honorP); + return 0; + } +#endif + +#ifdef CLASSIC + /** + * Sets kills + * + * @param uint32 kills + * @param bool honorable = true : if victims were honorable + */ + int SetHonorStoredKills(lua_State* L, Player* player) + { + uint32 kills = Eluna::CHECKVAL(L, 2); + bool honorable = Eluna::CHECKVAL(L, 3, true); + + player->SetHonorStoredKills(kills, honorable); + return 0; + } + + /** + * Sets rank points + * + * @param float rankPoints + */ + int SetRankPoints(lua_State* L, Player* player) + { + float rankPoints = Eluna::CHECKVAL(L, 2); + + player->SetRankPoints(rankPoints); + return 0; + } + + /** + * Sets last week's honor standing position + * + * @param int32 standingPos + */ + int SetHonorLastWeekStandingPos(lua_State* L, Player* player) + { + int32 standingPos = Eluna::CHECKVAL(L, 2); + + player->SetHonorLastWeekStandingPos(standingPos); + return 0; + } +#endif + + /** + * Sets the [Player]s amount of Lifetime Honorable Kills to the value specified + * + * @param uint32 honorableKills + */ + int SetLifetimeKills(lua_State* L, Player* player) + { + uint32 val = Eluna::CHECKVAL(L, 2); + player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, val); + return 0; + } + + /** + * Sets the [Player]s amount of money to copper specified + * + * @param uint32 copperAmt + */ + int SetCoinage(lua_State* L, Player* player) + { + uint32 amt = Eluna::CHECKVAL(L, 2); + player->SetMoney(amt); + return 0; + } + + /** + * Sets the [Player]s home location to the location specified + * + * @param float x : X Coordinate + * @param float y : Y Coordinate + * @param float z : Z Coordinate + * @param uint32 mapId : Map ID + * @param uint32 areaId : Area ID + */ + int SetBindPoint(lua_State* L, Player* player) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + uint32 mapId = Eluna::CHECKVAL(L, 5); + uint32 areaId = Eluna::CHECKVAL(L, 6); + + WorldLocation loc(mapId, x, y, z); +#if defined TRINITY || AZEROTHCORE + player->SetHomebind(loc, areaId); +#else + player->SetHomebindToLocation(loc, areaId); +#endif + return 0; + } + +#ifndef CLASSIC + /** + * Adds the specified title to the [Player]s list of known titles + * + * @param uint32 titleId + */ + int SetKnownTitle(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + CharTitlesEntry const* t = sCharTitlesStore.LookupEntry(id); + if (t) + player->SetTitle(t, false); + return 0; + } + + +#if defined(TRINITY) || defined(AZEROTHCORE) + /** + * Adds the specified achievement to the [Player]s + * + * @param uint32 achievementid + */ + int SetAchievement(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + AchievementEntry const* t = sAchievementStore.LookupEntry(id); + if (t) + player->CompletedAchievement(t); + return 0; + } +#endif + +#endif + +#if !defined TRINITY && !AZEROTHCORE + /** + * Toggle the [Player]s FFA flag + * + * @param bool applyFFA = true + */ + int SetFFA(lua_State* L, Player* player) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + player->SetFFAPvP(apply); + return 0; + } +#endif + + /*int SetMovement(lua_State* L, Player* player) + { + int32 pType = Eluna::CHECKVAL(L, 2); + + player->SetMovement((PlayerMovementType)pType); + return 0; + }*/ + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Resets the [Player]s pets talent points + */ + int ResetPetTalents(lua_State* /*L*/, Player* player) + { +#ifndef TRINITY + Pet* pet = player->GetPet(); + Pet::resetTalentsForAllPetsOf(player, pet); + if (pet) + player->SendTalentsInfoData(true); +#else + player->ResetPetTalents(); + player->SendTalentsInfoData(true); +#endif + return 0; + } + + /** + * Reset the [Player]s completed achievements + */ + int ResetAchievements(lua_State* /*L*/, Player* player) + { +#if defined TRINITY || AZEROTHCORE + player->ResetAchievements(); +#else + player->GetAchievementMgr().Reset(); +#endif + return 0; + } +#endif + + /** + * Shows the mailbox window to the player from specified guid. + * + * @param ObjectGuid guid = playerguid : guid of the mailbox window sender + */ + int SendShowMailBox(lua_State* L, Player* player) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2, player->GET_GUID()); + +#if (defined(CLASSIC) || defined(TBC)) + WorldPacket data(CMSG_GET_MAIL_LIST, 8); + data << guid; + player->GetSession()->HandleGetMailList(data); +#else + player->GetSession()->SendShowMailBox(guid); +#endif + return 0; + } + +#if defined(TBC) || defined(WOTLK) + /** + * Adds or detracts from the [Player]s current Arena Points + * + * @param int32 amount + */ + int ModifyArenaPoints(lua_State* L, Player* player) + { + int32 amount = Eluna::CHECKVAL(L, 2); + + player->ModifyArenaPoints(amount); + return 0; + } + + /** + * Adds or detracts from the [Player]s current Honor Points + * + * @param int32 amount + */ + int ModifyHonorPoints(lua_State* L, Player* player) + { + int32 amount = Eluna::CHECKVAL(L, 2); + + player->ModifyHonorPoints(amount); + return 0; + } +#endif + + /** + * Saves the [Player] to the database + */ + int SaveToDB(lua_State* /*L*/, Player* player) + { +#ifndef AZEROTHCORE + player->SaveToDB(); +#else + player->SaveToDB(false, false); +#endif + return 0; + } + + /** + * Sends a summon request to the player from the given summoner + * + * @param [Unit] summoner + */ + int SummonPlayer(lua_State* L, Player* player) + { + Unit* summoner = Eluna::CHECKOBJ(L, 2); + +#ifdef TRINITY + player->SendSummonRequestFrom(summoner); +#else + float x, y, z; + summoner->GetPosition(x,y,z); + player->SetSummonPoint(summoner->GetMapId(), x, y, z); + + WorldPacket data(SMSG_SUMMON_REQUEST, 8 + 4 + 4); + data << summoner->GET_GUID(); + data << uint32(summoner->GetZoneId()); + data << uint32(MAX_PLAYER_SUMMON_DELAY * IN_MILLISECONDS); +#ifdef CMANGOS + player->GetSession()->SendPacket(data); +#else + player->GetSession()->SendPacket(&data); +#endif +#endif + return 0; + } + + /** + * Mutes the [Player] for the amount of seconds specified + * + * @param uint32 muteTime + */ + int Mute(lua_State* L, Player* player) + { + uint32 muteseconds = Eluna::CHECKVAL(L, 2); + /*const char* reason = luaL_checkstring(E, 2);*/ // Mangos does not have a reason field in database. + + time_t muteTime = GameTime::GetGameTime().count() + muteseconds; + player->GetSession()->m_muteTime = muteTime; + LoginDatabase.Execute("UPDATE account SET mutetime = {} WHERE id = {}", muteTime, player->GetSession()->GetAccountId()); + return 0; + } + + /** + * Rewards the given quest entry for the [Player] if he has completed it. + * + * @param uint32 entry : quest entry + */ + int RewardQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Quest const* quest = eObjectMgr->GetQuestTemplate(entry); + + // If player doesn't have the quest + if (!quest || player->GetQuestStatus(entry) != QUEST_STATUS_COMPLETE) + return 0; + + player->RewardQuest(quest, 0, player); + return 0; + } + + /** + * Sends an auction house window to the [Player] from the [Unit] specified + * + * @param [Unit] sender + */ + int SendAuctionMenu(lua_State* L, Player* player) + { + Unit* unit = Eluna::CHECKOBJ(L, 2); + +#if defined TRINITY || AZEROTHCORE + AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->GetFaction()); +#else + AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit); +#endif + if (!ahEntry) + return 0; + + WorldPacket data(MSG_AUCTION_HELLO, 12); + data << unit->GET_GUID(); +#ifdef TRINITY + data << uint32(ahEntry->ID); +#else + data << uint32(ahEntry->houseId); +#endif + data << uint8(1); +#ifdef CMANGOS + player->GetSession()->SendPacket(data); +#else + player->GetSession()->SendPacket(&data); +#endif + return 0; + } + + /** + * Sends a flightmaster window to the [Player] from the [Creature] specified + * + * @param [Creature] sender + */ + int SendTaxiMenu(lua_State* L, Player* player) + { + Creature* creature = Eluna::CHECKOBJ(L, 2); + + player->GetSession()->SendTaxiMenu(creature); + return 0; + } + + /** + * Sends a spirit resurrection request to the [Player] + */ + int SendSpiritResurrect(lua_State* /*L*/, Player* player) + { + player->GetSession()->SendSpiritResurrect(); + return 0; + } + + /** + * Sends a tabard vendor window to the [Player] from the [WorldObject] specified + * + * @param [WorldObject] sender + */ + int SendTabardVendorActivate(lua_State* L, Player* player) + { + WorldObject* obj = Eluna::CHECKOBJ(L, 2); + + player->GetSession()->SendTabardVendorActivate(obj->GET_GUID()); + return 0; + } + + /** + * Sends a bank window to the [Player] from the [WorldObject] specified. + * + * @param [WorldObject] sender + */ + int SendShowBank(lua_State* L, Player* player) + { + WorldObject* obj = Eluna::CHECKOBJ(L, 2); + + player->GetSession()->SendShowBank(obj->GET_GUID()); + return 0; + } + + /** + * Sends a vendor window to the [Player] from the [WorldObject] specified. + * + * @param [WorldObject] sender + */ + int SendListInventory(lua_State* L, Player* player) + { + WorldObject* obj = Eluna::CHECKOBJ(L, 2); + uint32 vendorId = Eluna::CHECKVAL(L, 3, 0); + + player->GetSession()->SendListInventory(obj->GET_GUID(), vendorId); + return 0; + } + + /** + * Sends a trainer window to the [Player] from the [Creature] specified + * + * @param [Creature] sender + */ + int SendTrainerList(lua_State* L, Player* player) + { + Creature* obj = Eluna::CHECKOBJ(L, 2); + +#ifdef TRINITY + player->GetSession()->SendTrainerList(obj); +#else + player->GetSession()->SendTrainerList(obj->GET_GUID()); +#endif + return 0; + } + + /** + * Sends a guild invitation from the [Player]s [Guild] to the [Player] object specified + * + * @param [Player] invitee + */ + int SendGuildInvite(lua_State* L, Player* player) + { + Player* plr = Eluna::CHECKOBJ(L, 2); + +#if defined TRINITY || AZEROTHCORE + if (Guild* guild = player->GetGuild()) + guild->HandleInviteMember(player->GetSession(), plr->GetName()); +#else + player->GetSession()->SendGuildInvite(plr); +#endif + return 0; + } + + /** + * Sends an update for the world state to the [Player] + * + * @param uint32 field + * @param uint32 value + */ + int SendUpdateWorldState(lua_State* L, Player* player) + { + uint32 field = Eluna::CHECKVAL(L, 2); + uint32 value = Eluna::CHECKVAL(L, 3); + + player->SendUpdateWorldState(field, value); + return 0; + } + + /** + * Forces the [Player] to log out + * + * @param bool saveToDb = true + */ + int LogoutPlayer(lua_State* L, Player* player) + { + bool save = Eluna::CHECKVAL(L, 2, true); + + player->GetSession()->LogoutPlayer(save); + return 0; + } + + /** + * Forcefully removes the [Player] from a [BattleGround] raid group + */ + int RemoveFromBattlegroundRaid(lua_State* /*L*/, Player* player) + { +#if defined TRINITY || AZEROTHCORE + player->RemoveFromBattlegroundOrBattlefieldRaid(); +#else + player->RemoveFromBattleGroundRaid(); +#endif + return 0; + } + + /** + * Unbinds the [Player] from his instances except the one he currently is in. + * + * Difficulty is not used on classic. + * + * @param uint32 map = true + * @param uint32 difficulty = 0 + */ + int UnbindInstance(lua_State* L, Player* player) + { + uint32 map = Eluna::CHECKVAL(L, 2); +#ifndef CLASSIC + uint32 difficulty = Eluna::CHECKVAL(L, 3, 0); + + if (difficulty < MAX_DIFFICULTY) +#ifndef AZEROTHCORE + player->UnbindInstance(map, (Difficulty)difficulty); +#else + sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), map, Difficulty(difficulty), true, player); +#endif//AZEROTHCORE +#else//CLASSIC + player->UnbindInstance(map); +#endif + return 0; + } + + /** + * Unbinds the [Player] from his instances except the one he currently is in. + */ + int UnbindAllInstances(lua_State* /*L*/, Player* player) + { +#ifdef CLASSIC + Player::BoundInstancesMap& binds = player->GetBoundInstances(); + for (Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) + { + if (itr->first != player->GetMapId()) + player->UnbindInstance(itr); + else + ++itr; + } +#elif defined AZEROTHCORE + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + const BoundInstancesMap& binds = sInstanceSaveMgr->PlayerGetBoundInstances(player->GetGUID(), Difficulty(i)); + for (BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end();) + { + if (itr->first != player->GetMapId()) + { + sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), itr->first, Difficulty(i), true, player); + itr = binds.begin(); + } + else + { + ++itr; + } + } + } +#else + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + Player::BoundInstancesMap& binds = player->GetBoundInstances(Difficulty(i)); + for (Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) + { + if (itr->first != player->GetMapId()) + player->UnbindInstance(itr, Difficulty(i)); + else + ++itr; + } + } +#endif + return 0; + } + + /** + * Forces the [Player] to leave a [BattleGround] + * + * @param bool teleToEntry = true + */ + int LeaveBattleground(lua_State* L, Player* player) + { + (void)L; // ensure that the variable is referenced in order to pass compiler checks +#ifndef AZEROTHCORE + bool teleToEntryPoint = Eluna::CHECKVAL(L, 2, true); + player->LeaveBattleground(teleToEntryPoint); +#else + player->LeaveBattleground(); +#endif + return 0; + } + + /** + * Repairs [Item] at specified position. + * + * @param uint16 position + * @param bool cost = true + * @param float discountMod = 1.0 + */ + int DurabilityRepair(lua_State* L, Player* player) + { + uint16 position = Eluna::CHECKVAL(L, 2); + bool takeCost = Eluna::CHECKVAL(L, 3, true); + float discountMod = Eluna::CHECKVAL(L, 4, 1.0f); + +#ifdef CLASSIC + player->DurabilityRepair(position, takeCost, discountMod); +#elif defined(TRINITY) + player->DurabilityRepair(position, takeCost, discountMod); +#else + player->DurabilityRepair(position, takeCost, discountMod, false); +#endif + return 0; + } + + /** + * Repairs all [Item]s. + * + * @param bool takeCost = true + * @param float discountMod = 1.0 + * @param bool guidBank = false + */ + int DurabilityRepairAll(lua_State* L, Player* player) + { + bool takeCost = Eluna::CHECKVAL(L, 2, true); + float discountMod = Eluna::CHECKVAL(L, 3, 1.0f); + bool guildBank = Eluna::CHECKVAL(L, 4, false); + +#ifdef CLASSIC + player->DurabilityRepairAll(takeCost, discountMod); +#else + player->DurabilityRepairAll(takeCost, discountMod, guildBank); +#endif + return 0; + } + + /** + * Sets durability loss for an [Item] in the specified slot + * + * @param int32 slot + */ + int DurabilityPointLossForEquipSlot(lua_State* L, Player* player) + { + int32 slot = Eluna::CHECKVAL(L, 2); + + if (slot >= EQUIPMENT_SLOT_START && slot < EQUIPMENT_SLOT_END) + player->DurabilityPointLossForEquipSlot((EquipmentSlots)slot); + return 0; + } + + /** + * Sets durability loss on all [Item]s equipped + * + * If inventory is true, sets durability loss for [Item]s in bags + * + * @param int32 points + * @param bool inventory = true + */ + int DurabilityPointsLossAll(lua_State* L, Player* player) + { + int32 points = Eluna::CHECKVAL(L, 2); + bool inventory = Eluna::CHECKVAL(L, 3, true); + + player->DurabilityPointsLossAll(points, inventory); + return 0; + } + + /** + * Sets durability loss for the specified [Item] + * + * @param [Item] item + * @param int32 points + */ + int DurabilityPointsLoss(lua_State* L, Player* player) + { + Item* item = Eluna::CHECKOBJ(L, 2); + int32 points = Eluna::CHECKVAL(L, 3); + + player->DurabilityPointsLoss(item, points); + return 0; + } + + /** + * Damages specified [Item] + * + * @param [Item] item + * @param double percent + */ + int DurabilityLoss(lua_State* L, Player* player) + { + Item* item = Eluna::CHECKOBJ(L, 2); + double percent = Eluna::CHECKVAL(L, 3); + + player->DurabilityLoss(item, percent); + return 0; + } + + /** + * Damages all [Item]s equipped. If inventory is true, damages [Item]s in bags + * + * @param double percent + * @param bool inventory = true + */ + int DurabilityLossAll(lua_State* L, Player* player) + { + double percent = Eluna::CHECKVAL(L, 2); + bool inventory = Eluna::CHECKVAL(L, 3, true); + + player->DurabilityLossAll(percent, inventory); + return 0; + } + + /** + * Kills the [Player] + */ + int KillPlayer(lua_State* /*L*/, Player* player) + { + player->KillPlayer(); + return 0; + } + + /** + * Forces the [Player] to leave a [Group] + */ + int RemoveFromGroup(lua_State* /*L*/, Player* player) + { + if (!player->GetGroup()) + return 0; + + player->RemoveFromGroup(); + return 0; + } + + /** + * Returns the [Player]s accumulated talent reset cost + * + * @return uint32 resetCost + */ + int ResetTalentsCost(lua_State* L, Player* player) + { +#ifdef CATA + Eluna::Push(L, player->GetNextResetTalentsCost()); +#else +#ifdef TRINITY + Eluna::Push(L, player->ResetTalentsCost()); +#else + Eluna::Push(L, player->resetTalentsCost()); +#endif +#endif + return 1; + } + + /** + * Resets the [Player]s talents + * + * @param bool noCost = true + */ + int ResetTalents(lua_State* L, Player* player) + { + bool no_cost = Eluna::CHECKVAL(L, 2, true); + +#ifdef CATA + player->ResetTalents(no_cost); +#else +#ifdef TRINITY + player->ResetTalents(no_cost); +#else + player->resetTalents(no_cost); +#endif +#endif +#if (!defined(TBC) && !defined(CLASSIC)) + player->SendTalentsInfoData(false); +#endif + return 0; + } + + /** + * Removes the [Spell] from the [Player] + * + * @param uint32 entry : entry of a [Spell] + */ + int RemoveSpell(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + +#ifdef TRINITY + player->RemoveSpell(entry); +#elif defined (AZEROTHCORE) + player->removeSpell(entry, SPEC_MASK_ALL, false); +#else + player->removeSpell(entry); +#endif + return 0; + } + + /** + * Clears the [Player]s combo points + */ + int ClearComboPoints(lua_State* /*L*/, Player* player) + { + player->ClearComboPoints(); + return 0; + } + + /** + * Adds combo points to the [Player] + * + * @param [Unit] target + * @param int8 count + */ + int AddComboPoints(lua_State* L, Player* player) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + int8 count = Eluna::CHECKVAL(L, 3); + + player->AddComboPoints(target, count); + return 0; + } + + /** + * Gives [Quest] monster talked to credit + * + * @param uint32 entry : entry of a [Creature] + * @param [Creature] creature + */ + int TalkedToCreature(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + Creature* creature = Eluna::CHECKOBJ(L, 3); + + player->TalkedToCreature(entry, creature->GET_GUID()); + return 0; + } + + /** + * Gives [Quest] monster killed credit + * + * @param uint32 entry : entry of a [Creature] + */ + int KilledMonsterCredit(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + player->KilledMonsterCredit(entry, player->GET_GUID()); + return 0; + } + + /** + * Completes a [Quest] if in a [Group] + * + * @param uint32 quest : entry of a quest + * @param [WorldObject] obj + */ + int GroupEventHappens(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + WorldObject* obj = Eluna::CHECKOBJ(L, 3); + + player->GroupEventHappens(questId, obj); + return 0; + } + + /** + * Completes the [Quest] if a [Quest] area is explored, or completes the [Quest] + * + * @param uint32 quest : entry of a [Quest] + */ + int AreaExploredOrEventHappens(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + + player->AreaExploredOrEventHappens(questId); + return 0; + } + + /** + * Sets the given [Quest] entry failed for the [Player]. + * + * @param uint32 entry : entry of a [Quest] + */ + int FailQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + player->FailQuest(entry); + return 0; + } + + /** + * Sets the given quest entry incomplete for the [Player]. + * + * @param uint32 entry : quest entry + */ + int IncompleteQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + player->IncompleteQuest(entry); + return 0; + } + + /** + * Completes the given quest entry for the [Player] and tries to satisfy all quest requirements. + * + * The player should have the quest to complete it. + * + * @param uint32 entry : quest entry + */ + int CompleteQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Quest const* quest = eObjectMgr->GetQuestTemplate(entry); + + // If player doesn't have the quest + if (!quest || player->GetQuestStatus(entry) == QUEST_STATUS_NONE) + return 0; + + // Add quest items for quests that require items + for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x) + { +#if defined TRINITY || AZEROTHCORE + uint32 id = quest->RequiredItemId[x]; + uint32 count = quest->RequiredItemCount[x]; +#else + uint32 id = quest->ReqItemId[x]; + uint32 count = quest->ReqItemCount[x]; +#endif + + if (!id || !count) + continue; + + uint32 curItemCount = player->GetItemCount(id, true); + + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count - curItemCount); + if (msg == EQUIP_ERR_OK) + { + Item* item = player->StoreNewItem(dest, id, true); + player->SendNewItem(item, count - curItemCount, true, false); + } + } + + // All creature/GO slain/cast (not required, but otherwise it will display "Creature slain 0/10") + for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + { +#if defined TRINITY || AZEROTHCORE + int32 creature = quest->RequiredNpcOrGo[i]; + uint32 creatureCount = quest->RequiredNpcOrGoCount[i]; + + if (creature > 0) + { + if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature)) + for (uint16 z = 0; z < creatureCount; ++z) + player->KilledMonster(creatureInfo, ObjectGuid::Empty); + } + else if (creature < 0) + for (uint16 z = 0; z < creatureCount; ++z) + player->KillCreditGO(creature); +#else + int32 creature = quest->ReqCreatureOrGOId[i]; + uint32 creaturecount = quest->ReqCreatureOrGOCount[i]; + + if (uint32 spell_id = quest->ReqSpell[i]) + { + for (uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(creature, ObjectGuid(), spell_id); + } + else if (creature > 0) + { + if (CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(creature)) + for (uint16 z = 0; z < creaturecount; ++z) + player->KilledMonster(cInfo, ObjectGuid()); + } + else if (creature < 0) + { + for (uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(-creature, ObjectGuid(), 0); + } +#endif + } + + + // If the quest requires reputation to complete + if (uint32 repFaction = quest->GetRepObjectiveFaction()) + { + uint32 repValue = quest->GetRepObjectiveValue(); + uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); + if (curRep < repValue) + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction)) + player->GetReputationMgr().SetReputation(factionEntry, repValue); + } + +#if defined TRINITY || AZEROTHCORE + // If the quest requires a SECOND reputation to complete + if (uint32 repFaction = quest->GetRepObjectiveFaction2()) + { + uint32 repValue2 = quest->GetRepObjectiveValue2(); + uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); + if (curRep < repValue2) + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction)) + player->GetReputationMgr().SetReputation(factionEntry, repValue2); + } +#endif + + // If the quest requires money + int32 ReqOrRewMoney = quest->GetRewOrReqMoney(); + if (ReqOrRewMoney < 0) + player->ModifyMoney(-ReqOrRewMoney); + +#ifdef TRINITY + if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled + { + // prepare Quest Tracker datas + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE); + stmt->setUInt32(0, quest->GetQuestId()); + stmt->setUInt32(1, player->GetGUID().GetCounter()); + + // add to Quest Tracker + CharacterDatabase.Execute(stmt); + } +#endif + + player->CompleteQuest(entry); + return 0; + } + + /** + * Tries to add the given quest entry for the [Player]. + * + * @param uint32 entry : quest entry + */ + int AddQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Quest const* quest = eObjectMgr->GetQuestTemplate(entry); + + if (!quest) + return 0; + +#if defined TRINITY || AZEROTHCORE + // check item starting quest (it can work incorrectly if added without item in inventory) +#ifndef AZEROTHCORE + ItemTemplateContainer const& itc = sObjectMgr->GetItemTemplateStore(); + auto itr = std::find_if(std::begin(itc), std::end(itc), [quest](ItemTemplateContainer::value_type const& value) + { + return value.second.StartQuest == quest->GetQuestId(); + }); + + if (itr != std::end(itc)) + return 0; +#else + ItemTemplateContainer const* itc = sObjectMgr->GetItemTemplateStore(); + ItemTemplateContainer::const_iterator result = find_if(itc->begin(), itc->end(), Finder(entry, &ItemTemplate::StartQuest)); + + if (result != itc->end()) + return 0; +#endif + // ok, normal (creature/GO starting) quest + if (player->CanAddQuest(quest, true)) + player->AddQuestAndCheckCompletion(quest, NULL); +#else + // check item starting quest (it can work incorrectly if added without item in inventory) + for (uint32 id = 0; id < sItemStorage.GetMaxEntry(); ++id) + { + ItemPrototype const* pProto = sItemStorage.LookupEntry(id); + if (!pProto) + continue; + + if (pProto->StartQuest == entry) + return 0; + } + + // ok, normal (creature/GO starting) quest + if (player->CanAddQuest(quest, true)) + { + player->AddQuest(quest, NULL); + + if (player->CanCompleteQuest(entry)) + player->CompleteQuest(entry); + } +#endif + + return 0; + } + + /** + * Removes the given quest entry from the [Player]. + * + * @param uint32 entry : quest entry + */ + int RemoveQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + Quest const* quest = eObjectMgr->GetQuestTemplate(entry); + + if (!quest) + return 0; + + // remove all quest entries for 'entry' from quest log + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 logQuest = player->GetQuestSlotQuestId(slot); + if (logQuest == entry) + { + player->SetQuestSlot(slot, 0); + + // we ignore unequippable quest items in this case, its' still be equipped + player->TakeQuestSourceItem(logQuest, false); + +#if defined TRINITY || AZEROTHCORE + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest(); + player->UpdatePvPState(); + } +#endif + } + } + +#if defined TRINITY || AZEROTHCORE + player->RemoveActiveQuest(entry, false); + player->RemoveRewardedQuest(entry); +#else + // set quest status to not started (will updated in DB at next save) + player->SetQuestStatus(entry, QUEST_STATUS_NONE); + + // reset rewarded for restart repeatable quest + player->getQuestStatusMap()[entry].m_rewarded = false; +#endif + return 0; + } + + /** + * Sends whisper text from the [Player] + * + * @param string text + * @param uint32 lang : language the [Player] will speak + * @param [Player] receiver : is the [Player] that will receive the whisper, if TrinityCore + * @param ObjectGuid guid : is the GUID of a [Player] that will receive the whisper, not TrinityCore + */ + int Whisper(lua_State* L, Player* player) + { + std::string text = Eluna::CHECKVAL(L, 2); + uint32 lang = Eluna::CHECKVAL(L, 3); +#if defined(TRINITY) || defined(AZEROTHCORE) + Player* receiver = Eluna::CHECKOBJ(L, 4); + player->Whisper(text, (Language)lang, receiver); +#else + ObjectGuid guid = Eluna::CHECKVAL(L, 4); + player->Whisper(text, lang, guid); +#endif + return 0; + } + + /** + * Sends a text emote from the [Player] + * + * @param string emoteText + */ + int TextEmote(lua_State* L, Player* player) + { + std::string text = Eluna::CHECKVAL(L, 2); + + player->TextEmote(text); + return 0; + } + + /** + * Sends yell text from the [Player] + * + * @param string text : text for the [Player] to yells + * @param uint32 lang : language the [Player] will speak + */ + int Yell(lua_State* L, Player* player) + { + std::string text = Eluna::CHECKVAL(L, 2); + uint32 lang = Eluna::CHECKVAL(L, 3); +#if defined(TRINITY) || defined(AZEROTHCORE) + player->Yell(text, (Language)lang); +#else + player->Yell(text, lang); +#endif + return 0; + } + + /** + * Sends say text from the [Player] + * + * @param string text : text for the [Player] to say + * @param uint32 lang : language the [Player] will speak + */ + int Say(lua_State* L, Player* player) + { + std::string text = Eluna::CHECKVAL(L, 2); + uint32 lang = Eluna::CHECKVAL(L, 3); +#if defined(TRINITY) || defined(AZEROTHCORE) + player->Say(text, (Language)lang); +#else + player->Say(text, lang); +#endif + return 0; + } + + /** + * Gives the [Player] experience + * + * @param uint32 xp : experience to give + * @param [Unit] victim = nil + */ + int GiveXP(lua_State* L, Player* player) + { + uint32 xp = Eluna::CHECKVAL(L, 2); + Unit* victim = Eluna::CHECKOBJ(L, 3, false); + + player->GiveXP(xp, victim); + return 0; + } + + /** + * Toggle the [Player]s 'Do Not Disturb' flag + */ + int ToggleDND(lua_State* /*L*/, Player* player) + { + player->ToggleDND(); + return 0; + } + + /** + * Toggle the [Player]s 'Away From Keyboard' flag + */ + int ToggleAFK(lua_State* /*L*/, Player* player) + { + player->ToggleAFK(); + return 0; + } + + /** + * Equips the given item or item entry to the given slot. Returns the equipped item or nil. + * + * enum EquipmentSlots // 19 slots + * { + * EQUIPMENT_SLOT_START = 0, + * EQUIPMENT_SLOT_HEAD = 0, + * EQUIPMENT_SLOT_NECK = 1, + * EQUIPMENT_SLOT_SHOULDERS = 2, + * EQUIPMENT_SLOT_BODY = 3, + * EQUIPMENT_SLOT_CHEST = 4, + * EQUIPMENT_SLOT_WAIST = 5, + * EQUIPMENT_SLOT_LEGS = 6, + * EQUIPMENT_SLOT_FEET = 7, + * EQUIPMENT_SLOT_WRISTS = 8, + * EQUIPMENT_SLOT_HANDS = 9, + * EQUIPMENT_SLOT_FINGER1 = 10, + * EQUIPMENT_SLOT_FINGER2 = 11, + * EQUIPMENT_SLOT_TRINKET1 = 12, + * EQUIPMENT_SLOT_TRINKET2 = 13, + * EQUIPMENT_SLOT_BACK = 14, + * EQUIPMENT_SLOT_MAINHAND = 15, + * EQUIPMENT_SLOT_OFFHAND = 16, + * EQUIPMENT_SLOT_RANGED = 17, + * EQUIPMENT_SLOT_TABARD = 18, + * EQUIPMENT_SLOT_END = 19 + * }; + * + * enum InventorySlots // 4 slots + * { + * INVENTORY_SLOT_BAG_START = 19, + * INVENTORY_SLOT_BAG_END = 23 + * }; + * + * @proto equippedItem = (item, slot) + * @proto equippedItem = (entry, slot) + * @param [Item] item : item to equip + * @param uint32 entry : entry of the item to equip + * @param uint32 slot : equipment slot to equip the item to The slot can be [EquipmentSlots] or [InventorySlots] + * @return [Item] equippedItem : item or nil if equipping failed + */ + int EquipItem(lua_State* L, Player* player) + { + uint16 dest = 0; + Item* item = Eluna::CHECKOBJ(L, 2, false); + uint32 slot = Eluna::CHECKVAL(L, 3); + + if (slot >= INVENTORY_SLOT_BAG_END) + return 1; + + if (!item) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + item = Item::CreateItem(entry, 1, player); + if (!item) + return 1; + + InventoryResult result = player->CanEquipItem(slot, dest, item, false); + if (result != EQUIP_ERR_OK) + { + delete item; + return 1; + } + player->ItemAddedQuestCheck(entry, 1); +#if (!defined(TBC) && !defined(CLASSIC)) + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, entry, 1); +#endif + } + else + { + InventoryResult result = player->CanEquipItem(slot, dest, item, false); + if (result != EQUIP_ERR_OK) + return 1; + player->RemoveItem(item->GetBagSlot(), item->GetSlot(), true); + } + + Eluna::Push(L, player->EquipItem(dest, item, true)); + player->AutoUnequipOffhandIfNeed(); + return 1; + } + + /** + * Returns true if the player can equip the given [Item] or item entry to the given slot, false otherwise. + * + * @proto canEquip = (item, slot) + * @proto canEquip = (entry, slot) + * @param [Item] item : item to equip + * @param uint32 entry : entry of the item to equip + * @param uint32 slot : equipment slot to test + * @return bool canEquip + */ + int CanEquipItem(lua_State* L, Player* player) + { + Item* item = Eluna::CHECKOBJ(L, 2, false); + uint32 slot = Eluna::CHECKVAL(L, 3); + if (slot >= EQUIPMENT_SLOT_END) + { + Eluna::Push(L, false); + return 1; + } + + if (!item) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + uint16 dest; + InventoryResult msg = player->CanEquipNewItem(slot, dest, entry, false); + if (msg != EQUIP_ERR_OK) + { + Eluna::Push(L, false); + return 1; + } + } + else + { + uint16 dest; + InventoryResult msg = player->CanEquipItem(slot, dest, item, false); + if (msg != EQUIP_ERR_OK) + { + Eluna::Push(L, false); + return 1; + } + } + Eluna::Push(L, true); + return 1; + } + +#ifndef CLASSIC + /** + * Removes a title by ID from the [Player]s list of known titles + * + * @param uint32 titleId + */ + int UnsetKnownTitle(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + CharTitlesEntry const* t = sCharTitlesStore.LookupEntry(id); + if (t) + player->SetTitle(t, true); + return 0; + } +#endif + + /** + * Advances all of the [Player]s weapon skills to the maximum amount available + */ + int AdvanceSkillsToMax(lua_State* /*L*/, Player* player) + { +#ifdef TRINITY + player->UpdateWeaponsSkillsToMaxSkillsForLevel(); +#else + player->UpdateSkillsToMaxSkillsForLevel(); +#endif + return 0; + } + + /** + * Advances all of the [Player]s skills to the amount specified + * + * @param uint32 skillStep + */ + int AdvanceAllSkills(lua_State* L, Player* player) + { + uint32 step = Eluna::CHECKVAL(L, 2); + + if (!step) + return 0; + + for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) + { + if (SkillLineEntry const* entry = sSkillLineStore.LookupEntry(i)) + { +#ifdef TRINITY + if (entry->CategoryID == SKILL_CATEGORY_LANGUAGES || entry->CategoryID == SKILL_CATEGORY_GENERIC) + continue; + + if (player->HasSkill(entry->ID)) + player->UpdateSkill(entry->ID, step); +#else + if (entry->categoryId == SKILL_CATEGORY_LANGUAGES || entry->categoryId == SKILL_CATEGORY_GENERIC) + continue; + + if (player->HasSkill(entry->id)) + player->UpdateSkill(entry->id, step); +#endif + } + } + + return 0; + } + + /** + * Advances a [Player]s specific skill to the amount specified + * + * @param uint32 skillId + * @param uint32 skillStep + */ + int AdvanceSkill(lua_State* L, Player* player) + { + uint32 _skillId = Eluna::CHECKVAL(L, 2); + uint32 _step = Eluna::CHECKVAL(L, 3); + if (_skillId && _step) + { + if (player->HasSkill(_skillId)) + player->UpdateSkill(_skillId, _step); + } + return 0; + } + + /** + * Teleports a [Player] to the location specified + * + * @param uint32 mappId + * @param float xCoord + * @param float yCoord + * @param float zCoord + * @param float orientation + */ + int Teleport(lua_State* L, Player* player) + { + uint32 mapId = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + float o = Eluna::CHECKVAL(L, 6); +#if defined AZEROTHCORE + if (player->IsInFlight()) + { + player->GetMotionMaster()->MovementExpired(); + player->m_taxi.ClearTaxiDestinations(); + } +#elif defined TRINITY + if (player->IsInFlight()) + player->FinishTaxiFlight(); + else + player->SaveRecallPosition(); +#else + if (player->IsTaxiFlying()) + { + player->GetMotionMaster()->MovementExpired(); + player->m_taxi.ClearTaxiDestinations(); + } +#endif + Eluna::Push(L, player->TeleportTo(mapId, x, y, z, o)); + return 1; + } + + int AddLifetimeKills(lua_State* L, Player* player) + { + uint32 val = Eluna::CHECKVAL(L, 2); + uint32 currentKills = player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS); + player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, currentKills + val); + return 0; + } + + /** + * Adds the given amount of the specified item entry to the player. + * + * @param uint32 entry : entry of the item to add + * @param uint32 itemCount = 1 : amount of the item to add + * @return [Item] item : the item that was added or nil + */ + int AddItem(lua_State* L, Player* player) + { + uint32 itemId = Eluna::CHECKVAL(L, 2); + uint32 itemCount = Eluna::CHECKVAL(L, 3, 1); + +#if defined TRINITY || AZEROTHCORE + uint32 noSpaceForCount = 0; + ItemPosCountVec dest; + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, itemCount, &noSpaceForCount); + if (msg != EQUIP_ERR_OK) + itemCount -= noSpaceForCount; + + if (itemCount == 0 || dest.empty()) + return 1; +#ifndef AZEROTHCORE + Item* item = player->StoreNewItem(dest, itemId, true, GenerateItemRandomPropertyId(itemId)); +#else + Item* item = player->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); +#endif + if (item) + player->SendNewItem(item, itemCount, true, false); + Eluna::Push(L, item); +#else + Eluna::Push(L, player->StoreNewItemInInventorySlot(itemId, itemCount)); +#endif + return 1; + } + + /** + * Removes the given amount of the specified [Item] from the player. + * + * @proto (item, itemCount) + * @proto (entry, itemCount) + * @param [Item] item : item to remove + * @param uint32 entry : entry of the item to remove + * @param uint32 itemCount = 1 : amount of the item to remove + */ + int RemoveItem(lua_State* L, Player* player) + { + Item* item = Eluna::CHECKOBJ(L, 2, false); + uint32 itemCount = Eluna::CHECKVAL(L, 3); + if (!item) + { + uint32 itemId = Eluna::CHECKVAL(L, 2); + player->DestroyItemCount(itemId, itemCount, true); + } + else + { + bool all = itemCount >= item->GetCount(); + player->DestroyItemCount(item, itemCount, true); + if (all) + Eluna::CHECKOBJ(L, 2)->Invalidate(); + } + return 0; + } + + /** + * Removes specified amount of lifetime kills + * + * @param uint32 val : kills to remove + */ + int RemoveLifetimeKills(lua_State* L, Player* player) + { + uint32 val = Eluna::CHECKVAL(L, 2); + uint32 currentKills = player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS); + if (val > currentKills) + val = currentKills; + player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, currentKills - val); + return 0; + } + + /** + * Resets cooldown of the specified spell + * + * @param uint32 spellId + * @param bool update = true + */ + int ResetSpellCooldown(lua_State* L, Player* player) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + bool update = Eluna::CHECKVAL(L, 3, true); +#ifdef TRINITY + player->GetSpellHistory()->ResetCooldown(spellId, update); +#else + player->RemoveSpellCooldown(spellId, update); +#endif + return 0; + } + + /** + * Resets cooldown of the specified category + * + * @param uint32 category + * @param bool update = true + */ + int ResetTypeCooldowns(lua_State* L, Player* player) + { + uint32 category = Eluna::CHECKVAL(L, 2); + bool update = Eluna::CHECKVAL(L, 3, true); + (void)update; // ensure that the variable is referenced in order to pass compiler checks + +#ifdef TRINITY + player->GetSpellHistory()->ResetCooldowns([category](SpellHistory::CooldownStorageType::iterator itr) -> bool + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + return spellInfo && spellInfo->GetCategory() == category; + }, update); +#else +#ifndef AZEROTHCORE + player->RemoveSpellCategoryCooldown(category, update); +#else + player->RemoveCategoryCooldown(category); +#endif +#endif + return 0; + } + + /** + * Resets all of the [Player]'s cooldowns + */ + int ResetAllCooldowns(lua_State* /*L*/, Player* player) + { +#ifdef TRINITY + player->GetSpellHistory()->ResetAllCooldowns(); +#else + player->RemoveAllSpellCooldown(); +#endif + return 0; + } + + /** + * Sends a Broadcast Message to the [Player] + * + * @param string message + */ + int SendBroadcastMessage(lua_State* L, Player* player) + { + const char* message = Eluna::CHECKVAL(L, 2); + if (std::string(message).length() > 0) + ChatHandler(player->GetSession()).SendSysMessage(message); + return 0; + } + + /** + * Sends an Area Trigger Message to the [Player] + * + * @param string message + */ + int SendAreaTriggerMessage(lua_State* L, Player* player) + { + std::string msg = Eluna::CHECKVAL(L, 2); + if (msg.length() > 0) + player->GetSession()->SendAreaTriggerMessage("%s", msg.c_str()); + return 0; + } + + /** + * Sends a Notification to the [Player] + * + * @param string message + */ + int SendNotification(lua_State* L, Player* player) + { + std::string msg = Eluna::CHECKVAL(L, 2); + if (msg.length() > 0) + player->GetSession()->SendNotification("%s", msg.c_str()); + return 0; + } + + /** + * Sends a [WorldPacket] to the [Player] + * + * @param [WorldPacket] packet + * @param bool selfOnly = true + */ + int SendPacket(lua_State* L, Player* player) + { + WorldPacket* data = Eluna::CHECKOBJ(L, 2); + bool selfOnly = Eluna::CHECKVAL(L, 3, true); +#ifdef CMANGOS + if (selfOnly) + player->GetSession()->SendPacket(*data); + else + player->SendMessageToSet(*data, true); +#else + if (selfOnly) + player->GetSession()->SendPacket(data); + else + player->SendMessageToSet(data, true); +#endif + return 0; + } + + /** + * Sends addon message to the [Player] receiver + * + * @param string prefix + * @param string message + * @param [ChatMsg] channel + * @param [Player] receiver + * + */ + int SendAddonMessage(lua_State* L, Player* player) + { + std::string prefix = Eluna::CHECKVAL(L, 2); + std::string message = Eluna::CHECKVAL(L, 3); + uint8 channel = Eluna::CHECKVAL(L, 4); + Player* receiver = Eluna::CHECKOBJ(L, 5); + + std::string fullmsg = prefix + "\t" + message; + + WorldPacket data(SMSG_MESSAGECHAT, 100); + data << uint8(channel); + data << int32(LANG_ADDON); + data << player->GET_GUID(); +#ifndef CLASSIC + data << uint32(0); + data << receiver->GET_GUID(); +#endif + data << uint32(fullmsg.length() + 1); + data << fullmsg; + data << uint8(0); +#ifdef CMANGOS + receiver->GetSession()->SendPacket(data); +#else + receiver->GetSession()->SendPacket(&data); +#endif + return 0; + } + + /** + * Kicks the [Player] from the server + */ + int KickPlayer(lua_State* /*L*/, Player* player) + { +#ifdef TRINITY + player->GetSession()->KickPlayer("PlayerMethods::KickPlayer Kick the player"); +#else + player->GetSession()->KickPlayer(); +#endif + return 0; + } + + /** + * Adds or subtracts from the [Player]s money in copper + * + * @param int32 copperAmt : negative to remove, positive to add + */ + int ModifyMoney(lua_State* L, Player* player) + { + int32 amt = Eluna::CHECKVAL(L, 2); + + player->ModifyMoney(amt); + return 1; + } + + /** + * Teaches the [Player] the [Spell] specified by entry ID + * + * @param uint32 spellId + */ + int LearnSpell(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + +#ifdef TRINITY + player->LearnSpell(id, false); +#elif AZEROTHCORE + player->learnSpell(id); +#else + player->learnSpell(id, false); +#endif + return 0; + } + + /** + * Learn the [Player] the talent specified by talent_id and talentRank + * + * @param uint32 talent_id + * @param uint32 talentRank + */ + int LearnTalent(lua_State* L, Player* player) + { + uint32 id = Eluna::CHECKVAL(L, 2); + uint32 rank = Eluna::CHECKVAL(L, 3); + + player->LearnTalent(id, rank); +#if (!defined(TBC) && !defined(CLASSIC)) + player->SendTalentsInfoData(false); +#endif + +#if !defined TRINITY && !AZEROTHCORE + // if player has a pet, update owner talent auras + if (player->GetPet()) + player->GetPet()->CastOwnerTalentAuras(); +#endif + return 0; + } + + /** + * Adds a glyph specified by `glyphId` to the [Player]'s current talent specialization into the slot with the index `slotIndex` + * + * @param uint32 glyphId + * @param uint32 slotIndex + */ + int SetGlyph(lua_State* L, Player* player) + { + uint32 glyphId = Eluna::CHECKVAL(L, 2); + uint32 slotIndex = Eluna::CHECKVAL(L, 3); + + player->SetGlyph(slotIndex, glyphId, true); + player->SendTalentsInfoData(false); // Also handles GlyphData + + return 0; + } + +#if !defined(CLASSIC) + /** + * Remove cooldowns on spells that have less than 10 minutes of cooldown from the [Player], similarly to when you enter an arena. + */ + int RemoveArenaSpellCooldowns(lua_State* /*L*/, Player* player) + { + player->RemoveArenaSpellCooldowns(); + return 0; + } +#endif + + /** + * Resurrects the [Player]. + * + * @param float healthPercent = 100.0f + * @param bool ressSickness = false + */ + int ResurrectPlayer(lua_State* L, Player* player) + { + float percent = Eluna::CHECKVAL(L, 2, 100.0f); + bool sickness = Eluna::CHECKVAL(L, 3, false); + player->ResurrectPlayer(percent, sickness); + player->SpawnCorpseBones(); + return 0; + } + + /** + * Adds a new item to the gossip menu shown to the [Player] on next call to [Player:GossipSendMenu]. + * + * sender and intid are numbers which are passed directly to the gossip selection handler. Internally they are partly used for the database gossip handling. + * code specifies whether to show a box to insert text to. The player inserted text is passed to the gossip selection handler. + * money specifies an amount of money the player needs to have to click the option. An error message is shown if the player doesn't have enough money. + * Note that the money amount is only checked client side and is not removed from the player either. You will need to check again in your code before taking action. + * + * See also: [Player:GossipSendMenu], [Player:GossipAddQuests], [Player:GossipComplete], [Player:GossipClearMenu] + * + * @param uint32 icon : number that specifies used icon + * @param string msg : label on the gossip item + * @param uint32 sender : number passed to gossip handlers + * @param uint32 intid : number passed to gossip handlers + * @param bool code = false : show text input on click if true + * @param string popup = nil : if non empty string, a popup with given text shown on click + * @param uint32 money = 0 : required money in copper + */ + int GossipMenuAddItem(lua_State* L, Player* player) + { + uint32 _icon = Eluna::CHECKVAL(L, 2); + const char* msg = Eluna::CHECKVAL(L, 3); + uint32 _sender = Eluna::CHECKVAL(L, 4); + uint32 _intid = Eluna::CHECKVAL(L, 5); + bool _code = Eluna::CHECKVAL(L, 6, false); + const char* _promptMsg = Eluna::CHECKVAL(L, 7, ""); + uint32 _money = Eluna::CHECKVAL(L, 8, 0); +#if defined TRINITY || AZEROTHCORE + player->PlayerTalkClass->GetGossipMenu().AddMenuItem(-1, _icon, msg, _sender, _intid, _promptMsg, _money, _code); +#else +#ifndef CLASSIC + player->PlayerTalkClass->GetGossipMenu().AddMenuItem(_icon, msg, _sender, _intid, _promptMsg, _money, _code); +#else + player->PlayerTalkClass->GetGossipMenu().AddMenuItem(_icon, msg, _sender, _intid, _promptMsg, _code); +#endif +#endif//TRINITY + return 0; + } + + /** + * Closes the [Player]s currently open Gossip Menu. + * + * See also: [Player:GossipMenuAddItem], [Player:GossipAddQuests], [Player:GossipSendMenu], [Player:GossipClearMenu] + */ + int GossipComplete(lua_State* /*L*/, Player* player) + { +#if defined TRINITY || AZEROTHCORE + player->PlayerTalkClass->SendCloseGossip(); +#else + player->PlayerTalkClass->CloseGossip(); +#endif + return 0; + } + + /** + * Sends the current gossip items of the player to him as a gossip menu with header text from the given textId. + * + * If sender is a [Player] then menu_id is mandatory, otherwise it is not used for anything. + * menu_id is the ID used to trigger the OnGossipSelect registered for players. See [Global:RegisterPlayerGossipEvent] + * + * See also: [Player:GossipMenuAddItem], [Player:GossipAddQuests], [Player:GossipComplete], [Player:GossipClearMenu] + * + * @proto (npc_text, sender) + * @proto (npc_text, sender, menu_id) + * @param uint32 npc_text : entry ID of a header text in npc_text database table, common default is 100 + * @param [Object] sender : object acting as the source of the sent gossip menu + * @param uint32 menu_id : if sender is a [Player] then menu_id is mandatory + */ + int GossipSendMenu(lua_State* L, Player* player) + { + uint32 npc_text = Eluna::CHECKVAL(L, 2); + Object* sender = Eluna::CHECKOBJ(L, 3); + if (sender->GetTypeId() == TYPEID_PLAYER) + { + uint32 menu_id = Eluna::CHECKVAL(L, 4); + player->PlayerTalkClass->GetGossipMenu().SetMenuId(menu_id); + } + player->PlayerTalkClass->SendGossipMenu(npc_text, sender->GET_GUID()); + return 0; + } + + /** + * Clears the [Player]s current gossip item list. + * + * See also: [Player:GossipMenuAddItem], [Player:GossipSendMenu], [Player:GossipAddQuests], [Player:GossipComplete] + * + * Note: This is needed when you show a gossip menu without using gossip hello or select hooks which do this automatically. + * Usually this is needed when using [Player] is the sender of a Gossip Menu. + */ + int GossipClearMenu(lua_State* /*L*/, Player* player) + { + player->PlayerTalkClass->ClearMenus(); + return 0; + } + + /** + * Attempts to start the taxi/flying to the given pathID + * + * @param uint32 pathId : pathId from DBC or [Global:AddTaxiPath] + */ + int StartTaxi(lua_State* L, Player* player) + { + uint32 pathId = Eluna::CHECKVAL(L, 2); + + player->ActivateTaxiPathTo(pathId); + return 0; + } + + /** + * Sends POI to the location on your map + * + * @param float x + * @param float y + * @param uint32 icon : map icon to show + * @param uint32 flags + * @param uint32 data + * @param string iconText + */ + int GossipSendPOI(lua_State* L, Player* player) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + uint32 icon = Eluna::CHECKVAL(L, 4); + uint32 flags = Eluna::CHECKVAL(L, 5); + uint32 data = Eluna::CHECKVAL(L, 6); + std::string iconText = Eluna::CHECKVAL(L, 7); + + WorldPacket packet(SMSG_GOSSIP_POI, 4 + 4 + 4 + 4 + 4 + 10); + packet << flags; + packet << x; + packet << y; + packet << icon; + packet << data; + packet << iconText; +#ifdef CMANGOS + player->GetSession()->SendPacket(packet); +#else + player->GetSession()->SendPacket(&packet); +#endif + return 0; + } + + /** + * Adds the gossip items to the [Player]'s gossip for the quests the given [WorldObject] can offer to the player. + * + * @param [WorldObject] source : a questgiver with quests + */ + int GossipAddQuests(lua_State* L, Player* player) + { + WorldObject* source = Eluna::CHECKOBJ(L, 2); + + if (source->GetTypeId() == TYPEID_UNIT) + { + if (source->GetUInt32Value(UNIT_NPC_FLAGS) & UNIT_NPC_FLAG_QUESTGIVER) + player->PrepareQuestMenu(source->GET_GUID()); + } + else if (source->GetTypeId() == TYPEID_GAMEOBJECT) + { + if (source->ToGameObject()->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + player->PrepareQuestMenu(source->GET_GUID()); + } + return 0; + } + + /** + * Shows a quest accepting window to the [Player] for the given quest. + * + * @param uint32 questId : entry of a quest + * @param bool activateAccept = true : auto finish the quest + */ + int SendQuestTemplate(lua_State* L, Player* player) + { + uint32 questId = Eluna::CHECKVAL(L, 2); + bool activateAccept = Eluna::CHECKVAL(L, 3, true); + + Quest const* quest = eObjectMgr->GetQuestTemplate(questId); + if (!quest) + return 0; + + player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, player->GET_GUID(), activateAccept); + return 0; + } + + /** + * Converts [Player]'s corpse to bones + */ + int SpawnBones(lua_State* /*L*/, Player* player) + { + player->SpawnCorpseBones(); + return 0; + } + + /** + * Loots [Player]'s bones for insignia + * + * @param [Player] looter + */ + int RemovedInsignia(lua_State* L, Player* player) + { + Player* looter = Eluna::CHECKOBJ(L, 2); + player->RemovedInsignia(looter); + return 0; + } + + /** + * Makes the [Player] invite another player to a group. + * + * @param [Player] invited : player to invite to group + * @return bool success : true if the player was invited to a group + */ + int GroupInvite(lua_State* L, Player* player) + { + Player* invited = Eluna::CHECKOBJ(L, 2); + + if (invited->GetGroup() || invited->GetGroupInvite()) + { + Eluna::Push(L, false); + return 1; + } + + // Get correct existing group if any + Group* group = player->GetGroup(); + if (group && group->isBGGroup()) + group = player->GetOriginalGroup(); + + bool success = false; + + // Try invite if group found + if (group) + success = !group->IsFull() && group->AddInvite(invited); + else + { + // Create new group if one not found + group = new Group; + success = group->AddLeaderInvite(player) && group->AddInvite(invited); + if (!success) + delete group; + } + + if (success) + { +#if defined(CLASSIC) || defined(TBC) + WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size + data << player->GetName(); +#ifdef CMANGOS + invited->GetSession()->SendPacket(data); +#else + invited->GetSession()->SendPacket(&data); +#endif +#else + WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size + data << uint8(1); // invited/already in group flag + data << player->GetName(); // max len 48 + data << uint32(0); // unk + data << uint8(0); // count + data << uint32(0); // unk +#ifdef CMANGOS + invited->GetSession()->SendPacket(data); +#else + invited->GetSession()->SendPacket(&data); +#endif +#endif + } + + Eluna::Push(L, success); + return 1; + } + + /** + * Creates a new [Group] with the creator [Player] as leader. + * + * @param [Player] invited : player to add to group + * @return [Group] createdGroup : the created group or nil + */ + int GroupCreate(lua_State* L, Player* player) + { + Player* invited = Eluna::CHECKOBJ(L, 2); + + if (player->GetGroup() || invited->GetGroup()) + return 0; + + if (player->GetGroupInvite()) + player->UninviteFromGroup(); + if (invited->GetGroupInvite()) + invited->UninviteFromGroup(); + + // Try create new group + Group* group = new Group; + if (!group->AddLeaderInvite(player)) + { + delete group; + return 0; + } + + // Forming a new group, create it + if (!group->IsCreated()) + { + group->RemoveInvite(player); +#if defined TRINITY || AZEROTHCORE + group->Create(player); + sGroupMgr->AddGroup(group); +#else + if (!group->Create(group->GetLeaderGuid(), group->GetLeaderName())) + return 0; + sObjectMgr.AddGroup(group); +#endif + } + +#if defined TRINITY || AZEROTHCORE + if (!group->AddMember(invited)) + return 0; + group->BroadcastGroupUpdate(); +#else + if (!group->AddMember(invited->GetObjectGuid(), invited->GetName())) + return 0; +#endif + Eluna::Push(L, group); + return 1; + } + + /** + * Starts a cinematic for the [Player] + * + * @param uint32 CinematicSequenceId : entry of a cinematic + */ + int SendCinematicStart(lua_State* L, Player* player) + { + uint32 CinematicSequenceId = Eluna::CHECKVAL(L, 2); + + player->SendCinematicStart(CinematicSequenceId); + return 0; + } + +#if !defined(CLASSIC) && !defined(TBC) + /** + * Starts a movie for the [Player] + * + * @param uint32 MovieId : entry of a movie + */ + int SendMovieStart(lua_State* L, Player* player) + { + uint32 MovieId = Eluna::CHECKVAL(L, 2); + + player->SendMovieStart(MovieId); + return 0; + } +#endif + + /** + * Sets a setting value for the [Player] + * + * @param string source + * @param uint32 index + * @param uint32 value + */ + int UpdatePlayerSetting(lua_State* L, Player* player) + { + std::string source = Eluna::CHECKVAL(L, 2); + uint32 index = Eluna::CHECKVAL(L, 3); + uint32 value = Eluna::CHECKVAL(L, 4); + player->UpdatePlayerSetting(source, index, value); + return 0; + } + + /** + * Gets a setting value for the [Player] + * + * @param string source + * @param uint32 index + */ + int GetPlayerSettingValue(lua_State* L, Player* player) + { + std::string source = Eluna::CHECKVAL(L, 2); + uint32 index = Eluna::CHECKVAL(L, 3); + uint32 value = player->GetPlayerSetting(source, index).value; + Eluna::Push(L, value); + return 1; + } + + /** + * Returns the [Player] that is currently trading with this [Player] + * + * @return [Player] trader : the player trading, or nil + */ + int GetTrader(lua_State* L, Player* player) + { + Eluna::Push(L, player->GetTrader()); + return 1; + } + + /*int BindToInstance(lua_State* L, Player* player) + { + player->BindToInstance(); + return 0; + }*/ + + /*int AddTalent(lua_State* L, Player* player) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + uint8 spec = Eluna::CHECKVAL(L, 3); + bool learning = Eluna::CHECKVAL(L, 4, true); + if (spec >= MAX_TALENT_SPECS) + Eluna::Push(L, false); + else + Eluna::Push(L, player->AddTalent(spellId, spec, learning)); + return 1; + }*/ + + /*int GainSpellComboPoints(lua_State* L, Player* player) + { + int8 count = Eluna::CHECKVAL(L, 2); + + player->GainSpellComboPoints(count); + return 0; + }*/ + + /*int KillGOCredit(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + ObjectGuid guid = Eluna::CHECKVAL(L, 3); + player->KillCreditGO(entry, guid); + return 0; + }*/ + + /*int KilledPlayerCredit(lua_State* L, Player* player) + { + player->KilledPlayerCredit(); + return 0; + }*/ + + /*int RemoveRewardedQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + player->RemoveRewardedQuest(entry); + return 0; + }*/ + + /*int RemoveActiveQuest(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + + player->RemoveActiveQuest(entry); + return 0; + }*/ + + /*int SummonPet(lua_State* L, Player* player) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + float o = Eluna::CHECKVAL(L, 6); + uint32 petType = Eluna::CHECKVAL(L, 7); + uint32 despwtime = Eluna::CHECKVAL(L, 8); + + if (petType >= MAX_PET_TYPE) + return 0; + + player->SummonPet(entry, x, y, z, o, (PetType)petType, despwtime); + return 0; + }*/ + + /*int RemovePet(lua_State* L, Player* player) + { + int mode = Eluna::CHECKVAL(L, 2, PET_SAVE_AS_DELETED); + bool returnreagent = Eluna::CHECKVAL(L, 2, false); + + if (!player->GetPet()) + return 0; + + player->RemovePet(player->GetPet(), (PetSaveMode)mode, returnreagent); + return 0; + }*/ +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/QuestMethods.h b/modules/mod-eluna/src/LuaEngine/QuestMethods.h new file mode 100644 index 0000000..7ca026b --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/QuestMethods.h @@ -0,0 +1,187 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef QUESTMETHODS_H +#define QUESTMETHODS_H + +/*** + * Inherits all methods from: none + */ +namespace LuaQuest +{ + /** + * Returns 'true' if the [Quest] has the specified flag, false otherwise. + * Below flags are based off of 3.3.5a. Subject to change. + * + *
+     * enum QuestFlags
+     * {
+     *     // Flags used at server and sent to client
+     *     QUEST_FLAGS_NONE                    = 0x0,
+     *     QUEST_FLAGS_STAY_ALIVE              = 0x1,       // Not used currently
+     *     QUEST_FLAGS_PARTY_ACCEPT            = 0x2,       // Not used currently. If player in party, all players that can accept this quest will receive confirmation box to accept quest CMSG_QUEST_CONFIRM_ACCEPT/SMSG_QUEST_CONFIRM_ACCEPT
+     *     QUEST_FLAGS_EXPLORATION             = 0x4,       // Not used currently
+     *     QUEST_FLAGS_SHARABLE                = 0x8,       // Can be shared: Player::CanShareQuest()
+     *     QUEST_FLAGS_HAS_CONDITION           = 0x10,      // Not used currently
+     *     QUEST_FLAGS_HIDE_REWARD_POI         = 0x20,      // Not used currently: Unsure of content
+     *     QUEST_FLAGS_RAID                    = 0x40,      // Not used currently
+     *     QUEST_FLAGS_TBC                     = 0x80,      // Not used currently: Available if TBC expansion enabled only
+     *     QUEST_FLAGS_NO_MONEY_FROM_XP        = 0x100,     // Not used currently: Experience is not converted to gold at max level
+     *     QUEST_FLAGS_HIDDEN_REWARDS          = 0x200,     // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUESTGIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE))
+     *     QUEST_FLAGS_TRACKING                = 0x400,     // These quests are automatically rewarded on quest complete and they will never appear in quest log client side.
+     *     QUEST_FLAGS_DEPRECATE_REPUTATION    = 0x800,     // Not used currently
+     *     QUEST_FLAGS_DAILY                   = 0x1000,    // Used to know quest is Daily one
+     *     QUEST_FLAGS_FLAGS_PVP               = 0x2000,    // Having this quest in log forces PvP flag
+     *     QUEST_FLAGS_UNAVAILABLE             = 0x4000,    // Used on quests that are not generically available
+     *     QUEST_FLAGS_WEEKLY                  = 0x8000,
+     *     QUEST_FLAGS_AUTOCOMPLETE            = 0x10000,   // auto complete
+     *     QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x20000,   // Displays usable item in quest tracker
+     *     QUEST_FLAGS_OBJ_TEXT                = 0x40000,   // use Objective text as Complete text
+     *     QUEST_FLAGS_AUTO_ACCEPT             = 0x80000,   // The client recognizes this flag as auto-accept. However, NONE of the current quests (3.3.5a) have this flag. Maybe blizz used to use it, or will use it in the future.
+     *
+     *     // ... 4.x added flags up to 0x80000000 - all unknown for now
+     * };
+     * 
+ * + * @param [QuestFlags] flag : all available flags can be seen above + * @return bool hasFlag + */ + int HasFlag(lua_State* L, Quest* quest) + { + uint32 flag = Eluna::CHECKVAL(L, 2); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, quest->HasFlag(flag)); +#else + Eluna::Push(L, quest->HasQuestFlag((QuestFlags)flag)); +#endif + return 1; + } + +#ifndef CLASSIC + /** + * Returns 'true' if the [Quest] is a daily quest, false otherwise. + * + * @return bool isDaily + */ + int IsDaily(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->IsDaily()); + return 1; + } +#endif + + /** + * Returns 'true' if the [Quest] is repeatable, false otherwise. + * + * @return bool isRepeatable + */ + int IsRepeatable(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->IsRepeatable()); + return 1; + } + + /** + * Returns entry ID of the [Quest]. + * + * @return uint32 entryId + */ + int GetId(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetQuestId()); + return 1; + } + + /** + * Returns the [Quest]'s level. + * + * @return uint32 level + */ + int GetLevel(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetQuestLevel()); + return 1; + } + + /** + * Returns the minimum level required to pick up the [Quest]. + * + * @return uint32 minLevel + */ + int GetMinLevel(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetMinLevel()); + return 1; + } + + /** + * Returns the next [Quest] entry ID. + * + * @return int32 entryId + */ + int GetNextQuestId(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetNextQuestId()); + return 1; + } + + /** + * Returns the previous [Quest] entry ID. + * + * @return int32 entryId + */ + int GetPrevQuestId(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetPrevQuestId()); + return 1; + } + + /** + * Returns the next [Quest] entry ID in the specific [Quest] chain. + * + * @return int32 entryId + */ + int GetNextQuestInChain(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetNextQuestInChain()); + return 1; + } + + /** + * Returns the [Quest]'s flags. + * + * @return [QuestFlags] flags + */ + int GetFlags(lua_State* L, Quest* quest) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, quest->GetFlags()); +#else + Eluna::Push(L, quest->GetQuestFlags()); +#endif + return 1; + } + + /** + * Returns the [Quest]'s type. + * + * TODO: Document types available. + * + * @return uint32 type + */ + int GetType(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetType()); + return 1; + } + + /*int GetMaxLevel(lua_State* L, Quest* quest) + { + Eluna::Push(L, quest->GetMaxLevel()); + return 1; + }*/ +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/RollMethods.h b/modules/mod-eluna/src/LuaEngine/RollMethods.h new file mode 100644 index 0000000..d36fe11 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/RollMethods.h @@ -0,0 +1,212 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef ROLLMETHODS_H +#define ROLLMETHODS_H + +#include "Group.h" + +namespace LuaRoll +{ + /** + * Returns the rolled [Item]'s GUID. + * + * @return ObjectGuid guid + */ + int GetItemGUID(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemGUID.GetCounter()); + return 1; + } + + /** + * Returns the rolled [Item]'s entry. + * + * @return uint32 entry + */ + int GetItemId(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemid); + return 1; + } + + /** + * Returns the rolled [Item]'s random property ID. + * + * @return int32 randomPropId + */ + int GetItemRandomPropId(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemRandomPropId); + return 1; + } + + /** + * Returns the rolled [Item]'s random suffix ID. + * + * @return uint32 randomSuffix + */ + int GetItemRandomSuffix(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemRandomSuffix); + return 1; + } + + /** + * Returns the rolled [Item]'s count. + * + * @return uint8 count + */ + int GetItemCount(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemCount); + return 1; + } + + /** + * Returns the vote type for a [Player] on this [Roll]. + * See [Roll:GetPlayerVoteGUIDs] to obtain the GUIDs of the [Player]s who rolled. + * + *
+     * enum RollVote
+     * {
+     *     PASS              = 0,
+     *     NEED              = 1,
+     *     GREED             = 2,
+     *     DISENCHANT        = 3,
+     *     NOT_EMITED_YET    = 4,
+     *     NOT_VALID         = 5
+     * };
+     * 
+ * + * @param ObjectGuid guid + * @return [RollVote] vote + */ + int GetPlayerVote(lua_State* L, Roll* roll) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + + bool found = false; + for (std::pair& pair : roll->playerVote) + { + if (pair.first == guid) + { + Eluna::Push(L, pair.second); + found = true; + } + } + + if (!found) + { + Eluna::Push(L); + } + + return 1; + } + + /** + * Returns the GUIDs of the [Player]s who rolled. + * See [Roll:GetPlayerVote] to obtain the vote type of a [Player]. + * + * @return table guids + */ + int GetPlayerVoteGUIDs(lua_State* L, Roll* roll) + { + lua_newtable(L); + int table = lua_gettop(L); + uint32 i = 1; + for (std::pair& pair : roll->playerVote) + { + Eluna::Push(L, pair.first); + lua_rawseti(L, table, i); + ++i; + } + + lua_settop(L, table); // push table to top of stack + return 1; + } + + /** + * Returns the total number of players who rolled. + * + * @return uint8 playersCount + */ + int GetTotalPlayersRolling(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->totalPlayersRolling); + return 1; + } + + /** + * Returns the total number of players who rolled need. + * + * @return uint8 playersCount + */ + int GetTotalNeed(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->totalNeed); + return 1; + } + + /** + * Returns the total number of players who rolled greed. + * + * @return uint8 playersCount + */ + int GetTotalGreed(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->totalGreed); + return 1; + } + + /** + * Returns the total number of players who passed. + * + * @return uint8 playersCount + */ + int GetTotalPass(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->totalPass); + return 1; + } + + /** + * Returns the rolled [Item]'s slot in the loot window. + * + * @return uint8 slot + */ + int GetItemSlot(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->itemSlot); + return 1; + } + + /** + * Returns the mask applied to this [Roll]. + * + *
+     * enum RollMask
+     * {
+     *     ROLL_FLAG_TYPE_PASS                 = 0x01,
+     *     ROLL_FLAG_TYPE_NEED                 = 0x02,
+     *     ROLL_FLAG_TYPE_GREED                = 0x04,
+     *     ROLL_FLAG_TYPE_DISENCHANT           = 0x08,
+     * 
+     *     ROLL_ALL_TYPE_NO_DISENCHANT         = 0x07,
+     *     ROLL_ALL_TYPE_MASK                  = 0x0F
+     * };
+     * 
+ * + * @return [RollMask] rollMask + */ + int GetRollVoteMask(lua_State* L, Roll* roll) + { + Eluna::Push(L, roll->rollVoteMask); + return 1; + } +} + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/ServerHooks.cpp b/modules/mod-eluna/src/LuaEngine/ServerHooks.cpp new file mode 100644 index 0000000..db2c537 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/ServerHooks.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaEventMgr.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +#define START_HOOK_WITH_RETVAL(EVENT, RETVAL) \ + if (!IsEnabled())\ + return RETVAL;\ + auto key = EventKey(EVENT);\ + if (!ServerEventBindings->HasBindingsFor(key))\ + return RETVAL;\ + LOCK_ELUNA + +bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel) +{ + START_HOOK_WITH_RETVAL(ADDON_EVENT_ON_MESSAGE, true); + Push(sender); + Push(type); + + auto delimeter_position = msg.find('\t'); + if (delimeter_position == std::string::npos) + { + Push(msg); // prefix + Push(); // msg + } + else + { + std::string prefix = msg.substr(0, delimeter_position); + std::string content = msg.substr(delimeter_position + 1, std::string::npos); + Push(prefix); + Push(content); + } + + if (receiver) + Push(receiver); + else if (guild) + Push(guild); + else if (group) + Push(group); + else if (channel) + Push(channel->GetChannelId()); + else + Push(); + + return CallAllFunctionsBool(ServerEventBindings, key, true); +} + +void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj) +{ + LOCK_ELUNA; + ASSERT(!event_level); + + // Get function + lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef); + + // Push parameters + Push(L, funcRef); + Push(L, delay); + Push(L, calls); + Push(L, obj); + + // Call function + ExecuteCall(4, 0); + + ASSERT(!event_level); + InvalidateObjects(); +} + +void Eluna::OnGameEventStart(uint32 eventid) +{ + START_HOOK(GAME_EVENT_START); + Push(eventid); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnGameEventStop(uint32 eventid) +{ + START_HOOK(GAME_EVENT_STOP); + Push(eventid); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnLuaStateClose() +{ + START_HOOK(ELUNA_EVENT_ON_LUA_STATE_CLOSE); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnLuaStateOpen() +{ + START_HOOK(ELUNA_EVENT_ON_LUA_STATE_OPEN); + CallAllFunctions(ServerEventBindings, key); +} + +// AreaTrigger +bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger) +{ + START_HOOK_WITH_RETVAL(TRIGGER_EVENT_ON_TRIGGER, false); + Push(pPlayer); +#ifdef TRINITY + Push(pTrigger->ID); +#elif AZEROTHCORE + Push(pTrigger->entry); +#else + Push(pTrigger->id); + +#endif + return CallAllFunctionsBool(ServerEventBindings, key); +} + +// Weather +void Eluna::OnChange(Weather* /*weather*/, uint32 zone, WeatherState state, float grade) +{ + START_HOOK(WEATHER_EVENT_ON_CHANGE); + Push(zone); + Push(state); + Push(grade); + CallAllFunctions(ServerEventBindings, key); +} + +// Auction House +void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry) +{ +#ifdef AZEROTHCORE + Player* owner = eObjectAccessor()FindPlayer(entry->owner); +#else + Player* owner = eObjectAccessor()FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); +#endif + +#ifdef TRINITY + Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); + uint32 expiretime = entry->expire_time; +#elif AZEROTHCORE + Item* item = eAuctionMgr->GetAItem(entry->item_guid); + uint32 expiretime = entry->expire_time; +#else + Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow); + uint32 expiretime = entry->expireTime; +#endif + + if (!owner || !item) + return; + + START_HOOK(AUCTION_EVENT_ON_ADD); + Push(entry->Id); + Push(owner); + Push(item); + Push(expiretime); + Push(entry->buyout); + Push(entry->startbid); + Push(entry->bid); + Push(entry->bidder); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry) +{ +#ifdef AZEROTHCORE + Player* owner = eObjectAccessor()FindPlayer(entry->owner); +#else + Player* owner = eObjectAccessor()FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); +#endif + +#ifdef TRINITY + Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); + uint32 expiretime = entry->expire_time; +#elif AZEROTHCORE + Item* item = eAuctionMgr->GetAItem(entry->item_guid); + uint32 expiretime = entry->expire_time; +#else + Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow); + uint32 expiretime = entry->expireTime; +#endif + + + if (!owner || !item) + return; + + START_HOOK(AUCTION_EVENT_ON_REMOVE); + Push(entry->Id); + Push(owner); + Push(item); + Push(expiretime); + Push(entry->buyout); + Push(entry->startbid); + Push(entry->bid); + Push(entry->bidder); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry) +{ +#ifdef AZEROTHCORE + Player* owner = eObjectAccessor()FindPlayer(entry->owner); +#else + Player* owner = eObjectAccessor()FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); +#endif + +#ifdef TRINITY + Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); + uint32 expiretime = entry->expire_time; +#elif AZEROTHCORE + Item* item = eAuctionMgr->GetAItem(entry->item_guid); + uint32 expiretime = entry->expire_time; +#else + Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow); + uint32 expiretime = entry->expireTime; +#endif + + + if (!owner || !item) + return; + + START_HOOK(AUCTION_EVENT_ON_SUCCESSFUL); + Push(entry->Id); + Push(owner); + Push(item); + Push(expiretime); + Push(entry->buyout); + Push(entry->startbid); + Push(entry->bid); + Push(entry->bidder); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry) +{ +#ifdef AZEROTHCORE + Player* owner = eObjectAccessor()FindPlayer(entry->owner); +#else + Player* owner = eObjectAccessor()FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER)); +#endif + +#ifdef TRINITY + Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow); + uint32 expiretime = entry->expire_time; +#elif AZEROTHCORE + Item* item = eAuctionMgr->GetAItem(entry->item_guid); + uint32 expiretime = entry->expire_time; +#else + Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow); + uint32 expiretime = entry->expireTime; +#endif + + + if (!owner || !item) + return; + + START_HOOK(AUCTION_EVENT_ON_EXPIRE); + Push(entry->Id); + Push(owner); + Push(item); + Push(expiretime); + Push(entry->buyout); + Push(entry->startbid); + Push(entry->bid); + Push(entry->bidder); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnOpenStateChange(bool open) +{ + START_HOOK(WORLD_EVENT_ON_OPEN_STATE_CHANGE); + Push(open); + CallAllFunctions(ServerEventBindings, key); +} + +#ifndef AZEROTHCORE +void Eluna::OnConfigLoad(bool reload) +#else +void Eluna::OnConfigLoad(bool reload, bool isBefore) +#endif +{ + START_HOOK(WORLD_EVENT_ON_CONFIG_LOAD); + Push(reload); +#ifdef AZEROTHCORE + Push(isBefore); +#endif + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) +{ + START_HOOK(WORLD_EVENT_ON_SHUTDOWN_INIT); + Push(code); + Push(mask); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnShutdownCancel() +{ + START_HOOK(WORLD_EVENT_ON_SHUTDOWN_CANCEL); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnWorldUpdate(uint32 diff) +{ + { + LOCK_ELUNA; + if (ShouldReload()) + _ReloadEluna(); + } + + eventMgr->globalProcessor->Update(diff); + httpManager.HandleHttpResponses(); + queryProcessor.ProcessReadyCallbacks(); + + START_HOOK(WORLD_EVENT_ON_UPDATE); + Push(diff); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnStartup() +{ + START_HOOK(WORLD_EVENT_ON_STARTUP); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnShutdown() +{ + START_HOOK(WORLD_EVENT_ON_SHUTDOWN); + CallAllFunctions(ServerEventBindings, key); +} + +/* Map */ +void Eluna::OnCreate(Map* map) +{ + START_HOOK(MAP_EVENT_ON_CREATE); + Push(map); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnDestroy(Map* map) +{ + START_HOOK(MAP_EVENT_ON_DESTROY); + Push(map); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnPlayerEnter(Map* map, Player* player) +{ + START_HOOK(MAP_EVENT_ON_PLAYER_ENTER); + Push(map); + Push(player); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnPlayerLeave(Map* map, Player* player) +{ + START_HOOK(MAP_EVENT_ON_PLAYER_LEAVE); + Push(map); + Push(player); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnUpdate(Map* map, uint32 diff) +{ + START_HOOK(MAP_EVENT_ON_UPDATE); + // enable this for multithread + // eventMgr->globalProcessor->Update(diff); + Push(map); + Push(diff); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnRemove(GameObject* gameobject) +{ + START_HOOK(WORLD_EVENT_ON_DELETE_GAMEOBJECT); + Push(gameobject); + CallAllFunctions(ServerEventBindings, key); +} + +void Eluna::OnRemove(Creature* creature) +{ + START_HOOK(WORLD_EVENT_ON_DELETE_CREATURE); + Push(creature); + CallAllFunctions(ServerEventBindings, key); +} diff --git a/modules/mod-eluna/src/LuaEngine/SpellMethods.h b/modules/mod-eluna/src/LuaEngine/SpellMethods.h new file mode 100644 index 0000000..2036c00 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/SpellMethods.h @@ -0,0 +1,193 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef SPELLMETHODS_H +#define SPELLMETHODS_H + +/*** + * An instance of a spell, created when the spell is cast by a [Unit]. + * + * Inherits all methods from: none + */ +namespace LuaSpell +{ + /** + * Returns `true` if the [Spell] is automatically repeating, `false` otherwise. + * + * @return bool isAutoRepeating + */ + int IsAutoRepeat(lua_State* L, Spell* spell) + { + Eluna::Push(L, spell->IsAutoRepeat()); + return 1; + } + + /** + * Returns the [Unit] that casted the [Spell]. + * + * @return [Unit] caster + */ + int GetCaster(lua_State* L, Spell* spell) + { + Eluna::Push(L, spell->GetCaster()); + return 1; + } + + /** + * Returns the cast time of the [Spell]. + * + * @return int32 castTime + */ + int GetCastTime(lua_State* L, Spell* spell) + { + Eluna::Push(L, spell->GetCastTime()); + return 1; + } + + /** + * Returns the entry ID of the [Spell]. + * + * @return uint32 entryId + */ + int GetEntry(lua_State* L, Spell* spell) + { + Eluna::Push(L, spell->m_spellInfo->Id); + return 1; + } + + /** + * Returns the power cost of the [Spell]. + * + * @return uint32 powerCost + */ + int GetPowerCost(lua_State* L, Spell* spell) + { + Eluna::Push(L, spell->GetPowerCost()); + return 1; + } + + /** + * Returns the spell duration of the [Spell]. + * + * @return int32 duration + */ + int GetDuration(lua_State* L, Spell* spell) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, spell->GetSpellInfo()->GetDuration()); +#else + Eluna::Push(L, GetSpellDuration(spell->m_spellInfo)); +#endif + return 1; + } + + /** + * Returns the target destination coordinates of the [Spell]. + * + * @return float x : x coordinate of the [Spell] + * @return float y : y coordinate of the [Spell] + * @return float z : z coordinate of the [Spell] + */ + int GetTargetDest(lua_State* L, Spell* spell) + { +#if defined TRINITY || AZEROTHCORE + if (!spell->m_targets.HasDst()) + return 3; + float x, y, z; + spell->m_targets.GetDstPos()->GetPosition(x, y, z); +#else + if (!(spell->m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) + return 3; + float x, y, z; + spell->m_targets.getDestination(x, y, z); +#endif + Eluna::Push(L, x); + Eluna::Push(L, y); + Eluna::Push(L, z); + return 3; + } + + /** + * Returns the target [Object] of the [Spell]. + * + * The target can be any of the following [Object] types: + * - [Player] + * - [Creature] + * - [GameObject] + * - [Item] + * - [Corpse] + * + * @return [Object] target + */ + int GetTarget(lua_State* L, Spell* spell) + { +#if defined TRINITY || AZEROTHCORE + if (GameObject* target = spell->m_targets.GetGOTarget()) + Eluna::Push(L, target); + else if (Item* target = spell->m_targets.GetItemTarget()) + Eluna::Push(L, target); + else if (Corpse* target = spell->m_targets.GetCorpseTarget()) + Eluna::Push(L, target); + else if (Unit* target = spell->m_targets.GetUnitTarget()) + Eluna::Push(L, target); + else if (WorldObject* target = spell->m_targets.GetObjectTarget()) + Eluna::Push(L, target); +#else + if (GameObject* target = spell->m_targets.getGOTarget()) + Eluna::Push(L, target); + else if (Item* target = spell->m_targets.getItemTarget()) + Eluna::Push(L, target); + else if (Corpse* target = spell->GetCaster()->GetMap()->GetCorpse(spell->m_targets.getCorpseTargetGuid())) + Eluna::Push(L, target); + else if (Unit* target = spell->m_targets.getUnitTarget()) + Eluna::Push(L, target); +#endif + return 1; + } + + /** + * Sets the [Spell] to automatically repeat. + * + * @param bool repeat : set variable to 'true' for spell to automatically repeat + */ + int SetAutoRepeat(lua_State* L, Spell* spell) + { + bool repeat = Eluna::CHECKVAL(L, 2); + spell->SetAutoRepeat(repeat); + return 0; + } + + /** + * Casts the [Spell]. + * + * @param bool skipCheck = false : skips initial checks to see if the [Spell] can be casted or not, this is optional + */ + int Cast(lua_State* L, Spell* spell) + { + bool skipCheck = Eluna::CHECKVAL(L, 2, false); + spell->cast(skipCheck); + return 0; + } + + /** + * Cancels the [Spell]. + */ + int Cancel(lua_State* /*L*/, Spell* spell) + { + spell->cancel(); + return 0; + } + + /** + * Finishes the [Spell]. + */ + int Finish(lua_State* /*L*/, Spell* spell) + { + spell->finish(); + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/UnitMethods.h b/modules/mod-eluna/src/LuaEngine/UnitMethods.h new file mode 100644 index 0000000..50e467b --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/UnitMethods.h @@ -0,0 +1,2657 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef UNITMETHODS_H +#define UNITMETHODS_H + +/*** + * Inherits all methods from: [Object], [WorldObject] + */ +namespace LuaUnit +{ + /** + * The [Unit] tries to attack a given target + * + * @param [Unit] who : [Unit] to attack + * @param bool meleeAttack = false: attack with melee or not + * @return didAttack : if the [Unit] did not attack + */ + int Attack(lua_State* L, Unit* unit) + { + Unit* who = Eluna::CHECKOBJ(L, 2); + bool meleeAttack = Eluna::CHECKVAL(L, 3, false); + + Eluna::Push(L, unit->Attack(who, meleeAttack)); + return 1; + } + + /** + * The [Unit] stops attacking its target + * + * @return bool isAttacking : if the [Unit] wasn't attacking already + */ + int AttackStop(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->AttackStop()); + return 1; + } + + /** + * Returns true if the [Unit] is standing. + * + * @return bool isStanding + */ + int IsStandState(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsStandState()); + return 1; + } + + /** + * Returns true if the [Unit] is mounted. + * + * @return bool isMounted + */ + int IsMounted(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsMounted()); + return 1; + } + + /** + * Returns true if the [Unit] is rooted. + * + * @return bool isRooted + */ + int IsRooted(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->isInRoots() || unit->HasUnitMovementFlag(MOVEMENTFLAG_ROOT)); + + return 1; + } + + /** + * Returns true if the [Unit] has full health. + * + * @return bool hasFullHealth + */ + int IsFullHealth(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsFullHealth()); + return 1; + } + + /** + * Returns true if the [Unit] is in an accessible place for the given [Creature]. + * + * @param [WorldObject] obj + * @param float radius + * @return bool isAccessible + */ + int IsInAccessiblePlaceFor(lua_State* L, Unit* unit) + { + Creature* creature = Eluna::CHECKOBJ(L, 2); + + Eluna::Push(L, unit->isInAccessiblePlaceFor(creature)); + + return 1; + } + + /** + * Returns true if the [Unit] an auctioneer. + * + * @return bool isAuctioneer + */ + int IsAuctioneer(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsAuctioner()); + + return 1; + } + + /** + * Returns true if the [Unit] a guild master. + * + * @return bool isGuildMaster + */ + int IsGuildMaster(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsGuildMaster()); + return 1; + } + + /** + * Returns true if the [Unit] an innkeeper. + * + * @return bool isInnkeeper + */ + int IsInnkeeper(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsInnkeeper()); + return 1; + } + + /** + * Returns true if the [Unit] a trainer. + * + * @return bool isTrainer + */ + int IsTrainer(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsTrainer()); + return 1; + } + + /** + * Returns true if the [Unit] is able to show a gossip window. + * + * @return bool hasGossip + */ + int IsGossip(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsGossip()); + return 1; + } + + /** + * Returns true if the [Unit] is a taxi master. + * + * @return bool isTaxi + */ + int IsTaxi(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsTaxi()); + return 1; + } + + /** + * Returns true if the [Unit] is a spirit healer. + * + * @return bool isSpiritHealer + */ + int IsSpiritHealer(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsSpiritHealer()); + return 1; + } + + /** + * Returns true if the [Unit] is a spirit guide. + * + * @return bool isSpiritGuide + */ + int IsSpiritGuide(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsSpiritGuide()); + return 1; + } + + /** + * Returns true if the [Unit] is a tabard designer. + * + * @return bool isTabardDesigner + */ + int IsTabardDesigner(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsTabardDesigner()); + return 1; + } + + /** + * Returns true if the [Unit] provides services like vendor, training and auction. + * + * @return bool isTabardDesigner + */ + int IsServiceProvider(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsServiceProvider()); + return 1; + } + + /** + * Returns true if the [Unit] is a spirit guide or spirit healer. + * + * @return bool isSpiritService + */ + int IsSpiritService(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsSpiritService()); + return 1; + } + + /** + * Returns true if the [Unit] is alive. + * + * @return bool isAlive + */ + int IsAlive(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsAlive()); + return 1; + } + + /** + * Returns true if the [Unit] is dead. + * + * @return bool isDead + */ + int IsDead(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->isDead()); + return 1; + } + + /** + * Returns true if the [Unit] is dying. + * + * @return bool isDying + */ + int IsDying(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->isDying()); + return 1; + } + + /** + * Returns true if the [Unit] is a banker. + * + * @return bool isBanker + */ + int IsBanker(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsBanker()); + return 1; + } + + /** + * Returns true if the [Unit] is a vendor. + * + * @return bool isVendor + */ + int IsVendor(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsVendor()); + return 1; + } + + /** + * Returns true if the [Unit] is a battle master. + * + * @return bool isBattleMaster + */ + int IsBattleMaster(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsBattleMaster()); + return 1; + } + + /** + * Returns true if the [Unit] is a charmed. + * + * @return bool isCharmed + */ + int IsCharmed(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsCharmed()); + return 1; + } + + /** + * Returns true if the [Unit] is an armorer and can repair equipment. + * + * @return bool isArmorer + */ + int IsArmorer(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsArmorer()); + return 1; + } + + /** + * Returns true if the [Unit] is attacking a player. + * + * @return bool isAttackingPlayer + */ + int IsAttackingPlayer(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->isAttackingPlayer()); + return 1; + } + + /** + * Returns true if the [Unit] flagged for PvP. + * + * @return bool isPvP + */ + int IsPvPFlagged(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsPvP()); + return 1; + } + +#ifndef CLASSIC + /** + * Returns true if the [Unit] is on a [Vehicle]. + * + * @return bool isOnVehicle + */ + int IsOnVehicle(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetVehicle()); + return 1; + } +#endif + + /** + * Returns true if the [Unit] is in combat. + * + * @return bool inCombat + */ + int IsInCombat(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsInCombat()); + return 1; + } + + /** + * Returns true if the [Unit] is under water. + * + * @return bool underWater + */ + int IsUnderWater(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsUnderWater()); + return 1; + } + + /** + * Returns true if the [Unit] is in water. + * + * @return bool inWater + */ + int IsInWater(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsInWater()); + return 1; + } + + /** + * Returns true if the [Unit] is not moving. + * + * @return bool notMoving + */ + int IsStopped(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsStopped()); + return 1; + } + + /** + * Returns true if the [Unit] is a quest giver. + * + * @return bool questGiver + */ + int IsQuestGiver(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsQuestGiver()); + return 1; + } + + /** + * Returns true if the [Unit]'s health is below the given percentage. + * + * @param int32 healthpct : percentage in integer from + * @return bool isBelow + */ + int HealthBelowPct(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->HealthBelowPct(Eluna::CHECKVAL(L, 2))); + return 1; + } + + /** + * Returns true if the [Unit]'s health is above the given percentage. + * + * @param int32 healthpct : percentage in integer from + * @return bool isAbove + */ + int HealthAbovePct(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->HealthAbovePct(Eluna::CHECKVAL(L, 2))); + return 1; + } + + /** + * Returns true if the [Unit] has an aura from the given spell entry. + * + * @param uint32 spell : entry of the aura spell + * @return bool hasAura + */ + int HasAura(lua_State* L, Unit* unit) + { + uint32 spell = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, unit->HasAura(spell)); + return 1; + } + + /** + * Returns true if the [Unit] is casting a spell + * + * @return bool isCasting + */ + int IsCasting(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->HasUnitState(UNIT_STATE_CASTING)); + return 1; + } + + /** + * Returns true if the [Unit] has the given unit state. + * + * @param [UnitState] state : an unit state + * @return bool hasState + */ + int HasUnitState(lua_State* L, Unit* unit) + { + uint32 state = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, unit->HasUnitState(state)); + return 1; + } + + /*int IsVisible(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsVisible()); + return 1; + }*/ + + /*int IsMoving(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->isMoving()); + return 1; + }*/ + + /*int IsFlying(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->IsFlying()); + return 1; + }*/ + + /** + * Returns the [Unit]'s owner. + * + * @return [Unit] owner + */ + int GetOwner(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetOwner()); + return 1; + } + + /** + * Returns the [Unit]'s owner's GUID. + * + * @return ObjectGuid ownerGUID + */ + int GetOwnerGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetOwnerGUID()); + return 1; + } + + /** + * Returns the [Unit]'s mount's modelID. + * + * @return uint32 mountId : displayId of the mount + */ + int GetMountId(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetMountID()); + return 1; + } + + /** + * Returns the [Unit]'s creator's GUID. + * + * @return ObjectGuid creatorGUID + */ + int GetCreatorGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCreatorGUID()); + return 1; + } + + /** + * Returns the [Unit]'s charmer's GUID. + * + * @return ObjectGuid charmerGUID + */ + int GetCharmerGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCharmerGUID()); + return 1; + } + + /** + * Returns the GUID of the [Unit]'s charmed entity. + * + * @return ObjectGuid charmedGUID + */ + int GetCharmGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCharmGUID()); + return 1; + } + + /** + * Returns the GUID of the [Unit]'s pet. + * + * @return ObjectGuid petGUID + */ + int GetPetGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetPetGUID()); + return 1; + } + + /** + * Returns the GUID of the [Unit]'s charmer or owner. + * + * @return ObjectGuid controllerGUID + */ + int GetControllerGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCharmerOrOwnerGUID()); + return 1; + } + + /** + * Returns the GUID of the [Unit]'s charmer or owner or its own GUID. + * + * @return ObjectGuid controllerGUID + */ + int GetControllerGUIDS(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCharmerOrOwnerOrOwnGUID()); + return 1; + } + + /** + * Returns [Unit]'s specified stat + * + * @param uint32 statType + * @return float stat + */ + int GetStat(lua_State* L, Unit* unit) + { + uint32 stat = Eluna::CHECKVAL(L, 2); + + if (stat >= MAX_STATS) + return 1; + + Eluna::Push(L, unit->GetStat((Stats)stat)); + return 1; + } + + /** + * Returns the [Unit]'s base spell power + * + * @param uint32 spellSchool + * @return uint32 spellPower + */ + int GetBaseSpellPower(lua_State* L, Unit* unit) + { + uint32 spellschool = Eluna::CHECKVAL(L, 2); + + if (spellschool >= MAX_SPELL_SCHOOL) + return 1; + + Eluna::Push(L, unit->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + spellschool)); + return 1; + } + + /** + * Returns the [Unit]'s current victim target or nil. + * + * @return [Unit] victim + */ + int GetVictim(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetVictim()); + return 1; + } + + /** + * Returns the currently casted [Spell] of given type or nil. + * + *
+     * enum CurrentSpellTypes
+     * {
+     *     CURRENT_MELEE_SPELL             = 0,
+     *     CURRENT_GENERIC_SPELL           = 1,
+     *     CURRENT_CHANNELED_SPELL         = 2,
+     *     CURRENT_AUTOREPEAT_SPELL        = 3
+     * };
+     * 
+ * + * @param [CurrentSpellTypes] spellType + * @return [Spell] castedSpell + */ + int GetCurrentSpell(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type >= CURRENT_MAX_SPELL) + return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); + + Eluna::Push(L, unit->GetCurrentSpell(type)); + return 1; + } + + /** + * Returns the [Unit]'s current stand state. + * + * @return uint8 standState + */ + int GetStandState(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getStandState()); + return 1; + } + + /** + * Returns the [Unit]'s current display ID. + * + * @return uint32 displayId + */ + int GetDisplayId(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetDisplayId()); + return 1; + } + + /** + * Returns the [Unit]'s native/original display ID. + * + * @return uint32 displayId + */ + int GetNativeDisplayId(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetNativeDisplayId()); + return 1; + } + + /** + * Returns the [Unit]'s level. + * + * @return uint8 level + */ + int GetLevel(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetLevel()); + return 1; + } + + /** + * Returns the [Unit]'s health amount. + * + * @return uint32 healthAmount + */ + int GetHealth(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetHealth()); + return 1; + } + + Powers PowerSelectorHelper(lua_State* L, Unit* unit, int powerType = -1) + { + if (powerType == -1) + return unit->getPowerType(); + + if (powerType < 0 || powerType >= int(MAX_POWERS)) + luaL_argerror(L, 2, "valid Powers expected"); + + return (Powers)powerType; + } + + /** + * Returns the [Unit]'s power amount for given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + * @return uint32 powerAmount + */ + int GetPower(lua_State* L, Unit* unit) + { + int type = Eluna::CHECKVAL(L, 2, -1); + Powers power = PowerSelectorHelper(L, unit, type); + + Eluna::Push(L, unit->GetPower(power)); + return 1; + } + + /** + * Returns the [Unit]'s max power amount for given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + * @return uint32 maxPowerAmount + */ + int GetMaxPower(lua_State* L, Unit* unit) + { + int type = Eluna::CHECKVAL(L, 2, -1); + Powers power = PowerSelectorHelper(L, unit, type); + + Eluna::Push(L, unit->GetMaxPower(power)); + return 1; + } + + /** + * Returns the [Unit]'s power percent for given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + * @return float powerPct + */ + int GetPowerPct(lua_State* L, Unit* unit) + { + int type = Eluna::CHECKVAL(L, 2, -1); + Powers power = PowerSelectorHelper(L, unit, type); + + float percent = ((float)unit->GetPower(power) / (float)unit->GetMaxPower(power)) * 100.0f; + + Eluna::Push(L, percent); + return 1; + } + + /** + * Returns the [Unit]'s current power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @return [Powers] powerType + */ + int GetPowerType(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getPowerType()); + return 1; + } + + /** + * Returns the [Unit]'s max health. + * + * @return uint32 maxHealth + */ + int GetMaxHealth(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetMaxHealth()); + return 1; + } + + /** + * Returns the [Unit]'s health percent. + * + * @return float healthPct + */ + int GetHealthPct(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetHealthPct()); + return 1; + } + + /** + * Returns the [Unit]'s gender. + * + * @return uint8 gender : 0 for male, 1 for female and 2 for none + */ + int GetGender(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getGender()); + return 1; + } + + /** + * Returns the [Unit]'s race ID. + * + * @return [Races] race + */ + int GetRace(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getRace()); + return 1; + } + + /** + * Returns the [Unit]'s class ID. + * + * @return [Classes] class + */ + int GetClass(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getClass()); + return 1; + } + + /** + * Returns the race mask + * + * @return uint32 racemask + */ + int GetRaceMask(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getRaceMask()); + return 1; + } + + /** + * Returns the class mask + * + * @return uint32 classmask + */ + int GetClassMask(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->getClassMask()); + return 1; + } + + /** + * Returns the [Unit]'s creature type ID (enumerated in CreatureType.dbc). + * + *
+     * enum CreatureType
+     * {
+     *     CREATURE_TYPE_BEAST            = 1,
+     *     CREATURE_TYPE_DRAGONKIN        = 2,
+     *     CREATURE_TYPE_DEMON            = 3,
+     *     CREATURE_TYPE_ELEMENTAL        = 4,
+     *     CREATURE_TYPE_GIANT            = 5,
+     *     CREATURE_TYPE_UNDEAD           = 6,
+     *     CREATURE_TYPE_HUMANOID         = 7,
+     *     CREATURE_TYPE_CRITTER          = 8,
+     *     CREATURE_TYPE_MECHANICAL       = 9,
+     *     CREATURE_TYPE_NOT_SPECIFIED    = 10,
+     *     CREATURE_TYPE_TOTEM            = 11,
+     *     CREATURE_TYPE_NON_COMBAT_PET   = 12,     // This and below is TBC+
+     *     CREATURE_TYPE_GAS_CLOUD        = 13
+     * };
+     * 
+ * + * @return [CreatureType] creatureType + */ + int GetCreatureType(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCreatureType()); + return 1; + } + + /** + * Returns the [Unit]'s class' name in given or default locale or nil. + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE + * @return string className : class name or nil + */ + int GetClassAsString(lua_State* L, Unit* unit) + { + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + + const ChrClassesEntry* entry = sChrClassesStore.LookupEntry(unit->getClass()); + if (!entry) + return 1; + + Eluna::Push(L, entry->name[locale]); + return 1; + } + + /** + * Returns the [Unit]'s race's name in given or default locale or nil. + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the race name in + * @return string raceName : race name or nil + */ + int GetRaceAsString(lua_State* L, Unit* unit) + { + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + + const ChrRacesEntry* entry = sChrRacesStore.LookupEntry(unit->getRace()); + if (!entry) + return 1; + + Eluna::Push(L, entry->name[locale]); + return 1; + } + + /** + * Returns the [Unit]'s faction ID. + * + * @return uint32 faction + */ + int GetFaction(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetFaction()); + return 1; + } + + /** + * Returns the [Aura] of the given spell entry on the [Unit] or nil. + * + * @param uint32 spellID : entry of the aura spell + * @return [Aura] aura : aura object or nil + */ + int GetAura(lua_State* L, Unit* unit) + { + uint32 spellID = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, unit->GetAura(spellID)); + return 1; + } + + /** + * Returns a table containing friendly [Unit]'s within given range of the [Unit]. + * + * @param float range = 533.333 : search radius + * @return table friendyUnits : table filled with friendly units + */ + int GetFriendlyUnitsInRange(lua_State* L, Unit* unit) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + + std::list list; + + Acore::AnyFriendlyUnitInObjectRangeCheck checker(unit, unit, range); + Acore::UnitListSearcher searcher(unit, list, checker); + Cell::VisitAllObjects(unit, searcher, range); + + ElunaUtil::ObjectGUIDCheck guidCheck(unit->GET_GUID()); + list.remove_if(guidCheck); + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns a table containing unfriendly [Unit]'s within given range of the [Unit]. + * + * @param float range = 533.333 : search radius + * @return table unfriendyUnits : table filled with unfriendly units + */ + int GetUnfriendlyUnitsInRange(lua_State* L, Unit* unit) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + + std::list list; + Acore::AnyUnfriendlyUnitInObjectRangeCheck checker(unit, unit, range); + Acore::UnitListSearcher searcher(unit, list, checker); + Cell::VisitAllObjects(unit, searcher, range); + ElunaUtil::ObjectGUIDCheck guidCheck(unit->GET_GUID()); + list.remove_if(guidCheck); + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Returns [Unit]'s [Vehicle] methods + * + * @return [Vehicle] vehicle + */ + int GetVehicleKit(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetVehicleKit()); + return 1; + } + + /* + int GetVehicle(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetVehicle()); + return 1; + } + */ + + /** + * Returns the Critter Guid + * + * @return ObjectGuid critterGuid + */ + int GetCritterGUID(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetCritterGUID()); + return 1; + } +#endif + + /** + * Returns the [Unit]'s speed of given [UnitMoveType]. + * + *
+     * enum UnitMoveType
+     * {
+     *     MOVE_WALK           = 0,
+     *     MOVE_RUN            = 1,
+     *     MOVE_RUN_BACK       = 2,
+     *     MOVE_SWIM           = 3,
+     *     MOVE_SWIM_BACK      = 4,
+     *     MOVE_TURN_RATE      = 5,
+     *     MOVE_FLIGHT         = 6,
+     *     MOVE_FLIGHT_BACK    = 7,
+     *     MOVE_PITCH_RATE     = 8
+     * };
+     * 
+ * + * @param [UnitMoveType] type + * @return float speed + */ + int GetSpeed(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type >= MAX_MOVE_TYPE) + return luaL_argerror(L, 2, "valid UnitMoveType expected"); + + Eluna::Push(L, unit->GetSpeed((UnitMoveType)type)); + + return 1; + } + + /** + * Returns the [Unit]'s speed rate of given [UnitMoveType]. + * + *
+    * enum UnitMoveType
+    * {
+    *     MOVE_WALK           = 0,
+    *     MOVE_RUN            = 1,
+    *     MOVE_RUN_BACK       = 2,
+    *     MOVE_SWIM           = 3,
+    *     MOVE_SWIM_BACK      = 4,
+    *     MOVE_TURN_RATE      = 5,
+    *     MOVE_FLIGHT         = 6,
+    *     MOVE_FLIGHT_BACK    = 7,
+    *     MOVE_PITCH_RATE     = 8
+    * };
+    * 
+ * + * @param [UnitMoveType] type + * @return float speed + */ + int GetSpeedRate(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type >= MAX_MOVE_TYPE) + { + return luaL_argerror(L, 2, "valid UnitMoveType expected"); + } + + Eluna::Push(L, unit->GetSpeedRate((UnitMoveType)type)); + + return 1; + } + + /** + * Returns the current movement type for this [Unit]. + * + *
+     * enum MovementGeneratorType
+     * {
+     *     IDLE_MOTION_TYPE                = 0,
+     *     RANDOM_MOTION_TYPE              = 1,
+     *     WAYPOINT_MOTION_TYPE            = 2,
+     *     MAX_DB_MOTION_TYPE              = 3,
+     *     ANIMAL_RANDOM_MOTION_TYPE       = 3, // TC
+     *
+     *     CONFUSED_MOTION_TYPE            = 4,
+     *     CHASE_MOTION_TYPE               = 5,
+     *     HOME_MOTION_TYPE                = 6,
+     *     FLIGHT_MOTION_TYPE              = 7,
+     *     POINT_MOTION_TYPE               = 8,
+     *     FLEEING_MOTION_TYPE             = 9,
+     *     DISTRACT_MOTION_TYPE            = 10,
+     *     ASSISTANCE_MOTION_TYPE          = 11,
+     *     ASSISTANCE_DISTRACT_MOTION_TYPE = 12,
+     *     TIMED_FLEEING_MOTION_TYPE       = 13,
+     *     FOLLOW_MOTION_TYPE              = 14,
+     *     EFFECT_MOTION_TYPE              = 15, // mangos
+     *     ROTATE_MOTION_TYPE              = 15, // TC
+     *     EFFECT_MOTION_TYPE              = 16, // TC
+     *     NULL_MOTION_TYPE                = 17, // TC
+     * };
+     * 
+ * + * @return [MovementGeneratorType] movementType + */ + int GetMovementType(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->GetMotionMaster()->GetCurrentMovementGeneratorType()); + return 1; + } + + /** + * Returns the [Unit]'s attackers. + * + * @return table attackers : table of [Unit]s attacking the unit + */ + int GetAttackers(lua_State* L, Unit* unit) + { + const Unit::AttackerSet& attackers = unit->getAttackers(); + + lua_newtable(L); + int table = lua_gettop(L); + uint32 i = 1; + for (Unit* attacker : attackers) + { + if (!attacker) + { + continue; + } + + Eluna::Push(L, attacker); + lua_rawseti(L, table, i); + ++i; + } + + lua_settop(L, table); // push table to top of stack + return 1; + } + + /** + * Sets the [Unit]'s owner GUID to given GUID. + * + * @param ObjectGuid guid : new owner guid + */ + int SetOwnerGUID(lua_State* L, Unit* unit) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + + unit->SetOwnerGUID(guid); + return 0; + } + + /** + * Sets the [Unit]'s PvP on or off. + * + * @param bool apply = true : true if set on, false if off + */ + int SetPvP(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + unit->SetPvP(apply); + return 0; + } + + /** + * Sets the [Unit]'s sheath state. + * + * enum SheathState + * { + * SHEATH_STATE_UNARMED = 0, // non prepared weapon + * SHEATH_STATE_MELEE = 1, // prepared melee weapon + * SHEATH_STATE_RANGED = 2 // prepared ranged weapon + * }; + * + * @param [SheathState] sheathState : valid SheathState + */ + int SetSheath(lua_State* L, Unit* unit) + { + uint32 sheathed = Eluna::CHECKVAL(L, 2); + if (sheathed >= MAX_SHEATH_STATE) + return luaL_argerror(L, 2, "valid SheathState expected"); + + unit->SetSheath((SheathState)sheathed); + return 0; + } + + /** + * Sets the [Unit]'s name internally. + * + * @param string name : new name + */ + int SetName(lua_State* L, Unit* unit) + { + const char* name = Eluna::CHECKVAL(L, 2); + if (std::string(name).length() > 0) + unit->SetName(name); + return 0; + } + + /** + * Sets the [Unit]'s speed of given [UnitMoveType] to given speed. + * If forced, packets sent to clients forcing the visual change. + * + *
+     * enum UnitMoveType
+     * {
+     *     MOVE_WALK           = 0,
+     *     MOVE_RUN            = 1,
+     *     MOVE_RUN_BACK       = 2,
+     *     MOVE_SWIM           = 3,
+     *     MOVE_SWIM_BACK      = 4,
+     *     MOVE_TURN_RATE      = 5,
+     *     MOVE_FLIGHT         = 6,
+     *     MOVE_FLIGHT_BACK    = 7,
+     *     MOVE_PITCH_RATE     = 8
+     * };
+     * 
+ * + * @param [UnitMoveType] type + * @param float rate + * @param bool forced = false + */ + int SetSpeed(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + float rate = Eluna::CHECKVAL(L, 3); + bool forced = Eluna::CHECKVAL(L, 4, false); + (void)forced; // ensure that the variable is referenced in order to pass compiler checks + if (type >= MAX_MOVE_TYPE) + return luaL_argerror(L, 2, "valid UnitMoveType expected"); + + unit->SetSpeed((UnitMoveType)type, rate); + + return 0; + } + + /** + * Sets the [Unit]'s speed rate of given [UnitMoveType] to given rate. + * If forced, packets sent to clients forcing the visual change. + * + *
+     * enum UnitMoveType
+     * {
+     *     MOVE_WALK           = 0,
+     *     MOVE_RUN            = 1,
+     *     MOVE_RUN_BACK       = 2,
+     *     MOVE_SWIM           = 3,
+     *     MOVE_SWIM_BACK      = 4,
+     *     MOVE_TURN_RATE      = 5,
+     *     MOVE_FLIGHT         = 6,
+     *     MOVE_FLIGHT_BACK    = 7,
+     *     MOVE_PITCH_RATE     = 8
+     * };
+     * 
+ * + * @param [UnitMoveType] type + * @param float rate + * @param bool forced = false + */ + int SetSpeedRate(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + float rate = Eluna::CHECKVAL(L, 3); + if (type >= MAX_MOVE_TYPE) + return luaL_argerror(L, 2, "valid UnitMoveType expected"); + + unit->SetSpeedRate((UnitMoveType)type, rate); + + return 0; + } + + /** + * Sets the [Unit]'s faction. + * + * @param uint32 faction : new faction ID + */ + int SetFaction(lua_State* L, Unit* unit) + { + uint32 factionId = Eluna::CHECKVAL(L, 2); + + unit->SetFaction(factionId); + + return 0; + } + + /** + * Sets the [Unit]'s level. + * + * @param uint8 level : new level + */ + int SetLevel(lua_State* L, Unit* unit) + { + uint8 newlevel = Eluna::CHECKVAL(L, 2); + + if (newlevel < 1) + return luaL_argerror(L, 2, "level cannot be below 1"); + + if (Player* player = unit->ToPlayer()) + { + player->GiveLevel(newlevel); + player->InitTalentForLevel(); + player->SetUInt32Value(PLAYER_XP, 0); + } + else + unit->SetLevel(newlevel); + + return 0; + } + + /** + * Sets the [Unit]'s health. + * + * @param uint32 health : new health + */ + int SetHealth(lua_State* L, Unit* unit) + { + uint32 amt = Eluna::CHECKVAL(L, 2); + unit->SetHealth(amt); + return 0; + } + + /** + * Sets the [Unit]'s max health. + * + * @param uint32 maxHealth : new max health + */ + int SetMaxHealth(lua_State* L, Unit* unit) + { + uint32 amt = Eluna::CHECKVAL(L, 2); + unit->SetMaxHealth(amt); + return 0; + } + + /** + * Sets the [Unit]'s power amount for the given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param uint32 amount : new power amount + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + */ + int SetPower(lua_State* L, Unit* unit) + { + uint32 amt = Eluna::CHECKVAL(L, 2); + int type = Eluna::CHECKVAL(L, 3, -1); + Powers power = PowerSelectorHelper(L, unit, type); + + unit->SetPower(power, amt); + return 0; + } + + /** + * modifies the [Unit]'s power amount for the given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param int32 amount : amount to modify + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + */ + int ModifyPower(lua_State* L, Unit* unit) + { + int32 amt = Eluna::CHECKVAL(L, 2); + int type = Eluna::CHECKVAL(L, 3, -1); + Powers power = PowerSelectorHelper(L, unit, type); + + unit->ModifyPower(power, amt); + return 0; + } + + /** + * Sets the [Unit]'s max power amount for the given power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param int type = -1 : a valid power type from [Powers] or -1 for the [Unit]'s current power type + * @param uint32 maxPower : new max power amount + */ + int SetMaxPower(lua_State* L, Unit* unit) + { + int type = Eluna::CHECKVAL(L, 2, -1); + uint32 amt = Eluna::CHECKVAL(L, 3); + Powers power = PowerSelectorHelper(L, unit, type); + + unit->SetMaxPower(power, amt); + return 0; + } + + /** + * Sets the [Unit]'s power type. + * + * enum Powers + * { + * POWER_MANA = 0, + * POWER_RAGE = 1, + * POWER_FOCUS = 2, + * POWER_ENERGY = 3, + * POWER_HAPPINESS = 4, + * POWER_RUNE = 5, + * POWER_RUNIC_POWER = 6, + * MAX_POWERS = 7, + * POWER_ALL = 127, // default for class? + * POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + * }; + * + * @param [Powers] type : a valid power type + */ + int SetPowerType(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type >= int(MAX_POWERS)) + return luaL_argerror(L, 2, "valid Powers expected"); + + unit->setPowerType((Powers)type); + return 0; + } + + /** + * Sets the [Unit]'s modelID. + * + * @param uint32 displayId + */ + int SetDisplayId(lua_State* L, Unit* unit) + { + uint32 model = Eluna::CHECKVAL(L, 2); + unit->SetDisplayId(model); + return 0; + } + + /** + * Sets the [Unit]'s native/default modelID. + * + * @param uint32 displayId + */ + int SetNativeDisplayId(lua_State* L, Unit* unit) + { + uint32 model = Eluna::CHECKVAL(L, 2); + unit->SetNativeDisplayId(model); + return 0; + } + + /** + * Sets the [Unit]'s facing/orientation. + * + * @param uint32 orientation + */ + int SetFacing(lua_State* L, Unit* unit) + { + float o = Eluna::CHECKVAL(L, 2); + unit->SetFacingTo(o); + return 0; + } + + /** + * Sets the [Unit] to face the given [WorldObject]'s direction. + * + * @param [WorldObject] target + */ + int SetFacingToObject(lua_State* L, Unit* unit) + { + WorldObject* obj = Eluna::CHECKOBJ(L, 2); + unit->SetFacingToObject(obj); + return 0; + } + + /** + * Sets creator GUID + * + * @param ObjectGuid guid + */ + int SetCreatorGUID(lua_State* L, Unit* unit) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + unit->SetCreatorGUID(guid); + return 0; + } + + /** + * Sets pet GUID + * + * @param ObjectGuid guid + */ + int SetPetGUID(lua_State* L, Unit* unit) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + unit->SetPetGUID(guid); + return 0; + } + + /** + * Toggles (Sets) [Unit]'s water walking + * + * @param bool enable = true + */ + int SetWaterWalk(lua_State* L, Unit* unit) + { + bool enable = Eluna::CHECKVAL(L, 2, true); + unit->SetWaterWalking(enable); + return 0; + } + + /** + * Sets the [Unit]'s stand state + * + * @param uint8 state : stand state + */ + int SetStandState(lua_State* L, Unit* unit) + { + uint8 state = Eluna::CHECKVAL(L, 2); + unit->SetStandState(state); + return 0; + } + + /** + * Sets the [Unit] in combat with the `enemy` [Unit]. + * + * @param [Unit] enemy : the [Unit] to start combat with + */ + int SetInCombatWith(lua_State* L, Unit* unit) + { + Unit* enemy = Eluna::CHECKOBJ(L, 2); + unit->SetInCombatWith(enemy); + return 0; + } + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Sets the [Unit]'s FFA flag on or off. + * + * @param bool apply = true + */ + int SetFFA(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + if (apply) + { + unit->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + for (Unit::ControlSet::iterator itr = unit->m_Controlled.begin(); itr != unit->m_Controlled.end(); ++itr) + (*itr)->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + } + else + { + unit->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + for (Unit::ControlSet::iterator itr = unit->m_Controlled.begin(); itr != unit->m_Controlled.end(); ++itr) + (*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + } + return 0; + } + + /** + * Sets the [Unit]'s sanctuary flag on or off. + * + * @param bool apply = true + */ + int SetSanctuary(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + if (apply) + { + unit->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); + unit->CombatStop(); + unit->CombatStopWithPets(); + } + else + unit->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); + + return 0; + } + + int SetCritterGUID(lua_State* L, Unit* unit) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + unit->SetCritterGUID(guid); + return 0; + } +#endif + + /*int SetStunned(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + unit->SetControlled(apply, UNIT_STATE_STUNNED); + return 0; + }*/ + + /** + * Roots the [Unit] to the ground, if 'false' specified, unroots the [Unit]. + * + * @param bool apply = true + */ + int SetRooted(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + unit->SetControlled(apply, UNIT_STATE_ROOT); + return 0; + } + + /** + * Confuses the [Unit], if 'false' specified, the [Unit] is no longer confused. + * + * @param bool apply = true + */ + int SetConfused(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + unit->SetControlled(apply, UNIT_STATE_CONFUSED); + return 0; + } + + /** + * Fears the [Unit], if 'false' specified, the [Unit] is no longer feared. + * + * @param bool apply = true + */ + int SetFeared(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + unit->SetControlled(apply, UNIT_STATE_FLEEING); + return 0; + } + + /*int SetCanFly(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + unit->SetCanFly(apply); + return 0; + }*/ + + /*int SetVisible(lua_State* L, Unit* unit) + { + bool x = Eluna::CHECKVAL(L, 2, true); + unit->SetVisible(x); + return 0; + }*/ + + /** + * Clears the [Unit]'s threat list. + */ + int ClearThreatList(lua_State* /*L*/, Unit* unit) + { + unit->GetThreatMgr().ClearAllThreat(); + return 0; + } + + /** + * Returns the [Unit]'s threat list. + * + * @return table threatList : table of [Unit]s in the threat list + */ + int GetThreatList(lua_State* L, Unit* unit) + { + if (!unit->CanHaveThreatList()) + { + Eluna::Push(L); + return 1; + } + + ThreatContainer::StorageType const& list = unit->GetThreatMgr().GetThreatList(); + + lua_newtable(L); + int table = lua_gettop(L); + uint32 i = 1; + for (ThreatReference* item : list) + { + if (!item) + { + continue; + } + Unit* victim = item->GetVictim(); + if (!victim) + { + continue; + } + + Eluna::Push(L, victim); + lua_rawseti(L, table, i); + ++i; + } + + lua_settop(L, table); // push table to top of stack + return 1; + } + + /** + * Mounts the [Unit] on the given displayID/modelID. + * + * @param uint32 displayId + */ + int Mount(lua_State* L, Unit* unit) + { + uint32 displayId = Eluna::CHECKVAL(L, 2); + + unit->Mount(displayId); + return 0; + } + + /** + * Dismounts the [Unit]. + */ + int Dismount(lua_State* /*L*/, Unit* unit) + { + if (unit->IsMounted()) + { + unit->Dismount(); + unit->RemoveAurasByType(SPELL_AURA_MOUNTED); + } + + return 0; + } + + /** + * Makes the [Unit] perform the given emote. + * + * @param uint32 emoteId + */ + int PerformEmote(lua_State* L, Unit* unit) + { + unit->HandleEmoteCommand(Eluna::CHECKVAL(L, 2)); + return 0; + } + + /** + * Makes the [Unit] perform the given emote continuously. + * + * @param uint32 emoteId + */ + int EmoteState(lua_State* L, Unit* unit) + { + uint32 emoteId = Eluna::CHECKVAL(L, 2); + + unit->SetUInt32Value(UNIT_NPC_EMOTESTATE, emoteId); + return 0; + } + + /** + * Returns calculated percentage from Health + * + * @return int32 percentage + */ + int CountPctFromCurHealth(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->CountPctFromCurHealth(Eluna::CHECKVAL(L, 2))); + return 1; + } + + /** + * Returns calculated percentage from Max Health + * + * @return int32 percentage + */ + int CountPctFromMaxHealth(lua_State* L, Unit* unit) + { + Eluna::Push(L, unit->CountPctFromMaxHealth(Eluna::CHECKVAL(L, 2))); + return 1; + } + + /** + * Sends chat message to [Player] + * + * @param uint8 type : chat, whisper, etc + * @param uint32 lang : language to speak + * @param string msg + * @param [Player] target + */ + int SendChatMessageToPlayer(lua_State* L, Unit* unit) + { + uint8 type = Eluna::CHECKVAL(L, 2); + uint32 lang = Eluna::CHECKVAL(L, 3); + std::string msg = Eluna::CHECKVAL(L, 4); + Player* target = Eluna::CHECKOBJ(L, 5); + + if (type >= MAX_CHAT_MSG_TYPE) + return luaL_argerror(L, 2, "valid ChatMsg expected"); + if (lang >= LANGUAGES_COUNT) + return luaL_argerror(L, 3, "valid Language expected"); + + WorldPacket data; + ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), unit, target, msg); + target->GetSession()->SendPacket(&data); + return 0; + } + + /*static void PrepareMove(Unit* unit) + { + unit->GetMotionMaster()->MovementExpired(); // Chase + unit->StopMoving(); // Some + unit->GetMotionMaster()->Clear(); // all + }*/ + + /** + * Stops the [Unit]'s movement + */ + int MoveStop(lua_State* /*L*/, Unit* unit) + { + unit->StopMoving(); + return 0; + } + + /** + * The [Unit]'s movement expires and clears movement + * + * @param bool reset = true : cleans movement + */ + int MoveExpire(lua_State* L, Unit* unit) + { + bool reset = Eluna::CHECKVAL(L, 2, true); + unit->GetMotionMaster()->MovementExpired(reset); + return 0; + } + + /** + * Clears the [Unit]'s movement + * + * @param bool reset = true : clean movement + */ + int MoveClear(lua_State* L, Unit* unit) + { + bool reset = Eluna::CHECKVAL(L, 2, true); + unit->GetMotionMaster()->Clear(reset); + return 0; + } + + /** + * The [Unit] will be idle + */ + int MoveIdle(lua_State* /*L*/, Unit* unit) + { + unit->GetMotionMaster()->MoveIdle(); + return 0; + } + + /** + * The [Unit] will move at random + * + * @param float radius : limit on how far the [Unit] will move at random + */ + int MoveRandom(lua_State* L, Unit* unit) + { + float radius = Eluna::CHECKVAL(L, 2); + float x, y, z; + unit->GetPosition(x, y, z); + unit->GetMotionMaster()->MoveRandom(radius); + return 0; + } + + /** + * The [Unit] will move to its set home location + */ + int MoveHome(lua_State* /*L*/, Unit* unit) + { + unit->GetMotionMaster()->MoveTargetedHome(); + return 0; + } + + /** + * The [Unit] will follow the target + * + * @param [Unit] target : target to follow + * @param float dist = 0 : distance to start following + * @param float angle = 0 + */ + int MoveFollow(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + float dist = Eluna::CHECKVAL(L, 3, 0.0f); + float angle = Eluna::CHECKVAL(L, 4, 0.0f); + unit->GetMotionMaster()->MoveFollow(target, dist, angle); + return 0; + } + + /** + * The [Unit] will chase the target + * + * @param [Unit] target : target to chase + * @param float dist = 0 : distance start chasing + * @param float angle = 0 + */ + int MoveChase(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + float dist = Eluna::CHECKVAL(L, 3, 0.0f); + float angle = Eluna::CHECKVAL(L, 4, 0.0f); + unit->GetMotionMaster()->MoveChase(target, dist, angle); + return 0; + } + + /** + * The [Unit] will move confused + */ + int MoveConfused(lua_State* /*L*/, Unit* unit) + { + unit->GetMotionMaster()->MoveConfused(); + return 0; + } + + /** + * The [Unit] will flee + * + * @param [Unit] target + * @param uint32 time = 0 : flee delay + */ + int MoveFleeing(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + uint32 time = Eluna::CHECKVAL(L, 3, 0); + unit->GetMotionMaster()->MoveFleeing(target, time); + return 0; + } + + /** + * The [Unit] will move to the coordinates + * + * @param uint32 id : unique waypoint Id + * @param float x + * @param float y + * @param float z + * @param bool genPath = true : if true, generates path + */ + int MoveTo(lua_State* L, Unit* unit) + { + uint32 id = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + bool genPath = Eluna::CHECKVAL(L, 6, true); + unit->GetMotionMaster()->MovePoint(id, x, y, z, genPath); + return 0; + } + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Makes the [Unit] jump to the coordinates + * + * @param float x + * @param float y + * @param float z + * @param float zSpeed : start velocity + * @param float maxHeight : maximum height + * @param uint32 id = 0 : unique movement Id + */ + int MoveJump(lua_State* L, Unit* unit) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + float zSpeed = Eluna::CHECKVAL(L, 5); + float maxHeight = Eluna::CHECKVAL(L, 6); + uint32 id = Eluna::CHECKVAL(L, 7, 0); + Position pos(x, y, z); + unit->GetMotionMaster()->MoveJump(pos, zSpeed, maxHeight, id); + return 0; + } +#endif + + /** + * The [Unit] will whisper the message to a [Player] + * + * @param string msg : message for the [Unit] to emote + * @param uint32 lang : language for the [Unit] to speak + * @param [Player] receiver : specific [Unit] to receive the message + * @param bool bossWhisper = false : is a boss whisper + */ + int SendUnitWhisper(lua_State* L, Unit* unit) + { + const char* msg = Eluna::CHECKVAL(L, 2); + uint32 lang = Eluna::CHECKVAL(L, 3); + (void)lang; // ensure that the variable is referenced in order to pass compiler checks + Player* receiver = Eluna::CHECKOBJ(L, 4); + bool bossWhisper = Eluna::CHECKVAL(L, 5, false); + if (std::string(msg).length() > 0) + unit->Whisper(msg, (Language)lang, receiver, bossWhisper); + return 0; + } + + /** + * The [Unit] will emote the message + * + * @param string msg : message for the [Unit] to emote + * @param [Unit] receiver = nil : specific [Unit] to receive the message + * @param bool bossEmote = false : is a boss emote + */ + int SendUnitEmote(lua_State* L, Unit* unit) + { + const char* msg = Eluna::CHECKVAL(L, 2); + Unit* receiver = Eluna::CHECKOBJ(L, 3, false); + bool bossEmote = Eluna::CHECKVAL(L, 4, false); + if (std::string(msg).length() > 0) + unit->TextEmote(msg, receiver, bossEmote); + return 0; + } + + /** + * The [Unit] will say the message + * + * @param string msg : message for the [Unit] to say + * @param uint32 language : language for the [Unit] to speak + */ + int SendUnitSay(lua_State* L, Unit* unit) + { + const char* msg = Eluna::CHECKVAL(L, 2); + uint32 language = Eluna::CHECKVAL(L, 3); + if (std::string(msg).length() > 0) + unit->Say(msg, (Language)language, unit); + return 0; + } + + /** + * The [Unit] will yell the message + * + * @param string msg : message for the [Unit] to yell + * @param uint32 language : language for the [Unit] to speak + */ + int SendUnitYell(lua_State* L, Unit* unit) + { + const char* msg = Eluna::CHECKVAL(L, 2); + uint32 language = Eluna::CHECKVAL(L, 3); + if (std::string(msg).length() > 0) + unit->Yell(msg, (Language)language, unit); + return 0; + } + + /** + * Unmorphs the [Unit] setting it's display ID back to the native display ID. + */ + int DeMorph(lua_State* /*L*/, Unit* unit) + { + unit->DeMorph(); + return 0; + } + + /** + * Makes the [Unit] cast the spell on the target. + * + * @param [Unit] target = nil : can be self or another unit + * @param uint32 spell : entry of a spell + * @param bool triggered = false : if true the spell is instant and has no cost + */ + int CastSpell(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2, false); + uint32 spell = Eluna::CHECKVAL(L, 3); + bool triggered = Eluna::CHECKVAL(L, 4, false); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell); + if (!spellEntry) + return 0; + + unit->CastSpell(target, spell, triggered); + return 0; + } + + /** + * Casts the [Spell] at target [Unit] with custom basepoints or casters. + * See also [Unit:CastSpell]. + * + * @param [Unit] target = nil + * @param uint32 spell + * @param bool triggered = false + * @param int32 bp0 = nil : custom basepoints for [Spell] effect 1. If nil, no change is made + * @param int32 bp1 = nil : custom basepoints for [Spell] effect 2. If nil, no change is made + * @param int32 bp2 = nil : custom basepoints for [Spell] effect 3. If nil, no change is made + * @param [Item] castItem = nil + * @param ObjectGuid originalCaster = ObjectGuid() + */ + int CastCustomSpell(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2, false); + uint32 spell = Eluna::CHECKVAL(L, 3); + bool triggered = Eluna::CHECKVAL(L, 4, false); + bool has_bp0 = !lua_isnoneornil(L, 5); + int32 bp0 = Eluna::CHECKVAL(L, 5, 0); + bool has_bp1 = !lua_isnoneornil(L, 6); + int32 bp1 = Eluna::CHECKVAL(L, 6, 0); + bool has_bp2 = !lua_isnoneornil(L, 7); + int32 bp2 = Eluna::CHECKVAL(L, 7, 0); + Item* castItem = Eluna::CHECKOBJ(L, 8, false); + ObjectGuid originalCaster = Eluna::CHECKVAL(L, 9, ObjectGuid()); + + unit->CastCustomSpell(target, spell, has_bp0 ? &bp0 : NULL, has_bp1 ? &bp1 : NULL, has_bp2 ? &bp2 : NULL, triggered, castItem, NULL, ObjectGuid(originalCaster)); + return 0; + } + + /** + * Makes the [Unit] cast the spell to the given coordinates, used for area effect spells. + * + * @param float x + * @param float y + * @param float z + * @param uint32 spell : entry of a spell + * @param bool triggered = false : if true the spell is instant and has no cost + */ + int CastSpellAoF(lua_State* L, Unit* unit) + { + float _x = Eluna::CHECKVAL(L, 2); + float _y = Eluna::CHECKVAL(L, 3); + float _z = Eluna::CHECKVAL(L, 4); + uint32 spell = Eluna::CHECKVAL(L, 5); + bool triggered = Eluna::CHECKVAL(L, 6, true); + unit->CastSpell(_x, _y, _z, spell, triggered); + return 0; + } + + /** + * Clears the [Unit]'s combat + */ + int ClearInCombat(lua_State* /*L*/, Unit* unit) + { + unit->ClearInCombat(); + return 0; + } + + /** + * Stops the [Unit]'s current spell cast + * + * @param uint32 spell = 0 : entry of a spell + */ + int StopSpellCast(lua_State* L, Unit* unit) + { + uint32 spellId = Eluna::CHECKVAL(L, 2, 0); + unit->CastStop(spellId); + return 0; + } + + /** + * Interrupts [Unit]'s spell state, casting, etc. + * + * if spell is not interruptible, it will return + * + * @param int32 spellType : type of spell to interrupt + * @param bool delayed = true : skips if the spell is delayed + */ + int InterruptSpell(lua_State* L, Unit* unit) + { + int spellType = Eluna::CHECKVAL(L, 2); + bool delayed = Eluna::CHECKVAL(L, 3, true); + switch (spellType) + { + case 0: + spellType = CURRENT_MELEE_SPELL; + break; + case 1: + spellType = CURRENT_GENERIC_SPELL; + break; + case 2: + spellType = CURRENT_CHANNELED_SPELL; + break; + case 3: + spellType = CURRENT_AUTOREPEAT_SPELL; + break; + default: + return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); + } + + unit->InterruptSpell((CurrentSpellTypes)spellType, delayed); + return 0; + } + + /** + * Adds the [Aura] of the given spell entry on the given target from the [Unit]. + * + * @param uint32 spell : entry of a spell + * @param [Unit] target : aura will be applied on the target + * @return [Aura] aura + */ + int AddAura(lua_State* L, Unit* unit) + { + uint32 spell = Eluna::CHECKVAL(L, 2); + Unit* target = Eluna::CHECKOBJ(L, 3); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell); + if (!spellEntry) + return 1; + + Eluna::Push(L, unit->AddAura(spell, target)); + return 1; + } + + /** + * Removes [Aura] of the given spell entry from the [Unit]. + * + * @param uint32 spell : entry of a spell + */ + int RemoveAura(lua_State* L, Unit* unit) + { + uint32 spellId = Eluna::CHECKVAL(L, 2); + unit->RemoveAurasDueToSpell(spellId); + return 0; + } + + /** + * Removes all [Aura]'s from the [Unit]. + * + * Note: talents and racials are also auras, use with caution + */ + int RemoveAllAuras(lua_State* /*L*/, Unit* unit) + { + unit->RemoveAllAuras(); + return 0; + } + +#if !defined(CLASSIC) + /** + * Removes all positive visible [Aura]'s from the [Unit]. + */ + int RemoveArenaAuras(lua_State* /*L*/, Unit* unit) + { + unit->RemoveArenaAuras(); + return 0; + } +#endif + + /** + * Adds the given unit state for the [Unit]. + * + * @param [UnitState] state + */ + int AddUnitState(lua_State* L, Unit* unit) + { + uint32 state = Eluna::CHECKVAL(L, 2); + + unit->AddUnitState(state); + return 0; + } + + /** + * Removes the given unit state from the [Unit]. + * + * @param [UnitState] state + */ + int ClearUnitState(lua_State* L, Unit* unit) + { + uint32 state = Eluna::CHECKVAL(L, 2); + + unit->ClearUnitState(state); + return 0; + } + + /** + * Makes the [Unit] teleport to given coordinates within same map. + * + * @param float x + * @param float y + * @param float z + * @param float o : orientation + */ + int NearTeleport(lua_State* L, Unit* unit) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + float o = Eluna::CHECKVAL(L, 5); + + unit->NearTeleportTo(x, y, z, o); + return 0; + } + + /** + * Makes the [Unit] damage the target [Unit] + * + *
+     * enum SpellSchools
+     * {
+     *     SPELL_SCHOOL_NORMAL  = 0,
+     *     SPELL_SCHOOL_HOLY    = 1,
+     *     SPELL_SCHOOL_FIRE    = 2,
+     *     SPELL_SCHOOL_NATURE  = 3,
+     *     SPELL_SCHOOL_FROST   = 4,
+     *     SPELL_SCHOOL_SHADOW  = 5,
+     *     SPELL_SCHOOL_ARCANE  = 6,
+     *     MAX_SPELL_SCHOOL     = 7
+     * };
+     * 
+ * + * @param [Unit] target : [Unit] to damage + * @param uint32 damage : amount to damage + * @param bool durabilityloss = true : if false, the damage does not do durability damage + * @param [SpellSchools] school = MAX_SPELL_SCHOOL : school the damage is done in or MAX_SPELL_SCHOOL for direct damage + * @param uint32 spell = 0 : spell that inflicts the damage + */ + int DealDamage(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + uint32 damage = Eluna::CHECKVAL(L, 3); + bool durabilityloss = Eluna::CHECKVAL(L, 4, true); + uint32 school = Eluna::CHECKVAL(L, 5, MAX_SPELL_SCHOOL); + uint32 spell = Eluna::CHECKVAL(L, 6, 0); + if (school > MAX_SPELL_SCHOOL) + return luaL_argerror(L, 6, "valid SpellSchool expected"); + + // flat melee damage without resistence/etc reduction + if (school == MAX_SPELL_SCHOOL) + { + Unit::DealDamage(unit, target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, durabilityloss); + unit->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); + return 0; + } + + SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); + + if (Unit::IsDamageReducedByArmor(schoolmask)) + damage = Unit::CalcArmorReducedDamage(unit, target, damage, NULL, BASE_ATTACK); + + if (!spell) + { + DamageInfo dmgInfo(unit, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE); + unit->CalcAbsorbResist(dmgInfo); + + if (!dmgInfo.GetDamage()) + damage = 0; + else + damage = dmgInfo.GetDamage(); + + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + unit->DealDamageMods(target, damage, &absorb); + Unit::DealDamage(unit, target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); + unit->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); + return 0; + } + + if (!spell) + return 0; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell); + if (!spellInfo) + return 0; + + SpellNonMeleeDamage dmgInfo(unit, target, spellInfo, spellInfo->GetSchoolMask()); + Unit::DealDamageMods(dmgInfo.target, dmgInfo.damage, &dmgInfo.absorb); + unit->SendSpellNonMeleeDamageLog(&dmgInfo); + unit->DealSpellDamage(&dmgInfo, true); + return 0; + } + + /** + * Makes the [Unit] heal the target [Unit] with given spell + * + * @param [Unit] target : [Unit] to heal + * @param uint32 spell : spell that causes the healing + * @param uint32 amount : amount to heal + * @param bool critical = false : if true, heal is logged as critical + */ + int DealHeal(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + uint32 spell = Eluna::CHECKVAL(L, 3); + uint32 amount = Eluna::CHECKVAL(L, 4); + bool critical = Eluna::CHECKVAL(L, 5, false); + + if (const SpellInfo* info = sSpellMgr->GetSpellInfo(spell)) + { + HealInfo healInfo(unit, target, amount, info, info->GetSchoolMask()); + unit->HealBySpell(healInfo, critical); + } + return 0; + } + + /** + * Makes the [Unit] kill the target [Unit] + * + * @param [Unit] target : [Unit] to kill + * @param bool durLoss = true : when true, the target's items suffer durability loss + */ + int Kill(lua_State* L, Unit* unit) + { + Unit* target = Eluna::CHECKOBJ(L, 2); + bool durLoss = Eluna::CHECKVAL(L, 3, true); + + Unit::Kill(unit, target, durLoss); + return 0; + } + + /** + * Adds threat to the [Unit] from the victim. + * + *
+     * enum SpellSchoolMask
+     * {
+     *     SPELL_SCHOOL_MASK_NONE    = 0,
+     *     SPELL_SCHOOL_MASK_NORMAL  = 1,
+     *     SPELL_SCHOOL_MASK_HOLY    = 2,
+     *     SPELL_SCHOOL_MASK_FIRE    = 4,
+     *     SPELL_SCHOOL_MASK_NATURE  = 8,
+     *     SPELL_SCHOOL_MASK_FROST   = 16,
+     *     SPELL_SCHOOL_MASK_SHADOW  = 32,
+     *     SPELL_SCHOOL_MASK_ARCANE  = 64,
+     * }
+     * 
+ * + * @param [Unit] victim : [Unit] that caused the threat + * @param float threat : threat amount + * @param [SpellSchoolMask] schoolMask = 0 : [SpellSchoolMask] of the threat causer + * @param uint32 spell = 0 : spell entry used for threat + */ + int AddThreat(lua_State* L, Unit* unit) + { + Unit* victim = Eluna::CHECKOBJ(L, 2); + float threat = Eluna::CHECKVAL(L, 3, true); + uint32 spell = Eluna::CHECKVAL(L, 4, 0); + + uint32 schoolMask = Eluna::CHECKVAL(L, 5, 0); + if (schoolMask > SPELL_SCHOOL_MASK_ALL) + { + return luaL_argerror(L, 4, "valid SpellSchoolMask expected"); + } + unit->AddThreat(victim, threat, (SpellSchoolMask)schoolMask, spell ? sSpellMgr->GetSpellInfo(spell) : NULL); + return 0; + } + + /** + * Modifies threat in pct to the [Unit] from the victim + * + * @param [Unit] victim : [Unit] that caused the threat + * @param int32 percent : threat amount in pct + */ + int ModifyThreatPct(lua_State* L, Unit* unit) + { + Unit* victim = Eluna::CHECKOBJ(L, 2); + int32 threatPct = Eluna::CHECKVAL(L, 3, true); + + unit->GetThreatMgr().ModifyThreatByPercent(victim, threatPct); + return 0; + } + + /*int RestoreDisplayId(lua_State* L, Unit* unit) + { + unit->RestoreDisplayId(); + return 0; + }*/ + + /*int RestoreFaction(lua_State* L, Unit* unit) + { + unit->RestoreFaction(); + return 0; + }*/ + + /*int RemoveBindSightAuras(lua_State* L, Unit* unit) + { + unit->RemoveBindSightAuras(); + return 0; + }*/ + + /*int RemoveCharmAuras(lua_State* L, Unit* unit) + { + unit->RemoveCharmAuras(); + return 0; + }*/ + + /*int DisableMelee(lua_State* L, Unit* unit) + { + bool apply = Eluna::CHECKVAL(L, 2, true); + + if (apply) + unit->AddUnitState(UNIT_STATE_CANNOT_AUTOATTACK); + else + unit->ClearUnitState(UNIT_STATE_CANNOT_AUTOATTACK); + return 0; + }*/ + + /*int SummonGuardian(lua_State* L, Unit* unit) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + float o = Eluna::CHECKVAL(L, 6); + uint32 desp = Eluna::CHECKVAL(L, 7, 0); + + SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(61); + if (!properties) + return 1; + Position pos; + pos.Relocate(x,y,z,o); + TempSummon* summon = unit->GetMap()->SummonCreature(entry, pos, properties, desp, unit); + + if (!summon) + return 1; + + if (summon->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + ((Guardian*)summon)->InitStatsForLevel(unit->getLevel()); + + if (properties && properties->Category == SUMMON_CATEGORY_ALLY) + summon->setFaction(unit->getFaction()); + if (summon->GetEntry() == 27893) + { + if (uint32 weapon = unit->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID)) + { + summon->SetDisplayId(11686); + summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon); + } + else + summon->SetDisplayId(1126); + } + summon->AI()->EnterEvadeMode(); + + Eluna::Push(L, summon); + return 1; + }*/ +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/VehicleHooks.cpp b/modules/mod-eluna/src/LuaEngine/VehicleHooks.cpp new file mode 100644 index 0000000..44eaf23 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/VehicleHooks.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 - 2016 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "BindingMap.h" +#include "ElunaTemplate.h" + +#ifndef CLASSIC +#ifndef TBC + +using namespace Hooks; + +#define START_HOOK(EVENT) \ + if (!IsEnabled())\ + return;\ + auto key = EventKey(EVENT);\ + if (!VehicleEventBindings->HasBindingsFor(key))\ + return;\ + LOCK_ELUNA + +void Eluna::OnInstall(Vehicle* vehicle) +{ + START_HOOK(VEHICLE_EVENT_ON_INSTALL); + Push(vehicle); + CallAllFunctions(VehicleEventBindings, key); +} + +void Eluna::OnUninstall(Vehicle* vehicle) +{ + START_HOOK(VEHICLE_EVENT_ON_UNINSTALL); + Push(vehicle); + CallAllFunctions(VehicleEventBindings, key); +} + +void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory) +{ + START_HOOK(VEHICLE_EVENT_ON_INSTALL_ACCESSORY); + Push(vehicle); + Push(accessory); + CallAllFunctions(VehicleEventBindings, key); +} + +void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId) +{ + START_HOOK(VEHICLE_EVENT_ON_ADD_PASSENGER); + Push(vehicle); + Push(passenger); + Push(seatId); + CallAllFunctions(VehicleEventBindings, key); +} + +void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger) +{ + START_HOOK(VEHICLE_EVENT_ON_REMOVE_PASSENGER); + Push(vehicle); + Push(passenger); + CallAllFunctions(VehicleEventBindings, key); +} + +#endif // CLASSIC +#endif // TBC diff --git a/modules/mod-eluna/src/LuaEngine/VehicleMethods.h b/modules/mod-eluna/src/LuaEngine/VehicleMethods.h new file mode 100644 index 0000000..3bbfea5 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/VehicleMethods.h @@ -0,0 +1,117 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef VEHICLEMETHODS_H +#define VEHICLEMETHODS_H +#ifndef CLASSIC +#ifndef TBC + +/*** + * Inherits all methods from: none + */ +namespace LuaVehicle +{ + /** + * Returns true if the [Unit] passenger is on board + * + * @param [Unit] passenger + * @return bool isOnBoard + */ + int IsOnBoard(lua_State* L, Vehicle* vehicle) + { + Unit* passenger = Eluna::CHECKOBJ(L, 2); +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, passenger->IsOnVehicle(vehicle->GetBase())); +#else + Eluna::Push(L, vehicle->HasOnBoard(passenger)); +#endif + return 1; + } + + /** + * Returns the [Vehicle]'s owner + * + * @return [Unit] owner + */ + int GetOwner(lua_State* L, Vehicle* vehicle) + { +#if defined TRINITY || AZEROTHCORE + Eluna::Push(L, vehicle->GetBase()); +#else + Eluna::Push(L, vehicle->GetOwner()); +#endif + return 1; + } + + /** + * Returns the [Vehicle]'s entry + * + * @return uint32 entry + */ + int GetEntry(lua_State* L, Vehicle* vehicle) + { +#ifdef TRINITY + Eluna::Push(L, vehicle->GetVehicleInfo()->ID); +#elif AZEROTHCORE + Eluna::Push(L, vehicle->GetVehicleInfo()->m_ID); +#else + Eluna::Push(L, vehicle->GetVehicleEntry()->m_ID); +#endif + return 1; + } + + /** + * Returns the [Vehicle]'s passenger in the specified seat + * + * @param int8 seat + * @return [Unit] passenger + */ + int GetPassenger(lua_State* L, Vehicle* vehicle) + { + int8 seatId = Eluna::CHECKVAL(L, 2); + Eluna::Push(L, vehicle->GetPassenger(seatId)); + return 1; + } + + /** + * Adds [Unit] passenger to a specified seat in the [Vehicle] + * + * @param [Unit] passenger + * @param int8 seat + */ + int AddPassenger(lua_State* L, Vehicle* vehicle) + { + Unit* passenger = Eluna::CHECKOBJ(L, 2); + int8 seatId = Eluna::CHECKVAL(L, 3); +#if defined TRINITY || AZEROTHCORE + vehicle->AddPassenger(passenger, seatId); +#else + if (vehicle->CanBoard(passenger)) + vehicle->Board(passenger, seatId); +#endif + return 0; + } + + /** + * Removes [Unit] passenger from the [Vehicle] + * + * @param [Unit] passenger + */ + int RemovePassenger(lua_State* L, Vehicle* vehicle) + { + Unit* passenger = Eluna::CHECKOBJ(L, 2); +#if defined TRINITY || AZEROTHCORE + vehicle->RemovePassenger(passenger); +#else + vehicle->UnBoard(passenger, false); +#endif + return 0; + } +} + +#endif // CLASSIC +#endif // TBC +#endif // VEHICLEMETHODS_H diff --git a/modules/mod-eluna/src/LuaEngine/WorldObjectMethods.h b/modules/mod-eluna/src/LuaEngine/WorldObjectMethods.h new file mode 100644 index 0000000..babf66d --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/WorldObjectMethods.h @@ -0,0 +1,1233 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef WORLDOBJECTMETHODS_H +#define WORLDOBJECTMETHODS_H + +/*** + * Inherits all methods from: [Object] + */ +namespace LuaWorldObject +{ + /** + * Returns the name of the [WorldObject] + * + * @return string name + */ + int GetName(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetName()); + return 1; + } + + /** + * Returns the current [Map] object of the [WorldObject] + * + * @return [Map] mapObject + */ + int GetMap(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetMap()); + return 1; + } + +#if (!defined(TBC) && !defined(CLASSIC)) + /** + * Returns the current phase of the [WorldObject] + * + * @return uint32 phase + */ + int GetPhaseMask(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetPhaseMask()); + return 1; + } + + /** + * Sets the [WorldObject]'s phase mask. + * + * @param uint32 phaseMask + * @param bool update = true : update visibility to nearby objects + */ + int SetPhaseMask(lua_State* L, WorldObject* obj) + { + uint32 phaseMask = Eluna::CHECKVAL(L, 2); + bool update = Eluna::CHECKVAL(L, 3, true); + obj->SetPhaseMask(phaseMask, update); + return 0; + } +#endif + + /** + * Returns the current instance ID of the [WorldObject] + * + * @return uint32 instanceId + */ + int GetInstanceId(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetInstanceId()); + return 1; + } + + /** + * Returns the current area ID of the [WorldObject] + * + * @return uint32 areaId + */ + int GetAreaId(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetAreaId()); + return 1; + } + + /** + * Returns the current zone ID of the [WorldObject] + * + * @return uint32 zoneId + */ + int GetZoneId(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetZoneId()); + return 1; + } + + /** + * Returns the current map ID of the [WorldObject] + * + * @return uint32 mapId + */ + int GetMapId(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetMapId()); + return 1; + } + + /** + * Returns the current X coordinate of the [WorldObject] + * + * @return float x + */ + int GetX(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetPositionX()); + return 1; + } + + /** + * Returns the current Y coordinate of the [WorldObject] + * + * @return float y + */ + int GetY(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetPositionY()); + return 1; + } + + /** + * Returns the current Z coordinate of the [WorldObject] + * + * @return float z + */ + int GetZ(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetPositionZ()); + return 1; + } + + /** + * Returns the current orientation of the [WorldObject] + * + * @return float orientation / facing + */ + int GetO(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetOrientation()); + return 1; + } + + /** + * Returns the coordinates and orientation of the [WorldObject] + * + * @return float x : x coordinate of the [WorldObject] + * @return float y : y coordinate of the [WorldObject] + * @return float z : z coordinate (height) of the [WorldObject] + * @return float o : facing / orientation of the [WorldObject] + */ + int GetLocation(lua_State* L, WorldObject* obj) + { + Eluna::Push(L, obj->GetPositionX()); + Eluna::Push(L, obj->GetPositionY()); + Eluna::Push(L, obj->GetPositionZ()); + Eluna::Push(L, obj->GetOrientation()); + return 4; + } + + /** + * Returns the nearest [Player] object in sight of the [WorldObject] or within the given range + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return [Player] nearestPlayer + */ + int GetNearestPlayer(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 hostile = Eluna::CHECKVAL(L, 3, 0); + uint32 dead = Eluna::CHECKVAL(L, 4, 1); + + Unit* target = NULL; + ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_PLAYER, 0, hostile, dead); +#ifdef TRINITY + Trinity::UnitLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); + +#elif AZEROTHCORE + Acore::UnitLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::UnitLastSearcher searcher(target, checker); + Cell::VisitWorldObjects(obj, searcher, range); +#endif + + Eluna::Push(L, target); + return 1; + } + + /** + * Returns the nearest [GameObject] object in sight of the [WorldObject] or within the given range and/or with a specific entry ID + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 entryId = 0 : optionally set entry ID of game object to find + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * + * @return [GameObject] nearestGameObject + */ + int GetNearestGameObject(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 entry = Eluna::CHECKVAL(L, 3, 0); + uint32 hostile = Eluna::CHECKVAL(L, 4, 0); + + GameObject* target = NULL; + ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_GAMEOBJECT, entry, hostile); +#ifdef TRINITY + Trinity::GameObjectLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::GameObjectLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::GameObjectLastSearcher searcher(target, checker); + Cell::VisitGridObjects(obj, searcher, range); +#endif + + Eluna::Push(L, target); + return 1; + } + + /** + * Returns the nearest [Creature] object in sight of the [WorldObject] or within the given range and/or with a specific entry ID + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 entryId = 0 : optionally set entry ID of creature to find + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return [Creature] nearestCreature + */ + int GetNearestCreature(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 entry = Eluna::CHECKVAL(L, 3, 0); + uint32 hostile = Eluna::CHECKVAL(L, 4, 0); + uint32 dead = Eluna::CHECKVAL(L, 5, 1); + + Creature* target = NULL; + ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_UNIT, entry, hostile, dead); +#ifdef TRINITY + Trinity::CreatureLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::CreatureLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::CreatureLastSearcher searcher(target, checker); + Cell::VisitGridObjects(obj, searcher, range); + +#endif + + Eluna::Push(L, target); + return 1; + } + + /** + * Returns a table of [Player] objects in sight of the [WorldObject] or within the given range + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return table playersInRange : table of [Player]s + */ + int GetPlayersInRange(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 hostile = Eluna::CHECKVAL(L, 3, 0); + uint32 dead = Eluna::CHECKVAL(L, 4, 1); + + std::list list; + ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_PLAYER, 0, hostile, dead); +#ifdef TRINITY + Trinity::PlayerListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::PlayerListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::PlayerListSearcher searcher(list, checker); + Cell::VisitWorldObjects(obj, searcher, range); +#endif + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns a table of [Creature] objects in sight of the [WorldObject] or within the given range and/or with a specific entry ID + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 entryId = 0 : optionally set entry ID of creatures to find + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return table creaturesInRange : table of [Creature]s + */ + int GetCreaturesInRange(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 entry = Eluna::CHECKVAL(L, 3, 0); + uint32 hostile = Eluna::CHECKVAL(L, 4, 0); + uint32 dead = Eluna::CHECKVAL(L, 5, 1); + + std::list list; + ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_UNIT, entry, hostile, dead); +#ifdef TRINITY + Trinity::CreatureListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif defined AZEROTHCORE + Acore::CreatureListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::CreatureListSearcher searcher(list, checker); + Cell::VisitGridObjects(obj, searcher, range); +#endif + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns a table of [GameObject] objects in sight of the [WorldObject] or within the given range and/or with a specific entry ID + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param uint32 entryId = 0 : optionally set entry ID of game objects to find + * @param uint32 hostile = 0 : 0 both, 1 hostile, 2 friendly + * + * @return table gameObjectsInRange : table of [GameObject]s + */ + int GetGameObjectsInRange(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint32 entry = Eluna::CHECKVAL(L, 3, 0); + uint32 hostile = Eluna::CHECKVAL(L, 4, 0); + + std::list list; + ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_GAMEOBJECT, entry, hostile); +#ifdef TRINITY + Trinity::GameObjectListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::GameObjectListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::GameObjectListSearcher searcher(list, checker); + Cell::VisitGridObjects(obj, searcher, range); +#endif + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns nearest [WorldObject] in sight of the [WorldObject]. + * The distance, type, entry and hostility requirements the [WorldObject] must match can be passed. + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param [TypeMask] type = 0 : the [TypeMask] that the [WorldObject] must be. This can contain multiple types. 0 will be ingored + * @param uint32 entry = 0 : the entry of the [WorldObject], 0 will be ingored + * @param uint32 hostile = 0 : specifies whether the [WorldObject] needs to be 1 hostile, 2 friendly or 0 either + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return [WorldObject] worldObject + */ + int GetNearObject(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint16 type = Eluna::CHECKVAL(L, 3, 0); // TypeMask + uint32 entry = Eluna::CHECKVAL(L, 4, 0); + uint32 hostile = Eluna::CHECKVAL(L, 5, 0); // 0 none, 1 hostile, 2 friendly + uint32 dead = Eluna::CHECKVAL(L, 6, 1); // 0 both, 1 alive, 2 dead + + float x, y, z; + obj->GetPosition(x, y, z); + ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, type, entry, hostile, dead); + + WorldObject* target = NULL; +#ifdef TRINITY + Trinity::WorldObjectLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::WorldObjectLastSearcher searcher(obj, target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::WorldObjectLastSearcher searcher(target, checker); + Cell::VisitAllObjects(obj, searcher, range); +#endif + + Eluna::Push(L, target); + return 1; + } + + /** + * Returns a table of [WorldObject]s in sight of the [WorldObject]. + * The distance, type, entry and hostility requirements the [WorldObject] must match can be passed. + * + * @param float range = 533.33333 : optionally set range. Default range is grid size + * @param [TypeMask] type = 0 : the [TypeMask] that the [WorldObject] must be. This can contain multiple types. 0 will be ingored + * @param uint32 entry = 0 : the entry of the [WorldObject], 0 will be ingored + * @param uint32 hostile = 0 : specifies whether the [WorldObject] needs to be 1 hostile, 2 friendly or 0 either + * @param uint32 dead = 1 : 0 both, 1 alive, 2 dead + * + * @return table worldObjectList : table of [WorldObject]s + */ + int GetNearObjects(lua_State* L, WorldObject* obj) + { + float range = Eluna::CHECKVAL(L, 2, SIZE_OF_GRIDS); + uint16 type = Eluna::CHECKVAL(L, 3, 0); // TypeMask + uint32 entry = Eluna::CHECKVAL(L, 4, 0); + uint32 hostile = Eluna::CHECKVAL(L, 5, 0); // 0 none, 1 hostile, 2 friendly + uint32 dead = Eluna::CHECKVAL(L, 6, 1); // 0 both, 1 alive, 2 dead + + float x, y, z; + obj->GetPosition(x, y, z); + ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, type, entry, hostile, dead); + + std::list list; +#ifdef TRINITY + Trinity::WorldObjectListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#elif AZEROTHCORE + Acore::WorldObjectListSearcher searcher(obj, list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#else + MaNGOS::WorldObjectListSearcher searcher(list, checker); + Cell::VisitAllObjects(obj, searcher, range); +#endif + + lua_createtable(L, list.size(), 0); + int tbl = lua_gettop(L); + uint32 i = 0; + + for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + Eluna::Push(L, *it); + lua_rawseti(L, tbl, ++i); + } + + lua_settop(L, tbl); + return 1; + } + + /** + * Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 3d space. + * + * The function takes into account the given object sizes. See also [WorldObject:GetExactDistance], [WorldObject:GetDistance2d] + * + * @proto dist = (obj) + * @proto dist = (x, y, z) + * + * @param [WorldObject] obj + * @param float x : the X-coordinate of the point + * @param float y : the Y-coordinate of the point + * @param float z : the Z-coordinate of the point + * + * @return float dist : the distance in yards + */ + int GetDistance(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + if (target) + Eluna::Push(L, obj->GetDistance(target)); + else + { + float X = Eluna::CHECKVAL(L, 2); + float Y = Eluna::CHECKVAL(L, 3); + float Z = Eluna::CHECKVAL(L, 4); + Eluna::Push(L, obj->GetDistance(X, Y, Z)); + } + return 1; + } + + /** + * Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 3d space. + * + * The function does not take into account the given object sizes, which means only the object coordinates are compared. See also [WorldObject:GetDistance], [WorldObject:GetDistance2d] + * + * @proto dist = (obj) + * @proto dist = (x, y, z) + * + * @param [WorldObject] obj + * @param float x : the X-coordinate of the point + * @param float y : the Y-coordinate of the point + * @param float z : the Z-coordinate of the point + * + * @return float dist : the distance in yards + */ + int GetExactDistance(lua_State* L, WorldObject* obj) + { + float x, y, z; + obj->GetPosition(x, y, z); + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + if (target) + { + float x2, y2, z2; + target->GetPosition(x2, y2, z2); + x -= x2; + y -= y2; + z -= z2; + } + else + { + x -= Eluna::CHECKVAL(L, 2); + y -= Eluna::CHECKVAL(L, 3); + z -= Eluna::CHECKVAL(L, 4); + } + + Eluna::Push(L, std::sqrt(x*x + y*y + z*z)); + return 1; + } + + /** + * Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 2d space. + * + * The function takes into account the given object sizes. See also [WorldObject:GetDistance], [WorldObject:GetExactDistance2d] + * + * @proto dist = (obj) + * @proto dist = (x, y) + * + * @param [WorldObject] obj + * @param float x : the X-coordinate of the point + * @param float y : the Y-coordinate of the point + * + * @return float dist : the distance in yards + */ + int GetDistance2d(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + if (target) + Eluna::Push(L, obj->GetDistance2d(target)); + else + { + float X = Eluna::CHECKVAL(L, 2); + float Y = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, obj->GetDistance2d(X, Y)); + } + return 1; + } + + /** + * Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 2d space. + * + * The function does not take into account the given object sizes, which means only the object coordinates are compared. See also [WorldObject:GetDistance], [WorldObject:GetDistance2d] + * + * @proto dist = (obj) + * @proto dist = (x, y) + * + * @param [WorldObject] obj + * @param float x : the X-coordinate of the point + * @param float y : the Y-coordinate of the point + * + * @return float dist : the distance in yards + */ + int GetExactDistance2d(lua_State* L, WorldObject* obj) + { + float x, y, z; + obj->GetPosition(x, y, z); + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + if (target) + { + float x2, y2, z2; + target->GetPosition(x2, y2, z2); + x -= x2; + y -= y2; + } + else + { + x -= Eluna::CHECKVAL(L, 2); + y -= Eluna::CHECKVAL(L, 3); + } + + Eluna::Push(L, std::sqrt(x*x + y*y)); + return 1; + } + + /** + * Returns the x, y and z of a point dist away from the [WorldObject]. + * + * @param float distance : specifies the distance of the point from the [WorldObject] in yards + * @param float angle : specifies the angle of the point relative to the orientation / facing of the [WorldObject] in radians + * + * @return float x + * @return float y + * @return float z + */ + int GetRelativePoint(lua_State* L, WorldObject* obj) + { + float dist = Eluna::CHECKVAL(L, 2); + float rad = Eluna::CHECKVAL(L, 3); + + float x, y, z; + obj->GetClosePoint(x, y, z, 0.0f, dist, rad); + + Eluna::Push(L, x); + Eluna::Push(L, y); + Eluna::Push(L, z); + return 3; + } + + /** + * Returns the angle between this [WorldObject] and another [WorldObject] or a point. + * + * The angle is the angle between two points and orientation will be ignored. + * + * @proto dist = (obj) + * @proto dist = (x, y) + * + * @param [WorldObject] object + * @param float x + * @param float y + * + * @return float angle : angle in radians in range 0..2*pi + */ + int GetAngle(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); +#if defined TRINITY && !AZEROTHCORE + if (target) + Eluna::Push(L, obj->GetAbsoluteAngle(target)); + else + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, obj->GetAbsoluteAngle(x, y)); + } +#else + if (target) + Eluna::Push(L, obj->GetAngle(target)); + else + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + Eluna::Push(L, obj->GetAngle(x, y)); + } +#endif + return 1; + } + + /** + * Sends a [WorldPacket] to [Player]s in sight of the [WorldObject]. + * + * @param [WorldPacket] packet + */ + int SendPacket(lua_State* L, WorldObject* obj) + { + WorldPacket* data = Eluna::CHECKOBJ(L, 2); +#ifdef CMANGOS + obj->SendMessageToSet(*data, true); +#else + obj->SendMessageToSet(data, true); +#endif + return 0; + } + + /** + * Spawns a [GameObject] at specified location. + * + * @param uint32 entry : [GameObject] entry ID + * @param float x + * @param float y + * @param float z + * @param float o + * @param uint32 respawnDelay = 30 : respawn time in seconds + * @return [GameObject] gameObject + */ + int SummonGameObject(lua_State* L, WorldObject* obj) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + float o = Eluna::CHECKVAL(L, 6); + uint32 respawnDelay = Eluna::CHECKVAL(L, 7, 30); +#ifdef TRINITY + QuaternionData rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f); + Eluna::Push(L, obj->SummonGameObject(entry, Position(x, y, z, o), rot, Seconds(respawnDelay))); +#elif AZEROTHCORE + Eluna::Push(L, obj->SummonGameObject(entry, x, y, z, o, 0, 0, 0, 0, respawnDelay)); +#else + Eluna::Push(L, obj->SummonGameObject(entry, x, y, z, o, respawnDelay)); +#endif + return 1; + } + + /** + * Spawns the creature at specified location. + * + * enum TempSummonType + * { + * TEMPSUMMON_TIMED_OR_DEAD_DESPAWN = 1, // despawns after a specified time OR when the creature disappears + * TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN = 2, // despawns after a specified time OR when the creature dies + * TEMPSUMMON_TIMED_DESPAWN = 3, // despawns after a specified time + * TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT = 4, // despawns after a specified time after the creature is out of combat + * TEMPSUMMON_CORPSE_DESPAWN = 5, // despawns instantly after death + * TEMPSUMMON_CORPSE_TIMED_DESPAWN = 6, // despawns after a specified time after death + * TEMPSUMMON_DEAD_DESPAWN = 7, // despawns when the creature disappears + * TEMPSUMMON_MANUAL_DESPAWN = 8, // despawns when UnSummon() is called + * TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN = 9, // despawns after a specified time (OOC) OR when the creature dies + * TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN = 10 // despawns after a specified time (OOC) OR when the creature disappears + * }; + * + * @param uint32 entry : [Creature]'s entry ID + * @param float x + * @param float y + * @param float z + * @param float o + * @param [TempSummonType] spawnType = MANUAL_DESPAWN : defines how and when the creature despawns + * @param uint32 despawnTimer = 0 : despawn time in milliseconds + * @return [Creature] spawnedCreature + */ + int SpawnCreature(lua_State* L, WorldObject* obj) + { + uint32 entry = Eluna::CHECKVAL(L, 2); + float x = Eluna::CHECKVAL(L, 3); + float y = Eluna::CHECKVAL(L, 4); + float z = Eluna::CHECKVAL(L, 5); + float o = Eluna::CHECKVAL(L, 6); + uint32 spawnType = Eluna::CHECKVAL(L, 7, 8); + uint32 despawnTimer = Eluna::CHECKVAL(L, 8, 0); + +#if defined TRINITY || AZEROTHCORE + TempSummonType type; + switch (spawnType) + { + case 1: + type = TEMPSUMMON_TIMED_OR_DEAD_DESPAWN; + break; + case 2: + type = TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN; + break; + case 3: + type = TEMPSUMMON_TIMED_DESPAWN; + break; + case 4: + type = TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT; + break; + case 5: + type = TEMPSUMMON_CORPSE_DESPAWN; + break; + case 6: + type = TEMPSUMMON_CORPSE_TIMED_DESPAWN; + break; + case 7: + type = TEMPSUMMON_DEAD_DESPAWN; + break; + case 8: + type = TEMPSUMMON_MANUAL_DESPAWN; + break; + default: + return luaL_argerror(L, 7, "valid SpawnType expected"); + } +#else + TempSpawnType type; + switch (spawnType) + { + case 1: + type = TEMPSPAWN_TIMED_OR_DEAD_DESPAWN; + break; + case 2: + type = TEMPSPAWN_TIMED_OR_CORPSE_DESPAWN; + break; + case 3: + type = TEMPSPAWN_TIMED_DESPAWN; + break; + case 4: + type = TEMPSPAWN_TIMED_OOC_DESPAWN; + break; + case 5: + type = TEMPSPAWN_CORPSE_DESPAWN; + break; + case 6: + type = TEMPSPAWN_CORPSE_TIMED_DESPAWN; + break; + case 7: + type = TEMPSPAWN_DEAD_DESPAWN; + break; + case 8: + type = TEMPSPAWN_MANUAL_DESPAWN; + break; + case 9: + type = TEMPSPAWN_TIMED_OOC_OR_CORPSE_DESPAWN; + break; + case 10: + type = TEMPSPAWN_TIMED_OOC_OR_DEAD_DESPAWN; + break; + default: + return luaL_argerror(L, 7, "valid SpawnType expected"); + } +#endif +#ifdef TRINITY + Eluna::Push(L, obj->SummonCreature(entry, x, y, z, o, type, Seconds(despawnTimer))); +#else + Eluna::Push(L, obj->SummonCreature(entry, x, y, z, o, type, despawnTimer)); +#endif + return 1; + } + + /** + * Registers a timed event to the [WorldObject] + * When the passed function is called, the parameters `(eventId, delay, repeats, worldobject)` are passed to it. + * Repeats will decrease on each call if the event does not repeat indefinitely + * + * Note that for [Creature] and [GameObject] the timed event timer ticks only if the creature is in sight of someone + * For all [WorldObject]s the timed events are removed when the object is destoryed. This means that for example a [Player]'s events are removed on logout. + * + * local function Timed(eventid, delay, repeats, worldobject) + * print(worldobject:GetName()) + * end + * worldobject:RegisterEvent(Timed, 1000, 5) -- do it after 1 second 5 times + * worldobject:RegisterEvent(Timed, {1000, 10000}, 0) -- do it after 1 to 10 seconds forever + * + * @proto eventId = (function, delay) + * @proto eventId = (function, delaytable) + * @proto eventId = (function, delay, repeats) + * @proto eventId = (function, delaytable, repeats) + * + * @param function function : function to trigger when the time has passed + * @param uint32 delay : set time in milliseconds for the event to trigger + * @param table delaytable : a table `{min, max}` containing the minimum and maximum delay time + * @param uint32 repeats = 1 : how many times for the event to repeat, 0 is infinite + * @return int eventId : unique ID for the timed event used to cancel it or nil + */ + int RegisterEvent(lua_State* L, WorldObject* obj) + { + luaL_checktype(L, 2, LUA_TFUNCTION); + uint32 min, max; + if (lua_istable(L, 3)) + { + Eluna::Push(L, 1); + lua_gettable(L, 3); + min = Eluna::CHECKVAL(L, -1); + Eluna::Push(L, 2); + lua_gettable(L, 3); + max = Eluna::CHECKVAL(L, -1); + lua_pop(L, 2); + } + else + min = max = Eluna::CHECKVAL(L, 3); + uint32 repeats = Eluna::CHECKVAL(L, 4, 1); + + if (min > max) + return luaL_argerror(L, 3, "min is bigger than max delay"); + + lua_pushvalue(L, 2); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) + { + obj->elunaEvents->AddEvent(functionRef, min, max, repeats); + Eluna::Push(L, functionRef); + } + return 1; + } + + /** + * Removes the timed event from a [WorldObject] by the specified event ID + * + * @param int eventId : event Id to remove + */ + int RemoveEventById(lua_State* L, WorldObject* obj) + { + int eventId = Eluna::CHECKVAL(L, 2); + obj->elunaEvents->SetState(eventId, LUAEVENT_STATE_ABORT); + return 0; + } + + /** + * Removes all timed events from a [WorldObject] + * + */ + int RemoveEvents(lua_State* /*L*/, WorldObject* obj) + { + obj->elunaEvents->SetStates(LUAEVENT_STATE_ABORT); + return 0; + } + + /** + * Returns true if the given [WorldObject] or coordinates are in the [WorldObject]'s line of sight + * + * @proto isInLoS = (worldobject) + * @proto isInLoS = (x, y, z) + * + * @param [WorldObject] worldobject + * @param float x + * @param float y + * @param float z + * @return bool isInLoS + */ + int IsWithinLoS(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + + if (target) + Eluna::Push(L, obj->IsWithinLOSInMap(target)); + else + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + Eluna::Push(L, obj->IsWithinLOS(x, y, z)); + } + + return 1; + } + + /** + * Returns true if the [WorldObject]s are on the same map + * + * @param [WorldObject] worldobject + * @return bool isInMap + */ + int IsInMap(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, true); + Eluna::Push(L, obj->IsInMap(target)); + return 1; + } + + /** + * Returns true if the point is in the given distance of the [WorldObject] + * + * Notice that the distance is measured from the edge of the [WorldObject]. + * + * @param float x + * @param float y + * @param float z + * @param float distance + * @return bool isInDistance + */ + int IsWithinDist3d(lua_State* L, WorldObject* obj) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + float dist = Eluna::CHECKVAL(L, 5); + Eluna::Push(L, obj->IsWithinDist3d(x, y, z, dist)); + return 1; + } + + /** + * Returns true if the point is in the given distance of the [WorldObject] + * + * The distance is measured only in x,y coordinates. + * Notice that the distance is measured from the edge of the [WorldObject]. + * + * @param float x + * @param float y + * @param float distance + * @return bool isInDistance + */ + int IsWithinDist2d(lua_State* L, WorldObject* obj) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float dist = Eluna::CHECKVAL(L, 4); + Eluna::Push(L, obj->IsWithinDist2d(x, y, dist)); + return 1; + } + + /** + * Returns true if the target is in the given distance of the [WorldObject] + * + * Notice that the distance is measured from the edge of the [WorldObject]s. + * + * @param [WorldObject] target + * @param float distance + * @param bool is3D = true : if false, only x,y coordinates used for checking + * @return bool isInDistance + */ + int IsWithinDist(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, true); + float distance = Eluna::CHECKVAL(L, 3); + bool is3D = Eluna::CHECKVAL(L, 4, true); + Eluna::Push(L, obj->IsWithinDist(target, distance, is3D)); + return 1; + } + + /** + * Returns true if the [WorldObject] is on the same map and within given distance + * + * Notice that the distance is measured from the edge of the [WorldObject]s. + * + * @param [WorldObject] target + * @param float distance + * @param bool is3D = true : if false, only x,y coordinates used for checking + * @return bool isInDistance + */ + int IsWithinDistInMap(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2); + float distance = Eluna::CHECKVAL(L, 3); + bool is3D = Eluna::CHECKVAL(L, 4, true); + + Eluna::Push(L, obj->IsWithinDistInMap(target, distance, is3D)); + return 1; + } + + /** + * Returns true if the target is within given range + * + * Notice that the distance is measured from the edge of the [WorldObject]s. + * + * @param [WorldObject] target + * @param float minrange + * @param float maxrange + * @param bool is3D = true : if false, only x,y coordinates used for checking + * @return bool isInDistance + */ + int IsInRange(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2); + float minrange = Eluna::CHECKVAL(L, 3); + float maxrange = Eluna::CHECKVAL(L, 4); + bool is3D = Eluna::CHECKVAL(L, 5, true); + + Eluna::Push(L, obj->IsInRange(target, minrange, maxrange, is3D)); + return 1; + } + + /** + * Returns true if the point is within given range + * + * Notice that the distance is measured from the edge of the [WorldObject]. + * + * @param float x + * @param float y + * @param float minrange + * @param float maxrange + * @return bool isInDistance + */ + int IsInRange2d(lua_State* L, WorldObject* obj) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float minrange = Eluna::CHECKVAL(L, 4); + float maxrange = Eluna::CHECKVAL(L, 5); + + Eluna::Push(L, obj->IsInRange2d(x, y, minrange, maxrange)); + return 1; + } + + /** + * Returns true if the point is within given range + * + * Notice that the distance is measured from the edge of the [WorldObject]. + * + * @param float x + * @param float y + * @param float z + * @param float minrange + * @param float maxrange + * @return bool isInDistance + */ + int IsInRange3d(lua_State* L, WorldObject* obj) + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + float minrange = Eluna::CHECKVAL(L, 5); + float maxrange = Eluna::CHECKVAL(L, 6); + + Eluna::Push(L, obj->IsInRange3d(x, y, z, minrange, maxrange)); + return 1; + } + + /** + * Returns true if the target is in the given arc in front of the [WorldObject] + * + * @param [WorldObject] target + * @param float arc = pi + * @return bool isInFront + */ + int IsInFront(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2); + float arc = Eluna::CHECKVAL(L, 3, static_cast(M_PI)); + +#ifdef MANGOS + Eluna::Push(L, obj->IsInFront(target, arc)); +#else + Eluna::Push(L, obj->isInFront(target, arc)); +#endif + return 1; + } + + /** + * Returns true if the target is in the given arc behind the [WorldObject] + * + * @param [WorldObject] target + * @param float arc = pi + * @return bool isInBack + */ + int IsInBack(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2); + float arc = Eluna::CHECKVAL(L, 3, static_cast(M_PI)); + +#ifdef MANGOS + Eluna::Push(L, obj->IsInBack(target, arc)); +#else + Eluna::Push(L, obj->isInBack(target, arc)); +#endif + return 1; + } + + /** + * The [WorldObject] plays music to a [Player] + * + * If no [Player] provided it will play the music to everyone near. + * This method does not interrupt previously played music. + * + * See also [WorldObject:PlayDistanceSound], [WorldObject:PlayDirectSound] + * + * @param uint32 music : entry of a music + * @param [Player] player = nil : [Player] to play the music to + */ + int PlayMusic(lua_State* L, WorldObject* obj) + { + uint32 musicid = Eluna::CHECKVAL(L, 2); + Player* player = Eluna::CHECKOBJ(L, 3, false); + + WorldPacket data(SMSG_PLAY_MUSIC, 4); + data << uint32(musicid); +#ifdef CMANGOS + if (player) + player->SendDirectMessage(data); + else + obj->SendMessageToSet(data, true); +#else + if (player) + player->SendDirectMessage(&data); + else + obj->SendMessageToSet(&data, true); +#endif + return 0; + } + + /** + * The [WorldObject] plays a sound to a [Player] + * + * If no [Player] provided it will play the sound to everyone near. + * This method will play sound and does not interrupt prvious sound. + * + * See also [WorldObject:PlayDistanceSound], [WorldObject:PlayMusic] + * + * @param uint32 sound : entry of a sound + * @param [Player] player = nil : [Player] to play the sound to + */ + int PlayDirectSound(lua_State* L, WorldObject* obj) + { + uint32 soundId = Eluna::CHECKVAL(L, 2); + Player* player = Eluna::CHECKOBJ(L, 3, false); + if (!sSoundEntriesStore.LookupEntry(soundId)) + return 0; + + if (player) + obj->PlayDirectSound(soundId, player); + else + obj->PlayDirectSound(soundId); + return 0; + } + + /** + * The [WorldObject] plays a sound to a [Player] + * + * If no [Player] it will play the sound to everyone near. + * Sound will fade the further you are from the [WorldObject]. + * This method interrupts previously playing sound. + * + * See also [WorldObject:PlayDirectSound], [WorldObject:PlayMusic] + * + * @param uint32 sound : entry of a sound + * @param [Player] player = nil : [Player] to play the sound to + */ + int PlayDistanceSound(lua_State* L, WorldObject* obj) + { + uint32 soundId = Eluna::CHECKVAL(L, 2); + Player* player = Eluna::CHECKOBJ(L, 3, false); + if (!sSoundEntriesStore.LookupEntry(soundId)) + return 0; + + if (player) + obj->PlayDistanceSound(soundId, player); + else + obj->PlayDistanceSound(soundId); + return 0; + } +}; +#endif diff --git a/modules/mod-eluna/src/LuaEngine/WorldPacketMethods.h b/modules/mod-eluna/src/LuaEngine/WorldPacketMethods.h new file mode 100644 index 0000000..750c096 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/WorldPacketMethods.h @@ -0,0 +1,310 @@ +/* +* Copyright (C) 2010 - 2016 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + +#ifndef WORLDPACKETMETHODS_H +#define WORLDPACKETMETHODS_H + +/*** + * A packet used to pass messages between the server and a client. + * + * Each packet has an opcode that determines the type of message being sent, + * e.g. if a CMSG_LOGOUT_REQUEST packet is sent to the server, + * the client has sent a message that its [Player] wants to logout. + * + * The packet can contain further data, the format of which depends on the opcode. + * + * Inherits all methods from: none + */ +namespace LuaPacket +{ + /** + * Returns the opcode of the [WorldPacket]. + * + * @return uint16 opcode + */ + int GetOpcode(lua_State* L, WorldPacket* packet) + { + Eluna::Push(L, packet->GetOpcode()); + return 1; + } + + /** + * Returns the size of the [WorldPacket]. + * + * @return uint32 size + */ + int GetSize(lua_State* L, WorldPacket* packet) + { + Eluna::Push(L, packet->size()); + return 1; + } + + /** + * Sets the opcode of the [WorldPacket] to the specified opcode. + * + * @param [Opcodes] opcode : see Opcodes.h for all known opcodes + */ + int SetOpcode(lua_State* L, WorldPacket* packet) + { + uint32 opcode = Eluna::CHECKVAL(L, 2); + if (opcode >= NUM_MSG_TYPES) + return luaL_argerror(L, 2, "valid opcode expected"); + packet->SetOpcode((OpcodesList)opcode); + return 0; + } + + /** + * Reads and returns a signed 8-bit integer value from the [WorldPacket]. + * + * @return int8 value + */ + int ReadByte(lua_State* L, WorldPacket* packet) + { + int8 _byte; + (*packet) >> _byte; + Eluna::Push(L, _byte); + return 1; + } + + /** + * Reads and returns an unsigned 8-bit integer value from the [WorldPacket]. + * + * @return uint8 value + */ + int ReadUByte(lua_State* L, WorldPacket* packet) + { + uint8 _ubyte; + (*packet) >> _ubyte; + Eluna::Push(L, _ubyte); + return 1; + } + + /** + * Reads and returns a signed 16-bit integer value from the [WorldPacket]. + * + * @return int16 value + */ + int ReadShort(lua_State* L, WorldPacket* packet) + { + int16 _short; + (*packet) >> _short; + Eluna::Push(L, _short); + return 1; + } + + /** + * Reads and returns an unsigned 16-bit integer value from the [WorldPacket]. + * + * @return uint16 value + */ + int ReadUShort(lua_State* L, WorldPacket* packet) + { + uint16 _ushort; + (*packet) >> _ushort; + Eluna::Push(L, _ushort); + return 1; + } + + /** + * Reads and returns a signed 32-bit integer value from the [WorldPacket]. + * + * @return int32 value + */ + int ReadLong(lua_State* L, WorldPacket* packet) + { + int32 _long; + (*packet) >> _long; + Eluna::Push(L, _long); + return 1; + } + + /** + * Reads and returns an unsigned 32-bit integer value from the [WorldPacket]. + * + * @return uint32 value + */ + int ReadULong(lua_State* L, WorldPacket* packet) + { + uint32 _ulong; + (*packet) >> _ulong; + Eluna::Push(L, _ulong); + return 1; + } + + /** + * Reads and returns a single-precision floating-point value from the [WorldPacket]. + * + * @return float value + */ + int ReadFloat(lua_State* L, WorldPacket* packet) + { + float _val; + (*packet) >> _val; + Eluna::Push(L, _val); + return 1; + } + + /** + * Reads and returns a double-precision floating-point value from the [WorldPacket]. + * + * @return double value + */ + int ReadDouble(lua_State* L, WorldPacket* packet) + { + double _val; + (*packet) >> _val; + Eluna::Push(L, _val); + return 1; + } + + /** + * Reads and returns an unsigned 64-bit integer value from the [WorldPacket]. + * + * @return ObjectGuid value : value returned as string + */ + int ReadGUID(lua_State* L, WorldPacket* packet) + { + ObjectGuid guid; + (*packet) >> guid; + Eluna::Push(L, guid); + return 1; + } + + /** + * Reads and returns a string value from the [WorldPacket]. + * + * @return string value + */ + int ReadString(lua_State* L, WorldPacket* packet) + { + std::string _val; + (*packet) >> _val; + Eluna::Push(L, _val); + return 1; + } + + /** + * Writes an unsigned 64-bit integer value to the [WorldPacket]. + * + * @param ObjectGuid value : the value to be written to the [WorldPacket] + */ + int WriteGUID(lua_State* L, WorldPacket* packet) + { + ObjectGuid guid = Eluna::CHECKVAL(L, 2); + (*packet) << guid; + return 0; + } + + /** + * Writes a string to the [WorldPacket]. + * + * @param string value : the string to be written to the [WorldPacket] + */ + int WriteString(lua_State* L, WorldPacket* packet) + { + std::string _val = Eluna::CHECKVAL(L, 2); + (*packet) << _val; + return 0; + } + + /** + * Writes a signed 8-bit integer value to the [WorldPacket]. + * + * @param int8 value : the int8 value to be written to the [WorldPacket] + */ + int WriteByte(lua_State* L, WorldPacket* packet) + { + int8 byte = Eluna::CHECKVAL(L, 2); + (*packet) << byte; + return 0; + } + + /** + * Writes an unsigned 8-bit integer value to the [WorldPacket]. + * + * @param uint8 value : the uint8 value to be written to the [WorldPacket] + */ + int WriteUByte(lua_State* L, WorldPacket* packet) + { + uint8 byte = Eluna::CHECKVAL(L, 2); + (*packet) << byte; + return 0; + } + + /** + * Writes a signed 16-bit integer value to the [WorldPacket]. + * + * @param int16 value : the int16 value to be written to the [WorldPacket] + */ + int WriteShort(lua_State* L, WorldPacket* packet) + { + int16 _short = Eluna::CHECKVAL(L, 2); + (*packet) << _short; + return 0; + } + + /** + * Writes an unsigned 16-bit integer value to the [WorldPacket]. + * + * @param uint16 value : the uint16 value to be written to the [WorldPacket] + */ + int WriteUShort(lua_State* L, WorldPacket* packet) + { + uint16 _ushort = Eluna::CHECKVAL(L, 2); + (*packet) << _ushort; + return 0; + } + + /** + * Writes a signed 32-bit integer value to the [WorldPacket]. + * + * @param int32 value : the int32 value to be written to the [WorldPacket] + */ + int WriteLong(lua_State* L, WorldPacket* packet) + { + int32 _long = Eluna::CHECKVAL(L, 2); + (*packet) << _long; + return 0; + } + + /** + * Writes an unsigned 32-bit integer value to the [WorldPacket]. + * + * @param uint32 value : the uint32 value to be written to the [WorldPacket] + */ + int WriteULong(lua_State* L, WorldPacket* packet) + { + uint32 _ulong = Eluna::CHECKVAL(L, 2); + (*packet) << _ulong; + return 0; + } + + /** + * Writes a 32-bit floating-point value to the [WorldPacket]. + * + * @param float value : the float value to be written to the [WorldPacket] + */ + int WriteFloat(lua_State* L, WorldPacket* packet) + { + float _val = Eluna::CHECKVAL(L, 2); + (*packet) << _val; + return 0; + } + + /** + * Writes a 64-bit floating-point value to the [WorldPacket]. + * + * @param double value : the double value to be written to the [WorldPacket] + */ + int WriteDouble(lua_State* L, WorldPacket* packet) + { + double _val = Eluna::CHECKVAL(L, 2); + (*packet) << _val; + return 0; + } +}; + +#endif diff --git a/modules/mod-eluna/src/LuaEngine/docs/.gitignore b/modules/mod-eluna/src/LuaEngine/docs/.gitignore new file mode 100644 index 0000000..3fd1eba --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/.gitignore @@ -0,0 +1,2 @@ +# Ignore the temporary "build" folder. +build \ No newline at end of file diff --git a/modules/mod-eluna/src/LuaEngine/docs/CONTRIBUTING.md b/modules/mod-eluna/src/LuaEngine/docs/CONTRIBUTING.md new file mode 100644 index 0000000..2a287f4 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/CONTRIBUTING.md @@ -0,0 +1,19 @@ +# Contributing +Eluna uses C for the Lua engine, C++ for the server modifications and system code, Lua for scripting side code and scripts, python for the web documentation generation - but you do not have to be able to code to help. + +You can contribute to Eluna in various ways: +* Improve our documentation: [Documentation generation](DOC_GEN.md) +* Create new features or enhance old features: [Eluna source](https://github.com/ElunaLuaEngine/Eluna) +* Notify us about your concerns, problems and needs regarding Eluna: [Issue tracker](https://github.com/ElunaLuaEngine/Eluna/issues) +* Create and improve Lua scripts, systems, releases and guides: [Eluna forum section](https://www.getmangos.eu/forums/forum/118-eluna-lua-engine/) + +### Features and documentation +To contribute to the source code and documentation within it, create a pull request for our github repository: + +1. [Set up git](https://help.github.com/articles/set-up-git/) +2. [Fork](https://help.github.com/articles/fork-a-repo/) our repository: [Eluna repository](https://github.com/ElunaLuaEngine/Eluna) +3. Create a branch: `git checkout -b mybranch` +4. Make your contribution changes +5. Commit your changes `git commit -a -m "commit message"` +6. Push your commit to github: `git push` +7. Open a [pull request](https://help.github.com/articles/using-pull-requests/) diff --git a/modules/mod-eluna/src/LuaEngine/docs/DOC_GEN.md b/modules/mod-eluna/src/LuaEngine/docs/DOC_GEN.md new file mode 100644 index 0000000..6acac22 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/DOC_GEN.md @@ -0,0 +1,165 @@ +# Documentation generation +Eluna uses a custom made documentation generator to create it's [web documentation](http://elunaluaengine.github.io/). +The generator is written in python by Patman. It works by parsing Eluna's source files for comments and then generates the HTML and javascript for the documentation based on them. + +This page guides you through generating the web documentation locally and explains the standards of the documentation comments for you to help us improve our documentation. To contribute with your documentation changes, create a [pull request](https://help.github.com/articles/using-pull-requests/) + +# Generating locally +- install [python](https://www.python.org/)(2) + - when installing, tick to install the path variable + - you may need restart afterwards for the installation to properly take effect +- install a package manager like [pip](https://pip.pypa.io/en/latest/) + - if you installed pip and it does not work, restart or try easy_install command +- install the dependencies with manager + - [Jinja2](https://pypi.python.org/pypi/Jinja2) + - [typedecorator](https://pypi.python.org/pypi/typedecorator) + - [markdown](https://pypi.python.org/pypi/Markdown) +- Run in cmd `python -m ElunaDoc` when at `\LuaEngine\docs\` + +# Documenting +You can document functions in the Eluna source code. To find examples simply open a method header file like `PlayerMethods.h` and see the comments. + +## Templates +Here are some basic templates for a function documentation. When defining a parameter or a return value the type and value name are mandatory, unless the parameter type is `...`, which is used for variable arguments; do not include a name in this case. + +```c++ +/** + * Short description (about 80 characters long). + * + * @param Type paramName + * @return Type returnName + */ +``` + +```c++ +/** + * Short description (about 80 characters long). + * + * @param Type paramName = defaultValue : parameter description + * @return Type returnName : return value description + */ +``` + +This is a template for a function that takes in different parameters. When defining a parameter or a return value, the type and value name are mandatory. + +```c++ +/** + * Short description (about 80 characters long). + * + * @proto returnValue = (object) + * @proto returnValue = (x, y, z) + * @param [WorldObject] object = defaultValue : parameter description + * @param float x = defaultValue : parameter description + * @param float y = defaultValue : parameter description + * @param float z = defaultValue : parameter description + * @return Type returnName : return value description + */ +``` + +## Standard +A documentation comment block will always start with `/**` and end with `*/`. +All lines start with `*` character followed by one space before any content. + +The first paragrph is used as a short description of the function/class, so it should be kept to about 80 characters. The other paragraphs can be as long as desired. + +All paragraphs in the description (including the first) should start with a capital letter and end with a period. +**Paragraphs must be separated by an empty line**, e.g.: + +```c++ +/** + * This is a short description (about 80 characters). + * + * Here's another paragraph with more info. NOTE THE EMPTY LINE BETWEEN THE PARAGRAPHS. + * This does need to be short, and this line is still part of the same paragraph because + * there is no empty line. + */ + ``` + +The parameter and return value descriptions should start with a lowercase letter and not end with a period. If more than one sentence is needed, start the *first* without a capital letter and end the *last* without a period. + +Any class, enum or function can be referenced (made a link to) with square brackets. +`[Player]` will reference a player. `[WeatherType]` will reference an enum. `[Player:GetName]` will reference a function. + +Use correct indentation with documentation comments. + +```c++ +/** + * Correct indentation. + */ +``` + +```c++ +/** +* Invalid indentation. +*/ +``` + +## Markdown +You can use [markdown](http://pythonhosted.org//Markdown/) in your descriptions. +For syntax see http://daringfireball.net/projects/markdown/syntax and http://pythonhosted.org//Markdown/#differences + +``` +/** + * Description. + * + * - list item + * - list item + * - list item + * + * + * // Codeblock + * // Code goes here. + * // Note the 4-space indent. + * + * + * `code line` + * + * *italic* + * **bold** + */ +``` + +**The above markdown code produces the output below:** + +Description. + +- list item +- list item +- list item + +``` +// Codeblock +// Code goes here. +// Note the 4-space indent. +``` + +`code line` + +*italic* +**bold** + +## Types +Here are some examples of possible types and most commonly used ones: + +``` +string +uint64 +uint32 +uint16 +uint8 +int64 +int32 +int16 +int8 +double +float +... +[EnumName] +[Player] +[Creature] +[GameObject] +[Item] +[Unit] +[WorldObject] +[Object] +``` diff --git a/modules/mod-eluna/src/LuaEngine/docs/Eluna.png b/modules/mod-eluna/src/LuaEngine/docs/Eluna.png new file mode 100644 index 0000000..b450d33 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/Eluna.png differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/.gitignore b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/.gitignore new file mode 100644 index 0000000..b32d8aa --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/.gitignore @@ -0,0 +1,2 @@ +*.pyc +.idea \ No newline at end of file diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/__init__.py b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/__main__.py b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/__main__.py new file mode 100644 index 0000000..75ce746 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/__main__.py @@ -0,0 +1,174 @@ +import os +import shutil +import typing +from jinja2 import Environment, FileSystemLoader +from typedecorator import params, returns +from ElunaDoc.parser import ClassParser, MethodDoc +import glob +import time + + +@returns([(str, typing.IO)]) +@params(search_path=str) +def find_class_files(search_path): + """Find and open all files containing Eluna class methods in `search_path`. + + :param search_path: the path to search for Eluna methods in + :return: a list of all files containing Eluna methods, and the name of their respective classes + """ + # Get the current working dir and switch to the search path. + old_dir = os.getcwd() + os.chdir(search_path) + # Search for all files ending in "Methods.h". + method_file_names = glob.glob('*Methods.h') + # Open each file. + method_files = [open(file_name, 'r') for file_name in method_file_names] + # Go back to where we were before. + os.chdir(old_dir) + return method_files + + +def make_renderer(template_path, link_parser_factory): + """Return a function that can be used to render Jinja2 templates from the `template_path` directory.""" + + # Set up jinja2 environment to load templates from the templates folder. + env = Environment(loader=FileSystemLoader(template_path)) + + + def inner(template_name, output_path, level, **kwargs): + env.filters['parse_links'], env.filters['parse_data_type'] = link_parser_factory(level) + template = env.get_template(template_name) + static = make_static(level) + root = make_root(level) + + with open('build/' + output_path, 'w') as out: + out.write(template.render(level=level, static=static, root=root, **kwargs)) + + return inner + + +def make_static(level): + return lambda file_name: ('../' * level) + 'static/' + file_name + + +def make_root(level): + return lambda file_name: ('../' * level) + file_name + + +if __name__ == '__main__': + # Recreate the build folder and copy static files over. + if os.path.exists('build'): + shutil.rmtree('build') + os.mkdir('build') + shutil.copytree('ElunaDoc/static', 'build/static') + + # Load up all files with methods we need to parse. + print('Finding Eluna method files...') + class_files = find_class_files('../') + + # Parse all the method files. + classes = [] + for f in class_files: + print(f'Parsing file {f.name}...') + classes.append(ClassParser.parse_file(f)) + f.close() + + # Sort the classes so they are in the correct order in lists. + classes.sort(key=lambda c: c.name) + + def make_parsers(level): + """Returns a function that parses content for refs to other classes, methods, or enums, + and automatically inserts the correct link. + """ + # Make lists of all class names and method names. + class_names = [] + method_names = [] + + for class_ in classes: + class_names.append('[' + class_.name + ']') + + for method in class_.methods: + method_names.append('[' + class_.name + ':' + method.name + ']') + + def link_parser(content): + # Replace all occurrencies of &Class:Function and then &Class with a link to given func or class + + for name in method_names: + # Take the [] off the front of the method's name. + full_name = name[1:-1] + # Split "Class:Method" into "Class" and "Method". + class_name, method_name = full_name.split(':') + url = '{}{}/{}.html'.format(('../' * level), class_name, method_name) + # Replace occurrencies of &Class:Method with the url created + content = content.replace(name, '{}'.format(url, full_name)) + + for name in class_names: + # Take the [] off the front of the class's name. + class_name = name[1:-1] + url = '{}{}/index.html'.format(('../' * level), class_name) + # Replace occurrencies of &Class:Method with the url created + content = content.replace(name, '{}'.format(url, class_name)) + + return content + + # Links to the "Programming in Lua" documentation for each Lua type. + lua_type_documentation = { + 'nil': 'http://www.lua.org/pil/2.1.html', + 'boolean': 'http://www.lua.org/pil/2.2.html', + 'number': 'http://www.lua.org/pil/2.3.html', + 'string': 'http://www.lua.org/pil/2.4.html', + 'table': 'http://www.lua.org/pil/2.5.html', + 'function': 'http://www.lua.org/pil/2.6.html', + '...': 'http://www.lua.org/pil/5.2.html', + } + + def data_type_parser(content): + # If the type is a Lua type, return a link to Lua documentation. + if content in lua_type_documentation: + url = lua_type_documentation[content] + return '{}'.format(url, content) + + # Otherwise try to build a link to the proper page. + if content in class_names: + class_name = content[1:-1] + url = '{}{}/index.html'.format(('../' * level), class_name) + return '{}'.format(url, class_name) + + # Case for enums to direct to a search on github + enum_name = content[1:-1] + url = 'https://github.com/ElunaLuaEngine/ElunaTrinityWotlk/search?l=cpp&q=%22enum+{}%22&type=Code&utf8=%E2%9C%93'.format(enum_name) + return '{}'.format(url, enum_name) + + # By default we just return the name without the [] around it + return content[1:-1] + + return link_parser, data_type_parser + + # Create the render function with the template path and parser maker. + render = make_renderer('ElunaDoc/templates', make_parsers) + + # Render the index. + render('index.html', 'index.html', level=0, classes=classes) + # Render the search index. + render('search-index.js', 'search-index.js', level=0, classes=classes) + # Render the date. + render('date.js', 'date.js', level=0, currdate=time.strftime("%d/%m/%Y")) + + for class_ in classes: + print(f'Rendering pages for class {class_.name}...') + + # Make a folder for the class. + os.mkdir('build/' + class_.name) + index_path = '{}/index.html'.format(class_.name) + sidebar_path = '{}/sidebar.js'.format(class_.name) + + # Render the class's index page. + render('class.html', index_path, level=1, classes=classes, current_class=class_) + + # Render the class's sidebar script. + render('sidebar.js', sidebar_path, level=1, classes=classes, current_class=class_) + + # Render each method's page. + for method in class_.methods: + method_path = '{}/{}.html'.format(class_.name, method.name) + render('method.html', method_path, level=1, current_class=class_, current_method=method) diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/parser.py b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/parser.py new file mode 100644 index 0000000..471c87f --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/parser.py @@ -0,0 +1,333 @@ +import re +import typing +import markdown +from typedecorator import params, returns, Nullable + + +class ParameterDoc(object): + """The documentation data of a parameter or return value for an Eluna method.""" + + # The integer ranges that each C++ type is valid for. None means valid for all numbers. + valid_ranges = { + 'float': None, + 'double': None, + 'int': ('-2,147,483,647', '2,147,483,647'), # This should be -32767..32767, but it's pretty safe to assume 32-bit. + 'int8': ('-127', '127'), + 'uint8': ('0', '255'), + 'int16': ('-32,767', '32,767'), + 'uint16': ('0', '65,535'), + 'int32': ('-2,147,483,647', '2,147,483,647'), + 'uint32': ('0', '4,294,967,295'), + 'int64': ('-9,223,372,036,854,775,808', '9,223,372,036,854,775,807'), + 'uint64': ('0', '18,446,744,073,709,551,615'), + 'ObjectGuid': ('0', '18,446,744,073,709,551,615'), + } + + @params(self=object, name=Nullable(str), data_type=str, description=str, default_value=Nullable(str)) + def __init__(self, name, data_type, description, default_value=None): + """If `name` is not provided, the Parameter is a returned value instead of a parameter.""" + self.name = name + self.data_type = data_type + self.default_value = default_value + + if self.data_type == '...': + self.name = '...' + else: + assert(self.name is not None) + + if description: + # Capitalize the first letter, add a period, and parse as Markdown. + self.description = '{}{}. '.format(description[0].capitalize(), description[1:]) + self.description = markdown.markdown(self.description) + else: + self.description = '' + + # If the data type is a C++ number, convert to Lua number and add range info to description. + if self.data_type in self.valid_ranges.keys(): + range = ParameterDoc.valid_ranges[self.data_type] + if range: + self.description += '

Valid numbers: integers from {0} to {1}.

'.format(range[0], range[1]) + else: + self.description += '

Valid numbers: all decimal numbers.

' + + self.data_type = 'number' + + elif self.data_type == 'bool': + self.data_type = 'boolean' + + elif self.data_type == 'int64' or self.data_type == 'uint64': + self.data_type = '[' + self.data_type + ']' + + elif not self.data_type in ['nil', 'boolean', 'number', 'string', 'table', 'function', '...'] and self.data_type[:1] != '[': + print(f"Missing angle brackets [] around the data type name: `{self.data_type}`") + + +class MethodDoc(object): + """The documentation data of an Eluna method.""" + @params(self=object, name=str, description=str, prototypes=[str], parameters=[ParameterDoc], returned=[ParameterDoc]) + def __init__(self, name, description, prototypes, parameters, returned): + self.name = name + self.prototypes = prototypes + self.parameters = parameters + self.returned = returned + + # Parse the description as Markdown. + self.description = markdown.markdown(description) + # Pull the first paragraph out of the description as the short description. + self.short_description = self.description.split('

')[0][3:] + # If it has a description, it is "documented". + self.documented = self.description != '' + + +class MangosClassDoc(object): + """The documentation of a MaNGOS class that has Lua methods.""" + @params(self=object, name=str, description=str, methods=[MethodDoc]) + def __init__(self, name, description, methods): + self.name = name + # Parse the description as Markdown. + self.description = markdown.markdown(description) + # Pull the first paragraph out of the description as the short description. + self.short_description = self.description.split('

')[0][3:] + # Sort the methods by their names. + self.methods = sorted(methods, key=lambda m: m.name) + + # If any of our methods are not documented, we aren't fully documented. + for method in methods: + if not method.documented: + self.fully_documented = False + break + else: + self.fully_documented = True + + # In the same vein, if any of our methods are documented, we aren't fully *un*documented. + for method in methods: + if method.documented: + self.fully_undocumented = False + break + else: + self.fully_undocumented = True + + +class ClassParser(object): + """Parses a file line-by-line and returns methods when enough information is received to build them.""" + + # Various regular expressions to parse different parts of the doc string. + # There are used to parse the class's description. + class_start_regex = re.compile(r"\s*/\*\*\*") # The start of class documentation, i.e. /*** + class_body_regex = re.compile(r"\s*\*\s*(.*)") # The "body", i.e. a * and optionally some descriptive text. + class_end_regex = re.compile(r"\s*\*/") # The end of the comment portion, i.e. */ + + # These are used to parse method documentation. + start_regex = re.compile(r"\s*/\*\*") # The start of documentation, i.e. /** + body_regex = re.compile(r"\s*\s?\*\s?(.*)") # The "body", i.e. a * and optionally some descriptive text. + # An extra optional space (\s?) was thrown in to make it different from `class_body_regex`. + + param_regex = re.compile(r"""\s*\*\s@param\s # The @param tag starts with opt. whitespace followed by "* @param ". + ([^\s]+)\s(\w+)? # The data type, a space, and the name of the param. + (?:\s=\s(\w+))? # The default value: a = surrounded by spaces, followed by text. + (?:\s:\s(.+))? # The description: a colon surrounded by spaces, followed by text. + """, re.X) + # This is the same as the @param tag, minus the default value part. + return_regex = re.compile(r"""\s*\*\s@return\s + ([\[\]\w]+)\s(\w+) + (?:\s:\s(.+))? + """, re.X) + proto_regex = re.compile(r"""\s*\*\s@proto\s + ([\w\s,]+)? # The list of arguments. + (?:=\s)? # An equals sign and a space separate the args and returns. + (?:\(([\w\s,]+)\))? # The list of return values, in parens. + """, re.X) + + comment_end_regex = re.compile(r"\s*\*/") # The end of the comment portion, i.e. */ + end_regex = re.compile(r"\s*int\s(\w+)\s*\(") # The end of the documentation, i.e. int MethodName( + + def __init__(self, class_name): + assert ClassParser.class_body_regex is not ClassParser.body_regex + # The methods that have been parsed. + self.methods = [] + # The name of the class being parsed. + self.class_name = class_name + # The description of the class being parsed. + self.class_description = '' + # Reset the parser's state machine. + self.reset() + + def reset(self): + # What the last handled regex was, to determine what the next should be. + self.last_regex = None + + # These are used to piece together the next `Method`. + self.description = '' + self.params = [] + self.returned = [] + self.method_name = None + self.prototypes = [] + + def handle_class_body(self, match): + text = match.group(1) + self.class_description += text + '\n' + + def handle_body(self, match): + text = match.group(1) + self.description += text + '\n' + + def handle_param(self, match): + data_type, name, default, description = match.group(1), match.group(2), match.group(3), match.group(4) + self.params.append(ParameterDoc(name, data_type, description, default)) + + def handle_return(self, match): + data_type, name, description = match.group(1), match.group(2), match.group(3) + self.returned.append(ParameterDoc(name, data_type, description)) + + def handle_proto(self, match): + return_values, parameters = match.group(1), match.group(2) + parameters = ' '+parameters+' ' if parameters else '' + return_values = return_values + '= ' if return_values else '' + + if self.class_name == 'Global': + prototype = '{0}{{0}}({1})'.format(return_values, parameters) + else: + prototype = '{0}{1}:{{0}}({2})'.format(return_values, self.class_name, parameters) + + self.prototypes.append(prototype) + + def handle_end(self, match): + self.method_name = match.group(1) + + def make_prototype(parameters): + if parameters != '': + parameters = ' ' + parameters + ' ' + + if self.class_name == 'Global': + if self.returned: + return_values = ', '.join([param.name for param in self.returned]) + prototype = '{0} = {1}({2})'.format(return_values, self.method_name, parameters) + else: + prototype = '{0}({1})'.format(self.method_name, parameters) + else: + if self.returned: + return_values = ', '.join([param.name for param in self.returned]) + prototype = '{0} = {1}:{2}({3})'.format(return_values, self.class_name, self.method_name, parameters) + else: + prototype = '{0}:{1}({2})'.format(self.class_name, self.method_name, parameters) + + return prototype + + # If there's no prototype, make one with all params and returns. + if not self.prototypes: + # A list of all parameters with default values. + params_with_default = [] + # The index of the last non-default parameter. + last_non_default_i = 0 + # If False, a parameter WITHOUT a default value follows one WITH a default value. + # In this case, don't bother generating prototypes. + simple_order = True + + for i, param in enumerate(self.params): + if param.default_value: + params_with_default.append(param) + else: + last_non_default_i = i + if params_with_default: + simple_order = False + + if not params_with_default or not simple_order: + # Just generate one prototype with all the parameters. + parameters = ', '.join([param.name for param in self.params]) + self.prototypes.append(make_prototype(parameters)) + else: + # Generate a prototype for all the non-default parameters, + # then one for each default parameter with all the previous parameters. + for i in range(last_non_default_i, len(self.params)): + parameters = ', '.join([param.name for param in self.params[:i+1]]) + self.prototypes.append(make_prototype(parameters)) + + else: + # Format the method name into each prototype. + self.prototypes = [proto.format(self.method_name) for proto in self.prototypes] + + self.methods.append(MethodDoc(self.method_name, self.description, self.prototypes, self.params, self.returned)) + + # Table of which handler is used to handle each regular expressions. + regex_handlers = { + class_start_regex: None, + class_body_regex: handle_class_body, + class_end_regex: None, + start_regex: None, + body_regex: handle_body, + param_regex: handle_param, + return_regex: handle_return, + proto_regex: handle_proto, + comment_end_regex: None, + end_regex: handle_end, + } + + # Table of which regular expressions can follow the last handled regex. + # `body_regex` must always come LAST when used, since it also matches param, return, and comment_end. + next_regexes = { + None: [class_start_regex, start_regex, end_regex], + class_start_regex: [class_end_regex, class_body_regex], + class_body_regex: [class_end_regex, class_body_regex], + class_end_regex: [], + start_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex], + body_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex], + proto_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex], + param_regex: [param_regex, return_regex, comment_end_regex, body_regex], + return_regex: [return_regex, comment_end_regex], + comment_end_regex: [end_regex], + end_regex: [], + } + + @returns(Nullable(MethodDoc)) + @params(self=object, line=str) + def next_line(self, line): + """Parse the next line of the file. + + This method returns a `Method` when enough data to form a `Method` has been parsed. + Otherwise, it returns None. + """ + # Get the list of expected regular expressions using the last one handled. + valid_regexes = self.next_regexes[self.last_regex] + + # Try to find a match. + for regex in valid_regexes: + match = regex.match(line) + + if match: + handler = self.regex_handlers[regex] + + if handler: + handler(self, match) + + # Not every regex has a handler, but keep track of where we are anyway. + self.last_regex = regex + # Break at the first match. + break + else: + # No valid regex was found, reset everything. + self.reset() + + @returns(MangosClassDoc) + def to_class_doc(self): + """Create an instance of `MangosClassDoc` from the parser's data. + + Is called by `parse_file` once parsing is finished. + """ + return MangosClassDoc(self.class_name, self.class_description, self.methods) + + @staticmethod + @returns(MangosClassDoc) + @params(file=typing.IO) + def parse_file(file): + """Parse the file `file` into a documented class.""" + # Get the class name from "ClassMethods.h" by stripping off "Methods.h". + class_name = file.name[:-len('Methods.h')] + parser = ClassParser(class_name) + + line = file.readline() + + while line: + parser.next_line(line) + line = file.readline() + + return parser.to_class_doc() diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Medium.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Medium.woff new file mode 100644 index 0000000..5627227 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Medium.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Regular.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Regular.woff new file mode 100644 index 0000000..9ff4044 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/FiraSans-Regular.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/Heuristica-Italic.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/Heuristica-Italic.woff new file mode 100644 index 0000000..b0cebf0 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/Heuristica-Italic.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Regular.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Regular.woff new file mode 100644 index 0000000..5576670 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Regular.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Semibold.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Semibold.woff new file mode 100644 index 0000000..ca972a1 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceCodePro-Semibold.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Bold.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Bold.woff new file mode 100644 index 0000000..ac1b1b3 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Bold.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Regular.woff b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Regular.woff new file mode 100644 index 0000000..e8c43b8 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/SourceSerifPro-Regular.woff differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/dark.css b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/dark.css new file mode 100644 index 0000000..a284615 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/dark.css @@ -0,0 +1,361 @@ +/* + _______ + / \ + .==. .==. + (( ))==(( )) + / "==" "=="\ + /____|| || ||___\ + ________ ____ ________ ___ ___ + | ___ \ / \ | ___ \ | | / / + | | \ \ / /\ \ | | \ \| |_/ / + | | ) / /__\ \ | |__/ /| ___ \ + | |__/ / ______ \| ____ \| | \ \ +_______|_______/__/ ____ \__\__|___\__\__|___\__\____ +| ___ \ | ____/ / \ | ___ \ | ____| ___ \ +| | \ \| |___ / /\ \ | | \ \| |___| | \ \ +| |__/ /| ____/ /__\ \ | | ) | ____| |__/ / +| ____ \| |__/ ______ \| |__/ /| |___| ____ \ +|__| \__\____/__/ \__\_______/ |______|__| \__\ + https://darkreader.org +*/ + +/*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/main/LICENSE */ + +/* User-Agent Style */ +html { + background-color: #181a1b !important; +} +html { + color-scheme: dark !important; +} +html, body, input, textarea, select, button, dialog { + background-color: #181a1b; +} +html, body, input, textarea, select, button { + border-color: #736b5e; + color: #e8e6e3; +} +a { + color: #3391ff; +} +table { + border-color: #545b5e; +} +::placeholder { + color: #b2aba1; +} +input:-webkit-autofill, +textarea:-webkit-autofill, +select:-webkit-autofill { + background-color: #404400 !important; + color: #e8e6e3 !important; +} +::-webkit-scrollbar { + background-color: #202324; + color: #aba499; +} +::-webkit-scrollbar-thumb { + background-color: #454a4d; +} +::-webkit-scrollbar-thumb:hover { + background-color: #575e62; +} +::-webkit-scrollbar-thumb:active { + background-color: #484e51; +} +::-webkit-scrollbar-corner { + background-color: #181a1b; +} +::selection { + background-color: #004daa !important; + color: #e8e6e3 !important; +} +::-moz-selection { + background-color: #004daa !important; + color: #e8e6e3 !important; +} + +/* Invert Style */ +.jfk-bubble.gtx-bubble, .captcheck_answer_label > input + img, span#closed_text > img[src^="https://www.gstatic.com/images/branding/googlelogo"], span[data-href^="https://www.hcaptcha.com/"] > #icon, #bit-notification-bar-iframe, ::-webkit-calendar-picker-indicator { + filter: invert(100%) hue-rotate(180deg) contrast(90%) !important; +} + +/* Variables Style */ +:root { + --darkreader-neutral-background: #131516; + --darkreader-neutral-text: #d8d4cf; + --darkreader-selection-background: #004daa; + --darkreader-selection-text: #e8e6e3; +} + +/* Modified CSS */ +body { + color: rgb(200, 195, 188); +} +h1, +h2, +h3:not(.impl):not(.method), +h4:not(.method) { + color: rgb(232, 230, 227); +} +h1.fqn { + border-bottom-color: rgb(60, 65, 67); +} +h2, +h3:not(.impl):not(.method), +h4:not(.method) { + border-bottom-color: rgb(58, 62, 65); +} +.docblock code { + background-color: rgb(30, 32, 33); +} +pre { + background-color: rgb(30, 32, 33); +} +.sidebar .location { + background-image: initial; + background-color: rgb(41, 44, 46); + color: rgb(200, 195, 188); +} +.block a:hover { + background-image: initial; + background-color: rgb(30, 32, 33); +} +.content pre.line-numbers { + border-color: initial; +} +.line-numbers span { + color: rgb(214, 149, 75); +} +.line-numbers .line-highlighted { + background-color: rgb(68, 73, 2); +} +.content .highlighted { + background-color: rgb(53, 57, 59); + color: rgb(232, 230, 227) !important; +} +.content .highlighted a { + color: rgb(232, 230, 227) !important; +} +.content .highlighted.trait { + background-color: rgb(128, 80, 1); +} +.content .highlighted.mod { + background-color: rgb(29, 54, 86); +} +.content .highlighted.enum { + background-color: rgb(47, 77, 58); +} +.content .highlighted.struct { + background-color: rgb(98, 42, 25); +} +.content .highlighted.fn { + background-color: rgb(78, 55, 59); +} +.docblock h1, +.docblock h2, +.docblock h3, +.docblock h4, +.docblock h5 { + border-bottom-color: rgb(58, 62, 65); +} +nav { + border-bottom-color: rgb(57, 61, 64); +} +nav.main .current { + border-top-color: rgb(140, 130, 115); + border-bottom-color: rgb(140, 130, 115); +} +nav.main .separator { + border-color: rgb(140, 130, 115); +} +a { + text-decoration-color: initial; + color: rgb(232, 230, 227); + background-image: initial; + background-color: transparent; +} +p a { + color: rgb(92, 155, 206); +} +p a:hover { + text-decoration-color: initial; +} +.content a.trait, +.block a.current.trait { + color: rgb(252, 173, 39); +} +.content a.mod, +.block a.current.mod { + color: rgb(115, 156, 193); +} +.content a.enum, +.block a.current.enum { + color: rgb(155, 146, 133); +} +.content a.struct, +.block a.current.struct { + color: rgb(255, 94, 44); +} +.content a.fn, +.block a.current.fn { + color: rgb(157, 149, 136); +} +.content .fnname { + color: rgb(157, 149, 136); +} +.search-input { + outline-color: initial; + border-color: initial; + color: rgb(178, 172, 162); + box-shadow: rgb(42, 45, 47) 0px 0px 0px 1px, + rgba(0, 0, 0, 0) 0px 0px 0px 2px; +} +.search-input:focus { + border-color: initial; + outline-color: initial; + box-shadow: rgb(6, 113, 173) 0px 0px 8px; +} +#help { + background-image: initial; + background-color: rgb(36, 39, 41); + box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 6px; + border-color: rgb(66, 72, 74); +} +#help dt { + border-color: rgb(66, 72, 74); + background-image: initial; + background-color: rgb(24, 26, 27); +} +.stability { + border-left-color: initial; +} +.stability.Deprecated { + border-color: rgb(100, 65, 106); + color: rgb(179, 123, 188); +} +.stability.Experimental { + border-color: rgb(124, 38, 36); + color: rgb(202, 101, 98); +} +.stability.Unstable { + border-color: rgb(124, 95, 36); + color: rgb(202, 167, 98); +} +.stability.Stable { + border-color: rgb(60, 120, 64); + color: rgb(123, 211, 128); +} +.stability.Frozen { + border-color: rgb(0, 211, 70); + color: rgb(121, 255, 164); +} +.stability.Locked { + border-color: rgb(0, 145, 200); + color: rgb(106, 215, 255); +} +.stability.Unmarked { + border-color: rgb(67, 73, 76); +} +.summary.Deprecated { + background-color: rgb(110, 72, 117); +} +.summary.Experimental { + background-color: rgb(129, 40, 37); +} +.summary.Unstable { + background-color: rgb(97, 74, 28); +} +.summary.Stable { + background-color: rgb(67, 134, 71); +} +.summary.Unmarked { + background-color: rgb(62, 68, 70); +} +:target { + background-image: initial; + background-color: rgb(56, 58, 0); +} +pre.rust .kw { + color: rgb(149, 105, 177); +} +pre.rust .kw-2, +pre.rust .prelude-ty { + color: rgb(114, 160, 201); +} +pre.rust .number, +pre.rust .string { + color: rgb(226, 255, 106); +} +pre.rust .self, +pre.rust .boolval, +pre.rust .prelude-val, +pre.rust .attribute, +pre.rust .attribute .ident { + color: rgb(219, 73, 73); +} +pre.rust .comment { + color: rgb(161, 152, 140); +} +pre.rust .doccomment { + color: rgb(184, 178, 168); +} +pre.rust .macro, +pre.rust .macro-nonterminal { + color: rgb(107, 192, 197); +} +pre.rust .lifetime { + color: rgb(236, 158, 81); +} +.methods .section-header { + border-bottom-color: initial !important; +} +.collapse-toggle { + color: rgb(168, 160, 149); +} +.toggle-label { + color: rgb(168, 160, 149); +} + +/* Override Style */ +.vimvixen-hint { + background-color: #7b5300 !important; + border-color: #d8b013 !important; + color: #f3e8c8 !important; +} +::placeholder { + opacity: 0.5 !important; +} +#edge-translate-panel-body, +.MuiTypography-body1, +.nfe-quote-text { + color: var(--darkreader-neutral-text) !important; +} +gr-main-header { + background-color: #0f3a48 !important; +} +.tou-z65h9k, +.tou-mignzq, +.tou-1b6i2ox, +.tou-lnqlqk { + background-color: var(--darkreader-neutral-background) !important; +} +.tou-75mvi { + background-color: #032029 !important; +} +.tou-ta9e87, +.tou-1w3fhi0, +.tou-1b8t2us, +.tou-py7lfi, +.tou-1lpmd9d, +.tou-1frrtv8, +.tou-17ezmgn { + background-color: #0a0a0a !important; +} +.tou-uknfeu { + background-color: #231603 !important; +} +.tou-6i3zyv { + background-color: #19576c !important; +} +embed[type="application/pdf"][src="about:blank"] { filter: invert(100%) contrast(90%); } diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/eluna-logo.png b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/eluna-logo.png new file mode 100644 index 0000000..6694768 Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/eluna-logo.png differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/favicon.ico b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/favicon.ico new file mode 100644 index 0000000..9c83cad Binary files /dev/null and b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/favicon.ico differ diff --git a/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/jquery.js b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/jquery.js new file mode 100644 index 0000000..2adda35 --- /dev/null +++ b/modules/mod-eluna/src/LuaEngine/docs/ElunaDoc/static/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length; +while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("