diff --git a/data-canary/scripts/actions/objects/imbuement_shrine.lua b/data-canary/scripts/actions/objects/imbuement_shrine.lua
index 71e3776f2f0..11d75150cf8 100644
--- a/data-canary/scripts/actions/objects/imbuement_shrine.lua
+++ b/data-canary/scripts/actions/objects/imbuement_shrine.lua
@@ -13,5 +13,7 @@ function imbuement.onUse(player, item, fromPosition, target, toPosition, isHotke
return true
end
+imbuement:position({ x = 1943, y = 1340, z = 7 }, 25061)
+
imbuement:id(25060, 25061, 25103, 25104, 25202, 25174, 25175, 25182, 25183)
imbuement:register()
diff --git a/data-canary/scripts/actions/other/christmas_bundle.lua b/data-canary/scripts/actions/other/christmas_bundle.lua
deleted file mode 100644
index 3c74fa30a4d..00000000000
--- a/data-canary/scripts/actions/other/christmas_bundle.lua
+++ /dev/null
@@ -1,72 +0,0 @@
-local setting = { -- [christmas bundle item id] = {{reward item id, count}, ...}
- [6506] = { -- red bundle
- { 6569, 15 }, -- candy
- { 3585, 5 }, -- red apple
- { 3586, 10 }, -- orange
- { 3598, 20 }, -- cookie
- { 3599, 10 }, -- candy cane
- 6500, -- gingerbreadman
- 6501, -- christmas wreath
- 6489, -- christmas branch
- 6503, -- red christmas garland
- 6387, -- christmas card
- },
- [6507] = { -- blue bundle
- { 6569, 15 }, -- candy
- { 3585, 5 }, -- red apple
- { 3586, 10 }, -- orange
- { 3598, 20 }, -- cookie
- { 3599, 10 }, -- candy cane
- 6500, -- gingerbreadman
- 6501, -- christmas wreath
- 6489, -- christmas branch
- 6505, -- blue christmas garland
- 6387, -- christmas card
- },
- [6508] = { -- green bundle
- { 6569, 15 }, -- candy
- { 3585, 5 }, -- red apple
- { 3586, 10 }, -- orange
- { 3598, 20 }, -- cookie
- { 3599, 10 }, -- candy cane
- 6500, -- gingerbreadman
- 6501, -- christmas wreath
- 6489, -- christmas branch
- 6502, -- christmas garland
- 6387, -- christmas card
- },
-}
-
-local christmasBundle = Action()
-
-function christmasBundle.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- local targetItem = setting[item.itemid]
- if not targetItem then
- return true
- end
-
- local rewards = {}
- while #rewards < 7 do
- local count = 1
- local rand = math.random(#targetItem)
- local gift = targetItem[rand]
- if type(gift) == "table" then
- gift, count = unpack(gift)
- end
- rewards[#rewards + 1] = { gift, count }
- table.remove(targetItem, rand)
- end
-
- for i = 1, #rewards do
- player:addItem(unpack(rewards[i]))
- end
- item:remove(1)
- player:getPosition():sendMagicEffect(CONST_ME_GIFT_WRAPS)
- return true
-end
-
-for index, value in pairs(setting) do
- christmasBundle:id(index)
-end
-
-christmasBundle:register()
diff --git a/data-canary/scripts/actions/other/destroy.lua b/data-canary/scripts/actions/other/destroy.lua
index 587df2f5ea7..62af94ab101 100644
--- a/data-canary/scripts/actions/other/destroy.lua
+++ b/data-canary/scripts/actions/other/destroy.lua
@@ -250,7 +250,7 @@ local setting = {
local destroy = Action()
function destroy.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- return ActionsLib.destroyItem(player, target, toPosition)
+ return destroyItem(player, target, toPosition)
end
for index, value in ipairs(setting) do
diff --git a/data-canary/scripts/actions/other/ferumbras_amulet.lua b/data-canary/scripts/actions/other/ferumbras_amulet.lua
deleted file mode 100644
index 01f1ca7a502..00000000000
--- a/data-canary/scripts/actions/other/ferumbras_amulet.lua
+++ /dev/null
@@ -1,17 +0,0 @@
-local ferumbrasAmulet = Action()
-
-function ferumbrasAmulet.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if math.random(2) == 1 then
- player:addMana(1000)
- else
- player:addHealth(1000)
- end
- item:transform(22768)
- item:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
- item:decay()
- player:say("Magical sparks whirl around the amulet and you suddenly feel refreshed.", TALKTYPE_MONSTER_SAY)
- return true
-end
-
-ferumbrasAmulet:id(22767)
-ferumbrasAmulet:register()
diff --git a/data-canary/scripts/actions/other/ferumbras_mana_keg.lua b/data-canary/scripts/actions/other/ferumbras_mana_keg.lua
deleted file mode 100644
index c1400379d6d..00000000000
--- a/data-canary/scripts/actions/other/ferumbras_mana_keg.lua
+++ /dev/null
@@ -1,13 +0,0 @@
-local ferumbrasManaKeg = Action()
-
-function ferumbrasManaKeg.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- player:addItem(238, 10)
- item:transform(22770)
- item:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
- item:decay()
- player:say("Magical sparks whirl around the keg as you open the spigot and you fill ten empty vials with mana fluid.", TALKTYPE_MONSTER_SAY)
- return true
-end
-
-ferumbrasManaKeg:id(22769)
-ferumbrasManaKeg:register()
diff --git a/data-canary/scripts/actions/other/ferumbras_staff.lua b/data-canary/scripts/actions/other/ferumbras_staff.lua
deleted file mode 100644
index f2f897f2c3f..00000000000
--- a/data-canary/scripts/actions/other/ferumbras_staff.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-local ferumbrasStaff = Action()
-
-function ferumbrasStaff.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if math.random(100) > 20 then
- item:transform(22767)
- else
- item:transform(22766)
- end
- item:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
- item:decay()
- player:say("Magical sparks whirl around the staff and suddenly it changes its appearance.", TALKTYPE_MONSTER_SAY)
- return ActionsLib.destroyItem(player, target, toPosition)
-end
-
-ferumbrasStaff:id(22764)
-ferumbrasStaff:register()
diff --git a/data-canary/scripts/actions/other/music.lua b/data-canary/scripts/actions/other/music.lua
index eb44c56aeed..589723a1f89 100644
--- a/data-canary/scripts/actions/other/music.lua
+++ b/data-canary/scripts/actions/other/music.lua
@@ -27,8 +27,6 @@ local setting = {
[2966] = { effect = CONST_ME_SOUND_RED }, -- war drum
[3103] = { effect = CONST_ME_SOUND_YELLOW, itemId = 3592, itemCount = 10, chance = 80, remove = true }, -- cornucopia
[5786] = { effects = { failure = CONST_ME_SOUND_RED, success = CONST_ME_SOUND_YELLOW }, monster = "war wolf", chance = 60, remove = true }, -- wooden whistle
- [6572] = { effect = CONST_ME_SOUND_GREEN, text = "TOOOOOOT", transformId = 6573, decayId = 6572 }, -- party trumpet
- [6573] = { effect = CONST_ME_SOUND_GREEN, text = "TOOOOOOT", transformId = 6572, decayId = 6573 }, -- party trumpet
[12602] = { effect = CONST_ME_SOUND_BLUE }, -- small whistle (actual effect is unknown)
[23725] = { effect = CONST_ME_SOUND_WHITE }, -- small crystal bell
}
diff --git a/data-canary/scripts/actions/other/sewer.lua b/data-canary/scripts/actions/other/sewer.lua
deleted file mode 100644
index 2868e887ae5..00000000000
--- a/data-canary/scripts/actions/other/sewer.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local sewer = Action()
-
-function sewer.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if item:getId() == 435 then
- fromPosition.z = fromPosition.z + 1
- end
- player:teleportTo(fromPosition, false)
- return true
-end
-
-sewer:id(435)
-sewer:register()
diff --git a/data-canary/scripts/actions/other/surprise_bag.lua b/data-canary/scripts/actions/other/surprise_bag.lua
deleted file mode 100644
index be59af96267..00000000000
--- a/data-canary/scripts/actions/other/surprise_bag.lua
+++ /dev/null
@@ -1,62 +0,0 @@
-local setting = {
- -- Blue present
- [6570] = {
- { 3598, 10 },
- { 6393, 3 },
- 2995,
- 6569,
- 6572,
- 6574,
- 6575,
- 6576,
- 6577,
- 6578,
- 6279,
- },
- -- Red present
- [6571] = {
- { 3035, 10 },
- { 3035, 10 },
- { 3035, 10 },
- { 2995, 3 },
- { 6392, 2 },
- { 6574, 2 },
- { 6576, 2 },
- { 6578, 2 },
- 2993,
- 3036,
- 3079,
- 3386,
- 3420,
- 5944,
- 6566,
- 6568,
- },
-}
-
-local surpriseBag = Action()
-
-function surpriseBag.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- local count = 1
- local targetItem = setting[item.itemid]
- if not targetItem then
- return true
- end
-
- local gift = targetItem[math.random(#targetItem)]
- if type(gift) == "table" then
- gift = gift[1]
- count = gift[2]
- end
-
- player:addItem(gift, count)
- item:remove(1)
- fromPosition:sendMagicEffect(CONST_ME_GIFT_WRAPS)
- return true
-end
-
-for index, value in pairs(setting) do
- surpriseBag:id(index)
-end
-
-surpriseBag:register()
diff --git a/data-canary/scripts/creaturescripts/#modal_window_example.lua b/data-canary/scripts/creaturescripts/#modal_window_example.lua
deleted file mode 100644
index e2de4a9e474..00000000000
--- a/data-canary/scripts/creaturescripts/#modal_window_example.lua
+++ /dev/null
@@ -1,63 +0,0 @@
---[[
- ModalWindowHelper Example
-]]
---
-
-local moveDirectionTest = {
- ["Right"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_EAST)
- player:teleportTo(pos, true)
- end,
- ["Left"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_WEST)
- player:teleportTo(pos, true)
- end,
- ["Up"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_NORTH)
- player:teleportTo(pos, true)
- end,
- ["Down"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_SOUTH)
- player:teleportTo(pos, true)
- end,
-}
-
-local talkAction = TalkAction("!modalTest")
-
-function talkAction.onSay(player, words, param, type)
- local modalWindow = ModalWindow({
- title = "Modal Window Helper Example",
- message = "This is an example of ModalWindowHelper.",
- })
- if param == "choices" then
- for text, callback in pairs(moveDirectionTest) do
- modalWindow:addChoice(text, function(player, button, choice)
- if button.name == "Select" then
- callback(player)
- modalWindow:sendToPlayer(player)
- end
- end)
- end
-
- modalWindow:addButton("Select")
- modalWindow:addButton("Cancel")
- elseif param == "buttons" then
- for direction, callback in pairs(moveDirectionTest) do
- modalWindow:addButton(direction, function(player, button, choice)
- callback(player)
- modalWindow:sendToPlayer(player)
- end)
- end
- end
- modalWindow:sendToPlayer(player)
- return false
-end
-
---talkAction:accountType(ACCOUNT_TYPE_GOD)
---talkAction:access(true)
-talkAction:separator(" ")
-talkAction:register()
diff --git a/data-canary/scripts/creaturescripts/monster.lua b/data-canary/scripts/creaturescripts/monster.lua
deleted file mode 100644
index abbdae1aea4..00000000000
--- a/data-canary/scripts/creaturescripts/monster.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-local monsterDeath = CreatureEvent("monsterDeath")
-function monsterDeath.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamage_unjustified)
- if creature:isMonster() then
- local self = creature:getStorageValue(MonsterStorage.Spawn.monster_spawn_object)
- self:executeFunctionMonster("onDeath", creature)
- self:deleteMonster(creature)
- return true
- end
- return true
-end
-
-local monsterDeathBoss = CreatureEvent("monsterDeathBoss")
-function monsterDeathBoss.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamage_unjustified)
- if creature:isMonster() then
- local self = creature:getStorageValue(MonsterStorage.Spawn.monster_spawn_object)
- self:removeSpawn()
- self:removeMonsters()
- return true
- end
- return true
-end
-
-monsterDeathBoss:register()
-monsterDeath:register()
diff --git a/data-otservbr-global/lib/others/fragment_gems.lua b/data-otservbr-global/lib/others/fragment_gems.lua
deleted file mode 100644
index cb82b9e951e..00000000000
--- a/data-otservbr-global/lib/others/fragment_gems.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-MAX_GEM_BREAK = 10
-
-FRAGMENT_GEMS = {
- small = { ids = { 44602, 44605, 44608, 44611 }, fragment = 46625, range = { 1, 4 } },
- medium = { ids = { 44603, 44606, 44609, 44612 }, fragment = 46625, range = { 2, 8 } },
- great = { ids = { 44604, 44607, 44610, 44613 }, fragment = 46626, range = { 1, 4 } },
-}
-
-function getGemData(id)
- for _, gem in pairs(FRAGMENT_GEMS) do
- if table.contains(gem.ids, id) then
- return gem.fragment, gem.range
- end
- end
- return nil
-end
diff --git a/data-otservbr-global/lib/others/load.lua b/data-otservbr-global/lib/others/load.lua
index 3d7da57cc77..031c8fb2026 100644
--- a/data-otservbr-global/lib/others/load.lua
+++ b/data-otservbr-global/lib/others/load.lua
@@ -1,2 +1 @@
dofile(DATA_DIRECTORY .. "/lib/others/dawnport.lua")
-dofile(DATA_DIRECTORY .. "/lib/others/fragment_gems.lua")
diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua
index f5b2d75f5ba..a6058bc4715 100644
--- a/data-otservbr-global/lib/quests/soul_war.lua
+++ b/data-otservbr-global/lib/quests/soul_war.lua
@@ -1455,7 +1455,7 @@ function Player:getSoulWarZoneMonster()
return zoneMonsterName
end
-function Player:isInBoatSpot()
+function Creature:isInBoatSpot()
-- Get ebb and flow zone and check if player is in zone
local zone = SoulWarQuest.ebbAndFlow.getZone()
local tile = Tile(self:getPosition())
@@ -1464,11 +1464,11 @@ function Player:isInBoatSpot()
groundId = tile:getGround():getId()
end
if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then
- logger.trace("Player {} is in boat spot", self:getName())
+ logger.trace("Creature {} is in boat spot", self:getName())
return true
end
- logger.trace("Player {} is not in boat spot", self:getName())
+ logger.trace("Creature {} is not in boat spot", self:getName())
return false
end
diff --git a/data-otservbr-global/npc/hireling.lua b/data-otservbr-global/npc/hireling.lua
index ce5c6737e02..bfc9000ca0f 100644
--- a/data-otservbr-global/npc/hireling.lua
+++ b/data-otservbr-global/npc/hireling.lua
@@ -420,11 +420,13 @@ function createHirelingType(HirelingName)
local TOPIC_FOOD = {
SKILL_CHOOSE = 1301,
+ SKILL_SURPRISE = 1302,
}
local GREETINGS = {
BANK = "Alright! What can I do for you and your bank business, |PLAYERNAME|?",
- FOOD = "Hmm, yes! A variety of fine food awaits! However, a small expense of 15000 gold is expected to make these delicious masterpieces happen. Shall I?",
+ FOOD = [[Hmm, yes! A variety of fine food awaits! However, a small expense of 15000 gold is expected to make these delicious masterpieces happen.
+ For 90000 gold I will also serve you a specific dish. Just tell me what it shall be: a {specific} meal or a little {surprise}.]],
STASH = "Of course, here is your stash! Well-maintained and neatly sorted for your convenience!",
}
@@ -513,7 +515,7 @@ function createHirelingType(HirelingName)
return message
end
- local function deliverFood(npc, creature, food_id)
+ local function deliverFood(npc, creature, food_id, cost)
local playerId = creature:getId()
local player = Player(creature)
local itType = ItemType(food_id)
@@ -523,8 +525,8 @@ function createHirelingType(HirelingName)
npcHandler:say("Sorry, but you don't have enough capacity.", npc, creature)
elseif not inbox or #inboxItems >= inbox:getMaxCapacity() then
player:getPosition():sendMagicEffect(CONST_ME_POFF)
- npcHandler:say("Sorry, you don't have enough room on your inbox", npc, creature)
- elseif not player:removeMoneyBank(15000) then
+ npcHandler:say("Sorry, you don't have enough room on your inbox.", npc, creature)
+ elseif not player:removeMoneyBank(cost) then
npcHandler:say("Sorry, you don't have enough money.", npc, creature)
else
local message = getDeliveredMessageByFoodId(food_id)
@@ -534,38 +536,66 @@ function createHirelingType(HirelingName)
npcHandler:setTopic(playerId, TOPIC.SERVICES)
end
- local function cookFood(npc, creature)
+ local function cookFood(npc, creature, specificRequest)
local playerId = creature:getId()
- local random = math.random(6)
- if random == 6 then
- -- ask for preferred skill
+ if specificRequest then
+ npcHandler:say("Very well. You may choose one of the following: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature)
npcHandler:setTopic(playerId, TOPIC_FOOD.SKILL_CHOOSE)
- npcHandler:say("Yay! I have the ingredients to make a skill boost dish. Would you rather like to boost your {magic}, {melee}, {shielding} or {distance} skill?", npc, creature)
- else -- deliver the random generated index
- deliverFood(npc, creature, HIRELING_FOODS_IDS[random])
+ else
+ npcHandler:say("Alright, let me astonish you. Shall I?", npc, creature)
+ deliverFood(npc, creature, HIRELING_FOODS_IDS[math.random(#HIRELING_FOODS_IDS)], 15000)
end
end
local function handleFoodActions(npc, creature, message)
local playerId = creature:getId()
+
if npcHandler:getTopic(playerId) == TOPIC.FOOD then
- if MsgContains(message, "yes") then
- cookFood(npc, creature)
+ if MsgContains(message, "specific") then
+ npcHandler:setTopic(playerId, TOPIC_FOOD.SPECIFIC)
+ npcHandler:say("Which specific meal would you like? Choices are: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature)
+ elseif MsgContains(message, "surprise") then
+ local random = math.random(6)
+ if random == 6 then
+ npcHandler:setTopic(playerId, TOPIC_FOOD.SKILL_CHOOSE)
+ npcHandler:say("Yay! I have the ingredients to make a skill boost dish. Would you rather like to boost your {magic}, {melee}, {shielding}, or {distance} skill?", npc, creature)
+ else
+ deliverFood(npc, creature, HIRELING_FOODS_IDS[random], 15000)
+ end
+ elseif MsgContains(message, "yes") then
+ deliverFood(npc, creature, HIRELING_FOODS_IDS[math.random(#HIRELING_FOODS_IDS)], 15000)
elseif MsgContains(message, "no") then
npcHandler:setTopic(playerId, TOPIC.SERVICES)
npcHandler:say("Alright then, ask me for other {services}, if you want.", npc, creature)
end
elseif npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE then
if MsgContains(message, "magic") then
- deliverFood(npc, creature, HIRELING_FOODS_BOOST.MAGIC)
+ deliverFood(npc, creature, HIRELING_FOODS_BOOST.MAGIC, 15000)
elseif MsgContains(message, "melee") then
- deliverFood(npc, creature, HIRELING_FOODS_BOOST.MELEE)
+ deliverFood(npc, creature, HIRELING_FOODS_BOOST.MELEE, 15000)
elseif MsgContains(message, "shielding") then
- deliverFood(npc, creature, HIRELING_FOODS_BOOST.SHIELDING)
+ deliverFood(npc, creature, HIRELING_FOODS_BOOST.SHIELDING, 15000)
elseif MsgContains(message, "distance") then
- deliverFood(npc, creature, HIRELING_FOODS_BOOST.DISTANCE)
+ deliverFood(npc, creature, HIRELING_FOODS_BOOST.DISTANCE, 15000)
+ else
+ npcHandler:say("Sorry, but you must choose a valid skill class. Would you like to boost your {magic}, {melee}, {shielding}, or {distance} skill?", npc, creature)
+ end
+ elseif npcHandler:getTopic(playerId) == TOPIC_FOOD.SPECIFIC then
+ local specificFoodOptions = {
+ ["chilli con carniphila"] = 29412,
+ ["svargrond salmon filet"] = 29413,
+ ["carrion casserole"] = 29414,
+ ["consecrated beef"] = 29415,
+ ["roasted wyvern wings"] = 29408,
+ ["carrot pie"] = 29409,
+ ["tropical marinated tiger"] = 29410,
+ ["delicatessen salad"] = 29411,
+ }
+
+ if specificFoodOptions[message:lower()] then
+ deliverFood(npc, creature, specificFoodOptions[message:lower()], 90000)
else
- npcHandler:say("Sorry, but you must choose a valid skill class. Would you like to boost your {magic}, {melee}, {shielding} or {distance} skill?", npc, creature)
+ npcHandler:say("I'm sorry, but that's not a valid food option. Please choose from: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature)
end
end
end
@@ -656,7 +686,7 @@ function createHirelingType(HirelingName)
end
elseif npcHandler:getTopic(playerId) == TOPIC.BANK then
enableBankSystem[playerId] = true
- elseif npcHandler:getTopic(playerId) == TOPIC.FOOD or npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE then
+ elseif npcHandler:getTopic(playerId) == TOPIC.FOOD or npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE or npcHandler:getTopic(playerId) == TOPIC_FOOD.SPECIFIC then
handleFoodActions(npc, creature, message)
elseif npcHandler:getTopic(playerId) == TOPIC.GOODS then
-- Ensures players cannot access other shop categories
diff --git a/data-otservbr-global/npc/kais.lua b/data-otservbr-global/npc/kais.lua
index d7fe97f0e75..5da84b1d9cf 100644
--- a/data-otservbr-global/npc/kais.lua
+++ b/data-otservbr-global/npc/kais.lua
@@ -46,8 +46,8 @@ npcType.onCloseChannel = function(npc, creature)
end
-- Blood of the Mountain
-local blessKeyword = keywordHandler:addKeyword({ "blood" }, StdModule.say, { npcHandler = npcHandler, text = "Would you like to receive that protection for a sacrifice of |BLESSCOST| gold, child?" })
-blessKeyword:addChildKeyword({ "yes" }, StdModule.bless, { npcHandler = npcHandler, text = "So receive the Blood of the Mountain, pilgrim.", cost = "|BLESSCOST|", bless = 7 })
+local blessKeyword = keywordHandler:addKeyword({ "enhanced" }, StdModule.say, { npcHandler = npcHandler, text = "I have the power to grant you the blood of the mountain's blessing. But I must ask of you to sacrifice |BLESSCOST| gold. Are you prepared for that?" })
+blessKeyword:addChildKeyword({ "yes" }, StdModule.bless, { npcHandler = npcHandler, text = "So receive the blood of the mountain, master.", cost = "|BLESSCOST|", bless = 8 })
blessKeyword:addChildKeyword({ "" }, StdModule.say, { npcHandler = npcHandler, text = "Fine. You are free to decline my offer.", reset = true })
-- Healing
@@ -58,6 +58,7 @@ local function addHealKeyword(text, condition, effect)
player:removeCondition(condition)
player:getPosition():sendMagicEffect(effect)
end)
+ keywordHandler:addAliasKeyword({ "help" })
end
addHealKeyword("You are burning. Let me quench those flames.", CONDITION_FIRE, CONST_ME_MAGIC_GREEN)
@@ -74,26 +75,19 @@ end, function(player)
player:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
end)
keywordHandler:addKeyword({ "heal" }, StdModule.say, { npcHandler = npcHandler, text = "You aren't looking that bad. Sorry, I can't help you. But if you are looking for additional protection you should go on the {pilgrimage} of ashes or get the protection of the {twist of fate} here." })
+keywordHandler:addAliasKeyword({ "help" })
-- Basic
-keywordHandler:addKeyword({ "pilgrimage" }, StdModule.say, { npcHandler = npcHandler, text = "Whenever you receive a lethal wound, your vital force is damaged and there is a chance that you lose some of your equipment. With every single of the five {blessings} you have, this damage and chance of loss will be reduced." })
-keywordHandler:addKeyword({ "blessings" }, StdModule.say, { npcHandler = npcHandler, text = "There are five blessings available in five sacred places: the {spiritual} shielding, the spark of the {phoenix}, the {embrace} of Tibia, the fire of the {suns} and the wisdom of {solitude}. Additionally, you can receive the {twist of fate} here." })
-keywordHandler:addKeyword({ "spiritual" }, StdModule.say, { npcHandler = npcHandler, text = "I see you received the spiritual shielding in the whiteflower temple south of Thais." }, function(player)
- return player:hasBlessing(1)
-end)
-keywordHandler:addAliasKeyword({ "shield" })
-keywordHandler:addKeyword({ "suns" }, StdModule.say, { npcHandler = npcHandler, text = "I can see you received the blessing of the two suns in the suntower near Ab'Dendriel." }, function(player)
- return player:hasBlessing(3)
-end)
-keywordHandler:addAliasKeyword({ "fire" })
-keywordHandler:addKeyword({ "phoenix" }, StdModule.say, { npcHandler = npcHandler, text = "I can sense that the spark of the phoenix already was given to you by the dwarven priests of earth and fire in Kazordoon." }, function(player)
- return player:hasBlessing(4)
-end)
-keywordHandler:addAliasKeyword({ "spark" })
-keywordHandler:addKeyword({ "solitude" }, StdModule.say, { npcHandler = npcHandler, text = "I can sense you already talked to the hermit Eremo on the isle of Cormaya and received this blessing." }, function(player)
- return player:hasBlessing(5)
-end)
-keywordHandler:addAliasKeyword({ "wisdom" })
+keywordHandler:addKeyword({ "Kais" }, StdModule.say, { npcHandler = npcHandler, text = "I am Kais, Kais the Bound. Eternally {fixed} to the wretched place, unless... unless I prove my worth in aiding all those who seek my {help}." })
+
+keywordHandler:addKeyword({ "pilgrimage" }, StdModule.say, { npcHandler = npcHandler, text = "Well, as I am quite in a fix currently, my only hope to escape this situation may be to grant you {healing} or an {enhanced} blessing if you wish. You must desire SOMETHING, right? Sure you do." })
+keywordHandler:addAliasKeyword({ "job" })
+
+keywordHandler:addKeyword({ "blessing" }, StdModule.say, {
+ npcHandler = npcHandler,
+ text = "Besides the {enhanced} blessing available from me, I know of one other, granted by a solitary {nomad} far west of Svargrond. There are also five different other blessings available, each in a sacred place. ...\nThese blessings are: the {spiritual} shielding, the spark of the {phoenix}, the {embrace} of Tibia, the fire of the {suns} and the wisdom of {solitude}.",
+})
+
keywordHandler:addKeyword({ "spiritual" }, StdModule.say, { npcHandler = npcHandler, text = "You can ask for the blessing of spiritual shielding in the whiteflower temple south of Thais." })
keywordHandler:addAliasKeyword({ "shield" })
keywordHandler:addKeyword({ "suns" }, StdModule.say, { npcHandler = npcHandler, text = "You can ask for the blessing of the two suns in the suntower near Ab'Dendriel." })
@@ -102,10 +96,14 @@ keywordHandler:addKeyword({ "phoenix" }, StdModule.say, { npcHandler = npcHandle
keywordHandler:addAliasKeyword({ "spark" })
keywordHandler:addKeyword({ "solitude" }, StdModule.say, { npcHandler = npcHandler, text = "Talk to the hermit Eremo on the isle of Cormaya about this blessing." })
keywordHandler:addAliasKeyword({ "wisdom" })
+keywordHandler:addKeyword({ "embrace" }, StdModule.say, { npcHandler = npcHandler, text = "The druids north of Carlin will provide you with the embrace of Tibia." })
+keywordHandler:addAliasKeyword({ "tibia" })
+
+keywordHandler:addKeyword({ "nomad" }, StdModule.say, { npcHandler = npcHandler, text = "I know everyone and everything. It is certain that there is another enhanced blessing, the 'heart of the mountain'. Talk to a nomad far to the west of Svargrond, hiding slightly above ground." })
-npcHandler:setMessage(MESSAGE_GREET, "Welcome, noble |PLAYERNAME|")
-npcHandler:setMessage(MESSAGE_WALKAWAY, "Good Bye, noble |PLAYERNAME|")
-npcHandler:setMessage(MESSAGE_FAREWELL, "Good Bye, noble |PLAYERNAME|")
+npcHandler:setMessage(MESSAGE_GREET, "Hmm... surely you are in need of {help} - will you let me? I am {Kais} the Bound and I can lend you a hand in {healing} your body and soul or even grant an {enhanced} blessing!")
+npcHandler:setMessage(MESSAGE_WALKAWAY, "Fare you well... |PLAYERNAME|")
+npcHandler:setMessage(MESSAGE_FAREWELL, "Fare you well... |PLAYERNAME|")
npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true)
diff --git a/data-otservbr-global/npc/nomad.lua b/data-otservbr-global/npc/nomad.lua
index 79dee9cc229..2e33e91a872 100644
--- a/data-otservbr-global/npc/nomad.lua
+++ b/data-otservbr-global/npc/nomad.lua
@@ -50,8 +50,8 @@ npcType.onCloseChannel = function(npc, creature)
end
-- Heart of the Mountain
-local blessKeyword = keywordHandler:addKeyword({ "heart" }, StdModule.say, { npcHandler = npcHandler, text = "Would you like to receive that protection for a sacrifice of |BLESSCOST| gold, child?" })
-blessKeyword:addChildKeyword({ "yes" }, StdModule.bless, { npcHandler = npcHandler, text = "So receive the Heart of the Mountain, pilgrim.", cost = "|BLESSCOST|", bless = 8 })
+local blessKeyword = keywordHandler:addKeyword({ "enhanced" }, StdModule.say, { npcHandler = npcHandler, text = "I am able to grant you the heart of the mountain's blessing. But I must ask of you to sacrifice |BLESSCOST| gold. Are you willing to part with that amount of wealth?" })
+blessKeyword:addChildKeyword({ "yes" }, StdModule.bless, { npcHandler = npcHandler, text = "Receive the heart of the mountain then.", cost = "|BLESSCOST|", bless = 7 })
blessKeyword:addChildKeyword({ "" }, StdModule.say, { npcHandler = npcHandler, text = "Fine. You are free to decline my offer.", reset = true })
-- Healing
@@ -62,6 +62,7 @@ local function addHealKeyword(text, condition, effect)
player:removeCondition(condition)
player:getPosition():sendMagicEffect(effect)
end)
+ keywordHandler:addAliasKeyword({ "help" })
end
addHealKeyword("You are burning. Let me quench those flames.", CONDITION_FIRE, CONST_ME_MAGIC_GREEN)
@@ -78,26 +79,17 @@ end, function(player)
player:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
end)
keywordHandler:addKeyword({ "heal" }, StdModule.say, { npcHandler = npcHandler, text = "You aren't looking that bad. Sorry, I can't help you. But if you are looking for additional protection you should go on the {pilgrimage} of ashes or get the protection of the {twist of fate} here." })
+keywordHandler:addAliasKeyword({ "help" })
-- Basic
-keywordHandler:addKeyword({ "pilgrimage" }, StdModule.say, { npcHandler = npcHandler, text = "Whenever you receive a lethal wound, your vital force is damaged and there is a chance that you lose some of your equipment. With every single of the five {blessings} you have, this damage and chance of loss will be reduced." })
-keywordHandler:addKeyword({ "blessings" }, StdModule.say, { npcHandler = npcHandler, text = "There are five blessings available in five sacred places: the {spiritual} shielding, the spark of the {phoenix}, the {embrace} of Tibia, the fire of the {suns} and the wisdom of {solitude}. Additionally, you can receive the {twist of fate} here." })
-keywordHandler:addKeyword({ "spiritual" }, StdModule.say, { npcHandler = npcHandler, text = "I see you received the spiritual shielding in the whiteflower temple south of Thais." }, function(player)
- return player:hasBlessing(1)
-end)
-keywordHandler:addAliasKeyword({ "shield" })
-keywordHandler:addKeyword({ "suns" }, StdModule.say, { npcHandler = npcHandler, text = "I can see you received the blessing of the two suns in the suntower near Ab'Dendriel." }, function(player)
- return player:hasBlessing(3)
-end)
-keywordHandler:addAliasKeyword({ "fire" })
-keywordHandler:addKeyword({ "phoenix" }, StdModule.say, { npcHandler = npcHandler, text = "I can sense that the spark of the phoenix already was given to you by the dwarven priests of earth and fire in Kazordoon." }, function(player)
- return player:hasBlessing(4)
-end)
-keywordHandler:addAliasKeyword({ "spark" })
-keywordHandler:addKeyword({ "solitude" }, StdModule.say, { npcHandler = npcHandler, text = "I can sense you already talked to the hermit Eremo on the isle of Cormaya and received this blessing." }, function(player)
- return player:hasBlessing(5)
-end)
-keywordHandler:addAliasKeyword({ "wisdom" })
+keywordHandler:addKeyword({ "blessing" }, StdModule.say, {
+ npcHandler = npcHandler,
+ text = "Besides the {enhanced} blessing available from me, I know of one other, granted by a solitary {nomad} far west of Svargrond. There are also five different other blessings available, each in a sacred place. ...\nThese blessings are: the {spiritual} shielding, the spark of the {phoenix}, the {embrace} of Tibia, the fire of the {suns} and the wisdom of {solitude}.",
+})
+
+keywordHandler:addKeyword({ "pilgrimage" }, StdModule.say, { npcHandler = npcHandler, text = "Well, as I am quite in a {fix} currently, my only hope to escape this situation may be to grant you {healing} or an {enhanced} blessing if you wish. You must desire SOMETHING, right? Sure you do." })
+keywordHandler:addAliasKeyword({ "job" })
+
keywordHandler:addKeyword({ "spiritual" }, StdModule.say, { npcHandler = npcHandler, text = "You can ask for the blessing of spiritual shielding in the whiteflower temple south of Thais." })
keywordHandler:addAliasKeyword({ "shield" })
keywordHandler:addKeyword({ "suns" }, StdModule.say, { npcHandler = npcHandler, text = "You can ask for the blessing of the two suns in the suntower near Ab'Dendriel." })
@@ -106,10 +98,16 @@ keywordHandler:addKeyword({ "phoenix" }, StdModule.say, { npcHandler = npcHandle
keywordHandler:addAliasKeyword({ "spark" })
keywordHandler:addKeyword({ "solitude" }, StdModule.say, { npcHandler = npcHandler, text = "Talk to the hermit Eremo on the isle of Cormaya about this blessing." })
keywordHandler:addAliasKeyword({ "wisdom" })
+keywordHandler:addKeyword({ "embrace" }, StdModule.say, { npcHandler = npcHandler, text = "The druids north of Carlin will provide you with the embrace of Tibia." })
+keywordHandler:addAliasKeyword({ "tibia" })
+
+keywordHandler:addKeyword({ "djinn" }, StdModule.say, { npcHandler = npcHandler, text = "I know of a mysterious djinn, bound to an existence of slavery far to the north of Tiquanda's jungles. He is bound to tell you his secrets and offer you the 'blood of the mountain'. ...\nI do not know where exactly but I guess you must first dig that one out to actually talk to him." })
+keywordHandler:addKeyword({ "nomad" }, StdModule.say, { npcHandler = npcHandler, text = "I am one with nature, one with the ice and the cold. Names are of no worth out here. Out here, you face isolation and loneliness. Only your strength, willpower and {training} can keep you alive." })
+keywordHandler:addKeyword({ "training" }, StdModule.say, { npcHandler = npcHandler, text = "My life is one of hardship, hardship I chose freely. Endurance, strength and the power of the will are my only companions in this frigid wilderness. My strength comes from disciplined training and knowledge of the outdoors." })
-npcHandler:setMessage(MESSAGE_GREET, "Welcome, noble |PLAYERNAME|")
-npcHandler:setMessage(MESSAGE_WALKAWAY, "Good Bye, noble |PLAYERNAME|")
-npcHandler:setMessage(MESSAGE_FAREWELL, "Good Bye, noble |PLAYERNAME|")
+npcHandler:setMessage(MESSAGE_GREET, "Ah, another diciple of the extreme... surviving the icy outdoors? Let me {help}! If you need some first aid out here, I can provide {healing} or grant you an {enhanced} blessing!")
+npcHandler:setMessage(MESSAGE_WALKAWAY, "Keep a stiff upper lip!")
+npcHandler:setMessage(MESSAGE_FAREWELL, "Keep a stiff upper lip!")
npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true)
diff --git a/data-otservbr-global/scripts/actions/other/bed_modification_kits.lua b/data-otservbr-global/scripts/actions/other/bed_modification_kits.lua
deleted file mode 100644
index 4dd68ff834d..00000000000
--- a/data-otservbr-global/scripts/actions/other/bed_modification_kits.lua
+++ /dev/null
@@ -1,54 +0,0 @@
-local beds = {
- [831] = { { 734, 735 }, { 736, 737 } }, -- green kit
- [832] = { { 742, 743 }, { 744, 745 } }, -- yellow kit
- [833] = { { 738, 739 }, { 740, 741 } }, -- red kit
- [834] = { { 2487, 2488 }, { 2493, 2494 } }, -- removal kit
- [17972] = { { 17917, 17918 }, { 17919, 17920 } }, -- canopy kit
-}
-
-local function internalBedTransform(item, target, toPosition, itemArray)
- target:transform(itemArray[1])
- target:getPosition():sendMagicEffect(CONST_ME_POFF)
-
- toPosition:getTile():getItemByType(ITEM_TYPE_BED):transform(itemArray[2])
- toPosition:sendMagicEffect(CONST_ME_POFF)
-
- item:remove()
-end
-
-local bedModificationKits = Action()
-
-function bedModificationKits.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- local newBed = beds[item.itemid]
- if not newBed then
- return false
- end
-
- local tile = toPosition:getTile()
- if not tile or not tile:getHouse() then
- return false
- end
-
- if target.itemid == newBed[1][1] or target.itemid == newBed[2][1] then
- player:sendTextMessage(MESSAGE_FAILURE, "You already have this bed modification.")
- return true
- end
-
- for kit, bed in pairs(beds) do
- if bed[1][1] == target.itemid or table.contains({ 2491, 5501, 15506 }, target.itemid) then
- toPosition:sendMagicEffect(CONST_ME_POFF)
- toPosition.y = toPosition.y + 1
- internalBedTransform(item, target, toPosition, newBed[1])
- break
- elseif bed[2][1] == target.itemid or table.contains({ 2489, 5499, 15508 }, target.itemid) then
- toPosition:sendMagicEffect(CONST_ME_POFF)
- toPosition.x = toPosition.x + 1
- internalBedTransform(item, target, toPosition, newBed[2])
- break
- end
- end
- return true
-end
-
-bedModificationKits:id(831, 832, 833, 834, 17972)
-bedModificationKits:register()
diff --git a/data-otservbr-global/scripts/actions/other/dolls.lua b/data-otservbr-global/scripts/actions/other/dolls.lua
deleted file mode 100644
index 32864dcd109..00000000000
--- a/data-otservbr-global/scripts/actions/other/dolls.lua
+++ /dev/null
@@ -1,106 +0,0 @@
-local dolls = {
- [5080] = { "Hug me." },
- [5668] = {
- "It's not winning that matters, but winning in style.",
- "Today's your lucky day. Probably.",
- "Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.",
- "That is one stupid question.",
- "You'll need more rum for that.",
- "Do or do not. There is no try.",
- "You should do something you always wanted to.",
- "If you walk under a ladder and it falls down on you it probably means bad luck.",
- "Never say 'oops'. Always say 'Ah, interesting!'",
- "Five steps east, fourteen steps south, two steps north and seventeen steps west!",
- },
- [6566] = {
- "Fchhhhhh!",
- "Zchhhhhh!",
- "Grooaaaaar*cough*",
- "Aaa... CHOO!",
- "You... will.... burn!!",
- },
- [6387] = { "Merry Christmas |PLAYERNAME|." },
- [6511] = {
- "Ho ho ho",
- "Jingle bells, jingle bells...",
- "Have you been naughty?",
- "Have you been nice?",
- "Merry Christmas!",
- "Can you stop squeezing me now... I'm starting to feel a little sick.",
- },
- [8146] = { "ARE YOU PREPARED TO FACE YOUR DESTINY?" },
- [8149] = {
- "Weirdo, you're a weirdo! Actually all of you are!",
- "Pie for breakfast, pie for lunch and pie for dinner!",
- "All hail the control panel!",
- "I own, Tibiacity owns, perfect match!",
- "Hug me! Feed me! Hail me!",
- },
- [8153] = {
- "It's news to me.",
- "News, updated as infrequently as possible!",
- "Extra! Extra! Read all about it!",
- "Fresh off the press!",
- },
- [8154] = {
- "Hail TibiaNordic!",
- "So cold..",
- "Run, mammoth!",
- },
- [21435] = {
- "I can hear their whisperings... Revenge!",
- "You shall feel pain and terror, |PLAYERNAME|",
- "I do not need a sword to slaughter you",
- "My sword is broken, but my spirit is not dead",
- "I can say 469 and more...",
- "My dark magic lies on tibialatina.wikia.com",
- },
- [21962] = { "Hail Tibia Brasileiros! (União&Força)" },
- [32918] = {
- "COME HERE! FREE ITEMS FOR EVERYONE!",
- "DON'T BE AFRAID! I AM COMING IN PEACE!",
- "BOW TO THE POWER OF THE RUTHLESS SEVEN!",
- "Slay your friends and I will spare you!",
- },
-}
-
-local doll = Action()
-
-function doll.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- local sounds = dolls[item.itemid]
- if not sounds then
- return false
- end
-
- if fromPosition.x == CONTAINER_POSITION then
- fromPosition = player:getPosition()
- end
-
- local random = math.random(#sounds)
- local sound = sounds[random]
- if item.itemid == 6566 then
- if random == 3 then
- fromPosition:sendMagicEffect(CONST_ME_POFF)
- elseif random == 4 then
- fromPosition:sendMagicEffect(CONST_ME_FIREAREA)
- elseif random == 5 then
- doTargetCombatHealth(0, player, COMBAT_PHYSICALDAMAGE, -1, -1, CONST_ME_EXPLOSIONHIT)
- end
- elseif item.itemid == 5668 then
- fromPosition:sendMagicEffect(CONST_ME_MAGIC_RED)
- item:transform(item.itemid + 1)
- item:decay()
- elseif item.itemid == 6387 then
- fromPosition:sendMagicEffect(CONST_ME_SOUND_YELLOW)
- end
-
- sound = sound:gsub("|PLAYERNAME|", player:getName())
- player:say(sound, TALKTYPE_MONSTER_SAY, false, 0, fromPosition)
- return true
-end
-
-for index, value in pairs(dolls) do
- doll:id(index)
-end
-
-doll:register()
diff --git a/data-otservbr-global/scripts/actions/other/surprise_bag.lua b/data-otservbr-global/scripts/actions/other/surprise_bag.lua
deleted file mode 100644
index 052fc987c61..00000000000
--- a/data-otservbr-global/scripts/actions/other/surprise_bag.lua
+++ /dev/null
@@ -1,103 +0,0 @@
-local config = {
- [6570] = { -- bluePresent
- { 3598, 10 },
- { 6393, 3 },
- 6279,
- 6574,
- 6578,
- 6575,
- 6577,
- 6569,
- 6576,
- 6572,
- 2995,
- 14027,
- 14681,
- },
- [6571] = { -- redPresent
- 6574,
- 3079,
- 6393,
- 6576,
- 6578,
- 2995,
- 14027,
- 3036,
- 5944,
- 3386,
- 3420,
- 3039,
- 5080,
- 2993,
- 3392,
- 3057,
- 5791,
- },
- [8853] = { -- surpriseBag
- { 3031, 10 },
- 123,
- 2995,
- 2397,
- 651,
- 3218,
- 6574,
- 6393,
- 7377,
- 3578,
- 8778,
- },
- [14751] = { -- surpriseBag
- { 9642, 15 },
- { 3581, 15 },
- 5917,
- 3273,
- 10302,
- 9019,
- 5928,
- 5926,
- 5927,
- 6095,
- 5918,
- 6097,
- 6098,
- 5461,
- 5090,
- },
- [14759] = { -- surpriseBag
- { 6569, 10 },
- { 6541, 10 },
- { 6542, 10 },
- { 6543, 10 },
- { 6544, 10 },
- { 6545, 10 },
- 6574,
- 4839,
- 6570,
- 6571,
- 3215,
- },
-}
-
-local surpriseBag = Action()
-
-function surpriseBag.onUse(cid, item, fromPosition, itemEx, toPosition)
- local present = config[item.itemid]
- if not present then
- return false
- end
-
- local count = 1
- local gift = present[math.random(1, #present)]
- if type(gift) == "table" then
- count = math.random(1, gift[2])
- gift = gift[1]
- end
-
- Player(cid):addItem(gift, count)
- Item(item.uid):remove(1)
- fromPosition:sendMagicEffect(CONST_ME_GIFT_WRAPS)
- return true
-end
-
-surpriseBag:id(6570, 6571, 8853, 14751, 14759)
-surpriseBag:register()
diff --git a/data-otservbr-global/scripts/actions/other/surprise_box.lua b/data-otservbr-global/scripts/actions/other/surprise_box.lua
deleted file mode 100644
index 94fdb95eb2d..00000000000
--- a/data-otservbr-global/scripts/actions/other/surprise_box.lua
+++ /dev/null
@@ -1,31 +0,0 @@
-local prize = {
- [1] = { chance = 1, id = 3246, amount = 1 },
- [2] = { chance = 2, id = 10227, amount = 1 },
- [3] = { chance = 3, id = 11588, amount = 1 },
- [4] = { chance = 4, id = 3549, amount = 1 },
- [5] = { chance = 5, id = 3420, amount = 1 },
- [6] = { chance = 10, id = ITEM_CRYSTAL_COIN, amount = 17 },
- [7] = { chance = 20, id = ITEM_GOLD_COIN, amount = 1 },
- [8] = { chance = 30, id = ITEM_CRYSTAL_COIN, amount = 1 },
- [9] = { chance = 40, id = ITEM_GOLD_COIN, amount = 50 },
- [10] = { chance = 50, id = ITEM_PLATINUM_COIN, amount = 15 },
- [11] = { chance = 90, id = ITEM_GOLD_COIN, amount = 80 },
-}
-
-local surpriseBox = Action()
-
-function surpriseBox.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- for i = 1, #prize do
- local number = math.random() * 100
- if prize[i].chance > 100 - number then
- player:getPosition():sendMagicEffect(CONST_ME_POFF)
- player:addItem(prize[i].id, prize[i].amount)
- item:remove()
- break
- end
- end
- return true
-end
-
-surpriseBox:id(12045)
-surpriseBox:register()
diff --git a/data-otservbr-global/scripts/actions/other/teleport.lua b/data-otservbr-global/scripts/actions/other/teleport.lua
deleted file mode 100644
index 7e763f00594..00000000000
--- a/data-otservbr-global/scripts/actions/other/teleport.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-local ladderTable = Game.getLadderIds()
-
-local upFloorIds = ladderTable
-
-local teleport = Action()
-
-function teleport.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if table.contains(upFloorIds, item.itemid) then
- fromPosition:moveUpstairs()
- else
- fromPosition.z = fromPosition.z + 1
- end
- player:teleportTo(fromPosition, false)
- return true
-end
-
-teleport:id(435)
-teleport:id(unpack(ladderTable))
-teleport:register()
diff --git a/data-otservbr-global/scripts/actions/other/transform_to.lua b/data-otservbr-global/scripts/actions/other/transform_to.lua
deleted file mode 100644
index 5257544eb60..00000000000
--- a/data-otservbr-global/scripts/actions/other/transform_to.lua
+++ /dev/null
@@ -1,484 +0,0 @@
-local voices = {
- [23708] = "Au au!",
- [23443] = "Grooaarr!",
-}
-
-local transformItems = {
- [2062] = 2063,
- [2063] = 2062, -- sacred statue
- [2064] = 2065,
- [2065] = 2064, -- sacred statue
- [2108] = 2109,
- [2109] = 2108, -- street lamp
- [2334] = 2335,
- [2335] = 2334, -- table
- [2336] = 2337,
- [2337] = 2336, -- table
- [2338] = 2339,
- [2339] = 2338, -- table
- [2340] = 2341,
- [2341] = 2340, -- table
- [2535] = 2536,
- [2536] = 2535, -- oven
- [2537] = 2538,
- [2538] = 2537, -- oven
- [2539] = 2540,
- [2540] = 2539, -- oven
- [2541] = 2542,
- [2542] = 2541, -- oven
- [2660] = 2661,
- [2661] = 2660, -- cuckoo clock
- [2662] = 2663,
- [2663] = 2662, -- cuckoo clock
- [2772] = 2773,
- [2773] = 2772, -- lever
- [2911] = 2912,
- [2912] = 2911, -- candelabrum
- [2914] = 2915,
- [2915] = 2914, -- lamp
- [2917] = 2918,
- [2918] = 2917, -- candlestick
- [2920] = 2921,
- [2921] = 2920, -- torch
- [2922] = 2923,
- [2923] = 2922, -- torch
- [2924] = 2925,
- [2925] = 2924, -- torch
- [2928] = 2929,
- [2929] = 2928, -- torch bearer
- [2930] = 2931,
- [2931] = 2930, -- torch bearer
- [2934] = 2935,
- [2935] = 2934, -- table lamp
- [2977] = 2978,
- [2978] = 2977, -- pumpkinhead
- [3046] = 3047,
- [3047] = 3046, -- magic light wand
- [3481] = 3482, -- closed trap
- [5812] = 5813,
- [5813] = 5812, -- skull candle
- [6488] = 6489,
- [6489] = 6488, -- christmas branch
- [7058] = 7059,
- [7059] = 7058, -- skull pillar
- [7856] = 7857,
- [7857] = 7856, -- chimney
- [7858] = 7859,
- [7859] = 7858, -- chimney
- [7860] = 7861,
- [7861] = 7860, -- chimney
- [7862] = 7863,
- [7863] = 7862, -- chimney
- [8659] = 8660,
- [8660] = 8659, -- street lamp
- [8661] = 8662,
- [8662] = 8661, -- street lamp
- [8663] = 8664,
- [8664] = 8663, -- street lamp
- [8665] = 8666,
- [8666] = 8665, -- street lamp
- [8832] = 8833,
- [8833] = 8832, -- wall lamp
- [8834] = 8835,
- [8835] = 8834, -- wall lamp
- [17411] = 17412,
- [17412] = 17411, -- street lamp
- [20280] = 20281,
- [20281] = 20280, -- beacon
- [20498] = 20497,
- [20497] = 20498, -- street lamp
- [20500] = 20499,
- [20499] = 20500, -- street lamp
- [20501] = 20502,
- [20502] = 20501, -- candle
- [20503] = 20504,
- [20504] = 20503, -- candle
- [22153] = 22154,
- [22154] = 22153, -- skull
- [22764] = 22765,
- [22765] = 22764, -- ferumbras staff
- [23434] = 23436,
- [23436] = 23434, -- predador lamp
- [23435] = 23437,
- [23437] = 23435, -- predador lamp
- [23438] = 23440,
- [23440] = 23438, -- protectress lamp
- [23439] = 23441,
- [23441] = 23439, -- protectress lamp
- [23442] = 23443,
- [23443] = 23442, -- baby dragon
- [23444] = 23445,
- [23445] = 23444, -- hamster wheel
- [23451] = 23452,
- [23452] = 23451, -- cat in a basket
- [23485] = 23486,
- [23486] = 23485, -- barrel
- [23708] = 23709,
- [23709] = 23708, -- dog house
- [24432] = 24433,
- [24433] = 24432, -- parrot
- [24434] = 24436,
- [24435] = 24434, -- skull lamp
- [25212] = 25210,
- [25211] = 25212, -- vengothic lamp
- [26078] = 26079, -- spider terrarium
- [26081] = 26083,
- [26083] = 26081, -- hrodmiran weapons rack
- [26084] = 26082,
- [26082] = 26084, -- hrodmiran weapons rack side
- [26171] = 26169,
- [26172] = 26170, -- snake terrarium
- [26173] = 26175,
- [26174] = 26176, -- demon pet
- [27667] = 27668, -- light of change empty to red
- [27668] = 27669, -- light of change red to green
- [27669] = 27670, -- light of change green to blue
- [27670] = 27667, -- light of change blue to empty
- [27671] = 27673, -- torch of change empty to red
- [27673] = 27674, -- torch of change red to green
- [27674] = 27675, -- torch of change green to blue
- [27675] = 27671, -- torch of change blue to empty
- [27683] = 27685,
- [27684] = 27686, -- alchemistic scales
- [27687] = 27688,
- [27688] = 27687, -- pile of alchemistic books
- [27691] = 27692,
- [27692] = 27691, -- ferumbras bust
- [27693] = 27694,
- [27694] = 27693, -- ferumbras bust
- [27986] = 27988,
- [27988] = 27986, -- bonelord statue
- [27987] = 27989,
- [27989] = 27987, -- bonelord statue
- [27996] = 27998,
- [27998] = 27996, -- scholar bust
- [27997] = 27999,
- [27999] = 27997, -- scholar bust
- [28000] = 28002,
- [28002] = 28000, -- scholar bust
- [28001] = 28003,
- [28003] = 28001, -- scholar bust
- [28674] = 28675,
- [28675] = 28674, -- anglerfish lamp
- [28690] = 28691,
- [28692] = 28693, -- baby rotworm
- [28694] = 28695, --fennec
- [28915] = 28916,
- [28917] = 28918, -- adamant shield
- [28920] = 28921,
- [28921] = 28920, -- fluorescent fungi
- [28922] = 28923,
- [28923] = 28922, -- luminescent fungi
- [28924] = 28925,
- [28925] = 28924, -- glowing sulphur fungi
- [28926] = 28927,
- [28927] = 28926, -- gloomy poisonous fungi
- [30229] = 30230,
- [30230] = 30231, -- festive table
- [30231] = 30229, -- festive table
- [30233] = 30234,
- [30234] = 30233, -- festive fireplace
- [30235] = 30236,
- [30236] = 30235, -- festive fireplace
- [30237] = 30238,
- [30238] = 30237, -- festive tree
- [30248] = 30249,
- [30249] = 30248, -- festive pyramid
- [30362] = 30365, -- Badbara
- [30363] = 30366, -- Tearesa
- [30364] = 30367, -- Cryana
- [31196] = 31197,
- [31197] = 31196, -- crystal lamp
- [31213] = 31215,
- [31215] = 31213, -- idol lamp
- [31214] = 31216,
- [31216] = 31214, -- idol lamp side
- [31462] = 31463,
- [31464] = 31465, -- jousting eagle baby
- [31674] = 31675, -- omniscient owl
- [31681] = 31682, -- hedgehog
- [31683] = 31684,
- [31684] = 31683, -- exalted sarcophagus
- [31695] = 31696,
- [31696] = 31695, -- curly hortensis lamp
- [31697] = 31698,
- [31698] = 31697, -- little big flower lamp
- [31703] = 31704, -- baby unicorn
- [32760] = 32758,
- [32761] = 32759, -- mini NaBbot
- [32784] = 32785,
- [32785] = 32784, -- ice chandelier
- [32788] = 32789, -- baby seal
- [32790] = 32791,
- [32792] = 32793, -- baby polar bear
- [32897] = 32899,
- [32899] = 32897, -- wall lamp
- [32900] = 32901,
- [32901] = 32900, -- torch bearer
- [32902] = 32903,
- [32903] = 32902, -- bamboo wall lamp
- [32904] = 32905,
- [32905] = 32904, -- wall candle
- [32907] = 32910, -- guzzlemaw grub
- [32908] = 32911, -- baby vulcongra
- [32909] = 32912, -- baby brain squid
- [33026] = 33047,
- [33027] = 33026, -- heart lamp
- [33028] = 33048,
- [33029] = 33028, -- heart lamp (flower)
- [33030] = 33049,
- [33031] = 33030, -- heart lamp (small flower)
- [33040] = 33042, -- bat
- [33331] = 33332,
- [33333] = 33334, -- bard doll
- [34026] = 34027, -- baby bonelord
- [34030] = 34031,
- [34031] = 34030, -- artist shelf
- [34032] = 34033,
- [34033] = 34032, -- artist shelf
- [34034] = 34035,
- [34035] = 34034, -- artist table
- [34044] = 34045,
- [34045] = 34044, -- sculptor shelf
- [34046] = 34047,
- [34047] = 34046, -- sculptor shelf
- [34048] = 34049,
- [34049] = 34048, -- sculptor table
- [34064] = 34065,
- [34065] = 34066, -- sculpture of a noblewoman
- [34066] = 34067,
- [34067] = 34064, -- sculpture of a noblewoman
- [34068] = 34069,
- [34069] = 34070, -- sculpture of a noblewoman
- [34070] = 34071,
- [34071] = 34068, -- sculpture of a noblewoman
- [34264] = 34265,
- [34266] = 34267, -- Tibiapedia
- [34268] = 34269,
- [34269] = 34268, -- Baby Munster
- [34270] = 34271,
- [34271] = 34270, -- glowworms
- [34272] = 34273,
- [34273] = 34272, -- oven
- [34274] = 34275,
- [34275] = 34274, -- oven
- [34284] = 34285,
- [34285] = 34284, -- kitchen table (empty)
- [34287] = 34288,
- [34288] = 34287, -- kitchen table (empty)
- [34286] = 34290,
- [34290] = 34286, -- kitchen table
- [34289] = 34291,
- [34291] = 34289, -- kitchen table
- [34300] = 34301,
- [34301] = 34300, -- barrel
- [34304] = 34305,
- [34305] = 34304, -- kitchen lamp
- [34326] = 34327, -- wicked witch
- [35153] = 35154, -- baby elephant
- [35155] = 35157,
- [35157] = 35159, -- forge
- [35159] = 35155,
- [35156] = 35158, -- forge
- [35158] = 35160,
- [35160] = 35156, -- forge
- [35161] = 35162,
- [35162] = 35161, -- metal wall lamp
- [35163] = 35165,
- [35165] = 35163, -- workbench
- [35164] = 35166,
- [35166] = 35164, -- workbench
- [35177] = 35180,
- [35180] = 35177, -- grinding wheel
- [35178] = 35179,
- [35179] = 35178, -- grinding wheel
- [35181] = 35183,
- [35183] = 35181, -- pair of bellows
- [35182] = 35184,
- [35184] = 35182, -- pair of bellows
- [35185] = 35186,
- [35186] = 35185, -- anvil
- [35187] = 35188,
- [35188] = 35187, -- water bucket
- [35909] = 35910, -- chaos critical dice
- [36019] = 36020, -- white lion doll
- [36478] = 36479,
- [36480] = 36481, -- banor doll
- [36618] = 36619,
- [36619] = 36618, -- volcanic basin
- [36620] = 36621,
- [36621] = 36620, -- volcanic sphere
- [36622] = 36623,
- [36623] = 36622, -- volcanic spire
- [36624] = 36625,
- [36625] = 36624, -- volcanic bulb
- [36626] = 36628,
- [36628] = 36626, -- volcanic mirror
- [36627] = 36629,
- [36629] = 36627, -- volcanic mirror
- [36638] = 36639,
- [36639] = 36638, -- volcanic table
- [36640] = 36642,
- [36642] = 36644, -- volcanic shelf
- [36644] = 36640,
- [36641] = 36643, -- volcanic shelf
- [36643] = 36645,
- [36645] = 36641, -- volcanic shelf
- [36646] = 36649,
- [36647] = 36650, -- demon baller
- [36648] = 36651,
- [36653] = 36652, -- demon baller
- [36654] = 36646, -- demon baller
- [36750] = 36751,
- [36754] = 36752, -- falcon pet
- [36756] = 36753, -- falcon pet
- [36959] = 36960, -- megasylvan plant
- [36978] = 36979,
- [36979] = 36978, -- magic hat
- [36996] = 36997,
- [36998] = 36999, -- Luna
- [37015] = 37016,
- [37016] = 37015, -- yellow shroom lamp
- [37017] = 37018,
- [37018] = 37017, -- pink shroom lamp
- [37021] = 37022, -- dragon plant
- [37052] = 37053,
- [37053] = 37052, -- bonelord tome
- [37054] = 37055,
- [37056] = 37057, -- Bella Bonecrusher's doll
- [37061] = 37062,
- [37063] = 37064, -- Evora
- [37111] = 37112,
- [37113] = 37114, -- armillary sphere
- [37185] = 37186,
- [37186] = 37700, -- kraken watcher lamp
- [37700] = 37185, -- kraken watcher lamp
- [37187] = 37519,
- [37519] = 37187, -- kraken buoy lamp
- [37188] = 37520,
- [37520] = 37188, -- kraken tentacle lamp
- [37189] = 37191,
- [37191] = 37189, -- kraken shelf
- [37190] = 37192,
- [37192] = 37190, -- kraken shelf
- [37205] = 37206,
- [37206] = 37207, -- sculpture of an octoputz
- [37207] = 37205,
- [37208] = 37209, -- sculpture of an octoputz
- [37209] = 37210,
- [37210] = 37208, -- sculpture of an octoputz
- [37211] = 37212,
- [37212] = 37211, -- octoputz
- [37543] = 37580,
- [37580] = 37543, -- string of fairy lights RYG
- [37544] = 37581,
- [37581] = 37544, -- string of fairy lights BRG
- [37545] = 37582,
- [37582] = 37545, -- string of fairy lights BGY
- [37557] = 37558,
- [37559] = 37560, -- dragon pinata
- [37743] = 37744,
- [37745] = 37746, -- draptor doll
- [37749] = 37750,
- [37750] = 37749, -- dark oracle
- [37806] = 37807,
- [37807] = 37806, -- zaoan wall lamp
- [37808] = 37809,
- [37809] = 37808, -- zaoan wall lamps
- [37811] = 37813,
- [37812] = 37814, -- sculpture of a fox
- [38522] = 38524,
- [38524] = 38522, -- naga lamp
- [38523] = 38525,
- [38525] = 38523, -- naga lamp
- [38526] = 38528,
- [38528] = 38526, -- basin with a glowing flower
- [38677] = 38680,
- [38704] = 38705, -- beaver of wisdom
- [38827] = 38828,
- [38828] = 38827, -- wall lamp
- [39423] = 39425,
- [39425] = 39423, -- knightly table
- [39424] = 39426,
- [39426] = 39424, -- knightly table
- [39427] = 39428,
- [39428] = 39427, -- knightly chess table
- [39443] = 39444,
- [39444] = 39445, -- knightly fire bowl
- [39445] = 39443, -- knightly fire bowl
- [39498] = 39499,
- [39499] = 39498, -- knightly candelabra
- [39500] = 39501,
- [39501] = 39500, -- knightly candle holder
- [39508] = 39509,
- [39668] = 39510, -- knightly guard
- [39694] = 39696, -- lucky dragon
- [39697] = 39698,
- [39698] = 39697, -- rainbow torch
- [39699] = 39700,
- [39700] = 39699, -- rainbow torch
- [39701] = 39702,
- [39702] = 39701, -- rainbow torch
- [39757] = 39758, -- yeti doll
- [39759] = 39760,
- [39761] = 39762, -- the gods' twilight doll
- [39772] = 39773,
- [39773] = 39774, -- flower table
- [39774] = 39772, -- flower table
- [39793] = 39794,
- [39794] = 39793, -- turquoise flower lamp
- [39795] = 39796,
- [39796] = 39795, -- purple flower lamp
- [39801] = 39802,
- [39802] = 39801, -- wall leaves
- [39803] = 39804,
- [39804] = 39803, -- tendrils
- [39805] = 39806,
- [39807] = 39808, -- water nymph
- [39810] = 39809, -- water nymph
- [42271] = 42272,
- [42272] = 42271, -- seafarer table
- [42291] = 42292,
- [42292] = 42291, -- seashell lamp
- [42293] = 42294,
- [42294] = 42293, -- seashell lamp
- [42295] = 42296,
- [42296] = 42295, -- tentacle lamp
- [42297] = 42298,
- [42298] = 42297, -- tentacle lamp
- [42299] = 42300,
- [42300] = 42299, -- sea-devil wall lamp
- [42301] = 42302,
- [42302] = 42301, -- seafood bucket
- [42324] = 42326,
- [42326] = 42324, -- opulent table
- [42325] = 42327,
- [42327] = 42325, -- opulent table
- [42346] = 42347,
- [42347] = 42346, -- opulent floor lamp
- [42348] = 42349,
- [42349] = 42348, -- opulent floor lamp
- [42363] = 42364, -- djinn lamp
- [42365] = 42366, -- djinn lamp
-}
-
-local transformTo = Action()
-
-function transformTo.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if voices[item:getId()] then
- local spectators = Game.getSpectators(fromPosition, false, true, 3, 3)
- for i = 1, #spectators do
- player:say(voices[item:getId()], TALKTYPE_MONSTER_SAY, false, spectators[i], fromPosition)
- end
- end
-
- item:transform(transformItems[item.itemid])
- item:decay()
- return true
-end
-
-for index, value in pairs(transformItems) do
- transformTo:id(index)
-end
-
-transformTo:register()
diff --git a/data-otservbr-global/scripts/actions/other/vessels.lua b/data-otservbr-global/scripts/actions/other/vessels.lua
deleted file mode 100644
index b1f0701becb..00000000000
--- a/data-otservbr-global/scripts/actions/other/vessels.lua
+++ /dev/null
@@ -1,30 +0,0 @@
-local config = {
- [37572] = CONST_ME_GAZHARAGOTH, -- vessel of Gaz'haragoth
- [37573] = CONST_ME_FERUMBRAS_1, -- vessel of Ferumbras
- [37574] = CONST_ME_MAD_MAGE, -- vessel of the Mad Mage
- [37575] = CONST_ME_HORESTIS, -- vessel of Horestis
- [37576] = CONST_ME_DEVOVORGA, -- vessel of Devovorga
-}
-
-local vessels = Action()
-
-function vessels.onUse(player, item, fromPosition, itemEx, toPosition)
- local vessel = config[item.itemid]
- local tile = toPosition:getTile()
- if not vessel or not player then
- return false
- end
- if not tile:isWalkable() then
- player:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
- else
- item:remove(1)
- toPosition:sendMagicEffect(vessel)
- end
- return true
-end
-
-for index, value in pairs(config) do
- vessels:id(index)
-end
-vessels:allowFarUse(true)
-vessels:register()
diff --git a/data-otservbr-global/scripts/actions/tools/amber_crusher.lua b/data-otservbr-global/scripts/actions/tools/amber_crusher.lua
deleted file mode 100644
index d9c3edc4ce8..00000000000
--- a/data-otservbr-global/scripts/actions/tools/amber_crusher.lua
+++ /dev/null
@@ -1,31 +0,0 @@
-local amberCrusher = Action()
-
-function amberCrusher.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if not target or not target:isItem() or target:getId() == item:getId() or player:getItemCount(target:getId()) <= 0 then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the crusher on a valid gem in your inventory.")
- return false
- end
-
- local fragmentType, fragmentRange = getGemData(target:getId())
- if not fragmentType then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This item can't be broken into fragments.")
- return false
- end
-
- if target:getCount() >= MAX_GEM_BREAK then
- target:remove(MAX_GEM_BREAK)
- for i = 1, MAX_GEM_BREAK, 1 do
- player:addItem(fragmentType, math.random(fragmentRange[1], fragmentRange[2]))
- end
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have broken the gems into fragments.")
- else
- target:remove(1)
- player:addItem(fragmentType, math.random(fragmentRange[1], fragmentRange[2]))
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have broken the gem into fragments.")
- end
-
- return true
-end
-
-amberCrusher:id(46628)
-amberCrusher:register()
diff --git a/data-otservbr-global/scripts/actions/tools/crusher.lua b/data-otservbr-global/scripts/actions/tools/crusher.lua
deleted file mode 100644
index 8daa9f2771b..00000000000
--- a/data-otservbr-global/scripts/actions/tools/crusher.lua
+++ /dev/null
@@ -1,42 +0,0 @@
-local crusher = Action()
-
-function crusher.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if not target or not target:isItem() or target:getId() == item:getId() or player:getItemCount(target:getId()) <= 0 then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the crusher on a valid gem in your inventory.")
- return false
- end
-
- local fragmentType, fragmentRange = getGemData(target:getId())
- if not fragmentType then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This item can't be broken into fragments.")
- return false
- end
-
- local crusherCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
- if not crusherCharges or crusherCharges <= 0 then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your crusher has no more charges.")
- return false
- end
-
- target:remove(1)
-
- player:addItem(fragmentType, math.random(fragmentRange[1], fragmentRange[2]))
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have broken the gem into fragments.")
-
- crusherCharges = crusherCharges - 1
- if crusherCharges > 0 then
- local container = item:getParent()
- item:setAttribute(ITEM_ATTRIBUTE_CHARGES, crusherCharges)
- if container:isContainer() then
- player:sendUpdateContainer(container)
- end
- else
- item:remove()
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your crusher has been consumed.")
- end
-
- return true
-end
-
-crusher:id(46627)
-crusher:register()
diff --git a/data-otservbr-global/scripts/creaturescripts/customs/freequests.lua b/data-otservbr-global/scripts/creaturescripts/customs/freequests.lua
index 1cbca17c563..bfeac7acad0 100644
--- a/data-otservbr-global/scripts/creaturescripts/customs/freequests.lua
+++ b/data-otservbr-global/scripts/creaturescripts/customs/freequests.lua
@@ -1,392 +1,354 @@
local stage = configManager.getNumber(configKeys.FREE_QUEST_STAGE)
local questTable = {
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 2 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 4 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 7 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 9 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 12 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.Shooting, storageValue = 5 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 16 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 20 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 23 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.QuestLineComplete, storageValue = 2 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.Rank, storageValue = 1440 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.Warzone1Access, storageValue = 2 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.Warzone2Access, storageValue = 2 },
- { storage = Storage.Quest.U9_60.BigfootsBurden.Warzone3Access, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Questline, storageValue = 10 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneVI, storageValue = 10 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneV, storageValue = 10 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneIV, storageValue = 30 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Points, storageValue = 10 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Points, storageValue = 10 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Points, storageValue = 10 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Questline, storageValue = 51 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission01, storageValue = 6 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission02, storageValue = 8 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission03, storageValue = 6 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission04, storageValue = 6 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission05, storageValue = 8 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission06, storageValue = 5 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission07, storageValue = 5 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission08, storageValue = 4 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission09, storageValue = 2 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission10, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe01, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe02, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe03, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe04, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedDan, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedBill, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedFred, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.AlchemistFormula, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.BadSide, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.GoodSide, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.MrWestDoor, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.MrWestStatus, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.TamerinStatus, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.MorikSummon, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraState, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraSplasher, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraSharptooth, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraInky, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.MatrixState, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.NotesPalimuth, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.NotesAzerus, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToAzerus, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToBog, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToLastFight, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToMatrix, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToQuara, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Questline, storageValue = 7 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.JamesfrancisTask, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.BossTimer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone1, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone2, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone3, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Answer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.MotA.QuestionId, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.sulphur, storageValue = 4 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Tar, storageValue = 3 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Ice, storageValue = 3 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Objects, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Temp, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.LookType, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.BossTimer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Life.Mission, storageValue = 7 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Life.BossTimer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Vaporized, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Decaying, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Humans.BossTimer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Mission, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Monsters, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Exorcisms, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Time, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.BossTimer, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.EntranceAccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.AccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 1 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 4 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 7 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 16 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 26 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 29 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 32 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 35 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 38 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 41 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 43 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 46 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 47 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 50 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 55 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 56 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 58 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 61 },
- { storage = Storage.Quest.U7_6.ExplorerSociety.CalassaQuest, storageValue = 2 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.Tomes, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.LastLoreKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.TimeGuardianKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.DragonkingKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.ThornKnightKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.LloydKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.LadyTenebrisKilled, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessMachine, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessLavaTeleport, storageValue = 1 },
- { storage = Storage.Quest.U8_0.BarbarianTest.Questline, storageValue = 8 },
- { storage = Storage.Quest.U8_0.BarbarianTest.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U8_0.BarbarianTest.Mission02, storageValue = 3 },
- { storage = Storage.Quest.U8_0.BarbarianTest.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Questline, storageValue = 21 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission00, storageValue = 2 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission02, storageValue = 5 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission04, storageValue = 6 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission05, storageValue = 3 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding01, storageValue = 1 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding02, storageValue = 1 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding03, storageValue = 1 },
- { storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.StrangeSymbols, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.Faction.Greeting, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.Faction.MaridDoor, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.Faction.EfreetDoor, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Start, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission02, storageValue = 3 },
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Start, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission01, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission02, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.RataMari, storageValue = 2 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.TheWayToYalahar, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.TownsCounter, storageValue = 5 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.AbDendriel, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Darashia, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Venore, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Ankrahmun, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.PortHope, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Thais, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.LibertyBay, storageValue = 1 },
- { storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Carlin, storageValue = 1 },
- { storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.DefaultStart, storageValue = 1 },
- { storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.GoingDown, storageValue = 1 },
- { storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.WayToBeregar, storageValue = 1 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Questline, storageValue = 40 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission02, storageValue = 5 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission04, storageValue = 2 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission05, storageValue = 6 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission06, storageValue = 8 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission07, storageValue = 3 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission08, storageValue = 4 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission09, storageValue = 2 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission10, storageValue = 2 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission11, storageValue = 2 },
- { storage = Storage.Quest.U8_0.TheIceIslands.Mission12, storageValue = 6 },
- { storage = Storage.Quest.U8_0.TheIceIslands.yakchalDoor, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Questline, storageValue = 25 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission01, storageValue = 7 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission02, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission03, storageValue = 6 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission04, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission05, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission06, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission07, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.GrofGuard, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.KulagGuard, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.TimGuard, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.WalterGuard, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheInquisitionQuest.StorkusVampiredust, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Questline, storageValue = 29 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission02[1], storageValue = 4 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission04, storageValue = 2 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05[1], storageValue = 2 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission06, storageValue = 5 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission07[1], storageValue = 2 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission08, storageValue = 2 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission09[1], storageValue = 3 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission10[1], storageValue = 2 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission10.MagicCarpetDoor, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.TomeofKnowledge, storageValue = 12 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver1, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver2, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver3, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.KingTibianus, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Leeland, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Angus, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Wyrdin, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Telas, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Humgolf, storageValue = 1 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.DefaultStart, storageValue = 3 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.TheGovernorDaughter, storageValue = 3 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.TheErrand, storageValue = 2 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToMeriana, storageValue = 1 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.APoemForTheMermaid, storageValue = 3 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.ADjinnInLove, storageValue = 5 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToLagunaIsland, storageValue = 1 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToGoroma, storageValue = 1 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.Shipwrecked, storageValue = 2 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.DragahsSpellbook, storageValue = 1 },
- { storage = Storage.Quest.U7_8.TheShatteredIsles.TheCounterspell, storageValue = 4 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Questline, storageValue = 1 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission01, storageValue = 2 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission02, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission04, storageValue = 8 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission05, storageValue = 2 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission06, storageValue = 4 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission07, storageValue = 2 },
- { storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission08, storageValue = 1 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission01, storageValue = 1 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission01, storageValue = 2 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission02, storageValue = 5 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission04, storageValue = 3 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission05, storageValue = 3 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission06, storageValue = 2 },
- { storage = Storage.Quest.U8_1.TheTravellingTrader.Mission07, storageValue = 1 },
- { storage = Storage.Quest.U8_0.BarbarianArena.QuestLogGreenhorn, storageValue = 1 },
- { storage = Storage.Quest.U8_1.TibiaTales.DefaultStart, storageValue = 1 },
- { storage = Storage.Quest.U8_1.TibiaTales.ToAppeaseTheMightyQuest, storageValue = 1 },
- { storage = 12450, storageValue = 6 },
- { storage = 12330, storageValue = 1 },
- { storage = 12332, storageValue = 13 },
- { storage = 12333, storageValue = 3 },
- { storage = Storage.Quest.U7_8.FriendsAndTraders.DefaultStart, storageValue = 1 },
- { storage = Storage.Quest.U7_8.FriendsAndTraders.TheSweatyCyclops, storageValue = 2 },
- { storage = Storage.Quest.U7_8.FriendsAndTraders.TheMermaidMarina, storageValue = 2 },
- { storage = Storage.Quest.U7_8.FriendsAndTraders.TheBlessedStake, storageValue = 12 },
- { storage = 100157, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Questline, storageValue = 29 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission01, storageValue = 3 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission02, storageValue = 3 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission03, storageValue = 3 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission04, storageValue = 3 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission05, storageValue = 3 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission06, storageValue = 4 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission07, storageValue = 6 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission08, storageValue = 2 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission09, storageValue = 2 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission10, storageValue = 1 },
- { storage = Storage.Quest.U7_6.TheApeCity.Started, storageValue = 1 },
- { storage = Storage.Quest.U7_6.TheApeCity.Questline, storageValue = 18 },
- { storage = Storage.BanutaSecretTunnel.DeeperBanutaShortcut, storageValue = 1 },
- { storage = Storage.Quest.U10_50.OramondQuest.QuestLine, storageValue = 1 },
- { storage = Storage.Quest.U10_50.OramondQuest.ToTakeRoots.Mission, storageValue = 3000 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Questline, storageValue = 1 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Home, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Subterranean, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Measurements, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Ordnance, storageValue = 3 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Charting, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Growth, storageValue = 2 },
- { storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Diremaw, storageValue = 2 },
- { storage = Storage.Quest.U11_40.ThreatenedDreams.QuestLine, storageValue = 1 },
- { storage = Storage.Quest.U11_40.ThreatenedDreams.Mission01[1], storageValue = 16 },
- { storage = Storage.Quest.U11_40.ThreatenedDreams.Mission02.KroazurAccess, storageValue = 1 },
- { storage = Storage.Quest.U9_80.AdventurersGuild.QuestLine, storageValue = 1 },
- { storage = Storage.Quest.U10_80.TheGreatDragonHunt.WarriorSkeleton, storageValue = 1 },
- { storage = Storage.Quest.U10_80.TheGreatDragonHunt.WarriorSkeleton, storageValue = 2 },
- { storage = Storage.Quest.U10_80.TheLostBrotherQuest, storageValue = 3 },
- { storage = Storage.Quest.U10_55.Dawnport.Questline, storageValue = 1 },
- { storage = Storage.Quest.U10_55.Dawnport.GoMain, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessDeath, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessViolet, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessEarth, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessFire, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessIce, storageValue = 1 },
- { storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessGolden, storageValue = 1 },
- { storage = Storage.Quest.U10_80.GrimvaleQuest.AncientFeudDoors, storageValue = 1 },
- { storage = Storage.Quest.U10_80.GrimvaleQuest.AncientFeudShortcut, storageValue = 1 },
- { storage = Storage.Kilmaresh.AccessDoor, storageValue = 1 },
- { storage = Storage.Kilmaresh.CatacombDoors, storageValue = 1 },
- { storage = Storage.Quest.U12_00.TheDreamCourts.AccessDoors, storageValue = 1 },
- { storage = Storage.Quest.U12_00.TheDreamCourts.HauntedHouseAccess, storageValue = 1 },
- { storage = Storage.Quest.U12_00.TheDreamCourts.BuriedCathedralAccess, storageValue = 1 },
- { storage = Storage.Quest.U12_00.TheDreamCourts.DreamScarAccess, storageValue = 1 },
- { storage = Storage.Quest.U12_40.TheOrderOfTheLion.AccessEastSide, storageValue = 1 },
- { storage = Storage.Quest.U12_40.TheOrderOfTheLion.AccessSouthernSide, storageValue = 1 },
- { storage = Storage.Quest.U12_60.APiratesTail.TentuglyDoor, storageValue = 1 },
- { storage = Storage.Quest.U12_60.APiratesTail.RascacoonShortcut, storageValue = 1 },
- { storage = Storage.Quest.U12_70.AdventuresOfGalthen.AccessDoor, storageValue = 1 },
-
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.AccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.TrialAccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.TarAccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.BossAccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Life.AccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.AccessDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_40.CultsOfTibia.FinalBoss.AccessDoor, storageValue = 1 },
-
- { storage = Storage.Quest.U10_90.FerumbrasAscension.FirstDoor, storageValue = 1 },
- { storage = Storage.Quest.U10_90.FerumbrasAscension.MonsterDoor, storageValue = 1 },
- { storage = Storage.Quest.U10_90.FerumbrasAscension.TarbazDoor, storageValue = 1 },
- { storage = Storage.Quest.U10_90.FerumbrasAscension.HabitatsAccess, storageValue = 1 },
- { storage = Storage.Quest.U10_90.FerumbrasAscension.TheLordOfTheLiceAccess, storageValue = 1 },
- { storage = Storage.Quest.U10_90.FerumbrasAscension.Statue, storageValue = 1 },
-
- { storage = Storage.Quest.U12_00.TheDreamCourts.AndrewDoor, storageValue = 1 },
-
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.AwarnessEmperor, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.BossRoom, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.InnerSanctum, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Rebel, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.SleepingDragon, storageValue = 2 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Wote10, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Zizzle, storageValue = 1 },
- { storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Zlak, storageValue = 1 },
-
- --[[ { storage = Storage.Quest.U11_80.TheSecretLibrary.FalconBastionAccess, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.LowerBastionAccess, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.UndergroundBastionAccess, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.ShortcutToBastion, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.OberonAccess, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MotaDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.BasinDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.SkullDoor, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.Mota, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MiniBosses.PreceptorLazare, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MiniBosses.GrandCanonDominus, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MiniBosses.GrandChaplainGaunder, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MiniBosses.GrandCommanderSoeren, storageValue = 1 },
- { storage = Storage.Quest.U11_80.TheSecretLibrary.MiniBosses.DazedLeafGolem, storageValue = 1 }, ]]
-
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.DoorToLamp, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.DoorToMaridTerritory, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.DoorToLamp, storageValue = 1 },
- { storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.DoorToEfreetTerritory, storageValue = 1 },
-
- { storage = Storage.Quest.U12_20.GraveDanger.QuestLine, storageValue = 14 },
- { storage = Storage.Quest.U12_20.GraveDanger.Bosses.KingZelosDoor, storageValue = 1 },
-
- { storage = Storage.Quest.U13_10.CradleOfMonsters.Access.Ingol, storageValue = 1 },
- { storage = Storage.Quest.U13_10.CradleOfMonsters.Access.LowerIngol, storageValue = 1 },
- { storage = Storage.Quest.U13_10.CradleOfMonsters.Access.Monster, storageValue = 1 },
- { storage = Storage.Quest.U13_10.CradleOfMonsters.Access.MutatedAbomination, storageValue = 1 },
- { storage = Storage.Quest.U8_54.TheNewFrontier.SnakeHeadTeleport, storageValue = 1 },
- { storage = Storage.Quest.U9_4.LiquidBlackQuest.Visitor, storageValue = 5 },
- { storage = Storage.Quest.U8_4.BloodBrothers.VengothAccess, storageValue = 1 },
-
- -- Assassin Outfit quests
- { storage = Storage.Quest.U8_5.KillingInTheNameOf.BudrikMinos, storageValue = 0 },
- { storage = Storage.Quest.U8_1.ToOutfoxAFoxQuest.Questline, storageValue = 2 },
-
- -- Hunter Outfit quests
- { storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet01, storageValue = 1 },
- { storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet02, storageValue = 1 },
- { storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet03, storageValue = 1 },
- { storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet04, storageValue = 1 },
-
- -- Norseman
- { storage = Storage.Quest.U8_0.TheIceIslands.NorsemanOutfit, storageValue = 1 },
- { storage = Storage.OutfitQuest.DefaultStart, storageValue = 1 },
-
- { storage = Storage.HeroRathleton.AccessDoor, storageValue = 1 },
- { storage = Storage.HeroRathleton.AccessTeleport1, storageValue = 1 },
- { storage = Storage.HeroRathleton.AccessTeleport2, storageValue = 1 },
- { storage = Storage.HeroRathleton.AccessTeleport3, storageValue = 1 },
-
- -- Sea Serpent Quest
- { storage = Storage.Quest.U8_2.TheHuntForTheSeaSerpent.FishForASerpent, storageValue = 5 },
- { storage = Storage.Quest.U8_2.TheHuntForTheSeaSerpent.QuestLine, storageValue = 2 },
-
- --The White Raven Monastery
- { storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.QuestLog, storageValue = 1 },
- { storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Passage, storageValue = 1 },
- { storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Diary, storageValue = 2 },
- { storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Door, storageValue = 1 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 2 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 4 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 7 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 9 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 12 },
+ { storageName = "BigfootsBurden.Shooting", storage = Storage.Quest.U9_60.BigfootsBurden.Shooting, storageValue = 5 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 16 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 20 },
+ { storageName = "BigfootsBurden.QuestLine", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLine, storageValue = 23 },
+ { storageName = "BigfootsBurden.QuestLineComplete", storage = Storage.Quest.U9_60.BigfootsBurden.QuestLineComplete, storageValue = 2 },
+ { storageName = "BigfootsBurden.Rank", storage = Storage.Quest.U9_60.BigfootsBurden.Rank, storageValue = 1440 },
+ { storageName = "BigfootsBurden.Warzone1Access", storage = Storage.Quest.U9_60.BigfootsBurden.Warzone1Access, storageValue = 2 },
+ { storageName = "BigfootsBurden.Warzone2Access", storage = Storage.Quest.U9_60.BigfootsBurden.Warzone2Access, storageValue = 2 },
+ { storageName = "BigfootsBurden.Warzone3Access", storage = Storage.Quest.U9_60.BigfootsBurden.Warzone3Access, storageValue = 2 },
+ { storageName = "DangerousDepths.Questline", storage = Storage.Quest.U11_50.DangerousDepths.Questline, storageValue = 10 },
+ { storageName = "DangerousDepths.Access.LavaPumpWarzoneVI", storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneVI, storageValue = 10 },
+ { storageName = "DangerousDepths.Access.LavaPumpWarzoneV", storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneV, storageValue = 10 },
+ { storageName = "DangerousDepths.Access.LavaPumpWarzoneIV", storage = Storage.Quest.U11_50.DangerousDepths.Access.LavaPumpWarzoneIV, storageValue = 30 },
+ { storageName = "DangerousDepths.Dwarves.Points", storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Points, storageValue = 10 },
+ { storageName = "DangerousDepths.Scouts.Points", storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Points, storageValue = 10 },
+ { storageName = "DangerousDepths.Gnomes.Points", storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Points, storageValue = 10 },
+ { storageName = "InServiceOfYalahar.Questline", storage = Storage.Quest.U8_4.InServiceOfYalahar.Questline, storageValue = 51 },
+ { storageName = "InServiceOfYalahar.Mission01", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission01, storageValue = 6 },
+ { storageName = "InServiceOfYalahar.Mission02", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission02, storageValue = 8 },
+ { storageName = "InServiceOfYalahar.Mission03", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission03, storageValue = 6 },
+ { storageName = "InServiceOfYalahar.Mission04", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission04, storageValue = 6 },
+ { storageName = "InServiceOfYalahar.Mission05", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission05, storageValue = 8 },
+ { storageName = "InServiceOfYalahar.Mission06", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission06, storageValue = 5 },
+ { storageName = "InServiceOfYalahar.Mission07", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission07, storageValue = 5 },
+ { storageName = "InServiceOfYalahar.Mission08", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission08, storageValue = 4 },
+ { storageName = "InServiceOfYalahar.Mission09", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission09, storageValue = 2 },
+ { storageName = "InServiceOfYalahar.Mission10", storage = Storage.Quest.U8_4.InServiceOfYalahar.Mission10, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SewerPipe01", storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe01, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SewerPipe02", storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe02, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SewerPipe03", storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe03, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SewerPipe04", storage = Storage.Quest.U8_4.InServiceOfYalahar.SewerPipe04, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DiseasedDan", storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedDan, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DiseasedBill", storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedBill, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DiseasedFred", storage = Storage.Quest.U8_4.InServiceOfYalahar.DiseasedFred, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.AlchemistFormula", storage = Storage.Quest.U8_4.InServiceOfYalahar.AlchemistFormula, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.BadSide", storage = Storage.Quest.U8_4.InServiceOfYalahar.BadSide, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.GoodSide", storage = Storage.Quest.U8_4.InServiceOfYalahar.GoodSide, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.MrWestDoor", storage = Storage.Quest.U8_4.InServiceOfYalahar.MrWestDoor, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.MrWestStatus", storage = Storage.Quest.U8_4.InServiceOfYalahar.MrWestStatus, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.TamerinStatus", storage = Storage.Quest.U8_4.InServiceOfYalahar.TamerinStatus, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.MorikSummon", storage = Storage.Quest.U8_4.InServiceOfYalahar.MorikSummon, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.QuaraState", storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraState, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.QuaraSplasher", storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraSplasher, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.QuaraSharptooth", storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraSharptooth, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.QuaraInky", storage = Storage.Quest.U8_4.InServiceOfYalahar.QuaraInky, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.MatrixState", storage = Storage.Quest.U8_4.InServiceOfYalahar.MatrixState, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.NotesPalimuth", storage = Storage.Quest.U8_4.InServiceOfYalahar.NotesPalimuth, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.NotesAzerus", storage = Storage.Quest.U8_4.InServiceOfYalahar.NotesAzerus, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DoorToAzerus", storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToAzerus, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DoorToBog", storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToBog, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DoorToLastFight", storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToLastFight, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DoorToMatrix", storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToMatrix, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.DoorToQuara", storage = Storage.Quest.U8_4.InServiceOfYalahar.DoorToQuara, storageValue = 1 },
+ { storageName = "CultsOfTibia.Questline", storage = Storage.Quest.U11_40.CultsOfTibia.Questline, storageValue = 7 },
+ { storageName = "CultsOfTibia.Minotaurs.JamesfrancisTask", storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.JamesfrancisTask, storageValue = 1 },
+ { storageName = "CultsOfTibia.Minotaurs.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.Minotaurs.BossTimer", storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.BossTimer, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.Stone1", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone1, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.Stone2", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone2, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.Stone3", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Stone3, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.Answer", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.Answer, storageValue = 1 },
+ { storageName = "CultsOfTibia.MotA.QuestionId", storage = Storage.Quest.U11_40.CultsOfTibia.MotA.QuestionId, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.Sulphur", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Sulphur, storageValue = 4 },
+ { storageName = "CultsOfTibia.Barkless.Tar", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Tar, storageValue = 3 },
+ { storageName = "CultsOfTibia.Barkless.Ice", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Ice, storageValue = 3 },
+ { storageName = "CultsOfTibia.Barkless.Objects", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Objects, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.Temp", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.Temp, storageValue = 1 },
+ { storageName = "CultsOfTibia.Orcs.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.Orcs.LookType", storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.LookType, storageValue = 1 },
+ { storageName = "CultsOfTibia.Orcs.BossTimer", storage = Storage.Quest.U11_40.CultsOfTibia.Orcs.BossTimer, storageValue = 1 },
+ { storageName = "CultsOfTibia.Life.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Life.Mission, storageValue = 7 },
+ { storageName = "CultsOfTibia.Life.BossTimer", storage = Storage.Quest.U11_40.CultsOfTibia.Life.BossTimer, storageValue = 1 },
+ { storageName = "CultsOfTibia.Humans.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.Humans.Vaporized", storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Vaporized, storageValue = 1 },
+ { storageName = "CultsOfTibia.Humans.Decaying", storage = Storage.Quest.U11_40.CultsOfTibia.Humans.Decaying, storageValue = 1 },
+ { storageName = "CultsOfTibia.Humans.BossTimer", storage = Storage.Quest.U11_40.CultsOfTibia.Humans.BossTimer, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.Mission", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Mission, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.Monsters", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Monsters, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.Exorcisms", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Exorcisms, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.Time", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.Time, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.BossTimer", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.BossTimer, storageValue = 1 },
+ { storageName = "CultsOfTibia.Minotaurs.BossAccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.BossAccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Minotaurs.AccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Minotaurs.AccessDoor, storageValue = 1 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 1 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 4 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 7 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 16 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 26 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 29 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 32 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 35 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 38 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 41 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 43 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 46 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 47 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 50 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 55 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 56 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 58 },
+ { storageName = "ExplorerSociety.QuestLine", storage = Storage.Quest.U7_6.ExplorerSociety.QuestLine, storageValue = 61 },
+ { storageName = "ExplorerSociety.CalassaQuest", storage = Storage.Quest.U7_6.ExplorerSociety.CalassaQuest, storageValue = 2 },
+ { storageName = "ForgottenKnowledge.Tomes", storage = Storage.Quest.U11_02.ForgottenKnowledge.Tomes, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.LastLoreKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.LastLoreKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.TimeGuardianKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.TimeGuardianKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.HorrorKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.DragonkingKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.DragonkingKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.ThornKnightKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.ThornKnightKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.LloydKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.LloydKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.LadyTenebrisKilled", storage = Storage.Quest.U11_02.ForgottenKnowledge.LadyTenebrisKilled, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessMachine", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessMachine, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessLavaTeleport", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessLavaTeleport, storageValue = 1 },
+ { storageName = "BarbarianTest.Questline", storage = Storage.Quest.U8_0.BarbarianTest.Questline, storageValue = 8 },
+ { storageName = "BarbarianTest.Mission01", storage = Storage.Quest.U8_0.BarbarianTest.Mission01, storageValue = 3 },
+ { storageName = "BarbarianTest.Mission02", storage = Storage.Quest.U8_0.BarbarianTest.Mission02, storageValue = 3 },
+ { storageName = "BarbarianTest.Mission03", storage = Storage.Quest.U8_0.BarbarianTest.Mission03, storageValue = 3 },
+ { storageName = "ChildrenOfTheRevolution.Questline", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Questline, storageValue = 21 },
+ { storageName = "ChildrenOfTheRevolution.Mission00", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission00, storageValue = 2 },
+ { storageName = "ChildrenOfTheRevolution.Mission01", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission01, storageValue = 3 },
+ { storageName = "ChildrenOfTheRevolution.Mission02", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission02, storageValue = 5 },
+ { storageName = "ChildrenOfTheRevolution.Mission03", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission03, storageValue = 3 },
+ { storageName = "ChildrenOfTheRevolution.Mission04", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission04, storageValue = 6 },
+ { storageName = "ChildrenOfTheRevolution.Mission05", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.Mission05, storageValue = 3 },
+ { storageName = "ChildrenOfTheRevolution.SpyBuilding01", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding01, storageValue = 1 },
+ { storageName = "ChildrenOfTheRevolution.SpyBuilding02", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding02, storageValue = 1 },
+ { storageName = "ChildrenOfTheRevolution.SpyBuilding03", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.SpyBuilding03, storageValue = 1 },
+ { storageName = "ChildrenOfTheRevolution.StrangeSymbols", storage = Storage.Quest.U8_54.ChildrenOfTheRevolution.StrangeSymbols, storageValue = 1 },
+ { storageName = "DjinnWar.Faction.Greeting", storage = Storage.Quest.U7_4.DjinnWar.Faction.Greeting, storageValue = 2 },
+ { storageName = "DjinnWar.Faction.MaridDoor", storage = Storage.Quest.U7_4.DjinnWar.Faction.MaridDoor, storageValue = 2 },
+ { storageName = "DjinnWar.Faction.EfreetDoor", storage = Storage.Quest.U7_4.DjinnWar.Faction.EfreetDoor, storageValue = 2 },
+ { storageName = "DjinnWar.EfreetFaction.Start", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Start, storageValue = 1 },
+ { storageName = "DjinnWar.EfreetFaction.Mission01", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission01, storageValue = 3 },
+ { storageName = "DjinnWar.EfreetFaction.Mission02", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission02, storageValue = 3 },
+ { storageName = "DjinnWar.EfreetFaction.Mission03", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.Mission03, storageValue = 3 },
+ { storageName = "DjinnWar.MaridFaction.Start", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Start, storageValue = 1 },
+ { storageName = "DjinnWar.MaridFaction.Mission01", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission01, storageValue = 2 },
+ { storageName = "DjinnWar.MaridFaction.Mission02", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission02, storageValue = 2 },
+ { storageName = "DjinnWar.MaridFaction.RataMari", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.RataMari, storageValue = 2 },
+ { storageName = "DjinnWar.MaridFaction.Mission03", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.Mission03, storageValue = 3 },
+ { storageName = "InServiceOfYalahar.TheWayToYalahar", storage = Storage.Quest.U8_4.InServiceOfYalahar.TheWayToYalahar, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.TownsCounter", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.TownsCounter, storageValue = 5 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.AbDendriel", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.AbDendriel, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.Darashia", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Darashia, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.Venore", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Venore, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.Ankrahmun", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Ankrahmun, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.PortHope", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.PortHope, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.Thais", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Thais, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.LibertyBay", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.LibertyBay, storageValue = 1 },
+ { storageName = "InServiceOfYalahar.SearoutesAroundYalahar.Carlin", storage = Storage.Quest.U8_4.InServiceOfYalahar.SearoutesAroundYalahar.Carlin, storageValue = 1 },
+ { storageName = "TheHiddenCityOfBeregar.DefaultStart", storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.DefaultStart, storageValue = 1 },
+ { storageName = "TheHiddenCityOfBeregar.GoingDown", storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.GoingDown, storageValue = 1 },
+ { storageName = "TheHiddenCityOfBeregar.WayToBeregar", storage = Storage.Quest.U8_4.TheHiddenCityOfBeregar.WayToBeregar, storageValue = 1 },
+ { storageName = "TheIceIslands.Questline", storage = Storage.Quest.U8_0.TheIceIslands.Questline, storageValue = 40 },
+ { storageName = "TheIceIslands.Mission01", storage = Storage.Quest.U8_0.TheIceIslands.Mission01, storageValue = 3 },
+ { storageName = "TheIceIslands.Mission02", storage = Storage.Quest.U8_0.TheIceIslands.Mission02, storageValue = 5 },
+ { storageName = "TheIceIslands.Mission03", storage = Storage.Quest.U8_0.TheIceIslands.Mission03, storageValue = 3 },
+ { storageName = "TheIceIslands.Mission04", storage = Storage.Quest.U8_0.TheIceIslands.Mission04, storageValue = 2 },
+ { storageName = "TheIceIslands.Mission05", storage = Storage.Quest.U8_0.TheIceIslands.Mission05, storageValue = 6 },
+ { storageName = "TheIceIslands.Mission06", storage = Storage.Quest.U8_0.TheIceIslands.Mission06, storageValue = 8 },
+ { storageName = "TheIceIslands.Mission07", storage = Storage.Quest.U8_0.TheIceIslands.Mission07, storageValue = 3 },
+ { storageName = "TheIceIslands.Mission08", storage = Storage.Quest.U8_0.TheIceIslands.Mission08, storageValue = 4 },
+ { storageName = "TheIceIslands.Mission09", storage = Storage.Quest.U8_0.TheIceIslands.Mission09, storageValue = 2 },
+ { storageName = "TheIceIslands.Mission10", storage = Storage.Quest.U8_0.TheIceIslands.Mission10, storageValue = 2 },
+ { storageName = "TheIceIslands.Mission11", storage = Storage.Quest.U8_0.TheIceIslands.Mission11, storageValue = 2 },
+ { storageName = "TheIceIslands.Mission12", storage = Storage.Quest.U8_0.TheIceIslands.Mission12, storageValue = 6 },
+ { storageName = "TheIceIslands.yakchalDoor", storage = Storage.Quest.U8_0.TheIceIslands.yakchalDoor, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.Questline", storage = Storage.Quest.U8_2.TheInquisitionQuest.Questline, storageValue = 25 },
+ { storageName = "TheInquisitionQuest.Mission01", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission01, storageValue = 7 },
+ { storageName = "TheInquisitionQuest.Mission02", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission02, storageValue = 3 },
+ { storageName = "TheInquisitionQuest.Mission03", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission03, storageValue = 6 },
+ { storageName = "TheInquisitionQuest.Mission04", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission04, storageValue = 3 },
+ { storageName = "TheInquisitionQuest.Mission05", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission05, storageValue = 3 },
+ { storageName = "TheInquisitionQuest.Mission06", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission06, storageValue = 3 },
+ { storageName = "TheInquisitionQuest.Mission07", storage = Storage.Quest.U8_2.TheInquisitionQuest.Mission07, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.GrofGuard", storage = Storage.Quest.U8_2.TheInquisitionQuest.GrofGuard, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.KulagGuard", storage = Storage.Quest.U8_2.TheInquisitionQuest.KulagGuard, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.TimGuard", storage = Storage.Quest.U8_2.TheInquisitionQuest.TimGuard, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.WalterGuard", storage = Storage.Quest.U8_2.TheInquisitionQuest.WalterGuard, storageValue = 1 },
+ { storageName = "TheInquisitionQuest.StorkusVampiredust", storage = Storage.Quest.U8_2.TheInquisitionQuest.StorkusVampiredust, storageValue = 1 },
+ { storageName = "TheNewFrontier.Questline", storage = Storage.Quest.U8_54.TheNewFrontier.Questline, storageValue = 29 },
+ { storageName = "TheNewFrontier.Mission01", storage = Storage.Quest.U8_54.TheNewFrontier.Mission01, storageValue = 3 },
+ { storageName = "TheNewFrontier.Mission02[1]", storage = Storage.Quest.U8_54.TheNewFrontier.Mission02[1], storageValue = 4 },
+ { storageName = "TheNewFrontier.Mission03", storage = Storage.Quest.U8_54.TheNewFrontier.Mission03, storageValue = 3 },
+ { storageName = "TheNewFrontier.Mission04", storage = Storage.Quest.U8_54.TheNewFrontier.Mission04, storageValue = 2 },
+ { storageName = "TheNewFrontier.Mission05[1]", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05[1], storageValue = 2 },
+ { storageName = "TheNewFrontier.Mission06", storage = Storage.Quest.U8_54.TheNewFrontier.Mission06, storageValue = 5 },
+ { storageName = "TheNewFrontier.Mission07[1]", storage = Storage.Quest.U8_54.TheNewFrontier.Mission07[1], storageValue = 2 },
+ { storageName = "TheNewFrontier.Mission08", storage = Storage.Quest.U8_54.TheNewFrontier.Mission08, storageValue = 2 },
+ { storageName = "TheNewFrontier.Mission09[1]", storage = Storage.Quest.U8_54.TheNewFrontier.Mission09[1], storageValue = 3 },
+ { storageName = "TheNewFrontier.Mission10[1]", storage = Storage.Quest.U8_54.TheNewFrontier.Mission10[1], storageValue = 2 },
+ { storageName = "TheNewFrontier.Mission10.MagicCarpetDoor", storage = Storage.Quest.U8_54.TheNewFrontier.Mission10.MagicCarpetDoor, storageValue = 1 },
+ { storageName = "TheNewFrontier.TomeofKnowledge", storage = Storage.Quest.U8_54.TheNewFrontier.TomeofKnowledge, storageValue = 12 },
+ { storageName = "TheNewFrontier.Mission02.Beaver1", storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver1, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission02.Beaver2", storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver2, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission02.Beaver3", storage = Storage.Quest.U8_54.TheNewFrontier.Mission02.Beaver3, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.KingTibianus", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.KingTibianus, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.Leeland", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Leeland, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.Angus", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Angus, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.Wyrdin", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Wyrdin, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.Telas", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Telas, storageValue = 1 },
+ { storageName = "TheNewFrontier.Mission05.Humgolf", storage = Storage.Quest.U8_54.TheNewFrontier.Mission05.Humgolf, storageValue = 1 },
+ { storageName = "TheShatteredIsles.DefaultStart", storage = Storage.Quest.U7_8.TheShatteredIsles.DefaultStart, storageValue = 3 },
+ { storageName = "TheShatteredIsles.TheGovernorDaughter", storage = Storage.Quest.U7_8.TheShatteredIsles.TheGovernorDaughter, storageValue = 3 },
+ { storageName = "TheShatteredIsles.TheErrand", storage = Storage.Quest.U7_8.TheShatteredIsles.TheErrand, storageValue = 2 },
+ { storageName = "TheShatteredIsles.AccessToMeriana", storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToMeriana, storageValue = 1 },
+ { storageName = "TheShatteredIsles.APoemForTheMermaid", storage = Storage.Quest.U7_8.TheShatteredIsles.APoemForTheMermaid, storageValue = 3 },
+ { storageName = "TheShatteredIsles.ADjinnInLove", storage = Storage.Quest.U7_8.TheShatteredIsles.ADjinnInLove, storageValue = 5 },
+ { storageName = "TheShatteredIsles.AccessToLagunaIsland", storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToLagunaIsland, storageValue = 1 },
+ { storageName = "TheShatteredIsles.AccessToGoroma", storage = Storage.Quest.U7_8.TheShatteredIsles.AccessToGoroma, storageValue = 1 },
+ { storageName = "TheShatteredIsles.Shipwrecked", storage = Storage.Quest.U7_8.TheShatteredIsles.Shipwrecked, storageValue = 2 },
+ { storageName = "TheShatteredIsles.DragahsSpellbook", storage = Storage.Quest.U7_8.TheShatteredIsles.DragahsSpellbook, storageValue = 1 },
+ { storageName = "TheShatteredIsles.TheCounterspell", storage = Storage.Quest.U7_8.TheShatteredIsles.TheCounterspell, storageValue = 4 },
+ { storageName = "TheThievesGuildQuest.Questline", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Questline, storageValue = 1 },
+ { storageName = "TheThievesGuildQuest.Mission01", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission01, storageValue = 2 },
+ { storageName = "TheThievesGuildQuest.Mission02", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission02, storageValue = 3 },
+ { storageName = "TheThievesGuildQuest.Mission03", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission03, storageValue = 3 },
+ { storageName = "TheThievesGuildQuest.Mission04", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission04, storageValue = 8 },
+ { storageName = "TheThievesGuildQuest.Mission05", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission05, storageValue = 2 },
+ { storageName = "TheThievesGuildQuest.Mission06", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission06, storageValue = 4 },
+ { storageName = "TheThievesGuildQuest.Mission07", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission07, storageValue = 2 },
+ { storageName = "TheThievesGuildQuest.Mission08", storage = Storage.Quest.U8_2.TheThievesGuildQuest.Mission08, storageValue = 1 },
+ { storageName = "TheTravellingTrader.Mission01", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission01, storageValue = 1 },
+ { storageName = "TheTravellingTrader.Mission01_2", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission01, storageValue = 2 },
+ { storageName = "TheTravellingTrader.Mission02", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission02, storageValue = 5 },
+ { storageName = "TheTravellingTrader.Mission03", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission03, storageValue = 3 },
+ { storageName = "TheTravellingTrader.Mission04", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission04, storageValue = 3 },
+ { storageName = "TheTravellingTrader.Mission05", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission05, storageValue = 3 },
+ { storageName = "TheTravellingTrader.Mission06", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission06, storageValue = 2 },
+ { storageName = "TheTravellingTrader.Mission07", storage = Storage.Quest.U8_1.TheTravellingTrader.Mission07, storageValue = 1 },
+ { storageName = "BarbarianArena.QuestLogGreenhorn", storage = Storage.Quest.U8_0.BarbarianArena.QuestLogGreenhorn, storageValue = 1 },
+ { storageName = "TibiaTales.DefaultStart", storage = Storage.Quest.U8_1.TibiaTales.DefaultStart, storageValue = 1 },
+ { storageName = "TibiaTales.ToAppeaseTheMightyQuest", storage = Storage.Quest.U8_1.TibiaTales.ToAppeaseTheMightyQuest, storageValue = 1 },
+ { storageName = "12450", storage = 12450, storageValue = 6 },
+ { storageName = "12330", storage = 12330, storageValue = 1 },
+ { storageName = "12332", storage = 12332, storageValue = 13 },
+ { storageName = "12333", storage = 12333, storageValue = 3 },
+ { storageName = "FriendsAndTraders.DefaultStart", storage = Storage.Quest.U7_8.FriendsAndTraders.DefaultStart, storageValue = 1 },
+ { storageName = "FriendsAndTraders.TheSweatyCyclops", storage = Storage.Quest.U7_8.FriendsAndTraders.TheSweatyCyclops, storageValue = 2 },
+ { storageName = "FriendsAndTraders.TheMermaidMarina", storage = Storage.Quest.U7_8.FriendsAndTraders.TheMermaidMarina, storageValue = 2 },
+ { storageName = "FriendsAndTraders.TheBlessedStake", storage = Storage.Quest.U7_8.FriendsAndTraders.TheBlessedStake, storageValue = 12 },
+ { storageName = "100157", storage = 100157, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.Questline", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Questline, storageValue = 29 },
+ { storageName = "WrathOfTheEmperor.Mission01", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission01, storageValue = 3 },
+ { storageName = "WrathOfTheEmperor.Mission02", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission02, storageValue = 3 },
+ { storageName = "WrathOfTheEmperor.Mission03", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission03, storageValue = 3 },
+ { storageName = "WrathOfTheEmperor.Mission04", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission04, storageValue = 3 },
+ { storageName = "WrathOfTheEmperor.Mission05", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission05, storageValue = 3 },
+ { storageName = "WrathOfTheEmperor.Mission06", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission06, storageValue = 4 },
+ { storageName = "WrathOfTheEmperor.Mission07", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission07, storageValue = 6 },
+ { storageName = "WrathOfTheEmperor.Mission08", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission08, storageValue = 2 },
+ { storageName = "WrathOfTheEmperor.Mission09", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission09, storageValue = 2 },
+ { storageName = "WrathOfTheEmperor.Mission10", storage = Storage.Quest.U8_6.WrathOfTheEmperor.Mission10, storageValue = 1 },
+ { storageName = "TheApeCity.Started", storage = Storage.Quest.U7_6.TheApeCity.Started, storageValue = 1 },
+ { storageName = "TheApeCity.Questline", storage = Storage.Quest.U7_6.TheApeCity.Questline, storageValue = 18 },
+ { storageName = "BanutaSecretTunnel.DeeperBanutaShortcut", storage = Storage.BanutaSecretTunnel.DeeperBanutaShortcut, storageValue = 1 },
+ { storageName = "OramondQuest.QuestLine", storage = Storage.Quest.U10_50.OramondQuest.QuestLine, storageValue = 1 },
+ { storageName = "OramondQuest.ToTakeRoots.Mission", storage = Storage.Quest.U10_50.OramondQuest.ToTakeRoots.Mission, storageValue = 3000 },
+ { storageName = "DangerousDepths.Questline", storage = Storage.Quest.U11_50.DangerousDepths.Questline, storageValue = 1 },
+ { storageName = "DangerousDepths.Dwarves.Home", storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Home, storageValue = 2 },
+ { storageName = "DangerousDepths.Dwarves.Subterranean", storage = Storage.Quest.U11_50.DangerousDepths.Dwarves.Subterranean, storageValue = 2 },
+ { storageName = "DangerousDepths.Gnomes.Measurements", storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Measurements, storageValue = 2 },
+ { storageName = "DangerousDepths.Gnomes.Ordnance", storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Ordnance, storageValue = 3 },
+ { storageName = "DangerousDepths.Gnomes.Charting", storage = Storage.Quest.U11_50.DangerousDepths.Gnomes.Charting, storageValue = 2 },
+ { storageName = "DangerousDepths.Scouts.Growth", storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Growth, storageValue = 2 },
+ { storageName = "DangerousDepths.Scouts.Diremaw", storage = Storage.Quest.U11_50.DangerousDepths.Scouts.Diremaw, storageValue = 2 },
+ { storageName = "ThreatenedDreams.QuestLine", storage = Storage.Quest.U11_40.ThreatenedDreams.QuestLine, storageValue = 1 },
+ { storageName = "ThreatenedDreams.Mission01[1]", storage = Storage.Quest.U11_40.ThreatenedDreams.Mission01[1], storageValue = 16 },
+ { storageName = "ThreatenedDreams.Mission02.KroazurAccess", storage = Storage.Quest.U11_40.ThreatenedDreams.Mission02.KroazurAccess, storageValue = 1 },
+ { storageName = "AdventurersGuild.QuestLine", storage = Storage.Quest.U9_80.AdventurersGuild.QuestLine, storageValue = 1 },
+ { storageName = "TheGreatDragonHunt.WarriorSkeleton", storage = Storage.Quest.U10_80.TheGreatDragonHunt.WarriorSkeleton, storageValue = 1 },
+ { storageName = "TheGreatDragonHunt.WarriorSkeleton_2", storage = Storage.Quest.U10_80.TheGreatDragonHunt.WarriorSkeleton, storageValue = 2 },
+ { storageName = "TheLostBrotherQuest", storage = Storage.Quest.U10_80.TheLostBrotherQuest, storageValue = 3 },
+ { storageName = "Dawnport.Questline", storage = Storage.Quest.U10_55.Dawnport.Questline, storageValue = 1 },
+ { storageName = "Dawnport.GoMain", storage = Storage.Quest.U10_55.Dawnport.GoMain, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessDeath", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessDeath, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessViolet", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessViolet, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessEarth", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessEarth, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessFire", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessFire, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessIce", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessIce, storageValue = 1 },
+ { storageName = "ForgottenKnowledge.AccessGolden", storage = Storage.Quest.U11_02.ForgottenKnowledge.AccessGolden, storageValue = 1 },
+ { storageName = "GrimvaleQuest.AncientFeudDoors", storage = Storage.Quest.U10_80.GrimvaleQuest.AncientFeudDoors, storageValue = 1 },
+ { storageName = "GrimvaleQuest.AncientFeudShortcut", storage = Storage.Quest.U10_80.GrimvaleQuest.AncientFeudShortcut, storageValue = 1 },
+ { storageName = "Kilmaresh.AccessDoor", storage = Storage.Kilmaresh.AccessDoor, storageValue = 1 },
+ { storageName = "Kilmaresh.CatacombDoors", storage = Storage.Kilmaresh.CatacombDoors, storageValue = 1 },
+ { storageName = "TheOrderOfTheLion.AccessEastSide", storage = Storage.Quest.U12_40.TheOrderOfTheLion.AccessEastSide, storageValue = 1 },
+ { storageName = "TheOrderOfTheLion.AccessSouthernSide", storage = Storage.Quest.U12_40.TheOrderOfTheLion.AccessSouthernSide, storageValue = 1 },
+ { storageName = "APiratesTail.TentuglyDoor", storage = Storage.Quest.U12_60.APiratesTail.TentuglyDoor, storageValue = 1 },
+ { storageName = "APiratesTail.RascacoonShortcut", storage = Storage.Quest.U12_60.APiratesTail.RascacoonShortcut, storageValue = 1 },
+ { storageName = "AdventuresOfGalthen.AccessDoor", storage = Storage.Quest.U12_70.AdventuresOfGalthen.AccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.AccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.AccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.TrialAccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.TrialAccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.TarAccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.TarAccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Barkless.BossAccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Barkless.BossAccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Life.AccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Life.AccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.Misguided.AccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.Misguided.AccessDoor, storageValue = 1 },
+ { storageName = "CultsOfTibia.FinalBoss.AccessDoor", storage = Storage.Quest.U11_40.CultsOfTibia.FinalBoss.AccessDoor, storageValue = 1 },
+ { storageName = "FerumbrasAscension.FirstDoor", storage = Storage.Quest.U10_90.FerumbrasAscension.FirstDoor, storageValue = 1 },
+ { storageName = "FerumbrasAscension.MonsterDoor", storage = Storage.Quest.U10_90.FerumbrasAscension.MonsterDoor, storageValue = 1 },
+ { storageName = "FerumbrasAscension.TarbazDoor", storage = Storage.Quest.U10_90.FerumbrasAscension.TarbazDoor, storageValue = 1 },
+ { storageName = "FerumbrasAscension.HabitatsAccess", storage = Storage.Quest.U10_90.FerumbrasAscension.HabitatsAccess, storageValue = 1 },
+ { storageName = "FerumbrasAscension.TheLordOfTheLiceAccess", storage = Storage.Quest.U10_90.FerumbrasAscension.TheLordOfTheLiceAccess, storageValue = 1 },
+ { storageName = "FerumbrasAscension.Statue", storage = Storage.Quest.U10_90.FerumbrasAscension.Statue, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.AwarnessEmperor", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.AwarnessEmperor, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.BossRoom", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.BossRoom, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.InnerSanctum", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.InnerSanctum, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.Rebel", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Rebel, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.SleepingDragon", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.SleepingDragon, storageValue = 2 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.Wote10", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Wote10, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.Zizzle", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Zizzle, storageValue = 1 },
+ { storageName = "WrathOfTheEmperor.TeleportAccess.Zlak", storage = Storage.Quest.U8_6.WrathOfTheEmperor.TeleportAccess.Zlak, storageValue = 1 },
+ { storageName = "DjinnWar.EfreetFaction.DoorToLamp", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.DoorToLamp, storageValue = 1 },
+ { storageName = "DjinnWar.EfreetFaction.DoorToMaridTerritory", storage = Storage.Quest.U7_4.DjinnWar.EfreetFaction.DoorToMaridTerritory, storageValue = 1 },
+ { storageName = "DjinnWar.MaridFaction.DoorToLamp", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.DoorToLamp, storageValue = 1 },
+ { storageName = "DjinnWar.MaridFaction.DoorToEfreetTerritory", storage = Storage.Quest.U7_4.DjinnWar.MaridFaction.DoorToEfreetTerritory, storageValue = 1 },
+ { storageName = "GraveDanger.QuestLine", storage = Storage.Quest.U12_20.GraveDanger.QuestLine, storageValue = 14 },
+ { storageName = "GraveDanger.Bosses.KingZelosDoor", storage = Storage.Quest.U12_20.GraveDanger.Bosses.KingZelosDoor, storageValue = 1 },
+ { storageName = "CradleOfMonsters.Access.Ingol", storage = Storage.Quest.U13_10.CradleOfMonsters.Access.Ingol, storageValue = 1 },
+ { storageName = "CradleOfMonsters.Access.LowerIngol", storage = Storage.Quest.U13_10.CradleOfMonsters.Access.LowerIngol, storageValue = 1 },
+ { storageName = "CradleOfMonsters.Access.Monster", storage = Storage.Quest.U13_10.CradleOfMonsters.Access.Monster, storageValue = 1 },
+ { storageName = "CradleOfMonsters.Access.MutatedAbomination", storage = Storage.Quest.U13_10.CradleOfMonsters.Access.MutatedAbomination, storageValue = 1 },
+ { storageName = "TheNewFrontier.SnakeHeadTeleport", storage = Storage.Quest.U8_54.TheNewFrontier.SnakeHeadTeleport, storageValue = 1 },
+ { storageName = "LiquidBlackQuest.Visitor", storage = Storage.Quest.U9_4.LiquidBlackQuest.Visitor, storageValue = 5 },
+ { storageName = "BloodBrothers.VengothAccess", storage = Storage.Quest.U8_4.BloodBrothers.VengothAccess, storageValue = 1 },
+ { storageName = "KillingInTheNameOf.BudrikMinos", storage = Storage.Quest.U8_5.KillingInTheNameOf.BudrikMinos, storageValue = 0 },
+ { storageName = "ToOutfoxAFoxQuest.Questline", storage = Storage.Quest.U8_1.ToOutfoxAFoxQuest.Questline, storageValue = 2 },
+ { storageName = "HunterOutfits.HunterMusicSheet01", storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet01, storageValue = 1 },
+ { storageName = "HunterOutfits.HunterMusicSheet02", storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet02, storageValue = 1 },
+ { storageName = "HunterOutfits.HunterMusicSheet03", storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet03, storageValue = 1 },
+ { storageName = "HunterOutfits.HunterMusicSheet04", storage = Storage.Quest.U7_8.HunterOutfits.HunterMusicSheet04, storageValue = 1 },
+ { storageName = "TheIceIslands.NorsemanOutfit", storage = Storage.Quest.U8_0.TheIceIslands.NorsemanOutfit, storageValue = 1 },
+ { storageName = "OutfitQuest.DefaultStart", storage = Storage.OutfitQuest.DefaultStart, storageValue = 1 },
+ { storageName = "HeroRathleton.AccessDoor", storage = Storage.HeroRathleton.AccessDoor, storageValue = 1 },
+ { storageName = "HeroRathleton.AccessTeleport1", storage = Storage.HeroRathleton.AccessTeleport1, storageValue = 1 },
+ { storageName = "HeroRathleton.AccessTeleport2", storage = Storage.HeroRathleton.AccessTeleport2, storageValue = 1 },
+ { storageName = "HeroRathleton.AccessTeleport3", storage = Storage.HeroRathleton.AccessTeleport3, storageValue = 1 },
+ { storageName = "TheHuntForTheSeaSerpent.FishForASerpent", storage = Storage.Quest.U8_2.TheHuntForTheSeaSerpent.FishForASerpent, storageValue = 5 },
+ { storageName = "TheHuntForTheSeaSerpent.QuestLine", storage = Storage.Quest.U8_2.TheHuntForTheSeaSerpent.QuestLine, storageValue = 2 },
+ { storageName = "TheWhiteRavenMonastery.QuestLog", storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.QuestLog, storageValue = 1 },
+ { storageName = "TheWhiteRavenMonastery.Passage", storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Passage, storageValue = 1 },
+ { storageName = "TheWhiteRavenMonastery.Diary", storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Diary, storageValue = 2 },
+ { storageName = "TheWhiteRavenMonastery.Door", storage = Storage.Quest.U7_24.TheWhiteRavenMonastery.Door, storageValue = 1 },
}
-- from Position: (33201, 31762, 1)
@@ -405,8 +367,15 @@ local function playerFreeQuestStart(playerId, index)
return
end
- if player:getStorageValue(questTable[index].storage) ~= questTable[index].storageValue then
- player:setStorageValue(questTable[index].storage, questTable[index].storageValue)
+ local questData = questTable[index]
+ local currentStorageValue = player:getStorageValue(questData.storage)
+
+ if not questData.storage then
+ logger.warn("[Freequest System]: error storage for '" .. questData.storageName .. "' is nil for the index")
+ elseif currentStorageValue ~= questData.storageValue then
+ player:setStorageValue(questData.storage, questData.storageValue)
+ elseif currentStorageValue == -1 then
+ logger.warn("[Freequest System]: warning Storage '" .. questData.storageName .. "' currently nil for player ID " .. playerId)
end
end
diff --git a/data-otservbr-global/scripts/creaturescripts/others/#modal_window_example.lua b/data-otservbr-global/scripts/creaturescripts/others/#modal_window_example.lua
deleted file mode 100644
index e2de4a9e474..00000000000
--- a/data-otservbr-global/scripts/creaturescripts/others/#modal_window_example.lua
+++ /dev/null
@@ -1,63 +0,0 @@
---[[
- ModalWindowHelper Example
-]]
---
-
-local moveDirectionTest = {
- ["Right"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_EAST)
- player:teleportTo(pos, true)
- end,
- ["Left"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_WEST)
- player:teleportTo(pos, true)
- end,
- ["Up"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_NORTH)
- player:teleportTo(pos, true)
- end,
- ["Down"] = function(player)
- local pos = player:getPosition()
- pos:getNextPosition(DIRECTION_SOUTH)
- player:teleportTo(pos, true)
- end,
-}
-
-local talkAction = TalkAction("!modalTest")
-
-function talkAction.onSay(player, words, param, type)
- local modalWindow = ModalWindow({
- title = "Modal Window Helper Example",
- message = "This is an example of ModalWindowHelper.",
- })
- if param == "choices" then
- for text, callback in pairs(moveDirectionTest) do
- modalWindow:addChoice(text, function(player, button, choice)
- if button.name == "Select" then
- callback(player)
- modalWindow:sendToPlayer(player)
- end
- end)
- end
-
- modalWindow:addButton("Select")
- modalWindow:addButton("Cancel")
- elseif param == "buttons" then
- for direction, callback in pairs(moveDirectionTest) do
- modalWindow:addButton(direction, function(player, button, choice)
- callback(player)
- modalWindow:sendToPlayer(player)
- end)
- end
- end
- modalWindow:sendToPlayer(player)
- return false
-end
-
---talkAction:accountType(ACCOUNT_TYPE_GOD)
---talkAction:access(true)
-talkAction:separator(" ")
-talkAction:register()
diff --git a/data-otservbr-global/scripts/creaturescripts/others/droploot.lua b/data-otservbr-global/scripts/creaturescripts/others/droploot.lua
index 7be3564048d..9bf77afa71b 100644
--- a/data-otservbr-global/scripts/creaturescripts/others/droploot.lua
+++ b/data-otservbr-global/scripts/creaturescripts/others/droploot.lua
@@ -1,5 +1,7 @@
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua")
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
+
local dropLoot = CreatureEvent("DropLoot")
+
function dropLoot.onDeath(player, corpse, killer, mostDamage, unjustified, mostDamage_unjustified)
local town = player:getTown()
if town and town:getId() == TOWNS_LIST.DAWNPORT and player:getLevel() < 8 then
@@ -9,6 +11,7 @@ function dropLoot.onDeath(player, corpse, killer, mostDamage, unjustified, mostD
if player:hasFlag(PlayerFlag_NotGenerateLoot) then
return true
end
+
Blessings.DebugPrint("onDeath DROPLOOT EVENT DropLoot")
return Blessings.PlayerDeath(player, corpse, killer)
end
diff --git a/data-otservbr-global/scripts/globalevents/others/guild_war.lua b/data-otservbr-global/scripts/globalevents/others/guild_war.lua
deleted file mode 100644
index 41238755494..00000000000
--- a/data-otservbr-global/scripts/globalevents/others/guild_war.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-local guildWar = GlobalEvent("guildwar")
-
-function guildWar.onThink(interval)
- local time = os.time()
- db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. time .. " WHERE `status` = 1 AND `ended` != 0 AND `ended` < " .. time)
- return true
-end
-
-guildWar:interval(60000)
-guildWar:register()
diff --git a/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua b/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua
index 91273ac4cbd..e5166038db2 100644
--- a/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua
+++ b/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua
@@ -18,17 +18,25 @@ local function updateWaterPoolsSize()
end
local function loadMapEmpty()
- if SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then
- local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers()
- for _, player in ipairs(players) do
- if player:getPosition().z == 8 then
- if player:isInBoatSpot() then
- local teleportPosition = player:getPosition()
- teleportPosition.z = 9
- player:teleportTo(teleportPosition)
- logger.trace("Teleporting player to down.")
+ local playersInZone = SoulWarQuest.ebbAndFlow.getZone():countPlayers()
+ local monstersInZone = SoulWarQuest.ebbAndFlow.getZone():countMonsters()
+ if playersInZone > 0 or monstersInZone > 0 then
+ local creatures = SoulWarQuest.ebbAndFlow.getZone():getCreatures()
+ for _, creature in ipairs(creatures) do
+ local creatureMaster = creature:getMaster()
+ local player = creature:getPlayer()
+ if creature:isPlayer() or (creature:isMonster() and creatureMaster and creatureMaster:getPlayer()) then
+ if creature:getPosition().z == 8 then
+ if creature:isInBoatSpot() then
+ local teleportPosition = creature:getPosition()
+ teleportPosition.z = 9
+ creature:teleportTo(teleportPosition)
+ logger.trace("Teleporting player to down.")
+ end
+ if player then
+ player:sendCreatureAppear()
+ end
end
- player:sendCreatureAppear()
end
end
end
@@ -72,22 +80,30 @@ local function findNearestRoomPosition(playerPosition)
end
local function loadMapInundate()
- if SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then
- local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers()
- for _, player in ipairs(players) do
- local playerPosition = player:getPosition()
- if playerPosition.z == 9 then
- if player:isInBoatSpot() then
- local nearestCenterPosition = findNearestRoomPosition(playerPosition)
- player:teleportTo(nearestCenterPosition)
- logger.trace("Teleporting player to the near center position room and updating tile.")
- else
- player:teleportTo(SoulWarQuest.ebbAndFlow.waitPosition)
- logger.trace("Teleporting player to wait position and updating tile.")
+ local playersInZone = SoulWarQuest.ebbAndFlow.getZone():countPlayers()
+ local monstersInZone = SoulWarQuest.ebbAndFlow.getZone():countMonsters()
+ if playersInZone > 0 or monstersInZone > 0 then
+ local creatures = SoulWarQuest.ebbAndFlow.getZone():getCreatures()
+ for _, creature in ipairs(creatures) do
+ local creatureMaster = creature:getMaster()
+ local player = creature:getPlayer()
+ if creature:isPlayer() or (creature:isMonster() and creatureMaster and creatureMaster:getPlayer()) then
+ local creaturePosition = creature:getPosition()
+ if creaturePosition.z == 9 then
+ if creature:isInBoatSpot() then
+ local nearestCenterPosition = findNearestRoomPosition(creaturePosition)
+ creature:teleportTo(nearestCenterPosition)
+ logger.trace("Teleporting player to the near center position room and updating tile.")
+ else
+ creature:teleportTo(SoulWarQuest.ebbAndFlow.waitPosition)
+ logger.trace("Teleporting player to wait position and updating tile.")
+ end
+ creaturePosition:sendMagicEffect(CONST_ME_TELEPORT)
+ end
+ if player then
+ player:sendCreatureAppear()
end
- playerPosition:sendMagicEffect(CONST_ME_TELEPORT)
end
- player:sendCreatureAppear()
end
end
diff --git a/data-otservbr-global/scripts/quests/the_hidden_city_of_beregar/actions_ladder.lua b/data-otservbr-global/scripts/quests/the_hidden_city_of_beregar/actions_ladder.lua
index 5260bc4469a..83074b595e3 100644
--- a/data-otservbr-global/scripts/quests/the_hidden_city_of_beregar/actions_ladder.lua
+++ b/data-otservbr-global/scripts/quests/the_hidden_city_of_beregar/actions_ladder.lua
@@ -1,7 +1,7 @@
local dwarvenLadder = Action()
function dwarvenLadder.onUse(player, item, fromPosition, itemEx, toPosition)
if player:getStorageValue(Storage.DwarvenLegs) < 1 then
- player:teleportTo({ x = 32681, y = 31507, z = 10 })
+ player:teleportTo({ x = 32681, y = 31507, z = 10 }, true)
player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
return true
else
diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua
index 78653733b58..c526553132d 100644
--- a/data/events/scripts/player.lua
+++ b/data/events/scripts/player.lua
@@ -315,7 +315,8 @@ function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder,
end
-- Reward System
- if toPosition.x == CONTAINER_POSITION then
+ local containerThing = tile and tile:getItemByType(ITEM_TYPE_CONTAINER)
+ if containerThing and toPosition.x == CONTAINER_POSITION then
local containerId = toPosition.y - 64
local container = self:getContainerById(containerId)
if not container then
diff --git a/data/items/items.xml b/data/items/items.xml
index eb00ac6bdf3..c1b8e8a63ba 100644
--- a/data/items/items.xml
+++ b/data/items/items.xml
@@ -4435,6 +4435,9 @@
-
+
+
+
@@ -76427,5 +76430,3305 @@ Granted by TibiaGoals.com"/>
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
diff --git a/data/libs/compat/compat.lua b/data/libs/compat/compat.lua
index 061d1dbe47e..ed1a229a826 100644
--- a/data/libs/compat/compat.lua
+++ b/data/libs/compat/compat.lua
@@ -572,8 +572,8 @@ function isPremium(cid)
return p ~= nil and p:isPremium() or false
end
-function getBlessingsCost(level, byCommand)
- return Blessings.getBlessingsCost(level, byCommand)
+function getBlessingCost(level, byCommand, blessId)
+ return Blessings.getBlessingCost(level, byCommand, blessId)
end
function getPvpBlessingCost(level, byCommand)
@@ -618,18 +618,7 @@ function getPlayerGUIDByName(name)
end
function getAccountNumberByPlayerName(name)
- local player = Player(name)
- if player then
- return player:getAccountId()
- end
-
- local resultId = db.storeQuery("SELECT `account_id` FROM `players` WHERE `name` = " .. db.escapeString(name))
- if resultId ~= false then
- local accountId = Result.getNumber(resultId, "account_id")
- Result.free(resultId)
- return accountId
- end
- return 0
+ return Game.getPlayerAccountId(name)
end
getPlayerAccountBalance = getPlayerBalance
diff --git a/data/libs/functions/functions.lua b/data/libs/functions/functions.lua
index 2327a1cf937..4b9a94968ca 100644
--- a/data/libs/functions/functions.lua
+++ b/data/libs/functions/functions.lua
@@ -110,21 +110,6 @@ function getRateFromTable(t, level, default)
return default
end
-function getAccountNumberByPlayerName(name)
- local player = Player(name)
- if player ~= nil then
- return player:getAccountId()
- end
-
- local resultId = db.storeQuery("SELECT `account_id` FROM `players` WHERE `name` = " .. db.escapeString(name))
- if resultId ~= false then
- local accountId = Result.getNumber(resultId, "account_id")
- Result.free(resultId)
- return accountId
- end
- return 0
-end
-
function getMoneyCount(string)
local b, e = string:find("%d+")
local money = b and e and tonumber(string:sub(b, e)) or -1
diff --git a/data/libs/functions/game.lua b/data/libs/functions/game.lua
index a7c7f7617ce..ae13f50038a 100644
--- a/data/libs/functions/game.lua
+++ b/data/libs/functions/game.lua
@@ -167,3 +167,18 @@ function Game.getTimeInWords(seconds)
end
return timeStr
end
+
+function Game.getPlayerAccountId(name)
+ local player = Player(name)
+ if player then
+ return player:getAccountId()
+ end
+
+ local resultId = db.storeQuery("SELECT `account_id` FROM `players` WHERE `name` = " .. db.escapeString(name))
+ if resultId then
+ local accountId = result.getNumber(resultId, "account_id")
+ result.free(resultId)
+ return accountId
+ end
+ return 0
+end
diff --git a/data/libs/functions/player.lua b/data/libs/functions/player.lua
index 3f7c8e17b75..0350310e397 100644
--- a/data/libs/functions/player.lua
+++ b/data/libs/functions/player.lua
@@ -459,17 +459,6 @@ function Player.getSubjectVerb(self, past)
return Pronouns.getPlayerSubjectVerb(self:getPronoun(), past)
end
-function Player.findItemInInbox(self, itemId)
- local inbox = self:getStoreInbox()
- local items = inbox:getItems()
- for _, item in pairs(items) do
- if item:getId() == itemId then
- return item
- end
- end
- return nil
-end
-
function Player.updateHazard(self)
local zones = self:getZones()
if not zones or #zones == 0 then
@@ -618,28 +607,6 @@ function Player:setFiendish()
return false
end
-function Player:findItemInInbox(itemId, name)
- local inbox = self:getStoreInbox()
- local items = inbox:getItems()
- for _, item in pairs(items) do
- if item:getId() == itemId and (not name or item:getName() == name) then
- return item
- end
- end
- return nil
-end
-
-function Player:sendColoredMessage(message)
- local grey = 3003
- local blue = 3043
- local green = 3415
- local purple = 36792
- local yellow = 34021
-
- local msg = message:gsub("{grey|", "{" .. grey .. "|"):gsub("{blue|", "{" .. blue .. "|"):gsub("{green|", "{" .. green .. "|"):gsub("{purple|", "{" .. purple .. "|"):gsub("{yellow|", "{" .. yellow .. "|")
- return self:sendTextMessage(MESSAGE_LOOT, msg)
-end
-
function Player:showInfoModal(title, message, buttonText)
local modal = ModalWindow({
title = title,
@@ -746,15 +713,6 @@ function Player.getNextRewardTime(self)
return math.max(self:getStorageValue(DailyReward.storages.nextRewardTime), 0)
end
-function Player.isRestingAreaBonusActive(self)
- local levelStreak = self:getStreakLevel()
- if levelStreak > 1 then
- return true
- else
- return false
- end
-end
-
function Player.getActiveDailyRewardBonusesName(self)
local msg = ""
local streakLevel = self:getStreakLevel()
@@ -846,45 +804,6 @@ function Player.inBossFight(self)
return false
end
--- For use of data/events/scripts/player.lua
-function Player:executeRewardEvents(item, toPosition)
- if toPosition.x == CONTAINER_POSITION then
- local containerId = toPosition.y - 64
- local container = self:getContainerById(containerId)
- if not container then
- return true
- end
-
- -- Do not let the player insert items into either the Reward Container or the Reward Chest
- local itemId = container:getId()
- if itemId == ITEM_REWARD_CONTAINER or itemId == ITEM_REWARD_CHEST then
- self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
- return false
- end
-
- -- The player also shouldn't be able to insert items into the boss corpse
- local tileCorpse = Tile(container:getPosition())
- for index, value in ipairs(tileCorpse:getItems() or {}) do
- if value:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2 ^ 31 - 1 and value:getName() == container:getName() then
- self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
- return false
- end
- end
- end
- -- Do not let the player move the boss corpse.
- if item:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2 ^ 31 - 1 then
- self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
- return false
- end
- -- Players cannot throw items on reward chest
- local tileChest = Tile(toPosition)
- if tileChest and tileChest:getItemById(ITEM_REWARD_CHEST) then
- self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
- self:getPosition():sendMagicEffect(CONST_ME_POFF)
- return false
- end
-end
-
do
local loyaltySystem = {
enable = configManager.getBoolean(configKeys.LOYALTY_ENABLED),
@@ -1009,3 +928,15 @@ function Player.getMarkdownLink(self)
return string.format("**[%s](%s)** %s [_%s_]", self:getName(), playerURL, emoji, vocation)
end
+
+function Player.findItemInInbox(self, itemId, name)
+ local inbox = self:getStoreInbox()
+ local items = inbox:getItems()
+
+ for _, item in pairs(items) do
+ if item:getId() == itemId and (not name or item:getName() == name) then
+ return item
+ end
+ end
+ return nil
+end
diff --git a/data/modules/scripts/blessings/blessings.lua b/data/libs/systems/blessing.lua
similarity index 52%
rename from data/modules/scripts/blessings/blessings.lua
rename to data/libs/systems/blessing.lua
index e061501a330..fee0e6fe8e8 100644
--- a/data/modules/scripts/blessings/blessings.lua
+++ b/data/libs/systems/blessing.lua
@@ -6,29 +6,44 @@ Blessings.Credits = {
lastUpdate = "08/04/2020",
todo = {
"Insert & Select query in blessings_history",
- "Add unfair fight reductio (convert the get killer is pvp fight with getDamageMap of dead player)",
- "Gamestore buy blessing",
- "Test ank print text",
- "Test all functions",
- "Test henricus prices/blessings",
- "Add data \\movements\\scripts\\quests\\cults of tibia\\icedeath.lua blessing information",
- "WotE data\\movements\\scripts\\quests\\wrath of the emperor\\realmTeleport.lua has line checking if player has bless 1??? wtf",
- "add blessings module support npc\\lib\\npcsystem\\modules.lua",
- "Fix store buying bless",
- "Check if store is inside lua or source...",
},
}
Blessings.Config = {
AdventurerBlessingLevel = configManager.getNumber(configKeys.ADVENTURERSBLESSING_LEVEL), -- Free full bless until level
HasToF = not configManager.getBoolean(configKeys.TOGGLE_SERVER_IS_RETRO), -- Enables/disables twist of fate
- InquisitonBlessPriceMultiplier = 1.1, -- Bless price multiplied by henricus
+ InquisitonBlessPriceMultiplier = 1.1, -- Bless price multiplier by henricus
SkulledDeathLoseStoreItem = configManager.getBoolean(configKeys.SKULLED_DEATH_LOSE_STORE_ITEM), -- Destroy all items on store when dying with red/blackskull
- InventoryGlowOnFiveBless = configManager.getBoolean(configKeys.INVENTORY_GLOW), -- Glow in yellow inventory items when the player has 5 or more bless,
- Debug = false, -- Prin debug messages in console if enabled
}
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/assets.lua")
+Blessings.Types = {
+ REGULAR = 1,
+ ENHANCED = 2,
+ PvP = 3,
+}
+
+Blessings.All = {
+ [1] = { id = 1, name = "Twist of Fate", type = Blessings.Types.PvP },
+ [2] = { id = 2, name = "The Wisdom of Solitude", charm = 10345, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
+ [3] = { id = 3, name = "The Spark of the Phoenix", charm = 10341, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
+ [4] = { id = 4, name = "The Fire of the Suns", charm = 10344, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
+ [5] = { id = 5, name = "The Spiritual Shielding", charm = 10343, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
+ [6] = { id = 6, name = "The Embrace of Tibia", charm = 10342, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
+ [7] = { id = 7, name = "Heart of the Mountain", charm = 25360, type = Blessings.Types.ENHANCED, losscount = true, inquisition = false },
+ [8] = { id = 8, name = "Blood of the Mountain", charm = 25361, type = Blessings.Types.ENHANCED, losscount = true, inquisition = false },
+}
+
+Blessings.LossPercent = {
+ [0] = { item = 100, skill = 0 },
+ [1] = { item = 70, skill = 8 },
+ [2] = { item = 45, skill = 16 },
+ [3] = { item = 25, skill = 24 },
+ [4] = { item = 10, skill = 32 },
+ [5] = { item = 0, skill = 40 },
+ [6] = { item = 0, skill = 48 },
+ [7] = { item = 0, skill = 56 },
+ [8] = { item = 0, skill = 56 },
+}
--[=====[
--
@@ -45,9 +60,6 @@ CREATE TABLE IF NOT EXISTS `blessings_history` (
--]=====]
Blessings.DebugPrint = function(content, pre, pos)
- if not Blessings.Config.Debug then
- return
- end
if pre == nil then
pre = ""
else
@@ -67,145 +79,93 @@ Blessings.DebugPrint = function(content, pre, pos)
end
end
-Blessings.C_Packet = {
- OpenWindow = 0xCF,
-}
-
-Blessings.S_Packet = {
- BlessDialog = 0x9B,
- BlessStatus = 0x9C,
-}
-
-function onRecvbyte(player, msg, byte)
- if byte == Blessings.C_Packet.OpenWindow then
- Blessings.sendBlessDialog(player)
- end
-end
-
-Blessings.sendBlessStatus = function(player, curBless)
- if player:getClient().version < 1200 then
- return true
- end
-
- -- why not using ProtocolGame::sendBlessStatus ?
- local msg = NetworkMessage()
- msg:addByte(Blessings.S_Packet.BlessStatus)
- callback = function(k)
- return true
- end
- if curBless == nil then
- curBless = player:getBlessings(callback) -- ex: {1, 2, 5, 7}
- end
- Blessings.DebugPrint(#curBless, "sendBlessStatus curBless")
- local bitWiseCurrentBless = 0
- local blessCount = 0
+Blessings.PlayerDeath = function(player, corpse, killer)
+ local hasAol = (player:getSlotItem(CONST_SLOT_NECKLACE) and player:getSlotItem(CONST_SLOT_NECKLACE):getId() == ITEM_AMULETOFLOSS)
+ local hasSkull = table.contains({ SKULL_RED, SKULL_BLACK }, player:getSkull())
+ local currBlessCount = player:getBlessings()
- for i = 1, #curBless do
- if curBless[i].losscount then
- blessCount = blessCount + 1
- end
- if (not curBless[i].losscount and Blessings.Config.HasToF) or curBless[i].losscount then
- bitWiseCurrentBless = bit.bor(bitWiseCurrentBless, Blessings.BitWiseTable[curBless[i].id])
- end
+ if hasSkull then
+ Blessings.DropLoot(player, corpse, 100, true)
+ elseif #currBlessCount < 5 and not hasAol then
+ local equipLossChance = Blessings.LossPercent[#currBlessCount].item
+ Blessings.DropLoot(player, corpse, equipLossChance)
end
- if blessCount > 5 and Blessings.Config.InventoryGlowOnFiveBless then
- bitWiseCurrentBless = bit.bor(bitWiseCurrentBless, 1)
+ if not player:getSlotItem(CONST_SLOT_BACKPACK) then
+ player:addItem(ITEM_BAG, 1, false, CONST_SLOT_BACKPACK)
end
- msg:addU16(bitWiseCurrentBless)
- msg:addByte(blessCount >= 7 and 3 or (blessCount > 0 and 2 or 1)) -- Bless dialog button colour 1 = Disabled | 2 = normal | 3 = green
-
- -- if #curBless >= 5 then
- -- msg:addU16(1) -- TODO ?
- -- else
- -- msg:addU16(0)
- -- end
-
- msg:sendToPlayer(player)
+ return true
end
-Blessings.sendBlessDialog = function(player)
- -- TODO: Migrate to protocolgame.cpp
- local msg = NetworkMessage()
- msg:addByte(Blessings.S_Packet.BlessDialog)
+Blessings.DropLoot = function(player, corpse, chance, skulled)
+ local multiplier = 100
+ math.randomseed(os.time())
+ chance = chance * multiplier
+ Blessings.DebugPrint("DropLoot chance " .. chance)
+ for i = CONST_SLOT_HEAD, CONST_SLOT_AMMO do
+ local item = player:getSlotItem(i)
+ if item then
+ local thisChance = item:isContainer() and chance or (chance / 10)
+ local thisRandom = math.random(100 * multiplier)
- callback = function(k)
- return true
- end
- local curBless = player:getBlessings()
-
- msg:addByte(Blessings.Config.HasToF and #Blessings.All or (#Blessings.All - 1)) -- total blessings
- for k = 1, #Blessings.All do
- v = Blessings.All[k]
- if v.type ~= Blessings.Types.PvP or Blessings.Config.HasToF then
- msg:addU16(Blessings.BitWiseTable[v.id])
- msg:addByte(player:getBlessingCount(v.id))
- if player:getClient().version > 1200 then
- msg:addByte(player:getBlessingCount(v.id, true)) -- Store Blessings Count
+ Blessings.DebugPrint(thisChance / multiplier .. "%" .. " | thisRandom " .. thisRandom / multiplier .. "%", "DropLoot item " .. item:getName() .. " |")
+ if skulled or thisRandom <= thisChance then
+ Blessings.DebugPrint("Dropped " .. item:getName())
+ item:moveTo(corpse)
end
end
end
- local promotion = (player:isPremium() and player:isPromoted()) and 30 or 0
- local PvPminXPLoss = Blessings.LossPercent[#curBless].skill + promotion
- local PvPmaxXPLoss = PvPminXPLoss
- if Blessings.Config.HasToF then
- PvPmaxXPLoss = math.floor(PvPminXPLoss * 1.15)
- end
- local PvEXPLoss = PvPminXPLoss
-
- local playerAmulet = player:getSlotItem(CONST_SLOT_NECKLACE)
- local haveSkull = player:getSkull() >= 4
- hasAol = (playerAmulet and playerAmulet:getId() == ITEM_AMULETOFLOSS)
-
- equipLoss = Blessings.LossPercent[#curBless].item
- if haveSkull then
- equipLoss = 100
- elseif hasAol then
- equipLoss = 0
- end
-
- msg:addByte(2) -- BYTE PREMIUM (only work with premium days)
- msg:addByte(promotion) -- XP Loss Lower POR SER PREMIUM
- msg:addByte(PvPminXPLoss) -- XP/Skill loss min pvp death
- msg:addByte(PvPmaxXPLoss) -- XP/Skill loss max pvp death
- msg:addByte(PvEXPLoss) -- XP/Skill pve death
- msg:addByte(equipLoss) -- Equip container lose pvp death
- msg:addByte(equipLoss) -- Equip container pve death
-
- msg:addByte(haveSkull and 1 or 0) -- is red/black skull
- msg:addByte(hasAol and 1 or 0)
-
- -- History
- local historyAmount = 1
- msg:addByte(historyAmount) -- History log count
- for i = 1, historyAmount do
- msg:addU32(os.time()) -- timestamp
- msg:addByte(0) -- Color message (1 - Red | 0 = White loss)
- msg:addString("Blessing Purchased", "Blessings.sendBlessDialog - Blessing Purchased") -- History message
+ if skulled and Blessings.Config.SkulledDeathLoseStoreItem then
+ local inbox = player:getStoreInbox()
+ local toBeDeleted = {}
+ if inbox and inbox:getSize() > 0 then
+ for i = 0, inbox:getSize() do
+ local item = inbox:getItem(i)
+ if item then
+ toBeDeleted[#toBeDeleted + 1] = item.uid
+ end
+ end
+ if #toBeDeleted > 0 then
+ for i, v in pairs(toBeDeleted) do
+ local item = Item(v)
+ if item then
+ item:remove()
+ end
+ end
+ end
+ end
end
-
- msg:sendToPlayer(player)
end
+-- Blessing Helpers --
Blessings.getCommandFee = function(cost)
local fee = configManager.getNumber(configKeys.BUY_BLESS_COMMAND_FEE) or 0
return cost + cost * (((fee > 100 and 100) or fee) / 100)
end
-Blessings.getBlessingsCost = function(level, byCommand)
+Blessings.getBlessingCost = function(level, byCommand, enhanced)
if byCommand == nil then
byCommand = false
end
+
+ if enhanced == nil then
+ enhanced = false
+ end
+
local cost
if level <= 30 then
cost = 2000
elseif level >= 120 then
- cost = 20000
+ local base_cost = enhanced and 26000 or 20000
+ local multiplier = enhanced and 100 or 75
+ cost = base_cost + multiplier * (level - 120)
else
- cost = (level - 20) * 200
+ local multiplier = enhanced and 260 or 200
+ cost = multiplier * (level - 20)
end
+
return byCommand and Blessings.getCommandFee(cost) or cost
end
@@ -213,6 +173,7 @@ Blessings.getPvpBlessingCost = function(level, byCommand)
if byCommand == nil then
byCommand = false
end
+
local cost
if level <= 30 then
cost = 2000
@@ -221,6 +182,7 @@ Blessings.getPvpBlessingCost = function(level, byCommand)
else
cost = (level - 20) * 200
end
+
return byCommand and Blessings.getCommandFee(cost) or cost
end
@@ -250,6 +212,7 @@ Blessings.checkBless = function(player)
for k, v in pairs(Blessings.All) do
result = player:hasBlessing(k) and result .. "\n" .. v.name or result
end
+
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, 20 > result:len() and "No blessings received." or result)
return true
end
@@ -258,6 +221,7 @@ Blessings.doAdventurerBlessing = function(player)
if player:getLevel() > Blessings.Config.AdventurerBlessingLevel then
return true
end
+
player:addMissingBless(true, true)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have adventurer's blessings for being level lower than " .. Blessings.Config.AdventurerBlessingLevel .. "!")
@@ -270,70 +234,16 @@ Blessings.getInquisitionPrice = function(player)
inquifilter = function(b)
return b.inquisition
end
+
donthavefilter = function(p, b)
return not p:hasBlessing(b)
end
+
local missing = #player:getBlessings(inquifilter, donthavefilter)
- local totalBlessPrice = Blessings.getBlessingsCost(player:getLevel(), false) * missing * Blessings.Config.InquisitonBlessPriceMultiplier
+ local totalBlessPrice = Blessings.getBlessingCost(player:getLevel(), false) * missing * Blessings.Config.InquisitonBlessPriceMultiplier
return missing, totalBlessPrice
end
-Blessings.DropLoot = function(player, corpse, chance, skulled)
- local multiplier = 100 -- Improve the loot randomness spectrum
- math.randomseed(os.time()) -- Improve the loot randomness spectrum
- chance = chance * multiplier
- Blessings.DebugPrint(chance, "DropLoot chance")
- for i = CONST_SLOT_HEAD, CONST_SLOT_AMMO do
- local item = player:getSlotItem(i)
- if item then
- local thisChance = chance
- local thisRandom = math.random(100 * multiplier)
- if not item:isContainer() then
- thisChance = chance / 10
- end
- Blessings.DebugPrint(thisChance / multiplier .. "%" .. " | thisRandom " .. thisRandom / multiplier .. "%", "DropLoot item " .. item:getName() .. " |")
- if skulled or thisRandom <= thisChance then
- Blessings.DebugPrint("Dropped " .. item:getName())
- item:moveTo(corpse)
- end
- end
- end
- if skulled and Blessings.Config.SkulledDeathLoseStoreItem then
- local inbox = player:getStoreInbox()
- local toBeDeleted = {}
- if inbox and inbox:getSize() > 0 then
- for i = 0, inbox:getSize() do
- local item = inbox:getItem(i)
- if item then
- toBeDeleted[#toBeDeleted + 1] = item.uid
- end
- end
- if #toBeDeleted > 0 then
- for i, v in pairs(toBeDeleted) do
- local item = Item(v)
- if item then
- item:remove()
- end
- end
- end
- end
- end
-end
-
-Blessings.ClearBless = function(player, killer, currentBless)
- Blessings.DebugPrint(#currentBless, "ClearBless #currentBless")
- local hasToF = Blessings.Config.HasToF and player:hasBlessing(1) or false
- if hasToF and killer(killer:isPlayer() or (killer:getMaster() and killer:getMaster():isPlayer())) then -- TODO add better check if its pvp or pve
- player:removeBlessing(1)
- return
- end
- for i = 1, #currentBless do
- Blessings.DebugPrint(i, "ClearBless curBless i", " | " .. currentBless[i].name)
- player:removeBlessing(currentBless[i].id, 1)
- end
-end
-
--- bought by command
Blessings.BuyAllBlesses = function(player)
if not Tile(player:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE) and (player:isPzLocked() or player:getCondition(CONDITION_INFIGHT, CONDITIONID_DEFAULT)) then
player:sendCancelMessage("You can't buy bless while in battle.")
@@ -341,23 +251,26 @@ Blessings.BuyAllBlesses = function(player)
return true
end
- local blessCost = Blessings.getBlessingsCost(player:getLevel(), true)
- local PvPBlessCost = Blessings.getPvpBlessingCost(player:getLevel(), true)
- local hasToF = Blessings.Config.HasToF and player:hasBlessing(1) or true
donthavefilter = function(p, b)
return not p:hasBlessing(b)
end
+
+ local hasToF = Blessings.Config.HasToF and player:hasBlessing(1) or true
local missingBless = player:getBlessings(nil, donthavefilter)
local missingBlessAmt = #missingBless + (hasToF and 0 or 1)
- local totalCost = blessCost * #missingBless
+ local totalCost
+ for i, bless in ipairs(missingBless) do
+ totalCost = totalCost + Blessings.getBlessingCost(player:getLevel(), true, bless.id >= 7)
+ end
if missingBlessAmt == 0 then
player:sendCancelMessage("You are already blessed.")
player:getPosition():sendMagicEffect(CONST_ME_POFF)
return true
end
+
if not hasToF then
- totalCost = totalCost + PvPBlessCost
+ totalCost = totalCost + Blessings.getPvpBlessingCost(player:getLevel(), true)
end
if player:removeMoneyBank(totalCost) then
@@ -365,9 +278,11 @@ Blessings.BuyAllBlesses = function(player)
player = player:getName(),
context = "blessings",
})
+
for i, v in ipairs(missingBless) do
player:addBlessing(v.id, 1)
end
+
player:sendCancelMessage("You received the remaining " .. missingBlessAmt .. " blesses for a total of " .. totalCost .. " gold.")
player:getPosition():sendMagicEffect(CONST_ME_HOLYAREA)
else
@@ -378,29 +293,6 @@ Blessings.BuyAllBlesses = function(player)
return true
end
-Blessings.PlayerDeath = function(player, corpse, killer)
- local hasToF = Blessings.Config.HasToF and player:hasBlessing(1) or false
- local hasAol = (player:getSlotItem(CONST_SLOT_NECKLACE) and player:getSlotItem(CONST_SLOT_NECKLACE):getId() == ITEM_AMULETOFLOSS)
- local haveSkull = table.contains({ SKULL_RED, SKULL_BLACK }, player:getSkull())
- local curBless = player:getBlessings()
-
- if haveSkull then -- lose all bless + drop all items
- Blessings.DropLoot(player, corpse, 100, true)
- elseif #curBless < 5 and not hasAol then -- lose all items
- local equipLoss = Blessings.LossPercent[#curBless].item
- Blessings.DropLoot(player, corpse, equipLoss)
- elseif #curBless < 5 and hasAol and not hasToF then
- player:removeItem(ITEM_AMULETOFLOSS, 1, -1, false)
- end
- --Blessings.ClearBless(player, killer, curBless) IMPLEMENTED IN SOURCE BECAUSE THIS WAS HAPPENING BEFORE SKILL/EXP CALCULATIONS
-
- if not player:getSlotItem(CONST_SLOT_BACKPACK) then
- player:addItem(ITEM_BAG, 1, false, CONST_SLOT_BACKPACK)
- end
-
- return true
-end
-
function Player.getBlessings(self, filter, hasblessingFilter)
local blessings = {}
if filter == nil then
@@ -414,11 +306,13 @@ function Player.getBlessings(self, filter, hasblessingFilter)
return p:hasBlessing(b)
end
end
+
for k, v in pairs(Blessings.All) do
if filter(v) and hasblessingFilter(self, k) then
table.insert(blessings, v)
end
end
+
return blessings
end
@@ -426,11 +320,13 @@ function Player.addMissingBless(self, all, tof)
if all == nil then
all = true
end
+
if tof == nil then
tof = false
elseif tof then
tof = tof and Blessings.Config.HasToF
end
+
for k, v in pairs(Blessings.All) do
if all or (v.type == Blessings.Types.REGULAR) or (tof and v.type == Blessings.Types.PvP) then
if not self:hasBlessing(k) then
@@ -438,5 +334,5 @@ function Player.addMissingBless(self, all, tof)
end
end
end
- Blessings.sendBlessStatus(self)
+ self:sendBlessStatus()
end
diff --git a/data/libs/systems/load.lua b/data/libs/systems/load.lua
index 281b8b1d466..ffe02320b96 100644
--- a/data/libs/systems/load.lua
+++ b/data/libs/systems/load.lua
@@ -1,4 +1,5 @@
-- Load systems functions
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
dofile(CORE_DIRECTORY .. "/libs/systems/concoctions.lua")
dofile(CORE_DIRECTORY .. "/libs/systems/daily_reward.lua")
dofile(CORE_DIRECTORY .. "/libs/systems/encounters.lua")
diff --git a/data/libs/systems/vip.lua b/data/libs/systems/vip.lua
index 9e76fd8ad80..49ef7bcf8cc 100644
--- a/data/libs/systems/vip.lua
+++ b/data/libs/systems/vip.lua
@@ -45,17 +45,17 @@ function Player.onAddVip(self, days, silent)
self:kv():scoped("account"):set("vip-system", true)
end
-function CheckPremiumAndPrint(player, msgType)
- if player:getVipDays() == 0xFFFF then
- player:sendTextMessage(msgType, "You have an unlimited VIP status.")
+function Player.sendVipStatus(self)
+ if self:getVipDays() == 0xFFFF then
+ self:sendTextMessage(MESSAGE_LOGIN, "You have unlimited VIP status.")
return true
end
- local playerVipTime = player:getVipTime()
+ local playerVipTime = self:getVipTime()
if playerVipTime < os.time() then
- player:sendTextMessage(msgType, "Your VIP status is currently inactive.")
+ self:sendTextMessage(MESSAGE_STATUS, "Your VIP status is currently inactive.")
return true
end
- player:sendTextMessage(msgType, string.format("You have %s of VIP time remaining.", getFormattedTimeRemaining(playerVipTime)))
+ self:sendTextMessage(MESSAGE_LOGIN, string.format("You have %s of VIP time remaining.", getFormattedTimeRemaining(playerVipTime)))
end
diff --git a/data/modules/modules.xml b/data/modules/modules.xml
index c45646183ac..e51bf055f2a 100644
--- a/data/modules/modules.xml
+++ b/data/modules/modules.xml
@@ -10,9 +10,6 @@
-
-
-
@@ -26,5 +23,4 @@
-
diff --git a/data/modules/scripts/blessings/assets.lua b/data/modules/scripts/blessings/assets.lua
deleted file mode 100644
index 73d02a272f3..00000000000
--- a/data/modules/scripts/blessings/assets.lua
+++ /dev/null
@@ -1,47 +0,0 @@
-Blessings.Types = {
- REGULAR = 1,
- ENHANCED = 2,
- PvP = 3,
-}
-
-Blessings.All = {
- [1] = { id = 1, name = "Twist of Fate", type = Blessings.Types.PvP },
- [2] = { id = 2, name = "The Wisdom of Solitude", charm = 10345, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
- [3] = { id = 3, name = "The Spark of the Phoenix", charm = 10341, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
- [4] = { id = 4, name = "The Fire of the Suns", charm = 10344, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
- [5] = { id = 5, name = "The Spiritual Shielding", charm = 10343, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
- [6] = { id = 6, name = "The Embrace of Tibia", charm = 10342, type = Blessings.Types.REGULAR, losscount = true, inquisition = true },
- [7] = { id = 7, name = "Blood of the Mountain", charm = 25360, type = Blessings.Types.ENHANCED, losscount = true, inquisition = false },
- [8] = { id = 8, name = "Heart of the Mountain", charm = 25361, type = Blessings.Types.ENHANCED, losscount = true, inquisition = false },
-}
-
-Blessings.LossPercent = {
- [0] = { item = 100, skill = 0 },
- [1] = { item = 70, skill = 8 },
- [2] = { item = 45, skill = 16 },
- [3] = { item = 25, skill = 24 },
- [4] = { item = 10, skill = 32 },
- [5] = { item = 0, skill = 40 },
- [6] = { item = 0, skill = 48 },
- [7] = { item = 0, skill = 56 },
- [8] = { item = 0, skill = 56 },
-}
-
-Blessings.BitWiseTable = {
- [0] = 1,
- [1] = 2,
- [2] = 4,
- [3] = 8,
- [4] = 16,
- [5] = 32,
- [6] = 64,
- [7] = 128,
- [8] = 256,
- [9] = 512,
- [10] = 1024,
- [11] = 2048,
- [12] = 4096,
- [13] = 8192,
- [14] = 16384,
- [15] = 32768,
-}
diff --git a/data/npclib/npc.lua b/data/npclib/npc.lua
index 4de60c45c49..4a8097ff27f 100644
--- a/data/npclib/npc.lua
+++ b/data/npclib/npc.lua
@@ -89,7 +89,7 @@ function SayEvent(npcId, playerId, messageDelayed, npcHandler, textType)
local parseInfo = {
[TAG_PLAYERNAME] = player:getName(),
[TAG_TIME] = getFormattedWorldTime(),
- [TAG_BLESSCOST] = Blessings.getBlessingsCost(player:getLevel(), false),
+ [TAG_BLESSCOST] = Blessings.getBlessingCost(player:getLevel(), false, (npc:getName() == "Kais" or npc:getName() == "Nomad") and true),
[TAG_PVPBLESSCOST] = Blessings.getPvpBlessingCost(player:getLevel(), false),
}
npc:say(npcHandler:parseMessage(messageDelayed, parseInfo), textType or TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
diff --git a/data/npclib/npc_system/modules.lua b/data/npclib/npc_system/modules.lua
index aca92804e80..08027a67d2b 100644
--- a/data/npclib/npc_system/modules.lua
+++ b/data/npclib/npc_system/modules.lua
@@ -60,7 +60,7 @@ if Modules == nil then
local parseInfo = {
[TAG_PLAYERNAME] = player:getName(),
[TAG_TIME] = getFormattedWorldTime(),
- [TAG_BLESSCOST] = Blessings.getBlessingsCost(player:getLevel(), false),
+ [TAG_BLESSCOST] = Blessings.getBlessingCost(player:getLevel(), false, (npc:getName() == "Kais" or npc:getName() == "Nomad") and true),
[TAG_PVPBLESSCOST] = Blessings.getPvpBlessingCost(player:getLevel(), false),
[TAG_TRAVELCOST] = costMessage,
}
@@ -160,7 +160,7 @@ if Modules == nil then
end
local parseInfo = {
- [TAG_BLESSCOST] = Blessings.getBlessingsCost(player:getLevel(), false),
+ [TAG_BLESSCOST] = Blessings.getBlessingCost(player:getLevel(), false, (npc:getName() == "Kais" or npc:getName() == "Nomad") and true),
[TAG_PVPBLESSCOST] = Blessings.getPvpBlessingCost(player:getLevel(), false),
}
if player:hasBlessing(parameters.bless) then
@@ -175,7 +175,7 @@ if Modules == nil then
npc,
player
)
- elseif not player:removeMoneyBank(type(parameters.cost) == "string" and npcHandler:parseMessage(parameters.cost, parseInfo) or parameters.cost) then
+ elseif not player:removeMoneyBank(type(parameters.cost) == "string" and tonumber(npcHandler:parseMessage(parameters.cost, parseInfo)) or parameters.cost) then
npcHandler:say("Oh. You do not have enough money.", npc, player)
else
npcHandler:say(parameters.text or "You have been blessed by one of the seven gods!", npc, player)
diff --git a/data-otservbr-global/scripts/actions/other/balloons.lua b/data/scripts/actions/items/anniversary_balloons.lua
similarity index 79%
rename from data-otservbr-global/scripts/actions/other/balloons.lua
rename to data/scripts/actions/items/anniversary_balloons.lua
index 35e84eec531..8fbeecee110 100644
--- a/data-otservbr-global/scripts/actions/other/balloons.lua
+++ b/data/scripts/actions/items/anniversary_balloons.lua
@@ -1,4 +1,4 @@
-local balloonItems = {
+local settings = {
[37471] = 37414,
[37414] = 37471, -- blue balloon
[37472] = 37416,
@@ -77,32 +77,28 @@ local balloonItems = {
[39692] = 39680, -- balloon no.9
}
-local balloons = Action()
+local anniversaryBalloons = Action()
-function balloons.onUse(player, item, fp, target, toPosition, isHotkey)
- local balloon = balloonItems[item.itemid]
+function anniversaryBalloons.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ local balloon = settings[item.itemid]
if not balloon then
- return false
+ return true
end
local fromPosition = item:getPosition()
local tile = Tile(fromPosition)
- if not fromPosition:getTile():getHouse() then
+
+ if not tile:getHouse() then
player:sendTextMessage(MESSAGE_FAILURE, "You may use this only inside a house.")
- elseif tile:getItemCountById(item.itemid) == 1 then
- for index, value in pairs(balloonItems) do
- if tile:getItemCountById(index) > 0 and index ~= item.itemid then
- player:sendCancelMessage(Game.getReturnMessage(RETURNVALUE_NOTPOSSIBLE))
- return true
- end
- end
- item:transform(balloon)
+ return true
end
+
+ item:transform(balloon, 1)
return true
end
-for index, value in pairs(balloonItems) do
- balloons:id(index)
+for itemId in pairs(settings) do
+ anniversaryBalloons:id(itemId)
end
-balloons:register()
+anniversaryBalloons:register()
diff --git a/data-canary/scripts/actions/other/bed_modification_kits.lua b/data/scripts/actions/items/bed_modification_kits.lua
similarity index 90%
rename from data-canary/scripts/actions/other/bed_modification_kits.lua
rename to data/scripts/actions/items/bed_modification_kits.lua
index 431e3cef5eb..a406f7fd5b2 100644
--- a/data-canary/scripts/actions/other/bed_modification_kits.lua
+++ b/data/scripts/actions/items/bed_modification_kits.lua
@@ -20,7 +20,7 @@ local bedModificationKits = Action()
function bedModificationKits.onUse(player, item, fromPosition, target, toPosition, isHotkey)
local newBed = setting[item:getId()]
- if not newBed or type(target) ~= "userdata" or not target:isItem() then
+ if not newBed or not target or not target:isItem() then
return false
end
@@ -35,7 +35,7 @@ function bedModificationKits.onUse(player, item, fromPosition, target, toPositio
return true
end
- for index, value in pairs(setting) do
+ for _, value in pairs(setting) do
if value[1][1] == targetItemId or table.contains({ 2491, 5501, 15506 }, targetItemId) then
toPosition:sendMagicEffect(CONST_ME_POFF)
toPosition.y = toPosition.y + 1
@@ -51,8 +51,8 @@ function bedModificationKits.onUse(player, item, fromPosition, target, toPositio
return true
end
-for index, value in pairs(setting) do
- bedModificationKits:id(index)
+for id in pairs(setting) do
+ bedModificationKits:id(id)
end
bedModificationKits:register()
diff --git a/data/scripts/actions/items/blessing_charms.lua b/data/scripts/actions/items/blessing_charms.lua
index 7e70c5a6719..fdca561c3a2 100644
--- a/data/scripts/actions/items/blessing_charms.lua
+++ b/data/scripts/actions/items/blessing_charms.lua
@@ -1,4 +1,4 @@
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua")
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
local blessingCharms = Action()
diff --git a/data/scripts/actions/items/check_bless.lua b/data/scripts/actions/items/check_bless.lua
index 0d2478f5f11..09d07fffd85 100644
--- a/data/scripts/actions/items/check_bless.lua
+++ b/data/scripts/actions/items/check_bless.lua
@@ -1,4 +1,4 @@
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua")
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
local checkBless = Action()
diff --git a/data/scripts/actions/items/christmas_bundle.lua b/data/scripts/actions/items/christmas_bundle.lua
new file mode 100644
index 00000000000..d0a56f6d050
--- /dev/null
+++ b/data/scripts/actions/items/christmas_bundle.lua
@@ -0,0 +1,42 @@
+local setting = {
+ [6506] = { { 6569, 15 }, { 3585, 5 }, { 3586, 10 }, { 3598, 20 }, { 3599, 10 }, 6500, 6501, 6489, 6503, 6387 }, -- red bundle
+ [6507] = { { 6569, 15 }, { 3585, 5 }, { 3586, 10 }, { 3598, 20 }, { 3599, 10 }, 6500, 6501, 6489, 6505, 6387 }, -- blue bundle
+ [6508] = { { 6569, 15 }, { 3585, 5 }, { 3586, 10 }, { 3598, 20 }, { 3599, 10 }, 6500, 6501, 6489, 6502, 6387 }, -- green bundle
+}
+
+local christmasBundle = Action()
+
+function christmasBundle.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ local targetItem = setting[item.itemid]
+ if not targetItem then
+ return true
+ end
+
+ local rewards = {}
+ while #rewards < 7 do
+ local randIndex = math.random(#targetItem)
+ local gift = targetItem[randIndex]
+
+ local count = 1
+ if type(gift) == "table" then
+ gift, count = unpack(gift)
+ end
+
+ rewards[#rewards + 1] = { gift, count }
+ table.remove(targetItem, randIndex)
+ end
+
+ for _, reward in ipairs(rewards) do
+ player:addItem(unpack(reward))
+ end
+
+ player:getPosition():sendMagicEffect(CONST_ME_GIFT_WRAPS)
+ item:remove(1)
+ return true
+end
+
+for itemId in pairs(setting) do
+ christmasBundle:id(itemId)
+end
+
+christmasBundle:register()
diff --git a/data-canary/scripts/actions/other/decay_to.lua b/data/scripts/actions/items/decay_to.lua
similarity index 87%
rename from data-canary/scripts/actions/other/decay_to.lua
rename to data/scripts/actions/items/decay_to.lua
index bfceedb288e..bb68e346e1f 100644
--- a/data-canary/scripts/actions/other/decay_to.lua
+++ b/data/scripts/actions/items/decay_to.lua
@@ -1,5 +1,9 @@
-local setting = {
- --[itemid] = decayto
+local voices = {
+ [23708] = "Au au!",
+ [23443] = "Grooaarr!",
+}
+
+local transformItems = {
[2062] = 2063,
[2063] = 2062, -- sacred statue
[2064] = 2065,
@@ -439,16 +443,69 @@ local setting = {
[39700] = 39699, -- rainbow torch
[39701] = 39702,
[39702] = 39701, -- rainbow torch
+ [39757] = 39758, -- yeti doll
+ [39759] = 39760,
+ [39761] = 39762, -- the gods' twilight doll
+ [39772] = 39773,
+ [39773] = 39774, -- flower table
+ [39774] = 39772, -- flower table
+ [39793] = 39794,
+ [39794] = 39793, -- turquoise flower lamp
+ [39795] = 39796,
+ [39796] = 39795, -- purple flower lamp
+ [39801] = 39802,
+ [39802] = 39801, -- wall leaves
+ [39803] = 39804,
+ [39804] = 39803, -- tendrils
+ [39805] = 39806,
+ [39807] = 39808, -- water nymph
+ [39810] = 39809, -- water nymph
+ [42271] = 42272,
+ [42272] = 42271, -- seafarer table
+ [42291] = 42292,
+ [42292] = 42291, -- seashell lamp
+ [42293] = 42294,
+ [42294] = 42293, -- seashell lamp
+ [42295] = 42296,
+ [42296] = 42295, -- tentacle lamp
+ [42297] = 42298,
+ [42298] = 42297, -- tentacle lamp
+ [42299] = 42300,
+ [42300] = 42299, -- sea-devil wall lamp
+ [42301] = 42302,
+ [42302] = 42301, -- seafood bucket
+ [42324] = 42326,
+ [42326] = 42324, -- opulent table
+ [42325] = 42327,
+ [42327] = 42325, -- opulent table
+ [42346] = 42347,
+ [42347] = 42346, -- opulent floor lamp
+ [42348] = 42349,
+ [42349] = 42348, -- opulent floor lamp
+ [42363] = 42364, -- djinn lamp
+ [42365] = 42366, -- djinn lamp
}
local decayTo = Action()
function decayTo.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- item:transform(setting[item.itemid])
+ local itemId = item:getId()
+ if voices[itemId] then
+ local spectators = Game.getSpectators(fromPosition, false, true, 3, 3)
+ for _, spectator in ipairs(spectators) do
+ player:say(voices[itemId], TALKTYPE_MONSTER_SAY, false, spectator, fromPosition)
+ end
+ end
+
+ local newItemId = transformItems[itemId]
+ if newItemId then
+ item:transform(newItemId)
+ item:decay()
+ end
return true
end
-for index, value in pairs(setting) do
+for index in pairs(transformItems) do
decayTo:id(index)
end
diff --git a/data-canary/scripts/actions/other/dolls.lua b/data/scripts/actions/items/dolls.lua
similarity index 100%
rename from data-canary/scripts/actions/other/dolls.lua
rename to data/scripts/actions/items/dolls.lua
diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_amulet.lua b/data/scripts/actions/items/ferumbras_amulet.lua
similarity index 95%
rename from data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_amulet.lua
rename to data/scripts/actions/items/ferumbras_amulet.lua
index d92c496e165..dee32339a46 100644
--- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_amulet.lua
+++ b/data/scripts/actions/items/ferumbras_amulet.lua
@@ -1,10 +1,12 @@
local ferumbrasAscendantAmulet = Action()
+
function ferumbrasAscendantAmulet.onUse(player, item, fromPosition, target, toPosition, isHotkey)
local amulet = player:getSlotItem(CONST_SLOT_NECKLACE)
- if amulet ~= item or amulet ~= item then
+ if amulet ~= item then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to equip the amulet to try use it.")
return true
end
+
if item.itemid == 22767 then
if math.random(2) == 1 then
player:addHealth(1000, true, true)
@@ -13,10 +15,10 @@ function ferumbrasAscendantAmulet.onUse(player, item, fromPosition, target, toPo
player:addMana(1000, true, true)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Magical sparks whirl around the amulet as you use it and you was restored.")
end
+
item:transform(22768)
item:decay()
player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE)
- return true
elseif item.itemid == 22768 then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are tired of the last use of the amulet, you must wait for the recharge.")
end
diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_mana_keg.lua b/data/scripts/actions/items/ferumbras_mana_keg.lua
similarity index 99%
rename from data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_mana_keg.lua
rename to data/scripts/actions/items/ferumbras_mana_keg.lua
index 8ece01ed6e8..04bbc7b6e50 100644
--- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ferumbras_mana_keg.lua
+++ b/data/scripts/actions/items/ferumbras_mana_keg.lua
@@ -1,4 +1,5 @@
local ferumbrasAscendantManaKeg = Action()
+
function ferumbrasAscendantManaKeg.onUse(player, item, fromPosition, target, toPosition, isHotkey)
if item.itemid == 22769 then
player:addItem("ultimate mana potion", 10)
diff --git a/data-canary/scripts/actions/other/ladder_up.lua b/data/scripts/actions/items/ladder_up.lua
similarity index 64%
rename from data-canary/scripts/actions/other/ladder_up.lua
rename to data/scripts/actions/items/ladder_up.lua
index efea920c9b8..5ec5f7c5b67 100644
--- a/data-canary/scripts/actions/other/ladder_up.lua
+++ b/data/scripts/actions/items/ladder_up.lua
@@ -1,9 +1,9 @@
-local setting = { 1948, 1968, 5542, 20474, 20475, 28656, 31262 }
+local ladderTable = Game.getLadderIds()
local ladder = Action()
function ladder.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- if table.contains(setting, item.itemid) then
+ if table.contains(ladderTable, item.itemid) then
fromPosition:moveUpstairs()
else
fromPosition.z = fromPosition.z + 1
@@ -14,12 +14,9 @@ function ladder.onUse(player, item, fromPosition, target, toPosition, isHotkey)
return true
end
- player:teleportTo(fromPosition, false)
+ player:teleportTo(fromPosition, true)
return true
end
-for index, value in ipairs(setting) do
- ladder:id(value)
-end
-
+ladder:id(435, unpack(ladderTable))
ladder:register()
diff --git a/data-otservbr-global/scripts/actions/other/party_trumpet.lua b/data/scripts/actions/items/party_trumpet.lua
similarity index 100%
rename from data-otservbr-global/scripts/actions/other/party_trumpet.lua
rename to data/scripts/actions/items/party_trumpet.lua
index 71ee617ec69..a1cb77bf56d 100644
--- a/data-otservbr-global/scripts/actions/other/party_trumpet.lua
+++ b/data/scripts/actions/items/party_trumpet.lua
@@ -1,10 +1,10 @@
local partyTrumpet = Action()
function partyTrumpet.onUse(player, item, fromPosition, target, toPosition, isHotkey)
- item:transform(6573)
- item:decay()
player:say("TOOOOOOT!", TALKTYPE_MONSTER_SAY)
fromPosition:sendMagicEffect(CONST_ME_SOUND_BLUE)
+ item:transform(6573)
+ item:decay()
return true
end
diff --git a/data-otservbr-global/scripts/actions/other/roasted_meat.lua b/data/scripts/actions/items/roasted_meat.lua
similarity index 100%
rename from data-otservbr-global/scripts/actions/other/roasted_meat.lua
rename to data/scripts/actions/items/roasted_meat.lua
diff --git a/data/scripts/actions/items/surprise_bags.lua b/data/scripts/actions/items/surprise_bags.lua
new file mode 100644
index 00000000000..09c03e516db
--- /dev/null
+++ b/data/scripts/actions/items/surprise_bags.lua
@@ -0,0 +1,32 @@
+local settings = {
+ [6570] = { { 3598, 10 }, 6393, 6279, 6574, 6578, 6575, 6577, 6569, 6576, 6572, 2995, 14027, 14681 }, -- blue present
+ [6571] = { 6574, 3079, 6393, 6576, 6578, 2995, 14027, 3036, 5944, 3386, 3420, 3039, 5080, 2993, 3392, 3057, 5791 }, -- red present
+ [8853] = { { 3031, 10 }, 123, 2995, 2397, 651, 3218, 6574, 6393, 7377, 3578, 8778 }, -- surprise bag
+ [14751] = { { 9642, 15 }, { 3581, 15 }, 5917, 3273, 10302, 9019, 5928, 5926, 5927, 6095, 5918, 6097, 6098, 5461, 5090 }, -- surprise bag
+ [14759] = { { 6569, 10 }, { 6541, 10 }, { 6542, 10 }, { 6543, 10 }, { 6544, 10 }, { 6545, 10 }, 6574, 4839, 6570, 6571, 3215 }, -- surprise bag
+}
+
+local surpriseBag = Action()
+
+function surpriseBag.onUse(player, item, fromPosition)
+ local present = settings[item.itemid]
+ if not present then
+ return true
+ end
+
+ local gift = present[math.random(#present)]
+ local count = 1
+
+ if type(gift) == "table" then
+ count = math.random(gift[2])
+ gift = gift[1]
+ end
+
+ player:addItem(gift, count)
+ fromPosition:sendMagicEffect(CONST_ME_GIFT_WRAPS)
+ item:remove(1)
+ return true
+end
+
+surpriseBag:id(6570, 6571, 8853, 14751, 14759)
+surpriseBag:register()
diff --git a/data/scripts/actions/items/surprise_music_box.lua b/data/scripts/actions/items/surprise_music_box.lua
new file mode 100644
index 00000000000..05abbac3d08
--- /dev/null
+++ b/data/scripts/actions/items/surprise_music_box.lua
@@ -0,0 +1,34 @@
+local prize = {
+ { chance = 1, id = 3246, amount = 1 },
+ { chance = 2, id = 10227, amount = 1 },
+ { chance = 3, id = 11588, amount = 1 },
+ { chance = 4, id = 3549, amount = 1 },
+ { chance = 5, id = 3420, amount = 1 },
+ { chance = 10, id = ITEM_CRYSTAL_COIN, amount = 17 },
+ { chance = 20, id = ITEM_GOLD_COIN, amount = 1 },
+ { chance = 30, id = ITEM_CRYSTAL_COIN, amount = 1 },
+ { chance = 40, id = ITEM_GOLD_COIN, amount = 50 },
+ { chance = 50, id = ITEM_PLATINUM_COIN, amount = 15 },
+ { chance = 90, id = ITEM_GOLD_COIN, amount = 80 },
+}
+
+local surpriseBox = Action()
+
+function surpriseBox.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ local number = math.random(1, 100)
+ local cumulativeChance = 0
+
+ for _, prizeEntry in ipairs(prize) do
+ cumulativeChance = cumulativeChance + prizeEntry.chance
+ if number <= cumulativeChance then
+ player:getPosition():sendMagicEffect(CONST_ME_POFF)
+ player:addItem(prizeEntry.id, prizeEntry.amount)
+ item:remove()
+ break
+ end
+ end
+ return true
+end
+
+surpriseBox:id(12045)
+surpriseBox:register()
diff --git a/data/scripts/actions/items/vessels.lua b/data/scripts/actions/items/vessels.lua
new file mode 100644
index 00000000000..2d6fe19bf00
--- /dev/null
+++ b/data/scripts/actions/items/vessels.lua
@@ -0,0 +1,26 @@
+local config = {
+ [37572] = CONST_ME_GAZHARAGOTH,
+ [37573] = CONST_ME_FERUMBRAS_1,
+ [37574] = CONST_ME_MAD_MAGE,
+ [37575] = CONST_ME_HORESTIS,
+ [37576] = CONST_ME_DEVOVORGA,
+}
+
+local vessels = Action()
+
+function vessels.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ local vessel = config[item.itemid]
+ if not vessel or not target:isPlayer() then
+ return true
+ end
+
+ toPosition:sendMagicEffect(vessel)
+ item:remove(1)
+ return true
+end
+
+for index in pairs(config) do
+ vessels:id(index)
+end
+
+vessels:register()
diff --git a/data-otservbr-global/scripts/actions/other/bath_tub.lua b/data/scripts/actions/objects/bath_tub_drain.lua
similarity index 99%
rename from data-otservbr-global/scripts/actions/other/bath_tub.lua
rename to data/scripts/actions/objects/bath_tub_drain.lua
index cd1b3238ca6..a09886a2ad1 100644
--- a/data-otservbr-global/scripts/actions/other/bath_tub.lua
+++ b/data/scripts/actions/objects/bath_tub_drain.lua
@@ -1,4 +1,5 @@
local bathtubDrain = Action()
+
function bathtubDrain.onUse(player, item, fromPosition, itemEx, toPosition)
local tile = Tile(fromPosition)
if tile:getTopCreature() then
diff --git a/data/scripts/actions/tools/crushers.lua b/data/scripts/actions/tools/crushers.lua
new file mode 100644
index 00000000000..99c3102616d
--- /dev/null
+++ b/data/scripts/actions/tools/crushers.lua
@@ -0,0 +1,86 @@
+local config = {
+ maxGemBreak = 10,
+ fragmentGems = {
+ small = { ids = { 44602, 44605, 44608, 44611 }, fragment = 46625, range = { 1, 4 } },
+ medium = { ids = { 44603, 44606, 44609, 44612 }, fragment = 46625, range = { 2, 8 } },
+ great = { ids = { 44604, 44607, 44610, 44613 }, fragment = 46626, range = { 1, 4 } },
+ },
+}
+
+local function getGemData(gemId)
+ for _, gemData in pairs(config.fragmentGems) do
+ if table.contains(gemData.ids, gemId) then
+ return gemData.fragment, gemData.range
+ end
+ end
+ return nil
+end
+
+local amberCrusher = Action()
+
+function amberCrusher.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ if not target or not target:isItem() or target:getId() == item:getId() or player:getItemCount(target:getId()) <= 0 then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the crusher on a valid gem in your inventory.")
+ return true
+ end
+
+ local fragmentType, fragmentRange = getGemData(target:getId())
+ if not fragmentType then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This item can't be broken into fragments.")
+ return true
+ end
+
+ local breakAmount = (target:getCount() >= config.maxGemBreak) and config.maxGemBreak or 1
+ target:remove(breakAmount)
+
+ for _ = 1, breakAmount do
+ player:addItem(fragmentType, math.random(fragmentRange[1], fragmentRange[2]))
+ end
+
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have broken the gem into fragments.")
+ return true
+end
+
+amberCrusher:id(46628)
+amberCrusher:register()
+
+local crusher = Action()
+
+function crusher.onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ if not target or not target:isItem() or target:getId() == item:getId() or player:getItemCount(target:getId()) <= 0 then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use the crusher on a valid gem in your inventory.")
+ return true
+ end
+
+ local fragmentType, fragmentRange = getGemData(target:getId())
+ if not fragmentType then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This item can't be broken into fragments.")
+ return true
+ end
+
+ local crusherCharges = item:getAttribute(ITEM_ATTRIBUTE_CHARGES)
+ if not crusherCharges or crusherCharges <= 0 then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your crusher has no more charges.")
+ return true
+ end
+
+ target:remove(1)
+ player:addItem(fragmentType, math.random(fragmentRange[1], fragmentRange[2]))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have broken the gem into fragments.")
+
+ crusherCharges = crusherCharges - 1
+ if crusherCharges > 0 then
+ local container = item:getParent()
+ item:setAttribute(ITEM_ATTRIBUTE_CHARGES, crusherCharges)
+ if container:isContainer() then
+ player:sendUpdateContainer(container)
+ end
+ else
+ item:remove()
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your crusher has been consumed.")
+ end
+ return true
+end
+
+crusher:id(46627)
+crusher:register()
diff --git a/data-otservbr-global/scripts/creaturescripts/monster/spawn_system.lua b/data/scripts/creaturescripts/monster/spawn_system.lua
similarity index 99%
rename from data-otservbr-global/scripts/creaturescripts/monster/spawn_system.lua
rename to data/scripts/creaturescripts/monster/spawn_system.lua
index 580dba6d07c..710585cced3 100644
--- a/data-otservbr-global/scripts/creaturescripts/monster/spawn_system.lua
+++ b/data/scripts/creaturescripts/monster/spawn_system.lua
@@ -1,4 +1,5 @@
local monsterDeath = CreatureEvent("monsterDeath")
+
function monsterDeath.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamageUnjustified)
if creature and creature:isMonster() then
local self = creature:getStorageValue(MonsterStorage.Spawn.monster_spawn_object)
@@ -12,6 +13,7 @@ end
monsterDeath:register()
local monsterDeathBoss = CreatureEvent("monsterDeathBoss")
+
function monsterDeathBoss.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamageUnjustified)
if creature and creature:isMonster() then
local self = creature:getStorageValue(MonsterStorage.Spawn.monster_spawn_object)
diff --git a/data-canary/scripts/creaturescripts/extended_opcode.lua b/data/scripts/creaturescripts/others/#extended_opcode.lua
similarity index 100%
rename from data-canary/scripts/creaturescripts/extended_opcode.lua
rename to data/scripts/creaturescripts/others/#extended_opcode.lua
diff --git a/data/scripts/creaturescripts/player/adventure_blessing_login.lua b/data/scripts/creaturescripts/player/adventure_blessing_login.lua
index 8ebf88a72e9..79c694d73bc 100644
--- a/data/scripts/creaturescripts/player/adventure_blessing_login.lua
+++ b/data/scripts/creaturescripts/player/adventure_blessing_login.lua
@@ -1,4 +1,4 @@
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua")
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
local adventurerBlessingLogin = CreatureEvent("AdventurerBlessingLogin")
diff --git a/data/scripts/creaturescripts/player/login.lua b/data/scripts/creaturescripts/player/login.lua
index 5f9f0e695f4..fe52be71b06 100644
--- a/data/scripts/creaturescripts/player/login.lua
+++ b/data/scripts/creaturescripts/player/login.lua
@@ -80,7 +80,7 @@ function playerLoginGlobal.onLogin(player)
end
-- Send Recruiter Outfit
- local resultId = db.storeQuery("SELECT `recruiter` FROM `accounts` WHERE `id`= " .. getAccountNumberByPlayerName(getPlayerName(player)))
+ local resultId = db.storeQuery("SELECT `recruiter` FROM `accounts` WHERE `id`= " .. Game.getPlayerAccountId(getPlayerName(player)))
if resultId then
local recruiterStatus = Result.getNumber(resultId, "recruiter")
local sex = player:getSex()
@@ -118,19 +118,19 @@ function playerLoginGlobal.onLogin(player)
-- Updates the player's VIP status and executes corresponding actions if applicable.
if configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) then
- local isVipNow = player:isVip()
- local wasVip = player:kv():scoped("account"):get("vip-system") or false
+ local isCurrentlyVip = player:isVip()
+ local hadVipStatus = player:kv():scoped("account"):get("vip-system") or false
- if wasVip ~= isVipNow then
- if wasVip then
+ if hadVipStatus ~= isCurrentlyVip then
+ if hadVipStatus then
player:onRemoveVip()
else
player:onAddVip(player:getVipDays())
end
end
- if isVipNow then
- CheckPremiumAndPrint(player, MESSAGE_LOGIN)
+ if isCurrentlyVip then
+ player:sendVipStatus()
end
end
diff --git a/data/scripts/globalevents/update_guild_war_status.lua b/data/scripts/globalevents/update_guild_war_status.lua
new file mode 100644
index 00000000000..e499d5aa22e
--- /dev/null
+++ b/data/scripts/globalevents/update_guild_war_status.lua
@@ -0,0 +1,10 @@
+local updateGuildWarStatus = GlobalEvent("UpdateGuildWarStatus")
+
+function updateGuildWarStatus.onThink(interval)
+ local currentTime = os.time()
+ db.query(string.format("UPDATE `guild_wars` SET `status` = 4, `ended` = %d WHERE `status` = 1 AND `ended` != 0 AND `ended` < %d", currentTime, currentTime))
+ return true
+end
+
+updateGuildWarStatus:interval(60000)
+updateGuildWarStatus:register()
diff --git a/data/scripts/lib/register_spells.lua b/data/scripts/lib/register_spells.lua
index 8c549859640..f2e7cacee3d 100644
--- a/data/scripts/lib/register_spells.lua
+++ b/data/scripts/lib/register_spells.lua
@@ -386,7 +386,7 @@ AREA_RING1_BURST3 = {
{ 0, 0, 1, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 1, 1, 1, 0, 0, 0, 1, 1, 1 },
- { 1, 1, 1, 0, 3, 0, 1, 1, 1 },
+ { 1, 1, 1, 0, 2, 0, 1, 1, 1 },
{ 1, 1, 1, 0, 0, 0, 1, 1, 1 },
{ 0, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 0, 0 },
diff --git a/data-otservbr-global/scripts/movements/others/bath_tub.lua b/data/scripts/movements/bath_tub.lua
similarity index 64%
rename from data-otservbr-global/scripts/movements/others/bath_tub.lua
rename to data/scripts/movements/bath_tub.lua
index 7ff7d1fe841..258efae4bb7 100644
--- a/data-otservbr-global/scripts/movements/others/bath_tub.lua
+++ b/data/scripts/movements/bath_tub.lua
@@ -1,35 +1,38 @@
-local playerBathTub = 26087
-
local bathtubEnter = MoveEvent()
function bathtubEnter.onStepIn(creature, item, position, fromPosition)
- if not creature:isPlayer() then
- return false
+ local player = creature:getPlayer()
+ if not player then
+ return true
end
local condition = Condition(CONDITION_OUTFIT)
- condition:setOutfit({ lookTypeEx = playerBathTub })
+ condition:setOutfit({ lookTypeEx = 26087 })
condition:setTicks(-1)
position:sendMagicEffect(CONST_ME_WATERSPLASH)
item:transform(BATHTUB_FILLED_NOTMOVABLE)
- creature:addCondition(condition)
+ player:addCondition(condition)
return true
end
+bathtubEnter:type("stepin")
bathtubEnter:id(BATHTUB_FILLED)
bathtubEnter:register()
local bathtubExit = MoveEvent()
+
function bathtubExit.onStepOut(creature, item, position, fromPosition)
- if not creature:isPlayer() then
- return false
+ local player = creature:getPlayer()
+ if not player then
+ return true
end
item:transform(BATHTUB_FILLED)
- creature:removeCondition(CONDITION_OUTFIT)
+ player:removeCondition(CONDITION_OUTFIT)
return true
end
+bathtubExit:type("stepout")
bathtubExit:id(BATHTUB_FILLED_NOTMOVABLE)
bathtubExit:register()
diff --git a/data/scripts/spells/attack/divine_grenade.lua b/data/scripts/spells/attack/divine_grenade.lua
index b1dc6399c7d..488962cb2f8 100644
--- a/data/scripts/spells/attack/divine_grenade.lua
+++ b/data/scripts/spells/attack/divine_grenade.lua
@@ -35,7 +35,7 @@ local explodeGrenade = function(position, playerId)
end
local var = {}
- var.instantName = "Divine Grenade Explode"
+ var.instantName = "Divine Grenade"
var.runeName = ""
var.type = 2 -- VARIANT_POSITION
var.pos = position
diff --git a/data/scripts/spells/attack/energy_beam.lua b/data/scripts/spells/attack/energy_beam.lua
index d3be218c0ca..049470f0ecb 100644
--- a/data/scripts/spells/attack/energy_beam.lua
+++ b/data/scripts/spells/attack/energy_beam.lua
@@ -28,11 +28,10 @@ local spell = Spell("instant")
function spell.onCastSpell(creature, var)
local player = creature:getPlayer()
- if creature and player and player:instantSkillWOD("Beam Mastery") then
- var.runeName = "Beam Mastery"
- return combatWOD:execute(creature, var)
+ if not creature or not player then
+ return false
end
- return combat:execute(creature, var)
+ return player:instantSkillWOD("Beam Mastery") and combatWOD:execute(creature, var) or combat:execute(creature, var)
end
spell:group("attack")
diff --git a/data/scripts/spells/attack/executioners_throw.lua b/data/scripts/spells/attack/executioners_throw.lua
index 2f2220625c5..08d700bfe54 100644
--- a/data/scripts/spells/attack/executioners_throw.lua
+++ b/data/scripts/spells/attack/executioners_throw.lua
@@ -40,28 +40,11 @@ function spell.onCastSpell(creature, var)
local grade = creature:revelationStageWOD("Executioner's Throw")
if grade == 0 then
- creature:sendCancelMessage("You cannot cast this spell")
+ creature:sendCancelMessage("You need to learn this spell first")
creature:getPosition():sendMagicEffect(CONST_ME_POFF)
return false
end
-
- local cooldown = 0
- if grade >= 3 then
- cooldown = 10
- elseif grade >= 2 then
- cooldown = 14
- elseif grade >= 1 then
- cooldown = 18
- end
-
- var.instantName = "Executioner's Throw"
- if combat:execute(creature, var) then
- local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 261)
- condition:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition)
- return true
- end
- return false
+ return combat:execute(creature, var)
end
spell:group("attack")
@@ -75,7 +58,7 @@ spell:range(5)
spell:needTarget(true)
spell:blockWalls(true)
spell:needWeapon(true)
-spell:cooldown(1000) -- Cooldown is calculated on the casting
+spell:cooldown(18 * 1000)
spell:groupCooldown(2 * 1000)
spell:needLearn(true)
spell:vocation("knight;true", "elite knight;true")
diff --git a/data/scripts/spells/attack/great_death_beam.lua b/data/scripts/spells/attack/great_death_beam.lua
index 02a17c78f41..84c75132d76 100644
--- a/data/scripts/spells/attack/great_death_beam.lua
+++ b/data/scripts/spells/attack/great_death_beam.lua
@@ -17,6 +17,7 @@ end
local combat1 = createCombat(initCombat, AREA_BEAM6)
local combat2 = createCombat(initCombat, AREA_BEAM7)
local combat3 = createCombat(initCombat, AREA_BEAM8)
+local combat = { combat1, combat2, combat3 }
local spell = Spell("instant")
@@ -28,32 +29,15 @@ function spell.onCastSpell(creature, var)
local grade = creature:upgradeSpellsWOD("Great Death Beam")
if grade == WHEEL_GRADE_NONE then
- creature:sendCancelMessage("You cannot cast this spell")
+ creature:sendCancelMessage("You need to learn this spell first")
creature:getPosition():sendMagicEffect(CONST_ME_POFF)
return false
end
- local cooldown = { 10, 8, 6 }
- var.runeName = "Beam Mastery"
- local executed = false
-
- local combat = { combat1, combat2, combat3 }
-
- executed = combat[grade]:execute(creature, var)
-
- if executed then
- local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 260)
- local executedCooldown = cooldown[grade]
- if executedCooldown ~= nil then
- condition:setTicks((executedCooldown * 1000))
- end
- creature:addCondition(condition)
- return true
- end
- return false
+ return combat[grade]:execute(creature, var)
end
-spell:group("attack")
+spell:group("attack", "greatbeams")
spell:id(260)
spell:name("Great Death Beam")
spell:words("exevo max mort")
@@ -62,8 +46,8 @@ spell:mana(140)
spell:isPremium(false)
spell:needDirection(true)
spell:blockWalls(true)
-spell:cooldown(1000) -- Cooldown is calculated on the casting
-spell:groupCooldown(2 * 1000)
+spell:cooldown(10 * 1000)
+spell:groupCooldown(2 * 1000, 6 * 1000)
spell:needLearn(true)
spell:vocation("sorcerer;true", "master sorcerer;true")
spell:register()
diff --git a/data/scripts/spells/attack/great_energy_beam.lua b/data/scripts/spells/attack/great_energy_beam.lua
index aae93e95c9a..f6b61f19fa4 100644
--- a/data/scripts/spells/attack/great_energy_beam.lua
+++ b/data/scripts/spells/attack/great_energy_beam.lua
@@ -28,15 +28,13 @@ local spell = Spell("instant")
function spell.onCastSpell(creature, var)
local player = creature:getPlayer()
- if creature and player and player:instantSkillWOD("Beam Mastery") then
- var.runeName = "Beam Mastery"
- return combatWOD:execute(creature, var)
+ if not creature or not player then
+ return false
end
-
- return combat:execute(creature, var)
+ return player:instantSkillWOD("Beam Mastery") and combatWOD:execute(creature, var) or combat:execute(creature, var)
end
-spell:group("attack")
+spell:group("attack", "greatbeams")
spell:id(23)
spell:name("Great Energy Beam")
spell:words("exevo gran vis lux")
@@ -47,7 +45,7 @@ spell:isPremium(false)
spell:needDirection(true)
spell:blockWalls(true)
spell:cooldown(6 * 1000)
-spell:groupCooldown(2 * 1000)
+spell:groupCooldown(2 * 1000, 6 * 1000)
spell:needLearn(false)
spell:vocation("sorcerer;true", "master sorcerer;true")
spell:register()
diff --git a/data/scripts/spells/attack/ice_burst.lua b/data/scripts/spells/attack/ice_burst.lua
index 9e1560f9dc9..fedcd9d5a04 100644
--- a/data/scripts/spells/attack/ice_burst.lua
+++ b/data/scripts/spells/attack/ice_burst.lua
@@ -14,50 +14,27 @@ combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
local spell = Spell("instant")
function spell.onCastSpell(creature, var)
- if not creature or not creature:isPlayer() then
- return false
- end
-
local grade = creature:revelationStageWOD("Twin Burst")
if grade == 0 then
- creature:sendCancelMessage("You cannot cast this spell")
+ creature:sendCancelMessage("You need to learn this spell first")
creature:getPosition():sendMagicEffect(CONST_ME_POFF)
return false
end
- local cooldown = 0
- if grade >= 3 then
- cooldown = 14
- elseif grade >= 2 then
- cooldown = 18
- elseif grade >= 1 then
- cooldown = 22
- end
-
- var.instantName = "Twin Burst"
- if combat:execute(creature, var) then
- -- Ice cooldown
- local condition1 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 262)
- condition1:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition1)
- -- Earth cooldown
- local condition2 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 263)
- condition2:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition2)
- return true
- end
- return false
+ return combat:execute(creature, var)
end
-spell:group("attack")
+spell:group("attack", "burstsofnature")
spell:id(262)
spell:name("Ice Burst")
spell:words("exevo ulus frigo")
+spell:castSound(SOUND_EFFECT_TYPE_SPELL_ETERNAL_WINTER)
spell:level(300)
spell:mana(230)
spell:isPremium(true)
-spell:cooldown(1000) -- Cooldown is calculated on the casting
-spell:groupCooldown(2 * 1000)
+spell:isSelfTarget(true)
+spell:cooldown(22 * 1000)
+spell:groupCooldown(2 * 1000, 22 * 1000)
spell:needLearn(true)
spell:vocation("druid;true", "elder druid;true")
spell:register()
diff --git a/data/scripts/spells/attack/terra_burst.lua b/data/scripts/spells/attack/terra_burst.lua
index 8a805c0ba48..15ce35c4912 100644
--- a/data/scripts/spells/attack/terra_burst.lua
+++ b/data/scripts/spells/attack/terra_burst.lua
@@ -14,50 +14,27 @@ combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
local spell = Spell("instant")
function spell.onCastSpell(creature, var)
- if not creature or not creature:isPlayer() then
- return false
- end
-
local grade = creature:revelationStageWOD("Twin Burst")
if grade == 0 then
- creature:sendCancelMessage("You cannot cast this spell")
+ creature:sendCancelMessage("You need to learn this spell first")
creature:getPosition():sendMagicEffect(CONST_ME_POFF)
return false
end
- local cooldown = 0
- if grade >= 3 then
- cooldown = 14
- elseif grade >= 2 then
- cooldown = 18
- elseif grade >= 1 then
- cooldown = 22
- end
-
- var.instantName = "Twin Burst"
- if combat:execute(creature, var) then
- -- Ice cooldown
- local condition1 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 262)
- condition1:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition1)
- -- Earth cooldown
- local condition2 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 263)
- condition2:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition2)
- return true
- end
- return false
+ return combat:execute(creature, var)
end
-spell:group("attack")
+spell:group("attack", "burstsofnature")
spell:id(263)
spell:name("Terra Burst")
spell:words("exevo ulus tera")
+spell:castSound(SOUND_EFFECT_TYPE_SPELL_WRATH_OF_NATURE)
spell:level(300)
spell:mana(230)
spell:isPremium(true)
-spell:cooldown(1000) -- Cooldown is calculated on the casting
-spell:groupCooldown(2 * 1000)
+spell:isSelfTarget(true)
+spell:cooldown(22 * 1000)
+spell:groupCooldown(2 * 1000, 22 * 1000)
spell:needLearn(true)
spell:vocation("druid;true", "elder druid;true")
spell:register()
diff --git a/data/scripts/spells/support/divine_empowerment.lua b/data/scripts/spells/support/divine_empowerment.lua
index e05203359f8..248f01a6e0f 100644
--- a/data/scripts/spells/support/divine_empowerment.lua
+++ b/data/scripts/spells/support/divine_empowerment.lua
@@ -26,18 +26,6 @@ function spell.onCastSpell(creature, var)
return false
end
- local cooldown = 0
- if grade >= 3 then
- cooldown = 24
- elseif grade >= 2 then
- cooldown = 28
- elseif grade >= 1 then
- cooldown = 32
- end
- local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 268)
- condition:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN))
- creature:addCondition(condition)
-
local position = creature:getPosition()
for x = -1, 1 do
for y = -1, 1 do
@@ -63,7 +51,7 @@ spell:isPremium(true)
spell:range(7)
spell:isSelfTarget(true)
spell:isAggressive(false)
-spell:cooldown(1000) -- Cooldown is calculated on the casting
+spell:cooldown(32 * 1000)
spell:groupCooldown(2 * 1000)
spell:needLearn(true)
spell:vocation("paladin;true", "royal paladin;true")
diff --git a/data/scripts/spells/support/sharpshooter.lua b/data/scripts/spells/support/sharpshooter.lua
index 568fec86e00..e5111781562 100644
--- a/data/scripts/spells/support/sharpshooter.lua
+++ b/data/scripts/spells/support/sharpshooter.lua
@@ -4,9 +4,9 @@ local combat = Combat()
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MAGIC_GREEN)
combat:setParameter(COMBAT_PARAM_AGGRESSIVE, false)
-local speed = Condition(CONDITION_HASTE)
+local speed = Condition(CONDITION_PARALYZE)
speed:setParameter(CONDITION_PARAM_TICKS, spellDuration)
-speed:setFormula(0.7, 0, 0.7, 0)
+speed:setFormula(0.7, 56, 0.7, 56)
combat:addCondition(speed)
local exhaustHealGroup = Condition(CONDITION_SPELLGROUPCOOLDOWN)
diff --git a/data/scripts/systems/item_tiers.lua b/data/scripts/systems/item_tiers.lua
index 06a8321a034..cc7a2a2697d 100644
--- a/data/scripts/systems/item_tiers.lua
+++ b/data/scripts/systems/item_tiers.lua
@@ -90,7 +90,7 @@ local itemTierClassifications = {
},
}
--- Item tier with gold price for uprading it
+-- Item tier with gold price for upgrading it
for classificationId, classificationTable in ipairs(itemTierClassifications) do
local itemClassification = Game.createItemClassification(classificationId)
local classification = {}
diff --git a/data/scripts/talkactions/gm/ban.lua b/data/scripts/talkactions/gm/ban.lua
index 0ab07040333..4d7569c78f5 100644
--- a/data/scripts/talkactions/gm/ban.lua
+++ b/data/scripts/talkactions/gm/ban.lua
@@ -1,48 +1,48 @@
-local banDays = 7
-
local ban = TalkAction("/ban")
function ban.onSay(player, words, param)
-- create log
logCommand(player, words, param)
- if param == "" then
- player:sendCancelMessage("Command param required.")
+ local params = param:split(",")
+ if #params < 3 then
+ player:sendCancelMessage("Command requires 3 parameters: /ban , , ")
return true
end
- local name = param
- local reason = ""
+ local playerName = params[1]:trim()
+ local banDuration = tonumber(params[2]:trim())
+ local banReason = params[3]:trim()
- local separatorPos = param:find(",")
- if separatorPos then
- name = param:sub(0, separatorPos - 1)
- reason = string.trim(param:sub(separatorPos + 1))
+ if not banDuration or banDuration <= 0 then
+ player:sendCancelMessage("Ban duration must be a positive number.")
+ return true
end
- local accountId = getAccountNumberByPlayerName(name)
+ local accountId = Game.getPlayerAccountId(playerName)
if accountId == 0 then
return true
end
local resultId = db.storeQuery("SELECT 1 FROM `account_bans` WHERE `account_id` = " .. accountId)
- if resultId ~= false then
- Result.free(resultId)
+ if resultId then
+ result.free(resultId)
return true
end
- local timeNow = os.time()
- db.query("INSERT INTO `account_bans` (`account_id`, `reason`, `banned_at`, `expires_at`, `banned_by`) VALUES (" .. accountId .. ", " .. db.escapeString(reason) .. ", " .. timeNow .. ", " .. timeNow + (banDays * 86400) .. ", " .. player:getGuid() .. ")")
+ local currentTime = os.time()
+ local expirationTime = currentTime + (banDuration * 24 * 60 * 60)
+ db.query(string.format("INSERT INTO `account_bans` (`account_id`, `reason`, `banned_at`, `expires_at`, `banned_by`) VALUES (%d, %s, %d, %d, %d)", accountId, db.escapeString(banReason), currentTime, expirationTime, player:getGuid()))
- local target = Player(name)
+ local target = Player(playerName)
if target then
- local text = target:getName() .. " has been banned"
- player:sendTextMessage(MESSAGE_ADMINISTRATOR, text)
- Webhook.sendMessage("Player Banned", text .. " reason: " .. reason .. ". (by: " .. player:getName() .. ")", WEBHOOK_COLOR_YELLOW, announcementChannels["serverAnnouncements"])
+ player:sendTextMessage(MESSAGE_ADMINISTRATOR, string.format("%s has been banned for %d days.", target:getName(), banDuration))
target:remove()
+ Webhook.sendMessage("Player Banned", string.format("%s has been banned for %d days. Reason: %s (by: %s)", target:getName(), banDuration, banReason, player:getName()), WEBHOOK_COLOR_YELLOW, announcementChannels["serverAnnouncements"])
else
- player:sendTextMessage(MESSAGE_ADMINISTRATOR, name .. " has been banned.")
+ player:sendTextMessage(MESSAGE_ADMINISTRATOR, string.format("%s has been banned for %d days.", playerName, banDuration))
end
+ return true
end
ban:separator(" ")
diff --git a/data/scripts/talkactions/gm/bless_status.lua b/data/scripts/talkactions/gm/bless_status.lua
index 7cb861947dd..a316330db31 100644
--- a/data/scripts/talkactions/gm/bless_status.lua
+++ b/data/scripts/talkactions/gm/bless_status.lua
@@ -1,4 +1,4 @@
-dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua")
+dofile(CORE_DIRECTORY .. "/libs/systems/blessing.lua")
local blessStatus = TalkAction("/bless")
@@ -6,7 +6,7 @@ function blessStatus.onSay(player, words, param)
-- create log
logCommand(player, words, param)
- Blessings.sendBlessStatus(player)
+ player:sendBlessStatus()
return true
end
diff --git a/data/scripts/talkactions/gm/gold_highscore.lua b/data/scripts/talkactions/gm/gold_highscore.lua
index de923712887..a68df6900a5 100644
--- a/data/scripts/talkactions/gm/gold_highscore.lua
+++ b/data/scripts/talkactions/gm/gold_highscore.lua
@@ -1,28 +1,33 @@
-local gold_rank = TalkAction("/goldrank")
+local goldRank = TalkAction("/goldrank")
-function gold_rank.onSay(player, words, param)
+function goldRank.onSay(player, words, param)
-- create log
logCommand(player, words, param)
- local resultId = db.storeQuery("SELECT `balance`, `name` FROM `players` WHERE group_id < 3 ORDER BY balance DESC LIMIT 10")
- if resultId ~= false then
- local str = ""
- local x = 0
- repeat
- x = x + 1
- str = str .. "\n" .. x .. "- " .. Result.getString(resultId, "name") .. " (" .. Result.getNumber(resultId, "balance") .. ")."
- until not Result.next(resultId)
- Result.free(resultId)
- if str == "" then
- str = "No highscore to show."
- end
- player:popupFYI("Current gold highscore for this server:\n" .. str)
- else
+ local highscoreQuery = db.storeQuery("SELECT `balance`, `name` FROM `players` WHERE group_id < 3 ORDER BY balance DESC LIMIT 10")
+ if not highscoreQuery then
player:sendCancelMessage("No highscore to show.")
+ return true
end
+
+ local highscoreList = ""
+ local rank = 0
+ repeat
+ rank = rank + 1
+ local playerName = Result.getString(highscoreQuery, "name")
+ local playerBalance = FormatNumber(Result.getNumber(highscoreQuery, "balance"))
+ highscoreList = highscoreList .. "\n" .. rank .. "- " .. playerName .. " (" .. playerBalance .. ")."
+ until not Result.next(highscoreQuery)
+
+ Result.free(highscoreQuery)
+ if highscoreList == "" then
+ highscoreList = "No highscore to show."
+ end
+
+ player:popupFYI("Current gold highscore for this server:\n" .. highscoreList)
return true
end
-gold_rank:separator(" ")
-gold_rank:groupType("gamemaster")
-gold_rank:register()
+goldRank:separator(" ")
+goldRank:groupType("gamemaster")
+goldRank:register()
diff --git a/data/scripts/talkactions/god/add_addon.lua b/data/scripts/talkactions/god/add_addon.lua
index 026336e270e..bbcd21c94fa 100644
--- a/data/scripts/talkactions/god/add_addon.lua
+++ b/data/scripts/talkactions/god/add_addon.lua
@@ -1,45 +1,305 @@
-local addons = TalkAction("/addaddon")
+local addaddon = TalkAction("/addaddon")
-function addons.onSay(player, words, param)
- -- create log
- logCommand(player, words, param)
+local looktypes = {
+ -- Female Outfits
+ 136,
+ 137,
+ 138,
+ 139,
+ 140,
+ 141,
+ 142,
+ 147,
+ 148,
+ 149,
+ 150,
+ 155,
+ 156,
+ 157,
+ 158,
+ 252,
+ 269,
+ 270,
+ 279,
+ 288,
+ 324,
+ 329,
+ 336,
+ 366,
+ 431,
+ 433,
+ 464,
+ 466,
+ 471,
+ 513,
+ 514,
+ 542,
+ 575,
+ 578,
+ 618,
+ 620,
+ 632,
+ 635,
+ 636,
+ 664,
+ 666,
+ 683,
+ 694,
+ 696,
+ 698,
+ 724,
+ 732,
+ 745,
+ 749,
+ 759,
+ 845,
+ 852,
+ 874,
+ 885,
+ 900,
+ 909,
+ 929,
+ 956,
+ 958,
+ 963,
+ 965,
+ 967,
+ 969,
+ 971,
+ 973,
+ 975,
+ 1020,
+ 1024,
+ 1043,
+ 1050,
+ 1057,
+ 1070,
+ 1095,
+ 1103,
+ 1128,
+ 1147,
+ 1162,
+ 1174,
+ 1187,
+ 1203,
+ 1205,
+ 1207,
+ 1211,
+ 1244,
+ 1246,
+ 1252,
+ 1271,
+ 1280,
+ 1283,
+ 1289,
+ 1293,
+ 1323,
+ 1332,
+ 1339,
+ 1372,
+ 1383,
+ 1385,
+ 1387,
+ 1416,
+ 1437,
+ 1445,
+ 1450,
+ 1456,
+ 1461,
+ 1490,
+ 1501,
+ 1569,
+ 1576,
+ 1582,
+ 1598,
+ 1613,
+ 1619,
+ 1663,
+ 1676,
+ 1681,
- local target
- local split = param:split(",")
- local name = split[1]
+ -- Male Outfits
+ 1714,
+ 1723,
+ 1726,
+ 1746,
+ 1775,
+ 1777,
+ 128,
+ 129,
+ 130,
+ 131,
+ 132,
+ 133,
+ 134,
+ 143,
+ 144,
+ 145,
+ 146,
+ 151,
+ 152,
+ 153,
+ 154,
+ 251,
+ 268,
+ 273,
+ 278,
+ 289,
+ 325,
+ 328,
+ 335,
+ 367,
+ 430,
+ 432,
+ 463,
+ 465,
+ 472,
+ 512,
+ 516,
+ 541,
+ 574,
+ 577,
+ 610,
+ 619,
+ 633,
+ 634,
+ 637,
+ 665,
+ 667,
+ 684,
+ 695,
+ 697,
+ 699,
+ 725,
+ 733,
+ 746,
+ 750,
+ 760,
+ 846,
+ 853,
+ 873,
+ 884,
+ 899,
+ 908,
+ 931,
+ 955,
+ 957,
+ 962,
+ 964,
+ 966,
+ 968,
+ 970,
+ 972,
+ 974,
+ 1021,
+ 1023,
+ 1042,
+ 1051,
+ 1056,
+ 1069,
+ 1094,
+ 1102,
+ 1127,
+ 1146,
+ 1161,
+ 1173,
+ 1186,
+ 1202,
+ 1204,
+ 1206,
+ 1210,
+ 1243,
+ 1245,
+ 1251,
+ 1270,
+ 1279,
+ 1282,
+ 1288,
+ 1292,
+ 1322,
+ 1331,
+ 1338,
+ 1371,
+ 1382,
+ 1384,
+ 1386,
+ 1415,
+ 1436,
+ 1444,
+ 1449,
+ 1457,
+ 1460,
+ 1489,
+ 1500,
+ 1568,
+ 1575,
+ 1581,
+ 1597,
+ 1612,
+ 1618,
+ 1662,
+ 1675,
+ 1680,
+ 1713,
+ 1722,
+ 1725,
+ 1745,
+ 1774,
+ 1776,
+}
+
+function addaddon.onSay(player, words, param)
+ -- Create log
+ logCommand(player, words, param)
if param == "" then
- target = player:getTarget()
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Gives players the ability to wear addon for a specific outfit. Usage: /addaddon , ")
- return true
- end
- else
- target = Player(name)
+ player:sendCancelMessage("Command param required.")
+ return true
end
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Player " .. name .. " is currently not online.")
+ local split = param:split(",")
+ if #split < 3 then
+ player:sendCancelMessage("Usage: /addaddon , , ")
return true
end
- local looktype = tonumber(split[2])
- if not looktype then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Invalid looktype.")
+ local playerName = split[1]
+ local target = Player(playerName)
+
+ if not target then
+ player:sendCancelMessage("Player not found.")
return true
end
- local addons = tonumber(split[3])
- if not addons or addons < 0 or addons > 3 then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Invalid addon.")
+ local addonParam = string.trim(split[2])
+ local addonValue = tonumber(string.trim(split[3]))
+
+ if not addonValue or addonValue < 0 or addonValue > 3 then
+ player:sendCancelMessage("Invalid addon value. It should be between 0 and 3.")
return true
end
- target:addOutfitAddon(looktype, addons)
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Addon for looktype " .. looktype .. "a for " .. target:getName() .. " set to " .. addons .. ".")
+ if addonParam == "all" then
+ for _, looktype in ipairs(looktypes) do
+ target:addOutfitAddon(looktype, addonValue)
+ end
+
+ target:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added addon %d to all your looktypes.", player:getName(), addonValue))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added addon %d to all looktypes of player %s.", addonValue, target:getName()))
+ else
+ local looktype = tonumber(addonParam)
+ if not looktype then
+ player:sendCancelMessage("Invalid looktype.")
+ return true
+ end
+
+ target:addOutfitAddon(looktype, addonValue)
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Addon %d for looktype %d set for player %s.", addonValue, looktype, target:getName()))
+ target:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added addon %d for looktype %d to you.", player:getName(), addonValue, looktype))
+ end
return true
end
-addons:separator(" ")
-addons:groupType("god")
-addons:register()
+addaddon:separator(" ")
+addaddon:groupType("god")
+addaddon:register()
diff --git a/data/scripts/talkactions/god/add_addons.lua b/data/scripts/talkactions/god/add_addons.lua
deleted file mode 100644
index 5498ae1e11b..00000000000
--- a/data/scripts/talkactions/god/add_addons.lua
+++ /dev/null
@@ -1,277 +0,0 @@
--- /addaddons playername
-
-local addons = TalkAction("/addaddons")
-local looktypes = {
-
- -- Female Outfits
- 136,
- 137,
- 138,
- 139,
- 140,
- 141,
- 142,
- 147,
- 148,
- 149,
- 150,
- 155,
- 156,
- 157,
- 158,
- 252,
- 269,
- 270,
- 279,
- 288,
- 324,
- 329,
- 336,
- 366,
- 431,
- 433,
- 464,
- 466,
- 471,
- 513,
- 514,
- 542,
- 575,
- 578,
- 618,
- 620,
- 632,
- 635,
- 636,
- 664,
- 666,
- 683,
- 694,
- 696,
- 698,
- 724,
- 732,
- 745,
- 749,
- 759,
- 845,
- 852,
- 874,
- 885,
- 900,
- 909,
- 929,
- 956,
- 958,
- 963,
- 965,
- 967,
- 969,
- 971,
- 973,
- 975,
- 1020,
- 1024,
- 1043,
- 1050,
- 1057,
- 1070,
- 1095,
- 1103,
- 1128,
- 1147,
- 1162,
- 1174,
- 1187,
- 1203,
- 1205,
- 1207,
- 1211,
- 1244,
- 1246,
- 1252,
- 1271,
- 1280,
- 1283,
- 1289,
- 1293,
- 1323,
- 1332,
- 1339,
- 1372,
- 1383,
- 1385,
- 1387,
- 1416,
- 1437,
- 1445,
- 1450,
- 1456,
- 1461,
- 1490,
- 1501,
- 1569,
- 1576,
- 1582,
- 1598,
- 1613,
- 1619,
- 1663,
- 1676,
- 1681,
-
- -- Male Outfits
- 128,
- 129,
- 130,
- 131,
- 132,
- 133,
- 134,
- 143,
- 144,
- 145,
- 146,
- 151,
- 152,
- 153,
- 154,
- 251,
- 268,
- 273,
- 278,
- 289,
- 325,
- 328,
- 335,
- 367,
- 430,
- 432,
- 463,
- 465,
- 472,
- 512,
- 516,
- 541,
- 574,
- 577,
- 610,
- 619,
- 633,
- 634,
- 637,
- 665,
- 667,
- 684,
- 695,
- 697,
- 699,
- 725,
- 733,
- 746,
- 750,
- 760,
- 846,
- 853,
- 873,
- 884,
- 899,
- 908,
- 931,
- 955,
- 957,
- 962,
- 964,
- 966,
- 968,
- 970,
- 972,
- 974,
- 1021,
- 1023,
- 1042,
- 1051,
- 1056,
- 1069,
- 1094,
- 1102,
- 1127,
- 1146,
- 1161,
- 1173,
- 1186,
- 1202,
- 1204,
- 1206,
- 1210,
- 1243,
- 1245,
- 1251,
- 1270,
- 1279,
- 1282,
- 1288,
- 1292,
- 1322,
- 1331,
- 1338,
- 1371,
- 1382,
- 1384,
- 1386,
- 1415,
- 1436,
- 1444,
- 1449,
- 1457,
- 1460,
- 1489,
- 1500,
- 1568,
- 1575,
- 1581,
- 1597,
- 1612,
- 1618,
- 1662,
- 1675,
- 1680,
-}
-
-function addons.onSay(player, words, param)
- -- create log
- logCommand(player, words, param)
-
- local target
- if param == "" then
- target = player:getTarget()
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Gives players the ability to wear all addons. Usage: /addaddons ")
- return true
- end
- else
- target = Player(param)
- end
-
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Player " .. param .. " is currently not online.")
- return true
- end
-
- if player:getAccountType() < ACCOUNT_TYPE_GOD then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Cannot perform action.")
- return true
- end
-
- for i = 1, #looktypes do
- target:addOutfitAddon(looktypes[i], 3)
- end
-
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All addons unlocked for " .. target:getName() .. ".")
- target:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All of your addons have been unlocked!")
- return true
-end
-
-addons:separator(" ")
-addons:groupType("god")
-addons:register()
diff --git a/data/scripts/talkactions/god/add_mount.lua b/data/scripts/talkactions/god/add_mount.lua
index b8b2f00dda1..5dc8c9a97fb 100644
--- a/data/scripts/talkactions/god/add_mount.lua
+++ b/data/scripts/talkactions/god/add_mount.lua
@@ -1,13 +1,7 @@
---[[
- /addmount playername, mount
-]]
+local addmount = TalkAction("/addmount")
-local printConsole = true
-
-local addOutfit = TalkAction("/addmount")
-
-function addOutfit.onSay(player, words, param)
- -- create log
+function addmount.onSay(player, words, param)
+ -- Create log
logCommand(player, words, param)
if param == "" then
@@ -16,23 +10,41 @@ function addOutfit.onSay(player, words, param)
end
local split = param:split(",")
- local name = split[1]
-
- local target = Player(name)
- if target then
- local mount = tonumber(split[2])
- target:addMount(mount)
- target:sendTextMessage(MESSAGE_ADMINISTRATOR, "" .. player:getName() .. " has been added a new mount for you.")
- player:sendTextMessage(MESSAGE_ADMINISTRATOR, "You have sucessfull added mount " .. mount .. " to the player " .. target:getName() .. ".")
- if printConsole then
- logger.info("[addOutfit.onSay] - Player: {} has been added mount: {} to the player: {}", player:getName(), lookType, target:getName())
- end
+ if #split < 2 then
+ player:sendCancelMessage("Usage: /addmount , ")
+ return true
+ end
+
+ local playerName = split[1]
+ local target = Player(playerName)
+
+ if not target then
+ player:sendCancelMessage("Player not found.")
return true
end
- player:sendCancelMessage("Player not found.")
+
+ local mountParam = string.trim(split[2])
+ if mountParam == "all" then
+ for mountId = 1, 231 do
+ target:addMount(mountId)
+ end
+
+ target:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added all mounts to you.", player:getName()))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added all mounts to player %s.", target:getName()))
+ else
+ local mountId = tonumber(mountParam)
+ if not mountId then
+ player:sendCancelMessage("Invalid mount ID.")
+ return true
+ end
+
+ target:addMount(mountId)
+ target:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added a new mount for you.", player:getName()))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added mount %d to player %s.", mountId, target:getName()))
+ end
return true
end
-addOutfit:separator(" ")
-addOutfit:groupType("god")
-addOutfit:register()
+addmount:separator(" ")
+addmount:groupType("god")
+addmount:register()
diff --git a/data/scripts/talkactions/god/add_mounts.lua b/data/scripts/talkactions/god/add_mounts.lua
deleted file mode 100644
index 3de09916505..00000000000
--- a/data/scripts/talkactions/god/add_mounts.lua
+++ /dev/null
@@ -1,32 +0,0 @@
--- /addmounts playername
-
-local mounts = TalkAction("/addmounts")
-function mounts.onSay(player, words, param)
- local target
- if param == "" then
- target = player:getTarget()
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Unlocks all mounts for certain player. Usage: /mounts ")
- return true
- end
- else
- target = Player(param)
- end
-
- if not target then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Player " .. param .. " is not currently online.")
- return true
- end
-
- for i = 1, 221 do
- target:addMount(i)
- end
-
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All mounts unlocked for: " .. target:getName())
- target:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All of your mounts have been unlocked!")
- return true
-end
-
-mounts:separator(" ")
-mounts:groupType("god")
-mounts:register()
diff --git a/data/scripts/talkactions/god/add_outfit.lua b/data/scripts/talkactions/god/add_outfit.lua
deleted file mode 100644
index a27fb4f8a18..00000000000
--- a/data/scripts/talkactions/god/add_outfit.lua
+++ /dev/null
@@ -1,42 +0,0 @@
---[[
- /addoutfit playername, looktype
- make sure you’re adding a male outfit to a male character
- if you try to add a female outfit to a male character, it won’t work
-]]
-
-local printConsole = true
-
-local addOutfit = TalkAction("/addoutfit")
-
-function addOutfit.onSay(player, words, param)
- -- create log
- logCommand(player, words, param)
-
- if param == "" then
- player:sendCancelMessage("Command param required.")
- return true
- end
-
- local split = param:split(",")
- local name = split[1]
-
- local target = Player(name)
- if target then
- local lookType = tonumber(split[2])
- target:addOutfit(lookType)
- target:sendTextMessage(MESSAGE_ADMINISTRATOR, "" .. player:getName() .. " has been added a new outfit for you.")
- player:sendTextMessage(MESSAGE_ADMINISTRATOR, "You have sucessfull added looktype " .. lookType .. " to the player " .. target:getName() .. ".")
- if printConsole then
- logger.info("[addOutfit.onSay] - Player: {} has been added looktype: {} to the player: {}", player:getName(), lookType, target:getName())
- end
- return true
- else
- player:sendCancelMessage("Player not found.")
- return true
- end
- return true
-end
-
-addOutfit:separator(" ")
-addOutfit:groupType("god")
-addOutfit:register()
diff --git a/data/scripts/talkactions/god/add_skill.lua b/data/scripts/talkactions/god/add_skill.lua
index 09d240ece4d..3d082f656af 100644
--- a/data/scripts/talkactions/god/add_skill.lua
+++ b/data/scripts/talkactions/god/add_skill.lua
@@ -1,25 +1,20 @@
+local skillMap = {
+ club = SKILL_CLUB,
+ sword = SKILL_SWORD,
+ axe = SKILL_AXE,
+ dist = SKILL_DISTANCE,
+ shield = SKILL_SHIELD,
+ fish = SKILL_FISHING,
+}
+
local function getSkillId(skillName)
- if skillName == "club" then
- return SKILL_CLUB
- elseif skillName == "sword" then
- return SKILL_SWORD
- elseif skillName == "axe" then
- return SKILL_AXE
- elseif skillName:sub(1, 4) == "dist" then
- return SKILL_DISTANCE
- elseif skillName:sub(1, 6) == "shield" then
- return SKILL_SHIELD
- elseif skillName:sub(1, 4) == "fish" then
- return SKILL_FISHING
- else
- return SKILL_FIST
- end
+ return skillMap[skillName:match("^%a+")] or SKILL_FIST
end
local addSkill = TalkAction("/addskill")
function addSkill.onSay(player, words, param)
- -- create log
+ -- Create log
logCommand(player, words, param)
if param == "" then
@@ -28,39 +23,51 @@ function addSkill.onSay(player, words, param)
end
local split = param:split(",")
- if not split[2] then
- player:sendCancelMessage("Insufficient parameters.")
+ if #split < 2 then
+ player:sendCancelMessage("Usage: /addskill , , [amount]")
return true
end
- local target = Player(split[1])
- if not target then
- player:sendCancelMessage("A player with that name is not online.")
+ local targetPlayerName = split[1]:trim()
+ local targetPlayer = Player(targetPlayerName)
+
+ if not targetPlayer then
+ player:sendCancelMessage("Player not found.")
return true
end
- split[2] = split[2]:trimSpace()
+ local skillParam = split[2]:trim()
+ local skillIncreaseAmount = tonumber(split[3]) or 1
+ local skillPrefix = skillParam:sub(1, 1)
- local count = 1
- if split[3] then
- count = tonumber(split[3])
- end
+ if skillPrefix == "l" then
+ local targetNewLevel = targetPlayer:getLevel() + skillIncreaseAmount
+ local targetNewExp = Game.getExperienceForLevel(targetNewLevel)
+ local experienceToAdd = targetNewExp - targetPlayer:getExperience()
+ local levelText = (skillIncreaseAmount > 1) and "levels" or "level"
- local ch = split[2]:sub(1, 1)
- if ch == "l" or ch == "e" then
- targetLevel = target:getLevel() + count
- targetExp = Game.getExperienceForLevel(targetLevel)
- addExp = targetExp - target:getExperience()
- target:addExperience(addExp, false)
- elseif ch == "m" then
- for i = 1, count do
- target:addManaSpent(target:getVocation():getRequiredManaSpent(target:getBaseMagicLevel() + 1) - target:getManaSpent(), true)
+ targetPlayer:addExperience(experienceToAdd, false)
+ targetPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added %d %s to you.", player:getName(), skillIncreaseAmount, levelText))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added %d %s to player %s.", skillIncreaseAmount, levelText, targetPlayer:getName()))
+ elseif skillPrefix == "m" then
+ for _ = 1, skillIncreaseAmount do
+ local requiredManaSpent = targetPlayer:getVocation():getRequiredManaSpent(targetPlayer:getBaseMagicLevel() + 1)
+ targetPlayer:addManaSpent(requiredManaSpent - targetPlayer:getManaSpent(), true)
end
+
+ local magicText = (skillIncreaseAmount > 1) and "magic levels" or "magic level"
+ targetPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added %d %s to you.", player:getName(), skillIncreaseAmount, magicText))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added %d %s to player %s.", skillIncreaseAmount, magicText, targetPlayer:getName()))
else
- local skillId = getSkillId(split[2])
- for i = 1, count do
- target:addSkillTries(skillId, target:getVocation():getRequiredSkillTries(skillId, target:getSkillLevel(skillId) + 1) - target:getSkillTries(skillId), true)
+ local skillId = getSkillId(skillParam)
+ for _ = 1, skillIncreaseAmount do
+ local requiredSkillTries = targetPlayer:getVocation():getRequiredSkillTries(skillId, targetPlayer:getSkillLevel(skillId) + 1)
+ targetPlayer:addSkillTries(skillId, requiredSkillTries - targetPlayer:getSkillTries(skillId), true)
end
+
+ local skillText = (skillIncreaseAmount > 1) and "skill levels" or "skill level"
+ targetPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s has added %d %s %s to you.", player:getName(), skillIncreaseAmount, skillParam, skillText))
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have successfully added %d %s %s to player %s.", skillIncreaseAmount, skillParam, skillText, targetPlayer:getName()))
end
return true
end
diff --git a/data/scripts/talkactions/god/manage_monster.lua b/data/scripts/talkactions/god/manage_monster.lua
index da110d59265..106acefa078 100644
--- a/data/scripts/talkactions/god/manage_monster.lua
+++ b/data/scripts/talkactions/god/manage_monster.lua
@@ -1,37 +1,38 @@
-local function createCreaturesAround(player, maxRadius, creatureName, creatureCount, creatureForge, boolForceCreate)
- local position = player:getPosition()
- local createdCount = 0
+local function createCreaturesAround(player, maxRadius, creatureName, creatureCount, creatureForge, forceCreateMonsters)
+ local playerPosition = player:getPosition()
+ local createdCreatureCount = 0
local sendMessage = false
local canSetFiendish, canSetInfluenced, influencedLevel = CheckDustLevel(creatureForge, player)
+
for radius = 1, maxRadius do
- if createdCount >= creatureCount then
+ if createdCreatureCount >= creatureCount then
break
end
- local minX = position.x - radius
- local maxX = position.x + radius
- local minY = position.y - radius
- local maxY = position.y + radius
+ local minX, maxX = playerPosition.x - radius, playerPosition.x + radius
+ local minY, maxY = playerPosition.y - radius, playerPosition.y + radius
for dx = minX, maxX do
for dy = minY, maxY do
- if (dx == minX or dx == maxX or dy == minY or dy == maxY) and createdCount < creatureCount then
- local checkPosition = Position(dx, dy, position.z)
+ if (dx == minX or dx == maxX or dy == minY or dy == maxY) and createdCreatureCount < creatureCount then
+ local checkPosition = Position(dx, dy, playerPosition.z)
local tile = Tile(checkPosition)
if tile and not tile:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) then
- local monster = Game.createMonster(creatureName, checkPosition, false, boolForceCreate)
+ local monster = Game.createMonster(creatureName, checkPosition, false, forceCreateMonsters)
if monster then
- createdCount = createdCount + 1
+ createdCreatureCount = createdCreatureCount + 1
monster:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
- position:sendMagicEffect(CONST_ME_MAGIC_RED)
- if creatureForge ~= nil and monster:isForgeable() then
+ playerPosition:sendMagicEffect(CONST_ME_MAGIC_RED)
+
+ if creatureForge and monster:isForgeable() then
local monsterType = monster:getType()
if canSetFiendish then
- SetFiendish(monsterType, position, player, monster)
+ SetFiendish(monsterType, playerPosition, player, monster)
end
+
if canSetInfluenced then
SetInfluenced(monsterType, monster, player, influencedLevel)
end
- elseif notSendMessage then
+ elseif not sendMessage then
sendMessage = true
end
end
@@ -40,86 +41,58 @@ local function createCreaturesAround(player, maxRadius, creatureName, creatureCo
end
end
end
- if sendMessage == true then
+
+ if sendMessage then
player:sendCancelMessage("Only allowed monsters can be fiendish or influenced.")
end
-
- logger.info("Player {} created '{}' monsters", player:getName(), createdCount)
end
local createMonster = TalkAction("/m")
--- @function createMonster.onSay
--- @desc TalkAction to create monsters with multiple options.
--- @param player: The player executing the command.
--- @param words: Command words.
--- @param param: String containing the command parameters.
--- Format: "/m monstername, monstercount, [fiendish/influenced level], spawnRadius, [forceCreate]"
--- Example: "/m rat, 10, fiendish, 5, true"
--- @param: the last param is by default "false", if add "," or any value it's set to true
--- @return true if the command is executed successfully, false otherwise.
function createMonster.onSay(player, words, param)
-- create log
logCommand(player, words, param)
+
if param == "" then
player:sendCancelMessage("Monster name param required.")
- logger.error("[createMonster.onSay] - Monster name param not found.")
return true
end
- local position = player:getPosition()
-
- local split = param:split(",")
- local monsterName = split[1]
- local monsterCount = 0
- if split[2] then
- split[2] = split[2]:trimSpace()
- monsterCount = tonumber(split[2])
- end
-
- local monsterForge = nil
- if split[3] then
- split[3] = split[3]:trimSpace()
- monsterForge = split[3]
- end
+ local playerPosition = player:getPosition()
+ local splitParams = param:split(",")
+ local monsterName = splitParams[1]
+ local monsterCount = tonumber(splitParams[2] or 1)
+ local monsterForge = splitParams[3] and splitParams[3]:trimSpace() or nil
+ local spawnRadius = tonumber(splitParams[4] or 5)
+ local forceCreate = splitParams[5] and true or false
if monsterCount > 1 then
- local spawnRadius = 5
- if split[4] then
- split[4] = split[4]:trimSpace()
- spawnRadius = split[4]
- print(spawnRadius)
- end
-
- local forceCreate = false
- if split[5] then
- forceCreate = true
- end
-
createCreaturesAround(player, spawnRadius, monsterName, monsterCount, monsterForge, forceCreate)
return true
end
- local monster = Game.createMonster(monsterName, position)
+ local monster = Game.createMonster(monsterName, playerPosition)
if monster then
local canSetFiendish, canSetInfluenced, influencedLevel = CheckDustLevel(monsterForge, player)
monster:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
- position:sendMagicEffect(CONST_ME_MAGIC_RED)
- if monsterForge ~= nil and not monster:isForgeable() then
+ playerPosition:sendMagicEffect(CONST_ME_MAGIC_RED)
+
+ if monsterForge and not monster:isForgeable() then
player:sendCancelMessage("Only allowed monsters can be fiendish or influenced.")
return true
end
local monsterType = monster:getType()
if canSetFiendish then
- SetFiendish(monsterType, position, player, monster)
+ SetFiendish(monsterType, playerPosition, player, monster)
end
+
if canSetInfluenced then
SetInfluenced(monsterType, monster, player, influencedLevel)
end
else
player:sendCancelMessage("There is not enough room.")
- position:sendMagicEffect(CONST_ME_POFF)
+ playerPosition:sendMagicEffect(CONST_ME_POFF)
end
return true
end
@@ -128,29 +101,27 @@ createMonster:separator(" ")
createMonster:groupType("god")
createMonster:register()
------------------ Rename monster name -----------------
local setMonsterName = TalkAction("/setmonstername")
--- @function setMonsterName.onSay
--- @desc TalkAction to rename nearby monsters within a radius of 4 sqm.
--- Format: "/setmonstername newName"
function setMonsterName.onSay(player, words, param)
+ -- create log
+ logCommand(player, words, param)
+
if param == "" then
player:sendCancelMessage("Command param required.")
return true
end
- local split = param:split(",")
- local monsterNewName = split[1]
-
+ local splitParams = param:split(",")
+ local newMonsterName = splitParams[1]
local spectators, spectator = Game.getSpectators(player:getPosition(), false, false, 4, 4, 4, 4)
+
for i = 1, #spectators do
spectator = spectators[i]
if spectator:isMonster() then
- spectator:setName(monsterNewName)
+ spectator:setName(newMonsterName)
end
end
-
return true
end
diff --git a/data/scripts/talkactions/player/vip.lua b/data/scripts/talkactions/player/vip.lua
index 65ca4be99f8..a80f6dd54dc 100644
--- a/data/scripts/talkactions/player/vip.lua
+++ b/data/scripts/talkactions/player/vip.lua
@@ -1,12 +1,10 @@
local vip = TalkAction("!checkvip", "!vip")
function vip.onSay(player, words, param)
- if not player:isVip() then
- local msg = "You do not have VIP on your account."
- player:sendCancelMessage(msg)
- player:sendTextMessage(MESSAGE_STATUS, msg)
+ if player:isVip() then
+ player:sendVipStatus()
else
- CheckPremiumAndPrint(player, MESSAGE_STATUS)
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You do not have VIP on your account.")
end
return true
end
diff --git a/docs/python-scripts/modify_lua_script_interfaces.py b/docs/python-scripts/modify_lua_script_interfaces.py
new file mode 100644
index 00000000000..881a8453d90
--- /dev/null
+++ b/docs/python-scripts/modify_lua_script_interfaces.py
@@ -0,0 +1,211 @@
+import os
+import re
+import argparse
+
+# Functions that modify the file
+
+def remove_constructor_and_destructor(content):
+ # Remove the class constructor and destructor, including a blank line after the destructor
+ pattern = r"explicit\s+\w+\(lua_State\* L\)\s*:\s*LuaScriptInterface\(\"[^\"]+\"\)\s*\{[^\}]*\}\n\s*~\w+\(\)\s*override\s*=\s*default;\n\s*\n?"
+ content = re.sub(pattern, "", content, flags=re.DOTALL)
+ return content
+
+def remove_include_luascript(content):
+ # Remove the specified include and the blank line below it
+ pattern = r'#include\s+"lua/scripts/luascript.hpp"\n\n?'
+ content = re.sub(pattern, "", content)
+ return content
+
+def remove_final_luascriptinterface(content):
+ # Remove "final : LuaScriptInterface", "public LuaScriptInterface", "final :", and "LuaScriptInterface" alone
+ pattern = r'final\s*:\s*public\s+LuaScriptInterface|public\s+LuaScriptInterface|final\s*:\s*|LuaScriptInterface\s*'
+ content = re.sub(pattern, "", content)
+ # Remove extra spaces between the class name and the opening block
+ content = re.sub(r'class\s+(\w+)\s*\{', r'class \1 {', content)
+ return content
+
+def move_init_function_to_cpp(hpp_content, cpp_content, class_name):
+ # Extracts the init function from the hpp, keeping the signature
+ pattern = r'static void init\(lua_State\* L\)\s*\{[^\}]*\}'
+ match = re.search(pattern, hpp_content, flags=re.DOTALL)
+ if match:
+ # Keep the function signature in the hpp, but remove the body
+ init_function_signature = "static void init(lua_State* L);"
+ hpp_content = re.sub(pattern, init_function_signature, hpp_content, flags=re.DOTALL)
+
+ # Adjust the function signature for the cpp
+ init_function = match.group()
+ init_function = re.sub(r'static void\s+', f'void {class_name}::', init_function)
+ # Remove extra indentation
+ init_function = init_function.replace(' \n\t\t', '\n\t')
+ # Remove the extra tab from the function closure
+ init_function = init_function.replace('\n\t}', '\n}')
+
+ # Add a blank line before and after the function
+ init_function = f"\n{init_function}\n"
+
+ # Add the function to the beginning of the cpp, after the includes
+ last_include = re.findall(r'#include\s+<[^>]+>|#include\s+"[^"]+"', cpp_content)
+ if last_include:
+ last_include_pos = cpp_content.rfind(last_include[-1]) + len(last_include[-1])
+ cpp_content = cpp_content[:last_include_pos] + "\n" + init_function + cpp_content[last_include_pos:]
+ else:
+ cpp_content = init_function + cpp_content
+ return hpp_content, cpp_content
+
+def add_include_to_cpp(cpp_content):
+ # Add the new include after the last include, if it is not already present
+ include_statement = '#include "lua/functions/lua_functions_loader.hpp"'
+ if include_statement not in cpp_content:
+ # Locate the last include
+ last_include = re.findall(r'#include\s+<[^>]+>|#include\s+"[^"]+"', cpp_content)
+ if last_include:
+ last_include_pos = cpp_content.rfind(last_include[-1]) + len(last_include[-1])
+ # Make sure there are not multiple line breaks before the include
+ cpp_content = cpp_content[:last_include_pos].rstrip() + "\n" + include_statement + "\n\n" + cpp_content[last_include_pos:].lstrip()
+ return cpp_content
+
+def process_files(hpp_file_path, cpp_file_path):
+ with open(hpp_file_path, 'r', encoding='utf-8') as hpp_file:
+ hpp_content = hpp_file.read()
+
+ with open(cpp_file_path, 'r', encoding='utf-8') as cpp_file:
+ cpp_content = cpp_file.read()
+
+ # Get the class name from the hpp file
+ class_name_match = re.search(r'class\s+(\w+)', hpp_content)
+ class_name = class_name_match.group(1) if class_name_match else None
+
+ if class_name:
+ # Apply all modifications
+ hpp_content = remove_constructor_and_destructor(hpp_content)
+ hpp_content = remove_include_luascript(hpp_content)
+ hpp_content = remove_final_luascriptinterface(hpp_content)
+ hpp_content, cpp_content = move_init_function_to_cpp(hpp_content, cpp_content, class_name)
+ cpp_content = add_include_to_cpp(cpp_content)
+
+ # Save the modified files
+ with open(hpp_file_path, 'w', encoding='utf-8') as hpp_file:
+ hpp_file.write(hpp_content)
+
+ with open(cpp_file_path, 'w', encoding='utf-8') as cpp_file:
+ cpp_file.write(cpp_content)
+
+ print(f'Modifications applied to: {hpp_file_path} and {cpp_file_path}')
+
+def main(directory):
+ # Scan the specified folder and find all .hpp and .cpp files
+ for root, _, files in os.walk(directory):
+ for file in files:
+ if file.endswith('.hpp'):
+ hpp_file_path = os.path.join(root, file)
+ cpp_file_path = hpp_file_path.replace('.hpp', '.cpp')
+ if os.path.exists(cpp_file_path):
+ process_files(hpp_file_path, cpp_file_path)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Apply modifications to .hpp and .cpp files according to specifications.')
+ parser.add_argument('directory', type=str, nargs='?', default='../../src/lua/functions/', help='Path of the directory to be scanned.')
+ args = parser.parse_args()
+
+ main(args.directory)
+
+# Functions you want to migrate to static calls
+functions_to_convert = [
+ "getNumber",
+ "getBoolean",
+ "getString",
+ "getUserdata",
+ "getScriptEnv",
+ "getCreature",
+ "getPlayer",
+ "getPosition",
+ "getOutfit",
+ "getThing",
+ "getUserdataShared",
+ "getUserdataType",
+ "getRawUserDataShared",
+ "getErrorDesc",
+ "getFormatedLoggerMessage",
+ "getField",
+ "getFieldString",
+ "getVariant",
+ "getGuild",
+ "isTable",
+ "isString",
+ "isNumber",
+ "isBoolean",
+ "isNil",
+ "isFunction",
+ "isUserdata",
+ "reportError",
+ "reportErrorFunc",
+ "pushInstantSpell",
+ "pushVariant",
+ "pushOutfit",
+ "pushCylinder",
+ "pushBoolean",
+ "pushString",
+ "pushUserdata",
+ "pushPosition",
+ "setMetatable",
+ "setWeakMetatable",
+ "setCreatureMetatable",
+ "setItemMetatable",
+ "setField",
+ "registerVariable",
+ "registerGlobalMethod",
+ "registerGlobalVariable",
+ "registerGlobalBoolean",
+ "registerMethod",
+ "registerClass",
+ "registerTable",
+ "registerSharedClass",
+ "registerMetaMethod",
+]
+
+# Files you want to exclude from scanning (relative paths)
+files_to_exclude = [
+ os.path.normpath("lua_functions_loader.cpp"),
+ os.path.normpath("lua_functions_loader.hpp")
+]
+
+def convert_to_static(file_path):
+ with open(file_path, 'r', encoding='utf-8') as file:
+ content = file.read()
+
+ original_content = content # Keep the original content to check for changes
+
+ for function in functions_to_convert:
+ # Regex to capture function calls and replace them with Lua::function
+ # Skip calls that are part of g_configManager() and handle both regular and template functions
+ pattern = r'(?)?\('
+ replacement = rf'Lua::{function}\1('
+ content = re.sub(pattern, replacement, content)
+
+ if content != original_content:
+ with open(file_path, 'w', encoding='utf-8') as file:
+ file.write(content)
+ print(f'File converted: {file_path}')
+ else:
+ print(f'No changes made to file: {file_path}')
+
+def main(directory):
+ # Scan the specified folder and find all .cpp and .hpp files
+ for root, _, files in os.walk(directory):
+ for file in files:
+ if file.endswith(('.cpp', '.hpp')):
+ file_path = os.path.normpath(os.path.join(root, file))
+
+ # Check if the file is in the exclusion list
+ if any(os.path.basename(file_path) == exclude_file for exclude_file in files_to_exclude):
+ print(f'File ignored: {file_path}')
+ continue # Skip the specified files
+
+ convert_to_static(file_path)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Convert functions to static calls.')
+ parser.add_argument('directory', type=str, nargs='?', default='../../src/lua/functions/', help='Path of the directory to be scanned.')
+
+ main(args.directory)
diff --git a/src/canary_server.cpp b/src/canary_server.cpp
index 687fa51b6cd..8dfbcfc954c 100644
--- a/src/canary_server.cpp
+++ b/src/canary_server.cpp
@@ -9,6 +9,7 @@
#include "canary_server.hpp"
+#include "core.hpp"
#include "config/configmanager.hpp"
#include "creatures/npcs/npcs.hpp"
#include "creatures/players/grouping/familiars.hpp"
@@ -31,8 +32,7 @@
#include "server/network/protocol/protocollogin.hpp"
#include "server/network/protocol/protocolstatus.hpp"
#include "server/network/webhook/webhook.hpp"
-
-#include "core.hpp"
+#include "creatures/players/vocations/vocation.hpp"
CanaryServer::CanaryServer(
Logger &logger,
@@ -322,6 +322,7 @@ void CanaryServer::initializeDatabase() {
&& !DatabaseManager::optimizeTables()) {
logger.debug("No tables were optimized");
}
+ g_logger().info("Database connection established!");
}
void CanaryServer::loadModules() {
diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp
index 6dcd0f229b3..6b7667a71a5 100644
--- a/src/creatures/combat/combat.cpp
+++ b/src/creatures/combat/combat.cpp
@@ -15,12 +15,14 @@
#include "creatures/monsters/monster.hpp"
#include "creatures/monsters/monsters.hpp"
#include "creatures/players/grouping/party.hpp"
+#include "creatures/players/player.hpp"
#include "creatures/players/imbuements/imbuements.hpp"
#include "creatures/players/wheel/player_wheel.hpp"
#include "game/game.hpp"
#include "game/scheduling/dispatcher.hpp"
#include "io/iobestiary.hpp"
#include "io/ioprey.hpp"
+#include "creatures/players/vocations/vocation.hpp"
#include "items/weapons/weapons.hpp"
#include "lib/metrics/metrics.hpp"
#include "lua/callbacks/event_callback.hpp"
@@ -1064,7 +1066,7 @@ void Combat::setupChain(const std::shared_ptr &weapon) {
}
bool Combat::doCombatChain(const std::shared_ptr &caster, const std::shared_ptr &target, bool aggressive) const {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (!params.chainCallback) {
return false;
}
@@ -1087,7 +1089,7 @@ bool Combat::doCombatChain(const std::shared_ptr &caster, const std::s
auto delay = i * std::max(50, g_configManager().getNumber(COMBAT_CHAIN_DELAY));
++i;
for (const auto &to : toVector) {
- auto nextTarget = g_game().getCreatureByID(to);
+ const auto &nextTarget = g_game().getCreatureByID(to);
if (!nextTarget) {
continue;
}
@@ -1279,11 +1281,6 @@ void Combat::CombatFunc(const std::shared_ptr &caster, const Position
combatTileEffects(spectators.data(), caster, tile, params);
}
- // Wheel of destiny update beam mastery damage
- if (casterPlayer) {
- casterPlayer->wheel()->updateBeamMasteryDamage(tmpDamage, beamAffectedTotal, beamAffectedCurrent);
- }
-
postCombatEffects(caster, origin, pos, params);
}
@@ -1472,7 +1469,7 @@ void Combat::setRuneSpellName(const std::string &value) {
std::vector>> Combat::pickChainTargets(const std::shared_ptr &caster, const CombatParams ¶ms, uint8_t chainDistance, uint8_t maxTargets, bool backtracking, bool aggressive, const std::shared_ptr &initialTarget /* = nullptr */) {
Benchmark bm_pickChain;
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (!caster) {
return {};
}
@@ -1515,7 +1512,7 @@ std::vector>> Combat::pickChainTargets
}
if (closestSpectator) {
- g_logger().trace("[{}] closestSpectator: {}", __METHOD_NAME__, closestSpectator->getName());
+ g_logger().trace("[{}] closestSpectator: {}", __FUNCTION__, closestSpectator->getName());
bool found = false;
for (auto &[pos, vec] : resultMap) {
@@ -1534,7 +1531,7 @@ std::vector>> Combat::pickChainTargets
continue;
}
if (backtracking) {
- g_logger().debug("[{}] backtracking", __METHOD_NAME__);
+ g_logger().debug("[{}] backtracking", __FUNCTION__);
targets.pop_back();
backtrackingAttempts--;
continue;
@@ -1542,7 +1539,7 @@ std::vector>> Combat::pickChainTargets
break;
}
- g_logger().debug("[{}] resultMap: {} in {} ms", __METHOD_NAME__, resultMap.size(), bm_pickChain.duration());
+ g_logger().debug("[{}] resultMap: {} in {} ms", __FUNCTION__, resultMap.size(), bm_pickChain.duration());
return resultMap;
}
@@ -2224,7 +2221,7 @@ void MagicField::onStepInField(const std::shared_ptr &creature) {
}
void Combat::applyExtensions(const std::shared_ptr &caster, const std::shared_ptr &target, CombatDamage &damage, const CombatParams ¶ms) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (damage.extension || !caster || damage.primary.type == COMBAT_HEALING) {
return;
}
diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp
index 0d66602ddca..f522eac86a6 100644
--- a/src/creatures/combat/spells.cpp
+++ b/src/creatures/combat/spells.cpp
@@ -20,10 +20,8 @@
#include "game/game.hpp"
#include "lua/global/lua_variant.hpp"
#include "lua/scripts/lua_environment.hpp"
-#include "lua/scripts/luascript.hpp"
-
-std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyRegularBoost = { 0 };
-std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyUpgradedBoost = { 0 };
+#include "lua/scripts/scripts.hpp"
+#include "lib/di/container.hpp"
Spells::Spells() = default;
Spells::~Spells() = default;
@@ -156,7 +154,7 @@ bool Spells::registerRuneLuaEvent(const std::shared_ptr &rune) {
"[{}] duplicate registered rune with id: {}, for script: {}",
__FUNCTION__,
id,
- rune->getScriptInterface()->getLoadingScriptName()
+ rune->getRuneSpellScriptInterface()->getLoadingScriptName()
);
}
return inserted;
@@ -277,29 +275,45 @@ Position Spells::getCasterPosition(const std::shared_ptr &creature, Di
return getNextPosition(dir, creature->getPosition());
}
+LuaScriptInterface* BaseSpell::getScriptInterface() const {
+ return &g_scripts().getScriptInterface();
+}
+
+bool BaseSpell::loadScriptId() {
+ LuaScriptInterface &luaInterface = g_scripts().getScriptInterface();
+ m_spellScriptId = luaInterface.getEvent();
+ if (m_spellScriptId == -1) {
+ g_logger().error("[MoveEvent::loadScriptId] Failed to load event. Script name: '{}', Module: '{}'", luaInterface.getLoadingScriptName(), luaInterface.getInterfaceName());
+ return false;
+ }
+
+ return true;
+}
+
+int32_t BaseSpell::getScriptId() const {
+ return m_spellScriptId;
+}
+
+void BaseSpell::setScriptId(int32_t newScriptId) {
+ m_spellScriptId = newScriptId;
+}
+
+bool BaseSpell::isLoadedScriptId() const {
+ return m_spellScriptId != 0;
+}
+
CombatSpell::CombatSpell(const std::shared_ptr &newCombat, bool newNeedTarget, bool newNeedDirection) :
- Script(&g_spells().getScriptInterface()),
m_combat(newCombat),
needDirection(newNeedDirection),
needTarget(newNeedTarget) {
- // Empty
-}
-
-bool CombatSpell::loadScriptCombat() {
- m_combat = g_luaEnvironment().getCombatObject(g_luaEnvironment().lastCombatId);
- return m_combat != nullptr;
}
std::shared_ptr CombatSpell::getCombat() const {
return m_combat;
}
-std::string CombatSpell::getScriptTypeName() const {
- return "onCastSpell";
-}
-
bool CombatSpell::castSpell(const std::shared_ptr &creature) {
- if (isLoadedCallback()) {
+ if (isLoadedScriptId()) {
LuaVariant var;
var.type = VARIANT_POSITION;
@@ -346,7 +360,7 @@ bool CombatSpell::castSpell(const std::shared_ptr &creature, const std
return false;
}
- if (isLoadedCallback()) {
+ if (isLoadedScriptId()) {
LuaVariant var;
if (combat->hasArea()) {
var.type = VARIANT_POSITION;
@@ -412,6 +426,8 @@ bool CombatSpell::executeCastSpell(const std::shared_ptr &creature, co
return getScriptInterface()->callFunction(2);
}
+Spell::Spell() = default;
+
bool Spell::playerSpellCheck(const std::shared_ptr &player) const {
if (player->hasFlag(PlayerFlags_t::CannotUseSpells)) {
return false;
@@ -730,7 +746,10 @@ void Spell::applyCooldownConditions(const std::shared_ptr &player) const
g_logger().debug("[{}] spell name: {}, spellCooldown: {}, bonus: {}, augment {}", __FUNCTION__, name, spellCooldown, player->wheel()->getSpellBonus(name, WheelSpellBoost_t::COOLDOWN), augmentCooldownReduction);
spellCooldown -= player->wheel()->getSpellBonus(name, WheelSpellBoost_t::COOLDOWN);
spellCooldown -= augmentCooldownReduction;
+ const int32_t halfBaseCooldown = cooldown / 2;
+ spellCooldown = halfBaseCooldown > spellCooldown ? halfBaseCooldown : spellCooldown; // The cooldown should never be reduced less than half (50%) of its base cooldown
if (spellCooldown > 0) {
+ player->wheel()->handleTwinBurstsCooldown(player, name, spellCooldown, rateCooldown);
const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, m_spellId);
player->addCondition(condition);
}
@@ -752,7 +771,9 @@ void Spell::applyCooldownConditions(const std::shared_ptr &player) const
if (isUpgraded) {
spellSecondaryGroupCooldown -= getWheelOfDestinyBoost(WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN, spellGrade);
}
+ spellSecondaryGroupCooldown -= player->wheel()->getSpellBonus(name, WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN);
if (spellSecondaryGroupCooldown > 0) {
+ player->wheel()->handleBeamMasteryCooldown(player, name, spellSecondaryGroupCooldown, rateCooldown);
const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, spellSecondaryGroupCooldown / rateCooldown, 0, false, secondaryGroup);
player->addCondition(condition);
}
@@ -1030,6 +1051,8 @@ void Spell::setLockedPZ(bool b) {
pzLocked = b;
}
+InstantSpell::InstantSpell() = default;
+
bool InstantSpell::playerCastInstant(const std::shared_ptr &player, std::string ¶m) const {
if (!playerSpellCheck(player)) {
return false;
@@ -1161,10 +1184,6 @@ bool InstantSpell::canThrowSpell(const std::shared_ptr &creature, cons
return true;
}
-std::string InstantSpell::getScriptTypeName() const {
- return "onCastSpell";
-}
-
bool InstantSpell::castSpell(const std::shared_ptr &creature) {
LuaVariant var;
var.instantName = getName();
@@ -1294,6 +1313,33 @@ bool InstantSpell::canCast(const std::shared_ptr &player) const {
return false;
}
+LuaScriptInterface* RuneSpell::getRuneSpellScriptInterface() const {
+ return &g_scripts().getScriptInterface();
+}
+
+bool RuneSpell::loadRuneSpellScriptId() {
+ LuaScriptInterface &luaInterface = g_scripts().getScriptInterface();
+ m_runeSpellScriptId = luaInterface.getEvent();
+ if (m_runeSpellScriptId == -1) {
+ g_logger().error("[MoveEvent::loadScriptId] Failed to load event. Script name: '{}', Module: '{}'", luaInterface.getLoadingScriptName(), luaInterface.getInterfaceName());
+ return false;
+ }
+
+ return true;
+}
+
+int32_t RuneSpell::getRuneSpellScriptId() const {
+ return m_runeSpellScriptId;
+}
+
+void RuneSpell::setRuneSpellScriptId(int32_t newScriptId) {
+ m_runeSpellScriptId = newScriptId;
+}
+
+bool RuneSpell::isRuneSpellLoadedScriptId() const {
+ return m_runeSpellScriptId != 0;
+}
+
ReturnValue RuneSpell::canExecuteAction(const std::shared_ptr &player, const Position &toPos) {
if (player->hasFlag(PlayerFlags_t::CannotUseSpells)) {
return RETURNVALUE_CANNOTUSETHISOBJECT;
@@ -1329,7 +1375,7 @@ bool RuneSpell::executeUse(const std::shared_ptr &player, const std::sha
}
// If script not loaded correctly, return
- if (!isLoadedCallback()) {
+ if (!isRuneSpellLoadedScriptId()) {
return false;
}
@@ -1391,13 +1437,9 @@ bool RuneSpell::castSpell(const std::shared_ptr &creature, const std::
return internalCastSpell(creature, var, false);
}
-std::string RuneSpell::getScriptTypeName() const {
- return "onCastSpell";
-}
-
bool RuneSpell::internalCastSpell(const std::shared_ptr &creature, const LuaVariant &var, bool isHotkey) const {
bool result;
- if (isLoadedCallback()) {
+ if (isRuneSpellLoadedScriptId()) {
result = executeCastSpell(creature, var, isHotkey);
} else {
result = false;
@@ -1415,11 +1457,11 @@ bool RuneSpell::executeCastSpell(const std::shared_ptr &creature, cons
}
ScriptEnvironment* env = LuaEnvironment::getScriptEnv();
- env->setScriptId(getScriptId(), getScriptInterface());
+ env->setScriptId(getRuneSpellScriptId(), getRuneSpellScriptInterface());
- lua_State* L = getScriptInterface()->getLuaState();
+ lua_State* L = getRuneSpellScriptInterface()->getLuaState();
- getScriptInterface()->pushFunction(getScriptId());
+ getRuneSpellScriptInterface()->pushFunction(getRuneSpellScriptId());
LuaScriptInterface::pushUserdata(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
@@ -1428,7 +1470,7 @@ bool RuneSpell::executeCastSpell(const std::shared_ptr &creature, cons
LuaScriptInterface::pushBoolean(L, isHotkey);
- return getScriptInterface()->callFunction(3);
+ return getRuneSpellScriptInterface()->callFunction(3);
}
bool RuneSpell::isInstant() const {
diff --git a/src/creatures/combat/spells.hpp b/src/creatures/combat/spells.hpp
index ab34fa6dbce..56ff1a330de 100644
--- a/src/creatures/combat/spells.hpp
+++ b/src/creatures/combat/spells.hpp
@@ -10,20 +10,22 @@
#pragma once
#include "lua/creature/actions.hpp"
-#include "lua/scripts/scripts.hpp"
-
-enum class WheelSpellBoost_t : uint8_t;
-enum class WheelSpellGrade_t : uint8_t;
+#include "creatures/players/wheel/wheel_definitions.hpp"
class InstantSpell;
class RuneSpell;
class Spell;
+class Combat;
+class Player;
+class Creature;
+class LuaScriptInterface;
struct LuaVariant;
+struct Position;
using VocSpellMap = std::map;
-class Spells final : public Scripts {
+class Spells {
public:
Spells();
~Spells();
@@ -78,11 +80,20 @@ class BaseSpell {
virtual bool castSpell(const std::shared_ptr &creature) = 0;
virtual bool castSpell(const std::shared_ptr &creature, const std::shared_ptr &target) = 0;
+ LuaScriptInterface* getScriptInterface() const;
+ bool loadScriptId();
+ int32_t getScriptId() const;
+ void setScriptId(int32_t newScriptId);
+ bool isLoadedScriptId() const;
+
SoundEffect_t soundImpactEffect = SoundEffect_t::SILENCE;
SoundEffect_t soundCastEffect = SoundEffect_t::SPELL_OR_RUNE;
+
+protected:
+ int32_t m_spellScriptId {};
};
-class CombatSpell final : public Script, public BaseSpell, public std::enable_shared_from_this {
+class CombatSpell final : public BaseSpell, public std::enable_shared_from_this {
public:
// Constructor
CombatSpell(const std::shared_ptr &newCombat, bool newNeedTarget, bool newNeedDirection);
@@ -97,12 +108,9 @@ class CombatSpell final : public Script, public BaseSpell, public std::enable_sh
// Scripting spell
bool executeCastSpell(const std::shared_ptr &creature, const LuaVariant &var) const;
- bool loadScriptCombat();
std::shared_ptr getCombat() const;
private:
- std::string getScriptTypeName() const override;
-
std::shared_ptr m_combat;
bool needDirection;
@@ -111,7 +119,7 @@ class CombatSpell final : public Script, public BaseSpell, public std::enable_sh
class Spell : public BaseSpell {
public:
- Spell() = default;
+ Spell();
[[nodiscard]] const std::string &getName() const;
void setName(std::string n);
@@ -246,6 +254,8 @@ class Spell : public BaseSpell {
bool pzLocked = false;
bool whellOfDestinyUpgraded = false;
+ std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyRegularBoost = { 0 };
+ std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyUpgradedBoost = { 0 };
private:
uint32_t mana = 0;
@@ -267,10 +277,9 @@ class Spell : public BaseSpell {
friend class SpellFunctions;
};
-class InstantSpell final : public Script, public Spell {
+class InstantSpell final : public Spell {
public:
- using Script::Script;
-
+ InstantSpell();
bool playerCastInstant(const std::shared_ptr &player, std::string ¶m) const;
bool castSpell(const std::shared_ptr &creature) override;
@@ -294,8 +303,6 @@ class InstantSpell final : public Script, public Spell {
bool canThrowSpell(const std::shared_ptr &creature, const std::shared_ptr &target) const;
private:
- [[nodiscard]] std::string getScriptTypeName() const override;
-
bool needDirection = false;
bool hasParam = false;
bool hasPlayerNameParam = false;
@@ -307,6 +314,12 @@ class RuneSpell final : public Action, public Spell {
public:
using Action::Action;
+ LuaScriptInterface* getRuneSpellScriptInterface() const;
+ bool loadRuneSpellScriptId();
+ int32_t getRuneSpellScriptId() const;
+ void setRuneSpellScriptId(int32_t newScriptId);
+ bool isRuneSpellLoadedScriptId() const;
+
ReturnValue canExecuteAction(const std::shared_ptr &player, const Position &toPos) override;
bool hasOwnErrorHandler() override;
std::shared_ptr getTarget(const std::shared_ptr &, const std::shared_ptr &targetCreature, const Position &, uint8_t) const override;
@@ -326,10 +339,10 @@ class RuneSpell final : public Action, public Spell {
void setCharges(uint32_t c);
private:
- [[nodiscard]] std::string getScriptTypeName() const override;
-
bool internalCastSpell(const std::shared_ptr &creature, const LuaVariant &var, bool isHotkey) const;
+ int32_t m_runeSpellScriptId = 0;
+
uint16_t runeId = 0;
uint32_t charges = 0;
bool hasCharges = false;
diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp
index 0e73ca050bf..586f5b8c1b2 100644
--- a/src/creatures/creature.cpp
+++ b/src/creatures/creature.cpp
@@ -35,7 +35,7 @@ Creature::~Creature() {
}
bool Creature::canSee(const Position &myPos, const Position &pos, int32_t viewRangeX, int32_t viewRangeY) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (myPos.z <= MAP_INIT_SURFACE_LAYER) {
// we are on ground level or above (7 -> 0)
// view is from 7 -> 0
@@ -95,11 +95,7 @@ int32_t Creature::getWalkSize() {
}
void Creature::onThink(uint32_t interval) {
- metrics::method_latency measure(__METHOD_NAME__);
- if (!isMapLoaded && useCacheMap()) {
- isMapLoaded = true;
- updateMapCache();
- }
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &followCreature = getFollowCreature();
const auto &master = getMaster();
@@ -186,7 +182,7 @@ void Creature::onCreatureWalk() {
checkingWalkCreature = true;
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
g_dispatcher().addWalkEvent([self = std::weak_ptr(getCreature()), this] {
if (!self.lock()) {
@@ -312,125 +308,18 @@ void Creature::stopEventWalk() {
}
}
-void Creature::updateMapCache() {
- if (!useCacheMap()) {
- return;
- }
-
- metrics::method_latency measure(__METHOD_NAME__);
- std::shared_ptr newTile;
- const Position &myPos = getPosition();
- Position pos(0, 0, myPos.z);
-
- for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
- for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
- pos.x = myPos.getX() + x;
- pos.y = myPos.getY() + y;
- newTile = g_game().map.getTile(pos);
- updateTileCache(newTile, pos);
- }
- }
-}
-
-void Creature::updateTileCache(const std::shared_ptr &newTile, int32_t dx, int32_t dy) {
- metrics::method_latency measure(__METHOD_NAME__);
- if (std::abs(dx) <= maxWalkCacheWidth && std::abs(dy) <= maxWalkCacheHeight) {
- localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx] = newTile && newTile->queryAdd(0, getCreature(), 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RETURNVALUE_NOERROR;
- }
-}
-
-void Creature::updateTileCache(const std::shared_ptr &upTile, const Position &pos) {
- const Position &myPos = getPosition();
- if (pos.z == myPos.z) {
- int32_t dx = Position::getOffsetX(pos, myPos);
- int32_t dy = Position::getOffsetY(pos, myPos);
- updateTileCache(upTile, dx, dy);
- }
-}
-
-int32_t Creature::getWalkCache(const Position &pos) {
- metrics::method_latency measure(__METHOD_NAME__);
- if (!useCacheMap()) {
- return 2;
- }
-
- const Position &myPos = getPosition();
- if (myPos.z != pos.z) {
- return 0;
- }
-
- if (pos == myPos) {
- return 1;
- }
-
- int32_t dx = Position::getOffsetX(pos, myPos);
- if (std::abs(dx) <= maxWalkCacheWidth) {
- int32_t dy = Position::getOffsetY(pos, myPos);
- if (std::abs(dy) <= maxWalkCacheHeight) {
- return localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx];
- }
- }
-
- // out of range
- return 2;
-}
-
-void Creature::onAddTileItem(const std::shared_ptr &tileItem, const Position &pos) {
- if (isMapLoaded && pos.z == getPosition().z) {
- updateTileCache(tileItem, pos);
- }
-}
-
-void Creature::onUpdateTileItem(const std::shared_ptr &updateTile, const Position &pos, const std::shared_ptr- &, const ItemType &oldType, const std::shared_ptr
- &, const ItemType &newType) {
- if (!isMapLoaded) {
- return;
- }
-
- if (oldType.blockSolid || oldType.blockPathFind || newType.blockPathFind || newType.blockSolid) {
- if (pos.z == getPosition().z) {
- updateTileCache(updateTile, pos);
- }
- }
-}
-
-void Creature::onRemoveTileItem(const std::shared_ptr &updateTile, const Position &pos, const ItemType &iType, const std::shared_ptr
- &) {
- if (!isMapLoaded) {
- return;
- }
-
- if (iType.blockSolid || iType.blockPathFind || iType.isGroundTile()) {
- if (pos.z == getPosition().z) {
- updateTileCache(updateTile, pos);
- }
- }
-}
-
void Creature::onCreatureAppear(const std::shared_ptr &creature, bool isLogin) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (creature.get() == this) {
- if (useCacheMap()) {
- isMapLoaded = true;
- updateMapCache();
- }
-
if (isLogin) {
setLastPosition(getPosition());
}
- } else if (isMapLoaded) {
- if (creature->getPosition().z == getPosition().z) {
- updateTileCache(creature->getTile(), creature->getPosition());
- }
}
}
void Creature::onRemoveCreature(const std::shared_ptr &creature, bool) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
onCreatureDisappear(creature, true);
- if (creature && creature != getCreature() && isMapLoaded) {
- if (creature->getPosition().z == getPosition().z) {
- updateTileCache(creature->getTile(), creature->getPosition());
- }
- }
// Update player from monster target list (avoid memory usage after clean)
if (const auto &monster = getMonster(); monster && monster->getAttackedCreature() == creature) {
@@ -440,7 +329,7 @@ void Creature::onRemoveCreature(const std::shared_ptr &creature, bool)
}
void Creature::onCreatureDisappear(const std::shared_ptr &creature, bool isLogout) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (getAttackedCreature() == creature) {
setAttackedCreature(nullptr);
onAttackedCreatureDisappear(isLogout);
@@ -453,7 +342,7 @@ void Creature::onCreatureDisappear(const std::shared_ptr &creature, bo
}
void Creature::onChangeZone(ZoneType_t zone) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &attackedCreature = getAttackedCreature();
if (attackedCreature && zone == ZONE_PROTECTION) {
onCreatureDisappear(attackedCreature, false);
@@ -461,7 +350,7 @@ void Creature::onChangeZone(ZoneType_t zone) {
}
void Creature::onAttackedCreatureChangeZone(ZoneType_t zone) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (zone == ZONE_PROTECTION) {
const auto &attackedCreature = getAttackedCreature();
if (attackedCreature) {
@@ -471,7 +360,7 @@ void Creature::onAttackedCreatureChangeZone(ZoneType_t zone) {
}
void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (hasSummons()) {
std::vector> despawnMonsterList;
for (const auto &summon : getSummons()) {
@@ -518,7 +407,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) {
}
void Creature::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (creature.get() == this) {
lastStep = OTSYS_TIME();
lastStepCost = 1;
@@ -548,101 +437,6 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s
if (newTile->getZoneType() != oldTile->getZoneType()) {
onChangeZone(getZoneType());
}
-
- // update map cache
- if (isMapLoaded) {
- if (teleport || oldPos.z != newPos.z) {
- updateMapCache();
- } else {
- const Position &myPos = getPosition();
-
- if (oldPos.y > newPos.y) { // north
- // shift y south
- for (int32_t y = mapWalkHeight - 1; --y >= 0;) {
- std::ranges::copy(std::span(localMapCache[y]), localMapCache[y + 1]);
- }
-
- // update 0
- for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
- const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() - maxWalkCacheHeight), myPos.z);
- updateTileCache(cacheTile, x, -maxWalkCacheHeight);
- }
- } else if (oldPos.y < newPos.y) { // south
- // shift y north
- for (int32_t y = 0; y <= mapWalkHeight - 2; ++y) {
- std::ranges::copy(std::span(localMapCache[y + 1]), localMapCache[y]);
- }
-
- // update mapWalkHeight - 1
- for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
- const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() + maxWalkCacheHeight), myPos.z);
- updateTileCache(cacheTile, x, maxWalkCacheHeight);
- }
- }
-
- if (oldPos.x < newPos.x) { // east
- // shift y west
- int32_t starty = 0;
- int32_t endy = mapWalkHeight - 1;
- int32_t dy = Position::getDistanceY(oldPos, newPos);
-
- if (dy < 0) {
- endy += dy;
- } else if (dy > 0) {
- starty = dy;
- }
-
- for (int32_t y = starty; y <= endy; ++y) {
- for (int32_t x = 0; x <= mapWalkWidth - 2; ++x) {
- localMapCache[y][x] = localMapCache[y][x + 1];
- }
- }
-
- // update mapWalkWidth - 1
- for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
- const auto &cacheTile = g_game().map.getTile(myPos.x + maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z);
- updateTileCache(cacheTile, maxWalkCacheWidth, y);
- }
- } else if (oldPos.x > newPos.x) { // west
- // shift y east
- int32_t starty = 0;
- int32_t endy = mapWalkHeight - 1;
- int32_t dy = Position::getDistanceY(oldPos, newPos);
-
- if (dy < 0) {
- endy += dy;
- } else if (dy > 0) {
- starty = dy;
- }
-
- for (int32_t y = starty; y <= endy; ++y) {
- for (int32_t x = mapWalkWidth - 1; --x >= 0;) {
- localMapCache[y][x + 1] = localMapCache[y][x];
- }
- }
-
- // update 0
- for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
- const auto &cacheTile = g_game().map.getTile(myPos.x - maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z);
- updateTileCache(cacheTile, -maxWalkCacheWidth, y);
- }
- }
-
- updateTileCache(oldTile, oldPos);
- }
- }
- } else {
- if (isMapLoaded) {
- const Position &myPos = getPosition();
-
- if (newPos.z == myPos.z) {
- updateTileCache(newTile, newPos);
- }
-
- if (oldPos.z == myPos.z) {
- updateTileCache(oldTile, oldPos);
- }
- }
}
const auto &followCreature = getFollowCreature();
@@ -675,7 +469,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s
}
void Creature::onDeath() {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
bool lastHitUnjustified = false;
bool mostDamageUnjustified = false;
const auto &lastHitCreature = g_game().getCreatureByID(lastHitCreatureId);
@@ -813,7 +607,7 @@ void Creature::onDeath() {
}
bool Creature::dropCorpse(const std::shared_ptr &lastHitCreature, const std::shared_ptr &mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (!lootDrop && getMonster()) {
if (getMaster()) {
// Scripting event onDeath
@@ -1120,7 +914,7 @@ void Creature::goToFollowCreature_async(std::function &&onComplete) {
}
void Creature::goToFollowCreature() {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &followCreature = getFollowCreature();
if (!followCreature) {
return;
@@ -1175,7 +969,7 @@ bool Creature::canFollowMaster() const {
}
bool Creature::setFollowCreature(const std::shared_ptr &creature) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (creature) {
if (getFollowCreature() == creature) {
return true;
@@ -1324,7 +1118,7 @@ void Creature::onAttackedCreatureDrainHealth(const std::shared_ptr &ta
}
void Creature::onAttackedCreatureKilled(const std::shared_ptr &target) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (target != getCreature()) {
uint64_t gainExp = target->getGainedExperience(static_self_cast());
onGainExperience(gainExp, target);
@@ -1332,7 +1126,7 @@ void Creature::onAttackedCreatureKilled(const std::shared_ptr &target)
}
bool Creature::deprecatedOnKilledCreature(const std::shared_ptr &target, bool lastHit) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &master = getMaster();
if (master) {
master->deprecatedOnKilledCreature(target, lastHit);
@@ -1347,7 +1141,7 @@ bool Creature::deprecatedOnKilledCreature(const std::shared_ptr &targe
}
void Creature::onGainExperience(uint64_t gainExp, const std::shared_ptr &target) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &master = getMaster();
if (gainExp == 0 || !master) {
return;
@@ -1378,7 +1172,7 @@ void Creature::onGainExperience(uint64_t gainExp, const std::shared_ptr &newMaster, bool reloadCreature /* = false*/) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
// Persists if this creature has ever been a summon
this->summoned = true;
const auto &oldMaster = getMaster();
@@ -1411,7 +1205,7 @@ bool Creature::setMaster(const std::shared_ptr &newMaster, bool reload
}
bool Creature::addCondition(const std::shared_ptr &condition, bool attackerPlayer /* = false*/) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (condition == nullptr) {
return false;
}
@@ -1449,7 +1243,7 @@ bool Creature::addCombatCondition(const std::shared_ptr &condition, b
}
void Creature::removeCondition(ConditionType_t type) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
std::shared_ptr condition = *it;
@@ -1467,7 +1261,7 @@ void Creature::removeCondition(ConditionType_t type) {
}
void Creature::removeCondition(ConditionType_t conditionType, ConditionId_t conditionId, bool force /* = false*/) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
auto it = conditions.begin();
const auto end = conditions.end();
while (it != end) {
@@ -1530,7 +1324,7 @@ std::shared_ptr Creature::getCondition(ConditionType_t type) const {
}
std::shared_ptr Creature::getCondition(ConditionType_t type, ConditionId_t conditionId, uint32_t subId /* = 0*/) const {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
for (const auto &condition : conditions) {
if (condition->getType() == type && condition->getId() == conditionId && condition->getSubId() == subId) {
return condition;
@@ -1550,7 +1344,7 @@ std::vector> Creature::getConditionsByType(ConditionT
}
void Creature::executeConditions(uint32_t interval) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
std::shared_ptr condition = *it;
@@ -1569,7 +1363,7 @@ void Creature::executeConditions(uint32_t interval) {
}
bool Creature::hasCondition(ConditionType_t type, uint32_t subId /* = 0*/) const {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (isSuppress(type, false)) {
return false;
}
@@ -1845,7 +1639,7 @@ ZoneType_t Creature::getZoneType() {
}
bool Creature::getPathTo(const Position &targetPos, std::vector &dirList, const FindPathParams &fpp) {
- metrics::method_latency measure(__METHOD_NAME__);
+ metrics::method_latency measure(__METRICS_METHOD_NAME__);
if (fpp.maxSearchDist != 0 || fpp.keepDistance) {
return g_game().map.getPathMatchingCond(getCreature(), targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp);
}
diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp
index 01477378efa..18a4bd817ab 100644
--- a/src/creatures/creature.hpp
+++ b/src/creatures/creature.hpp
@@ -494,9 +494,9 @@ class Creature : virtual public Thing, public SharedObject {
virtual void turnToCreature(const std::shared_ptr &creature);
- void onAddTileItem(const std::shared_ptr &tile, const Position &pos);
- virtual void onUpdateTileItem(const std::shared_ptr &tile, const Position &pos, const std::shared_ptr
- &oldItem, const ItemType &oldType, const std::shared_ptr
- &newItem, const ItemType &newType);
- virtual void onRemoveTileItem(const std::shared_ptr &tile, const Position &pos, const ItemType &iType, const std::shared_ptr
- &item);
+ void onAddTileItem(const std::shared_ptr & /*tile*/, const Position & /*pos*/) { }
+ virtual void onUpdateTileItem(const std::shared_ptr &tile, const Position &pos, const std::shared_ptr
- &oldItem, const ItemType &oldType, const std::shared_ptr
- &newItem, const ItemType &newType) { }
+ virtual void onRemoveTileItem(const std::shared_ptr &tile, const Position &pos, const ItemType &iType, const std::shared_ptr
- &item) { }
virtual void onCreatureAppear(const std::shared_ptr &creature, bool isLogin);
virtual void onRemoveCreature(const std::shared_ptr &creature, bool isLogout);
@@ -566,8 +566,6 @@ class Creature : virtual public Thing, public SharedObject {
return m_tile.lock();
}
- int32_t getWalkCache(const Position &pos);
-
const Position &getLastPosition() const {
return lastPosition;
}
@@ -705,19 +703,10 @@ class Creature : virtual public Thing, public SharedObject {
Pathfinder = 1 << 3
};
- virtual bool useCacheMap() const {
- return false;
- }
-
virtual bool isDead() const {
return false;
}
- static constexpr int32_t mapWalkWidth = MAP_MAX_VIEW_PORT_X * 2 + 1;
- static constexpr int32_t mapWalkHeight = MAP_MAX_VIEW_PORT_Y * 2 + 1;
- static constexpr int32_t maxWalkCacheWidth = (mapWalkWidth - 1) / 2;
- static constexpr int32_t maxWalkCacheHeight = (mapWalkHeight - 1) / 2;
-
Position position;
CountMap damageMap;
@@ -781,9 +770,7 @@ class Creature : virtual public Thing, public SharedObject {
std::atomic_bool creatureCheck = false;
std::atomic_bool inCheckCreaturesVector = false;
- bool localMapCache[mapWalkHeight][mapWalkWidth] = { { false } };
bool isInternalRemoved = false;
- bool isMapLoaded = false;
bool isUpdatingPath = false;
bool skillLoss = true;
bool lootDrop = true;
@@ -807,9 +794,6 @@ class Creature : virtual public Thing, public SharedObject {
bool hasEventRegistered(CreatureEventType_t event) const;
CreatureEventList getCreatureEvents(CreatureEventType_t type) const;
- void updateMapCache();
- void updateTileCache(const std::shared_ptr &tile, int32_t dx, int32_t dy);
- void updateTileCache(const std::shared_ptr &tile, const Position &pos);
void onCreatureDisappear(const std::shared_ptr &creature, bool isLogout);
virtual void doAttacking(uint32_t) { }
virtual bool hasExtraSwing() {
diff --git a/src/creatures/creatures_definitions.hpp b/src/creatures/creatures_definitions.hpp
index f7ba1e203b1..dd554c086b3 100644
--- a/src/creatures/creatures_definitions.hpp
+++ b/src/creatures/creatures_definitions.hpp
@@ -706,6 +706,8 @@ enum SpellGroup_t : uint8_t {
SPELLGROUP_CRIPPLING = 6,
SPELLGROUP_FOCUS = 7,
SPELLGROUP_ULTIMATESTRIKES = 8,
+ SPELLGROUP_BURSTS_OF_NATURE = 9,
+ SPELLGROUP_GREAT_BEAMS = 10,
};
enum ChannelEvent_t : uint8_t {
diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp
index 89345fab9c4..16d80f14d75 100644
--- a/src/creatures/monsters/monster.cpp
+++ b/src/creatures/monsters/monster.cpp
@@ -1014,10 +1014,7 @@ void Monster::onAddCondition(ConditionType_t type) {
onConditionStatusChange(type);
}
-void Monster::onConditionStatusChange(ConditionType_t type) {
- if (type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON) {
- updateMapCache();
- }
+void Monster::onConditionStatusChange(ConditionType_t /*type*/) {
updateIdleStatus();
}
@@ -1517,7 +1514,6 @@ void Monster::doWalkBack(uint32_t &flags, Direction &nextDirection, bool &result
} else {
if (ignoreFieldDamage) {
ignoreFieldDamage = false;
- updateMapCache();
}
int32_t distance = std::max(Position::getDistanceX(position, masterPos), Position::getDistanceY(position, masterPos));
@@ -1543,7 +1539,6 @@ void Monster::doFollowCreature(uint32_t &flags, Direction &nextDirection, bool &
} else {
if (ignoreFieldDamage) {
ignoreFieldDamage = false;
- updateMapCache();
}
// target dancing
const auto &attackedCreature = getAttackedCreature();
@@ -2225,10 +2220,6 @@ void Monster::setHazardSystemDefenseBoost(bool value) {
bool Monster::canWalkTo(Position pos, Direction moveDirection) {
pos = getNextPosition(moveDirection, pos);
if (isInSpawnRange(pos)) {
- if (getWalkCache(pos) == 0) {
- return false;
- }
-
const auto &tile = g_game().map.getTile(pos);
if (tile && tile->getTopVisibleCreature(getMonster()) == nullptr && tile->queryAdd(0, getMonster(), 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RETURNVALUE_NOERROR) {
return true;
@@ -2405,7 +2396,6 @@ void Monster::drainHealth(const std::shared_ptr &attacker, int32_t dam
if (damage > 0 && randomStepping) {
ignoreFieldDamage = true;
- updateMapCache();
}
if (isInvisible()) {
diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp
index ed9a628159f..b8a6087acc1 100644
--- a/src/creatures/monsters/monster.hpp
+++ b/src/creatures/monsters/monster.hpp
@@ -332,13 +332,6 @@ class Monster final : public Creature {
uint16_t getLookCorpse() const override;
void dropLoot(const std::shared_ptr &corpse, const std::shared_ptr &lastHitCreature) override;
void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override;
- bool useCacheMap() const override {
- // return !randomStepping;
- // As the map cache is done synchronously for each movement that a monster makes, it is better to disable it,
- // as the pathfinder, which is one of the resources that uses this cache the most,
- // is multithreding and thus the processing cost is divided between the threads.
- return false;
- }
friend class MonsterFunctions;
friend class Map;
diff --git a/src/creatures/monsters/monsters.cpp b/src/creatures/monsters/monsters.cpp
index 87fd967ab46..cd33e12e248 100644
--- a/src/creatures/monsters/monsters.cpp
+++ b/src/creatures/monsters/monsters.cpp
@@ -16,6 +16,7 @@
#include "game/game.hpp"
#include "items/weapons/weapons.hpp"
#include "lua/scripts/luascript.hpp"
+#include "lib/di/container.hpp"
void MonsterType::loadLoot(const std::shared_ptr &monsterType, LootBlock lootBlock) const {
if (lootBlock.childLoot.empty()) {
diff --git a/src/creatures/npcs/npcs.cpp b/src/creatures/npcs/npcs.cpp
index cff44588d71..53ed757336f 100644
--- a/src/creatures/npcs/npcs.cpp
+++ b/src/creatures/npcs/npcs.cpp
@@ -14,6 +14,7 @@
#include "lua/scripts/lua_environment.hpp"
#include "lua/scripts/luascript.hpp"
#include "lua/scripts/scripts.hpp"
+#include "lib/di/container.hpp"
bool NpcType::canSpawn(const Position &pos) const {
bool canSpawn = true;
diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp
index 0c29e1d1534..66fd6b9e98b 100644
--- a/src/creatures/players/player.cpp
+++ b/src/creatures/players/player.cpp
@@ -62,6 +62,7 @@
#include "lua/creature/events.hpp"
#include "lua/creature/movement.hpp"
#include "map/spectators.hpp"
+#include "creatures/players/vocations/vocation.hpp"
MuteCountMap Player::muteCountMap;
@@ -977,8 +978,6 @@ void Player::closeContainer(uint8_t cid) {
removeEmptyRewards();
}
openContainers.erase(it);
- if (container && container->getID() == ITEM_BROWSEFIELD) {
- }
}
void Player::removeEmptyRewards() {
@@ -2740,6 +2739,10 @@ uint16_t Player::getGrindingXpBoost() const {
return grindingXpBoost;
}
+uint16_t Player::getDisplayGrindingXpBoost() const {
+ return std::clamp(grindingXpBoost * (baseXpGain / 100), 0, std::numeric_limits::max());
+}
+
void Player::setGrindingXpBoost(uint16_t value) {
grindingXpBoost = std::min(std::numeric_limits::max(), value);
}
@@ -2748,6 +2751,10 @@ uint16_t Player::getXpBoostPercent() const {
return xpBoostPercent;
}
+uint16_t Player::getDisplayXpBoostPercent() const {
+ return std::clamp(xpBoostPercent * (baseXpGain / 100), 0, std::numeric_limits::max());
+}
+
void Player::setXpBoostPercent(uint16_t percent) {
xpBoostPercent = percent;
}
@@ -3452,7 +3459,6 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
g_game().sendSingleSoundEffect(static_self_cast()->getPosition(), sex == PLAYERSEX_FEMALE ? SoundEffect_t::HUMAN_FEMALE_DEATH : SoundEffect_t::HUMAN_MALE_DEATH, getPlayer());
if (skillLoss) {
- uint8_t unfairFightReduction = 100;
int playerDmg = 0;
int othersDmg = 0;
uint32_t sumLevels = 0;
@@ -3469,10 +3475,13 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
}
}
}
+
bool pvpDeath = false;
if (playerDmg > 0 || othersDmg > 0) {
pvpDeath = (Player::lastHitIsPlayer(lastHitCreature) || playerDmg / (playerDmg + static_cast(othersDmg)) >= 0.05);
}
+
+ uint8_t unfairFightReduction = 100;
if (pvpDeath && sumLevels > level) {
double reduce = level / static_cast(sumLevels);
unfairFightReduction = std::max(20, std::floor((reduce * 100) + 0.5));
@@ -3482,7 +3491,7 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
uint64_t sumMana = 0;
uint64_t lostMana = 0;
- // sum up all the mana
+ // Sum up all the mana
for (uint32_t i = 1; i <= magLevel; ++i) {
sumMana += vocation->getReqMana(i);
}
@@ -3492,12 +3501,10 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
double deathLossPercent = getLostPercent() * (unfairFightReduction / 100.);
// Charm bless bestiary
- if (lastHitCreature && lastHitCreature->getMonster()) {
- if (charmRuneBless != 0) {
- const auto mType = g_monsters().getMonsterType(lastHitCreature->getName());
- if (mType && mType->info.raceid == charmRuneBless) {
- deathLossPercent = (deathLossPercent * 90) / 100;
- }
+ if (lastHitCreature && lastHitCreature->getMonster() && charmRuneBless != 0) {
+ const auto &mType = g_monsters().getMonsterType(lastHitCreature->getName());
+ if (mType && mType->info.raceid == charmRuneBless) {
+ deathLossPercent = (deathLossPercent * 90) / 100;
}
}
@@ -3519,7 +3526,9 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
}
// Level loss
- auto expLoss = static_cast(experience * deathLossPercent);
+ auto expLoss = static_cast(std::ceil(experience * deathLossPercent));
+ g_logger().debug("[{}] - experience lost {}", __FUNCTION__, expLoss);
+
g_events().eventPlayerOnLoseExperience(static_self_cast(), expLoss);
g_callbacks().executeCallback(EventCallback_t::playerOnLoseExperience, &EventCallback::playerOnLoseExperience, getPlayer(), expLoss);
@@ -3528,9 +3537,9 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
lostExp << "You lost " << expLoss << " experience.";
// Skill loss
- for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { // for each skill
+ for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { // For each skill
uint64_t sumSkillTries = 0;
- for (uint16_t c = 11; c <= skills[i].level; ++c) { // sum up all required tries for all skill levels
+ for (uint16_t c = 11; c <= skills[i].level; ++c) { // Sum up all required tries for all skill levels
sumSkillTries += vocation->getReqSkillTries(i, c);
}
@@ -3606,14 +3615,21 @@ void Player::death(const std::shared_ptr &lastHitCreature) {
bless.empty() ? blessOutput << "You weren't protected with any blessings."
: blessOutput << "You were blessed with " << bless;
- // Make player lose bless
+ const auto playerSkull = getSkull();
+ bool hasSkull = (playerSkull == Skulls_t::SKULL_RED || playerSkull == Skulls_t::SKULL_BLACK);
uint8_t maxBlessing = 8;
- if (pvpDeath && hasBlessing(1)) {
+ if (!hasSkull && pvpDeath && hasBlessing(1)) {
removeBlessing(1, 1); // Remove TOF only
} else {
for (int i = 2; i <= maxBlessing; i++) {
removeBlessing(i, 1);
}
+
+ const auto &playerAmulet = getThing(CONST_SLOT_NECKLACE);
+ bool usingAol = (playerAmulet && playerAmulet->getItem()->getID() == ITEM_AMULETOFLOSS);
+ if (usingAol) {
+ removeItemOfType(ITEM_AMULETOFLOSS, 1, -1);
+ }
}
}
sendTextMessage(MESSAGE_EVENT_ADVANCE, blessOutput.str());
@@ -5023,8 +5039,8 @@ ItemsTierCountList Player::getDepotChestItemsId() const {
ItemsTierCountList Player::getDepotInboxItemsId() const {
ItemsTierCountList itemMap;
- const auto &inbox = getInbox();
- const auto &container = inbox->getContainer();
+ const auto &inboxPtr = getInbox();
+ const auto &container = inboxPtr->getContainer();
if (container) {
for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) {
const auto &item = *it;
@@ -6295,21 +6311,30 @@ double Player::getLostPercent() const {
return std::max(0, deathLosePercent) / 100.;
}
+ bool isRetro = g_configManager().getBoolean(TOGGLE_SERVER_IS_RETRO);
+ const auto factor = (isRetro ? 6.31 : 8);
+ double percentReduction = (blessingCount * factor) / 100.;
+
double lossPercent;
if (level >= 24) {
const double tmpLevel = level + (levelPercent / 100.);
lossPercent = ((tmpLevel + 50) * 50 * ((tmpLevel * tmpLevel) - (5 * tmpLevel) + 8)) / experience;
} else {
- lossPercent = 5;
+ percentReduction = (percentReduction >= 0.40 ? 0.50 : percentReduction);
+ lossPercent = 10;
}
- double percentReduction = 0;
+ g_logger().debug("[{}] - lossPercent {}", __FUNCTION__, lossPercent);
+ g_logger().debug("[{}] - before promotion {}", __FUNCTION__, percentReduction);
+
if (isPromoted()) {
- percentReduction += 30;
+ percentReduction += 30 / 100.;
+ g_logger().debug("[{}] - after promotion {}", __FUNCTION__, percentReduction);
}
- percentReduction += blessingCount * 8;
- return lossPercent * (1 - (percentReduction / 100.)) / 100.;
+ g_logger().debug("[{}] - total lost percent {}", __FUNCTION__, (lossPercent * (1 - percentReduction)) / 100.);
+
+ return (lossPercent * (1 - percentReduction)) / 100.;
}
[[nodiscard]] const std::string &Player::getGuildNick() const {
@@ -6341,7 +6366,7 @@ uint32_t Player::getMagicLevel() const {
uint32_t magic = std::max(0, getLoyaltyMagicLevel() + varStats[STAT_MAGICPOINTS]);
// Wheel of destiny magic bonus
magic += m_wheelPlayer->getStat(WheelStat_t::MAGIC); // Regular bonus
- magic += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::MAGIC); // Revelation bonus
+ magic += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::MAGIC); // Revelation bonus
return magic;
}
@@ -6399,12 +6424,12 @@ uint16_t Player::getSkillLevel(skills_t skill) const {
skillLevel += m_wheelPlayer->getStat(WheelStat_t::MELEE);
skillLevel += m_wheelPlayer->getMajorStatConditional("Battle Instinct", WheelMajor_t::MELEE);
} else if (skill == SKILL_DISTANCE) {
- skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::DISTANCE);
+ skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::DISTANCE);
skillLevel += m_wheelPlayer->getStat(WheelStat_t::DISTANCE);
} else if (skill == SKILL_SHIELD) {
skillLevel += m_wheelPlayer->getMajorStatConditional("Battle Instinct", WheelMajor_t::SHIELD);
} else if (skill == SKILL_MAGLEVEL) {
- skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::MAGIC);
+ skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::MAGIC);
skillLevel += m_wheelPlayer->getStat(WheelStat_t::MAGIC);
} else if (skill == SKILL_LIFE_LEECH_AMOUNT) {
skillLevel += m_wheelPlayer->getStat(WheelStat_t::LIFE_LEECH);
@@ -6506,7 +6531,7 @@ void Player::setPerfectShotDamage(uint8_t range, int32_t damage) {
}
int32_t Player::getSpecializedMagicLevel(CombatType_t combat, bool useCharges) const {
- int32_t result = specializedMagicLevel[combatTypeToIndex(combat)];
+ int32_t result = specializedMagicLevel[combatTypeToIndex(combat)] + m_wheelPlayer->getSpecializedMagic(combat);
for (const auto &item : getEquippedItems()) {
const ItemType &itemType = Item::items[item->getID()];
if (!itemType.abilities) {
@@ -8020,7 +8045,7 @@ void sendStowItems(const std::shared_ptr
- &item, const std::shared_ptr
- &item, uint32_t count, bool allItems) {
- if (!item || !item->isItemStorable()) {
+ if (!item || (!item->isItemStorable() && item->getID() != ITEM_GOLD_POUCH)) {
sendCancelMessage("This item cannot be stowed here.");
return;
}
@@ -8822,8 +8847,6 @@ void Player::triggerTranscendance() {
}
// Forge system
-// Forge system
-
void Player::forgeFuseItems(ForgeAction_t actionType, uint16_t firstItemId, uint8_t tier, uint16_t secondItemId, bool success, bool reduceTierLoss, bool convergence, uint8_t bonus, uint8_t coreCount) {
if (getFreeBackpackSlots() == 0) {
sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp
index 03f248cfa2f..6ab3be4ca7a 100644
--- a/src/creatures/players/player.hpp
+++ b/src/creatures/players/player.hpp
@@ -972,8 +972,10 @@ class Player final : public Creature, public Cylinder, public Bankable {
uint16_t getVoucherXpBoost() const;
void setVoucherXpBoost(uint16_t value);
uint16_t getGrindingXpBoost() const;
+ uint16_t getDisplayGrindingXpBoost() const;
void setGrindingXpBoost(uint16_t value);
uint16_t getXpBoostPercent() const;
+ uint16_t getDisplayXpBoostPercent() const;
void setXpBoostPercent(uint16_t percent);
uint16_t getStaminaXpBoost() const;
void setStaminaXpBoost(uint16_t value);
diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp
index 6d3ee2713a7..7d39720dc4d 100644
--- a/src/creatures/players/wheel/player_wheel.cpp
+++ b/src/creatures/players/wheel/player_wheel.cpp
@@ -9,6 +9,8 @@
#include "creatures/players/wheel/player_wheel.hpp"
+#include "map/spectators.hpp"
+#include "creatures/monsters/monster.hpp"
#include "config/configmanager.hpp"
#include "creatures/combat/condition.hpp"
#include "creatures/combat/spells.hpp"
@@ -957,6 +959,45 @@ int PlayerWheel::getSpellAdditionalDuration(const std::string &spellName) const
return 0;
}
+bool PlayerWheel::handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const {
+ // Map of spell pairs for Twin Bursts
+ static const std::unordered_map spellPairs = {
+ { "Terra Burst", "Ice Burst" },
+ { "Ice Burst", "Terra Burst" }
+ };
+
+ auto it = spellPairs.find(spellName);
+ if (it != spellPairs.end()) {
+ const auto &spell = g_spells().getSpellByName(it->second);
+ if (spell) {
+ const auto spellId = spell->getSpellId();
+ const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId);
+ return player->addCondition(condition);
+ }
+ }
+
+ return false;
+}
+
+bool PlayerWheel::handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const {
+ static const std::unordered_map spellPairs = {
+ { "Great Death Beam", "Great Energy Beam" },
+ { "Great Energy Beam", "Great Death Beam" }
+ };
+
+ auto it = spellPairs.find(spellName);
+ if (it != spellPairs.end()) {
+ const auto &spell = g_spells().getSpellByName(it->second);
+ if (spell) {
+ const auto spellId = spell->getSpellId();
+ const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId);
+ return player->addCondition(condition);
+ }
+ }
+
+ return false;
+}
+
void PlayerWheel::addPromotionScrolls(NetworkMessage &msg) const {
std::vector unlockedScrolls;
@@ -988,7 +1029,7 @@ std::shared_ptr PlayerWheel::gemsGradeKV(WheelFragmentType_t type, uint8_t p
uint8_t PlayerWheel::getGemGrade(WheelFragmentType_t type, uint8_t pos) const {
uint8_t grade = 0;
- auto gradeKV = gemsGradeKV(type, pos)->get("grade");
+ const auto gradeKV = gemsGradeKV(type, pos)->get("grade");
if (gradeKV.has_value()) {
grade = static_cast(gradeKV->get());
@@ -1190,7 +1231,7 @@ void PlayerWheel::destroyGem(uint16_t index) const {
if (greaterFragments > 0) {
const auto &fragmentsItem = Item::CreateItem(ITEM_GREATER_FRAGMENT, greaterFragments);
- auto returnValue = g_game().internalPlayerAddItem(m_player.getPlayer(), fragmentsItem, false, CONST_SLOT_BACKPACK);
+ auto returnValue = g_game().internalPlayerAddItem(m_player.getPlayer(), fragmentsItem, false, CONST_SLOT_WHEREEVER);
if (returnValue != RETURNVALUE_NOERROR) {
g_logger().error("Failed to add {} greater fragments to player with name {}", greaterFragments, m_player.getName());
m_player.sendCancelMessage(getReturnMessage(RETURNVALUE_CONTACTADMINISTRATOR));
@@ -1201,8 +1242,11 @@ void PlayerWheel::destroyGem(uint16_t index) const {
gem.remove(gemsKV());
- m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT));
- m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT));
+ const auto totalLesserFragment = m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT) + m_player.getStashItemCount(ITEM_LESSER_FRAGMENT);
+ const auto totalGreaterFragment = m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT) + m_player.getStashItemCount(ITEM_GREATER_FRAGMENT);
+
+ m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, totalLesserFragment);
+ m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, totalGreaterFragment);
sendOpenWheelWindow(m_player.getID());
}
@@ -1233,7 +1277,7 @@ void PlayerWheel::toggleGemLock(uint16_t index) const {
}
void PlayerWheel::setActiveGem(WheelGemAffinity_t affinity, uint16_t index) const {
- const auto gem = getGem(index);
+ auto gem = getGem(index);
if (gem.uuid.empty()) {
g_logger().error("[{}] Failed to load gem with index {}", __FUNCTION__, index);
return;
@@ -1251,6 +1295,67 @@ void PlayerWheel::removeActiveGem(WheelGemAffinity_t affinity) const {
gemsKV()->scoped("active")->remove(key);
}
+void PlayerWheel::addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points) {
+ m_bonusRevelationPoints[static_cast(affinity)] += points;
+}
+
+void PlayerWheel::resetRevelationBonus() {
+ m_bonusRevelationPoints = { 0, 0, 0, 0 };
+}
+
+void PlayerWheel::addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus) {
+ if (m_spellsBonuses.contains(spellName)) {
+ m_spellsBonuses[spellName].decrease.cooldown += bonus.decrease.cooldown;
+ m_spellsBonuses[spellName].decrease.manaCost += bonus.decrease.manaCost;
+ m_spellsBonuses[spellName].decrease.secondaryGroupCooldown += bonus.decrease.secondaryGroupCooldown;
+ m_spellsBonuses[spellName].increase.aditionalTarget += bonus.increase.aditionalTarget;
+ m_spellsBonuses[spellName].increase.area = bonus.increase.area;
+ m_spellsBonuses[spellName].increase.criticalChance += bonus.increase.criticalChance;
+ m_spellsBonuses[spellName].increase.criticalDamage += bonus.increase.criticalDamage;
+ m_spellsBonuses[spellName].increase.damage += bonus.increase.damage;
+ m_spellsBonuses[spellName].increase.damageReduction += bonus.increase.damageReduction;
+ m_spellsBonuses[spellName].increase.duration += bonus.increase.duration;
+ m_spellsBonuses[spellName].increase.heal += bonus.increase.heal;
+ m_spellsBonuses[spellName].leech.life += bonus.leech.life;
+ m_spellsBonuses[spellName].leech.mana += bonus.leech.mana;
+ return;
+ }
+ m_spellsBonuses[spellName] = bonus;
+}
+
+int32_t PlayerWheel::getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const {
+ using enum WheelSpellBoost_t;
+
+ if (!m_spellsBonuses.contains(spellName)) {
+ return 0;
+ }
+ const auto &[leech, increase, decrease] = m_spellsBonuses.at(spellName);
+ switch (boost) {
+ case COOLDOWN:
+ return decrease.cooldown;
+ case MANA:
+ return decrease.manaCost;
+ case SECONDARY_GROUP_COOLDOWN:
+ return decrease.secondaryGroupCooldown;
+ case CRITICAL_CHANCE:
+ return increase.criticalChance;
+ case CRITICAL_DAMAGE:
+ return increase.criticalDamage;
+ case DAMAGE:
+ return increase.damage;
+ case DAMAGE_REDUCTION:
+ return increase.damageReduction;
+ case HEAL:
+ return increase.heal;
+ case LIFE_LEECH:
+ return leech.life;
+ case MANA_LEECH:
+ return leech.mana;
+ default:
+ return 0;
+ }
+}
+
void PlayerWheel::addGems(NetworkMessage &msg) const {
const auto activeGems = getActiveGems();
msg.addByte(activeGems.size());
@@ -1343,7 +1448,7 @@ void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos)
return;
}
- if (!m_player.hasItemCountById(fragmentId, quantity, false)) {
+ if (!m_player.hasItemCountById(fragmentId, quantity, true)) {
g_logger().error("[{}] Player {} does not have the required {} fragments with id {}", __FUNCTION__, m_player.getName(), quantity, fragmentId);
return;
}
@@ -1353,7 +1458,7 @@ void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos)
return;
}
- if (!m_player.removeItemCountById(fragmentId, quantity, false)) {
+ if (!m_player.removeItemCountById(fragmentId, quantity, true)) {
g_logger().error("[{}] Failed to remove {} fragments with id {} from player {}", std::source_location::current().function_name(), quantity, fragmentId, m_player.getName());
return;
}
@@ -1414,20 +1519,23 @@ void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) {
addPromotionScrolls(msg);
addGems(msg);
addGradeModifiers(msg);
- // TODO: read items from inventory
+
const auto &voc = m_player.getVocation();
if (!voc) {
g_logger().error("[{}] Failed to get vocation for player {}", __FUNCTION__, m_player.getName());
return;
}
+ const auto totalLesserFragment = m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT) + m_player.getStashItemCount(ITEM_LESSER_FRAGMENT);
+ const auto totalGreaterFragment = m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT) + m_player.getStashItemCount(ITEM_GREATER_FRAGMENT);
+
m_player.client->sendResourceBalance(RESOURCE_BANK, m_player.getBankBalance());
m_player.client->sendResourceBalance(RESOURCE_INVENTORY_MONEY, m_player.getMoney());
m_player.client->sendResourceBalance(RESOURCE_LESSER_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Lesser)));
m_player.client->sendResourceBalance(RESOURCE_REGULAR_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Regular)));
m_player.client->sendResourceBalance(RESOURCE_GREATER_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Greater)));
- m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT));
- m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT));
+ m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, totalLesserFragment);
+ m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, totalGreaterFragment);
}
void PlayerWheel::sendGiftOfLifeCooldown() const {
@@ -1569,7 +1677,7 @@ void PlayerWheel::saveSlotPointsOnPressSaveButton(NetworkMessage &msg) {
*/
void PlayerWheel::loadDBPlayerSlotPointsOnLogin() {
auto resultString = fmt::format("SELECT `slot` FROM `player_wheeldata` WHERE `player_id` = {}", m_player.getGUID());
- const DBResult_ptr &result = Database::getInstance().storeQuery(resultString);
+ const DBResult_ptr &result = g_database().storeQuery(resultString);
// Ignore if player not have nothing inserted in the table
if (!result) {
return;
@@ -1590,17 +1698,12 @@ void PlayerWheel::loadDBPlayerSlotPointsOnLogin() {
}
bool PlayerWheel::saveDBPlayerSlotPointsOnLogout() const {
- const Database &db = Database::getInstance();
- std::ostringstream query;
DBInsert insertWheelData("INSERT INTO `player_wheeldata` (`player_id`, `slot`) VALUES ");
insertWheelData.upsert({ "slot" });
PropWriteStream stream;
const auto wheelSlots = getSlots();
for (uint8_t i = 1; i < wheelSlots.size(); ++i) {
auto value = wheelSlots[i];
- if (value == 0) {
- continue;
- }
stream.write(i);
stream.write(value);
@@ -1610,7 +1713,7 @@ bool PlayerWheel::saveDBPlayerSlotPointsOnLogout() const {
size_t attributesSize;
const char* attributes = stream.getStream(attributesSize);
if (attributesSize > 0) {
- query << m_player.getGUID() << ',' << db.escapeBlob(attributes, static_cast(attributesSize));
+ const auto query = fmt::format("{}, {}", m_player.getGUID(), g_database().escapeBlob(attributes, static_cast(attributesSize)));
if (!insertWheelData.addRow(query)) {
g_logger().debug("[{}] failed to insert row data", __FUNCTION__);
return false;
@@ -1819,7 +1922,7 @@ void PlayerWheel::reloadPlayerData() const {
void PlayerWheel::registerPlayerBonusData() {
addStat(WheelStat_t::HEALTH, m_playerBonusData.stats.health);
addStat(WheelStat_t::MANA, m_playerBonusData.stats.mana);
- addStat(WheelStat_t::CAPACITY, m_playerBonusData.stats.capacity * 100);
+ addStat(WheelStat_t::CAPACITY, m_playerBonusData.stats.capacity);
addStat(WheelStat_t::MITIGATION, m_playerBonusData.mitigation * 100);
addStat(WheelStat_t::DAMAGE, m_playerBonusData.stats.damage);
addStat(WheelStat_t::HEALING, m_playerBonusData.stats.healing);
@@ -1836,7 +1939,7 @@ void PlayerWheel::registerPlayerBonusData() {
// Instant
setSpellInstant("Battle Instinct", m_playerBonusData.instant.battleInstinct);
setSpellInstant("Battle Healing", m_playerBonusData.instant.battleHealing);
- setSpellInstant("Positional Tatics", m_playerBonusData.instant.positionalTatics);
+ setSpellInstant("Positional Tactics", m_playerBonusData.instant.positionalTactics);
setSpellInstant("Ballistic Mastery", m_playerBonusData.instant.ballisticMastery);
setSpellInstant("Healing Link", m_playerBonusData.instant.healingLink);
setSpellInstant("Runic Mastery", m_playerBonusData.instant.runicMastery);
@@ -1871,14 +1974,13 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.stages.divineEmpowerment; ++i) {
setSpellInstant("Divine Empowerment", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 4 * 1000;
+
if (m_playerBonusData.stages.divineEmpowerment >= 2) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 4000;
addSpellBonus("Divine Empowerment", bonus);
}
if (m_playerBonusData.stages.divineEmpowerment >= 3) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 4000;
addSpellBonus("Divine Empowerment", bonus);
}
} else {
@@ -1891,12 +1993,12 @@ void PlayerWheel::registerPlayerBonusData() {
}
if (m_playerBonusData.stages.divineGrenade >= 2) {
WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 4000;
+ bonus.decrease.cooldown = 4 * 1000;
addSpellBonus("Divine Grenade", bonus);
}
if (m_playerBonusData.stages.divineGrenade >= 3) {
WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 6000;
+ bonus.decrease.cooldown = 6 * 1000;
addSpellBonus("Divine Grenade", bonus);
}
} else {
@@ -1911,9 +2013,21 @@ void PlayerWheel::registerPlayerBonusData() {
setSpellInstant("Drain Body", false);
}
if (m_playerBonusData.stages.beamMastery > 0) {
+ m_beamMasterySpells.emplace("Energy Beam");
+ m_beamMasterySpells.emplace("Great Death Beam");
+ m_beamMasterySpells.emplace("Great Energy Beam");
for (int i = 0; i < m_playerBonusData.stages.beamMastery; ++i) {
setSpellInstant("Beam Mastery", true);
}
+ WheelSpells::Bonus deathBeamBonus;
+ deathBeamBonus.decrease.cooldown = 2 * 1000;
+ deathBeamBonus.increase.damage = 6;
+ if (m_playerBonusData.stages.beamMastery >= 2) {
+ addSpellBonus("Great Death Beam", deathBeamBonus);
+ }
+ if (m_playerBonusData.stages.beamMastery >= 3) {
+ addSpellBonus("Great Death Beam", deathBeamBonus);
+ }
} else {
setSpellInstant("Beam Mastery", false);
}
@@ -1922,6 +2036,17 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.stages.twinBurst; ++i) {
setSpellInstant("Twin Burst", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 4 * 1000;
+ bonus.decrease.secondaryGroupCooldown = 4 * 1000;
+ if (m_playerBonusData.stages.twinBurst >= 2) {
+ addSpellBonus("Ice Burst", bonus);
+ addSpellBonus("Terra Burst", bonus);
+ }
+ if (m_playerBonusData.stages.twinBurst >= 3) {
+ addSpellBonus("Ice Burst", bonus);
+ addSpellBonus("Terra Burst", bonus);
+ }
} else {
setSpellInstant("Twin Burst", false);
}
@@ -1930,6 +2055,14 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.stages.executionersThrow; ++i) {
setSpellInstant("Executioner's Throw", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 4 * 1000;
+ if (m_playerBonusData.stages.executionersThrow >= 2) {
+ addSpellBonus("Executioner's Throw", bonus);
+ }
+ if (m_playerBonusData.stages.executionersThrow >= 3) {
+ addSpellBonus("Executioner's Throw", bonus);
+ }
} else {
setSpellInstant("Executioner's Throw", false);
}
@@ -1939,14 +2072,13 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.avatar.light; ++i) {
setSpellInstant("Avatar of Light", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
+
if (m_playerBonusData.avatar.light >= 2) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Light", bonus);
}
if (m_playerBonusData.avatar.light >= 3) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Light", bonus);
}
} else {
@@ -1957,14 +2089,13 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.avatar.nature; ++i) {
setSpellInstant("Avatar of Nature", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
+
if (m_playerBonusData.avatar.nature >= 2) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Nature", bonus);
}
if (m_playerBonusData.avatar.nature >= 3) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Nature", bonus);
}
} else {
@@ -1975,14 +2106,12 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.avatar.steel; ++i) {
setSpellInstant("Avatar of Steel", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
if (m_playerBonusData.avatar.steel >= 2) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Steel", bonus);
}
if (m_playerBonusData.avatar.steel >= 3) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Steel", bonus);
}
} else {
@@ -1993,14 +2122,12 @@ void PlayerWheel::registerPlayerBonusData() {
for (int i = 0; i < m_playerBonusData.avatar.storm; ++i) {
setSpellInstant("Avatar of Storm", true);
}
+ WheelSpells::Bonus bonus;
+ bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
if (m_playerBonusData.avatar.storm >= 2) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Storm", bonus);
}
if (m_playerBonusData.avatar.storm >= 3) {
- WheelSpells::Bonus bonus;
- bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes
addSpellBonus("Avatar of Storm", bonus);
}
} else {
@@ -2100,8 +2227,8 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus
if (bonusData.instant.battleHealing) {
g_logger().debug(" battleHealing: {}", bonusData.instant.battleHealing);
}
- if (bonusData.instant.positionalTatics) {
- g_logger().debug(" positionalTatics: {}", bonusData.instant.positionalTatics);
+ if (bonusData.instant.positionalTactics) {
+ g_logger().debug(" positionalTactics: {}", bonusData.instant.positionalTactics);
}
if (bonusData.instant.ballisticMastery) {
g_logger().debug(" ballisticMastery: {}", bonusData.instant.ballisticMastery);
@@ -2167,10 +2294,10 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus
g_logger().debug("mitigation: {}", bonusData.mitigation);
}
- auto &spellsVector = bonusData.spells;
+ const auto &spellsVector = bonusData.spells;
if (!spellsVector.empty()) {
g_logger().debug("Spells:");
- for (const auto &spell : bonusData.spells) {
+ for (const auto &spell : spellsVector) {
g_logger().debug(" {}", spell);
}
}
@@ -2180,7 +2307,7 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus
void PlayerWheel::loadDedicationAndConvictionPerks() {
using VocationBonusFunction = std::function &, uint16_t, uint8_t, PlayerWheelMethodsBonusData &)>;
- auto wheelFunctions = g_game().getIOWheel()->getWheelMapFunctions();
+ const auto &wheelFunctions = g_game().getIOWheel()->getWheelMapFunctions();
const auto vocationCipId = m_player.getPlayerVocationEnum();
if (vocationCipId < VOCATION_KNIGHT_CIP || vocationCipId > VOCATION_DRUID_CIP) {
return;
@@ -2245,7 +2372,7 @@ void PlayerWheel::processActiveGems() {
if (count >= 3 && quality >= WheelGemQuality_t::Greater) {
uint8_t grade = getGemGrade(WheelFragmentType_t::Greater, static_cast(supremeModifier));
std::string modifierName(magic_enum::enum_name(supremeModifier));
- g_logger().info("[{}] Adding supreme modifier {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity));
+ g_logger().debug("[{}] Adding supreme modifier {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity));
m_modifierContext->addStrategies(supremeModifier, grade);
}
}
@@ -2267,7 +2394,7 @@ void PlayerWheel::applyStageBonusForColor(const std::string &color) {
return;
}
- auto [statsDamage, statsHealing] = g_game().getIOWheel()->getRevelationStatByStage(stageEnum);
+ const auto &[statsDamage, statsHealing] = g_game().getIOWheel()->getRevelationStatByStage(stageEnum);
m_playerBonusData.stats.damage += statsDamage;
m_playerBonusData.stats.healing += statsHealing;
@@ -2345,7 +2472,6 @@ void PlayerWheel::applyBlueStageBonus(uint8_t stageValue, Vocation_t vocationEnu
} else if (vocationEnum == Vocation_t::VOCATION_DRUID_CIP) {
m_playerBonusData.stages.twinBurst = stageValue;
for (uint8_t i = 1; i <= stageValue; ++i) {
- addSpellToVector("Twin Burst");
addSpellToVector("Terra Burst");
addSpellToVector("Ice Burst");
}
@@ -2429,7 +2555,7 @@ WheelStageEnum_t PlayerWheel::getPlayerSliceStage(const std::string &color) cons
const auto modsSupremeIt = modsSupremePositionByVocation.find(vocationBaseId);
if (modsSupremeIt != modsSupremePositionByVocation.end()) {
- for (auto modPosition : modsSupremeIt->second.get()) {
+ for (const auto &modPosition : modsSupremeIt->second.get()) {
const auto pos = static_cast(modPosition);
uint8_t grade = 0;
auto gradeKV = gemsGradeKV(WheelFragmentType_t::Greater, pos)->get("grade");
@@ -2465,7 +2591,7 @@ void PlayerWheel::checkAbilities() {
if (getInstant("Battle Instinct") && getOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT) < OTSYS_TIME() && checkBattleInstinct()) {
reloadClient = true;
}
- if (getInstant("Positional Tatics") && getOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS) < OTSYS_TIME() && checkPositionalTatics()) {
+ if (getInstant("Positional Tactics") && getOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS) < OTSYS_TIME() && checkPositionalTactics()) {
reloadClient = true;
}
if (getInstant("Ballistic Mastery") && getOnThinkTimer(WheelOnThink_t::BALLISTIC_MASTERY) < OTSYS_TIME() && checkBallisticMastery()) {
@@ -2482,35 +2608,7 @@ bool PlayerWheel::checkBattleInstinct() {
setOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT, OTSYS_TIME() + 2000);
bool updateClient = false;
m_creaturesNearby = 0;
- uint16_t creaturesNearby = 0;
- for (int offsetX = -1; offsetX <= 1; offsetX++) {
- if (creaturesNearby >= 8) {
- break;
- }
- for (int offsetY = -1; offsetY <= 1; offsetY++) {
- if (creaturesNearby >= 8) {
- break;
- }
-
- const auto playerPositionOffSet = Position(
- m_player.getPosition().x + offsetX,
- m_player.getPosition().y + offsetY,
- m_player.getPosition().z
- );
- const auto &tile = g_game().map.getTile(playerPositionOffSet);
- if (!tile) {
- continue;
- }
-
- const auto &creature = tile->getTopVisibleCreature(m_player.getPlayer());
- if (!creature || creature == m_player.getPlayer() || (creature->getMaster() && creature->getMaster()->getPlayer() == m_player.getPlayer())) {
- continue;
- }
-
- creaturesNearby++;
- }
- }
-
+ uint16_t creaturesNearby = Spectators().find(m_player.getPosition(), false, 1, 1, 1, 1).excludePlayerMaster().size();
if (creaturesNearby >= 5) {
m_creaturesNearby = creaturesNearby;
creaturesNearby -= 4;
@@ -2530,36 +2628,13 @@ bool PlayerWheel::checkBattleInstinct() {
return updateClient;
}
-bool PlayerWheel::checkPositionalTatics() {
- setOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS, OTSYS_TIME() + 2000);
+bool PlayerWheel::checkPositionalTactics() {
+ setOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS, OTSYS_TIME() + 2000);
m_creaturesNearby = 0;
bool updateClient = false;
- uint16_t creaturesNearby = 0;
- for (int offsetX = -1; offsetX <= 1; offsetX++) {
- if (creaturesNearby > 0) {
- break;
- }
- for (int offsetY = -1; offsetY <= 1; offsetY++) {
- const auto playerPositionOffSet = Position(
- m_player.getPosition().x + offsetX,
- m_player.getPosition().y + offsetY,
- m_player.getPosition().z
- );
- const auto &tile = g_game().map.getTile(playerPositionOffSet);
- if (!tile) {
- continue;
- }
-
- const auto &creature = tile->getTopVisibleCreature(m_player.getPlayer());
- if (!creature || creature == m_player.getPlayer() || !creature->getMonster() || (creature->getMaster() && creature->getMaster()->getPlayer())) {
- continue;
- }
-
- creaturesNearby++;
- break;
- }
- }
- constexpr uint16_t magicSkill = 3;
+ uint16_t creaturesNearby = Spectators().find(m_player.getPosition(), false, 1, 1, 1, 1).excludePlayerMaster().size();
+ constexpr uint16_t holyMagicSkill = 3;
+ constexpr uint16_t healingMagicSkill = 3;
constexpr uint16_t distanceSkill = 3;
if (creaturesNearby == 0) {
m_creaturesNearby = creaturesNearby;
@@ -2567,8 +2642,12 @@ bool PlayerWheel::checkPositionalTatics() {
setMajorStat(WheelMajor_t::DISTANCE, distanceSkill);
updateClient = true;
}
- if (getMajorStat(WheelMajor_t::MAGIC) != 0) {
- setMajorStat(WheelMajor_t::MAGIC, 0);
+ if (getSpecializedMagic(COMBAT_HOLYDAMAGE) != 0) {
+ setSpecializedMagic(COMBAT_HOLYDAMAGE, 0);
+ updateClient = true;
+ }
+ if (getSpecializedMagic(COMBAT_HEALING) != 0) {
+ setSpecializedMagic(COMBAT_HEALING, 0);
updateClient = true;
}
} else {
@@ -2576,8 +2655,12 @@ bool PlayerWheel::checkPositionalTatics() {
setMajorStat(WheelMajor_t::DISTANCE, 0);
updateClient = true;
}
- if (getMajorStat(WheelMajor_t::MAGIC) != magicSkill) {
- setMajorStat(WheelMajor_t::MAGIC, magicSkill);
+ if (getSpecializedMagic(COMBAT_HOLYDAMAGE) != holyMagicSkill) {
+ setSpecializedMagic(COMBAT_HOLYDAMAGE, holyMagicSkill);
+ updateClient = true;
+ }
+ if (getSpecializedMagic(COMBAT_HEALING) != healingMagicSkill) {
+ setSpecializedMagic(COMBAT_HEALING, healingMagicSkill);
updateClient = true;
}
}
@@ -2954,7 +3037,7 @@ void PlayerWheel::onThink(bool force /* = false*/) {
if (getGiftOfCooldown() > 0 /*getInstant("Gift of Life")*/ && getOnThinkTimer(WheelOnThink_t::GIFT_OF_LIFE) <= OTSYS_TIME()) {
decreaseGiftOfCooldown(1);
}
- if (!m_player.hasCondition(CONDITION_INFIGHT) || m_player.getZoneType() == ZONE_PROTECTION || (!getInstant("Battle Instinct") && !getInstant("Positional Tatics") && !getInstant("Ballistic Mastery") && !getInstant("Gift of Life") && !getInstant("Combat Mastery") && !getInstant("Divine Empowerment") && getGiftOfCooldown() == 0)) {
+ if (!m_player.hasCondition(CONDITION_INFIGHT) || m_player.getZoneType() == ZONE_PROTECTION || (!getInstant("Battle Instinct") && !getInstant("Positional Tactics") && !getInstant("Ballistic Mastery") && !getInstant("Gift of Life") && !getInstant("Combat Mastery") && !getInstant("Divine Empowerment") && getGiftOfCooldown() == 0)) {
bool mustReset = false;
for (int i = 0; i < static_cast(WheelMajor_t::TOTAL_COUNT); i++) {
if (getMajorStat(static_cast(i)) != 0) {
@@ -2979,8 +3062,8 @@ void PlayerWheel::onThink(bool force /* = false*/) {
if (getInstant("Battle Instinct") && (force || getOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT) < OTSYS_TIME()) && checkBattleInstinct()) {
updateClient = true;
}
- // Positional Tatics
- if (getInstant("Positional Tatics") && (force || getOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS) < OTSYS_TIME()) && checkPositionalTatics()) {
+ // Positional Tactics
+ if (getInstant("Positional Tactics") && (force || getOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS) < OTSYS_TIME()) && checkPositionalTactics()) {
updateClient = true;
}
// Ballistic Mastery
@@ -3003,12 +3086,33 @@ void PlayerWheel::onThink(bool force /* = false*/) {
void PlayerWheel::reduceAllSpellsCooldownTimer(int32_t value) const {
for (const auto &condition : m_player.getConditionsByType(CONDITION_SPELLCOOLDOWN)) {
- if (condition->getTicks() <= value) {
- m_player.sendSpellCooldown(condition->getSubId(), 0);
- condition->endCondition(m_player.getPlayer());
- } else {
- condition->setTicks(condition->getTicks() - value);
- m_player.sendSpellCooldown(condition->getSubId(), condition->getTicks());
+ const auto spellId = condition->getSubId();
+ const auto &spell = g_spells().getInstantSpellById(spellId);
+ if (!spell) {
+ continue;
+ }
+
+ const auto spellSecondaryGroup = spell->getSecondaryGroup();
+ const auto &secondCondition = m_player.getCondition(CONDITION_SPELLGROUPCOOLDOWN, CONDITIONID_DEFAULT, spellSecondaryGroup);
+
+ if (secondCondition) {
+ if (secondCondition->getTicks() <= value) {
+ m_player.sendSpellGroupCooldown(spellSecondaryGroup, 0);
+ secondCondition->endCondition(m_player.getPlayer());
+ } else {
+ secondCondition->setTicks(secondCondition->getTicks() - value);
+ m_player.sendSpellGroupCooldown(spellSecondaryGroup, secondCondition->getTicks());
+ }
+ }
+
+ if (condition) {
+ if (condition->getTicks() <= value) {
+ m_player.sendSpellCooldown(spellId, 0);
+ condition->endCondition(m_player.getPlayer());
+ } else {
+ condition->setTicks(condition->getTicks() - value);
+ m_player.sendSpellCooldown(spellId, condition->getTicks());
+ }
}
}
}
@@ -3022,6 +3126,7 @@ void PlayerWheel::resetUpgradedSpells() {
m_creaturesNearby = 0;
m_spellsSelected.clear();
m_learnedSpellsSelected.clear();
+ m_beamMasterySpells.clear();
for (int i = 0; i < static_cast(WheelMajor_t::TOTAL_COUNT); i++) {
setMajorStat(static_cast(i), 0);
}
@@ -3087,17 +3192,15 @@ std::shared_ptr PlayerWheel::getCombatDataSpell(CombatDamage &damage) {
damage.lifeLeechChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH_CHANCE, spellGrade);
}
- if (m_spellsBonuses.contains(spellName)) {
- damage.criticalDamage += (getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_DAMAGE) * 100);
- damage.criticalChance += getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_CHANCE);
- damage.damageMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE);
- damage.damageReductionMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE_REDUCTION);
- damage.healingMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::HEAL);
- damage.manaLeech += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH);
- damage.manaLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH_CHANCE);
- damage.lifeLeech += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH);
- damage.lifeLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH_CHANCE);
- }
+ damage.criticalDamage += (getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_DAMAGE) * 100);
+ damage.criticalChance += getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_CHANCE);
+ damage.damageMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE);
+ damage.damageReductionMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE_REDUCTION);
+ damage.healingMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::HEAL);
+ damage.manaLeech += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH);
+ damage.manaLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH_CHANCE);
+ damage.lifeLeech += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH);
+ damage.lifeLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH_CHANCE);
}
return spell;
@@ -3131,6 +3234,15 @@ void PlayerWheel::setMajorStat(WheelMajor_t type, int32_t value) {
}
}
+void PlayerWheel::setSpecializedMagic(CombatType_t type, int32_t value) {
+ auto enumValue = static_cast(type);
+ try {
+ m_specializedMagic.at(enumValue) = value;
+ } catch (const std::out_of_range &e) {
+ g_logger().error("[{}]. Type {} is out of range, value {}. Error message: {}", __FUNCTION__, enumValue, value, e.what());
+ }
+}
+
void PlayerWheel::setInstant(WheelInstant_t type, bool toggle) {
auto enumValue = static_cast(type);
try {
@@ -3167,9 +3279,9 @@ void PlayerWheel::setSpellInstant(const std::string &name, bool value) {
}
} else if (name == "Battle Healing") {
setInstant(WheelInstant_t::BATTLE_HEALING, value);
- } else if (name == "Positional Tatics") {
- setInstant(WheelInstant_t::POSITIONAL_TATICS, value);
- if (!getInstant(WheelInstant_t::POSITIONAL_TATICS)) {
+ } else if (name == "Positional Tactics") {
+ setInstant(WheelInstant_t::POSITIONAL_TACTICS, value);
+ if (!getInstant(WheelInstant_t::POSITIONAL_TACTICS)) {
setMajorStat(WheelMajor_t::MAGIC, 0);
setMajorStat(WheelMajor_t::HOLY_RESISTANCE, 0);
}
@@ -3296,65 +3408,38 @@ bool PlayerWheel::getInstant(WheelInstant_t type) const {
uint8_t PlayerWheel::getStage(std::string_view name) const {
using enum WheelInstant_t;
using enum WheelStage_t;
- if (name == "Battle Instinct") {
- return PlayerWheel::getInstant(BATTLE_INSTINCT);
- }
- if (name == "Battle Healing") {
- return PlayerWheel::getInstant(BATTLE_HEALING);
- }
- if (name == "Positional Tatics") {
- return PlayerWheel::getInstant(POSITIONAL_TATICS);
- }
- if (name == "Ballistic Mastery") {
- return PlayerWheel::getInstant(BALLISTIC_MASTERY);
- }
- if (name == "Healing Link") {
- return PlayerWheel::getInstant(HEALING_LINK);
- }
- if (name == "Runic Mastery") {
- return PlayerWheel::getInstant(RUNIC_MASTERY);
- }
- if (name == "Focus Mastery") {
- return PlayerWheel::getInstant(FOCUS_MASTERY);
- }
- if (name == "Beam Mastery") {
- return PlayerWheel::getStage(BEAM_MASTERY);
- }
- if (name == "Combat Mastery") {
- return PlayerWheel::getStage(COMBAT_MASTERY);
- }
- if (name == "Gift of Life") {
- return PlayerWheel::getStage(GIFT_OF_LIFE);
- }
- if (name == "Blessing of the Grove") {
- return PlayerWheel::getStage(BLESSING_OF_THE_GROVE);
- }
- if (name == "Drain Body") {
- return PlayerWheel::getStage(DRAIN_BODY);
- }
- if (name == "Divine Empowerment") {
- return PlayerWheel::getStage(DIVINE_EMPOWERMENT);
- }
- if (name == "Divine Grenade") {
- return PlayerWheel::getStage(DIVINE_GRENADE);
- }
- if (name == "Twin Burst") {
- return PlayerWheel::getStage(TWIN_BURST);
- }
- if (name == "Executioner's Throw") {
- return PlayerWheel::getStage(EXECUTIONERS_THROW);
- }
- if (name == "Avatar of Light") {
- return PlayerWheel::getStage(AVATAR_OF_LIGHT);
- }
- if (name == "Avatar of Nature") {
- return PlayerWheel::getStage(AVATAR_OF_NATURE);
- }
- if (name == "Avatar of Steel") {
- return PlayerWheel::getStage(AVATAR_OF_STEEL);
+
+ static const std::unordered_map instantMapping = {
+ { "Battle Instinct", BATTLE_INSTINCT },
+ { "Battle Healing", BATTLE_HEALING },
+ { "Positional Tatics", POSITIONAL_TACTICS },
+ { "Ballistic Mastery", BALLISTIC_MASTERY },
+ { "Healing Link", HEALING_LINK },
+ { "Runic Mastery", RUNIC_MASTERY },
+ { "Focus Mastery", FOCUS_MASTERY }
+ };
+
+ static const std::unordered_map stageMapping = {
+ { "Beam Mastery", BEAM_MASTERY },
+ { "Combat Mastery", COMBAT_MASTERY },
+ { "Gift of Life", GIFT_OF_LIFE },
+ { "Blessing of the Grove", BLESSING_OF_THE_GROVE },
+ { "Drain Body", DRAIN_BODY },
+ { "Divine Empowerment", DIVINE_EMPOWERMENT },
+ { "Divine Grenade", DIVINE_GRENADE },
+ { "Twin Burst", TWIN_BURST },
+ { "Executioner's Throw", EXECUTIONERS_THROW },
+ { "Avatar of Light", AVATAR_OF_LIGHT },
+ { "Avatar of Nature", AVATAR_OF_NATURE },
+ { "Avatar of Steel", AVATAR_OF_STEEL },
+ { "Avatar of Storm", AVATAR_OF_STORM }
+ };
+
+ if (auto it = instantMapping.find(name); it != instantMapping.end()) {
+ return PlayerWheel::getInstant(it->second);
}
- if (name == "Avatar of Storm") {
- return PlayerWheel::getStage(AVATAR_OF_STORM);
+ if (auto it = stageMapping.find(name); it != stageMapping.end()) {
+ return PlayerWheel::getStage(it->second);
}
return false;
@@ -3380,6 +3465,16 @@ int32_t PlayerWheel::getMajorStat(WheelMajor_t type) const {
return 0;
}
+int32_t PlayerWheel::getSpecializedMagic(CombatType_t type) const {
+ auto enumValue = static_cast(type);
+ try {
+ return m_specializedMagic.at(enumValue);
+ } catch (const std::out_of_range &e) {
+ g_logger().error("[{}]. Instant type {}. Error message: {}", __FUNCTION__, enumValue, e.what());
+ }
+ return 0;
+}
+
int32_t PlayerWheel::getStat(WheelStat_t type) const {
auto enumValue = static_cast(type);
try {
@@ -3440,65 +3535,39 @@ int64_t PlayerWheel::getOnThinkTimer(WheelOnThink_t type) const {
bool PlayerWheel::getInstant(std::string_view name) const {
using enum WheelInstant_t;
- if (name == "Battle Instinct") {
- return PlayerWheel::getInstant(BATTLE_INSTINCT);
- }
- if (name == "Battle Healing") {
- return PlayerWheel::getInstant(BATTLE_HEALING);
- }
- if (name == "Positional Tatics") {
- return PlayerWheel::getInstant(POSITIONAL_TATICS);
- }
- if (name == "Ballistic Mastery") {
- return PlayerWheel::getInstant(BALLISTIC_MASTERY);
- }
- if (name == "Healing Link") {
- return PlayerWheel::getInstant(HEALING_LINK);
- }
- if (name == "Runic Mastery") {
- return PlayerWheel::getInstant(RUNIC_MASTERY);
- }
- if (name == "Focus Mastery") {
- return PlayerWheel::getInstant(FOCUS_MASTERY);
- }
- if (name == "Beam Mastery") {
- return PlayerWheel::getStage(WheelStage_t::BEAM_MASTERY);
- }
- if (name == "Combat Mastery") {
- return PlayerWheel::getStage(WheelStage_t::COMBAT_MASTERY);
- }
- if (name == "Gift of Life") {
- return PlayerWheel::getStage(WheelStage_t::GIFT_OF_LIFE);
- }
- if (name == "Blessing of the Grove") {
- return PlayerWheel::getStage(WheelStage_t::BLESSING_OF_THE_GROVE);
- }
- if (name == "Drain Body") {
- return PlayerWheel::getStage(WheelStage_t::DRAIN_BODY);
- }
- if (name == "Divine Empowerment") {
- return PlayerWheel::getStage(WheelStage_t::DIVINE_EMPOWERMENT);
- }
- if (name == "Divine Grenade") {
- return PlayerWheel::getStage(WheelStage_t::DIVINE_GRENADE);
- }
- if (name == "Twin Burst") {
- return PlayerWheel::getStage(WheelStage_t::TWIN_BURST);
- }
- if (name == "Executioner's Throw") {
- return PlayerWheel::getStage(WheelStage_t::EXECUTIONERS_THROW);
- }
- if (name == "Avatar of Light") {
- return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_LIGHT);
- }
- if (name == "Avatar of Nature") {
- return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_NATURE);
- }
- if (name == "Avatar of Steel") {
- return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_STEEL);
+ using enum WheelStage_t;
+
+ static const std::unordered_map instantMapping = {
+ { "Battle Instinct", BATTLE_INSTINCT },
+ { "Battle Healing", BATTLE_HEALING },
+ { "Positional Tactics", POSITIONAL_TACTICS },
+ { "Ballistic Mastery", BALLISTIC_MASTERY },
+ { "Healing Link", HEALING_LINK },
+ { "Runic Mastery", RUNIC_MASTERY },
+ { "Focus Mastery", FOCUS_MASTERY }
+ };
+
+ static const std::unordered_map stageMapping = {
+ { "Beam Mastery", BEAM_MASTERY },
+ { "Combat Mastery", COMBAT_MASTERY },
+ { "Gift of Life", GIFT_OF_LIFE },
+ { "Blessing of the Grove", BLESSING_OF_THE_GROVE },
+ { "Drain Body", DRAIN_BODY },
+ { "Divine Empowerment", DIVINE_EMPOWERMENT },
+ { "Divine Grenade", DIVINE_GRENADE },
+ { "Twin Burst", TWIN_BURST },
+ { "Executioner's Throw", EXECUTIONERS_THROW },
+ { "Avatar of Light", AVATAR_OF_LIGHT },
+ { "Avatar of Nature", AVATAR_OF_NATURE },
+ { "Avatar of Steel", AVATAR_OF_STEEL },
+ { "Avatar of Storm", AVATAR_OF_STORM }
+ };
+
+ if (auto it = instantMapping.find(name); it != instantMapping.end()) {
+ return PlayerWheel::getInstant(it->second);
}
- if (name == "Avatar of Storm") {
- return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_STORM);
+ if (auto it = stageMapping.find(name); it != stageMapping.end()) {
+ return PlayerWheel::getStage(it->second);
}
return false;
@@ -3599,7 +3668,7 @@ void PlayerWheel::setWheelBonusData(const PlayerWheelMethodsBonusData &newBonusD
// Functions used to Manage Combat
uint8_t PlayerWheel::getBeamAffectedTotal(const CombatDamage &tmpDamage) const {
uint8_t beamAffectedTotal = 0; // Removed const
- if (tmpDamage.runeSpellName == "Beam Mastery" && getInstant("Beam Mastery")) {
+ if (m_beamMasterySpells.contains(tmpDamage.instantSpellName) && getInstant("Beam Mastery")) {
beamAffectedTotal = 3;
}
return beamAffectedTotal;
@@ -3608,6 +3677,7 @@ uint8_t PlayerWheel::getBeamAffectedTotal(const CombatDamage &tmpDamage) const {
void PlayerWheel::updateBeamMasteryDamage(CombatDamage &tmpDamage, uint8_t &beamAffectedTotal, uint8_t &beamAffectedCurrent) const {
if (beamAffectedTotal > 0) {
tmpDamage.damageMultiplier += checkBeamMasteryDamage();
+ reduceAllSpellsCooldownTimer(1000); // Reduces all spell cooldown by 1 second per target hit (max 3 seconds)
--beamAffectedTotal;
beamAffectedCurrent++;
}
diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp
index 840cc72d8dc..7c3bd2348a6 100644
--- a/src/creatures/players/wheel/player_wheel.hpp
+++ b/src/creatures/players/wheel/player_wheel.hpp
@@ -107,6 +107,9 @@ class PlayerWheel {
int getSpellAdditionalDuration(const std::string &spellName) const;
bool getSpellAdditionalArea(const std::string &spellName) const;
+ bool handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const;
+ bool handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const;
+
/*
* Functions for manage slots
*/
@@ -209,7 +212,7 @@ class PlayerWheel {
void checkAbilities();
void checkGiftOfLife();
bool checkBattleInstinct();
- bool checkPositionalTatics();
+ bool checkPositionalTactics();
bool checkBallisticMastery();
bool checkCombatMastery();
bool checkDivineEmpowerment();
@@ -260,6 +263,16 @@ class PlayerWheel {
*/
void setMajorStat(WheelMajor_t type, int32_t value);
+ /**
+ * @brief Sets the value of a specific specialized magic in the Wheel of Destiny.
+ *
+ * This function sets the value of the specified specialized magic in the Wheel of Destiny to the provided value.
+ *
+ * @param type The type of the combat to set the specialized magic.
+ * @param value The value to set for the specialized magic.
+ */
+ void setSpecializedMagic(CombatType_t type, int32_t value);
+
/**
* @brief Sets the value of a specific instant in the Wheel of Destiny.
*
@@ -310,6 +323,7 @@ class PlayerWheel {
uint8_t getStage(WheelStage_t type) const;
WheelSpellGrade_t getSpellUpgrade(const std::string &name) const;
int32_t getMajorStat(WheelMajor_t type) const;
+ int32_t getSpecializedMagic(CombatType_t type) const;
int32_t getStat(WheelStat_t type) const;
int32_t getResistance(CombatType_t type) const;
int32_t getMajorStatConditional(const std::string &instant, WheelMajor_t major) const;
@@ -379,63 +393,11 @@ class PlayerWheel {
void toggleGemLock(uint16_t index) const;
void setActiveGem(WheelGemAffinity_t affinity, uint16_t index) const;
void removeActiveGem(WheelGemAffinity_t affinity) const;
- void addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points) {
- m_bonusRevelationPoints[static_cast(affinity)] += points;
- }
- void resetRevelationBonus() {
- m_bonusRevelationPoints = { 0, 0, 0, 0 };
- }
-
- void addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus) {
- if (m_spellsBonuses.contains(spellName)) {
- m_spellsBonuses[spellName].decrease.cooldown += bonus.decrease.cooldown;
- m_spellsBonuses[spellName].decrease.manaCost += bonus.decrease.manaCost;
- m_spellsBonuses[spellName].decrease.secondaryGroupCooldown += bonus.decrease.secondaryGroupCooldown;
- m_spellsBonuses[spellName].increase.aditionalTarget += bonus.increase.aditionalTarget;
- m_spellsBonuses[spellName].increase.area = bonus.increase.area;
- m_spellsBonuses[spellName].increase.criticalChance += bonus.increase.criticalChance;
- m_spellsBonuses[spellName].increase.criticalDamage += bonus.increase.criticalDamage;
- m_spellsBonuses[spellName].increase.damage += bonus.increase.damage;
- m_spellsBonuses[spellName].increase.damageReduction += bonus.increase.damageReduction;
- m_spellsBonuses[spellName].increase.duration += bonus.increase.duration;
- m_spellsBonuses[spellName].increase.heal += bonus.increase.heal;
- m_spellsBonuses[spellName].leech.life += bonus.leech.life;
- m_spellsBonuses[spellName].leech.mana += bonus.leech.mana;
- return;
- }
- m_spellsBonuses[spellName] = bonus;
- }
-
- int32_t getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const {
- if (!m_spellsBonuses.contains(spellName)) {
- return 0;
- }
- auto [leech, increase, decrease] = m_spellsBonuses.at(spellName);
- switch (boost) {
- case WheelSpellBoost_t::COOLDOWN:
- return decrease.cooldown;
- case WheelSpellBoost_t::MANA:
- return decrease.manaCost;
- case WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN:
- return decrease.secondaryGroupCooldown;
- case WheelSpellBoost_t::CRITICAL_CHANCE:
- return increase.criticalChance;
- case WheelSpellBoost_t::CRITICAL_DAMAGE:
- return increase.criticalDamage;
- case WheelSpellBoost_t::DAMAGE:
- return increase.damage;
- case WheelSpellBoost_t::DAMAGE_REDUCTION:
- return increase.damageReduction;
- case WheelSpellBoost_t::HEAL:
- return increase.heal;
- case WheelSpellBoost_t::LIFE_LEECH:
- return leech.life;
- case WheelSpellBoost_t::MANA_LEECH:
- return leech.mana;
- default:
- return 0;
- }
- }
+ void addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points);
+ void resetRevelationBonus();
+ void addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus);
+
+ int32_t getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const;
WheelGemBasicModifier_t selectBasicModifier2(WheelGemBasicModifier_t modifier1) const;
@@ -465,9 +427,11 @@ class PlayerWheel {
std::array(WheelMajor_t::TOTAL_COUNT)> m_majorStats = { 0 };
std::array(WheelInstant_t::INSTANT_COUNT)> m_instant = { false };
std::array m_resistance = { 0 };
+ std::array m_specializedMagic = { 0 };
int32_t m_creaturesNearby = 0;
std::map m_spellsSelected;
std::vector m_learnedSpellsSelected;
std::unordered_map m_spellsBonuses;
+ std::unordered_set m_beamMasterySpells;
};
diff --git a/src/creatures/players/wheel/wheel_definitions.hpp b/src/creatures/players/wheel/wheel_definitions.hpp
index 0aa22c5a7b9..a136bd620d3 100644
--- a/src/creatures/players/wheel/wheel_definitions.hpp
+++ b/src/creatures/players/wheel/wheel_definitions.hpp
@@ -97,7 +97,7 @@ enum class WheelStage_t : uint8_t {
enum class WheelOnThink_t : uint8_t {
BATTLE_INSTINCT = 0,
- POSITIONAL_TATICS = 1,
+ POSITIONAL_TACTICS = 1,
BALLISTIC_MASTERY = 2,
COMBAT_MASTERY = 3,
FOCUS_MASTERY = 4,
@@ -148,7 +148,7 @@ enum class WheelMajor_t : uint8_t {
enum class WheelInstant_t : uint8_t {
BATTLE_INSTINCT = 0,
BATTLE_HEALING = 1,
- POSITIONAL_TATICS = 2,
+ POSITIONAL_TACTICS = 2,
BALLISTIC_MASTERY = 3,
HEALING_LINK = 4,
RUNIC_MASTERY = 5,
@@ -217,7 +217,7 @@ struct PlayerWheelMethodsBonusData {
struct Instant {
bool battleInstinct = false; // Knight
bool battleHealing = false; // Knight
- bool positionalTatics = false; // Paladin
+ bool positionalTactics = false; // Paladin
bool ballisticMastery = false; // Paladin
bool healingLink = false; // Druid
bool runicMastery = false; // Druid/sorcerer
@@ -282,7 +282,7 @@ namespace WheelSpells {
struct Decrease {
int cooldown = 0;
int manaCost = 0;
- uint8_t secondaryGroupCooldown = 0;
+ int secondaryGroupCooldown = 0;
};
struct Leech {
diff --git a/src/creatures/players/wheel/wheel_gems.cpp b/src/creatures/players/wheel/wheel_gems.cpp
index a2c7a898766..766fa9ee049 100644
--- a/src/creatures/players/wheel/wheel_gems.cpp
+++ b/src/creatures/players/wheel/wheel_gems.cpp
@@ -238,16 +238,16 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
switch (modifier) {
case WheelGemSupremeModifier_t::General_Dodge:
- m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 25 * gradeMultiplier));
+ m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 28 * gradeMultiplier));
break;
case WheelGemSupremeModifier_t::General_LifeLeech:
- m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 120 * gradeMultiplier));
+ m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 200 * gradeMultiplier));
break;
case WheelGemSupremeModifier_t::General_ManaLeech:
- m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 40 * gradeMultiplier));
+ m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 80 * gradeMultiplier));
break;
case WheelGemSupremeModifier_t::General_CriticalDamage:
- m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 150 * gradeMultiplier));
+ m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 200 * gradeMultiplier));
break;
case WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife:
m_strategies.emplace_back(std::make_unique(m_wheel, WheelGemAffinity_t::Green, 150 * gradeMultiplier));
@@ -255,7 +255,7 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
break;
case WheelGemSupremeModifier_t::SorcererDruid_UltimateHealing:
- bonus.increase.heal = 10 * gradeMultiplier;
+ bonus.increase.heal = 5 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Ultimate Healing", bonus));
break;
@@ -312,25 +312,25 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
break;
case WheelGemSupremeModifier_t::Knight_AvatarOfSteel_Cooldown:
- bonus.decrease.cooldown = 300 * 1000;
+ bonus.decrease.cooldown = 900 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Steel", bonus));
break;
case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_Cooldown:
- bonus.decrease.cooldown = 1 * 1000;
+ bonus.decrease.cooldown = 2 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus));
break;
case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 6 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus));
break;
case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 5 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Fierce Berserk", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_CriticalExtraDamage:
@@ -338,35 +338,35 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
m_strategies.emplace_back(std::make_unique(m_wheel, "Fierce Berserk", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Berserk_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 5 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Berserk", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Berserk_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Berserk", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Front_Sweep_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Front Sweep", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Front_Sweep_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 8 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Front Sweep", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Groundshaker_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = static_cast(std::round(6.5 * gradeMultiplier));
m_strategies.emplace_back(std::make_unique(m_wheel, "Groundshaker", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Groundshaker_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Groundshaker", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Annihilation_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 15 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Annihilation", bonus));
break;
case WheelGemSupremeModifier_t::Knight_Annihilation_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Annihilation", bonus));
break;
case WheelGemSupremeModifier_t::Knight_FairWoundCleansing_HealingIncrease:
@@ -375,72 +375,72 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
break;
case WheelGemSupremeModifier_t::Paladin_AvatarOfLight_Cooldown:
- bonus.decrease.cooldown = 300 * 1000;
+ bonus.decrease.cooldown = 900 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Light", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineDazzle_Cooldown:
- bonus.decrease.cooldown = 2 * 1000;
+ bonus.decrease.cooldown = 4 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Dazzle", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineGrenade_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 6 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineGrenade_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineCaldera_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 5 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Caldera", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineCaldera_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Caldera", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineMissile_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 8 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Missile", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineMissile_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Missile", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_EtherealSpear_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 10 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Ethereal Spear", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_EtherealSpear_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 15 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Ethereal Spear", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 8 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 12 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineEmpowerment_Cooldown:
- bonus.decrease.cooldown = 3 * 1000;
+ bonus.decrease.cooldown = 6 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Empowerment", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_DivineGrenade_Cooldown:
- bonus.decrease.cooldown = 1 * 1000;
+ bonus.decrease.cooldown = 2 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus));
break;
case WheelGemSupremeModifier_t::Paladin_Salvation_HealingIncrease:
- bonus.increase.heal = 10 * gradeMultiplier;
+ bonus.increase.heal = 6 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Salvation", bonus));
break;
case WheelGemSupremeModifier_t::Sorcerer_AvatarOfStorm_Cooldown:
- bonus.decrease.cooldown = 300 * 1000;
+ bonus.decrease.cooldown = 900 * 1000;
wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1;
m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Storm", bonus));
break;
@@ -450,31 +450,31 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin
m_strategies.emplace_back(std::make_unique(m_wheel, "Energy Wave", bonus));
break;
case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_DamageIncrease:
- bonus.increase.damage = 25 * gradeMultiplier;
+ bonus.increase.damage = 10 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique(m_wheel, "Great Death Beam", bonus));
break;
case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_CriticalExtraDamage:
- bonus.increase.criticalDamage = 8 * gradeMultiplier;
+ bonus.increase.criticalDamage = 15 * gradeMultiplier;
m_strategies.emplace_back(std::make_unique