mirror of
https://github.com/araxiaonline/ets-module-collection.git
synced 2026-06-13 02:52:20 -04:00
Add all modules
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
ets.env
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.vscode
|
||||||
|
wow-wotlk-declarations
|
||||||
|
|
||||||
|
|
||||||
3
SQL/Gambler/SlotMachine.sql
Normal file
3
SQL/Gambler/SlotMachine.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
DELETE FROM `gameobject_template` WHERE (`entry` = 750001);
|
||||||
|
INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES
|
||||||
|
(750001, 1, 2373, 'Slot Machine', 'Interact', '', '', 0.6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0);
|
||||||
1733
SQL/achievement-tokens/db_world/achievements.sql
Normal file
1733
SQL/achievement-tokens/db_world/achievements.sql
Normal file
File diff suppressed because it is too large
Load Diff
9
SQL/araxia-tokens/db_character/player_stats.sql
Normal file
9
SQL/araxia-tokens/db_character/player_stats.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
-- TABLE FOR PLAYER STATS AND SETTINGS
|
||||||
|
CREATE TABLE `acore_characters`.`player_stats` (
|
||||||
|
`id` int NOT NULL, -- GUID of player
|
||||||
|
`name` varchar(150) COLLATE utf8mb4_general_ci NOT NULL,
|
||||||
|
`value` int DEFAULT '0',
|
||||||
|
`updated` int DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`,`name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
||||||
13
SQL/araxia-tokens/db_world/gobject-token-chest.sql
Normal file
13
SQL/araxia-tokens/db_world/gobject-token-chest.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
-- Token Chest
|
||||||
|
DELETE FROM `gameobject_template` WHERE (`entry` = 110000);
|
||||||
|
INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES
|
||||||
|
(110000, 3, 259, 'Token Chest', '', '', '', 1, 57, 110000, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0);
|
||||||
|
|
||||||
|
DELETE FROM `gameobject_template_addon` WHERE (`entry` = 110000);
|
||||||
|
INSERT INTO `gameobject_template_addon` (`entry`, `faction`, `flags`, `mingold`, `maxgold`, `artkit0`, `artkit1`, `artkit2`, `artkit3`) VALUES
|
||||||
|
(110000, 34, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
DELETE FROM `gameobject_loot_template` WHERE (`Entry` = 110000);
|
||||||
|
INSERT INTO `gameobject_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
|
||||||
|
(110000, 910001, 0, 100, 0, 1, 0, 1, 1, 'Token Chest - Araxia Token');
|
||||||
5
SQL/araxia-tokens/db_world/item-araxia-token.sql
Normal file
5
SQL/araxia-tokens/db_world/item-araxia-token.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
-- Item Araxia Token
|
||||||
|
DELETE FROM `item_template` WHERE (`entry` = 910001);
|
||||||
|
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||||
|
(910001, 15, 4, -1, 'Araxia Token', 32278, 4, 0, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 'Use to buy the rarest goods in the realm', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
|
||||||
3
SQL/soulswapper/db_world/soulswapper.sql
Normal file
3
SQL/soulswapper/db_world/soulswapper.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
DELETE FROM `gameobject_template` WHERE (`entry` = 750000);
|
||||||
|
INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES
|
||||||
|
(750000, 1, 6778, 'Soul Swapper', '', '', '', 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0);
|
||||||
5
SQL/special-items/db_world/harvesting-enhancers.sql
Normal file
5
SQL/special-items/db_world/harvesting-enhancers.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-- LEGENDARY DIAMOND PICKAXE GIVES BONUS ORE ON MINE
|
||||||
|
DELETE FROM `item_template` WHERE (`entry` = 910000);
|
||||||
|
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||||
|
(910000, 2, 14, -1, 'Diamond Pickaxe', 36594, 5, 0, 0, 1, 8100000, 16, 21, -1, -1, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 'Steve loaned this to me!', 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1024, 165, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 12340);
|
||||||
|
|
||||||
168
development/gothuk-oakenstein.lua
Normal file
168
development/gothuk-oakenstein.lua
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
local ____lualib = require("lualib_bundle")
|
||||||
|
local __TS__New = ____lualib.__TS__New
|
||||||
|
local __TS__ArrayIncludes = ____lualib.__TS__ArrayIncludes
|
||||||
|
local __TS__StringIncludes = ____lualib.__TS__StringIncludes
|
||||||
|
local ____exports = {}
|
||||||
|
local ____money = require("classes.money")
|
||||||
|
local ToCopper = ____money.ToCopper
|
||||||
|
local GetPlayerTax = ____money.GetPlayerTax
|
||||||
|
local ____account = require("classes.account")
|
||||||
|
local AccountInfo = ____account.AccountInfo
|
||||||
|
local spawned = {}
|
||||||
|
local NPCS = {
|
||||||
|
GOTHUK = 9000003,
|
||||||
|
BERNIE = 9000004,
|
||||||
|
EDWARD = 9000005,
|
||||||
|
LUNA = 9000006,
|
||||||
|
BOB_B = 9000007,
|
||||||
|
SHIVA = 9000008
|
||||||
|
}
|
||||||
|
local selectedItem = {}
|
||||||
|
local function GossipHello(____, event, player, creature)
|
||||||
|
local accountId = player:GetAccountId()
|
||||||
|
local bernieCost = ToCopper(nil, 1000) + GetPlayerTax(nil, player, 5)
|
||||||
|
player:GossipClearMenu()
|
||||||
|
do
|
||||||
|
local i = 23
|
||||||
|
while i <= 38 do
|
||||||
|
local item = player:GetItemByPos(255, i)
|
||||||
|
if item ~= nil then
|
||||||
|
print(item:GetItemLink())
|
||||||
|
if item:IsSoulBound() then
|
||||||
|
local quality = item:GetQuality()
|
||||||
|
if quality > 2 then
|
||||||
|
player:GossipMenuAddItem(
|
||||||
|
1,
|
||||||
|
"Item: " .. item:GetItemLink(),
|
||||||
|
1,
|
||||||
|
item:GetGUIDLow(),
|
||||||
|
nil,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
player:GossipSendMenu(NPCS.GOTHUK, creature, 10000)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local function GossipSelect(____, event, player, creature, selection, action, code, menuId)
|
||||||
|
PrintInfo("selection: " .. tostring(selection))
|
||||||
|
print("action " .. tostring(action))
|
||||||
|
local account = __TS__New(
|
||||||
|
AccountInfo,
|
||||||
|
player:GetAccountId()
|
||||||
|
)
|
||||||
|
local characters = account:GetCharacters()
|
||||||
|
if action > 15 then
|
||||||
|
do
|
||||||
|
local numC = 0
|
||||||
|
while numC < #characters do
|
||||||
|
local name = characters[numC + 1].name
|
||||||
|
if name ~= player:GetName() then
|
||||||
|
player:GossipMenuAddItem(
|
||||||
|
2,
|
||||||
|
"Send to: " .. name,
|
||||||
|
2,
|
||||||
|
numC + 1,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
numC = numC + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
selectedItem[player:GetName()] = action
|
||||||
|
player:GossipSendMenu(NPCS.GOTHUK, creature, 10000)
|
||||||
|
end
|
||||||
|
if action <= 15 then
|
||||||
|
local itemToChange = selectedItem[player:GetName()]
|
||||||
|
local itemGuid = GetItemGUID(itemToChange)
|
||||||
|
local PlayerItem = player:GetItemByGUID(itemGuid)
|
||||||
|
print((("Item Info: " .. PlayerItem:GetOwner():GetName()) .. " owns ") .. PlayerItem:GetName())
|
||||||
|
print("To Name is " .. characters[action].name)
|
||||||
|
local newItemGuid = SendMail(
|
||||||
|
"Item Soulswap " .. PlayerItem:GetName(),
|
||||||
|
"Soulbinder has sent you a gift " .. PlayerItem:GetName(),
|
||||||
|
characters[action].guid,
|
||||||
|
player:GetGUIDLow(),
|
||||||
|
41,
|
||||||
|
100,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
PlayerItem:GetEntry(),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
print((("send new item " .. tostring(newItemGuid)) .. " to ") .. characters[action].name)
|
||||||
|
player:GossipComplete()
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
--- This will load NPCs that shoud be loaded based on purchased guild benefits
|
||||||
|
-- and if system is enabled.
|
||||||
|
local function LoadNpcOnStart(____, event)
|
||||||
|
local npcs = {
|
||||||
|
9000003,
|
||||||
|
9000004,
|
||||||
|
9000005,
|
||||||
|
9000006,
|
||||||
|
9000007,
|
||||||
|
9000008
|
||||||
|
}
|
||||||
|
local result = WorldDBQuery("SELECT * from guild_elite_benefits")
|
||||||
|
do
|
||||||
|
local i = 0
|
||||||
|
while i < result:GetRowCount() do
|
||||||
|
local benefit = result:GetRow()
|
||||||
|
local entry = benefit.creature_entry
|
||||||
|
if benefit.purchased == 1 and not __TS__ArrayIncludes(spawned, entry) then
|
||||||
|
PerformIngameSpawn(
|
||||||
|
1,
|
||||||
|
entry,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
benefit.x,
|
||||||
|
benefit.y,
|
||||||
|
benefit.z,
|
||||||
|
benefit.o,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
PrintInfo("benefit.benefit,'was purchased!")
|
||||||
|
else
|
||||||
|
PrintInfo("benefit.benefit,'was NOT purchased!'")
|
||||||
|
end
|
||||||
|
result:NextRow()
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RegisterCreatureGossipEvent(
|
||||||
|
9000003,
|
||||||
|
1,
|
||||||
|
function(...) return GossipHello(nil, ...) end
|
||||||
|
)
|
||||||
|
RegisterCreatureGossipEvent(
|
||||||
|
9000003,
|
||||||
|
2,
|
||||||
|
function(...) return GossipSelect(nil, ...) end
|
||||||
|
)
|
||||||
|
local function seeItems(____, event, player, command)
|
||||||
|
if __TS__StringIncludes(command, "backpack") then
|
||||||
|
do
|
||||||
|
local i = 23
|
||||||
|
while i <= 38 do
|
||||||
|
local item = player:GetItemByPos(255, i)
|
||||||
|
print(item:GetName())
|
||||||
|
print(item:GetItemLink())
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
42,
|
||||||
|
function(...) return seeItems(nil, ...) end
|
||||||
|
)
|
||||||
|
return ____exports
|
||||||
245
development/gothuk-oakenstein.ts
Normal file
245
development/gothuk-oakenstein.ts
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
import { ToGold, ToCopper, GetPlayerTax } from "../modules/classes/money";
|
||||||
|
import { AccountInfo } from "../modules/classes/account";
|
||||||
|
|
||||||
|
const spawned:Array<number> = [];
|
||||||
|
const NPCS = {
|
||||||
|
GOTHUK: 9000003,
|
||||||
|
BERNIE: 9000004,
|
||||||
|
EDWARD: 9000005,
|
||||||
|
LUNA: 9000006,
|
||||||
|
BOB_B: 9000007,
|
||||||
|
SHIVA: 9000008
|
||||||
|
};
|
||||||
|
const selectedItem: Record<string, number> = {};
|
||||||
|
const GossipHello : gossip_event_on_hello = (event: number, player: Player, creature: EObject) => {
|
||||||
|
|
||||||
|
const accountId = player.GetAccountId();
|
||||||
|
|
||||||
|
// NPC Hire Costs
|
||||||
|
const bernieCost = ToCopper(1000) + GetPlayerTax(player,5);
|
||||||
|
|
||||||
|
player.GossipClearMenu();
|
||||||
|
|
||||||
|
let items = 0;
|
||||||
|
for(let i=23; i <= 38; i++ ) {
|
||||||
|
let item = player.GetItemByPos(255, i);
|
||||||
|
if(item != undefined) {
|
||||||
|
print(item.GetItemLink());
|
||||||
|
if(item.IsSoulBound() ) {
|
||||||
|
const quality = item.GetQuality();
|
||||||
|
if(quality > 2) {
|
||||||
|
items += 1;
|
||||||
|
player.GossipMenuAddItem(1,`Item: ${item.GetItemLink()}`,1,item.GetGUIDLow(), undefined, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// print(item.GetName());
|
||||||
|
// print(item.GetItemLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(items === 0) {
|
||||||
|
player.SendNotification("You have no soulbound items in your backback to send to your other characters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.GossipMenuAddItem(1,`Stop using the device`,1,50500);
|
||||||
|
|
||||||
|
// player.GossipMenuAddItem(1,`Hire Grandmaster Smith - (Reset Timers) 200g`,1,10,undefined,undefined,10000*200);
|
||||||
|
// player.GossipMenuAddItem(1,`Hire Grandmaster Tailor - (Reset Timers) 200g`,1,20,undefined,undefined,10000*200);
|
||||||
|
// // // player.GossipMenuAddItem(1,`Hire Grandmaster Leatherworker - (Reset Timers) 200g`, 1,30, undefined, undefined, 10000*200);
|
||||||
|
// // player.GossipMenuAddItem(1,`Hire Grandmaster Jewelcrafter - (Reset Timers) 200g`, 1,40, undefined, undefined, 10000*200);
|
||||||
|
// player.GossipMenuAddItem(1,`Hire Bernie, Leather Trader - ${ToGold(bernieCost)}g`, NPCS.BERNIE,50, undefined, undefined, bernieCost);
|
||||||
|
// // player.GossipMenuAddItem(1,`Epic Tradeskill Vendor - 650g`, 1,60, undefined, undefined, 10000*650);
|
||||||
|
// // player.GossipMenuAddItem(1,`Secret Goods Vendor 1300g`, 1,80, undefined, undefined, 10000*1300);
|
||||||
|
// player.GossipMenuAddItem(0, `I will leave you alone`,1,2);
|
||||||
|
player.GossipSendMenu(NPCS.GOTHUK, creature, 10000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GossipSelect: gossip_event_on_select = (event: number, player: Player, creature: any, selection, action, code, menuId) => {
|
||||||
|
|
||||||
|
PrintInfo(`selection: ${selection}`);
|
||||||
|
print(`action ${action}`);
|
||||||
|
|
||||||
|
// const cost = 100000;
|
||||||
|
// const inGold = cost / 10000;
|
||||||
|
const account = new AccountInfo(player.GetAccountId());
|
||||||
|
const characters = account.GetCharacters();
|
||||||
|
|
||||||
|
if(action === 50500) {
|
||||||
|
player.GossipClearMenu();
|
||||||
|
player.GossipComplete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// player.GossipClearMenu();
|
||||||
|
|
||||||
|
if(action > 15) {
|
||||||
|
for(let numC = 0; numC < characters.length; numC++) {
|
||||||
|
let name = characters[numC].name;
|
||||||
|
|
||||||
|
if(name != player.GetName()) {
|
||||||
|
// player.GossipMenuAddItem(2, `Send to: ${name}`, 2, numC+1, undefined, `Are you sure you will to rebind this item to ${name}?`, 10000);
|
||||||
|
player.GossipMenuAddItem(2, `Send to: ${name}`, 2, numC+1, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedItem[player.GetName()] = action;
|
||||||
|
|
||||||
|
player.GossipSendMenu(NPCS.GOTHUK, creature, 10000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action <= 15) {
|
||||||
|
|
||||||
|
let itemToChange = selectedItem[player.GetName()];
|
||||||
|
let itemGuid = GetItemGUID(itemToChange);
|
||||||
|
|
||||||
|
const PlayerItem = player.GetItemByGUID(itemGuid);
|
||||||
|
print(`Item Info: ${PlayerItem.GetOwner().GetName()} owns ${PlayerItem.GetName()}`);
|
||||||
|
|
||||||
|
let newItemGuid = SendMail(
|
||||||
|
`Item Rebound ${PlayerItem.GetName()}`,
|
||||||
|
`Soulbinder has sent you a gift ${PlayerItem.GetName()}`,
|
||||||
|
characters[action-1].guid,
|
||||||
|
player.GetGUIDLow(),
|
||||||
|
MailStationery.MAIL_STATIONERY_DEFAULT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
PlayerItem.GetEntry(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
print(`To Name is ${characters[action-1].name}`);
|
||||||
|
player.RemoveItem(PlayerItem, PlayerItem.GetEntry(), 1);
|
||||||
|
|
||||||
|
print(`send new item ${newItemGuid} to ${characters[action-1].name}`);
|
||||||
|
player.GossipClearMenu();
|
||||||
|
player.GossipComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const MapLog: map_event_on_player_enter = (event: number, map: EMap, player:Player) => {
|
||||||
|
|
||||||
|
// PrintInfo(map.GetName());
|
||||||
|
// PrintInfo(`${map.GetInstanceId()}`);
|
||||||
|
|
||||||
|
// PrintInfo(`${player.GetZoneId()}`);
|
||||||
|
// PrintInfo(`${GetGameTime()}`);
|
||||||
|
|
||||||
|
// if(player.GetZoneId() == 876) {
|
||||||
|
// WorldDBExecute(`insert into guild_house_log VALUES(null,'${player.GetGUID()}','${player.GetName()} entered the guild house', CURTIME())`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will load NPCs that shoud be loaded based on purchased guild benefits
|
||||||
|
* and if system is enabled.
|
||||||
|
*/
|
||||||
|
const LoadNpcOnStart: eluna_event_on_lua_state_open = (event: number) => {
|
||||||
|
const npcs = [
|
||||||
|
9000003, // Gothuk
|
||||||
|
9000004, // Bernie
|
||||||
|
9000005, // Edward
|
||||||
|
9000006, // Luna
|
||||||
|
9000007, // Bob B
|
||||||
|
9000008 // Shiva
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = WorldDBQuery("SELECT * from guild_elite_benefits");
|
||||||
|
|
||||||
|
for(let i =0; i < result.GetRowCount(); i++ ) {
|
||||||
|
let benefit = result.GetRow();
|
||||||
|
let entry = benefit.creature_entry as number;
|
||||||
|
|
||||||
|
if(benefit.purchased === 1 && !spawned.includes(entry)) {
|
||||||
|
|
||||||
|
PerformIngameSpawn(1,entry,1,0,
|
||||||
|
// location data
|
||||||
|
benefit.x as number,
|
||||||
|
benefit.y as number,
|
||||||
|
benefit.z as number,
|
||||||
|
benefit.o as number,
|
||||||
|
false);
|
||||||
|
|
||||||
|
|
||||||
|
PrintInfo(`benefit.benefit,'was purchased!`);
|
||||||
|
} else {
|
||||||
|
PrintInfo(`benefit.benefit,'was NOT purchased!'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.NextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for(const npcId of npcs) {
|
||||||
|
// Get
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterServerEvent(
|
||||||
|
// ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN,
|
||||||
|
// (...args) => {
|
||||||
|
// let spawned = [];
|
||||||
|
// LoadNpcOnStart(...args)
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
|
||||||
|
// PerformIngameSpawn(1,9000003,1,0,16221.8,16278,20.9032,4.70345,false);
|
||||||
|
|
||||||
|
// const object = GetObjectGUID(3110516,9000003);
|
||||||
|
|
||||||
|
|
||||||
|
RegisterCreatureGossipEvent(
|
||||||
|
9000003,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_HELLO,
|
||||||
|
(...args) => GossipHello(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterCreatureGossipEvent(
|
||||||
|
9000003,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_SELECT,
|
||||||
|
(...args) => GossipSelect(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterGameObjectGossipEvent(
|
||||||
|
750000,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_HELLO,
|
||||||
|
(...args) => GossipHello(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterGameObjectGossipEvent(
|
||||||
|
750000,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_SELECT,
|
||||||
|
(...args) => GossipSelect(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// RegisterServerEvent(
|
||||||
|
// ServerEvents.MAP_EVENT_ON_PLAYER_ENTER,
|
||||||
|
// (...args) => MapLog(...args)
|
||||||
|
// )
|
||||||
|
|
||||||
|
const seeItems: player_event_on_command = (event: number, player: Player, command: string): boolean => {
|
||||||
|
if(command.includes('backpack')) {
|
||||||
|
for(let i=23; i <= 38; i++ ) {
|
||||||
|
let item = player.GetItemByPos(255, i);
|
||||||
|
print(item.GetName());
|
||||||
|
print(item.GetItemLink());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => seeItems(...args));
|
||||||
|
|
||||||
28
development/player_command.ts
Normal file
28
development/player_command.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class Command {
|
||||||
|
|
||||||
|
onCommand : player_event_on_command = (
|
||||||
|
event: number,
|
||||||
|
player: Player,
|
||||||
|
command: string
|
||||||
|
) => {
|
||||||
|
|
||||||
|
if(command == "doit") {
|
||||||
|
const message = "A Command from the script has been entered" + command;
|
||||||
|
print(message);
|
||||||
|
|
||||||
|
|
||||||
|
SendWorldMessage(message);
|
||||||
|
}
|
||||||
|
print("debug: " + command);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const commandHander = new Command();
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_COMMAND,
|
||||||
|
(...args) => commandHander.onCommand(...args)
|
||||||
|
)
|
||||||
56
development/soulswapper/soulswapper-client.ts
Normal file
56
development/soulswapper/soulswapper-client.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
|
||||||
|
|
||||||
|
if(!aio.AddAddon()) {
|
||||||
|
|
||||||
|
const myHandlers = aio.AddHandlers('AIOTest', {});
|
||||||
|
const FrameTest = CreateFrame("Frame", "FrameTest2", UIParent, "UIPanelDialogTemplate");
|
||||||
|
let frame = FrameTest;
|
||||||
|
|
||||||
|
frame.SetSize(400,300);
|
||||||
|
frame.SetMovable(true);
|
||||||
|
frame.RegisterForDrag("LeftButton");
|
||||||
|
frame.SetPoint("CENTER");
|
||||||
|
frame.EnableMouse(true);
|
||||||
|
frame.Hide();
|
||||||
|
frame.SetHyperlinksEnabled(true);
|
||||||
|
|
||||||
|
frame.SetScript("OnHyperlinkClick")
|
||||||
|
frame.SetScript("OnDragStart", frame.StartMoving);
|
||||||
|
frame.SetScript("OnHide", frame.StopMovingOrSizing);
|
||||||
|
frame.SetScript("OnDragStop", frame.StopMovingOrSizing);
|
||||||
|
|
||||||
|
let increment = -40;
|
||||||
|
|
||||||
|
frame.SetScript("OnEnter", (frame: WoWAPI.Frame) => {
|
||||||
|
|
||||||
|
if(CursorHasItem()) {
|
||||||
|
let [objectType, objectId, link] = GetCursorInfo();
|
||||||
|
const text = frame.CreateFontString('itemdragged', "OVERLAY", "GameFontHighlight");
|
||||||
|
text.SetPoint("TOPLEFT", 10,increment);
|
||||||
|
text.SetText(link);
|
||||||
|
increment = increment - 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// if(CursorHasItem()) {
|
||||||
|
// print(type);
|
||||||
|
// print(GetCursorInfo());
|
||||||
|
// print(details);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// print(CursorHasItem());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
myHandlers.ShowFrame = (player: Player) => {
|
||||||
|
frame.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.Show();
|
||||||
|
|
||||||
|
}
|
||||||
21
development/soulswapper/soulswapper-server.ts
Normal file
21
development/soulswapper/soulswapper-server.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
const myHandlers = aio.AddHandlers('AIOTest', {});
|
||||||
|
|
||||||
|
myHandlers.print = (...args) => {
|
||||||
|
print(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShowWindow: player_event_on_command = (event: number,player: Player, command: string): boolean => {
|
||||||
|
if(command == 'testwin') {
|
||||||
|
aio.Handle(player, 'AIOTest', 'ShowFrame');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_COMMAND,
|
||||||
|
(...args) => ShowWindow(...args)
|
||||||
|
);
|
||||||
|
|
||||||
41
development/specialty_items/index.ts
Normal file
41
development/specialty_items/index.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const COPPER_ORE = 2770;
|
||||||
|
|
||||||
|
const HandleSpell: player_event_on_spell_cast = (event: number, player: Player, spell: Spell, skipCheck: boolean) => {
|
||||||
|
print(spell.GetEntry());
|
||||||
|
print(skipCheck);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// State Changes
|
||||||
|
// 1 - Ready / Deactivated
|
||||||
|
// 2 - Activated
|
||||||
|
// 3 - Looting
|
||||||
|
const HandleMiningLoot: gameobject_event_on_loot_state_change = (event: number, gameObj: GameObject, state: number) => {
|
||||||
|
print(gameObj.GetName());
|
||||||
|
print(`State change: ${state}`);
|
||||||
|
|
||||||
|
let player = gameObj.GetNearestPlayer();
|
||||||
|
print(player.GetName());
|
||||||
|
|
||||||
|
// Is Mining and has special pick
|
||||||
|
if(state === 3) {
|
||||||
|
if(player.HasItem(910000)) {
|
||||||
|
let quantity = Math.ceil(Math.random() * 3);
|
||||||
|
player.AddItem(COPPER_ORE,quantity);
|
||||||
|
player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_LOOT, Language.LANG_COMMON, `Your Diamond Axe grants you gifts from beyond!`, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_SPELL_CAST,
|
||||||
|
(...args) => HandleSpell(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterGameObjectEvent(
|
||||||
|
1731,
|
||||||
|
GameObjectEvents.GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE,
|
||||||
|
(...args) => HandleMiningLoot(...args)
|
||||||
|
)
|
||||||
59
modules/UI/aio.example.client.ts
Normal file
59
modules/UI/aio.example.client.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
|
||||||
|
if(!aio.AddAddon()) {
|
||||||
|
const myHandlers = aio.AddHandlers('AIOTest', {});
|
||||||
|
const MainFrame = CreateFrame("Frame", "MainFrame", UIParent, "UIPanelDialogTemplate");
|
||||||
|
let frame = MainFrame;
|
||||||
|
|
||||||
|
frame.SetSize(800,600);
|
||||||
|
frame.SetMovable(true);
|
||||||
|
frame.RegisterForDrag("LeftButton");
|
||||||
|
frame.SetPoint("CENTER", 0, 20);
|
||||||
|
frame.EnableMouse(true);
|
||||||
|
frame.Hide();
|
||||||
|
|
||||||
|
|
||||||
|
frame.SetScript("OnDragStart", frame.StartMoving);
|
||||||
|
frame.SetScript("OnHide", frame.StopMovingOrSizing);
|
||||||
|
frame.SetScript("OnDragStop", frame.StopMovingOrSizing);
|
||||||
|
|
||||||
|
let increment = -40;
|
||||||
|
|
||||||
|
const ImgFrame = CreateFrame("Frame", "ImgFrame", frame);
|
||||||
|
ImgFrame.SetSize(800,600);
|
||||||
|
ImgFrame.SetPoint("CENTER", 0, 20 );
|
||||||
|
ImgFrame.SetFrameLevel(1);
|
||||||
|
|
||||||
|
const PageFrame = MainFrame.CreateTexture("MainFrameImgTexture", null, ImgFrame);
|
||||||
|
PageFrame.SetSize(512,512);
|
||||||
|
PageFrame.SetPoint("CENTER", 0, -15);
|
||||||
|
PageFrame.SetTexture("Interface/Comics/Comic_Page3");
|
||||||
|
|
||||||
|
|
||||||
|
frame.SetScript("OnEnter", (frame) => {
|
||||||
|
|
||||||
|
if(CursorHasItem()) {
|
||||||
|
let [objectType, objectId, link] = GetCursorInfo();
|
||||||
|
const text = frame.CreateFontString('itemdragged', "OVERLAY", "GameFontHighlight");
|
||||||
|
text.SetPoint("TOPLEFT", 10,increment);
|
||||||
|
text.SetText(link);
|
||||||
|
increment = increment - 15;
|
||||||
|
}
|
||||||
|
// if(CursorHasItem()) {
|
||||||
|
// print(type);
|
||||||
|
// print(GetCursorInfo());
|
||||||
|
// print(details);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// print(CursorHasItem());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
myHandlers.ShowFrame = (player: Player) => {
|
||||||
|
frame.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
23
modules/UI/aio.example.server.ts
Normal file
23
modules/UI/aio.example.server.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
const myHandlers = aio.AddHandlers('AIOTest', {});
|
||||||
|
|
||||||
|
myHandlers.print = (...args) => {
|
||||||
|
print(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const frame = CreateFrame
|
||||||
|
|
||||||
|
const ShowWindow: player_event_on_command = (event: number,player: Player, command: string): boolean => {
|
||||||
|
if(command == 'testwin') {
|
||||||
|
aio.Handle(player, 'AIOTest', 'ShowFrame');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_COMMAND,
|
||||||
|
(...args) => ShowWindow(...args)
|
||||||
|
);
|
||||||
|
|
||||||
232
modules/UI/gambler/gambler.client.ts
Normal file
232
modules/UI/gambler/gambler.client.ts
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
if(!aio.AddAddon()) {
|
||||||
|
|
||||||
|
const gamblerHandlers = aio.AddHandlers('GamblerMain', {});
|
||||||
|
|
||||||
|
const classImages = [
|
||||||
|
"Interface/Gambler/druid",
|
||||||
|
"Interface/Gambler/deathknight",
|
||||||
|
"Interface/Gambler/hunter",
|
||||||
|
"Interface/Gambler/mage",
|
||||||
|
"Interface/Gambler/paladin",
|
||||||
|
"Interface/Gambler/priest",
|
||||||
|
"Interface/Gambler/rogue",
|
||||||
|
"Interface/Gambler/shaman",
|
||||||
|
"Interface/Gambler/warlock",
|
||||||
|
"Interface/Gambler/warrior",
|
||||||
|
];
|
||||||
|
|
||||||
|
let slotSpin = [];
|
||||||
|
let multiplier = 1;
|
||||||
|
|
||||||
|
// this function will randomly select a class image from the array above
|
||||||
|
function getRandomClassImage() {
|
||||||
|
const spinIndex = Math.floor(Math.random() * classImages.length);
|
||||||
|
slotSpin.push(spinIndex);
|
||||||
|
|
||||||
|
return classImages[spinIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the spin
|
||||||
|
function resetSpin () {
|
||||||
|
slotSpin = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function determineWin(): number {
|
||||||
|
let win = 0;
|
||||||
|
let gold = 0;
|
||||||
|
let tokens = 0;
|
||||||
|
|
||||||
|
// Jackpot is all 3 slots as deathknight arthas
|
||||||
|
if(slotSpin[0] == 1 && slotSpin[1] == 1 && slotSpin[2] == 1) {
|
||||||
|
|
||||||
|
if(multiplier == 3) {
|
||||||
|
tokens = 100;
|
||||||
|
}
|
||||||
|
gold = multiplier * 5000;
|
||||||
|
win = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(slotSpin[0] == slotSpin[1] && slotSpin[1] == slotSpin[2]) {
|
||||||
|
if(multiplier == 3) {
|
||||||
|
tokens = 50;
|
||||||
|
}
|
||||||
|
gold = multiplier * 1000;
|
||||||
|
win = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deathknights are considered wild cards
|
||||||
|
if(
|
||||||
|
(slotSpin[0] == slotSpin[1] && slotSpin[2] === 1) ||
|
||||||
|
(slotSpin[0] == slotSpin[2] && slotSpin[1] === 1) ||
|
||||||
|
(slotSpin[1] == slotSpin[2] && slotSpin[0] === 1) ||
|
||||||
|
(slotSpin[0] == 1 && slotSpin[1] === 1) ||
|
||||||
|
(slotSpin[0] == 1 && slotSpin[2] === 1) ||
|
||||||
|
(slotSpin[1] == 1 && slotSpin[2] === 1)
|
||||||
|
|
||||||
|
) {
|
||||||
|
if(multiplier == 3) {
|
||||||
|
tokens = 20;
|
||||||
|
}
|
||||||
|
gold = multiplier * 500;
|
||||||
|
win = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle two of the same class in a row
|
||||||
|
if((slotSpin[0] == slotSpin[1]) && win == 0) {
|
||||||
|
gold = multiplier * 250;
|
||||||
|
win = 1;
|
||||||
|
|
||||||
|
if(slotSpin[1] == 1) {
|
||||||
|
if(multiplier == 3) {
|
||||||
|
tokens = 3;
|
||||||
|
}
|
||||||
|
gold = multiplier * 250;
|
||||||
|
win = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return money on any lich king wild
|
||||||
|
if((slotSpin[0] == 1 || slotSpin[1] == 1 || slotSpin[2] == 1) && win == 0) {
|
||||||
|
if(multiplier == 3) {
|
||||||
|
tokens = 0;
|
||||||
|
gold = 100;
|
||||||
|
} else {
|
||||||
|
tokens = 0;
|
||||||
|
gold = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
win = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(win > 0) {
|
||||||
|
PlaySoundFile("Sound\\Interface\\LootCoinLarge.wav", "Master");
|
||||||
|
aio.Handle("GamblerMain", "AwardSlotWin", gold, tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SpinSlots(SlotFrame: WoWAPI.Frame, Slot: WoWAPI.Texture[]) {
|
||||||
|
let timer = 1;
|
||||||
|
let counter = 1;
|
||||||
|
|
||||||
|
PlaySoundFile("Sound\\Doodad\\GnomeMachine02StandLoop.wav", "Master");
|
||||||
|
SlotFrame.SetScript("OnUpdate", (frame, elapsed) => {
|
||||||
|
timer = timer + elapsed;
|
||||||
|
if(timer > 0.20) {
|
||||||
|
counter = counter + 1;
|
||||||
|
|
||||||
|
resetSpin();
|
||||||
|
timer = 0;
|
||||||
|
Slot[0].SetTexture(getRandomClassImage());
|
||||||
|
Slot[1].SetTexture(getRandomClassImage());
|
||||||
|
Slot[2].SetTexture(getRandomClassImage());
|
||||||
|
|
||||||
|
if(counter > 22) {
|
||||||
|
frame.SetScript("OnUpdate", null);
|
||||||
|
|
||||||
|
determineWin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function ShowSlots(player: Player) {
|
||||||
|
|
||||||
|
const GamblerMainFrame = CreateFrame("Frame", "GamblerMainFrame", UIParent, "UIPanelDialogTemplate");
|
||||||
|
|
||||||
|
GamblerMainFrame.SetSize(512,324);
|
||||||
|
GamblerMainFrame.SetMovable(false);
|
||||||
|
GamblerMainFrame.SetPoint("CENTER");
|
||||||
|
GamblerMainFrame.EnableMouse(true);
|
||||||
|
GamblerMainFrame.EnableKeyboard(true);
|
||||||
|
GamblerMainFrame.Hide();
|
||||||
|
|
||||||
|
const Title = GamblerMainFrame.CreateFontString("TitleFrame", "OVERLAY", "GameFontHighlight");
|
||||||
|
Title.SetPoint("TOPLEFT", 15, -10);
|
||||||
|
Title.SetText("Heros Slots");
|
||||||
|
Title.SetFont("Fonts\\FRIZQT__.TTF", 10);
|
||||||
|
|
||||||
|
// Slots Display Window
|
||||||
|
const Slots = CreateFrame("Frame", "SlotsFrame", GamblerMainFrame);
|
||||||
|
Slots.SetSize(420,160);
|
||||||
|
Slots.SetPoint("CENTER", 0, 25);
|
||||||
|
Slots.SetFrameLevel(1);
|
||||||
|
Slots.SetBackdrop({
|
||||||
|
bgFile: "Interface/DialogFrame/UI-DialogBox-Background",
|
||||||
|
edgeFile: "Interface/DialogFrame/UI-DialogBox-Border",
|
||||||
|
tile: true,
|
||||||
|
tileSize: 32,
|
||||||
|
edgeSize: 32,
|
||||||
|
insets: {
|
||||||
|
left: 11,
|
||||||
|
right: 12,
|
||||||
|
top: 12,
|
||||||
|
bottom: 11
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Slot Columns 1 - 3
|
||||||
|
const Slot1 = Slots.CreateTexture("Slot1Texture", null, Slots);
|
||||||
|
Slot1.SetSize(128,128);
|
||||||
|
Slot1.SetAlpha(0.85);
|
||||||
|
Slot1.SetPoint("TOPLEFT", 13, -16);
|
||||||
|
Slot1.SetTexture(getRandomClassImage());
|
||||||
|
|
||||||
|
let [ Slot1Point, Slot1Region, Slot1RelPoint, x1offset, y1offset ] = Slot1.GetPoint();
|
||||||
|
|
||||||
|
const Slot2 = Slots.CreateTexture("Slot2Texture", null, Slots);
|
||||||
|
Slot2.SetSize(128,128);
|
||||||
|
Slot2.SetAlpha(0.85);
|
||||||
|
Slot2.SetPoint("TOPLEFT", Slot1Region, Slot1RelPoint, x1offset + 128 + 5, y1offset);
|
||||||
|
Slot2.SetTexture(getRandomClassImage());
|
||||||
|
|
||||||
|
let [ Slot2Point, Slot2Region, Slot2RelPoint, x2offset, y2offset ] = Slot2.GetPoint();
|
||||||
|
|
||||||
|
const Slot3 = Slots.CreateTexture("Slot3Texture", null, Slots);
|
||||||
|
Slot3.SetSize(128,128);
|
||||||
|
Slot3.SetAlpha(0.85);
|
||||||
|
Slot3.SetPoint("TOPLEFT", Slot2Region, Slot2RelPoint, x2offset + 128 + 5, y2offset);
|
||||||
|
Slot3.SetTexture(getRandomClassImage());
|
||||||
|
|
||||||
|
// Low bet button.
|
||||||
|
const SpinButton = CreateFrame("Button", "SpinButtonLow", GamblerMainFrame, "UIPanelButtonTemplate");
|
||||||
|
SpinButton.SetSize(128,32);
|
||||||
|
SpinButton.SetPoint("CENTER", -80, -80);
|
||||||
|
SpinButton.SetText("Bet 20g Spin");
|
||||||
|
SpinButton.SetFrameLevel(2);
|
||||||
|
SpinButton.SetScript("OnClick", (frame, mouse, button) => {
|
||||||
|
resetSpin();
|
||||||
|
multiplier = 1;
|
||||||
|
aio.Handle("GamblerMain", "PayForSpin", 20*10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
const SpinButtonHigh = CreateFrame("Button", "SpinButtonHigh", GamblerMainFrame, "UIPanelButtonTemplate");
|
||||||
|
SpinButtonHigh.SetSize(128,32);
|
||||||
|
SpinButtonHigh.SetPoint("CENTER", 80, -80);
|
||||||
|
SpinButtonHigh.SetText("Bet 100g Spin");
|
||||||
|
SpinButtonHigh.SetFrameLevel(2);
|
||||||
|
SpinButtonHigh.SetScript("OnClick", (frame, mouse, button) => {
|
||||||
|
resetSpin();
|
||||||
|
multiplier = 3;
|
||||||
|
aio.Handle("GamblerMain", "PayForSpin", 100*10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
gamblerHandlers.StartSpin = (player: Player) => {
|
||||||
|
SpinSlots(Slots, [Slot1, Slot2, Slot3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GamblerMainFrame.Show();
|
||||||
|
|
||||||
|
return GamblerMainFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
gamblerHandlers.ShowFrame = (player: Player) => {
|
||||||
|
ShowSlots(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
71
modules/UI/gambler/gambler.server.ts
Normal file
71
modules/UI/gambler/gambler.server.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/** @ts-expect-error */
|
||||||
|
let aio: AIO = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gambler - Slot Machine
|
||||||
|
* This is the server side code used to add gambling games to the server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Game OBject that will start the slot machine up
|
||||||
|
*/
|
||||||
|
const SLOT_GAME_OBJECT = 750001;
|
||||||
|
|
||||||
|
|
||||||
|
const ShowGambler: player_event_on_command = (event: number,player: Player, command: string): boolean => {
|
||||||
|
if(command == 'gamble') {
|
||||||
|
aio.Handle(player, 'GamblerMain', 'ShowFrame');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noSelf
|
||||||
|
*/
|
||||||
|
function PayForSpin(this:void, player: Player, cost: number): void {
|
||||||
|
const money = player.GetCoinage();
|
||||||
|
if(money >= cost) {
|
||||||
|
player.ModifyMoney(cost * -1);
|
||||||
|
aio.Handle(player, 'GamblerMain', 'StartSpin');
|
||||||
|
} else {
|
||||||
|
player.SendNotification("You don't have enough money to spin the slots!");
|
||||||
|
player.PlayDirectSound(8959, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function AwardSlotWin(this:void, player: Player, gold: number, tokens: number): void {
|
||||||
|
player.ModifyMoney(gold*10000);
|
||||||
|
if(tokens > 0) {
|
||||||
|
player.AddItem(910001, tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tokens > 75) {
|
||||||
|
player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_GUILD, 0, `|cff1eff00I HIT THE JACKPOT! I won ${gold} gold and ${tokens} tokens!`, player);
|
||||||
|
} else {
|
||||||
|
if(tokens > 0) {
|
||||||
|
player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_GUILD, 0, `|cff1eff00I won ${gold} gold and ${tokens} tokens!`, player);
|
||||||
|
} else {
|
||||||
|
player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_GUILD, 0, `|cff1eff00I won ${gold} gold`, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const SendSlotStart: gameobject_event_on_use = (event: number, gameobject: GameObject, player: Player): boolean => {
|
||||||
|
aio.Handle(player, 'GamblerMain', 'ShowFrame');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gamblerHandlers = aio.AddHandlers('GamblerMain', {
|
||||||
|
PayForSpin,
|
||||||
|
AwardSlotWin
|
||||||
|
});
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_COMMAND,
|
||||||
|
(...args) => ShowGambler(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterGameObjectEvent(SLOT_GAME_OBJECT, GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, (...args) => SendSlotStart(...args));
|
||||||
35
modules/classes/account.ts
Normal file
35
modules/classes/account.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Class for find out information about an account
|
||||||
|
*/
|
||||||
|
export type BasicCharacter = {
|
||||||
|
guid: number,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AccountInfo {
|
||||||
|
private accountId: number;
|
||||||
|
|
||||||
|
constructor(accountId: number) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAccountMoney(): number {
|
||||||
|
const result = CharDBQuery(`SELECT SUM(Money) as AccountMoney from acore_characters.characters WHERE account = ${this.accountId}`);
|
||||||
|
const row = result.GetRow() as Record<string, number>;
|
||||||
|
return row.AccountMoney;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCharacters(): BasicCharacter[] {
|
||||||
|
const result = CharDBQuery(`SELECT guid, name from characters WHERE account = ${this.accountId}`);
|
||||||
|
const characters: BasicCharacter[] = [];
|
||||||
|
|
||||||
|
for(let i=0; i < result.GetRowCount(); i++) {
|
||||||
|
const row = result.GetRow();
|
||||||
|
characters.push({ guid: row.guid as number, name: row.name as string });
|
||||||
|
result.NextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
return characters;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
modules/classes/money.ts
Normal file
32
modules/classes/money.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { AccountInfo } from "./account";
|
||||||
|
|
||||||
|
export const GOLD_TO_COPPER = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a copper cost to gold
|
||||||
|
* @param cost <number> Cost of item in copper
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
export function ToGold(cost: number) : number {
|
||||||
|
return Math.floor(cost / GOLD_TO_COPPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a gold cost to copper
|
||||||
|
* @param gold <number> Cost of item in gold
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
export function ToCopper(gold: number) : number {
|
||||||
|
return gold*GOLD_TO_COPPER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a scaling tax for players to help with balancing the economy for guild features.
|
||||||
|
* @param player Player
|
||||||
|
* @param tax amount of tax against player to levy number (0-100)
|
||||||
|
* @returns number result in copper
|
||||||
|
*/
|
||||||
|
export function GetPlayerTax(player: Player, tax: number) : number {
|
||||||
|
const account = new AccountInfo(player.GetAccountId());
|
||||||
|
return (tax/100) * account.GetAccountMoney();
|
||||||
|
}
|
||||||
132
modules/classes/stats.ts
Normal file
132
modules/classes/stats.ts
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
declare function GetGameTime(): number;
|
||||||
|
|
||||||
|
const PLAYER_TYPE = 'player';
|
||||||
|
export const StatEvents = {
|
||||||
|
TOKEN_CREATED: 'token_created',
|
||||||
|
TICKETS_AWARDED: 'darkmoon_tickets_awarded',
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Stats {
|
||||||
|
|
||||||
|
stats = new Map<string, Stat>();
|
||||||
|
entity: StatEntity;
|
||||||
|
|
||||||
|
constructor(entity: StatEntity) {
|
||||||
|
this.entity = entity;
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
static GetStatsByType(type: string, name: string) : Map<number, number> {
|
||||||
|
const result = CharDBQuery(`SELECT id, name, value, updated FROM ${type}_stats WHERE name = '${name}'`);
|
||||||
|
const stats = new Map<number, number>();
|
||||||
|
if(!result) {
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
for(let i=0; i < result.GetRowCount(); i++) {
|
||||||
|
const row = result.GetRow();
|
||||||
|
stats.set(row.id as number, row.value as number);
|
||||||
|
result.NextRow();
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
load() : boolean {
|
||||||
|
const result = CharDBQuery(`SELECT id, name, value, updated FROM ${this.entity.type}_stats WHERE id = ${this.entity.id}`);
|
||||||
|
if(!result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(let i=0; i < result.GetRowCount(); i++) {
|
||||||
|
const row = result.GetRow();
|
||||||
|
const stat: Stat = {
|
||||||
|
name: row.name as string,
|
||||||
|
type: this.entity.type,
|
||||||
|
value: row.value as number,
|
||||||
|
updated: row.updated as number,
|
||||||
|
loaded: true
|
||||||
|
}
|
||||||
|
this.stats.set(stat.name, stat);
|
||||||
|
result.NextRow();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
save() : void {
|
||||||
|
|
||||||
|
for(const stat of this.stats.values()) {
|
||||||
|
if(!stat.loaded) {
|
||||||
|
CharDBExecute(`INSERT INTO ${this.entity.type}_stats (id, name, value, updated) VALUES (${this.entity.id}, '${stat.name}', ${stat.value}, ${stat.updated})`);
|
||||||
|
PrintDebug(`Inserted ${stat.name} for ${this.entity.type} ${this.entity.id} with value ${stat.value}`);
|
||||||
|
} else {
|
||||||
|
CharDBExecute(`UPDATE ${this.entity.type}_stats SET value = ${stat.value}, updated = ${stat.updated} WHERE id = ${this.entity.id} AND name = '${stat.name}'`);
|
||||||
|
PrintDebug(`Updated ${stat.name} for ${this.entity.type} ${this.entity.id} to ${stat.value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getStat(name: string) : Stat | undefined {
|
||||||
|
return this.stats.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStat(name: string, value: number) : void {
|
||||||
|
const stat = this.stats.get(name);
|
||||||
|
if(stat) {
|
||||||
|
stat.value = value;
|
||||||
|
stat.updated = GetGameTime();
|
||||||
|
} else {
|
||||||
|
this.stats.set(name, {
|
||||||
|
name: name,
|
||||||
|
type: PLAYER_TYPE,
|
||||||
|
value: value,
|
||||||
|
updated: GetGameTime(),
|
||||||
|
loaded: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
increment(name: string, amount: number = 1) : void {
|
||||||
|
const stat = this.stats.get(name);
|
||||||
|
if(stat) {
|
||||||
|
stat.value += amount;
|
||||||
|
stat.updated = GetGameTime();
|
||||||
|
} else {
|
||||||
|
this.stats.set(name, {
|
||||||
|
name: name,
|
||||||
|
type: PLAYER_TYPE,
|
||||||
|
value: 0,
|
||||||
|
updated: GetGameTime(),
|
||||||
|
loaded: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom player stats that will be
|
||||||
|
*/
|
||||||
|
export class PlayerStats extends Stats {
|
||||||
|
|
||||||
|
player: Player;
|
||||||
|
playerStats: Stat[] = [];
|
||||||
|
|
||||||
|
constructor(player: Player) {
|
||||||
|
super({
|
||||||
|
id: player.GetGUID(),
|
||||||
|
type: PLAYER_TYPE
|
||||||
|
});
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatEntity {
|
||||||
|
type: string,
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Stat {
|
||||||
|
type: string,
|
||||||
|
name: string,
|
||||||
|
value: number,
|
||||||
|
updated: number,
|
||||||
|
loaded: boolean
|
||||||
|
}
|
||||||
37
modules/classes/triggers.ts
Normal file
37
modules/classes/triggers.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/* @noSelfInFile */
|
||||||
|
|
||||||
|
type TriggerInput = {
|
||||||
|
triggerName: string,
|
||||||
|
characterGuid: number,
|
||||||
|
isSet: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player trigger boolean that can be retieved later as needed
|
||||||
|
* @param charTrigger TriggerInput
|
||||||
|
*/
|
||||||
|
export function SetTrigger(charTrigger: TriggerInput) {
|
||||||
|
let sql = `INSERT INTO player_trigger (triggerName, characterGuid, isSet) `+
|
||||||
|
`VALUES ("${charTrigger.triggerName}", ${charTrigger.characterGuid}, ${charTrigger.isSet})`+
|
||||||
|
`ON DUPLICATE KEY UPDATE isSet=${charTrigger.isSet}`;
|
||||||
|
print(sql);
|
||||||
|
CharDBExecute(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will return the value of the trigger if it exists, otherwise it will return false
|
||||||
|
* @param charGuid number
|
||||||
|
* @param triggerName string
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
export function GetTrigger(charGuid: number, triggerName: string) {
|
||||||
|
let sql = `SELECT isSet from player_trigger WHERE triggerName="${triggerName}" and characterGuid=${charGuid}`;
|
||||||
|
const result = CharDBQuery(sql);
|
||||||
|
|
||||||
|
if(result && result.GetRowCount() > 0) {
|
||||||
|
return result.GetBool(0)
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
18
modules/classes/ui-utils.ts
Normal file
18
modules/classes/ui-utils.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export function colors(name: string) {
|
||||||
|
const colors = {
|
||||||
|
GREY: "|cff999999",
|
||||||
|
RED: "|cffff0000",
|
||||||
|
WHITE: "|cffFFFFFF",
|
||||||
|
GREEN: "|cff1eff00",
|
||||||
|
PURPLE: "|cff9F3FFF",
|
||||||
|
BLUE: "|cff0070dd",
|
||||||
|
ORANGE: "|cffFF8400",
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyName = name.toUpperCase();
|
||||||
|
if(colors[keyName]) {
|
||||||
|
return colors[keyName];
|
||||||
|
} else {
|
||||||
|
return colors.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
116
modules/commands/set-xp-rate.ts
Normal file
116
modules/commands/set-xp-rate.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* @file set-xp-rate.ts
|
||||||
|
* @date 2023-11-15
|
||||||
|
* @author ben-of-codecraft
|
||||||
|
*
|
||||||
|
* Type: Command
|
||||||
|
* Adds a command that allows players to set their own XP rate for their character up to 5x normal xp rate.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration options
|
||||||
|
*/
|
||||||
|
const MAX_XP_RATE = 5;
|
||||||
|
|
||||||
|
// Command to show the current xp rate
|
||||||
|
const xpCmd = "#xprate";
|
||||||
|
const showXPcmd = "#xprate show";
|
||||||
|
const setXPcmd = "#xprate set";
|
||||||
|
|
||||||
|
const XP_RATE_SETTING = "xp_rate";
|
||||||
|
|
||||||
|
import { PlayerStats } from "../classes/stats";
|
||||||
|
|
||||||
|
let xpRateCache = new Map<number, number>();
|
||||||
|
|
||||||
|
const XPRateHandler: player_event_on_chat = (event: number, player: Player, message: string) => {
|
||||||
|
|
||||||
|
if(message.includes(xpCmd)) {
|
||||||
|
|
||||||
|
const args = message.split(" ");
|
||||||
|
const cmd = args[1];
|
||||||
|
|
||||||
|
|
||||||
|
const playerCustom = new PlayerStats(player);
|
||||||
|
playerCustom.load();
|
||||||
|
|
||||||
|
if(cmd == "show") {
|
||||||
|
const xpRate = xpRateCache.get(player.GetGUIDLow());
|
||||||
|
if(xpRate != undefined) {
|
||||||
|
player.SendBroadcastMessage(`Your current XP rate is ${xpRate}x`);
|
||||||
|
} else {
|
||||||
|
player.SendBroadcastMessage(`Your current XP rate is 1x`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(cmd == "set") {
|
||||||
|
const rate = args[2];
|
||||||
|
const rateNum = parseInt(rate);
|
||||||
|
|
||||||
|
if(rateNum > MAX_XP_RATE) {
|
||||||
|
player.SendNotification(`You cannot set your XP rate higher then ${MAX_XP_RATE}x`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerCustom.setStat(XP_RATE_SETTING, rateNum);
|
||||||
|
playerCustom.save();
|
||||||
|
xpRateCache.set(player.GetGUIDLow(), rateNum);
|
||||||
|
|
||||||
|
player.SendBroadcastMessage(`Your XP rate has been set to ${rateNum}x`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
player.SendBroadcastMessage(`Usage: ${xpCmd} [show|set] [rate]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives players extra XP based on their rate
|
||||||
|
* @param event \
|
||||||
|
* @param player
|
||||||
|
* @param amount
|
||||||
|
* @param victim
|
||||||
|
*/
|
||||||
|
const XPBonus: player_event_on_give_xp = (event: number, player: Player, amount: number, victim: Unit) => {
|
||||||
|
|
||||||
|
const xpRate = xpRateCache.get(player.GetGUIDLow());
|
||||||
|
if(xpRate && xpRate > 1) {
|
||||||
|
player.GiveXP(amount * xpRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const XPRateLoader: player_event_on_login = (event: number, player: Player) => {
|
||||||
|
|
||||||
|
|
||||||
|
const playerCustom = new PlayerStats(player);
|
||||||
|
playerCustom.load();
|
||||||
|
|
||||||
|
const xpRate = playerCustom.getStat(XP_RATE_SETTING);
|
||||||
|
if(xpRate) {
|
||||||
|
xpRateCache.set(player.GetGUIDLow(), xpRate.value);
|
||||||
|
} else {
|
||||||
|
xpRateCache.set(player.GetGUIDLow(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grants players extra XP Based on their rate
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GIVE_XP, (...args) => XPBonus(...args));
|
||||||
|
|
||||||
|
// Register the command
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT,
|
||||||
|
(...args) => XPRateHandler(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loads the cache of seetings on login
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => XPRateLoader(...args));
|
||||||
|
|
||||||
|
// reloads the cache of settings when the lua state is opened
|
||||||
|
RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN, (...args) => {
|
||||||
|
xpRateCache = PlayerStats.GetStatsByType('player', XP_RATE_SETTING);
|
||||||
|
});
|
||||||
57
modules/events/achievement-tokens.ts
Normal file
57
modules/events/achievement-tokens.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* CONFIG OPTIONS
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Reward 1 token per every 5 achievement points earned.
|
||||||
|
const AWARD_RATE = 5;
|
||||||
|
|
||||||
|
// Token Id of the currency you want to aware the players.
|
||||||
|
const TOKEN_ID = 910001;
|
||||||
|
|
||||||
|
// Character GUID of the character that will be sending the tokens vai mail
|
||||||
|
const REWARD_CHAR_GUID = 2506;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Achivement complete the system will reward the player with tokens based on the AWARD_RATE
|
||||||
|
* set above
|
||||||
|
* Default is 5 Achievement Points = 1 Token
|
||||||
|
*
|
||||||
|
* IE)
|
||||||
|
* 10 Achievement Points = 2 Tokens
|
||||||
|
* 50 Achievement Points = 10 Tokens
|
||||||
|
*
|
||||||
|
* @param event : number
|
||||||
|
* @param player : Player
|
||||||
|
* @param achievement : Achievement
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
const achievementComplete: player_event_on_achievement_complete = (event, player, achievement) => {
|
||||||
|
|
||||||
|
const id = achievement.GetId();
|
||||||
|
const query = WorldDBQuery(`SELECT Points from achievements where ID=${id}`);
|
||||||
|
const points = query.GetUInt32(0);
|
||||||
|
|
||||||
|
if(points != undefined) {
|
||||||
|
const tokens = Math.ceil(points / AWARD_RATE);
|
||||||
|
SendMail(
|
||||||
|
`Your achievement token reward!`,
|
||||||
|
`You earned it now spend it!`,
|
||||||
|
player.GetGUIDLow(),
|
||||||
|
REWARD_CHAR_GUID,
|
||||||
|
MailStationery.MAIL_STATIONERY_DEFAULT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
TOKEN_ID,
|
||||||
|
tokens
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_ACHIEVEMENT_COMPLETE,
|
||||||
|
(...args) => achievementComplete(...args)
|
||||||
|
);
|
||||||
23
modules/events/tbc-launch.ts
Normal file
23
modules/events/tbc-launch.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { SetTrigger, GetTrigger } from "../classes/triggers";
|
||||||
|
/**
|
||||||
|
* Show the Burning Crusade moving on first login.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @param player
|
||||||
|
*/
|
||||||
|
const ShowBCMovie: player_event_on_login = (event: number, player: Player) => {
|
||||||
|
const movieShown = GetTrigger(player.GetGUIDLow(), "tbc_movie_shown");
|
||||||
|
|
||||||
|
if(movieShown === false) {
|
||||||
|
player.SendMovieStart(1);
|
||||||
|
SetTrigger({
|
||||||
|
triggerName: "tbc_movie_shown",
|
||||||
|
characterGuid: player.GetGUIDLow(),
|
||||||
|
isSet: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN,
|
||||||
|
(...args) => ShowBCMovie(...args)
|
||||||
|
);
|
||||||
24
modules/events/worgoblin-patch.ts
Normal file
24
modules/events/worgoblin-patch.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { ToCopper } from "../classes/money";
|
||||||
|
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_FIRST_LOGIN, (event, player) => {
|
||||||
|
|
||||||
|
// Worgren get additional racials and start at level 20 in Duskwood
|
||||||
|
if(player.GetRace() == 12 ) {
|
||||||
|
// Since we do not have all Worgren spells will give them another racial fitting of their class.
|
||||||
|
player.LearnSpell(20577); // Cannibalize
|
||||||
|
|
||||||
|
// learn spell blood fury
|
||||||
|
player.LearnSpell(33697);
|
||||||
|
|
||||||
|
player.SetLevel(20);
|
||||||
|
player.Teleport(0, -10728.057617, -1131.120850, 27.594067, 1.180833);
|
||||||
|
player.ModifyMoney(ToCopper(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are a goblin then start off at level 20 in Ratchet
|
||||||
|
if(player.GetRace() == 9) {
|
||||||
|
player.SetLevel(20);
|
||||||
|
player.ModifyMoney(ToCopper(100));
|
||||||
|
player.Teleport(1, -1049.596, -3645.963, 23.878, 4.468);
|
||||||
|
}
|
||||||
|
});
|
||||||
28
modules/items/badge-of-justice.ts
Normal file
28
modules/items/badge-of-justice.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Badge Of Justice Multiplier
|
||||||
|
* Increases the number of Badges of Justice a player will receive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BADGE_OF_JUSTICE_BONUS = 1;
|
||||||
|
const HEROIC_FOCUS_AURA = 95000;
|
||||||
|
const BADGE_OF_JUSTICE_ENTRY = 29434;
|
||||||
|
|
||||||
|
const LootToken: player_event_on_loot_item = (event: number, player: Player, item: Item) => {
|
||||||
|
|
||||||
|
if(item.GetEntry() == BADGE_OF_JUSTICE_ENTRY) {
|
||||||
|
player.AddItem(BADGE_OF_JUSTICE_ENTRY, BADGE_OF_JUSTICE_BONUS);
|
||||||
|
|
||||||
|
if(player.HasAura(HEROIC_FOCUS_AURA)) {
|
||||||
|
const randomNumber = Math.floor(Math.random() * 3) + 1;
|
||||||
|
player.AddItem(BADGE_OF_JUSTICE_ENTRY, randomNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => LootToken(...args));
|
||||||
27
modules/items/book-of-travel.ts
Normal file
27
modules/items/book-of-travel.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Item that will enable a user to teleport to a new location in azeroth loaded from
|
||||||
|
* existing waypoints set in the database.
|
||||||
|
* @date 2023-12-01
|
||||||
|
* @author ben-of-codecraft
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration options
|
||||||
|
*/
|
||||||
|
const TELEPORT_ITEM_ENTRY = 910006;
|
||||||
|
|
||||||
|
const TeleportHandler: item_event_on_use = (event: number, player: Player, item: Item, target: Unit) => {
|
||||||
|
|
||||||
|
if(player.IsHorde()) {
|
||||||
|
const master = PerformIngameSpawn(1, 2851, player.GetMapId(), player.GetInstanceId(), player.GetX(), player.GetY(), player.GetZ(), player.GetO(), false, 1, 0) as Creature;
|
||||||
|
player.SendTaxiMenu(master);
|
||||||
|
} else {
|
||||||
|
const master = player.SpawnCreature(1571, player.GetX(), player.GetY(), player.GetZ(), player.GetO(), TempSummonType.TEMPSUMMON_MANUAL_DESPAWN);
|
||||||
|
player.SendTaxiMenu(master);
|
||||||
|
master.DespawnOrUnsummon(60*1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
RegisterItemEvent(TELEPORT_ITEM_ENTRY, ItemEvents.ITEM_EVENT_ON_USE, (...args) => TeleportHandler(...args));
|
||||||
76
modules/items/darkmoon.ts
Normal file
76
modules/items/darkmoon.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { PlayerStats, StatEvents } from "../classes/stats";
|
||||||
|
|
||||||
|
const NORMAL_TICKET_CHANCE = 2;
|
||||||
|
const BOSS_TICKET_CHANCE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditions to get a potential token drop are as follows
|
||||||
|
* Helps with giving players more tickets during darkmoon fair month.
|
||||||
|
* If
|
||||||
|
*/
|
||||||
|
const TicketKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature ) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// let chance: number;
|
||||||
|
// if( creature.IsDungeonBoss() ) {
|
||||||
|
// chance = BOSS_TICKET_CHANCE;
|
||||||
|
// } else if(!creature.IsWorldBoss() ) {
|
||||||
|
// chance = 100;
|
||||||
|
// } else {
|
||||||
|
// chance = NORMAL_TICKET_CHANCE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // player level is greater then 7 levels than creature level
|
||||||
|
// const clevel = creature.GetLevel();
|
||||||
|
// const plevel = player.GetLevel();
|
||||||
|
|
||||||
|
// if(plevel >= (clevel + 7)) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let darkmoon = [];
|
||||||
|
// const result = WorldDBQuery('SELECT eventEntry from game_event WHERE description like "%Darkmoon Faire%"');
|
||||||
|
|
||||||
|
// // A Darkmoon event has to be active.
|
||||||
|
// const events = GetActiveGameEvents();
|
||||||
|
|
||||||
|
// for(let i=0; i < result.GetRowCount(); i++) {
|
||||||
|
// const row = result.GetRow();
|
||||||
|
// darkmoon.push(row.eventEntry);
|
||||||
|
// result.NextRow();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let darkmoonActive = false;
|
||||||
|
// for(let event of events) {
|
||||||
|
// if(darkmoon.includes(event)) {
|
||||||
|
// darkmoonActive = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Roll for token drop
|
||||||
|
// let roll = Math.floor(Math.random() * 100);
|
||||||
|
|
||||||
|
// const pStats = new PlayerStats(player);
|
||||||
|
// if(roll <= chance) {
|
||||||
|
// if(creature.IsWorldBoss()) {
|
||||||
|
// player.AddItem(19182,100);
|
||||||
|
// player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_LOOT, Language.LANG_COMMON, `Congrats here are 100 tickets.`, player);
|
||||||
|
// pStats.increment(StatEvents.TICKETS_AWARDED,100);
|
||||||
|
// } else if(creature.IsDungeonBoss()) {
|
||||||
|
// player.AddItem(19182, 20);
|
||||||
|
// player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_LOOT, Language.LANG_COMMON, `You received a 20 Darkmoon tickets, lucky you!`, player);
|
||||||
|
// pStats.increment(StatEvents.TICKETS_AWARDED,20);
|
||||||
|
// } else {
|
||||||
|
// player.AddItem(19182,1);
|
||||||
|
// player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_LOOT, Language.LANG_COMMON, `You received a Darkmoon ticket, lucky you!`, player);
|
||||||
|
// pStats.increment(StatEvents.TICKETS_AWARDED,1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterPlayerEvent(
|
||||||
|
// PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE,
|
||||||
|
// (...args) => TicketKill(...args)
|
||||||
|
// );
|
||||||
134
modules/items/tokens.ts
Normal file
134
modules/items/tokens.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import { PlayerStats, StatEvents } from "../classes/stats";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration options
|
||||||
|
*/
|
||||||
|
const TOKEN_ROLL_CHANCE = 5;
|
||||||
|
const NORMAL_ROLL_CHANCE = 5;
|
||||||
|
const TOKEN_ROLL_CAP = 2000;
|
||||||
|
const TOKEN_GROUP_SIZE = 2;
|
||||||
|
|
||||||
|
const createChest = (player: Player, creature: Creature, direction: string): void => {
|
||||||
|
|
||||||
|
const [x,y,z,o] = creature.GetLocation();
|
||||||
|
|
||||||
|
let chestX,chestY,chestZ;
|
||||||
|
if(direction == 'center') {
|
||||||
|
chestX = x+0.5;
|
||||||
|
chestY = y+0.5;
|
||||||
|
chestZ = z;
|
||||||
|
} else if(direction == 'left') {
|
||||||
|
chestX = x+2.5;
|
||||||
|
chestY = y+2.5;
|
||||||
|
chestZ = z;
|
||||||
|
} else {
|
||||||
|
chestX = x+2.5;
|
||||||
|
chestY = y-3.5;
|
||||||
|
chestZ = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.PlayDirectSound(7256); // Loud Chime
|
||||||
|
player.SummonGameObject(110000,chestX,chestY,chestZ,o, 0);
|
||||||
|
player.SummonGameObject(186246, chestX,chestY,chestZ+0.20,o, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This creates a randomly dropping currency that rewards players who play together.
|
||||||
|
* It also has a small chance for doing harder content for solo players to get it, but based chance is on
|
||||||
|
* any other kill is 0.2%
|
||||||
|
*/
|
||||||
|
const TokenKillEvent: player_event_on_kill_creature = (event: number, player: Player, creature: Creature ) => {
|
||||||
|
|
||||||
|
// if the creature level is much lower then you have 0 chance to get a token.
|
||||||
|
if(creature.GetLevel() < (player.GetLevel() - 5)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = creature.GetMap();
|
||||||
|
|
||||||
|
// Must be a group of real player 3(default) or more with bonus to drop rate for each player after 3, Condition (3)
|
||||||
|
const group = player.GetGroup();
|
||||||
|
let groupCount = 0;
|
||||||
|
|
||||||
|
if(group != undefined) {
|
||||||
|
const members = group.GetMembers();
|
||||||
|
|
||||||
|
for(let member of members) {
|
||||||
|
member.GetName();
|
||||||
|
groupCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintDebug(`Player: ${player.GetName()} is in a group of ${groupCount}`);
|
||||||
|
|
||||||
|
// Roll for token drop
|
||||||
|
let roll = Math.floor(Math.random() * TOKEN_ROLL_CAP);
|
||||||
|
let rollModifer = NORMAL_ROLL_CHANCE;
|
||||||
|
|
||||||
|
// Solo Drop rates
|
||||||
|
if(groupCount < TOKEN_GROUP_SIZE) {
|
||||||
|
if(creature.IsWorldBoss() || creature.IsDungeonBoss()) {
|
||||||
|
rollModifer += 30;
|
||||||
|
} else {
|
||||||
|
if(creature.IsElite()) {
|
||||||
|
rollModifer = rollModifer + TOKEN_ROLL_CHANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map.IsRaid() || map.IsHeroic()) {
|
||||||
|
rollModifer = rollModifer + 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map.IsDungeon()) {
|
||||||
|
rollModifer = rollModifer + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Group Drop Rates
|
||||||
|
if(creature.IsWorldBoss() || creature.IsDungeonBoss()) {
|
||||||
|
rollModifer += 300;
|
||||||
|
} else {
|
||||||
|
if(creature.IsElite()) {
|
||||||
|
rollModifer = rollModifer + 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map.IsRaid() || map.IsHeroic()) {
|
||||||
|
rollModifer = rollModifer + (20 * groupCount);
|
||||||
|
} else {
|
||||||
|
if(map.IsDungeon()) {
|
||||||
|
rollModifer = rollModifer + (4 * groupCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintDebug(`Player: ${player.GetName()} Roll: ${roll} Roll Modifer: ${rollModifer} Chance: ${rollModifer}`)
|
||||||
|
if(roll <= rollModifer) {
|
||||||
|
|
||||||
|
createChest(player, creature, 'center');
|
||||||
|
|
||||||
|
// Add player stat they created token
|
||||||
|
const pStats = new PlayerStats(player);
|
||||||
|
pStats.increment(StatEvents.TOKEN_CREATED);
|
||||||
|
pStats.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it is a larger group roll again!
|
||||||
|
if(groupCount >= TOKEN_GROUP_SIZE) {
|
||||||
|
if(creature.IsWorldBoss() || creature.IsDungeonBoss()) {
|
||||||
|
roll = Math.floor(Math.random() * TOKEN_ROLL_CAP);
|
||||||
|
if(roll <= rollModifer+200 ) {
|
||||||
|
createChest(player, creature,'left');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE,
|
||||||
|
(...args) => TokenKillEvent(...args)
|
||||||
|
);
|
||||||
10
modules/items/vashj-fix.ts
Normal file
10
modules/items/vashj-fix.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const TaintedKill: player_event_on_kill_creature = (event, player, creature) => {
|
||||||
|
if(creature.GetEntry() == 22009) {
|
||||||
|
player.AddItem(31088, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterPlayerEvent(
|
||||||
|
PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE,
|
||||||
|
(...args) => TaintedKill(...args)
|
||||||
|
);
|
||||||
0
modules/npcs/gambler.ts
Normal file
0
modules/npcs/gambler.ts
Normal file
169
modules/npcs/soulswapper.ts
Normal file
169
modules/npcs/soulswapper.ts
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { ToGold, ToCopper, GetPlayerTax } from "../classes/money";
|
||||||
|
import { AccountInfo } from "../classes/account";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SoulSwapper GameObject/NPC
|
||||||
|
* This is a module that allows players to send soulbound items to alts on the same account.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the list of item classes that are allowed to be sent to other characters.
|
||||||
|
* @link https://www.azerothcore.org/wiki/item_template
|
||||||
|
*/
|
||||||
|
const ALLOWED_ITEM_CLASSES = [2,4,9]; // 2 = weapon, 4 = armor, 9 = recipe
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the number of characters an account can have.
|
||||||
|
*/
|
||||||
|
const ALLOWED_ACCOUNT_CHARS = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base price for sending an item multipliers will be added on top
|
||||||
|
*/
|
||||||
|
const SOULSWAP_BASE_PRICE = ToCopper(20);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level the discount for sending items is no longer applied
|
||||||
|
*/
|
||||||
|
const NO_DISCOUNT_LEVEL = 70;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discount percentage applied per 10 levels
|
||||||
|
*/
|
||||||
|
const DISCOUNT_ADJ = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the object that will interact with the player to handle the soulswap
|
||||||
|
*/
|
||||||
|
const INTERACTIVE_OBJECT = 750000;
|
||||||
|
|
||||||
|
|
||||||
|
const selectedItem: Record<string, number> = {};
|
||||||
|
|
||||||
|
function getCost(guid: number, player: Player): number {
|
||||||
|
const itemGuid = GetItemGUID(guid);
|
||||||
|
const theItem = player.GetItemByGUID(itemGuid);
|
||||||
|
let discount = 1;
|
||||||
|
|
||||||
|
const iLevelModifer = theItem.GetItemLevel() / 40;
|
||||||
|
|
||||||
|
if(player.GetLevel() < NO_DISCOUNT_LEVEL) {
|
||||||
|
discount = (NO_DISCOUNT_LEVEL - player.GetLevel()) * DISCOUNT_ADJ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(discount > 100) {
|
||||||
|
discount = 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SOULSWAP_BASE_PRICE * iLevelModifer * ((100 - discount) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GossipHello : gossip_event_on_hello = (event: number, player: Player, gameobject: EObject) => {
|
||||||
|
|
||||||
|
player.GossipClearMenu();
|
||||||
|
|
||||||
|
let items = 0;
|
||||||
|
/**
|
||||||
|
* Backpack is 255, 23-38
|
||||||
|
*/
|
||||||
|
for(let i=23; i <= 38; i++ ) {
|
||||||
|
let item = player.GetItemByPos(255, i);
|
||||||
|
|
||||||
|
if(item != undefined) {
|
||||||
|
|
||||||
|
const itemClass = item.GetClass();
|
||||||
|
|
||||||
|
if( item.IsSoulBound() && (ALLOWED_ITEM_CLASSES.includes(itemClass)) ) {
|
||||||
|
const quality = item.GetQuality();
|
||||||
|
const quantity = item.GetCount();
|
||||||
|
const cost = getCost(item.GetGUIDLow(), player);
|
||||||
|
|
||||||
|
if(quality > 2 && quantity === 1) {
|
||||||
|
items += 1;
|
||||||
|
player.GossipMenuAddItem(1,`Item: ${item.GetItemLink()} (${ToGold(cost)}g)`,1,item.GetGUIDLow(), undefined, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(items === 0) {
|
||||||
|
player.SendNotification("You have no soulbound items in your backback to send to your other characters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.GossipMenuAddItem(1,`Stop using the device`,1,50500);
|
||||||
|
player.GossipSendMenu(1000, gameobject, 10000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GossipSelect: gossip_event_on_select = (event: number, player: Player, creature: any, selection, action, code, menuId) => {
|
||||||
|
|
||||||
|
const account = new AccountInfo(player.GetAccountId());
|
||||||
|
const characters = account.GetCharacters();
|
||||||
|
|
||||||
|
// 50500 is an item that is not in the game and can safely be used to exit the menu.
|
||||||
|
if(action === 50500) {
|
||||||
|
player.GossipClearMenu();
|
||||||
|
player.GossipComplete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the action is greater than the number
|
||||||
|
if(action > ALLOWED_ACCOUNT_CHARS) {
|
||||||
|
for(let numC = 0; numC < characters.length; numC++) {
|
||||||
|
let name = characters[numC].name;
|
||||||
|
|
||||||
|
if(name != player.GetName()) {
|
||||||
|
const cost = getCost(action, player);
|
||||||
|
player.GossipMenuAddItem(2, `Send to: ${name}`, 2, numC+1, undefined, `Are you sure you will to rebind this item? The item will be mailed to ${name}?`, cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedItem[player.GetName()] = action;
|
||||||
|
|
||||||
|
player.GossipSendMenu(1000, creature, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action to select player to receive the item.
|
||||||
|
if(action <= ALLOWED_ACCOUNT_CHARS) {
|
||||||
|
|
||||||
|
let itemToChange = selectedItem[player.GetName()];
|
||||||
|
let itemGuid = GetItemGUID(itemToChange);
|
||||||
|
|
||||||
|
const PlayerItem = player.GetItemByGUID(itemGuid);
|
||||||
|
print(`Item Info: ${PlayerItem.GetOwner().GetName()} owns ${PlayerItem.GetName()}`);
|
||||||
|
|
||||||
|
let newItemGuid = SendMail(
|
||||||
|
`Item Rebound ${PlayerItem.GetName()}`,
|
||||||
|
`Soulbinder has sent you a gift ${PlayerItem.GetName()}`,
|
||||||
|
characters[action-1].guid,
|
||||||
|
player.GetGUIDLow(),
|
||||||
|
MailStationery.MAIL_STATIONERY_DEFAULT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
PlayerItem.GetEntry(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
player.RemoveItem(PlayerItem, PlayerItem.GetEntry(), 1);
|
||||||
|
|
||||||
|
player.GossipClearMenu();
|
||||||
|
player.GossipComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterGameObjectGossipEvent(
|
||||||
|
INTERACTIVE_OBJECT,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_HELLO,
|
||||||
|
(...args) => GossipHello(...args)
|
||||||
|
);
|
||||||
|
|
||||||
|
RegisterGameObjectGossipEvent(
|
||||||
|
INTERACTIVE_OBJECT,
|
||||||
|
GossipEvents.GOSSIP_EVENT_ON_SELECT,
|
||||||
|
(...args) => GossipSelect(...args)
|
||||||
|
);
|
||||||
2481
package-lock.json
generated
Normal file
2481
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
package.json
Normal file
20
package.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"clean": "dotenv -e ets.env cross-var rimraf %ETS_BUILD_ROOT%",
|
||||||
|
"build": "ets build",
|
||||||
|
"dev": "npm run clean && ets build && npm run dev-copy",
|
||||||
|
"dev-copy": "dotenv -e ets.env cross-var ncp %ETS_BUILD_ROOT% %DEV_MODULE_PATH%",
|
||||||
|
"dev:watch": "ets build -w && npm run dev-copy"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"cross-var": "^1.1.0",
|
||||||
|
"dotenv-cli": "^7.3.0",
|
||||||
|
"ncp": "^2.0.0",
|
||||||
|
"rimraf": "^5.0.5",
|
||||||
|
"typescript": "^5.2.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"wow-eluna-ts-module": "^1.6.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
plugins/aio-plugin.ts
Normal file
29
plugins/aio-plugin.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import * as ts from "typescript";
|
||||||
|
import * as tstl from "typescript-to-lua";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This plugin will add AIO to the transpile process from TS assuming
|
||||||
|
* there is a Global installation of AIO installed in the directory, which is
|
||||||
|
* that follows Rochet2's instructions.
|
||||||
|
*/
|
||||||
|
const plugin: tstl.Plugin = {
|
||||||
|
beforeEmit(
|
||||||
|
program: ts.Program,
|
||||||
|
options: tstl.CompilerOptions,
|
||||||
|
emitHost: tstl.EmitHost,
|
||||||
|
result: tstl.EmitFile[],
|
||||||
|
) {
|
||||||
|
|
||||||
|
for (const file of result) {
|
||||||
|
|
||||||
|
if(file.code.includes("aio = {}")) {
|
||||||
|
console.log(`installing AIO for this file ${file.outputPath}`);
|
||||||
|
file.code = file.code.replace("-- @ts-expect-error", "");
|
||||||
|
file.code = file.code.replace("aio = {}", "local AIO = AIO or require(\"AIO\")");
|
||||||
|
file.code = file.code.replace(/aio\./g, "AIO.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default plugin;
|
||||||
48
tsconfig.json
Normal file
48
tsconfig.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./tstl.schema.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": false,
|
||||||
|
"target": "esnext",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"types": [
|
||||||
|
"lua-types/5.2",
|
||||||
|
"@typescript-to-lua/language-extensions",
|
||||||
|
"wow-eluna-ts-module",
|
||||||
|
"@araxiaonline/wow-wotlk-declarations"
|
||||||
|
|
||||||
|
],
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/wow-eluna-ts-module/types",
|
||||||
|
"./node_modules",
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./node_modules/@araxiaonline/wow-wotlk-declarations"
|
||||||
|
],
|
||||||
|
"rootDir": "modules"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"modules/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/node_modules",
|
||||||
|
"test",
|
||||||
|
"**/*spec.ts",
|
||||||
|
"**/__tests__",
|
||||||
|
"**/__mocks__"
|
||||||
|
],
|
||||||
|
"tstl": {
|
||||||
|
"luaTarget": "5.2",
|
||||||
|
"noHeader": true,
|
||||||
|
"luaLibImport": "require",
|
||||||
|
"luaBundleEntry": "./modules/index.ts",
|
||||||
|
"luaPlugins": [
|
||||||
|
{ "name": "./plugins/aio-plugin.ts" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
111
tstl.schema.json
Normal file
111
tstl.schema.json
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
{
|
||||||
|
"title": "tsconfig.json with TSTL",
|
||||||
|
"description": "JSON schema for the TypeScript compiler's configuration file with TSTL",
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "https://json.schemastore.org/tsconfig"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"tstl": {
|
||||||
|
"description": "TypeScriptToLua compiler options.",
|
||||||
|
"type": "object",
|
||||||
|
"definitions": {
|
||||||
|
"//": {
|
||||||
|
"reference": "https://typescripttolua.github.io/docs/configuration#custom-options"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"buildMode": {
|
||||||
|
"description": "Use buildMode: \"library\" to build publishable library packages.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "library",
|
||||||
|
"enum": ["default", "library"]
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"description": "File extension for the resulting Lua files. Defaults to \".lua\"",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lua51AllowTryCatchInAsyncAwait": {
|
||||||
|
"description": "Disable the warning that try/catch is not allowed in async functions in Lua 5.1, in case you are using a patched 5.1 lua version that supports this.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"luaBundle": {
|
||||||
|
"description": "The name of the lua file to bundle output lua to. Requires luaBundleEntry.",
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"luaBundleEntry": {
|
||||||
|
"description": "The entry *.ts file that will be executed when entering the luaBundle. Requires luaBundle.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"luaLibImport": {
|
||||||
|
"description": "Specifies how js standard features missing in lua are imported.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "require",
|
||||||
|
"enum": ["none", "inline", "require", "require-minimal"]
|
||||||
|
},
|
||||||
|
"luaTarget": {
|
||||||
|
"description": "Specifies the Lua version you want to generate code for.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "universal",
|
||||||
|
"enum": ["5.0", "universal", "5.1", "5.2", "5.3", "5.4", "JIT"]
|
||||||
|
},
|
||||||
|
"noImplicitGlobalVariables": {
|
||||||
|
"description": "Always declare all root-level variables as local, even if the file is not a module and they would be global in TypeScript.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"noImplicitSelf": {
|
||||||
|
"description": "If true, treats all project files as if they were prefixed with\n/** @noSelfInFile **/.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"noHeader": {
|
||||||
|
"description": "Specify if a header will be added to compiled files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"noResolvePaths": {
|
||||||
|
"description": "An array of import paths that should not be resolved but copied verbatim to output lua.",
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"sourceMapTraceback": {
|
||||||
|
"description": "Applies the source map to show source TS files and lines in error tracebacks.",
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"tstlVerbose": {
|
||||||
|
"description": "Give verbose tstl output, helpful when diagnosing tstl issues.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"luaPlugins": {
|
||||||
|
"description": "List of TypeScriptToLua plugins.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"description": "Describes TypeScriptToLua plugin",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["name"],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"description": "Path to the JS file, that contains the plugin code",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"measurePerformance": {
|
||||||
|
"description": "Measure and report performance of the tstl compiler.",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowTrailingCommas": true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user