diff --git a/data-otservbr-global/lib/core/storages.lua b/data-otservbr-global/lib/core/storages.lua index 741532cda7b..202bb290a38 100644 --- a/data-otservbr-global/lib/core/storages.lua +++ b/data-otservbr-global/lib/core/storages.lua @@ -2768,6 +2768,7 @@ Storage = { GoshnarMegalomaniaAccess = 47220, GoshnarMegalomaniaKilled = 47222, QuestReward = 47223, + OutfitReward = 47224, }, }, U12_60 = { -- update 12.60 - Reserved Storages 47501 - 47600 diff --git a/data-otservbr-global/monster/bosses/doctor_marrow.lua b/data-otservbr-global/monster/bosses/doctor_marrow.lua index 61f19f0b70b..308ab14b27b 100644 --- a/data-otservbr-global/monster/bosses/doctor_marrow.lua +++ b/data-otservbr-global/monster/bosses/doctor_marrow.lua @@ -20,10 +20,6 @@ monster.corpse = 18074 monster.speed = 180 monster.manaCost = 0 -monster.events = { - "DoctorMarrowHealth", -} - monster.changeTarget = { interval = 4000, chance = 15, diff --git a/data-otservbr-global/monster/bosses/the_first_dragon.lua b/data-otservbr-global/monster/bosses/the_first_dragon.lua index e70114de0a3..34294280dd1 100644 --- a/data-otservbr-global/monster/bosses/the_first_dragon.lua +++ b/data-otservbr-global/monster/bosses/the_first_dragon.lua @@ -58,7 +58,7 @@ monster.flags = { } monster.events = { - "First Dragon Death", + "FirstDragonDeath", } monster.light = { diff --git a/data-otservbr-global/monster/quests/a_pirates_tail_quest/ratmiral_blackwhiskers.lua b/data-otservbr-global/monster/quests/a_pirates_tail_quest/ratmiral_blackwhiskers.lua index a1d2b57ae54..d399413ed93 100644 --- a/data-otservbr-global/monster/quests/a_pirates_tail_quest/ratmiral_blackwhiskers.lua +++ b/data-otservbr-global/monster/quests/a_pirates_tail_quest/ratmiral_blackwhiskers.lua @@ -20,6 +20,10 @@ monster.corpse = 35846 monster.speed = 115 monster.manaCost = 0 +monster.events = { + "RatmiralBlackwhiskersDeath", +} + monster.changeTarget = { interval = 4000, chance = 10, diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua index 7487f4fda9a..1c871919b87 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua @@ -18,6 +18,7 @@ monster.maxHealth = 500000 monster.race = "undead" monster.corpse = 33889 monster.speed = 165 +monster.manaCost = 0 monster.changeTarget = { interval = 2000, diff --git a/data-otservbr-global/scripts/custom/monster_training_machine.lua b/data-otservbr-global/monster/trainers/training_machine.lua similarity index 97% rename from data-otservbr-global/scripts/custom/monster_training_machine.lua rename to data-otservbr-global/monster/trainers/training_machine.lua index 7ef2f78d707..c5a98a9ce28 100644 --- a/data-otservbr-global/scripts/custom/monster_training_machine.lua +++ b/data-otservbr-global/monster/trainers/training_machine.lua @@ -1,6 +1,7 @@ local mType = Game.createMonsterType("Training Machine") local monster = {} -monster.description = "Training Machine" + +monster.description = "a training machine" monster.experience = 0 monster.outfit = { lookType = 1142, diff --git a/data-otservbr-global/npc/imbuement_assistant.lua b/data-otservbr-global/npc/imbuement_assistant.lua index 35ab1a282ea..a4f1228ecd6 100644 --- a/data-otservbr-global/npc/imbuement_assistant.lua +++ b/data-otservbr-global/npc/imbuement_assistant.lua @@ -30,6 +30,8 @@ npcConfig.voices = { { text = "Hello adventurer, looking for Imbuement items? Just ask me!" }, } +local playerImbuementData = {} + local keywordHandler = KeywordHandler:new() local npcHandler = NpcHandler:new(keywordHandler) @@ -55,15 +57,309 @@ end npcType.onCloseChannel = function(npc, creature) npcHandler:onCloseChannel(npc, creature) + playerImbuementData[creature:getId()] = nil +end + +function addItemsToShoppingBag(npc, player) + local playerId = player:getId() + local playerData = playerImbuementData[playerId] + + if playerData then + local moneyRequired = playerData.moneyRequired + local itemList = playerData.itemList + if player:getMoney() + player:getBankBalance() < moneyRequired then + npcHandler:say("Sorry, you don't have enough money", npc, player) + npcHandler:setTopic(player:getId(), 0) + return false, "You don't have enough money." + end + + local totalWeight = 0 + for _, item in pairs(itemList) do + local itemType = ItemType(item.itemId) + totalWeight = totalWeight + (itemType:getWeight() * item.count) + end + + if player:getFreeCapacity() < totalWeight then + return false, "You don't have enough weight." + end + + if player:getFreeBackpackSlots() == 0 then + return false, "You don't have enough room." + end + + local shoppingBag = player:addItem(2856, 1) -- present box + for _, item in pairs(itemList) do + shoppingBag:addItem(item.itemId, item.count) + end + + player:removeMoneyBank(moneyRequired) + + return true + end + + return false end --- Basic +local imbuementPackagesData = { + -- Skill increase packages + ["bash"] = { + text = "skill club", + moneyRequired = 6250, + itemList = { + { itemId = 9657, count = 20 }, + { itemId = 22189, count = 15 }, + { itemId = 10405, count = 10 }, + }, + }, + ["blockade"] = { + text = "skill shield", + moneyRequired = 16150, + itemList = { + { itemId = 9641, count = 20 }, + { itemId = 11703, count = 25 }, + { itemId = 20199, count = 25 }, + }, + }, + ["chop"] = { + text = "skill axe", + moneyRequired = 13050, + itemList = { + { itemId = 10196, count = 20 }, -- orc tooth + { itemId = 11447, count = 25 }, -- battle stone + { itemId = 21200, count = 20 }, -- moohtant horn + }, + }, + ["epiphany"] = { + text = "magic level", + moneyRequired = 10650, + itemList = { + { itemId = 9635, count = 25 }, -- elvish talisman + { itemId = 11452, count = 15 }, -- broken shamanic staff + { itemId = 10309, count = 15 }, -- strand of medusa hair + }, + }, + ["precision"] = { + text = "skill distance", + moneyRequired = 6750, + itemList = { + { itemId = 11464, count = 25 }, -- elven scouting glass + { itemId = 18994, count = 20 }, -- elven hoof + { itemId = 10298, count = 10 }, -- metal spike + }, + }, + ["slash"] = { + text = "skill sword", + moneyRequired = 6550, + itemList = { + { itemId = 9691, count = 25 }, -- lion's mane + { itemId = 21202, count = 25 }, -- mooh'tah shell + { itemId = 9654, count = 5 }, -- war crystal + }, + }, + -- Additional attributes packages + ["featherweight"] = { + text = "capacity increase", + moneyRequired = 12250, + itemList = { + { itemId = 25694, count = 20 }, -- fairy wings + { itemId = 25702, count = 10 }, -- little bowl of myrrh + { itemId = 20205, count = 5 }, -- goosebump leather + }, + }, + ["strike"] = { + text = "critical", + moneyRequired = 16700, + itemList = { + { itemId = 11444, count = 20 }, -- protective charm + { itemId = 10311, count = 25 }, -- sabretooth + { itemId = 22728, count = 5 }, -- vexclaw talon + }, + }, + ["swiftness"] = { + text = "speed", + moneyRequired = 5225, + itemList = { + { itemId = 17458, count = 15 }, -- damselfly wing + { itemId = 10302, count = 25 }, -- compass + { itemId = 14081, count = 20 }, -- waspoid wing + }, + }, + ["vampirism"] = { + text = "life leech", + moneyRequired = 10475, + itemList = { + { itemId = 9685, count = 25 }, -- vampire teeth + { itemId = 9633, count = 15 }, -- bloody pincers + { itemId = 9663, count = 5 }, -- piece of dead brain + }, + }, + ["vibrancy"] = { + text = "paralysis removal", + moneyRequired = 15000, + itemList = { + { itemId = 22053, count = 20 }, -- wereboar hooves + { itemId = 23507, count = 15 }, -- crystallized anger + { itemId = 28567, count = 5 }, -- quill + }, + }, + ["void"] = { + text = "mana leech", + moneyRequired = 17400, + itemList = { + { itemId = 11492, count = 25 }, -- rope belt + { itemId = 20200, count = 25 }, -- silencer claws + { itemId = 22730, count = 5 }, -- some grimeleech wings + }, + }, + -- Elemental damage packages + ["electrify"] = { + text = "energy damage", + moneyRequired = 3770, + itemList = { + { itemId = 18993, count = 25 }, -- rorc feather + { itemId = 21975, count = 5 }, -- peacock feather fan + { itemId = 23508, count = 1 }, -- energy vein + }, + }, + ["frost"] = { + text = "ice damage", + moneyRequired = 9750, + itemList = { + { itemId = 9661, count = 25 }, -- frosty heart + { itemId = 21801, count = 10 }, -- seacrest hair + { itemId = 9650, count = 5 }, -- polar bear paw + }, + }, + ["reap"] = { + text = "death damage", + moneyRequired = 3475, + itemList = { + { itemId = 11484, count = 25 }, -- pile of grave earth + { itemId = 9647, count = 20 }, -- demonic skeletal hand + { itemId = 10420, count = 5 }, -- petrified scream + }, + }, + ["scorch"] = { + text = "fire damage", + moneyRequired = 15875, + itemList = { + { itemId = 9636, count = 25 }, -- fiery heart + { itemId = 5920, count = 5 }, -- green dragon scale + { itemId = 5954, count = 5 }, -- demon horn + }, + }, + ["venom"] = { + text = "earth damage", + moneyRequired = 1820, + itemList = { + { itemId = 9686, count = 25 }, -- swamp grass + { itemId = 9640, count = 20 }, -- poisonous slime + { itemId = 21194, count = 2 }, -- slime heart + }, + }, + -- Elemental protection packages + ["cloud fabric"] = { + text = "energy protection", + moneyRequired = 13775, + itemList = { + { itemId = 9644, count = 20 }, -- wyvern talisman + { itemId = 14079, count = 15 }, -- crawler head plating + { itemId = 9665, count = 10 }, -- wyrm scale + }, + }, + ["demon presence"] = { + text = "holy protection", + moneyRequired = 20250, + itemList = { + { itemId = 9639, count = 25 }, -- cultish robe + { itemId = 9638, count = 25 }, -- cultish mask + { itemId = 10304, count = 20 }, -- hellspawn tail + }, + }, + ["dragon hide"] = { + text = "fire protection", + moneyRequired = 10850, + itemList = { + { itemId = 5877, count = 20 }, -- green dragon leather + { itemId = 16131, count = 10 }, -- blazing bone + { itemId = 11658, count = 5 }, -- draken sulphur + }, + }, + ["lich shroud"] = { + text = "death protection", + moneyRequired = 5650, + itemList = { + { itemId = 11466, count = 25 }, -- flask of embalming fluid + { itemId = 22007, count = 20 }, -- gloom wolf fur + { itemId = 9660, count = 5 }, -- mystical hourglass + }, + }, + ["quara scale"] = { + text = "ice protection", + moneyRequired = 3650, + itemList = { + { itemId = 10295, count = 25 }, -- winter wolf fur + { itemId = 10307, count = 15 }, -- thick fur + { itemId = 14012, count = 10 }, -- deepling warts + }, + }, + ["snake skin"] = { + text = "earth protection", + moneyRequired = 12550, + itemList = { + { itemId = 17823, count = 25 }, -- piece of swampling wood + { itemId = 9694, count = 20 }, -- snake skin + { itemId = 11702, count = 10 }, -- brimstone fangs + }, + }, +} + +local function purchaseItems(npc, player, message) + local packageData = imbuementPackagesData[message] + if packageData and npcHandler:getTopic(player:getId()) == 1 then + npcHandler:say("Do you want to buy items for " .. packageData.text .. " imbuement for " .. packageData.moneyRequired .. " gold?", npc, player) + npcHandler:setTopic(player:getId(), 2) + playerImbuementData[player:getId()] = { + moneyRequired = packageData.moneyRequired, + itemList = packageData.itemList, + } + end +end + +local function creatureSayCallback(npc, creature, type, message) + local player = Player(creature) + local playerId = player:getId() + if not npcHandler:checkInteraction(npc, creature) then + return false + end + + local imbuementPackages = "Available imbuement packages: {bash}, {blockade}, {chop}, {epiphany}, {precision}, {slash}. additional attributes: {featherweight}, {strike}, {swiftness}, {vampirism}, {vibrancy}, {void}. elemental damage: {electrify}, {frost}, {reap}, {scorch}, {venom}. elemental protection: {cloud fabric}, {demon presence}, {dragon hide}, {lich shroud}, {quara scale}, {snake skin}." + if MsgContains(message, "imbuement packages") then + npcHandler:setTopic(playerId, 1) + npcHandler:say(imbuementPackages, npc, creature) + elseif imbuementPackagesData[message] then + purchaseItems(npc, player, message) + elseif MsgContains(message, "yes") and npcHandler:getTopic(playerId) == 2 then + local success, message = addItemsToShoppingBag(npc, player) + if not success then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) + npcHandler:setTopic(playerId, 1) + npcHandler:say(imbuementPackages, npc, player) + return + end + + playerImbuementData[playerId] = nil + npcHandler:say("You have successfully completed your purchase of the items.", npc, player) + npcHandler:setTopic(playerId, 1) + npcHandler:say(imbuementPackages, npc, creature) + end +end -keywordHandler:addKeyword({ "job" }, StdModule.say, { npcHandler = npcHandler, text = "Currently I have been working selling items for imbuement." }) +npcHandler:setMessage(MESSAGE_GREET, "Hello |PLAYERNAME|, say {imbuement packages} or {trade} for buy imbuement items.") +npcHandler:setMessage(MESSAGE_WALKAWAY, "See you later |PLAYERNAME| come back soon.") +npcHandler:setMessage(MESSAGE_FAREWELL, "See you later |PLAYERNAME| come back soon.") -npcHandler:setMessage(MESSAGE_GREET, "Welcome to Imbuement's shop!") -npcHandler:setMessage(MESSAGE_FAREWELL, "Good bye and come again.") -npcHandler:setMessage(MESSAGE_WALKAWAY, "Good bye and come again.") +npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback) npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true) diff --git a/data-otservbr-global/npc/the_lootmonger.lua b/data-otservbr-global/npc/the_lootmonger.lua index bfeea87da97..7374b7645c2 100644 --- a/data-otservbr-global/npc/the_lootmonger.lua +++ b/data-otservbr-global/npc/the_lootmonger.lua @@ -7,7 +7,7 @@ npcConfig.description = internalNpcName npcConfig.health = 100 npcConfig.maxHealth = npcConfig.health -npcConfig.walkInterval = 0 +npcConfig.walkInterval = 2000 npcConfig.walkRadius = 2 npcConfig.outfit = { diff --git a/data-otservbr-global/scripts/actions/adventurers_guild/adventurers_stone.lua b/data-otservbr-global/scripts/actions/adventurers_guild/adventurers_stone.lua index 9de94cbe1e3..4218f522bbb 100644 --- a/data-otservbr-global/scripts/actions/adventurers_guild/adventurers_stone.lua +++ b/data-otservbr-global/scripts/actions/adventurers_guild/adventurers_stone.lua @@ -1,5 +1,5 @@ local config = { - enableTemplaes = true, + enableTemples = true, enableDepots = false, Temples = { @@ -47,7 +47,7 @@ local adventurersStone = Action() function adventurersStone.onUse(player, item, fromPosition, target, toPosition, isHotkey) local playerPos, allowed, townId = player:getPosition(), false - if config.enableTemplaes then + if config.enableTemples then for _, temple in ipairs(config.Temples) do if isInRangeIgnoreZ(playerPos, temple.fromPos, temple.toPos) then allowed, townId = true, temple.townId @@ -67,7 +67,7 @@ function adventurersStone.onUse(player, item, fromPosition, target, toPosition, if not allowed then local enabledLocations = {} - if config.enableTemplaes then + if config.enableTemples then table.insert(enabledLocations, "temple") end if config.enableDepots then diff --git a/data-otservbr-global/scripts/actions/other/potions.lua b/data-otservbr-global/scripts/actions/other/potions.lua index ab5b97c8ff6..38c323e978e 100644 --- a/data-otservbr-global/scripts/actions/other/potions.lua +++ b/data-otservbr-global/scripts/actions/other/potions.lua @@ -262,7 +262,7 @@ function flaskPotion.onUse(player, item, fromPosition, target, toPosition, isHot potion.combat:execute(target, Variant(target:getId())) end - if not potion.effect then + if not potion.effect and target:getPosition() ~= nil then target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) end diff --git a/data-otservbr-global/scripts/actions/quests/dangerous_depth/gnomish_pesticide.lua b/data-otservbr-global/scripts/actions/quests/dangerous_depth/gnomish_pesticide.lua index 68fe03c67e9..bbc6fe66ede 100644 --- a/data-otservbr-global/scripts/actions/quests/dangerous_depth/gnomish_pesticide.lua +++ b/data-otservbr-global/scripts/actions/quests/dangerous_depth/gnomish_pesticide.lua @@ -4,7 +4,7 @@ function dangerousDepthPesticide.onUse(player, item, fromPosition, target, toPos return true end - if not target:isItem() then + if not target or not target:isItem() then return false end diff --git a/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua b/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua index e3cb7244b7b..ca95fa99bc9 100644 --- a/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua +++ b/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua @@ -408,7 +408,7 @@ function dangerousDepthCrystals.onUse(player, item, fromPosition, target, toPosi return true end - if not target:isItem() then + if not target or not target:isItem() then return false end diff --git a/data-otservbr-global/scripts/actions/quests/feaster_of_souls/portal_minis_feaster.lua b/data-otservbr-global/scripts/actions/quests/feaster_of_souls/portal_minis_feaster.lua index 5e10645ee23..fc957813d3d 100644 --- a/data-otservbr-global/scripts/actions/quests/feaster_of_souls/portal_minis_feaster.lua +++ b/data-otservbr-global/scripts/actions/quests/feaster_of_souls/portal_minis_feaster.lua @@ -84,7 +84,7 @@ function teleportBoss.onStepIn(creature, item, position, fromPosition) creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All the players need to be level " .. value.requiredLevel .. " or higher.") return true end - if creature:canFightBoss(value.bossName) then + if not creature:canFightBoss(value.bossName) then creature:teleportTo(fromPosition, true) creature:getPosition():sendMagicEffect(CONST_ME_TELEPORT) creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have to wait " .. value.timeToFightAgain .. " hours to face " .. value.bossName .. " again!") diff --git a/data-otservbr-global/scripts/actions/quests/ferumbras_ascendant/ferumbras_lever.lua b/data-otservbr-global/scripts/actions/quests/ferumbras_ascendant/ferumbras_lever.lua index 847a22b8440..674d6d77e4e 100644 --- a/data-otservbr-global/scripts/actions/quests/ferumbras_ascendant/ferumbras_lever.lua +++ b/data-otservbr-global/scripts/actions/quests/ferumbras_ascendant/ferumbras_lever.lua @@ -50,7 +50,7 @@ function ferumbrasAscendantLever.onUse(player, item, fromPosition, target, toPos for y = 31477, 31481 do local playerTile = Tile(Position(x, y, 14)):getTopCreature() if playerTile and playerTile:isPlayer() then - if playerTile:canFightBoss("Ferumbras Mortal Shell") then + if not playerTile:canFightBoss("Ferumbras Mortal Shell") then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You or a member in your team have to wait 5 days to face Ferumbras again!") item:transform(8912) return true diff --git a/data-otservbr-global/scripts/actions/quests/kilmaresh/portal_minis_kilmaresh.lua b/data-otservbr-global/scripts/actions/quests/kilmaresh/portal_minis_kilmaresh.lua index bb334e678d1..bd54e70fa01 100644 --- a/data-otservbr-global/scripts/actions/quests/kilmaresh/portal_minis_kilmaresh.lua +++ b/data-otservbr-global/scripts/actions/quests/kilmaresh/portal_minis_kilmaresh.lua @@ -84,7 +84,7 @@ function teleportBoss.onStepIn(creature, item, position, fromPosition) creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All the players need to be level " .. value.requiredLevel .. " or higher.") return true end - if creature:canFightBoss(value.bossName) then + if not creature:canFightBoss(value.bossName) then creature:teleportTo(fromPosition, true) creature:getPosition():sendMagicEffect(CONST_ME_TELEPORT) creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have to wait " .. value.timeToFightAgain .. " hours to face " .. value.bossName .. " again!") diff --git a/data-otservbr-global/scripts/actions/quests/soul_war/reward_soul_war.lua b/data-otservbr-global/scripts/actions/quests/soul_war/reward_soul_war.lua index b069e43fb69..2ab572b9376 100644 --- a/data-otservbr-global/scripts/actions/quests/soul_war/reward_soul_war.lua +++ b/data-otservbr-global/scripts/actions/quests/soul_war/reward_soul_war.lua @@ -18,6 +18,16 @@ local rewards = { { id = 34098, name = "Pair of Soulstalkers" }, { id = 34099, name = "Soulbastion" }, } +local outfits = { 1322, 1323 } + +local function addOutfits(player) + if player:getStorageValue(Storage.Quest.U12_40.SoulWar.OutfitReward) < 0 then + player:addOutfit(outfits[1], 0) + player:addOutfit(outfits[2], 0) + player:setStorageValue(Storage.Quest.U12_40.SoulWar.OutfitReward, 1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Congratulations you received the Revenant Outfit.") + end +end local rewardSoulWar = Action() function rewardSoulWar.onUse(creature, item, fromPosition, target, toPosition, isHotkey) @@ -31,8 +41,10 @@ function rewardSoulWar.onUse(creature, item, fromPosition, target, toPosition, i player:addItem(rewardItem.id, 1) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have found a " .. rewardItem.name .. ".") player:setStorageValue(Storage.Quest.U12_40.SoulWar.QuestReward, 1) + addOutfits(player) return true else + addOutfits(player) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have already collected your reward") return false end diff --git a/data-otservbr-global/scripts/actions/quests/the_dream_courts/dream_courts_lever.lua b/data-otservbr-global/scripts/actions/quests/the_dream_courts/dream_courts_lever.lua index b336b0a380c..eef26894389 100644 --- a/data-otservbr-global/scripts/actions/quests/the_dream_courts/dream_courts_lever.lua +++ b/data-otservbr-global/scripts/actions/quests/the_dream_courts/dream_courts_lever.lua @@ -25,6 +25,7 @@ local config = { }, exit = Position(32210, 32035, 13), } +local bossToday = config.bossName[os.date("%A")] local dreamCourtsLever = Action() function dreamCourtsLever.onUse(player, item, fromPosition, target, toPosition, isHotkey) @@ -37,7 +38,7 @@ function dreamCourtsLever.onUse(player, item, fromPosition, target, toPosition, spec:setCheckPosition(config.specPos) spec:check() if spec:getPlayers() > 0 then - player:say("There's someone fighting with " .. config.bossName[os.date("%A")] .. ".", TALKTYPE_MONSTER_SAY) + player:say("There's someone fighting with " .. bossToday .. ".", TALKTYPE_MONSTER_SAY) return true end local lever = Lever() @@ -55,7 +56,7 @@ function dreamCourtsLever.onUse(player, item, fromPosition, target, toPosition, for _, v in pairs(info) do local newPlayer = v.creature if newPlayer then - newPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You or a member in your team have to wait " .. config.timeToFightAgain .. " hours to face " .. config.bossName[os.date("%A")] .. " again!") + newPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You or a member in your team have to wait " .. config.timeToFightAgain .. " hours to face " .. bossToday .. " again!") if newPlayer:getStorageValue(config.storage) > os.time() then newPlayer:getPosition():sendMagicEffect(CONST_ME_POFF) end @@ -68,12 +69,12 @@ function dreamCourtsLever.onUse(player, item, fromPosition, target, toPosition, lever:checkPositions() if lever:checkConditions() then spec:removeMonsters() - local monster = Game.createMonster(config.bossName[os.date("%A")], config.bossPosition, true, true) + local monster = Game.createMonster(bossToday, config.bossPosition, true, true) if not monster then return true end lever:teleportPlayers() - lever:setCooldownAllPlayers(config.bossName, os.time() + config.timeToFightAgain * 3600) + lever:setCooldownAllPlayers(bossToday, os.time() + config.timeToFightAgain * 3600) addEvent(function() local old_players = lever:getInfoPositions() spec:clearCreaturesCache() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/a_pirates_tail/ratmiral_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/a_pirates_tail/ratmiral_death.lua index ea00d6ead07..8d659edbf10 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/a_pirates_tail/ratmiral_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/a_pirates_tail/ratmiral_death.lua @@ -1,7 +1,7 @@ -local event = CreatureEvent("RatmiralBlackwhiskersDeath") +local ratmiralBlackwhiskersDeath = CreatureEvent("RatmiralBlackwhiskersDeath") local outfits = { 1371, 1372 } -function event.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamage_unjustified) +function ratmiralBlackwhiskersDeath.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamage_unjustified) if not creature or not creature:getMonster() then return end @@ -17,4 +17,4 @@ function event.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDa end end -event:register() +ratmiralBlackwhiskersDeath:register() diff --git a/data-otservbr-global/scripts/custom/movement_trainer_entrance.lua b/data-otservbr-global/scripts/custom/movement_trainer_entrance.lua index 161c0ffb220..c7d805e8f42 100644 --- a/data-otservbr-global/scripts/custom/movement_trainer_entrance.lua +++ b/data-otservbr-global/scripts/custom/movement_trainer_entrance.lua @@ -67,8 +67,8 @@ function trainerEntrance.onStepIn(creature, item, position, fromPosition) end calculatingRoom(creature.uid, config.firstRoomPosition, 0, 0) - Game.createMonster("training machine", creature:getPosition(), true, false) - Game.createMonster("training machine", creature:getPosition(), true, false) + Game.createMonster("Training Machine", creature:getPosition(), true, false) + Game.createMonster("Training Machine", creature:getPosition(), true, false) return true end diff --git a/data-otservbr-global/scripts/movements/quests/cults_of_tibia/boss_timer.lua b/data-otservbr-global/scripts/movements/quests/cults_of_tibia/boss_timer.lua index 9b03b83d74e..1c2f1834270 100644 --- a/data-otservbr-global/scripts/movements/quests/cults_of_tibia/boss_timer.lua +++ b/data-otservbr-global/scripts/movements/quests/cults_of_tibia/boss_timer.lua @@ -40,7 +40,7 @@ function bossTimer.onStepIn(creature, item, position, fromPosition) end for b = 1, #setting do if player:getPosition() == Position(setting[b].tpPos) then - if not player:canFightBoss(setting[b].storage) > os.time() then + if not player:canFightBoss(setting[b].boss) then player:sendCancelMessage("You need to wait for 20 hours to face this boss again.") player:teleportTo(fromPosition) return false diff --git a/data-otservbr-global/scripts/movements/quests/first_dragon/entrance_teleport.lua b/data-otservbr-global/scripts/movements/quests/first_dragon/entrance_teleport.lua index 642c02f57e4..f0d30494c8c 100644 --- a/data-otservbr-global/scripts/movements/quests/first_dragon/entrance_teleport.lua +++ b/data-otservbr-global/scripts/movements/quests/first_dragon/entrance_teleport.lua @@ -57,7 +57,7 @@ function entranceTeleport.onStepIn(creature, item, position, fromPosition) return true end - if player:canFightBoss(setting.bossName) >= os.time() then + if not player:canFightBoss(setting.bossName) then player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) player:teleportTo(fromPosition) player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) diff --git a/data-otservbr-global/scripts/movements/quests/forgotten_knowledge/servant_teleport.lua b/data-otservbr-global/scripts/movements/quests/forgotten_knowledge/servant_teleport.lua index 534373c47fd..42921e1712f 100644 --- a/data-otservbr-global/scripts/movements/quests/forgotten_knowledge/servant_teleport.lua +++ b/data-otservbr-global/scripts/movements/quests/forgotten_knowledge/servant_teleport.lua @@ -6,7 +6,7 @@ function servantTeleport.onStepIn(creature, item, position, fromPosition) return end - if player:canFightBoss("LLoyd") then + if not player:canFightBoss("LLoyd") then player:teleportTo(Position(32815, 32872, 13)) player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) position:sendMagicEffect(CONST_ME_TELEPORT) diff --git a/data-otservbr-global/world/custom/otservbr-custom-npc.xml b/data-otservbr-global/world/custom/otservbr-custom-npc.xml index 6978f4a6bc1..3597ef592c3 100644 --- a/data-otservbr-global/world/custom/otservbr-custom-npc.xml +++ b/data-otservbr-global/world/custom/otservbr-custom-npc.xml @@ -48,4 +48,10 @@ + + + + + + diff --git a/data/XML/imbuements.xml b/data/XML/imbuements.xml index 4fca37e46b9..867bab66f52 100644 --- a/data/XML/imbuements.xml +++ b/data/XML/imbuements.xml @@ -242,23 +242,23 @@ - + - + - + - + diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua index 6ff45d87d65..0a78d96c40d 100644 --- a/data/events/scripts/player.lua +++ b/data/events/scripts/player.lua @@ -247,8 +247,8 @@ function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, -- SSA exhaust local exhaust = {} if toPosition.x == CONTAINER_POSITION and toPosition.y == CONST_SLOT_NECKLACE and item:getId() == ITEM_STONE_SKIN_AMULET then - local pid = self:getId() - if exhaust[pid] then + local playerId = self:getId() + if exhaust[playerId] then self:sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED) return false end diff --git a/data/items/items.xml b/data/items/items.xml index d23468cabf3..ec4ab6f9bbb 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -67826,6 +67826,10 @@ + + + + @@ -67964,6 +67968,20 @@ + + + + + + + + + + + + + + diff --git a/data/libs/encounters_lib.lua b/data/libs/encounters_lib.lua index 1707799b8ac..dee7a38c0c1 100644 --- a/data/libs/encounters_lib.lua +++ b/data/libs/encounters_lib.lua @@ -184,7 +184,12 @@ function Encounter:spawnMonsters(config) spawn(monster) end if event then - monster:registerEvent(event) + if type(event) == "string" then + event = { event } + end + for _, event in ipairs(event) do + monster:registerEvent(event) + end end if timeLimit then self:addEvent(function(monsterId) diff --git a/data/libs/functions/bosslever.lua b/data/libs/functions/bosslever.lua index a1441d6cb86..7e099ec9183 100644 --- a/data/libs/functions/bosslever.lua +++ b/data/libs/functions/bosslever.lua @@ -14,9 +14,11 @@ ---@field private playerPositions {pos: Position, teleport: Position}[] ---@field private area {from: Position, to: Position} ---@field private monsters {name: string, pos: Position}[] +---@field private exitTeleporter Position ---@field private exit Position ---@field private encounter Encounter ---@field private timeoutEvent Event +---@field private testMode boolean BossLever = {} --[[ @@ -65,9 +67,11 @@ setmetatable(BossLever, { disabled = config.disabled, playerPositions = config.playerPositions, onUseExtra = config.onUseExtra or function() end, + exitTeleporter = config.exitTeleporter, exit = config.exit, area = config.specPos, monsters = config.monsters or {}, + testMode = config.testMode, _position = nil, _uid = nil, _aid = nil, @@ -111,7 +115,7 @@ end ---@param player Player ---@return number function BossLever:lastEncounterTime(player) - if not player then + if not player or self.testMode then return 0 end return player:getBossCooldown(self.name) @@ -142,7 +146,7 @@ end function BossLever:onUse(player) local isParticipant = false for _, v in ipairs(self.playerPositions) do - if v.pos == player:getPosition() then + if Position(v.pos) == player:getPosition() then isParticipant = true end end @@ -212,6 +216,7 @@ function BossLever:onUse(player) lever:teleportPlayers() if self.encounter then local encounter = Encounter(self.encounter) + encounter:reset() encounter:start() end self:setLastEncounterTime(os.time() + self.timeToFightAgain) @@ -278,5 +283,9 @@ function BossLever:register() end action:register() BossLever[self.name] = self + + if self.exitTeleporter then + SimpleTeleport(self.exitTeleporter, self.exit) + end return true end diff --git a/data/libs/functions/player.lua b/data/libs/functions/player.lua index 3cda2a65b80..ac1706a364f 100644 --- a/data/libs/functions/player.lua +++ b/data/libs/functions/player.lua @@ -677,8 +677,5 @@ end function Player:canFightBoss(bossNameOrId) local cooldown = self:getBossCooldown(bossNameOrId) - if cooldown > os.time() then - return false - end - return true + return cooldown > os.time() and false or true end diff --git a/data/libs/zones_lib.lua b/data/libs/zones_lib.lua index 833c4d2cd4b..ff37af5b16a 100644 --- a/data/libs/zones_lib.lua +++ b/data/libs/zones_lib.lua @@ -41,6 +41,16 @@ function Zone:countMonsters(name) return count end +function Zone:getMonstersByName(name) + local monsters = {} + for _, monster in ipairs(self:getMonsters()) do + if monster:getName():lower() == name:lower() then + table.insert(monsters, monster) + end + end + return monsters +end + function Zone:countPlayers(notFlag) local players = self:getPlayers() local count = 0 diff --git a/data/scripts/reward_chest/boss_death.lua b/data/scripts/reward_chest/boss_death.lua index 7b3f992b384..f3a80909c8f 100644 --- a/data/scripts/reward_chest/boss_death.lua +++ b/data/scripts/reward_chest/boss_death.lua @@ -1,7 +1,7 @@ local bossDeath = CreatureEvent("BossDeath") function bossDeath.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified) - if not corpse then + if not corpse or corpse == 0 then return true end -- Deny summons and players @@ -14,9 +14,14 @@ function bossDeath.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUn -- Make sure it is a boss if monsterType and monsterType:isRewardBoss() then if not corpse.isContainer or not corpse:isContainer() then - logger.warn("[bossDeath.onDeath] Corpse (id: {}) for reward boss {} is not a container.", corpse:getId(), creature:getName()) + if corpse.getId() then + logger.warn("[bossDeath.onDeath] Corpse (id: {}, name: {}) for reward boss {} is not a container.", corpse:getId(), corpse:getName(), creature:getName()) + else + logger.warn("[bossDeath.onDeath] Error to get corpseId from boss: {}", creature:getName()) + end + else + corpse:registerReward() end - corpse:registerReward() local bossId = creature:getId() local rewardId = corpse:getAttribute(ITEM_ATTRIBUTE_DATE) diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 75cec14c30f..c398f07a2b2 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -2016,7 +2016,7 @@ void Combat::applyExtensions(std::shared_ptr caster, std::shared_ptrgetName(), target ? target->getName() : "null", damage.primary.value); + g_logger().trace("[Combat::applyExtensions] - Applying extensions for {} on {}. Initial damage: {}", caster->getName(), target ? target->getName() : "null", damage.primary.value); // Critical hit uint16_t chance = 0; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index e0df6f8b80f..2f855c6ac15 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -841,7 +841,7 @@ void Creature::mitigateDamage(const CombatType_t &combatType, BlockType_t &block if (combatType != COMBAT_MANADRAIN && combatType != COMBAT_LIFEDRAIN && combatType != COMBAT_AGONYDAMAGE) { // Increase mitigate damage auto originalDamage = damage; damage -= (damage * getMitigation()) / 100.; - g_logger().debug("[mitigation] creature: {}, original damage: {}, mitigation damage: {}", getName(), originalDamage, damage); + g_logger().trace("[mitigation] creature: {}, original damage: {}, mitigation damage: {}", getName(), originalDamage, damage); if (damage <= 0) { damage = 0; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index bd11cc3394e..1f7f9f088b0 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -592,7 +592,7 @@ void Player::updateInventoryImbuement() { continue; } - g_logger().debug("Decaying imbuement {} from item {} of player {}", imbuement->getName(), item->getName(), getName()); + g_logger().trace("Decaying imbuement {} from item {} of player {}", imbuement->getName(), item->getName(), getName()); // Calculate the new duration of the imbuement, making sure it doesn't go below 0 uint32_t duration = std::max(0, imbuementInfo.duration - EVENT_IMBUEMENT_INTERVAL / 1000); // Update the imbuement's duration in the item @@ -1658,7 +1658,7 @@ void Player::onCreatureAppear(std::shared_ptr creature, bool isLogin) g_game().checkPlayersRecord(); IOLoginData::updateOnlineStatus(guid, true); - if (getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL)) { + if (getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL) && getVocationId() > VOCATION_NONE) { for (uint8_t i = 2; i <= 6; i++) { if (!hasBlessing(i)) { addBlessing(i, 1); diff --git a/src/items/functions/item/custom_attribute.cpp b/src/items/functions/item/custom_attribute.cpp index 596ac55d127..f7cfa925eac 100644 --- a/src/items/functions/item/custom_attribute.cpp +++ b/src/items/functions/item/custom_attribute.cpp @@ -18,23 +18,19 @@ CustomAttribute::~CustomAttribute() = default; // Constructor for int64_t CustomAttribute::CustomAttribute(const std::string &initStringKey, const int64_t initInt64) : - stringKey(initStringKey) { - setValue(initInt64); + stringKey(initStringKey), value(initInt64) { } // Constructor for string CustomAttribute::CustomAttribute(const std::string &initStringKey, const std::string &initStringValue) : - stringKey(initStringKey) { - setValue(initStringValue); + stringKey(initStringKey), value(initStringValue) { } // Constructor for double CustomAttribute::CustomAttribute(const std::string &initStringKey, const double initDoubleValue) : - stringKey(initStringKey) { - setValue(initDoubleValue); + stringKey(initStringKey), value(initDoubleValue) { } // Constructor for boolean CustomAttribute::CustomAttribute(const std::string &initStringKey, const bool initBoolValue) : - stringKey(initStringKey) { - setValue(initBoolValue); + stringKey(initStringKey), value(initBoolValue) { } const std::string &CustomAttribute::getStringKey() const { @@ -122,7 +118,7 @@ bool CustomAttribute::unserialize(PropStream &propStream, const std::string &fun g_logger().error("[{}] failed to read string, call function: {}", __FUNCTION__, function); return false; } - setValue(readString); + value = readString; break; } case 2: { @@ -131,7 +127,7 @@ bool CustomAttribute::unserialize(PropStream &propStream, const std::string &fun g_logger().error("[{}] failed to read int64, call function: {}", __FUNCTION__, function); return false; } - setValue(readInt); + value = readInt; break; } case 3: { @@ -140,7 +136,7 @@ bool CustomAttribute::unserialize(PropStream &propStream, const std::string &fun g_logger().error("[{}] failed to read double, call function: {}", __FUNCTION__, function); return false; } - setValue(readDouble); + value = readDouble; break; } case 4: { @@ -149,7 +145,7 @@ bool CustomAttribute::unserialize(PropStream &propStream, const std::string &fun g_logger().error("[{}] failed to read boolean, call function: {}", __FUNCTION__, function); return false; } - setValue(readBoolean); + value = readBoolean; break; } default: diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index a2466038c99..6da9e94180e 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -919,7 +919,7 @@ void ProtocolGame::addBless() { std::ostringstream lostBlesses; (bless.length() == 0) ? lostBlesses << "You lost all your blessings." : lostBlesses << "You are still blessed with " << bless; player->sendTextMessage(MESSAGE_EVENT_ADVANCE, lostBlesses.str()); - if (player->getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL)) { + if (player->getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL) && player->getVocationId() > VOCATION_NONE) { for (uint8_t i = 2; i <= 6; i++) { if (!player->hasBlessing(i)) { player->addBlessing(i, 1); @@ -3972,7 +3972,7 @@ void ProtocolGame::sendBlessStatus() { if (oldProtocol) { msg.add(blessCount >= 5 ? 0x01 : 0x00); } else { - bool glow = (g_configManager().getBoolean(INVENTORY_GLOW) && blessCount >= 5) || player->getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL); + bool glow = player->getVocationId() > VOCATION_NONE && ((g_configManager().getBoolean(INVENTORY_GLOW) && blessCount >= 5) || player->getLevel() < g_configManager().getNumber(ADVENTURERSBLESSING_LEVEL)); msg.add(glow ? 1 : 0); // Show up the glowing effect in items if you have all blesses or adventurer's blessing msg.addByte((blessCount >= 7) ? 3 : ((blessCount >= 5) ? 2 : 1)); // 1 = Disabled | 2 = normal | 3 = green } diff --git a/src/server/network/webhook/webhook.cpp b/src/server/network/webhook/webhook.cpp index 386e804a7a9..69d05070aab 100644 --- a/src/server/network/webhook/webhook.cpp +++ b/src/server/network/webhook/webhook.cpp @@ -74,7 +74,7 @@ int Webhook::sendRequest(const char* url, const char* payload, std::string* resp curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &Webhook::writeCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, reinterpret_cast(response_body)); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "canary (https://github.com/Hydractify/canary)"); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "canary (https://github.com/opentibiabr/canary)"); CURLcode res = curl_easy_perform(curl);