From 1fc6c0eeb8c5fbd36a2e5ee32927f21e18d640a0 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Tue, 28 Jan 2025 09:42:33 -0300 Subject: [PATCH 01/18] fix: add missing houses (#3291) --- data-otservbr-global/world/otservbr-house.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data-otservbr-global/world/otservbr-house.xml b/data-otservbr-global/world/otservbr-house.xml index 5786def36f7..b1c4ffd116f 100644 --- a/data-otservbr-global/world/otservbr-house.xml +++ b/data-otservbr-global/world/otservbr-house.xml @@ -958,7 +958,7 @@ - + @@ -991,4 +991,6 @@ + + From e00ec0d1fee1e41f38c2e14d7fcc78344fa1f115 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:07:31 -0300 Subject: [PATCH 02/18] fix: dawnport vocation trial and npc plunderpurse (#3292) --- data-otservbr-global/npc/plunderpurse.lua | 6 +-- .../globalevents/dawnport_magic_effect.lua | 14 +++--- .../others/dawnport_vocation_trial.lua | 12 ++--- data-otservbr-global/startup/tables/tile.lua | 48 ++++++++----------- data-otservbr-global/world/otservbr-npc.xml | 13 ++--- data/items/items.xml | 18 +++++++ 6 files changed, 59 insertions(+), 52 deletions(-) diff --git a/data-otservbr-global/npc/plunderpurse.lua b/data-otservbr-global/npc/plunderpurse.lua index 4e1d5bd1b10..033c8071836 100644 --- a/data-otservbr-global/npc/plunderpurse.lua +++ b/data-otservbr-global/npc/plunderpurse.lua @@ -7,15 +7,15 @@ npcConfig.description = internalNpcName npcConfig.health = 100 npcConfig.maxHealth = npcConfig.health -npcConfig.walkInterval = 0 +npcConfig.walkInterval = 2000 npcConfig.walkRadius = 2 npcConfig.outfit = { lookType = 151, lookHead = 114, - lookBody = 131, + lookBody = 132, lookLegs = 0, - lookFeet = 20, + lookFeet = 78, lookAddons = 1, } diff --git a/data-otservbr-global/scripts/globalevents/dawnport_magic_effect.lua b/data-otservbr-global/scripts/globalevents/dawnport_magic_effect.lua index d2cafef85ff..3f758cef987 100644 --- a/data-otservbr-global/scripts/globalevents/dawnport_magic_effect.lua +++ b/data-otservbr-global/scripts/globalevents/dawnport_magic_effect.lua @@ -1,12 +1,12 @@ local positions = { + { x = 32054, y = 31889, z = 5 }, { x = 32056, y = 31889, z = 5 }, - { x = 32056, y = 31892, z = 5 }, - { x = 32063, y = 31900, z = 5 }, - { x = 32066, y = 31900, z = 5 }, - { x = 32074, y = 31892, z = 5 }, - { x = 32074, y = 31889, z = 5 }, - { x = 32063, y = 31881, z = 5 }, - { x = 32066, y = 31881, z = 5 }, + { x = 32063, y = 31880, z = 5 }, + { x = 32063, y = 31882, z = 5 }, + { x = 32073, y = 31889, z = 5 }, + { x = 32075, y = 31889, z = 5 }, + { x = 32063, y = 31899, z = 5 }, + { x = 32063, y = 31901, z = 5 }, } local dawnportMagicEffect = GlobalEvent("DawnportMagicEffect") diff --git a/data-otservbr-global/scripts/movements/others/dawnport_vocation_trial.lua b/data-otservbr-global/scripts/movements/others/dawnport_vocation_trial.lua index faf2c2caee9..9713df78614 100644 --- a/data-otservbr-global/scripts/movements/others/dawnport_vocation_trial.lua +++ b/data-otservbr-global/scripts/movements/others/dawnport_vocation_trial.lua @@ -7,7 +7,7 @@ local vocationTrials = { -- Sorcerer trial [25005] = { tutorialId = 5, - effectPosition = { x = 32050, y = 31891, z = 5 }, + effectPosition = { x = 32064, y = 31905, z = 5 }, storage = Storage.Dawnport.Sorcerer, message = "As a sorcerer, you can use the following spells: Magic Patch, Buzz, Scorch.", vocation = { @@ -37,7 +37,7 @@ local vocationTrials = { -- Druid trial [25006] = { tutorialId = 6, - effectPosition = { x = 32064, y = 31905, z = 5 }, + effectPosition = { x = 32064, y = 31876, z = 5 }, storage = Storage.Dawnport.Druid, message = "As a druid, you can use these spells: Mud Attack, Chill Out, Magic Patch.", vocation = { @@ -67,7 +67,7 @@ local vocationTrials = { -- Paladin trial [25007] = { tutorialId = 4, - effectPosition = { x = 32078, y = 31891, z = 5 }, + effectPosition = { x = 32050, y = 31891, z = 5 }, storage = Storage.Dawnport.Paladin, message = "As a paladin, you can use the following spells: Magic Patch, Arrow Call.", vocation = { @@ -98,7 +98,7 @@ local vocationTrials = { -- Knight trial [25008] = { tutorialId = 3, - effectPosition = { x = 32064, y = 31876, z = 5 }, + effectPosition = { x = 32078, y = 31891, z = 5 }, storage = Storage.Dawnport.Knight, message = "As a knight, you can use the following spells: Bruise Bane.", vocation = { @@ -259,8 +259,8 @@ function dawnportVocationTrial.onStepIn(creature, item, position, fromPosition) local trial = vocationTrials[item.actionid] if trial then -- Center room position - local centerPosition = Position(32065, 31891, 5) - if centerPosition:getDistance(fromPosition) < centerPosition:getDistance(position) then + local centerPosition = Position(32063, 31889, 5) + if centerPosition:getDistance(fromPosition) >= centerPosition:getDistance(position) then -- Blocks the vocation trial if same vocation or after level 20 if player:getVocation():getId() == trial.vocation.id or player:getLevel() >= 20 then return true diff --git a/data-otservbr-global/startup/tables/tile.lua b/data-otservbr-global/startup/tables/tile.lua index 5246b290c37..4a80a8f1335 100644 --- a/data-otservbr-global/startup/tables/tile.lua +++ b/data-otservbr-global/startup/tables/tile.lua @@ -13,14 +13,18 @@ TileAction = { [20001] = { itemId = 416, itemPos = { - { x = 32064, y = 31881, z = 5 }, - { x = 32065, y = 31881, z = 5 }, - { x = 32074, y = 31890, z = 5 }, - { x = 32074, y = 31891, z = 5 }, - { x = 32064, y = 31900, z = 5 }, - { x = 32065, y = 31900, z = 5 }, - { x = 32056, y = 31890, z = 5 }, - { x = 32056, y = 31891, z = 5 }, + { x = 32064, y = 31880, z = 5 }, + { x = 32065, y = 31880, z = 5 }, + { x = 32066, y = 31880, z = 5 }, + { x = 32075, y = 31890, z = 5 }, + { x = 32075, y = 31891, z = 5 }, + { x = 32075, y = 31892, z = 5 }, + { x = 32064, y = 31901, z = 5 }, + { x = 32065, y = 31901, z = 5 }, + { x = 32066, y = 31901, z = 5 }, + { x = 32054, y = 31890, z = 5 }, + { x = 32054, y = 31891, z = 5 }, + { x = 32054, y = 31892, z = 5 }, }, }, -- Dark trails quest tile @@ -61,42 +65,30 @@ TileAction = { --Sorcerer vocation tile --Vocation trial: data\scripts\movements\others\dawnport_vocation_trial.lua [25005] = { - itemId = 416, + itemId = 44640, itemPos = { - { x = 32055, y = 31889, z = 5 }, - { x = 32055, y = 31890, z = 5 }, - { x = 32055, y = 31891, z = 5 }, - { x = 32055, y = 31892, z = 5 }, + { x = 32063, y = 31900, z = 5 }, }, }, --Druid vocation tile [25006] = { - itemId = 416, + itemId = 44641, itemPos = { - { x = 32063, y = 31901, z = 5 }, - { x = 32064, y = 31901, z = 5 }, - { x = 32065, y = 31901, z = 5 }, - { x = 32066, y = 31901, z = 5 }, + { x = 32063, y = 31881, z = 5 }, }, }, --Paladin vocation tile [25007] = { - itemId = 416, + itemId = 44639, itemPos = { - { x = 32075, y = 31889, z = 5 }, - { x = 32075, y = 31890, z = 5 }, - { x = 32075, y = 31891, z = 5 }, - { x = 32075, y = 31892, z = 5 }, + { x = 32055, y = 31889, z = 5 }, }, }, --Knight vocation tile [25008] = { - itemId = 416, + itemId = 44638, itemPos = { - { x = 32063, y = 31880, z = 5 }, - { x = 32064, y = 31880, z = 5 }, - { x = 32065, y = 31880, z = 5 }, - { x = 32066, y = 31880, z = 5 }, + { x = 32074, y = 31889, z = 5 }, }, }, -- Tiles data\scripts\movements\others\dawnport_tiles.lua diff --git a/data-otservbr-global/world/otservbr-npc.xml b/data-otservbr-global/world/otservbr-npc.xml index 6d9ed07557e..2166b890643 100644 --- a/data-otservbr-global/world/otservbr-npc.xml +++ b/data-otservbr-global/world/otservbr-npc.xml @@ -171,9 +171,6 @@ - - - @@ -282,8 +279,8 @@ - - + + @@ -1897,7 +1894,7 @@ - + @@ -2458,7 +2455,7 @@ - + @@ -2879,7 +2876,7 @@ - + diff --git a/data/items/items.xml b/data/items/items.xml index 552f0cb85c8..44476042d8b 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -76639,6 +76639,18 @@ Granted by TibiaGoals.com"/> + + + + + + + + + + + + @@ -76854,6 +76866,12 @@ Granted by TibiaGoals.com"/> + + + + + + From 7a51fdb71deeec2b50fb6595e0ccce8ad6c55312 Mon Sep 17 00:00:00 2001 From: Felipe <87909998+FelipePaluco@users.noreply.github.com> Date: Tue, 28 Jan 2025 14:33:54 -0300 Subject: [PATCH 03/18] feat: soul pit arena/animus mastery/soul core (#3230) SoulPit fighting arena along with Animus Mastery Logic. --------- Co-authored-by: Pedro Henrique Alves Cruz --- config.lua.dist | 11 ++ data-otservbr-global/lib/others/load.lua | 1 + data-otservbr-global/lib/others/soulpit.lua | 174 ++++++++++++++++++ data-otservbr-global/migrations/49.lua | 5 + .../actions/soulpit/soulpit_arena_exit.lua | 17 ++ .../actions/soulpit/soulpit_entrance.lua | 57 ++++++ .../scripts/quests/soulpit/exalted_core.lua | 92 +++++++++ .../quests/soulpit/ondroploot_soul_core.lua | 58 ++++++ .../scripts/quests/soulpit/soul_prism.lua | 106 +++++++++++ .../quests/soulpit/soulpit_creatureevents.lua | 17 ++ .../scripts/quests/soulpit/soulpit_fight.lua | 163 ++++++++++++++++ .../quests/soulpit/soulpit_intensehex.lua | 23 +++ .../quests/soulpit/soulpit_opressor.lua | 42 +++++ .../quests/soulpit/soulpit_powerless.lua | 21 +++ data/items/items.xml | 10 + data/libs/functions/lever.lua | 2 +- data/scripts/lib/register_spells.lua | 26 +++ schema.sql | 1 + src/config/config_enums.hpp | 4 + src/config/configmanager.cpp | 4 + src/creatures/CMakeLists.txt | 1 + src/creatures/combat/combat.cpp | 7 +- src/creatures/combat/condition.cpp | 26 +++ src/creatures/combat/spells.cpp | 10 +- src/creatures/combat/spells.hpp | 2 +- src/creatures/creatures_definitions.hpp | 3 + src/creatures/monsters/monster.cpp | 76 ++++++-- src/creatures/monsters/monster.hpp | 21 ++- src/creatures/monsters/monsters.cpp | 26 +++ src/creatures/monsters/monsters.hpp | 20 +- .../players/animus_mastery/animus_mastery.cpp | 72 ++++++++ .../players/animus_mastery/animus_mastery.hpp | 43 +++++ src/creatures/players/player.cpp | 43 ++++- src/creatures/players/player.hpp | 9 +- src/enums/player_icons.hpp | 1 + src/game/game.cpp | 11 +- src/io/functions/iologindata_load_player.cpp | 15 ++ src/io/functions/iologindata_load_player.hpp | 1 + src/io/functions/iologindata_save_player.cpp | 9 + src/io/iologindata.cpp | 3 + src/items/functions/item/item_parse.hpp | 2 +- src/items/items.hpp | 4 + .../functions/core/game/game_functions.cpp | 93 ++++++++++ .../functions/core/game/game_functions.hpp | 6 + .../creatures/monster/monster_functions.cpp | 103 +++++++++++ .../creatures/monster/monster_functions.hpp | 7 + .../monster/monster_type_functions.cpp | 48 +++++ .../monster/monster_type_functions.hpp | 4 + .../creatures/player/player_functions.cpp | 44 +++++ .../creatures/player/player_functions.hpp | 4 + src/server/network/protocol/protocolgame.cpp | 20 +- 51 files changed, 1510 insertions(+), 58 deletions(-) create mode 100644 data-otservbr-global/lib/others/soulpit.lua create mode 100644 data-otservbr-global/migrations/49.lua create mode 100644 data-otservbr-global/scripts/actions/soulpit/soulpit_arena_exit.lua create mode 100644 data-otservbr-global/scripts/actions/soulpit/soulpit_entrance.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/exalted_core.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soul_prism.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soulpit_creatureevents.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soulpit_fight.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soulpit_intensehex.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soulpit_opressor.lua create mode 100644 data-otservbr-global/scripts/quests/soulpit/soulpit_powerless.lua create mode 100644 src/creatures/players/animus_mastery/animus_mastery.cpp create mode 100644 src/creatures/players/animus_mastery/animus_mastery.hpp diff --git a/config.lua.dist b/config.lua.dist index 8f7422da26a..10105287115 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -88,6 +88,17 @@ maxItem = 5000 maxContainer = 500 maxContainerDepth = 200 +-- Animus Mastery - SoulPit (Get more info in: https://github.com/opentibiabr/canary/pull/3230) +-- NOTE: animusMasteryMaxMonsterXpMultiplier is the maximum experience the multiplier can be. +-- NOTE: animusMasteryMonsterXpMultiplier is the monster experience multiplier that has the animus mastery unlocked. +-- NOTE: animusMasteryMonstersXpMultiplier is the multiplier for each 'animusMasteryMonstersToIncreaseXpMultiplier' monsters that +-- the player has the animus mastery unlocked. +-- NOTE: animusMasteryMonstersToIncreaseXpMultiplier is the amount of monster to increase the experience multiplier by 'animusMasteryMonstersXpMultiplier'. +animusMasteryMaxMonsterXpMultiplier = 4.0 +animusMasteryMonsterXpMultiplier = 2.0 +animusMasteryMonstersXpMultiplier = 0.1 +animusMasteryMonstersToIncreaseXpMultiplier = 10 + -- Augments System (Get more info in: https://github.com/opentibiabr/canary/pull/2602) -- NOTE: the following values are for all weapons and equipments that have type of "increase damage", "powerful impact" and "strong impact". -- To customize the percentage of a particular item with these augment types, please add to the item "augments" section on items.xml as the example above. diff --git a/data-otservbr-global/lib/others/load.lua b/data-otservbr-global/lib/others/load.lua index 031c8fb2026..3422819b9f8 100644 --- a/data-otservbr-global/lib/others/load.lua +++ b/data-otservbr-global/lib/others/load.lua @@ -1 +1,2 @@ dofile(DATA_DIRECTORY .. "/lib/others/dawnport.lua") +dofile(DATA_DIRECTORY .. "/lib/others/soulpit.lua") diff --git a/data-otservbr-global/lib/others/soulpit.lua b/data-otservbr-global/lib/others/soulpit.lua new file mode 100644 index 00000000000..b677b10fd9c --- /dev/null +++ b/data-otservbr-global/lib/others/soulpit.lua @@ -0,0 +1,174 @@ +SoulPit = { + SoulCoresConfiguration = { + chanceToGetSameMonsterSoulCore = 15, -- 15% + chanceToDropSoulCore = 5, -- 5% + chanceToGetOminousSoulCore = 2, -- 2% + chanceToDropSoulPrism = 4, -- 4% + monsterVariationsSoulCore = { + ["Horse"] = "horse soul core (taupe)", + ["Brown Horse"] = "horse soul core (brown)", + ["Grey Horse"] = "horse soul core (gray)", + ["Nomad"] = "nomad soul core (basic)", + ["Nomad Blue"] = "nomad soul core (blue)", + ["Nomad Female"] = "nomad soul core (female)", + ["Purple Butterfly"] = "butterfly soul core (purple)", + ["Butterfly"] = "butterfly soul core (blue)", + ["Blue Butterfly"] = "butterfly soul core (blue)", + ["Red Butterfly"] = "butterfly soul core (red)", + }, + monstersDifficulties = { + ["Harmless"] = 1, + ["Trivial"] = 2, + ["Easy"] = 3, + ["Medium"] = 4, + ["Hard"] = 5, + ["Challenge"] = 6, + }, + }, + encounter = nil, + kickEvent = nil, + soulCores = Game.getSoulCoreItems(), + requiredLevel = 8, + playerPositions = { + { + pos = Position(32375, 31158, 8), + teleport = Position(32373, 31151, 8), + effect = CONST_ME_TELEPORT, + }, + { + pos = Position(32375, 31159, 8), + teleport = Position(32374, 31151, 8), + effect = CONST_ME_TELEPORT, + }, + { + pos = Position(32375, 31160, 8), + teleport = Position(32375, 31151, 8), + effect = CONST_ME_TELEPORT, + }, + { + pos = Position(32375, 31161, 8), + teleport = Position(32376, 31151, 8), + effect = CONST_ME_TELEPORT, + }, + { + pos = Position(32375, 31162, 8), + teleport = Position(32377, 31151, 8), + effect = CONST_ME_TELEPORT, + }, + }, + waves = { + [1] = { + stacks = { + [1] = 7, + }, + }, + [2] = { + stacks = { + [1] = 4, + [5] = 3, + }, + }, + [3] = { + stacks = { + [1] = 5, + [15] = 2, + }, + }, + [4] = { + stacks = { + [1] = 3, + [5] = 3, + [40] = 1, + }, + }, + }, + effects = { + [1] = CONST_ME_TELEPORT, + [5] = CONST_ME_ORANGETELEPORT, + [15] = CONST_ME_REDTELEPORT, + [40] = CONST_ME_PURPLETELEPORT, + }, + possibleAbilities = { + "overpowerSoulPit", + "enrageSoulPit", + "opressorSoulPit", + }, + bossAbilities = { + overpowerSoulPit = { + criticalChance = 50, -- 50% + criticalDamage = 25, -- 25% + apply = function(monster) + monster:criticalChance(SoulPit.bossAbilities.overpowerSoulPit.criticalChance) + monster:criticalDamage(SoulPit.bossAbilities.overpowerSoulPit.criticalDamage) + end, + }, + enrageSoulPit = { + bounds = { + [{ 0.8, 0.6 }] = 0.9, -- 10% damage reduction + [{ 0.6, 0.4 }] = 0.75, -- 25% damage reduction + [{ 0.4, 0.2 }] = 0.6, -- 40% damage reduction + [{ 0.0, 0.2 }] = 0.4, -- 60% damage reduction + }, + apply = function(monster) + monster:registerEvent("enrageSoulPit") + end, + }, + opressorSoulPit = { + spells = { + { name = "soulpit opressor", interval = 2000, chance = 25, minDamage = 0, maxDamage = 0 }, + { name = "soulpit powerless", interval = 2000, chance = 30, minDamage = 0, maxDamage = 0 }, + { name = "soulpit intensehex", interval = 2000, chance = 15, minDamage = 0, maxDamage = 0 }, + }, + apply = function(monster) + -- Applying spells + for _, spell in pairs(SoulPit.bossAbilities.opressorSoulPit.spells) do + monster:addAttackSpell(readSpell(spell, monster:getType())) + end + + return true + end, + }, + }, + timeToKick = 10 * 60 * 1000, -- 10 minutes + checkMonstersDelay = 4.5 * 1000, -- 4.5 seconds | The check delay should never be less than the timeToSpawnMonsters. + timeToSpawnMonsters = 4 * 1000, -- 4 seconds + totalMonsters = 7, + obeliskActive = 47379, + obeliskInactive = 47367, + obeliskPosition = Position(32375, 31157, 8), + bossPosition = Position(32376, 31144, 8), + exit = Position(32373, 31158, 8), + zone = Zone("soulpit"), + + getMonsterVariationNameBySoulCore = function(searchName) + for mTypeName, soulCoreName in pairs(SoulPit.SoulCoresConfiguration.monsterVariationsSoulCore) do + if soulCoreName == searchName then + return mTypeName + end + end + + return nil + end, + getSoulCoreMonster = function(name) + return name:match("^(.-) soul core") + end, + onFuseSoulCores = function(player, item, target) + local itemName = item:getName() + local targetItemName = target:getName() + + if SoulPit.getSoulCoreMonster(itemName) and SoulPit.getSoulCoreMonster(targetItemName) then + local randomSoulCore = SoulPit.soulCores[math.random(#SoulPit.soulCores)] + player:addItem(randomSoulCore:getId(), 1) + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have received a %s soul core.", randomSoulCore:getName())) + item:remove(1) + target:remove(1) + return true + end + + return false + end, +} + +SoulPit.zone:addArea(Position(32362, 31132, 8), Position(32390, 31153, 8)) +SoulPit.zone:setRemoveDestination(SoulPit.exit) diff --git a/data-otservbr-global/migrations/49.lua b/data-otservbr-global/migrations/49.lua new file mode 100644 index 00000000000..2f2f2460d10 --- /dev/null +++ b/data-otservbr-global/migrations/49.lua @@ -0,0 +1,5 @@ +function onUpdateDatabase() + logger.info("Updating database to version 49 (feat: animus mastery (soulpit))") + + db.query("ALTER TABLE `players` ADD `animus_mastery` mediumblob DEFAULT NULL;") +end diff --git a/data-otservbr-global/scripts/actions/soulpit/soulpit_arena_exit.lua b/data-otservbr-global/scripts/actions/soulpit/soulpit_arena_exit.lua new file mode 100644 index 00000000000..21304d0cfb5 --- /dev/null +++ b/data-otservbr-global/scripts/actions/soulpit/soulpit_arena_exit.lua @@ -0,0 +1,17 @@ +local soulpitArenaExitConfig = { + arenaExit = Position(32375, 31153, 8), + destination = Position(32373, 31158, 8), +} + +local soulpitArenaExit = Action() + +function soulpitArenaExit.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if not player then + return false + end + player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + player:teleportTo(soulpitArenaExitConfig.destination) +end + +soulpitArenaExit:position(soulpitArenaExitConfig.arenaExit) +soulpitArenaExit:register() diff --git a/data-otservbr-global/scripts/actions/soulpit/soulpit_entrance.lua b/data-otservbr-global/scripts/actions/soulpit/soulpit_entrance.lua new file mode 100644 index 00000000000..d31f63fe386 --- /dev/null +++ b/data-otservbr-global/scripts/actions/soulpit/soulpit_entrance.lua @@ -0,0 +1,57 @@ +local config = { + entrance = { + positions = { + Position(32350, 31030, 3), + Position(32349, 31030, 3), + }, + destination = Position(32374, 31171, 8), + }, + exit = { + position = Position(32374, 31173, 8), + destination = Position(32349, 31032, 3), + }, +} + +local soulpitEntrance = MoveEvent() + +function soulpitEntrance.onStepIn(creature, item, position, fromPosition) + local player = creature:getPlayer() + if not player then + return true + end + + if not config.entrance.destination then + return true + end + + player:teleportTo(config.entrance.destination) + position:sendMagicEffect(CONST_ME_TELEPORT) + return true +end + +soulpitEntrance:type("stepin") +for value in pairs(config.entrance.positions) do + soulpitEntrance:position(config.entrance.positions[value]) +end +soulpitEntrance:register() + +local soulpitExit = MoveEvent() + +function soulpitExit.onStepIn(creature, item, position, fromPosition) + local player = creature:getPlayer() + if not player then + return true + end + + if not config.exit then + return true + end + + player:teleportTo(config.exit.destination) + position:sendMagicEffect(CONST_ME_TELEPORT) + return true +end + +soulpitExit:type("stepin") +soulpitExit:position(config.exit.position) +soulpitExit:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/exalted_core.lua b/data-otservbr-global/scripts/quests/soulpit/exalted_core.lua new file mode 100644 index 00000000000..dadb7b7fd0d --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/exalted_core.lua @@ -0,0 +1,92 @@ +local exaltedCore = Action() + +local function getPreviousDifficultyLevel(currentLevel) + for level, value in pairs(SoulPit.SoulCoresConfiguration.monstersDifficulties) do + if value == currentLevel - 1 then + return level + end + end + return nil +end + +local function getSoulCoreItemForMonster(monsterName) + local lowerMonsterName = monsterName:lower() + local soulCoreName = SoulPit.SoulCoresConfiguration.monsterVariationsSoulCore[monsterName] + + if soulCoreName then + local newSoulCoreId = getItemIdByName(soulCoreName) + if newSoulCoreId then + return newSoulCoreId + end + else + local newMonsterSoulCore = string.format("%s soul core", monsterName) + local newSoulCoreId = getItemIdByName(newMonsterSoulCore) + if newSoulCoreId then + return newSoulCoreId + end + end + + return false +end + +function exaltedCore.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local itemName = target:getName() + local monsterName = SoulPit.getSoulCoreMonster(itemName) + + if not monsterName then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use Exalted Core with a Soul Core.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local monsterType = MonsterType(monsterName) + if not monsterType then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "Invalid monster type. Please contact an administrator.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local currentDifficulty = monsterType:BestiaryStars() + local previousDifficultyLevel = getPreviousDifficultyLevel(currentDifficulty) + local previousDifficultyMonsters = nil + + if previousDifficultyLevel then + previousDifficultyMonsters = Game.getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[previousDifficultyLevel]) + else + previousDifficultyLevel = currentDifficulty + previousDifficultyMonsters = Game.getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[currentDifficulty]) + end + + if #previousDifficultyMonsters == 0 then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "No monsters available for the previous difficulty level.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local newMonsterType = previousDifficultyMonsters[math.random(#previousDifficultyMonsters)] + local newSoulCoreItem = getSoulCoreItemForMonster(newMonsterType:getName()) + if not newSoulCoreItem then -- Retry a second time. + newSoulCoreItem = getSoulCoreItemForMonster(newMonsterType:getName()) + if not newSoulCoreItem then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "Failed to generate a Soul Core.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + end + + if player:getFreeCapacity() < ItemType(newSoulCoreItem):getWeight() then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You do not have enough capacity.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + player:addItem(newSoulCoreItem, 1) + target:remove(1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have received a %s soul core.", newMonsterType:getName())) + item:remove(1) + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + return true +end + +exaltedCore:id(37110) +exaltedCore:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua b/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua new file mode 100644 index 00000000000..9ddb479c117 --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua @@ -0,0 +1,58 @@ +local callback = EventCallback("MonsterOnDropLootSoulCore") + +function callback.monsterOnDropLoot(monster, corpse) + if not monster or not corpse then + return + end + local player = Player(corpse:getCorpseOwner()) + if not player or not player:canReceiveLoot() then + return + end + if monster:getMonsterForgeClassification() ~= FORGE_FIENDISH_MONSTER then + return + end + + local soulCoreId = nil + local trySameMonsterSoulCore = math.random(100) <= SoulPit.SoulCoresConfiguration.chanceToGetSameMonsterSoulCore + local mType = monster:getType() + local lootTable = {} + + if math.random(100) < SoulPit.SoulCoresConfiguration.chanceToDropSoulCore then + if trySameMonsterSoulCore then + local itemName = monster:getName():lower() .. " soul core" + soulCoreId = getItemIdByName(itemName) + end + + if not soulCoreId and not trySameMonsterSoulCore then + local race = mType:Bestiaryrace() + local monstersInCategory = Game.getMonstersByRace(race) + + if monstersInCategory and #monstersInCategory > 0 then + local randomMonster = monstersInCategory[math.random(#monstersInCategory)] + local itemName = randomMonster:name():lower() .. " soul core" + soulCoreId = getItemIdByName(itemName) + logger.info("soulcoreId: " .. soulCoreId) + end + end + + if soulCoreId then + lootTable[soulCoreId] = { + count = 1, + } + else + return {} + end + end + + if math.random(100) < SoulPit.SoulCoresConfiguration.chanceToDropSoulPrism then + local soulPrismId = getItemIdByName("soul prism") + if soulPrismId then + lootTable[soulPrismId] = { + count = 1, + } + end + end + corpse:addLoot(mType:generateLootRoll({}, lootTable, player)) +end + +callback:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soul_prism.lua b/data-otservbr-global/scripts/quests/soulpit/soul_prism.lua new file mode 100644 index 00000000000..326bba11e4d --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soul_prism.lua @@ -0,0 +1,106 @@ +local soulPrism = Action() + +local function getNextDifficultyLevel(currentLevel) + for level, value in pairs(SoulPit.SoulCoresConfiguration.monstersDifficulties) do + if value == currentLevel + 1 then + return level + end + end + return nil +end + +local function getPreviousDifficultyLevel(currentLevel) + for level, value in pairs(SoulPit.SoulCoresConfiguration.monstersDifficulties) do + if value == currentLevel - 1 then + return level + end + end + return nil +end + +local function getSoulCoreItemForMonster(monsterName) + local lowerMonsterName = monsterName:lower() + local soulCoreName = SoulPit.SoulCoresConfiguration.monsterVariationsSoulCore[monsterName] + + if soulCoreName then + local newSoulCoreId = getItemIdByName(soulCoreName) + if newSoulCoreId then + return newSoulCoreId + end + else + local newMonsterSoulCore = string.format("%s soul core", monsterName) + local newSoulCoreId = getItemIdByName(newMonsterSoulCore) + if newSoulCoreId then + return newSoulCoreId + end + end + + return false +end + +function soulPrism.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local itemName = target:getName() + local monsterName = SoulPit.getSoulCoreMonster(itemName) + + if not monsterName then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You can only use Soul Prism with a Soul Core.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local monsterType = MonsterType(monsterName) + if not monsterType then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "Invalid monster type. Please contact an administrator.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local currentDifficulty = monsterType:BestiaryStars() + local nextDifficultyLevel = getNextDifficultyLevel(currentDifficulty) + local nextDifficultyMonsters = nil + + if nextDifficultyLevel then + nextDifficultyMonsters = Game.getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[nextDifficultyLevel]) + else + nextDifficultyLevel = currentDifficulty + nextDifficultyMonsters = Game.getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[currentDifficulty]) + end + + if #nextDifficultyMonsters == 0 then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "No monsters available for the next difficulty level.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + local newMonsterType = nextDifficultyMonsters[math.random(#nextDifficultyMonsters)] + local newSoulCoreItem = getSoulCoreItemForMonster(newMonsterType:getName()) + if not newSoulCoreItem then -- Retry a second time. + newSoulCoreItem = getSoulCoreItemForMonster(newMonsterType:getName()) + if not newSoulCoreItem then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "Failed to generate a Soul Core.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + end + + if player:getFreeCapacity() < ItemType(newSoulCoreItem):getWeight() then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You do not have enough capacity.") + player:getPosition():sendMagicEffect(CONST_ME_POFF) + return false + end + + if math.random(100) <= SoulPit.SoulCoresConfiguration.chanceToGetOminousSoulCore then + player:addItem(49163, 1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have received an Ominous Soul Core.") + else + player:addItem(newSoulCoreItem, 1) + target:remove(1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have received a %s soul core.", newMonsterType:getName())) + end + item:remove(1) + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + return true +end + +soulPrism:id(49164) +soulPrism:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soulpit_creatureevents.lua b/data-otservbr-global/scripts/quests/soulpit/soulpit_creatureevents.lua new file mode 100644 index 00000000000..118a190bf51 --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soulpit_creatureevents.lua @@ -0,0 +1,17 @@ +local enrage = CreatureEvent("enrageSoulPit") +function enrage.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType) + if not creature or not creature:isMonster() and creature:getMaster() then + return true + end + + local healthPercentage = creature:getHealth() / creature:getMaxHealth() + + for bounds, reduction in pairs(SoulPit.bossAbilities.enrageSoulPit.bounds) do + if healthPercentage > bounds[2] and healthPercentage <= bounds[1] then + return primaryDamage * reduction, primaryType, secondaryDamage * reduction, secondaryType + end + end + + return primaryDamage, primaryType, secondaryDamage, secondaryType +end +enrage:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soulpit_fight.lua b/data-otservbr-global/scripts/quests/soulpit/soulpit_fight.lua new file mode 100644 index 00000000000..c607a0de9a9 --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soulpit_fight.lua @@ -0,0 +1,163 @@ +SoulPit.zone:blockFamiliars() + +local zoneEvent = ZoneEvent(SoulPit.zone) +function zoneEvent.afterLeave(zone, creature) + local player = creature:getPlayer() + if not player then + return false + end + + if table.empty(zone:getPlayers()) then + if SoulPit.encounter then + SoulPit.encounter:reset() + SoulPit.encounter = nil + end + if SoulPit.kickEvent then + stopEvent(SoulPit.kickEvent) + SoulPit.obeliskPosition:transformItem(SoulPit.obeliskActive, SoulPit.obeliskInactive) + end + end +end +zoneEvent:register() + +local soulPitAction = Action() +function soulPitAction.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if SoulPit.onFuseSoulCores(player, item, target) then + return true + end + + if target and target:getId() == SoulPit.obeliskActive then + creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting in the soulpit!") + return false + end + if not target or target:getId() ~= SoulPit.obeliskInactive then + return false + end + + local isParticipant = false + for _, v in ipairs(SoulPit.playerPositions) do + if Position(v.pos) == player:getPosition() then + isParticipant = true + end + end + + if not isParticipant then + return false + end + + local lever = Lever() + lever:setPositions(SoulPit.playerPositions) + lever:setCondition(function(creature) + if not creature or not creature:isPlayer() then + return true + end + + local isAccountNormal = creature:getAccountType() < ACCOUNT_TYPE_GAMEMASTER + if isAccountNormal and creature:getLevel() < SoulPit.requiredLevel then + local message = string.format("All players need to be level %s or higher.", SoulPit.requiredLevel) + creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) + return false + end + + return true + end) + + lever:checkPositions() + if not lever:checkConditions() then + return true + end + + item:remove(1) + + if SoulPit.kickEvent then + stopEvent(SoulPit.kickEvent) + end + + lever:teleportPlayers() + SoulPit.obeliskPosition:transformItem(SoulPit.obeliskInactive, SoulPit.obeliskActive) + SoulPit.kickEvent = addEvent(function() + SoulPit.kickEvent = nil + SoulPit.encounter = nil + SoulPit.zone:removePlayers() + SoulPit.obeliskPosition:transformItem(SoulPit.obeliskActive, SoulPit.obeliskInactive) + end, SoulPit.timeToKick) + + local monsterName = string.gsub(item:getName(), " soul core", "") + local monsterVariationName = SoulPit.getMonsterVariationNameBySoulCore(item:getName()) + monsterName = monsterVariationName and monsterVariationName or monsterName + + SoulPit.zone:removeMonsters() + + if SoulPit.encounter ~= nil then + SoulPit.encounter:reset() + end + + local encounter = Encounter("Soulpit", { + zone = SoulPit.zone, + }) + + function encounter:onReset(position) + SoulPit.zone:removeMonsters() + + for _, player in pairs(SoulPit.zone:getPlayers()) do + player:addAnimusMastery(monsterName) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have defeated the core of the %s soul and unlocked its animus mastery!", monsterName)) + end + + SoulPit.zone:removePlayers() + end + + SoulPit.encounter = encounter + + local function waveStart() + for stack, amount in pairs(SoulPit.waves[encounter.currentStage].stacks) do + for i = 1, amount do + local position = stack ~= 40 and SoulPit.zone:randomPosition() or SoulPit.bossPosition + for i = 1, SoulPit.timeToSpawnMonsters / 1000 do + encounter:addEvent(function(position) + local effect = SoulPit.effects[stack] + if effect then + position:sendMagicEffect(effect) + end + end, i * 1000, position) + end + + local randomAbility = SoulPit.possibleAbilities[math.random(1, #SoulPit.possibleAbilities)] + local chosenBossAbility = SoulPit.bossAbilities[randomAbility] + + encounter:addEvent(function(name, stack, position, bossAbilityName, bossAbility) + local monster = Game.createSoulPitMonster(name, position, stack) + if not monster then + return false + end + + if stack ~= 40 then + return false + end + + bossAbility.apply(monster) + end, SoulPit.timeToSpawnMonsters, monsterName, stack, position, randomAbility, chosenBossAbility) + end + end + end + + for i = 1, #SoulPit.waves do + encounter + :addStage({ + start = waveStart, + }) + :autoAdvance({ delay = SoulPit.checkMonstersDelay, monstersKilled = true }) + end + + encounter:start() + encounter:register() + + return true +end + +for _, itemType in pairs(SoulPit.soulCores) do + if itemType:getId() ~= 49164 then -- Exclude soul prism + soulPitAction:id(itemType:getId()) + end +end +soulPitAction:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soulpit_intensehex.lua b/data-otservbr-global/scripts/quests/soulpit/soulpit_intensehex.lua new file mode 100644 index 00000000000..9dc9f54dfbe --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soulpit_intensehex.lua @@ -0,0 +1,23 @@ +local combat = Combat() +combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_STUN) +combat:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_NONE) + +local condition = Condition(CONDITION_INTENSEHEX) +condition:setParameter(CONDITION_PARAM_BUFF_DAMAGEDEALT, 50) +condition:setParameter(CONDITION_PARAM_BUFF_HEALINGRECEIVED, 50) +condition:setParameter(CONDITION_PARAM_TICKS, 3000) +combat:addCondition(condition) + +local spell = Spell("instant") + +function spell.onCastSpell(creature, var) + return combat:execute(creature, var) +end + +spell:name("soulpit intensehex") +spell:words("###940") +spell:blockWalls(true) +spell:needTarget(true) +spell:needLearn(true) +spell:isAggressive(true) +spell:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soulpit_opressor.lua b/data-otservbr-global/scripts/quests/soulpit/soulpit_opressor.lua new file mode 100644 index 00000000000..0b29b4944b5 --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soulpit_opressor.lua @@ -0,0 +1,42 @@ +-- ROOT +local combatRoot = Combat() +combatRoot:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_ROOTS) + +local area = createCombatArea(AREA_ROOT_OPRESSOR) +combatRoot:setArea(area) + +local condition = Condition(CONDITION_ROOTED) +condition:setParameter(CONDITION_PARAM_TICKS, 3000) +combatRoot:addCondition(condition) + +-- FEAR + +local combatFear = Combat() +combatFear:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_BLUE_GHOST) + +local area = createCombatArea(AREA_FEAR_OPRESSOR) +combatFear:setArea(area) + +local condition = Condition(CONDITION_FEARED) +condition:setParameter(CONDITION_PARAM_TICKS, 3000) +combatFear:addCondition(condition) + +local spell = Spell("instant") + +local combats = { combatRoot, combatFear } + +function spell.onCastSpell(creature, var) + for _, combat in pairs(combats) do + combat:execute(creature, var) + end + + return true +end + +spell:name("soulpit opressor") +spell:words("###938") +spell:blockWalls(true) +spell:needTarget(false) +spell:needLearn(true) +spell:isAggressive(true) +spell:register() diff --git a/data-otservbr-global/scripts/quests/soulpit/soulpit_powerless.lua b/data-otservbr-global/scripts/quests/soulpit/soulpit_powerless.lua new file mode 100644 index 00000000000..36af89a9860 --- /dev/null +++ b/data-otservbr-global/scripts/quests/soulpit/soulpit_powerless.lua @@ -0,0 +1,21 @@ +local combat = Combat() +combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_EXPLOSIONHIT) +combat:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_NONE) + +local condition = Condition(CONDITION_POWERLESS) +condition:setParameter(CONDITION_PARAM_TICKS, 3000) +combat:addCondition(condition) + +local spell = Spell("instant") + +function spell.onCastSpell(creature, var) + return combat:execute(creature, var) +end + +spell:name("soulpit powerless") +spell:words("###939") +spell:blockWalls(true) +spell:needTarget(true) +spell:needLearn(true) +spell:isAggressive(true) +spell:register() diff --git a/data/items/items.xml b/data/items/items.xml index 44476042d8b..9b228d3882a 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -80328,5 +80328,15 @@ Granted by TibiaGoals.com"/> + + + + + + + + + + diff --git a/data/libs/functions/lever.lua b/data/libs/functions/lever.lua index 39802af49d2..651b1e9e908 100644 --- a/data/libs/functions/lever.lua +++ b/data/libs/functions/lever.lua @@ -172,7 +172,7 @@ function Lever.teleportPlayers(self) -- It will teleport all players to the posi local player = v.creature if player then player:teleportTo(v.teleport) - player:getPosition():sendMagicEffect(v.effect) + player:getPosition():sendMagicEffect(v.effect or CONST_ME_TELEPORT) self:getTeleportPlayerFunc(player) end end diff --git a/data/scripts/lib/register_spells.lua b/data/scripts/lib/register_spells.lua index f2e7cacee3d..3d945661ae4 100644 --- a/data/scripts/lib/register_spells.lua +++ b/data/scripts/lib/register_spells.lua @@ -399,6 +399,32 @@ CrossBeamArea3X2 = { { 0, 3, 0 }, } +AREA_FEAR_OPRESSOR = { + { 0, 1, 1, 1, 0 }, + { 1, 1, 1, 1, 1 }, + { 1, 1, 3, 1, 1 }, + { 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 0 }, +} + +AREA_ROOT_OPRESSOR = { + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + { 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 }, + { 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 }, + { 1, 1, 1, 1, 1, 0, 0, 3, 0, 0, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 }, + { 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 }, + { 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, +} + -- The numbered-keys represents the damage values, and their table -- contains the minimum and maximum number of rounds of those damage values. RANGE = { diff --git a/schema.sql b/schema.sql index 6fe1f21cbb8..9d8f3522f69 100644 --- a/schema.sql +++ b/schema.sql @@ -149,6 +149,7 @@ CREATE TABLE IF NOT EXISTS `players` ( `forge_dust_level` bigint(21) NOT NULL DEFAULT '100', `randomize_mount` tinyint(1) NOT NULL DEFAULT '0', `boss_points` int NOT NULL DEFAULT '0', + `animus_mastery` mediumblob DEFAULT NULL, INDEX `account_id` (`account_id`), INDEX `vocation` (`vocation`), CONSTRAINT `players_pk` PRIMARY KEY (`id`), diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 16b91289480..85a685cef3e 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -16,6 +16,10 @@ enum ConfigKey_t : uint16_t { AIMBOT_HOTKEY_ENABLED, ALLOW_CHANGEOUTFIT, ALLOW_RELOAD, + ANIMUS_MASTERY_MAX_MONSTER_XP_MULTIPLIER, + ANIMUS_MASTERY_MONSTER_XP_MULTIPLIER, + ANIMUS_MASTERY_MONSTERS_XP_MULTIPLIER, + ANIMUS_MASTERY_MONSTERS_TO_INCREASE_XP_MULTIPLIER, AUGMENT_INCREASED_DAMAGE_PERCENT, AUGMENT_POWERFUL_IMPACT_PERCENT, AUGMENT_STRONG_IMPACT_PERCENT, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index e0eefc98298..af7c72c24bc 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -199,6 +199,9 @@ bool ConfigManager::load() { loadFloatConfig(L, TRANSCENDANCE_CHANCE_FORMULA_A, "transcendanceChanceFormulaA", 0.0127); loadFloatConfig(L, TRANSCENDANCE_CHANCE_FORMULA_B, "transcendanceChanceFormulaB", 0.1070); loadFloatConfig(L, TRANSCENDANCE_CHANCE_FORMULA_C, "transcendanceChanceFormulaC", 0.0073); + loadFloatConfig(L, ANIMUS_MASTERY_MAX_MONSTER_XP_MULTIPLIER, "animusMasteryMaxMonsterXpMultiplier", 4.0); + loadFloatConfig(L, ANIMUS_MASTERY_MONSTER_XP_MULTIPLIER, "animusMasteryMonsterXpMultiplier", 2.0); + loadFloatConfig(L, ANIMUS_MASTERY_MONSTERS_XP_MULTIPLIER, "animusMasteryMonstersXpMultiplier", 0.1); loadIntConfig(L, ACTIONS_DELAY_INTERVAL, "timeBetweenActions", 200); loadIntConfig(L, ADVENTURERSBLESSING_LEVEL, "adventurersBlessingLevel", 21); @@ -345,6 +348,7 @@ bool ConfigManager::load() { loadIntConfig(L, AUGMENT_INCREASED_DAMAGE_PERCENT, "augmentIncreasedDamagePercent", 5); loadIntConfig(L, AUGMENT_POWERFUL_IMPACT_PERCENT, "augmentPowerfulImpactPercent", 10); loadIntConfig(L, AUGMENT_STRONG_IMPACT_PERCENT, "augmentStrongImpactPercent", 7); + loadIntConfig(L, ANIMUS_MASTERY_MONSTERS_TO_INCREASE_XP_MULTIPLIER, "animusMasteryMonstersToIncreaseXpMultiplier", 10); loadStringConfig(L, CORE_DIRECTORY, "coreDirectory", "data"); loadStringConfig(L, DATA_DIRECTORY, "dataPackDirectory", "data-otservbr-global"); diff --git a/src/creatures/CMakeLists.txt b/src/creatures/CMakeLists.txt index c87a45a0aa0..b48b9c42844 100644 --- a/src/creatures/CMakeLists.txt +++ b/src/creatures/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources(${PROJECT_NAME}_lib PRIVATE npcs/npc.cpp npcs/npcs.cpp npcs/spawns/spawn_npc.cpp + players/animus_mastery/animus_mastery.cpp players/grouping/familiars.cpp players/grouping/groups.cpp players/grouping/guild.cpp diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 6b7667a71a5..273eb3d382d 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -641,6 +641,10 @@ void Combat::CombatHealthFunc(const std::shared_ptr &caster, const std } } + if (targetPlayer && damage.primary.type == COMBAT_HEALING) { + damage.primary.value *= targetPlayer->getBuff(BUFF_HEALINGRECEIVED) / 100.; + } + damage.damageMultiplier += attackerPlayer->wheel()->getMajorStatConditional("Divine Empowerment", WheelMajor_t::DAMAGE); g_logger().trace("Wheel Divine Empowerment damage multiplier {}", damage.damageMultiplier); } @@ -2250,7 +2254,8 @@ void Combat::applyExtensions(const std::shared_ptr &caster, const std: } } } else if (monster) { - chance = monster->critChance() * 100; + chance = monster->getCriticalChance() * 100; + bonus = monster->getCriticalDamage() * 100; } bonus += damage.criticalDamage; diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index 4d4796ec2d5..0b769ce6d91 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -237,6 +237,9 @@ std::shared_ptr Condition::createCondition(ConditionId_t id, Conditio case CONDITION_SOUL: return ObjectPool::allocateShared(id, type, ticks, buff, subId); + case CONDITION_LESSERHEX: + case CONDITION_INTENSEHEX: + case CONDITION_GREATERHEX: case CONDITION_ATTRIBUTES: return ObjectPool::allocateShared(id, type, ticks, buff, subId); @@ -261,6 +264,7 @@ std::shared_ptr Condition::createCondition(ConditionId_t id, Conditio case CONDITION_MUTED: case CONDITION_CHANNELMUTEDTICKS: case CONDITION_YELLTICKS: + case CONDITION_POWERLESS: case CONDITION_PACIFIED: return ObjectPool::allocateShared(id, type, ticks, buff, subId); @@ -464,6 +468,23 @@ std::unordered_set ConditionGeneric::getIcons() const { case CONDITION_ROOTED: icons.insert(PlayerIcon::Rooted); break; + + case CONDITION_LESSERHEX: + icons.insert(PlayerIcon::LesserHex); + break; + + case CONDITION_INTENSEHEX: + icons.insert(PlayerIcon::IntenseHex); + break; + + case CONDITION_GREATERHEX: + icons.insert(PlayerIcon::GreaterHex); + break; + + case CONDITION_POWERLESS: + icons.insert(PlayerIcon::Powerless); + break; + case CONDITION_GOSHNARTAINT: switch (subId) { case 1: @@ -1004,6 +1025,11 @@ bool ConditionAttributes::setParam(ConditionParam_t param, int32_t value) { return true; } + case CONDITION_PARAM_BUFF_HEALINGRECEIVED: { + buffsPercent[BUFF_HEALINGRECEIVED] = std::max(0, value); + return true; + } + case CONDITION_PARAM_BUFF_DAMAGEDEALT: { buffsPercent[BUFF_DAMAGEDEALT] = std::max(0, value); return true; diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index f522eac86a6..2d611f3bfa6 100644 --- a/src/creatures/combat/spells.cpp +++ b/src/creatures/combat/spells.cpp @@ -931,7 +931,7 @@ void Spell::addVocMap(uint16_t vocationId, bool b) { vocSpellMap[vocationId] = b; } -SpellGroup_t Spell::getGroup() { +SpellGroup_t Spell::getGroup() const { return group; } @@ -1058,6 +1058,10 @@ bool InstantSpell::playerCastInstant(const std::shared_ptr &player, std: return false; } + if (player->hasCondition(CONDITION_POWERLESS) && getGroup() == SPELLGROUP_ATTACK) { + return false; + } + LuaVariant var; var.instantName = getName(); std::shared_ptr playerTarget = nullptr; @@ -1379,6 +1383,10 @@ bool RuneSpell::executeUse(const std::shared_ptr &player, const std::sha return false; } + if (player->hasCondition(CONDITION_POWERLESS) && getGroup() == SPELLGROUP_ATTACK) { + return false; + } + LuaVariant var; var.runeName = getName(); diff --git a/src/creatures/combat/spells.hpp b/src/creatures/combat/spells.hpp index 56ff1a330de..e7b8a2a6183 100644 --- a/src/creatures/combat/spells.hpp +++ b/src/creatures/combat/spells.hpp @@ -150,7 +150,7 @@ class Spell : public BaseSpell { [[nodiscard]] const VocSpellMap &getVocMap() const; void addVocMap(uint16_t vocationId, bool b); - SpellGroup_t getGroup(); + SpellGroup_t getGroup() const; void setGroup(SpellGroup_t g); SpellGroup_t getSecondaryGroup(); void setSecondaryGroup(SpellGroup_t g); diff --git a/src/creatures/creatures_definitions.hpp b/src/creatures/creatures_definitions.hpp index dd554c086b3..017a8db7c62 100644 --- a/src/creatures/creatures_definitions.hpp +++ b/src/creatures/creatures_definitions.hpp @@ -116,6 +116,7 @@ enum ConditionType_t : uint8_t { CONDITION_GREATERHEX = 33, CONDITION_BAKRAGORE = 34, CONDITION_GOSHNARTAINT = 35, + CONDITION_POWERLESS = 36, // Need the last ever CONDITION_COUNT @@ -222,6 +223,7 @@ enum ConditionParam_t { CONDITION_PARAM_INCREASE_MANADRAINPERCENT = 80, CONDITION_PARAM_INCREASE_DROWNPERCENT = 81, CONDITION_PARAM_CHARM_CHANCE_MODIFIER = 82, + CONDITION_PARAM_BUFF_HEALINGRECEIVED = 83, }; enum stats_t { @@ -1332,6 +1334,7 @@ enum class CreatureIconModifications_t { Influenced, Fiendish, ReducedHealth, + ReducedHealthExclamation, }; enum class CreatureIconQuests_t { diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 3535cd0897c..c3c5b4975fd 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -48,6 +48,8 @@ Monster::Monster(const std::shared_ptr &mType) : internalLight = mType->info.light; hiddenHealth = mType->info.hiddenHealth; targetDistance = mType->info.targetDistance; + attackSpells = mType->info.attackSpells; + defenseSpells = mType->info.defenseSpells; // Register creature events for (const std::string &scriptName : mType->info.scripts) { @@ -249,8 +251,20 @@ bool Monster::canSeeInvisibility() const { return isImmune(CONDITION_INVISIBLE); } -uint16_t Monster::critChance() const { - return mType->info.critChance; +void Monster::setCriticalDamage(uint16_t damage) { + criticalDamage = damage; +} + +uint16_t Monster::getCriticalDamage() const { + return criticalDamage; +} + +void Monster::setCriticalChance(uint16_t chance) { + criticalChance = chance; +} + +uint16_t Monster::getCriticalChance() const { + return mType->info.critChance + criticalChance; } uint32_t Monster::getManaCost() const { @@ -692,7 +706,8 @@ bool Monster::isOpponent(const std::shared_ptr &creature) const { } uint64_t Monster::getLostExperience() const { - return skillLoss ? mType->info.experience : 0; + float extraExperience = forgeStack <= 15 ? (forgeStack + 10) / 10 : 28; + return skillLoss ? static_cast(std::round(mType->info.experience * extraExperience)) : 0; } uint16_t Monster::getLookCorpse() const { @@ -1132,7 +1147,7 @@ void Monster::doAttacking(uint32_t interval) { const Position &myPos = getPosition(); const Position &targetPos = attackedCreature->getPosition(); - for (const spellBlock_t &spellBlock : mType->info.attackSpells) { + for (const spellBlock_t &spellBlock : attackSpells) { bool inRange = false; if (spellBlock.spell == nullptr || (spellBlock.isMelee && isFleeing())) { @@ -1184,7 +1199,7 @@ bool Monster::canUseAttack(const Position &pos, const std::shared_ptr if (isHostile()) { const Position &targetPos = target->getPosition(); uint32_t distance = std::max(Position::getDistanceX(pos, targetPos), Position::getDistanceY(pos, targetPos)); - for (const spellBlock_t &spellBlock : mType->info.attackSpells) { + for (const spellBlock_t &spellBlock : attackSpells) { if (spellBlock.range != 0 && distance <= spellBlock.range) { return g_game().isSightClear(pos, targetPos, true); } @@ -1279,7 +1294,7 @@ void Monster::onThinkDefense(uint32_t interval) { bool resetTicks = true; defenseTicks += interval; - for (const spellBlock_t &spellBlock : mType->info.defenseSpells) { + for (const spellBlock_t &spellBlock : defenseSpells) { if (spellBlock.speed > defenseTicks) { resetTicks = false; continue; @@ -1329,13 +1344,15 @@ void Monster::onThinkDefense(uint32_t interval) { } const auto &summon = Monster::createMonster(summonName); - if (summon) { - if (g_game().placeCreature(summon, getPosition(), false, summonForce)) { - summon->setMaster(static_self_cast(), true); - g_game().addMagicEffect(getPosition(), CONST_ME_MAGIC_BLUE); - g_game().addMagicEffect(summon->getPosition(), CONST_ME_TELEPORT); - g_game().sendSingleSoundEffect(summon->getPosition(), SoundEffect_t::MONSTER_SPELL_SUMMON, getMonster()); + if (summon && g_game().placeCreature(summon, getPosition(), false, summonForce)) { + if (getSoulPit()) { + const auto stack = getForgeStack(); + summon->setSoulPitStack(stack, true); } + summon->setMaster(static_self_cast(), true); + g_game().addMagicEffect(getPosition(), CONST_ME_MAGIC_BLUE); + g_game().addMagicEffect(summon->getPosition(), CONST_ME_TELEPORT); + g_game().sendSingleSoundEffect(summon->getPosition(), SoundEffect_t::MONSTER_SPELL_SUMMON, getMonster()); } } } @@ -2199,6 +2216,24 @@ void Monster::setHazardSystemDefenseBoost(bool value) { hazardDefenseBoost = value; } +bool Monster::getSoulPit() const { + return soulPit; +} + +void Monster::setSoulPit(bool value) { + soulPit = value; +} + +void Monster::setSoulPitStack(uint8_t stack, bool isSummon /* = false */) { + const bool isBoss = stack == 40; + const CreatureIconModifications_t icon = isBoss ? CreatureIconModifications_t::ReducedHealthExclamation : CreatureIconModifications_t::ReducedHealth; + setForgeStack(stack); + setIcon("soulpit", CreatureIcon(icon, isBoss ? 0 : stack)); + setSoulPit(true); + setDropLoot(false); + setSkillLoss(isBoss && !isSummon); +} + bool Monster::canWalkTo(Position pos, Direction moveDirection) { pos = getNextPosition(moveDirection, pos); if (isInSpawnRange(pos)) { @@ -2523,6 +2558,15 @@ void Monster::getPathSearchParams(const std::shared_ptr &creature, Fin } } +void Monster::applyStacks() { + // Change health based in stacks + const auto percentToIncrement = 1 + (15 * forgeStack + 35) / 100.f; + auto newHealth = static_cast(std::ceil(static_cast(healthMax) * percentToIncrement)); + + healthMax = newHealth; + health = newHealth; +} + void Monster::configureForgeSystem() { if (!canBeForgeMonster()) { return; @@ -2539,13 +2583,6 @@ void Monster::configureForgeSystem() { g_game().updateCreatureIcon(static_self_cast()); } - // Change health based in stacks - const auto percentToIncrement = 1 + (15 * forgeStack + 35) / 100.f; - auto newHealth = static_cast(std::ceil(static_cast(healthMax) * percentToIncrement)); - - healthMax = newHealth; - health = newHealth; - // Event to give Dusts const std::string &Eventname = "ForgeSystemMonster"; registerCreatureEvent(Eventname); @@ -2571,6 +2608,7 @@ uint16_t Monster::getForgeStack() const { void Monster::setForgeStack(uint16_t stack) { forgeStack = stack; + applyStacks(); } ForgeClassifications_t Monster::getMonsterForgeClassification() const { diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index 3661eea9bef..89305e7f5f7 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -77,7 +77,6 @@ class Monster final : public Creature { bool isHostile() const; bool isFamiliar() const; bool canSeeInvisibility() const override; - uint16_t critChance() const; uint32_t getManaCost() const; RespawnType getRespawnType() const; void setSpawnMonster(const std::shared_ptr &newSpawnMonster); @@ -179,6 +178,10 @@ class Monster final : public Creature { void setHazardSystemDefenseBoost(bool value); // Hazard end + bool getSoulPit() const; + void setSoulPit(bool value); + void setSoulPitStack(uint8_t stack, bool isSummon = false); + void updateTargetList(); void clearTargetList(); void clearFriendList(); @@ -187,6 +190,8 @@ class Monster final : public Creature { static uint32_t monsterAutoID; + void applyStacks(); + void configureForgeSystem(); bool canBeForgeMonster() const; @@ -225,6 +230,12 @@ class Monster final : public Creature { void setDead(bool isDead); + void setCriticalChance(uint16_t chance); + uint16_t getCriticalChance() const; + + void setCriticalDamage(uint16_t damage); + uint16_t getCriticalDamage() const; + protected: void onExecuteAsyncTasks() override; @@ -258,6 +269,9 @@ class Monster final : public Creature { uint16_t totalPlayersOnScreen = 0; + uint16_t criticalChance = 0; + uint16_t criticalDamage = 0; + uint32_t attackTicks = 0; uint32_t targetChangeTicks = 0; uint32_t defenseTicks = 0; @@ -276,6 +290,9 @@ class Monster final : public Creature { std::unordered_map m_reflectElementMap; + std::vector attackSpells; + std::vector defenseSpells; + Position masterPos; bool isWalkingBack = false; @@ -290,6 +307,8 @@ class Monster final : public Creature { bool hazardDamageBoost = false; bool hazardDefenseBoost = false; + bool soulPit = false; + bool m_isDead = false; bool m_isImmune = false; diff --git a/src/creatures/monsters/monsters.cpp b/src/creatures/monsters/monsters.cpp index cd33e12e248..fd269da1709 100644 --- a/src/creatures/monsters/monsters.cpp +++ b/src/creatures/monsters/monsters.cpp @@ -382,3 +382,29 @@ bool Monsters::tryAddMonsterType(const std::string &name, const std::shared_ptr< monsters[lowerName] = mType; return true; } + +std::vector> Monsters::getMonstersByRace(BestiaryType_t race) const { + std::vector> monstersByRace; + const auto &bestiaryList = g_game().getBestiaryList(); + + for (const auto &[raceId, name] : bestiaryList) { + const auto &monsterType = g_monsters().getMonsterType(name); + if (monsterType && monsterType->info.bestiaryRace == race) { + monstersByRace.emplace_back(monsterType); + } + } + return monstersByRace; +} + +std::vector> Monsters::getMonstersByBestiaryStars(uint8_t stars) const { + std::vector> monstersByStars; + const auto &bestiaryList = g_game().getBestiaryList(); + + for (const auto &[raceId, name] : bestiaryList) { + const auto &monsterType = g_monsters().getMonsterType(name); + if (monsterType && monsterType->info.bestiaryStars == stars) { + monstersByStars.emplace_back(monsterType); + } + } + return monstersByStars; +} diff --git a/src/creatures/monsters/monsters.hpp b/src/creatures/monsters/monsters.hpp index 35c4d73050d..146f53e604c 100644 --- a/src/creatures/monsters/monsters.hpp +++ b/src/creatures/monsters/monsters.hpp @@ -30,22 +30,6 @@ class Loot { class BaseSpell; struct spellBlock_t { - constexpr spellBlock_t() = default; - ~spellBlock_t() = default; - spellBlock_t(const spellBlock_t &other) = delete; - spellBlock_t &operator=(const spellBlock_t &other) = delete; - spellBlock_t(spellBlock_t &&other) noexcept : - spell(std::move(other.spell)), - chance(other.chance), - speed(other.speed), - range(other.range), - minCombatValue(other.minCombatValue), - maxCombatValue(other.maxCombatValue), - combatSpell(other.combatSpell), - isMelee(other.isMelee) { - other.spell = nullptr; - } - std::shared_ptr spell = nullptr; uint32_t chance = 100; uint32_t speed = 2000; @@ -94,6 +78,8 @@ class MonsterType { uint32_t maxSummons = 0; uint32_t changeTargetSpeed = 0; + uint32_t soulCore = 0; + std::bitset m_conditionImmunities; std::bitset m_damageImmunities; @@ -265,6 +251,8 @@ class Monsters { std::shared_ptr getMonsterTypeByRaceId(uint16_t raceId, bool isBoss = false) const; bool tryAddMonsterType(const std::string &name, const std::shared_ptr &mType); bool deserializeSpell(const std::shared_ptr &spell, spellBlock_t &sb, const std::string &description = "") const; + std::vector> getMonstersByRace(BestiaryType_t race) const; + std::vector> getMonstersByBestiaryStars(uint8_t stars) const; std::unique_ptr scriptInterface; std::map> monsters; diff --git a/src/creatures/players/animus_mastery/animus_mastery.cpp b/src/creatures/players/animus_mastery/animus_mastery.cpp new file mode 100644 index 00000000000..595c98ac81e --- /dev/null +++ b/src/creatures/players/animus_mastery/animus_mastery.cpp @@ -0,0 +1,72 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2024 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +// Player.hpp already includes the animus mastery +#include "creatures/players/player.hpp" + +#include "config/configmanager.hpp" +#include "io/fileloader.hpp" +#include "utils/tools.hpp" + +AnimusMastery::AnimusMastery(Player &player) : + m_player(player) { + maxMonsterXpMultiplier = g_configManager().getFloat(ANIMUS_MASTERY_MAX_MONSTER_XP_MULTIPLIER); + monsterXpMultiplier = g_configManager().getFloat(ANIMUS_MASTERY_MONSTER_XP_MULTIPLIER); + monstersXpMultiplier = g_configManager().getFloat(ANIMUS_MASTERY_MONSTERS_XP_MULTIPLIER); + monstersAmountToMultiply = std::clamp(g_configManager().getNumber(ANIMUS_MASTERY_MONSTERS_TO_INCREASE_XP_MULTIPLIER), 1, std::numeric_limits::max()); +} + +void AnimusMastery::add(const std::string &addMonsterType) { + if (!has(addMonsterType)) { + const std::string &lowerMonsterName = asLowerCaseString(addMonsterType); + animusMasteries.emplace_back(lowerMonsterName); + } +} + +void AnimusMastery::remove(const std::string &removeMonsterType) { + const std::string &lowerMonsterName = asLowerCaseString(removeMonsterType); + std::erase_if(animusMasteries, [lowerMonsterName](const std::string &monsterType) { + return asLowerCaseString(monsterType) == lowerMonsterName; + }); +} + +bool AnimusMastery::has(const std::string &searchMonsterType) const { + const std::string &lowerMonsterName = asLowerCaseString(searchMonsterType); + auto it = std::ranges::find(animusMasteries, lowerMonsterName); + + return it != animusMasteries.end(); +} + +float AnimusMastery::getExperienceMultiplier() const { + uint16_t monsterAmountMultiplier = animusMasteries.size() / monstersAmountToMultiply; + + return std::min(maxMonsterXpMultiplier, 1 + (monsterXpMultiplier + (monsterAmountMultiplier * monstersXpMultiplier)) / 100); +} + +uint16_t AnimusMastery::getPoints() const { + return animusMasteries.size(); +} + +const std::vector &AnimusMastery::getAnimusMasteries() const { + return animusMasteries; +} + +void AnimusMastery::serialize(PropWriteStream &propWriteStream) const { + std::ranges::for_each(animusMasteries, [&propWriteStream](const std::string &monsterName) { + propWriteStream.writeString(monsterName); + }); +} + +bool AnimusMastery::unserialize(PropStream &propStream) { + std::string monsterName; + while (propStream.readString(monsterName)) { + animusMasteries.emplace_back(monsterName); + } + return true; +} diff --git a/src/creatures/players/animus_mastery/animus_mastery.hpp b/src/creatures/players/animus_mastery/animus_mastery.hpp new file mode 100644 index 00000000000..e0b9625b4f2 --- /dev/null +++ b/src/creatures/players/animus_mastery/animus_mastery.hpp @@ -0,0 +1,43 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2024 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#pragma once + +class Player; +class PropStream; +class PropWriteStream; + +class AnimusMastery { +public: + explicit AnimusMastery(Player &player); + + void add(const std::string &addMonsterType); + void remove(const std::string &removeMonsterType); + + bool has(const std::string &searchMonsterType) const; + + float getExperienceMultiplier() const; + + uint16_t getPoints() const; + + const std::vector &getAnimusMasteries() const; + + void serialize(PropWriteStream &propWriteStream) const; + bool unserialize(PropStream &propStream); + +private: + Player &m_player; + + float maxMonsterXpMultiplier = 4.0; + float monsterXpMultiplier = 2.0; + float monstersXpMultiplier = 0.1; + uint16_t monstersAmountToMultiply = 10; + + std::vector animusMasteries; +}; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index a6fb54646e6..d55cb8f5022 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -19,6 +19,7 @@ #include "creatures/monsters/monster.hpp" #include "creatures/monsters/monsters.hpp" #include "creatures/npcs/npc.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/wheel/wheel_gems.hpp" #include "creatures/players/achievement/player_achievement.hpp" @@ -71,7 +72,8 @@ Player::Player(std::shared_ptr p) : lastPing(OTSYS_TIME()), lastPong(lastPing), inbox(std::make_shared(ITEM_INBOX)), - client(std::move(p)) { + client(std::move(p)), + m_animusMastery(*this) { m_playerVIP = std::make_unique(*this); m_wheelPlayer = std::make_unique(*this); m_playerAchievement = std::make_unique(*this); @@ -3134,6 +3136,14 @@ void Player::addExperience(const std::shared_ptr &target, uint64_t exp exp += (exp * (1.75 * getHazardSystemPoints() * g_configManager().getFloat(HAZARD_EXP_BONUS_MULTIPLIER))) / 100.; } + const bool handleAnimusMastery = monster && animusMastery().has(monster->getMonsterType()->name); + float animusMasteryMultiplier = 0; + + if (handleAnimusMastery) { + animusMasteryMultiplier = animusMastery().getExperienceMultiplier(); + exp *= animusMasteryMultiplier; + } + experience += exp; if (sendText) { @@ -3145,6 +3155,10 @@ void Player::addExperience(const std::shared_ptr &target, uint64_t exp } } + if (handleAnimusMastery) { + expString = fmt::format("{} (animus mastery bonus {:.1f}%)", expString, (animusMasteryMultiplier - 1) * 100); + } + TextMessage message(MESSAGE_EXPERIENCE, "You gained " + expString + (handleHazardExperience ? " (Hazard)" : "")); message.position = position; message.primary.value = exp; @@ -5854,9 +5868,11 @@ bool Player::onKilledMonster(const std::shared_ptr &monster) { g_logger().error("[{}] Monster type is null.", __FUNCTION__); return false; } - addHuntingTaskKill(mType); - addBestiaryKill(mType); - addBosstiaryKill(mType); + if (!monster->getSoulPit()) { + addHuntingTaskKill(mType); + addBestiaryKill(mType); + addBosstiaryKill(mType); + } return false; } @@ -10367,6 +10383,15 @@ const std::unique_ptr &Player::title() const { return m_playerTitle; } +// Cyclopedia interface +std::unique_ptr &Player::cyclopedia() { + return m_playerCyclopedia; +} + +const std::unique_ptr &Player::cyclopedia() const { + return m_playerCyclopedia; +} + // VIP interface std::unique_ptr &Player::vip() { return m_playerVIP; @@ -10376,13 +10401,13 @@ const std::unique_ptr &Player::vip() const { return m_playerVIP; } -// Cyclopedia -std::unique_ptr &Player::cyclopedia() { - return m_playerCyclopedia; +// Animus Mastery interface +AnimusMastery &Player::animusMastery() { + return m_animusMastery; } -const std::unique_ptr &Player::cyclopedia() const { - return m_playerCyclopedia; +const AnimusMastery &Player::animusMastery() const { + return m_animusMastery; } void Player::sendLootMessage(const std::string &message) const { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 8f99f9d1821..28ef63ec8ef 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -16,7 +16,9 @@ #include "items/cylinder.hpp" #include "game/movement/position.hpp" #include "creatures/creatures_definitions.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" +class AnimusMastery; class House; class NetworkMessage; class Weapon; @@ -1270,7 +1272,7 @@ class Player final : public Creature, public Cylinder, public Bankable { std::unique_ptr &title(); const std::unique_ptr &title() const; - // Player summary interface + // Player cyclopedia interface std::unique_ptr &cyclopedia(); const std::unique_ptr &cyclopedia() const; @@ -1278,6 +1280,10 @@ class Player final : public Creature, public Cylinder, public Bankable { std::unique_ptr &vip(); const std::unique_ptr &vip() const; + // Player animusMastery interface + AnimusMastery &animusMastery(); + const AnimusMastery &animusMastery() const; + void sendLootMessage(const std::string &message) const; std::shared_ptr getLootPouch(); @@ -1654,6 +1660,7 @@ class Player final : public Creature, public Cylinder, public Bankable { std::unique_ptr m_playerCyclopedia; std::unique_ptr m_playerTitle; std::unique_ptr m_playerVIP; + AnimusMastery m_animusMastery; std::mutex quickLootMutex; diff --git a/src/enums/player_icons.hpp b/src/enums/player_icons.hpp index 7878d9e5037..ecab8a5d8ce 100644 --- a/src/enums/player_icons.hpp +++ b/src/enums/player_icons.hpp @@ -42,6 +42,7 @@ enum class PlayerIcon : uint8_t { GoshnarTaint5 = 25, NewManaShield = 26, Agony = 27, + Powerless = 28, // Must always be the last Count diff --git a/src/game/game.cpp b/src/game/game.cpp index 09fa4346773..d755c05bb9e 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -7649,8 +7649,12 @@ void Game::buildMessageAsTarget( const std::string &damageString ) const { ss.str({}); - auto attackMsg = damage.critical ? "critical " : ""; - auto article = damage.critical ? "a" : "an"; + const auto &monster = attacker ? attacker->getMonster() : nullptr; + bool handleSoulPit = monster ? monster->getSoulPit() && monster->getForgeStack() == 40 : false; + + std::string attackMsg = damage.critical && !handleSoulPit ? "critical " : ""; + std::string article = damage.critical && !handleSoulPit ? "a" : "an"; + ss << "You lose " << damageString; if (!attacker) { ss << '.'; @@ -7662,6 +7666,9 @@ void Game::buildMessageAsTarget( if (damage.extension) { ss << " " << damage.exString; } + if (handleSoulPit && damage.critical) { + ss << " (Soulpit Crit)"; + } message.type = MESSAGE_DAMAGE_RECEIVED; message.text = ss.str(); } diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index 54d7135edf0..9410a5535cc 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -14,6 +14,7 @@ #include "creatures/combat/condition.hpp" #include "database/database.hpp" #include "creatures/monsters/monsters.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" #include "creatures/players/cyclopedia/player_cyclopedia.hpp" @@ -275,6 +276,20 @@ void IOLoginDataLoad::loadPlayerConditions(const std::shared_ptr &player } } +void IOLoginDataLoad::loadPlayerAnimusMastery(const std::shared_ptr &player, const DBResult_ptr &result) { + if (!result || !player) { + g_logger().warn("[{}] - Player or Result nullptr", __FUNCTION__); + return; + } + + unsigned long attrSize; + const char* attr = result->getStream("animus_mastery", attrSize); + PropStream propStream; + propStream.init(attr, attrSize); + + player->animusMastery().unserialize(propStream); +} + void IOLoginDataLoad::loadPlayerDefaultOutfit(const std::shared_ptr &player, const DBResult_ptr &result) { if (!result || !player) { g_logger().warn("[{}] - Player or Result nullptr", __FUNCTION__); diff --git a/src/io/functions/iologindata_load_player.hpp b/src/io/functions/iologindata_load_player.hpp index ca05bdcb1b8..08d31e93072 100644 --- a/src/io/functions/iologindata_load_player.hpp +++ b/src/io/functions/iologindata_load_player.hpp @@ -22,6 +22,7 @@ class IOLoginDataLoad : public IOLoginData { static void loadPlayerExperience(const std::shared_ptr &player, const DBResult_ptr &result); static void loadPlayerBlessings(const std::shared_ptr &player, const DBResult_ptr &result); static void loadPlayerConditions(const std::shared_ptr &player, const DBResult_ptr &result); + static void loadPlayerAnimusMastery(const std::shared_ptr &player, const DBResult_ptr &result); static void loadPlayerDefaultOutfit(const std::shared_ptr &player, const DBResult_ptr &result); static void loadPlayerSkullSystem(const std::shared_ptr &player, const DBResult_ptr &result); static void loadPlayerSkill(const std::shared_ptr &player, const DBResult_ptr &result); diff --git a/src/io/functions/iologindata_save_player.cpp b/src/io/functions/iologindata_save_player.cpp index 613fdac1cb0..11888ee6660 100644 --- a/src/io/functions/iologindata_save_player.cpp +++ b/src/io/functions/iologindata_save_player.cpp @@ -10,6 +10,7 @@ #include "io/functions/iologindata_save_player.hpp" #include "config/configmanager.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" #include "creatures/combat/condition.hpp" #include "creatures/monsters/monsters.hpp" #include "game/game.hpp" @@ -246,6 +247,14 @@ bool IOLoginDataSave::savePlayerFirst(const std::shared_ptr &player) { query << "`conditions` = " << db.escapeBlob(attributes, static_cast(attributesSize)) << ","; + // serialize animus mastery + PropWriteStream propAnimusMasteryStream; + player->animusMastery().serialize(propAnimusMasteryStream); + size_t animusMasterySize; + const char* animusMastery = propAnimusMasteryStream.getStream(animusMasterySize); + + query << "`animus_mastery` = " << db.escapeBlob(animusMastery, static_cast(animusMasterySize)) << ","; + if (g_game().getWorldType() != WORLD_TYPE_PVP_ENFORCED) { int64_t skullTime = 0; diff --git a/src/io/iologindata.cpp b/src/io/iologindata.cpp index 90c6a99c62e..0df4de64e2b 100644 --- a/src/io/iologindata.cpp +++ b/src/io/iologindata.cpp @@ -113,6 +113,9 @@ bool IOLoginData::loadPlayer(const std::shared_ptr &player, const DBResu // load conditions IOLoginDataLoad::loadPlayerConditions(player, result); + // load animus mastery + IOLoginDataLoad::loadPlayerAnimusMastery(player, result); + // load default outfit IOLoginDataLoad::loadPlayerDefaultOutfit(player, result); diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index 6fe6fbcccd3..43a4f79433c 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -179,7 +179,7 @@ const phmap::flat_hash_map ItemTypesMap = { { "food", ITEM_TYPE_FOOD }, { "valuable", ITEM_TYPE_VALUABLE }, { "potion", ITEM_TYPE_POTION }, - + { "soulcore", ITEM_TYPE_SOULCORES }, { "ladder", ITEM_TYPE_LADDER }, { "dummy", ITEM_TYPE_DUMMY }, }; diff --git a/src/items/items.hpp b/src/items/items.hpp index b977f0bf7a9..f4eae14df27 100644 --- a/src/items/items.hpp +++ b/src/items/items.hpp @@ -415,6 +415,10 @@ class Items { return items.size(); } + std::vector &getItems() { + return items; + } + NameMap nameToItems; void addLadderId(uint16_t newId) { diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index eec876eee7c..eff01af0313 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -66,6 +66,7 @@ void GameFunctions::init(lua_State* L) { Lua::registerMethod(L, "Game", "createItem", GameFunctions::luaGameCreateItem); Lua::registerMethod(L, "Game", "createContainer", GameFunctions::luaGameCreateContainer); Lua::registerMethod(L, "Game", "createMonster", GameFunctions::luaGameCreateMonster); + Lua::registerMethod(L, "Game", "createSoulPitMonster", GameFunctions::luaGameCreateSoulPitMonster); Lua::registerMethod(L, "Game", "createNpc", GameFunctions::luaGameCreateNpc); Lua::registerMethod(L, "Game", "generateNpc", GameFunctions::luaGameGenerateNpc); Lua::registerMethod(L, "Game", "createTile", GameFunctions::luaGameCreateTile); @@ -107,6 +108,11 @@ void GameFunctions::init(lua_State* L) { Lua::registerMethod(L, "Game", "getSecretAchievements", GameFunctions::luaGameGetSecretAchievements); Lua::registerMethod(L, "Game", "getPublicAchievements", GameFunctions::luaGameGetPublicAchievements); Lua::registerMethod(L, "Game", "getAchievements", GameFunctions::luaGameGetAchievements); + + Lua::registerMethod(L, "Game", "getSoulCoreItems", GameFunctions::luaGameGetSoulCoreItems); + + Lua::registerMethod(L, "Game", "getMonstersByRace", GameFunctions::luaGameGetMonstersByRace); + Lua::registerMethod(L, "Game", "getMonstersByBestiaryStars", GameFunctions::luaGameGetMonstersByBestiaryStars); } // Game @@ -546,6 +552,41 @@ int GameFunctions::luaGameCreateMonster(lua_State* L) { return 1; } +int GameFunctions::luaGameCreateSoulPitMonster(lua_State* L) { + // Game.createSoulPitMonster(monsterName, position, [stack = 1, [, extended = false[, force = false[, master = nil]]]]) + const auto &monster = Monster::createMonster(Lua::getString(L, 1)); + if (!monster) { + lua_pushnil(L); + return 1; + } + + bool isSummon = false; + if (lua_gettop(L) >= 6) { + if (const auto &master = Lua::getCreature(L, 6)) { + monster->setMaster(master, true); + isSummon = true; + } + } + + const Position &position = Lua::getPosition(L, 2); + const uint8_t stack = Lua::getNumber(L, 3, 1); + const bool extended = Lua::getBoolean(L, 4, false); + const bool force = Lua::getBoolean(L, 5, false); + if (g_game().placeCreature(monster, position, extended, force)) { + monster->setSoulPitStack(stack); + monster->onSpawn(position); + + Lua::pushUserdata(L, monster); + Lua::setMetatable(L, -1, "Monster"); + } else { + if (isSummon) { + monster->setMaster(nullptr); + } + lua_pushnil(L); + } + return 1; +} + int GameFunctions::luaGameGenerateNpc(lua_State* L) { // Game.generateNpc(npcName) const auto &npc = Npc::createNpc(Lua::getString(L, 1)); @@ -994,3 +1035,55 @@ int GameFunctions::luaGameGetAchievements(lua_State* L) { } return 1; } + +int GameFunctions::luaGameGetSoulCoreItems(lua_State* L) { + // Game.getSoulCoreItems() + std::vector soulCoreItems; + + for (const auto &itemType : Item::items.getItems()) { + if (itemType.m_primaryType == "SoulCores" || itemType.type == ITEM_TYPE_SOULCORES) { + soulCoreItems.emplace_back(&itemType); + } + } + + lua_createtable(L, soulCoreItems.size(), 0); + + int index = 0; + for (const auto* itemType : soulCoreItems) { + Lua::pushUserdata(L, itemType); + Lua::setMetatable(L, -1, "ItemType"); + lua_rawseti(L, -2, ++index); + } + + return 1; +} + +int GameFunctions::luaGameGetMonstersByRace(lua_State* L) { + // Game.getMonstersByRace(race) + const BestiaryType_t race = Lua::getNumber(L, 1); + const auto monstersByRace = g_monsters().getMonstersByRace(race); + + lua_createtable(L, monstersByRace.size(), 0); + int index = 0; + for (const auto &monsterType : monstersByRace) { + Lua::pushUserdata(L, monsterType); + Lua::setMetatable(L, -1, "MonsterType"); + lua_rawseti(L, -2, ++index); + } + return 1; +} + +int GameFunctions::luaGameGetMonstersByBestiaryStars(lua_State* L) { + // Game.getMonstersByBestiaryStars(stars) + const uint8_t stars = Lua::getNumber(L, 1); + const auto monstersByStars = g_monsters().getMonstersByBestiaryStars(stars); + + lua_createtable(L, monstersByStars.size(), 0); + int index = 0; + for (const auto &monsterType : monstersByStars) { + Lua::pushUserdata(L, monsterType); + Lua::setMetatable(L, -1, "MonsterType"); + lua_rawseti(L, -2, ++index); + } + return 1; +} diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index 6d332face9f..b24b960368c 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -46,6 +46,7 @@ class GameFunctions { static int luaGameCreateItem(lua_State* L); static int luaGameCreateContainer(lua_State* L); static int luaGameCreateMonster(lua_State* L); + static int luaGameCreateSoulPitMonster(lua_State* L); static int luaGameGenerateNpc(lua_State* L); static int luaGameCreateNpc(lua_State* L); static int luaGameCreateTile(lua_State* L); @@ -88,4 +89,9 @@ class GameFunctions { static int luaGameGetSecretAchievements(lua_State* L); static int luaGameGetPublicAchievements(lua_State* L); static int luaGameGetAchievements(lua_State* L); + + static int luaGameGetSoulCoreItems(lua_State* L); + + static int luaGameGetMonstersByRace(lua_State* L); + static int luaGameGetMonstersByBestiaryStars(lua_State* L); }; diff --git a/src/lua/functions/creatures/monster/monster_functions.cpp b/src/lua/functions/creatures/monster/monster_functions.cpp index 3f5d0c25ea8..7d73d7bbea9 100644 --- a/src/lua/functions/creatures/monster/monster_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_functions.cpp @@ -66,6 +66,8 @@ void MonsterFunctions::init(lua_State* L) { Lua::registerMethod(L, "Monster", "hazardDamageBoost", MonsterFunctions::luaMonsterHazardDamageBoost); Lua::registerMethod(L, "Monster", "hazardDefenseBoost", MonsterFunctions::luaMonsterHazardDefenseBoost); + Lua::registerMethod(L, "Monster", "soulPit", MonsterFunctions::luaMonsterSoulPit); + Lua::registerMethod(L, "Monster", "addReflectElement", MonsterFunctions::luaMonsterAddReflectElement); Lua::registerMethod(L, "Monster", "addDefense", MonsterFunctions::luaMonsterAddDefense); Lua::registerMethod(L, "Monster", "getDefense", MonsterFunctions::luaMonsterGetDefense); @@ -73,6 +75,12 @@ void MonsterFunctions::init(lua_State* L) { Lua::registerMethod(L, "Monster", "isDead", MonsterFunctions::luaMonsterIsDead); Lua::registerMethod(L, "Monster", "immune", MonsterFunctions::luaMonsterImmune); + Lua::registerMethod(L, "Monster", "criticalChance", MonsterFunctions::luaMonsterCriticalChance); + Lua::registerMethod(L, "Monster", "criticalDamage", MonsterFunctions::luaMonsterCriticalDamage); + + Lua::registerMethod(L, "Monster", "addAttackSpell", MonsterFunctions::luaMonsterAddAttackSpell); + Lua::registerMethod(L, "Monster", "addDefenseSpell", MonsterFunctions::luaMonsterAddDefenseSpell); + CharmFunctions::init(L); LootFunctions::init(L); MonsterSpellFunctions::init(L); @@ -700,6 +708,23 @@ int MonsterFunctions::luaMonsterHazardDefenseBoost(lua_State* L) { return 1; } +int MonsterFunctions::luaMonsterSoulPit(lua_State* L) { + // get: monster:soulPit() ; set: monster:soulPit(hazard) + const auto &monster = Lua::getUserdataShared(L, 1); + const bool soulPit = Lua::getBoolean(L, 2, false); + if (monster) { + if (lua_gettop(L) == 1) { + Lua::pushBoolean(L, monster->getSoulPit()); + } else { + monster->setSoulPit(soulPit); + Lua::pushBoolean(L, monster->getSoulPit()); + } + } else { + lua_pushnil(L); + } + return 1; +} + int MonsterFunctions::luaMonsterAddReflectElement(lua_State* L) { // monster:addReflectElement(type, percent) const auto &monster = Lua::getUserdataShared(L, 1); @@ -772,3 +797,81 @@ int MonsterFunctions::luaMonsterImmune(lua_State* L) { Lua::pushBoolean(L, monster->isImmune()); return 1; } + +int MonsterFunctions::luaMonsterCriticalChance(lua_State* L) { + // get: monster:criticalChance(); set: monster:criticalChance(critical) + const auto &monster = Lua::getUserdataShared(L, 1); + const auto critical = Lua::getNumber(L, 2, 0); + if (monster) { + if (lua_gettop(L) == 1) { + Lua::pushBoolean(L, monster->getCriticalChance()); + } else { + monster->setCriticalChance(critical); + Lua::pushBoolean(L, monster->getCriticalChance()); + } + } else { + lua_pushnil(L); + } + return 1; +} + +int MonsterFunctions::luaMonsterCriticalDamage(lua_State* L) { + // get: monster:criticalDamage(); set: monster:criticalDamage(damage) + const auto &monster = Lua::getUserdataShared(L, 1); + const auto damage = Lua::getNumber(L, 2, 0); + if (monster) { + if (lua_gettop(L) == 1) { + Lua::pushBoolean(L, monster->getCriticalDamage()); + } else { + monster->setCriticalDamage(damage); + Lua::pushBoolean(L, monster->getCriticalDamage()); + } + } else { + lua_pushnil(L); + } + return 1; +} + +int MonsterFunctions::luaMonsterAddAttackSpell(lua_State* L) { + // monster:addAttackSpell(monsterspell) + const auto &monster = Lua::getUserdataShared(L, 1); + if (monster) { + const auto &spell = Lua::getUserdataShared(L, 2); + if (spell) { + spellBlock_t sb; + const auto &monsterName = monster->getName(); + if (g_monsters().deserializeSpell(spell, sb, monsterName)) { + monster->attackSpells.push_back(std::move(sb)); + } else { + g_logger().warn("Monster: {}, cant load spell: {}", monsterName, spell->name); + } + } else { + lua_pushnil(L); + } + } else { + lua_pushnil(L); + } + return 1; +} + +int MonsterFunctions::luaMonsterAddDefenseSpell(lua_State* L) { + // monster:addDefenseSpell(monsterspell) + const auto &monster = Lua::getUserdataShared(L, 1); + if (monster) { + const auto &spell = Lua::getUserdataShared(L, 2); + if (spell) { + spellBlock_t sb; + const auto &monsterName = monster->getName(); + if (g_monsters().deserializeSpell(spell, sb, monsterName)) { + monster->defenseSpells.push_back(std::move(sb)); + } else { + g_logger().warn("Monster: {}, Cant load spell: {}", monsterName, spell->name); + } + } else { + lua_pushnil(L); + } + } else { + lua_pushnil(L); + } + return 1; +} diff --git a/src/lua/functions/creatures/monster/monster_functions.hpp b/src/lua/functions/creatures/monster/monster_functions.hpp index 4ba696e941b..a7c6a5269e1 100644 --- a/src/lua/functions/creatures/monster/monster_functions.hpp +++ b/src/lua/functions/creatures/monster/monster_functions.hpp @@ -76,8 +76,15 @@ class MonsterFunctions { static int luaMonsterAddDefense(lua_State* L); static int luaMonsterGetDefense(lua_State* L); + static int luaMonsterSoulPit(lua_State* L); + static int luaMonsterIsDead(lua_State* L); static int luaMonsterImmune(lua_State* L); + static int luaMonsterCriticalChance(lua_State* L); + static int luaMonsterCriticalDamage(lua_State* L); + + static int luaMonsterAddAttackSpell(lua_State* L); + static int luaMonsterAddDefenseSpell(lua_State* L); friend class CreatureFunctions; }; diff --git a/src/lua/functions/creatures/monster/monster_type_functions.cpp b/src/lua/functions/creatures/monster/monster_type_functions.cpp index 8b2f4a5f314..03ade91f273 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.cpp @@ -151,6 +151,8 @@ void MonsterTypeFunctions::init(lua_State* L) { Lua::registerMethod(L, "MonsterType", "deathSound", MonsterTypeFunctions::luaMonsterTypedeathSound); Lua::registerMethod(L, "MonsterType", "variant", MonsterTypeFunctions::luaMonsterTypeVariant); + Lua::registerMethod(L, "MonsterType", "getMonstersByRace", MonsterTypeFunctions::luaMonsterTypeGetMonstersByRace); + Lua::registerMethod(L, "MonsterType", "getMonstersByBestiaryStars", MonsterTypeFunctions::luaMonsterTypeGetMonstersByBestiaryStars); } void MonsterTypeFunctions::createMonsterTypeLootLuaTable(lua_State* L, const std::vector &lootList) { @@ -658,6 +660,22 @@ int MonsterTypeFunctions::luaMonsterTypeRaceid(lua_State* L) { return 1; } +int MonsterTypeFunctions::luaMonsterTypeSoulCore(lua_State* L) { + // get: monsterType:luaMonsterTypeSoulCore() set: monsterType:luaMonsterTypeSoulCore(id) + const auto &monsterType = Lua::getUserdataShared(L, 1); + if (monsterType) { + if (lua_gettop(L) == 1) { + lua_pushnumber(L, monsterType->info.soulCore); + } else { + monsterType->info.soulCore = Lua::getNumber(L, 2); + Lua::pushBoolean(L, true); + } + } else { + lua_pushnil(L); + } + return 1; +} + int MonsterTypeFunctions::luaMonsterTypeBestiarytoKill(lua_State* L) { // get: monsterType:BestiarytoKill() set: monsterType:BestiarytoKill(value) const auto &monsterType = Lua::getUserdataShared(L, 1); @@ -1857,3 +1875,33 @@ int MonsterTypeFunctions::luaMonsterTypeVariant(lua_State* L) { return 1; } + +int MonsterTypeFunctions::luaMonsterTypeGetMonstersByRace(lua_State* L) { + // monsterType:getMonstersByRace(race) + const BestiaryType_t race = Lua::getNumber(L, 1); + const auto monstersByRace = g_monsters().getMonstersByRace(race); + + lua_createtable(L, monstersByRace.size(), 0); + int index = 0; + for (const auto &monsterType : monstersByRace) { + Lua::pushUserdata(L, monsterType); + Lua::setMetatable(L, -1, "MonsterType"); + lua_rawseti(L, -2, ++index); + } + return 1; +} + +int MonsterTypeFunctions::luaMonsterTypeGetMonstersByBestiaryStars(lua_State* L) { + // monsterType:getMonstersByBestiaryStars(stars) + const uint8_t stars = Lua::getNumber(L, 1); + const auto monstersByStars = g_monsters().getMonstersByBestiaryStars(stars); + + lua_createtable(L, monstersByStars.size(), 0); + int index = 0; + for (const auto &monsterType : monstersByStars) { + Lua::pushUserdata(L, monsterType); + Lua::setMetatable(L, -1, "MonsterType"); + lua_rawseti(L, -2, ++index); + } + return 1; +} diff --git a/src/lua/functions/creatures/monster/monster_type_functions.hpp b/src/lua/functions/creatures/monster/monster_type_functions.hpp index e272ea45cd7..0994edaed23 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.hpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.hpp @@ -131,6 +131,8 @@ class MonsterTypeFunctions { static int luaMonsterTypeBossRace(lua_State* L); static int luaMonsterTypeBossRaceId(lua_State* L); + static int luaMonsterTypeSoulCore(lua_State* L); + static int luaMonsterTypeSoundChance(lua_State* L); static int luaMonsterTypeSoundSpeedTicks(lua_State* L); static int luaMonsterTypeAddSound(lua_State* L); @@ -139,4 +141,6 @@ class MonsterTypeFunctions { static int luaMonsterTypeCritChance(lua_State* L); static int luaMonsterTypeVariant(lua_State* L); + static int luaMonsterTypeGetMonstersByRace(lua_State* L); + static int luaMonsterTypeGetMonstersByBestiaryStars(lua_State* L); }; diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 46fdebd016e..97d3a07f876 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -15,6 +15,7 @@ #include "creatures/creature.hpp" #include "creatures/interactions/chat.hpp" #include "creatures/monsters/monsters.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" @@ -404,6 +405,10 @@ void PlayerFunctions::init(lua_State* L) { Lua::registerMethod(L, "Player", "removeIconBakragore", PlayerFunctions::luaPlayerRemoveIconBakragore); Lua::registerMethod(L, "Player", "sendCreatureAppear", PlayerFunctions::luaPlayerSendCreatureAppear); + Lua::registerMethod(L, "Player", "addAnimusMastery", PlayerFunctions::luaPlayerAddAnimusMastery); + Lua::registerMethod(L, "Player", "removeAnimusMastery", PlayerFunctions::luaPlayerRemoveAnimusMastery); + Lua::registerMethod(L, "Player", "hasAnimusMastery", PlayerFunctions::luaPlayerHasAnimusMastery); + GroupFunctions::init(L); GuildFunctions::init(L); MountFunctions::init(L); @@ -4870,3 +4875,42 @@ int PlayerFunctions::luaPlayerSendCreatureAppear(lua_State* L) { Lua::pushBoolean(L, true); return 1; } + +int PlayerFunctions::luaPlayerAddAnimusMastery(lua_State* L) { + auto player = Lua::getUserdataShared(L, 1); + if (!player) { + Lua::reportErrorFunc(Lua::getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + + const std::string &monsterType = Lua::getString(L, 2); + player->animusMastery().add(monsterType); + + return 1; +} +int PlayerFunctions::luaPlayerRemoveAnimusMastery(lua_State* L) { + auto player = Lua::getUserdataShared(L, 1); + if (!player) { + Lua::reportErrorFunc(Lua::getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + + const std::string &monsterType = Lua::getString(L, 2); + player->animusMastery().remove(monsterType); + + return 1; +} +int PlayerFunctions::luaPlayerHasAnimusMastery(lua_State* L) { + auto player = Lua::getUserdataShared(L, 1); + if (!player) { + Lua::reportErrorFunc(Lua::getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + + const std::string &monsterType = Lua::getString(L, 2); + + bool has = player->animusMastery().has(monsterType); + Lua::pushBoolean(L, has); + + return 1; +} diff --git a/src/lua/functions/creatures/player/player_functions.hpp b/src/lua/functions/creatures/player/player_functions.hpp index 8e4f1381b7b..54e57d56155 100644 --- a/src/lua/functions/creatures/player/player_functions.hpp +++ b/src/lua/functions/creatures/player/player_functions.hpp @@ -384,5 +384,9 @@ class PlayerFunctions { static int luaPlayerSendCreatureAppear(lua_State* L); + static int luaPlayerAddAnimusMastery(lua_State* L); + static int luaPlayerRemoveAnimusMastery(lua_State* L); + static int luaPlayerHasAnimusMastery(lua_State* L); + friend class CreatureFunctions; }; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 9d385be58c7..4cdc5ecbdf1 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -19,6 +19,7 @@ #include "creatures/monsters/monster.hpp" #include "creatures/monsters/monsters.hpp" #include "creatures/npcs/npc.hpp" +#include "creatures/players/animus_mastery/animus_mastery.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" #include "creatures/players/cyclopedia/player_cyclopedia.hpp" @@ -2390,9 +2391,13 @@ void ProtocolGame::parseBestiarysendMonsterData(NetworkMessage &msg) { newmsg.addByte(currentLevel); - newmsg.add(0); // Animus Mastery Bonus - newmsg.add(0); // Animus Mastery Points - + if (player->animusMastery().has(mtype->name)) { + newmsg.add(static_cast(std::round((player->animusMastery().getExperienceMultiplier() - 1) * 1000))); // Animus Mastery Bonus + newmsg.add(player->animusMastery().getPoints()); // Animus Mastery Points + } else { + newmsg.add(0); + newmsg.add(0); + } newmsg.add(killCounter); newmsg.add(mtype->info.bestiaryFirstUnlock); @@ -3026,10 +3031,15 @@ void ProtocolGame::parseBestiarysendCreatures(NetworkMessage &msg) { newmsg.addByte(0); } - newmsg.add(0); // Creature Animous Bonus + const auto monsterType = g_monsters().getMonsterType(it_.second); + if (monsterType && player->animusMastery().has(it_.second)) { + newmsg.add(static_cast(std::round((player->animusMastery().getExperienceMultiplier() - 1) * 1000))); // Animus Mastery Bonus + } else { + newmsg.add(0); + } } - newmsg.add(0); // Animus Mastery Points + newmsg.add(player->animusMastery().getPoints()); // Animus Mastery Points writeToOutputBuffer(newmsg); } From 51fb9703a5305ace45d4bc6fba6b1df8402ae004 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:48:09 -0300 Subject: [PATCH 04/18] fix: add soulpit includes on visual studio solution (#3296) --- vcproj/canary.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcproj/canary.vcxproj b/vcproj/canary.vcxproj index 6436dd704a9..38342c2b885 100644 --- a/vcproj/canary.vcxproj +++ b/vcproj/canary.vcxproj @@ -45,6 +45,7 @@ + @@ -260,6 +261,7 @@ + From 018f3b79e881cd86661713c1393ca3360f52294d Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 29 Jan 2025 11:29:52 -0300 Subject: [PATCH 05/18] fix: warning on transformItem (#3302) --- data/libs/functions/position.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/libs/functions/position.lua b/data/libs/functions/position.lua index 27923eeb268..ee0dad49967 100644 --- a/data/libs/functions/position.lua +++ b/data/libs/functions/position.lua @@ -302,7 +302,9 @@ function Position:transformItem(itemId, itemTransform, effect) local thing = Tile(self):getItemById(itemId) if thing then thing:transform(itemTransform) - Position(self):sendMagicEffect(effect) + if effect then + Position(self):sendMagicEffect(effect) + end end end From ede9b6ac1be514f871c9a6361db93354de5290f9 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:17:03 -0300 Subject: [PATCH 06/18] fix: ferumbras ascension quest bosses (#3297) --- .../ferumbras_ascension/actions_mazoran.lua | 71 +++++----------- .../ferumbras_ascension/actions_plagirath.lua | 71 +++++----------- .../ferumbras_ascension/actions_ragiaz.lua | 81 ++++++------------ .../ferumbras_ascension/actions_razzagorn.lua | 68 +++++---------- .../ferumbras_ascension/actions_shulgrax.lua | 70 +++++----------- .../ferumbras_ascension/actions_tarbaz.lua | 67 +++++---------- .../ferumbras_ascension/actions_zamulosh.lua | 83 +++++++------------ 7 files changed, 153 insertions(+), 358 deletions(-) diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_mazoran.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_mazoran.lua index aa564b94fd6..83ab13b7613 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_mazoran.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_mazoran.lua @@ -1,57 +1,24 @@ local config = { - centerRoom = Position(33584, 32689, 14), - BossPosition = Position(33584, 32689, 14), + boss = { + name = "Mazoran", + position = Position(33584, 32689, 14), + }, + + timeToDefeat = 30 * 60, playerPositions = { - Position(33593, 32644, 14), - Position(33593, 32645, 14), - Position(33593, 32646, 14), - Position(33593, 32647, 14), - Position(33593, 32648, 14), + { pos = Position(33593, 32644, 14), teleport = Position(33585, 32693, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33593, 32645, 14), teleport = Position(33585, 32693, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33593, 32646, 14), teleport = Position(33585, 32693, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33593, 32647, 14), teleport = Position(33585, 32693, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33593, 32648, 14), teleport = Position(33585, 32693, 14), effect = CONST_ME_TELEPORT }, }, - newPosition = Position(33585, 32693, 14), + specPos = { + from = Position(33570, 32677, 14), + to = Position(33597, 32700, 14), + }, + exit = Position(33319, 32318, 13), } -local leverMazoran = Action() - -function leverMazoran.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33593, 32644, 14) then - item:transform(8912) - return true - end - end - - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Mazoran", Position(33572, 32679, 14), Position(33599, 32701, 14)) then - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Mazoran.") - return true - end - end - Game.createMonster("Mazoran", config.BossPosition, true, true) - for y = 32644, 32648 do - local playerTile = Tile(Position(33593, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.MazoranTimer, os.time() + os.time() + 60 * 60 * 2 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33572, 32679, 14), Position(33599, 32701, 14), Position(33319, 32318, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverMazoran:uid(1025) -leverMazoran:register() +local lever = BossLever(config) +lever:position(Position(33593, 32643, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_plagirath.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_plagirath.lua index 82d5535f8e6..a29930503a8 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_plagirath.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_plagirath.lua @@ -1,57 +1,24 @@ local config = { - centerRoom = Position(33172, 31501, 13), - BossPosition = Position(33172, 31501, 13), + boss = { + name = "Plagirath", + position = Position(33172, 31501, 13), + }, + + timeToDefeat = 30 * 60, playerPositions = { - Position(33229, 31500, 13), - Position(33229, 31501, 13), - Position(33229, 31502, 13), - Position(33229, 31503, 13), - Position(33229, 31504, 13), + { pos = Position(33229, 31500, 13), teleport = Position(33173, 31504, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33229, 31501, 13), teleport = Position(33173, 31504, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33229, 31502, 13), teleport = Position(33173, 31504, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33229, 31503, 13), teleport = Position(33173, 31504, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33229, 31504, 13), teleport = Position(33173, 31504, 13), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33159, 31488, 13), + to = Position(33190, 31515, 13), }, - newPosition = Position(33173, 31504, 13), + exit = Position(33319, 32318, 13), } -local leverPlagirath = Action() - -function leverPlagirath.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33229, 31500, 13) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - if Game.getStorageValue(Storage.Quest.U10_90.FerumbrasAscension.PlagirathTimer) >= 1 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait a while, recently someone challenge Plagirath.") - return true - end - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Plagirath.") - return true - end - end - Game.createMonster("Plagirath", config.BossPosition, true, true) - for y = 31500, 31504 do - local playerTile = Tile(Position(33229, y, 13)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.PlagirathTimer, os.time() + 60 * 60 * 24 * 2) - end - end - Game.setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.PlagirathTimer, 1) - addEvent(clearForgotten, 30 * 60 * 1000, Position(33159, 31491, 13), Position(33185, 31513, 13), Position(33319, 32318, 13), Storage.Quest.U10_90.FerumbrasAscension.PlagirathTimer) - item:transform(8912) - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverPlagirath:uid(1022) -leverPlagirath:register() +local lever = BossLever(config) +lever:position(Position(33229, 31499, 13)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ragiaz.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ragiaz.lua index e63df82d82d..36533dbdb33 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ragiaz.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_ragiaz.lua @@ -1,59 +1,30 @@ local config = { - centerRoom = Position(33481, 32334, 13), - BossPosition = Position(33481, 32334, 13), - newPosition = Position(33482, 32339, 13), - deathDragons = { - Position(33476, 32331, 13), - Position(33476, 32340, 13), - Position(33487, 32340, 13), - Position(33488, 32331, 13), + boss = { + name = "Ragiaz", + position = Position(33481, 32334, 13), }, -} - -local leverRagiaz = Action() - -function leverRagiaz.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33456, 32356, 13) then - item:transform(8912) - return true - end - end - - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Ragiaz", Position(33472, 32323, 13), Position(33493, 32347, 13)) then - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Ragiaz.") - return true - end - end - Game.createMonster("Ragiaz", config.BossPosition, true, true) - for d = 1, #config.deathDragons do - Game.createMonster("Death Dragon", config.deathDragons[d], true, true) - end - for x = 33456, 33460 do - local playerTile = Tile(Position(x, 32356, 13)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.RagiazTimer, os.time() + 60 * 60 * 2 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33472, 32323, 13), Position(33493, 32347, 13), Position(33319, 32318, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - return true -end + timeToDefeat = 30 * 60, + playerPositions = { + { pos = Position(33456, 32356, 13), teleport = Position(33482, 32339, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33457, 32356, 13), teleport = Position(33482, 32339, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33458, 32356, 13), teleport = Position(33482, 32339, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33459, 32356, 13), teleport = Position(33482, 32339, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33460, 32356, 13), teleport = Position(33482, 32339, 13), effect = CONST_ME_TELEPORT }, + }, + monsters = { + { name = "Death Dragon", pos = Position(33476, 32331, 13) }, + { name = "Death Dragon", pos = Position(33476, 32340, 13) }, + { name = "Death Dragon", pos = Position(33487, 32340, 13) }, + { name = "Death Dragon", pos = Position(33488, 32331, 13) }, + }, + specPos = { + from = Position(33468, 32319, 13), + to = Position(33495, 32347, 13), + }, + exit = Position(33319, 32318, 13), +} -leverRagiaz:uid(1023) -leverRagiaz:register() +local lever = BossLever(config) +lever:position(Position(33455, 32356, 13)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_razzagorn.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_razzagorn.lua index fe5b4e06ed9..ca4f464a1b1 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_razzagorn.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_razzagorn.lua @@ -1,50 +1,24 @@ local config = { - centerRoom = Position(33422, 32467, 14), - BossPosition = Position(33422, 32467, 14), - newPosition = Position(33419, 32467, 14), -} - -local leverRazzagorn = Action() + boss = { + name = "Razzagorn", + position = Position(33422, 32467, 14), + }, -function leverRazzagorn.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33386, 32455, 14) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - if Game.getStorageValue(Storage.Quest.U10_90.FerumbrasAscension.RazzagornTimer) >= 1 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait a while, recently someone challenge Razzagorn.") - return true - end - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Razzagorn.") - return true - end - end - Game.createMonster("Razzagorn", config.BossPosition, true, true) - for x = 33386, 33390 do - local playerTile = Tile(Position(x, 32455, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.RazzagornTimer, os.time() + 60 * 60 * 2 * 24) - end - end - Game.setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.RazzagornTimer, 1) - addEvent(clearForgotten, 30 * 60 * 1000, Position(33408, 32454, 14), Position(33440, 32480, 14), Position(33319, 32318, 13), Storage.Quest.U10_90.FerumbrasAscension.RazzagornTimer) - item:transform(8912) - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end + timeToDefeat = 30 * 60, + playerPositions = { + { pos = Position(33386, 32455, 14), teleport = Position(33419, 32467, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33387, 32455, 14), teleport = Position(33419, 32467, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33388, 32455, 14), teleport = Position(33419, 32467, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33389, 32455, 14), teleport = Position(33419, 32467, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33390, 32455, 14), teleport = Position(33419, 32467, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33407, 32453, 14), + to = Position(33439, 32481, 14), + }, + exit = Position(33319, 32318, 13), +} -leverRazzagorn:uid(1024) -leverRazzagorn:register() +local lever = BossLever(config) +lever:position(Position(33385, 32455, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_shulgrax.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_shulgrax.lua index 2b1792a9261..a9106ce224d 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_shulgrax.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_shulgrax.lua @@ -1,56 +1,24 @@ local config = { - centerRoom = Position(33485, 32786, 13), - BossPosition = Position(33485, 32786, 13), + boss = { + name = "Shulgrax", + position = Position(33485, 32786, 13), + }, + + timeToDefeat = 30 * 60, playerPositions = { - Position(33434, 32785, 13), - Position(33434, 32786, 13), - Position(33434, 32787, 13), - Position(33434, 32788, 13), - Position(33434, 32789, 13), + { pos = Position(33434, 32785, 13), teleport = Position(33485, 32790, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33434, 32786, 13), teleport = Position(33485, 32790, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33434, 32787, 13), teleport = Position(33485, 32790, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33434, 32788, 13), teleport = Position(33485, 32790, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33434, 32789, 13), teleport = Position(33485, 32790, 13), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33474, 32775, 13), + to = Position(33496, 32798, 13), }, - newPosition = Position(33485, 32790, 13), + exit = Position(33319, 32318, 13), } -local leverShulgrax = Action() - -function leverShulgrax.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33434, 32785, 13) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Shulgrax", Position(33473, 32776, 13), Position(33496, 32798, 13)) then - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Shulgrax.") - return true - end - end - Game.createMonster("Shulgrax", config.BossPosition, true, true) - for y = 32785, 32789 do - local playerTile = Tile(Position(33434, y, 13)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.ShulgraxTimer, os.time() + 60 * 60 * 2 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33473, 32776, 13), Position(33496, 32798, 13), Position(33319, 32318, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverShulgrax:uid(1028) -leverShulgrax:register() +local lever = BossLever(config) +lever:position(Position(33434, 32784, 13)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_tarbaz.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_tarbaz.lua index 7423b8f3820..135b5f4940c 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_tarbaz.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_tarbaz.lua @@ -1,49 +1,24 @@ local config = { - centerRoom = Position(33459, 32844, 11), - BossPosition = Position(33459, 32844, 11), - newPosition = Position(33459, 32848, 11), -} - -local leverTarbaz = Action() + boss = { + name = "Tarbaz", + position = Position(33459, 32844, 11), + }, -function leverTarbaz.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33418, 32849, 11) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Tarbaz", Position(33446, 32833, 11), Position(33515, 32875, 12)) then - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Tarbaz.") - return true - end - end - Game.createMonster("Tarbaz", config.BossPosition, true, true) - for y = 32849, 32853 do - local playerTile = Tile(Position(33418, y, 11)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.TarbazTimer, os.time() + 60 * 60 * 2 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33446, 32833, 11), Position(33515, 32875, 12), Position(33319, 32318, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end + timeToDefeat = 30 * 60, + playerPositions = { + { pos = Position(33418, 32849, 11), teleport = Position(33459, 32848, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33418, 32850, 11), teleport = Position(33459, 32848, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33418, 32851, 11), teleport = Position(33459, 32848, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33418, 32852, 11), teleport = Position(33459, 32848, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33418, 32853, 11), teleport = Position(33459, 32848, 11), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33447, 32832, 11), + to = Position(33473, 32856, 11), + }, + exit = Position(33319, 32318, 13), +} -leverTarbaz:uid(1027) -leverTarbaz:register() +local lever = BossLever(config) +lever:position(Position(33418, 32848, 11)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_zamulosh.lua b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_zamulosh.lua index fc3e34a8219..9c62e19f19c 100644 --- a/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_zamulosh.lua +++ b/data-otservbr-global/scripts/quests/ferumbras_ascension/actions_zamulosh.lua @@ -1,60 +1,33 @@ local config = { - centerRoom = Position(33643, 32756, 11), - BossPosition = Position(33643, 32756, 11), - newPosition = Position(33644, 32760, 11), - zamuloshSummons = { - Position(33642, 32756, 11), - Position(33642, 32756, 11), - Position(33642, 32756, 11), - Position(33644, 32756, 11), - Position(33644, 32756, 11), - Position(33644, 32756, 11), + boss = { + name = "Zamulosh", + position = Position(33643, 32756, 11), }, -} - -local leverZamulosh = Action() -function leverZamulosh.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33680, 32741, 11) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Zamulosh", Position(33634, 32749, 11), Position(33654, 32765, 11)) then - local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) - for i = 1, #specs do - spec = specs[i] - if spec:isPlayer() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Someone is fighting with Zamulosh.") - return true - end - end - Game.createMonster("Zamulosh", config.BossPosition, true, true) - for d = 1, #config.zamuloshSummons do - Game.createMonster("Zamulosh3", config.zamuloshSummons[d], true, true) - end - for y = 32741, 32745 do - local playerTile = Tile(Position(33680, y, 11)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U10_90.FerumbrasAscension.ZamuloshTimer, os.time() + 60 * 60 * 2 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33634, 32749, 11), Position(33654, 32765, 11), Position(33319, 32318, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end + timeToDefeat = 30 * 60, + playerPositions = { + { pos = Position(33680, 32741, 11), teleport = Position(33644, 32760, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 32742, 11), teleport = Position(33644, 32760, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 32743, 11), teleport = Position(33644, 32760, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 32744, 11), teleport = Position(33644, 32760, 11), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 32745, 11), teleport = Position(33644, 32760, 11), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33632, 32747, 11), + to = Position(33654, 32765, 11), + }, + exit = Position(33319, 32318, 13), +} - return true -end +local zamuloshSummons = { + Position(33642, 32756, 11), + Position(33642, 32756, 11), + Position(33642, 32756, 11), + Position(33644, 32756, 11), + Position(33644, 32756, 11), + Position(33644, 32756, 11), +} -leverZamulosh:uid(1026) -leverZamulosh:register() +local lever = BossLever(config) +lever:position(Position(33680, 32740, 11)) +lever:register() From 69e3b155010eed640b3b821a89f9772e7592223d Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:36:18 -0300 Subject: [PATCH 07/18] fix: forgotten knowledge quest bosses (#3298) --- .../actions_dragonking_zyrtarch.lua | 76 ++++++---------- .../actions_frozen_horror.lua | 8 +- .../actions_lady_tenebris.lua | 65 ++++++-------- .../forgotten_knowledge/actions_lloyd.lua | 74 ++++++--------- .../actions_the_last_lore_keeper.lua | 89 +++++++++---------- .../actions_the_thorn_knight.lua | 67 ++++++-------- .../actions_the_time_guardian.lua | 68 +++++--------- 7 files changed, 174 insertions(+), 273 deletions(-) diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_dragonking_zyrtarch.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_dragonking_zyrtarch.lua index 426177864b2..99585188b91 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_dragonking_zyrtarch.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_dragonking_zyrtarch.lua @@ -1,52 +1,30 @@ local config = { - bossPosition = Position(33357, 31182, 10), - newPosition = Position(33359, 31186, 10), - soulPosition = Position(33359, 31182, 12), + boss = { + name = "soul of dragonking zyrtarch", + position = Position(33359, 31182, 12), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33391, 31178, 10), teleport = Position(33359, 31186, 10) }, + { pos = Position(33391, 31179, 10), teleport = Position(33359, 31186, 10) }, + { pos = Position(33391, 31180, 10), teleport = Position(33359, 31186, 10) }, + { pos = Position(33391, 31181, 10), teleport = Position(33359, 31186, 10) }, + { pos = Position(33391, 31182, 10), teleport = Position(33359, 31186, 10) }, + }, + monsters = { + { name = "soulcatcher", pos = Position(33352, 31187, 10) }, + { name = "soulcatcher", pos = Position(33363, 31187, 10) }, + { name = "soulcatcher", pos = Position(33353, 31176, 10) }, + { name = "soulcatcher", pos = Position(33363, 31176, 10) }, + { name = "dragonking zyrtarch", pos = Position(33357, 31182, 10) }, + }, + specPos = { + from = Position(33348, 31172, 10), + to = Position(33368, 31190, 12), + }, + exit = Position(33407, 31172, 10), } -local monsters = { - { position = Position(33352, 31187, 10) }, - { position = Position(33363, 31187, 10) }, - { position = Position(33353, 31176, 10) }, - { position = Position(33363, 31176, 10) }, -} - -local leverZyrtarch = Action() - -function leverZyrtarch.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33391, 31178, 10) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Dragonking Zyrtarch", Position(33348, 31172, 10), Position(33368, 31190, 12)) then - for d = 1, #monsters do - Game.createMonster("soulcatcher", monsters[d].position, true, true) - end - Game.createMonster("dragonking zyrtarch", config.bossPosition, true, true) - Game.createMonster("soul of dragonking zyrtarch", config.soulPosition, true, true) - for y = 31178, 31182 do - local playerTile = Tile(Position(33391, y, 10)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.DragonkingTimer, os.time() + 20 * 60 * 60) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(33348, 31172, 10), Position(33368, 31190, 12), Position(33407, 31172, 10)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverZyrtarch:position(Position(33391, 31177, 10)) -leverZyrtarch:register() +local lever = BossLever(config) +lever:position(Position(33391, 31177, 10)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_frozen_horror.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_frozen_horror.lua index fc7e5049b6a..c21a5e60f0d 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_frozen_horror.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_frozen_horror.lua @@ -21,7 +21,7 @@ function leverMeltingFrozenHorror.onUse(player, item, fromPosition, target, toPo end end if item.itemid == 8911 then - if Game.getStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorTimer) >= 1 then + if Game.getStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled) >= 1 then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait a while, recently someone challenge Frozen Horror.") return true end @@ -43,11 +43,11 @@ function leverMeltingFrozenHorror.onUse(player, item, fromPosition, target, toPo playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) playerTile:teleportTo(config.newPosition) playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorTimer, os.stime() + 20 * 60 * 60) + playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled, os.time() + 20 * 60 * 60) end end - Game.setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorTimer, 1) - addEvent(clearForgotten, 30 * 60 * 1000, Position(32264, 31070, 14), Position(32284, 31104, 14), Position(32319, 31091, 14), Storage.Quest.U11_02.ForgottenKnowledge.HorrorTimer) + Game.setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled, 1) + addEvent(clearForgotten, 30 * 60 * 1000, Position(32264, 31070, 14), Position(32284, 31104, 14), Position(32319, 31091, 14), Storage.Quest.U11_02.ForgottenKnowledge.HorrorKilled) item:transform(8912) elseif item.itemid == 8912 then item:transform(8911) diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lady_tenebris.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lady_tenebris.lua index 7f784c4516f..795b3cf2234 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lady_tenebris.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lady_tenebris.lua @@ -1,43 +1,28 @@ local config = { - centerRoom = Position(32912, 31599, 14), - bossPosition = Position(32912, 31599, 14), - newPosition = Position(32911, 31603, 14), + boss = { + name = "Lady Tenebris", + position = Position(32912, 31599, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(32902, 31623, 14), teleport = Position(32911, 31603, 14) }, + { pos = Position(32902, 31624, 14), teleport = Position(32911, 31603, 14) }, + { pos = Position(32902, 31625, 14), teleport = Position(32911, 31603, 14) }, + { pos = Position(32902, 31626, 14), teleport = Position(32911, 31603, 14) }, + { pos = Position(32902, 31627, 14), teleport = Position(32911, 31603, 14) }, + }, + monsters = { + { name = "shadow tentacle", pos = Position(32910, 31599, 14) }, + { name = "shadow tentacle", pos = Position(32912, 31597, 14) }, + { name = "shadow tentacle", pos = Position(32914, 31599, 14) }, + }, + specPos = { + from = Position(32899, 31587, 14), + to = Position(32923, 31612, 14), + }, + exit = Position(32902, 31629, 14), } -local leverLadyTenebris = Action() - -function leverLadyTenebris.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(32902, 31623, 14) then - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Lady Tenebris", Position(32902, 31589, 14), Position(32924, 31610, 14)) then - for d = 1, 6 do - Game.createMonster("shadow tentacle", Position(math.random(32909, 32914), math.random(31596, 31601), 14), true, true) - end - Game.createMonster("lady tenebris", config.bossPosition, true, true) - for y = 31623, 31627 do - local playerTile = Tile(Position(32902, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.LadyTenebrisTimer, os.time() + 20 * 60 * 60) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(32902, 31589, 14), Position(32924, 31610, 14), Position(32919, 31639, 14)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverLadyTenebris:position(Position(32902, 31622, 14)) -leverLadyTenebris:register() +local lever = BossLever(config) +lever:position(Position(32902, 31622, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lloyd.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lloyd.lua index 2a6a48b84c6..7a2fa1d0a86 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lloyd.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_lloyd.lua @@ -1,51 +1,29 @@ local config = { - centerRoom = Position(32799, 32832, 14), - bossPosition = Position(32799, 32827, 14), - newPosition = Position(32800, 32831, 14), + boss = { + name = "Lloyd", + position = Position(32799, 32827, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(32759, 32868, 14), teleport = Position(32800, 32831, 14) }, + { pos = Position(32759, 32869, 14), teleport = Position(32800, 32831, 14) }, + { pos = Position(32759, 32870, 14), teleport = Position(32800, 32831, 14) }, + { pos = Position(32759, 32871, 14), teleport = Position(32800, 32831, 14) }, + { pos = Position(32759, 32872, 14), teleport = Position(32800, 32831, 14) }, + }, + monsters = { + { name = "cosmic energy prism a invu", pos = Position(32801, 32827, 14) }, + { name = "cosmic energy prism b invu", pos = Position(32798, 32827, 14) }, + { name = "cosmic energy prism c invu", pos = Position(32803, 32826, 14) }, + { name = "cosmic energy prism d invu", pos = Position(32796, 32826, 14) }, + }, + specPos = { + from = Position(32785, 32813, 14), + to = Position(32812, 32838, 14), + }, + exit = Position(32815, 32873, 13), } -local monsters = { - { cosmic = "cosmic energy prism a", pos = Position(32801, 32827, 14) }, - { cosmic = "cosmic energy prism b", pos = Position(32798, 32827, 14) }, - { cosmic = "cosmic energy prism c", pos = Position(32803, 32826, 14) }, - { cosmic = "cosmic energy prism d", pos = Position(32796, 32826, 14) }, -} - -local leverLloyd = Action() - -function leverLloyd.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(32759, 32868, 14) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom(player:getId(), "Lloyd", Position(32785, 32814, 14), Position(32812, 32838, 14)) then - for n = 1, #monsters do - Game.createMonster(monsters[n].cosmic, monsters[n].pos, true, true) - end - Game.createMonster("lloyd", config.bossPosition, true, true) - for y = 32868, 32872 do - local playerTile = Tile(Position(32759, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.LloydTimer, os.time() + 20 * 60 * 60) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(32785, 32814, 14), Position(32812, 32838, 14), Position(32815, 32873, 13)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverLloyd:position(Position(32759, 32867, 14)) -leverLloyd:register() +local lever = BossLever(config) +lever:position(Position(32759, 32867, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_last_lore_keeper.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_last_lore_keeper.lua index aa704ba6435..d14d9b88d73 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_last_lore_keeper.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_last_lore_keeper.lua @@ -1,51 +1,44 @@ local config = { - { newPosition = Position(31985, 32851, 14) }, - { pos = Position(31986, 32840, 14), monster = "a shielded astral glyph" }, - { pos = Position(31975, 32856, 15), monster = "bound astral power" }, - { pos = Position(31987, 32839, 14), monster = "the astral source" }, - { pos = Position(31986, 32823, 15), monster = "the distorted astral source" }, - { pos = Position(31989, 32823, 15), monster = "an astral glyph" }, + boss = { + name = "The Last Lore Keeper", + position = Position(31987, 32839, 14), + }, + timeToFightAgain = ParseDuration("14d") / 1000, + timeToDefeat = ParseDuration("17m") / 1000, + requiredLevel = 250, + playerPositions = { + { pos = Position(32018, 32844, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32019, 32844, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32020, 32844, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32018, 32845, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32019, 32845, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32020, 32845, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32018, 32846, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32019, 32846, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32020, 32846, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32018, 32847, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32019, 32847, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32020, 32847, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32018, 32848, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32019, 32848, 14), teleport = Position(31984, 32851, 14) }, + { pos = Position(32020, 32848, 14), teleport = Position(31984, 32851, 14) }, + }, + monsters = { + { name = "bound astral power", pos = Position(31973, 32840, 15) }, + { name = "bound astral power", pos = Position(31973, 32856, 15) }, + { name = "bound astral power", pos = Position(31989, 32856, 15) }, + { name = "bound astral power", pos = Position(31989, 32840, 15) }, + { name = "a shielded astral glyph", pos = Position(31986, 32840, 14) }, + { name = "the distorted astral source", pos = Position(31986, 32823, 15) }, + { name = "an astral glyph", pos = Position(31989, 32823, 15) }, + }, + specPos = { + from = Position(31968, 32821, 14), + to = Position(32004, 32865, 15), + }, + exit = Position(32035, 32859, 14), } -local leverLoreKeeper = Action() - -function leverLoreKeeper.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(32019, 32844, 14) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("The Last Lorekeeper", Position(31968, 32821, 14), Position(32004, 32865, 15)) then - for x = 32018, 32020 do - for y = 32844, 32848 do - local playerTile = Tile(Position(x, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config[1].newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.LastLoreTimer, os.time() + 60 * 60 * 14 * 24) - table.insert(playersTable, playerTile:getId()) - end - end - end - for b = 2, #config do - Game.createMonster(config[b].monster, config[b].pos, true, true) - end - Game.setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.AstralPowerCounter, 1) - Game.setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.AstralGlyph, 0) - player:say("The Astral Glyph begins to draw upon bound astral power to expel you from the room!", TALKTYPE_MONSTER_SAY) - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(31968, 32821, 14), Position(32004, 32865, 15), Position(32035, 32859, 14)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - - return true -end - -leverLoreKeeper:position(Position(32019, 32843, 14)) -leverLoreKeeper:register() +local lever = BossLever(config) +lever:position(Position(32019, 32843, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_thorn_knight.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_thorn_knight.lua index 16b22300ea1..b48a07e44e1 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_thorn_knight.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_thorn_knight.lua @@ -1,43 +1,30 @@ local config = { - centerRoom = Position(32624, 32880, 14), - bossPosition = Position(32624, 32880, 14), - newPosition = Position(32624, 32886, 14), -} - -local leverThornKnight = Action() - -function leverThornKnight.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(32657, 32877, 14) then - item:transform(8912) - return true + boss = { + name = "The Enraged Thorn Knight", + createFunction = function() + return Game.createMonster("Mounted Thorn Knight", Position(32624, 32880, 14), true, true) + end, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(32657, 32877, 14), teleport = Position(32624, 32886, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(32657, 32878, 14), teleport = Position(32624, 32886, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(32657, 32879, 14), teleport = Position(32624, 32886, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(32657, 32880, 14), teleport = Position(32624, 32886, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(32657, 32881, 14), teleport = Position(32624, 32886, 14), effect = CONST_ME_TELEPORT }, + }, + onUseExtra = function(player) + for d = 1, 6 do + Game.createMonster("possessed tree", Position(math.random(32619, 32629), math.random(32877, 32884), 14), true, true) end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("Thorn Knight", Position(32613, 32869, 14), Position(32636, 32892, 14)) then - for d = 1, 6 do - Game.createMonster("possessed tree", Position(math.random(32619, 32629), math.random(32877, 32884), 14), true, true) - end - Game.createMonster("mounted thorn knight", config.bossPosition, true, true) - for y = 32877, 32881 do - local playerTile = Tile(Position(32657, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.ThornKnightTimer, os.stime() + 20 * 60 * 60) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(32613, 32869, 14), Position(32636, 32892, 14), Position(32678, 32888, 14)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - return true -end + end, + specPos = { + from = Position(32613, 32869, 14), + to = Position(32636, 32892, 14), + }, + exit = Position(32678, 32888, 14), +} -leverThornKnight:position(Position(32657, 32876, 14)) -leverThornKnight:register() +local lever = BossLever(config) +lever:position(Position(32657, 32876, 14)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_time_guardian.lua b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_time_guardian.lua index 75dcd0da028..386bce7d94d 100644 --- a/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_time_guardian.lua +++ b/data-otservbr-global/scripts/quests/forgotten_knowledge/actions_the_time_guardian.lua @@ -1,47 +1,27 @@ local config = { - centerRoom = Position(32977, 31662, 14), - newPosition = Position(32977, 31667, 14), + boss = { + name = "The Time Guardian", + position = Position(32977, 31662, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33010, 31660, 14), teleport = Position(32977, 31667, 14) }, + { pos = Position(33010, 31661, 14), teleport = Position(32977, 31667, 14) }, + { pos = Position(33010, 31662, 14), teleport = Position(32977, 31667, 14) }, + { pos = Position(33010, 31663, 14), teleport = Position(32977, 31667, 14) }, + { pos = Position(33010, 31664, 14), teleport = Position(32977, 31667, 14) }, + }, + monsters = { + { name = "The Freezing Time Guardian", pos = Position(32975, 31664, 13) }, + { name = "The Blazing Time Guardian", pos = Position(32980, 31664, 13) }, + }, + specPos = { + from = Position(32967, 31654, 14), + to = Position(32989, 31677, 14), + }, + exit = Position(32870, 32724, 14), } -local bosses = { - { bossPosition = Position(32977, 31662, 14), bossName = "The Time Guardian" }, - { bossPosition = Position(32975, 31664, 13), bossName = "The Freezing Time Guardian" }, - { bossPosition = Position(32980, 31664, 13), bossName = "The Blazing Time Guardian" }, -} - -local leverTimeGuardian = Action() - -function leverTimeGuardian.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item.itemid == 8911 then - if player:getPosition() ~= Position(33010, 31660, 14) then - item:transform(8912) - return true - end - end - if item.itemid == 8911 then - local playersTable = {} - if player:doCheckBossRoom("The Time Guardian", Position(32967, 31654, 13), Position(32989, 31677, 14)) then - for q = 1, #bosses do - Game.createMonster(bosses[q].bossName, bosses[q].bossPosition, true, true) - end - for y = 31660, 31664 do - local playerTile = Tile(Position(33010, y, 14)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(Storage.Quest.U11_02.ForgottenKnowledge.TimeGuardianTimer, os.time() + 20 * 60 * 60) - table.insert(playersTable, playerTile:getId()) - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, Position(32967, 31654, 13), Position(32989, 31677, 14), Position(32870, 32724, 14)) - item:transform(8912) - end - elseif item.itemid == 8912 then - item:transform(8911) - end - return true -end - -leverTimeGuardian:position(Position(33010, 31659, 14)) -leverTimeGuardian:register() +local lever = BossLever(config) +lever:position(Position(33010, 31659, 14)) +lever:register() From 6e5a1c34484ffd933fc1a144cecf5e5ab9eac089 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:43:46 -0300 Subject: [PATCH 08/18] fix: grave danger quest bosses (#3299) --- .../actions/bosses_levers/king_zelos.lua | 28 ----- .../actions_azaram_fight.lua | 28 ----- ...c_fight.lua => actions_baeloc_nictros.lua} | 0 .../actions_count_vlarkorth_.lua} | 2 +- .../grave_danger_quest/actions_duke_fight.lua | 107 ------------------ .../grave_danger_quest/actions_duke_krule.lua | 23 ++++ .../grave_danger_quest/actions_earl_fight.lua | 24 ---- .../grave_danger_quest/actions_earl_osam.lua} | 2 +- .../grave_danger_quest/actions_king_zelos.lua | 99 ++++------------ .../actions_lord_azaram.lua} | 2 +- .../actions_vlarkorth_fight.lua | 24 ---- ...lua => creaturescripts_baeloc_nictros.lua} | 0 ...ua => creaturescripts_count_vlarkorth.lua} | 0 ...ight.lua => creaturescripts_earl_osam.lua} | 0 ...ght.lua => creaturescripts_king_zelos.lua} | 0 ...ht.lua => creaturescripts_lord_azaram.lua} | 0 data-otservbr-global/startup/tables/lever.lua | 25 ---- 17 files changed, 50 insertions(+), 314 deletions(-) delete mode 100644 data-otservbr-global/scripts/actions/bosses_levers/king_zelos.lua delete mode 100644 data-otservbr-global/scripts/quests/grave_danger_quest/actions_azaram_fight.lua rename data-otservbr-global/scripts/quests/grave_danger_quest/{actions_baeloc_fight.lua => actions_baeloc_nictros.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/count_vlarkorth.lua => quests/grave_danger_quest/actions_count_vlarkorth_.lua} (94%) delete mode 100644 data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_fight.lua create mode 100644 data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_krule.lua delete mode 100644 data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_fight.lua rename data-otservbr-global/scripts/{actions/bosses_levers/earl_osam.lua => quests/grave_danger_quest/actions_earl_osam.lua} (94%) rename data-otservbr-global/scripts/{actions/bosses_levers/lord_azaram.lua => quests/grave_danger_quest/actions_lord_azaram.lua} (94%) delete mode 100644 data-otservbr-global/scripts/quests/grave_danger_quest/actions_vlarkorth_fight.lua rename data-otservbr-global/scripts/quests/grave_danger_quest/{creaturescripts_baeloc_nictros_fight.lua => creaturescripts_baeloc_nictros.lua} (100%) rename data-otservbr-global/scripts/quests/grave_danger_quest/{creaturescripts_count_vlarkorth_fight.lua => creaturescripts_count_vlarkorth.lua} (100%) rename data-otservbr-global/scripts/quests/grave_danger_quest/{creaturescripts_earl_osam_fight.lua => creaturescripts_earl_osam.lua} (100%) rename data-otservbr-global/scripts/quests/grave_danger_quest/{creaturescripts_king_zelos_fight.lua => creaturescripts_king_zelos.lua} (100%) rename data-otservbr-global/scripts/quests/grave_danger_quest/{creaturescripts_lord_azaram_fight.lua => creaturescripts_lord_azaram.lua} (100%) diff --git a/data-otservbr-global/scripts/actions/bosses_levers/king_zelos.lua b/data-otservbr-global/scripts/actions/bosses_levers/king_zelos.lua deleted file mode 100644 index aa14e575107..00000000000 --- a/data-otservbr-global/scripts/actions/bosses_levers/king_zelos.lua +++ /dev/null @@ -1,28 +0,0 @@ -local config = { - boss = { - name = "King Zelos", - position = Position(33443, 31545, 13), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33485, 31546, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33485, 31547, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33485, 31548, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33485, 31545, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33485, 31544, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33486, 31546, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33486, 31547, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33486, 31548, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33486, 31545, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33486, 31544, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33433, 31535, 13), - to = Position(33453, 31555, 13), - }, - exit = Position(32172, 31918, 8), -} - -local lever = BossLever(config) -lever:position({ x = 33484, y = 31546, z = 13 }) -lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_azaram_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_azaram_fight.lua deleted file mode 100644 index 14e479f6fe3..00000000000 --- a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_azaram_fight.lua +++ /dev/null @@ -1,28 +0,0 @@ -local config = { - boss = { - name = "Lord Azaram", - position = Position(33424, 31472, 13), - }, - timeAfterKill = 30 * 60, - playerPositions = { - { pos = Position(33422, 31493, 13), teleport = Position(33424, 31478, 13) }, - { pos = Position(33423, 31493, 13), teleport = Position(33424, 31478, 13) }, - { pos = Position(33424, 31493, 13), teleport = Position(33424, 31478, 13) }, - { pos = Position(33425, 31493, 13), teleport = Position(33424, 31478, 13) }, - { pos = Position(33426, 31493, 13), teleport = Position(33424, 31478, 13) }, - }, - specPos = { - from = Position(33414, 31463, 13), - to = Position(33433, 31481, 13), - }, - monsters = { - { name = "Condensed Sin", pos = Position(33426, 31471, 13) }, - { name = "Condensed Sin", pos = Position(33422, 31471, 13) }, - }, - exit = Position(32190, 31819, 8), - exitTeleporter = Position(32192, 31819, 8), -} - -local lever = BossLever(config) -lever:aid(14561) -lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_baeloc_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_baeloc_nictros.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/actions_baeloc_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/actions_baeloc_nictros.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/count_vlarkorth.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_count_vlarkorth_.lua similarity index 94% rename from data-otservbr-global/scripts/actions/bosses_levers/count_vlarkorth.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/actions_count_vlarkorth_.lua index 184d5fa6eca..ddb769917d5 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/count_vlarkorth.lua +++ b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_count_vlarkorth_.lua @@ -19,5 +19,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 33454, y = 31413, z = 13 }) +lever:position(Position(33454, 31413, 13)) lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_fight.lua deleted file mode 100644 index 283547db05e..00000000000 --- a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_fight.lua +++ /dev/null @@ -1,107 +0,0 @@ -local config = { - boss = { - name = "Duke Krule", - createFunction = function() - local boss = Game.createMonster("Duke Krule", Position(33456, 31473, 13), true, true) - boss:setStorageValue(1, os.time()) - return boss - end, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33455, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33456, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33457, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33458, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, - { pos = Position(33459, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33447, 31464, 13), - to = Position(33464, 31481, 13), - }, - exit = Position(32347, 32167, 12), -} - -local duke_water = Combat() -duke_water:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_ICETORNADO) -duke_water:setArea(createCombatArea(AREA_CIRCLE3X3)) - -function onTargetTile(cid, pos) - local tile = Tile(pos) - local target = tile:getTopCreature() - if tile then - if target and target:isPlayer() and target:getOutfit().lookType == 49 then - doTargetCombatHealth(0, target, COMBAT_ICEDAMAGE, -1500, -2000) - end - end -end - -duke_water:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile") - -local duke_fire = Combat() -duke_fire:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HITBYFIRE) -duke_fire:setArea(createCombatArea(AREA_CIRCLE3X3)) - -function onTargetTile(cid, pos) - local tile = Tile(pos) - local target = tile:getTopCreature() - if tile then - if target and target:isPlayer() and target:getOutfit().lookType == 286 then - doTargetCombatHealth(0, target, COMBAT_FIREDAMAGE, -1500, -2000) - end - end -end - -duke_fire:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile") - -config.onUseExtra = function() - local config = { - centerRoom = Position(33456, 31472, 13), - x = 10, - y = 10, - transformCD = Storage.Quest.U12_20.GraveDanger.Bosses.DukeKrule.TransformCD, - } - local function hitArea(creature) - local player = Player(creature) - - if player then - if player:getStorageValue(config.transformCD) <= os.time() then - if player:getOutfit().lookType == 49 then - local var = { type = 1, number = creature } - duke_fire:execute(player, var) - player:setStorageValue(config.transformCD, os.time() + 3) - addEvent(hitArea, 3 * 1000, creature) - elseif player:getOutfit().lookType == 286 then - local var = { type = 1, number = creature } - duke_water:execute(player, var) - player:setStorageValue(config.transformCD, os.time() + 3) - addEvent(hitArea, 3 * 1000, creature) - end - end - end - - return true - end - - local function transformPlayers(id) - local spectators = Game.getSpectators(config.centerRoom, false, true, config.x, config.x, config.y, config.y) - local form = { 49, 286 } - local boss = Creature("Duke Krule") - - if boss and boss:getStorageValue(1) == id then - if #spectators > 0 then - for _, player in pairs(spectators) do - doSetCreatureOutfit(player, { lookType = form[math.random(#form)] }, 30 * 1000) - addEvent(hitArea, 3 * 1000, player:getId()) - end - addEvent(transformPlayers, 36 * 1000, id) - end - end - return true - end - addEvent(transformPlayers, 30 * 1000, os.time()) -end - -local lever = BossLever(config) -lever:position({ x = 33454, y = 31493, z = 13 }) -lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_krule.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_krule.lua new file mode 100644 index 00000000000..5828099813b --- /dev/null +++ b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_duke_krule.lua @@ -0,0 +1,23 @@ +local config = { + boss = { + name = "Duke Krule", + position = Position(33456, 31473, 13), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33455, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33456, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33457, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33458, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33459, 31493, 13), teleport = Position(33455, 31464, 13), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33447, 31464, 13), + to = Position(33464, 31481, 13), + }, + exit = Position(32347, 32167, 12), +} + +local lever = BossLever(config) +lever:position(Position(33454, 31493, 13)) +lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_fight.lua deleted file mode 100644 index 0d40c7d8593..00000000000 --- a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_fight.lua +++ /dev/null @@ -1,24 +0,0 @@ -local config = { - boss = { - name = "Earl Osam", - position = Position(33488, 31438, 13), - }, - timeAfterKill = 30 * 60, - playerPositions = { - { pos = Position(33516, 31444, 13), teleport = Position(33489, 31441, 13) }, - { pos = Position(33517, 31444, 13), teleport = Position(33489, 31441, 13) }, - { pos = Position(33518, 31444, 13), teleport = Position(33489, 31441, 13) }, - { pos = Position(33519, 31444, 13), teleport = Position(33489, 31441, 13) }, - { pos = Position(33520, 31444, 13), teleport = Position(33489, 31441, 13) }, - }, - specPos = { - from = Position(33479, 31429, 13), - to = Position(33497, 31447, 13), - }, - exit = Position(33261, 31985, 8), - exitTeleporter = Position(33263, 31985, 8), -} - -local lever = BossLever(config) -lever:aid(14558) -lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/earl_osam.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_osam.lua similarity index 94% rename from data-otservbr-global/scripts/actions/bosses_levers/earl_osam.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_osam.lua index 363e3b2ba55..86ee236cf21 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/earl_osam.lua +++ b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_earl_osam.lua @@ -19,5 +19,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 33515, y = 31444, z = 13 }) +lever:position(Position(33515, 31444, 13)) lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_king_zelos.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_king_zelos.lua index f1c571de7f8..c3ce9126309 100644 --- a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_king_zelos.lua +++ b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_king_zelos.lua @@ -1,79 +1,28 @@ local config = { - centerRoom = Position(33443, 31545, 13), - newPosition = Position(33436, 31572, 13), - exitPos = Position(32172, 31917, 8), - x = 30, - y = 30, - summons = { - { - name = "Rewar The Bloody", - pos = Position(33463, 31562, 13), - }, - { - name = "The Red Knight", - pos = Position(33423, 31562, 13), - }, - { - name = "Magnor Mournbringer", - pos = Position(33463, 31529, 13), - }, - { - name = "Nargol the Impaler", - pos = Position(33423, 31529, 13), - }, - { - name = "King Zelos", - pos = Position(33443, 31545, 13), - }, + boss = { + name = "King Zelos", + position = Position(33443, 31545, 13), }, - timer = Storage.Quest.U12_20.GraveDanger.Bosses.KingZelos.Timer, - room = Storage.Quest.U12_20.GraveDanger.Bosses.KingZelos.Room, - fromPos = Position(33414, 31520, 13), - toPos = Position(33474, 31574, 13), + requiredLevel = 250, + playerPositions = { + { pos = Position(33485, 31546, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33485, 31547, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33485, 31548, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33485, 31545, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33485, 31544, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33486, 31546, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33486, 31547, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33486, 31548, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33486, 31545, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + { pos = Position(33486, 31544, 13), teleport = Position(33443, 31554, 13), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33433, 31535, 13), + to = Position(33453, 31555, 13), + }, + exit = Position(32172, 31918, 8), } -local king_zelos = Action() - -function king_zelos.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if not player:doCheckBossRoom("King Zelos", config.fromPos, config.toPos) then - player:sendCancelMessage("The room is already in use. Please wait.") - return true - end - - local spectators = Game.getSpectators(config.centerRoom, false, true, config.x, config.x, config.y, config.y) - - if player:getPosition() ~= Position(33485, 31546, 13) then - player:sendCancelMessage("Sorry, not possible.") - return true - end - - if #spectators > 0 then - player:say("The room is occupied by another team, please wait.", TALKTYPE_MONSTER_SAY, false, player) - return true - end - - for _, boss in pairs(config.summons) do - Game.createMonster(boss.name, boss.pos, false, true) - end - - for x = 33485, 33486 do - for y = 31544, 31548 do - local playerTile = Tile(Position(x, y, 13)):getTopCreature() - if playerTile and playerTile:isPlayer() then - playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) - playerTile:teleportTo(config.newPosition) - playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - playerTile:setStorageValue(config.timer, os.time() + 20 * 3600) - playerTile:setStorageValue(config.room, os.time() + 24 * 60) - playerTile:say("You have 24 minutes to kill and loot this boss. Otherwise you will lose that chance and will be kicked out.", TALKTYPE_MONSTER_SAY, false, playerTile) - end - end - end - - addEvent(clearForgotten, 24 * 60 * 1000, config.centerRoom, config.x, config.y, config.exitPos, config.room) - - return true -end - -king_zelos:aid(14568) -king_zelos:register() +local lever = BossLever(config) +lever:position(Position(33484, 31546, 13)) +lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/lord_azaram.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_lord_azaram.lua similarity index 94% rename from data-otservbr-global/scripts/actions/bosses_levers/lord_azaram.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/actions_lord_azaram.lua index 28a9369bc55..0613441b47c 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/lord_azaram.lua +++ b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_lord_azaram.lua @@ -19,5 +19,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 33421, y = 31493, z = 13 }) +lever:position(Position(33421, 31493, 13)) lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_vlarkorth_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/actions_vlarkorth_fight.lua deleted file mode 100644 index 86711ac8382..00000000000 --- a/data-otservbr-global/scripts/quests/grave_danger_quest/actions_vlarkorth_fight.lua +++ /dev/null @@ -1,24 +0,0 @@ -local config = { - boss = { - name = "Count Vlarkorth", - position = Position(33456, 31437, 13), - }, - timeAfterKill = 30 * 60, - playerPositions = { - { pos = Position(33455, 31413, 13), teleport = Position(33457, 31442, 13) }, - { pos = Position(33456, 31413, 13), teleport = Position(33457, 31442, 13) }, - { pos = Position(33457, 31413, 13), teleport = Position(33457, 31442, 13) }, - { pos = Position(33458, 31413, 13), teleport = Position(33457, 31442, 13) }, - { pos = Position(33459, 31413, 13), teleport = Position(33457, 31442, 13) }, - }, - specPos = { - from = Position(33451, 31432, 13), - to = Position(33461, 31442, 13), - }, - exit = Position(33195, 31696, 8), - exitTeleporter = Position(33456, 31446, 13), -} - -local lever = BossLever(config) -lever:aid(14557) -lever:register() diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_baeloc_nictros_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_baeloc_nictros.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_baeloc_nictros_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_baeloc_nictros.lua diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_count_vlarkorth_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_count_vlarkorth.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_count_vlarkorth_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_count_vlarkorth.lua diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_earl_osam_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_earl_osam.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_earl_osam_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_earl_osam.lua diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_king_zelos_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_king_zelos.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_king_zelos_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_king_zelos.lua diff --git a/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_lord_azaram_fight.lua b/data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_lord_azaram.lua similarity index 100% rename from data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_lord_azaram_fight.lua rename to data-otservbr-global/scripts/quests/grave_danger_quest/creaturescripts_lord_azaram.lua diff --git a/data-otservbr-global/startup/tables/lever.lua b/data-otservbr-global/startup/tables/lever.lua index bcf98109646..ab887209866 100644 --- a/data-otservbr-global/startup/tables/lever.lua +++ b/data-otservbr-global/startup/tables/lever.lua @@ -129,31 +129,6 @@ LeverAction = { { x = 32576, y = 31862, z = 14 }, }, }, - -- Grave Danger Quest - [14557] = { - itemId = 8911, - itemPos = { - { x = 33454, y = 31413, z = 13 }, - }, - }, - [14558] = { - itemId = 8911, - itemPos = { - { x = 33515, y = 31444, z = 13 }, - }, - }, - [14561] = { - itemId = 8911, - itemPos = { - { x = 33421, y = 31493, z = 13 }, - }, - }, - [14568] = { - itemId = 8911, - itemPos = { - { x = 33484, y = 31546, z = 13 }, - }, - }, -- Forgotten Knowledge Quest [26663] = { itemId = 9125, From 08a35ac68c3052877e8eca193dd6f317cefda8f3 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:52:37 -0300 Subject: [PATCH 09/18] fix: heart of destruction quest bosses (#3300) --- .../heart_of_destruction/actions_anomaly.lua} | 2 +- .../heart_of_destruction/actions_eradicator.lua} | 2 +- .../heart_of_destruction/actions_foreshock.lua} | 2 +- .../heart_of_destruction/actions_outburst.lua} | 2 +- .../heart_of_destruction/actions_rupture.lua} | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename data-otservbr-global/scripts/{actions/bosses_levers/anomaly.lua => quests/heart_of_destruction/actions_anomaly.lua} (97%) rename data-otservbr-global/scripts/{actions/bosses_levers/eradicator.lua => quests/heart_of_destruction/actions_eradicator.lua} (97%) rename data-otservbr-global/scripts/{actions/bosses_levers/foreshock.lua => quests/heart_of_destruction/actions_foreshock.lua} (97%) rename data-otservbr-global/scripts/{actions/bosses_levers/outburst.lua => quests/heart_of_destruction/actions_outburst.lua} (97%) rename data-otservbr-global/scripts/{actions/bosses_levers/rupture.lua => quests/heart_of_destruction/actions_rupture.lua} (97%) diff --git a/data-otservbr-global/scripts/actions/bosses_levers/anomaly.lua b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_anomaly.lua similarity index 97% rename from data-otservbr-global/scripts/actions/bosses_levers/anomaly.lua rename to data-otservbr-global/scripts/quests/heart_of_destruction/actions_anomaly.lua index 3cac20d9624..817abefc960 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/anomaly.lua +++ b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_anomaly.lua @@ -35,5 +35,5 @@ local config = { } local lever = BossLever(config) -lever:aid(14325) +lever:position(Position(32245, 31244, 14)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/eradicator.lua b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_eradicator.lua similarity index 97% rename from data-otservbr-global/scripts/actions/bosses_levers/eradicator.lua rename to data-otservbr-global/scripts/quests/heart_of_destruction/actions_eradicator.lua index a4d88c31c72..6bf1eefbcab 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/eradicator.lua +++ b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_eradicator.lua @@ -41,5 +41,5 @@ local config = { } local lever = BossLever(config) -lever:aid(14330) +lever:position(Position(32334, 31283, 14)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/foreshock.lua b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_foreshock.lua similarity index 97% rename from data-otservbr-global/scripts/actions/bosses_levers/foreshock.lua rename to data-otservbr-global/scripts/quests/heart_of_destruction/actions_foreshock.lua index 0bf9034d93b..8c62ab48710 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/foreshock.lua +++ b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_foreshock.lua @@ -38,5 +38,5 @@ local config = { } local lever = BossLever(config) -lever:aid(14329) +lever:position(Position(32182, 31243, 14)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/outburst.lua b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_outburst.lua similarity index 97% rename from data-otservbr-global/scripts/actions/bosses_levers/outburst.lua rename to data-otservbr-global/scripts/quests/heart_of_destruction/actions_outburst.lua index 6e377900bde..3c1ad8bd0c1 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/outburst.lua +++ b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_outburst.lua @@ -37,5 +37,5 @@ local config = { } local lever = BossLever(config) -lever:aid(14331) +lever:position(Position(32207, 31283, 14)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rupture.lua b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_rupture.lua similarity index 97% rename from data-otservbr-global/scripts/actions/bosses_levers/rupture.lua rename to data-otservbr-global/scripts/quests/heart_of_destruction/actions_rupture.lua index ecb892cef8e..506a5afe93f 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/rupture.lua +++ b/data-otservbr-global/scripts/quests/heart_of_destruction/actions_rupture.lua @@ -37,5 +37,5 @@ local config = { } local lever = BossLever(config) -lever:aid(14327) +lever:position(Position(32309, 31247, 14)) lever:register() From 0121d79b0b387dfa491c961b83e517858dabb71b Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:01:13 -0300 Subject: [PATCH 10/18] fix: the secret library quest bosses (#3301) --- .../{ => bosses}/lokathmor.lua | 0 .../{ => bosses}/mazzinor.lua | 0 .../actions/bosses_levers/gorzindel.lua | 23 --- .../library_area/actions_bossesLever.lua | 167 ------------------ .../library_area/actions_ghulosh.lua} | 5 +- .../library_area/actions_gorzindel.lua | 38 ++++ .../library_area/actions_lokathmor.lua} | 8 +- .../library_area/actions_mazzinor.lua} | 8 +- .../actions_the_scourge_of_oblivion.lua} | 2 +- 9 files changed, 57 insertions(+), 194 deletions(-) rename data-otservbr-global/monster/quests/the_secret_library/{ => bosses}/lokathmor.lua (100%) rename data-otservbr-global/monster/quests/the_secret_library/{ => bosses}/mazzinor.lua (100%) delete mode 100644 data-otservbr-global/scripts/actions/bosses_levers/gorzindel.lua delete mode 100644 data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_bossesLever.lua rename data-otservbr-global/scripts/{actions/bosses_levers/ghulosh.lua => quests/the_secret_library_quest/library_area/actions_ghulosh.lua} (86%) create mode 100644 data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_gorzindel.lua rename data-otservbr-global/scripts/{actions/bosses_levers/lokathmor.lua => quests/the_secret_library_quest/library_area/actions_lokathmor.lua} (72%) rename data-otservbr-global/scripts/{actions/bosses_levers/mazzinor.lua => quests/the_secret_library_quest/library_area/actions_mazzinor.lua} (72%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_scourge_of_oblivion.lua => quests/the_secret_library_quest/library_area/actions_the_scourge_of_oblivion.lua} (96%) diff --git a/data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/lokathmor.lua similarity index 100% rename from data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua rename to data-otservbr-global/monster/quests/the_secret_library/bosses/lokathmor.lua diff --git a/data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/mazzinor.lua similarity index 100% rename from data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua rename to data-otservbr-global/monster/quests/the_secret_library/bosses/mazzinor.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/gorzindel.lua b/data-otservbr-global/scripts/actions/bosses_levers/gorzindel.lua deleted file mode 100644 index 2cfe4ffb399..00000000000 --- a/data-otservbr-global/scripts/actions/bosses_levers/gorzindel.lua +++ /dev/null @@ -1,23 +0,0 @@ -local config = { - boss = { - name = "Gorzindel", - position = Position(32687, 32715, 10), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(32747, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, - { pos = Position(32748, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, - { pos = Position(32749, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, - { pos = Position(32750, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, - { pos = Position(32751, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(32680, 32711, 10), - to = Position(32695, 32726, 10), - }, - exit = Position(32660, 32734, 12), -} - -local lever = BossLever(config) -lever:position({ x = 32746, y = 32749, z = 10 }) -lever:register() diff --git a/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_bossesLever.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_bossesLever.lua deleted file mode 100644 index 6f579ea8e07..00000000000 --- a/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_bossesLever.lua +++ /dev/null @@ -1,167 +0,0 @@ -local mazzinorSummons = { - name = "Wild Knowledge", - eventName = "mazzinorDeath", - middlePosition = Position(32724, 32720, 10), - timing = 25, - positions = { - [1] = Position(32719, 32718, 10), - [2] = Position(32723, 32719, 10), - [3] = Position(32728, 32718, 10), - [4] = Position(32724, 32724, 10), - }, -} - -local ghuloshSummons = { - name = "Bone Jaw", - eventName = "", - middlePosition = Position(32756, 32721, 10), - timing = 25, - positions = { - [1] = Position(32755, 32721, 10), - }, -} - -local gorzindelSummons = { - name = "Mean Minion", - name2 = "Malicious Minion", - eventName = "", - middlePosition = Position(32687, 32719, 10), - timing = 25, - positions = { - [1] = Position(32687, 32717, 10), - }, - positions2 = { - [1] = Position(32687, 32720, 10), - }, - tomesPosition = { - [1] = { name = "stolen knowledge of armor", position = Position(32687, 32707, 10) }, - [2] = { name = "stolen knowledge of summoning", position = Position(32698, 32715, 10) }, - [3] = { name = "stolen knowledge of lifesteal", position = Position(32693, 32729, 10) }, - [4] = { name = "stolen knowledge of spells", position = Position(32681, 32729, 10) }, - [5] = { name = "stolen knowledge of healing", position = Position(32676, 32715, 10) }, - }, -} - -local lokathmorSummons = { - name = "Knowledge Raider", - eventName = "", - middlePosition = Position(32751, 32689, 10), - timing = 25, - positions = { - [1] = Position(32747, 32684, 10), - [2] = Position(32755, 32684, 10), - [3] = Position(32755, 32694, 10), - [4] = Position(32747, 32694, 10), - }, -} - -local bossNames = { "mazzinor", "supercharged mazzinor", "lokathmor", "ghulosh", "ghuloshz' deathgaze", "gorzindel", "stolen tome of portals" } - -local function spawnSummons(k, monsterName, eventName, timing, positionTable, middlePosition, isGorzindel) - local spectators = Game.getSpectators(middlePosition, false, false, 12, 12, 12, 12) - local hasPlayer = false - - for _, c in pairs(spectators) do - if c and c:isPlayer() then - hasPlayer = true - end - end - - if isGorzindel then - local hasTome = false - for _, c in pairs(spectators) do - for i = 1, #gorzindelSummons.tomesPosition do - if c and (c:getName():lower() == gorzindelSummons.tomesPosition[i].name) then - hasTome = true - end - end - end - if not hasTome then - return false - end - end - if hasPlayer then - if k <= 4 then - for i = 1, #positionTable do - local sqm = positionTable[i] - if sqm then - sqm:sendMagicEffect(CONST_ME_TELEPORT) - end - end - k = k + 1 - addEvent(spawnSummons, 2 * 1000, k, monsterName, eventName, timing, positionTable, middlePosition, isGorzindel) - else - for i = 1, #positionTable do - local monster = Game.createMonster(monsterName, positionTable[i]) - if monster then - monster:registerEvent(eventName) - end - end - addEvent(function() - spawnSummons(1, monsterName, eventName, timing, positionTable, middlePosition, isGorzindel) - end, timing * 1000) - end - end -end - -local leverInfo = { - [1] = { bossName = "Mazzinor", storage = Storage.Quest.U11_80.TheSecretLibrary.Library.MazzinorTimer, exit = Position(32616, 32532, 13), position = Position(32720, 32773, 10), type = "x", bossPosition = Position(32724, 32720, 10), teleportTo = Position(32724, 32726, 10), fromPosition = Position(32715, 32712, 10), toPosition = Position(32733, 32729, 10) }, - [2] = { bossName = "Lokathmor", storage = Storage.Quest.U11_80.TheSecretLibrary.Library.LokathmorTimer, exit = Position(32467, 32654, 12), position = Position(32720, 32749, 10), type = "x", bossPosition = Position(32751, 32689, 10), teleportTo = Position(32750, 32694, 10), fromPosition = Position(32741, 32680, 10), toPosition = Position(32759, 32697, 10) }, - [3] = { bossName = "Ghulosh", storage = Storage.Quest.U11_80.TheSecretLibrary.Library.GhuloshTimer, exit = Position(32659, 32713, 13), position = Position(32746, 32773, 10), type = "x", bossPosition = Position(32756, 32721, 10), teleportTo = Position(32755, 32727, 10), fromPosition = Position(32745, 32711, 10), toPosition = Position(32768, 32730, 10) }, - [4] = { bossName = "Gorzindel", storage = Storage.Quest.U11_80.TheSecretLibrary.Library.GorzindelTimer, exit = Position(32660, 32734, 12), position = Position(32746, 32749, 10), type = "x", bossPosition = Position(32685, 32717, 10), teleportTo = Position(32687, 32724, 10), fromPosition = Position(32671, 32703, 10), toPosition = Position(32702, 32734, 10) }, -} - -local actions_library_bossesLever = Action() - -function actions_library_bossesLever.onUse(player, item, fromPosition, itemEx, toPosition) - local playersTable = {} - - for _, lever in pairs(leverInfo) do - if toPosition == lever.position then - if player:doCheckBossRoom(lever.bossName, lever.fromPosition, lever.toPosition) then - if lever.type == "x" then - local startPos = lever.position.x + 1 - for x = startPos, startPos + 4 do - local sqm = Tile(Position(x, lever.position.y, lever.position.z)) - if sqm then - local c = sqm:getTopCreature() - if c and c:isPlayer() then - table.insert(playersTable, c:getId()) - c:teleportTo(lever.teleportTo) - c:setStorageValue(lever.storage, os.time() + 20 * 60 * 60) - end - end - end - end - - local monster = Game.createMonster(lever.bossName, lever.bossPosition) - - if monster then - if lever.bossName:lower() == "mazzinor" then - addEvent(spawnSummons, 4 * 1000, 1, mazzinorSummons.name, mazzinorSummons.eventName, mazzinorSummons.timing, mazzinorSummons.positions, mazzinorSummons.middlePosition, false) - elseif lever.bossName:lower() == "lokathmor" then - addEvent(spawnSummons, 4 * 1000, 1, lokathmorSummons.name, lokathmorSummons.eventName, lokathmorSummons.timing, lokathmorSummons.positions, lokathmorSummons.middlePosition, false) - elseif lever.bossName:lower() == "ghulosh" then - addEvent(spawnSummons, 4 * 1000, 1, ghuloshSummons.name, ghuloshSummons.eventName, ghuloshSummons.timing, ghuloshSummons.positions, ghuloshSummons.middlePosition, false) - local book = Game.createMonster("The Book of Death", Position(32755, 32716, 10)) - Game.setStorageValue(Storage.Quest.U11_80.TheSecretLibrary.Library.Ghulosh, 1) - elseif lever.bossName:lower() == "gorzindel" then - addEvent(spawnSummons, 4 * 1000, 1, gorzindelSummons.name, gorzindelSummons.eventName, gorzindelSummons.timing, gorzindelSummons.positions, gorzindelSummons.middlePosition, true) - addEvent(spawnSummons, 4 * 1000, 1, gorzindelSummons.name2, gorzindelSummons.eventName, gorzindelSummons.timing, gorzindelSummons.positions2, gorzindelSummons.middlePosition, true) - local tome = Game.createMonster("Stolen Tome of Portals", Position(32688, 32715, 10)) - for _, k in pairs(gorzindelSummons.tomesPosition) do - local monster = Game.createMonster(k.name, k.position) - local minion = Game.createMonster("Malicious Minion", k.position) - end - end - end - addEvent(kickPlayersAfterTime, 30 * 60 * 1000, playersTable, lever.fromPosition, lever.toPosition, lever.exit) - end - end - end - - return true -end - -actions_library_bossesLever:aid(4950) -actions_library_bossesLever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/ghulosh.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_ghulosh.lua similarity index 86% rename from data-otservbr-global/scripts/actions/bosses_levers/ghulosh.lua rename to data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_ghulosh.lua index 48fb4c17818..4f618c76d7b 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/ghulosh.lua +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_ghulosh.lua @@ -11,6 +11,9 @@ local config = { { pos = Position(32750, 32773, 10), teleport = Position(32757, 32727, 10), effect = CONST_ME_TELEPORT }, { pos = Position(32751, 32773, 10), teleport = Position(32757, 32727, 10), effect = CONST_ME_TELEPORT }, }, + monsters = { + { name = "the book of death", pos = Position(32756, 32718, 10) }, + }, specPos = { from = Position(32748, 32713, 10), to = Position(32763, 32729, 10), @@ -19,5 +22,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 32746, y = 32773, z = 10 }) +lever:position(Position(32746, 32773, 10)) lever:register() diff --git a/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_gorzindel.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_gorzindel.lua new file mode 100644 index 00000000000..8ab1e568feb --- /dev/null +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_gorzindel.lua @@ -0,0 +1,38 @@ +local config = { + boss = { + name = "Gorzindel", + position = Position(32687, 32715, 10), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(32747, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, + { pos = Position(32748, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, + { pos = Position(32749, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, + { pos = Position(32750, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, + { pos = Position(32751, 32749, 10), teleport = Position(32686, 32721, 10), effect = CONST_ME_TELEPORT }, + }, + monsters = { + { name = "mean minion", pos = Position(32687, 32717, 10) }, + { name = "malicious minion", pos = Position(32687, 32720, 10) }, + { name = "malicious minion", pos = Position(32687, 32708, 10) }, + { name = "malicious minion", pos = Position(32698, 32716, 10) }, + { name = "malicious minion", pos = Position(32693, 32730, 10) }, + { name = "malicious minion", pos = Position(32681, 32730, 10) }, + { name = "malicious minion", pos = Position(32676, 32716, 10) }, + { name = "stolen knowledge of armor", pos = Position(32687, 32707, 10) }, + { name = "stolen knowledge of summoning", pos = Position(32698, 32715, 10) }, + { name = "stolen knowledge of lifesteal", pos = Position(32693, 32729, 10) }, + { name = "stolen knowledge of spells", pos = Position(32681, 32729, 10) }, + { name = "stolen knowledge of healing", pos = Position(32676, 32715, 10) }, + { name = "stolen tome of portals", pos = Position(32688, 32715, 10) }, + }, + specPos = { + from = Position(32680, 32711, 10), + to = Position(32695, 32726, 10), + }, + exit = Position(32660, 32734, 12), +} + +local lever = BossLever(config) +lever:position(Position(32746, 32749, 10)) +lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/lokathmor.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_lokathmor.lua similarity index 72% rename from data-otservbr-global/scripts/actions/bosses_levers/lokathmor.lua rename to data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_lokathmor.lua index 5a56c186ee9..3855eb515ee 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/lokathmor.lua +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_lokathmor.lua @@ -11,6 +11,12 @@ local config = { { pos = Position(32724, 32749, 10), teleport = Position(32751, 32685, 10), effect = CONST_ME_TELEPORT }, { pos = Position(32725, 32749, 10), teleport = Position(32751, 32685, 10), effect = CONST_ME_TELEPORT }, }, + monsters = { + { name = "knowledge raider", pos = Position(32747, 32684, 10) }, + { name = "knowledge raider", pos = Position(32755, 32684, 10) }, + { name = "knowledge raider", pos = Position(32755, 32694, 10) }, + { name = "knowledge raider", pos = Position(32747, 32694, 10) }, + }, specPos = { from = Position(32742, 32681, 10), to = Position(32758, 32696, 10), @@ -19,5 +25,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 32720, y = 32749, z = 10 }) +lever:position(Position(32720, 32749, 10)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/mazzinor.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_mazzinor.lua similarity index 72% rename from data-otservbr-global/scripts/actions/bosses_levers/mazzinor.lua rename to data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_mazzinor.lua index 2472b5634ac..765c04ea08a 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/mazzinor.lua +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_mazzinor.lua @@ -11,6 +11,12 @@ local config = { { pos = Position(32724, 32773, 10), teleport = Position(32726, 32726, 10), effect = CONST_ME_TELEPORT }, { pos = Position(32725, 32773, 10), teleport = Position(32726, 32726, 10), effect = CONST_ME_TELEPORT }, }, + monsters = { + { name = "wild knowledge", pos = Position(32719, 32718, 10) }, + { name = "wild knowledge", pos = Position(32723, 32719, 10) }, + { name = "wild knowledge", pos = Position(32728, 32718, 10) }, + { name = "wild knowledge", pos = Position(32724, 32724, 10) }, + }, specPos = { from = Position(32716, 32713, 10), to = Position(32732, 32728, 10), @@ -19,5 +25,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 32720, y = 32773, z = 10 }) +lever:position(Position(32720, 32773, 10)) lever:register() diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_scourge_of_oblivion.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_the_scourge_of_oblivion.lua similarity index 96% rename from data-otservbr-global/scripts/actions/bosses_levers/the_scourge_of_oblivion.lua rename to data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_the_scourge_of_oblivion.lua index f7373fbe49b..2e4a9b19df6 100644 --- a/data-otservbr-global/scripts/actions/bosses_levers/the_scourge_of_oblivion.lua +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/library_area/actions_the_scourge_of_oblivion.lua @@ -24,5 +24,5 @@ local config = { } local lever = BossLever(config) -lever:position({ x = 32675, y = 32743, z = 11 }) +lever:position(Position(32675, 32743, 11)) lever:register() From 7f0bfccc9b5706e89169cde51d349cb3d4ace919 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:03:32 -0300 Subject: [PATCH 11/18] fix: move rotten blood quest files to quest folder (#3303) --- .../rotten_blood_quest/actions_bakragore.lua} | 0 .../rotten_blood_quest/actions_chagorz.lua} | 0 .../rotten_blood_quest/actions_ichgahal.lua} | 0 .../rotten_blood_quest/actions_murcion.lua} | 0 .../rotten_blood_quest/actions_sacrifice.lua} | 0 .../rotten_blood_quest/actions_vemiath.lua} | 0 .../rotten_blood_quest/creaturescripts_bosses_killed.lua} | 0 .../rotten_blood_quest/movements_blood_entrance.lua} | 0 .../rotten_blood_quest/movements_entrances.lua} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename data-otservbr-global/scripts/{actions/bosses_levers/rotten_bakragore.lua => quests/rotten_blood_quest/actions_bakragore.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/rotten_chagorz.lua => quests/rotten_blood_quest/actions_chagorz.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/rotten_ichgahal.lua => quests/rotten_blood_quest/actions_ichgahal.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/rotten_murcion.lua => quests/rotten_blood_quest/actions_murcion.lua} (100%) rename data-otservbr-global/scripts/{actions/quests/rotten_blood/sacrifice.lua => quests/rotten_blood_quest/actions_sacrifice.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/rotten_vemiath.lua => quests/rotten_blood_quest/actions_vemiath.lua} (100%) rename data-otservbr-global/scripts/{actions/quests/rotten_blood/bosses_killed.lua => quests/rotten_blood_quest/creaturescripts_bosses_killed.lua} (100%) rename data-otservbr-global/scripts/{actions/quests/rotten_blood/blood_entrance.lua => quests/rotten_blood_quest/movements_blood_entrance.lua} (100%) rename data-otservbr-global/scripts/{actions/quests/rotten_blood/entrances.lua => quests/rotten_blood_quest/movements_entrances.lua} (100%) diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rotten_bakragore.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_bakragore.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/rotten_bakragore.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_bakragore.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rotten_chagorz.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_chagorz.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/rotten_chagorz.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_chagorz.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rotten_ichgahal.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_ichgahal.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/rotten_ichgahal.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_ichgahal.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rotten_murcion.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_murcion.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/rotten_murcion.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_murcion.lua diff --git a/data-otservbr-global/scripts/actions/quests/rotten_blood/sacrifice.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_sacrifice.lua similarity index 100% rename from data-otservbr-global/scripts/actions/quests/rotten_blood/sacrifice.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_sacrifice.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/rotten_vemiath.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/actions_vemiath.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/rotten_vemiath.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/actions_vemiath.lua diff --git a/data-otservbr-global/scripts/actions/quests/rotten_blood/bosses_killed.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/creaturescripts_bosses_killed.lua similarity index 100% rename from data-otservbr-global/scripts/actions/quests/rotten_blood/bosses_killed.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/creaturescripts_bosses_killed.lua diff --git a/data-otservbr-global/scripts/actions/quests/rotten_blood/blood_entrance.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/movements_blood_entrance.lua similarity index 100% rename from data-otservbr-global/scripts/actions/quests/rotten_blood/blood_entrance.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/movements_blood_entrance.lua diff --git a/data-otservbr-global/scripts/actions/quests/rotten_blood/entrances.lua b/data-otservbr-global/scripts/quests/rotten_blood_quest/movements_entrances.lua similarity index 100% rename from data-otservbr-global/scripts/actions/quests/rotten_blood/entrances.lua rename to data-otservbr-global/scripts/quests/rotten_blood_quest/movements_entrances.lua From 2ffb075d96e731b1607a51ca1629c98a5fb02474 Mon Sep 17 00:00:00 2001 From: Majesty <32709570+majestyotbr@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:31:14 -0300 Subject: [PATCH 12/18] fix: move bosses levers to quests folders (#3305) --- .../a_pirates_tail/actions_ratmiral_blackwhiskers.lua} | 0 .../a_pirates_tail/actions_tentuglys_head.lua} | 0 .../ahau.lua => quests/adventures_of_galthen/actions_ahau.lua} | 0 .../adventures_of_galthen/actions_megasylvan_yselda.lua} | 0 .../bosses_levers => quests/cradle_of_monsters}/the_monster.lua | 0 .../feaster_of_souls/actions_the_dread_maiden.lua} | 0 .../feaster_of_souls/actions_the_fear_feaster.lua} | 0 .../feaster_of_souls/actions_the_pale_worm.lua} | 0 .../feaster_of_souls/actions_the_unwelcome.lua} | 0 .../bosses_levers => quests/marapur}/timira_the_many-headed.lua | 0 .../bosses_levers => quests/primal_ordeal_quest}/magma_bubble.lua | 0 .../primal_ordeal_quest/the_primal_menace.lua} | 0 .../the_dream_courts_quest/actions_the_nightmare_beast.lua} | 0 .../too_hot_to_handle_quest}/the_brainstealer.lua | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename data-otservbr-global/scripts/{actions/bosses_levers/ratmiral_blackwhiskers.lua => quests/a_pirates_tail/actions_ratmiral_blackwhiskers.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/tentuglys_head.lua => quests/a_pirates_tail/actions_tentuglys_head.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/ahau.lua => quests/adventures_of_galthen/actions_ahau.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/megasylvan_yselda.lua => quests/adventures_of_galthen/actions_megasylvan_yselda.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers => quests/cradle_of_monsters}/the_monster.lua (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_dread_maiden.lua => quests/feaster_of_souls/actions_the_dread_maiden.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_fear_feaster.lua => quests/feaster_of_souls/actions_the_fear_feaster.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_pale_worm.lua => quests/feaster_of_souls/actions_the_pale_worm.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_unwelcome.lua => quests/feaster_of_souls/actions_the_unwelcome.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers => quests/marapur}/timira_the_many-headed.lua (100%) rename data-otservbr-global/scripts/{actions/bosses_levers => quests/primal_ordeal_quest}/magma_bubble.lua (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_primal_manace.lua => quests/primal_ordeal_quest/the_primal_menace.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers/the_nightmare_beast.lua => quests/the_dream_courts_quest/actions_the_nightmare_beast.lua} (100%) rename data-otservbr-global/scripts/{actions/bosses_levers => quests/too_hot_to_handle_quest}/the_brainstealer.lua (100%) diff --git a/data-otservbr-global/scripts/actions/bosses_levers/ratmiral_blackwhiskers.lua b/data-otservbr-global/scripts/quests/a_pirates_tail/actions_ratmiral_blackwhiskers.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/ratmiral_blackwhiskers.lua rename to data-otservbr-global/scripts/quests/a_pirates_tail/actions_ratmiral_blackwhiskers.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/tentuglys_head.lua b/data-otservbr-global/scripts/quests/a_pirates_tail/actions_tentuglys_head.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/tentuglys_head.lua rename to data-otservbr-global/scripts/quests/a_pirates_tail/actions_tentuglys_head.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/ahau.lua b/data-otservbr-global/scripts/quests/adventures_of_galthen/actions_ahau.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/ahau.lua rename to data-otservbr-global/scripts/quests/adventures_of_galthen/actions_ahau.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/megasylvan_yselda.lua b/data-otservbr-global/scripts/quests/adventures_of_galthen/actions_megasylvan_yselda.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/megasylvan_yselda.lua rename to data-otservbr-global/scripts/quests/adventures_of_galthen/actions_megasylvan_yselda.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_monster.lua b/data-otservbr-global/scripts/quests/cradle_of_monsters/the_monster.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_monster.lua rename to data-otservbr-global/scripts/quests/cradle_of_monsters/the_monster.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_dread_maiden.lua b/data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_dread_maiden.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_dread_maiden.lua rename to data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_dread_maiden.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_fear_feaster.lua b/data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_fear_feaster.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_fear_feaster.lua rename to data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_fear_feaster.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_pale_worm.lua b/data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_pale_worm.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_pale_worm.lua rename to data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_pale_worm.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_unwelcome.lua b/data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_unwelcome.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_unwelcome.lua rename to data-otservbr-global/scripts/quests/feaster_of_souls/actions_the_unwelcome.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/timira_the_many-headed.lua b/data-otservbr-global/scripts/quests/marapur/timira_the_many-headed.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/timira_the_many-headed.lua rename to data-otservbr-global/scripts/quests/marapur/timira_the_many-headed.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/magma_bubble.lua b/data-otservbr-global/scripts/quests/primal_ordeal_quest/magma_bubble.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/magma_bubble.lua rename to data-otservbr-global/scripts/quests/primal_ordeal_quest/magma_bubble.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_primal_manace.lua b/data-otservbr-global/scripts/quests/primal_ordeal_quest/the_primal_menace.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_primal_manace.lua rename to data-otservbr-global/scripts/quests/primal_ordeal_quest/the_primal_menace.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_nightmare_beast.lua b/data-otservbr-global/scripts/quests/the_dream_courts_quest/actions_the_nightmare_beast.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_nightmare_beast.lua rename to data-otservbr-global/scripts/quests/the_dream_courts_quest/actions_the_nightmare_beast.lua diff --git a/data-otservbr-global/scripts/actions/bosses_levers/the_brainstealer.lua b/data-otservbr-global/scripts/quests/too_hot_to_handle_quest/the_brainstealer.lua similarity index 100% rename from data-otservbr-global/scripts/actions/bosses_levers/the_brainstealer.lua rename to data-otservbr-global/scripts/quests/too_hot_to_handle_quest/the_brainstealer.lua From 6e7f1a9125d9e24e410e195bc6b826c0045be981 Mon Sep 17 00:00:00 2001 From: aphirotx Date: Wed, 29 Jan 2025 22:37:59 +0100 Subject: [PATCH 13/18] fix: werecrocodile raceid (#3308) --- data-otservbr-global/monster/lycanthropes/werecrocodile.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/monster/lycanthropes/werecrocodile.lua b/data-otservbr-global/monster/lycanthropes/werecrocodile.lua index 125c25799c0..0d598a21413 100644 --- a/data-otservbr-global/monster/lycanthropes/werecrocodile.lua +++ b/data-otservbr-global/monster/lycanthropes/werecrocodile.lua @@ -13,7 +13,7 @@ monster.outfit = { lookMount = 0, } -monster.raceId = 2403 +monster.raceId = 2388 monster.Bestiary = { class = "Lycanthrope", race = BESTY_RACE_LYCANTHROPE, From 304656677dac994ce2784b9b5042f8c763806e93 Mon Sep 17 00:00:00 2001 From: Jonyrewind Date: Sat, 1 Feb 2025 18:28:14 +0100 Subject: [PATCH 14/18] fix: grand master oberon immunity and butterfly's raceid (#3307) --- .../quests/the_explorer_society/blue_butterfly.lua | 2 +- .../quests/the_explorer_society/yellow_butterfly.lua | 2 +- .../the_secret_library/bosses/grand_master_oberon.lua | 1 - data-otservbr-global/monster/vermins/butterfly.lua | 4 ++-- .../the_secret_library_quest/creaturescripts_kill.lua | 10 ---------- 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/data-otservbr-global/monster/quests/the_explorer_society/blue_butterfly.lua b/data-otservbr-global/monster/quests/the_explorer_society/blue_butterfly.lua index 3893adff8c4..bf2e1f56136 100644 --- a/data-otservbr-global/monster/quests/the_explorer_society/blue_butterfly.lua +++ b/data-otservbr-global/monster/quests/the_explorer_society/blue_butterfly.lua @@ -14,7 +14,7 @@ monster.outfit = { lookMount = 0, } -monster.raceId = 213 +monster.raceId = 227 monster.Bestiary = { class = "Vermin", race = BESTY_RACE_VERMIN, diff --git a/data-otservbr-global/monster/quests/the_explorer_society/yellow_butterfly.lua b/data-otservbr-global/monster/quests/the_explorer_society/yellow_butterfly.lua index b5e88d7f102..834130574f3 100644 --- a/data-otservbr-global/monster/quests/the_explorer_society/yellow_butterfly.lua +++ b/data-otservbr-global/monster/quests/the_explorer_society/yellow_butterfly.lua @@ -14,7 +14,7 @@ monster.outfit = { lookMount = 0, } -monster.raceId = 227 +monster.raceId = 235 monster.Bestiary = { class = "Vermin", race = BESTY_RACE_VERMIN, diff --git a/data-otservbr-global/monster/quests/the_secret_library/bosses/grand_master_oberon.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/grand_master_oberon.lua index 116555f7c4a..ce86aa47861 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/bosses/grand_master_oberon.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/bosses/grand_master_oberon.lua @@ -27,7 +27,6 @@ monster.manaCost = 0 monster.events = { "killingLibrary", - "oberonImmune", } monster.changeTarget = { diff --git a/data-otservbr-global/monster/vermins/butterfly.lua b/data-otservbr-global/monster/vermins/butterfly.lua index 9ea18cb070f..89bcbca5815 100644 --- a/data-otservbr-global/monster/vermins/butterfly.lua +++ b/data-otservbr-global/monster/vermins/butterfly.lua @@ -13,7 +13,7 @@ monster.outfit = { lookMount = 0, } -monster.raceId = 213 +monster.raceId = 227 monster.Bestiary = { class = "Vermin", race = BESTY_RACE_VERMIN, @@ -31,7 +31,7 @@ monster.Bestiary = { monster.health = 2 monster.maxHealth = 2 monster.race = "venom" -monster.corpse = 4378 +monster.corpse = 4993 monster.speed = 160 monster.manaCost = 0 diff --git a/data-otservbr-global/scripts/quests/the_secret_library_quest/creaturescripts_kill.lua b/data-otservbr-global/scripts/quests/the_secret_library_quest/creaturescripts_kill.lua index 5a3bde3b049..c7e88237022 100644 --- a/data-otservbr-global/scripts/quests/the_secret_library_quest/creaturescripts_kill.lua +++ b/data-otservbr-global/scripts/quests/the_secret_library_quest/creaturescripts_kill.lua @@ -45,13 +45,3 @@ function creaturescripts_library_bosses.onDeath(creature, corpse, killer, mostDa end creaturescripts_library_bosses:register() - -local creaturescripts_library_bosses_oberon = CreatureEvent("oberonImmune") - -function creaturescripts_library_bosses_oberon.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) - primaryDamage = 0 - secondaryDamage = 0 - return primaryDamage, primaryType, secondaryDamage, secondaryType -end - -creaturescripts_library_bosses_oberon:register() From 2a5a0e74d49338254af9cb79f01e01930dbfb719 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Sun, 2 Feb 2025 21:49:47 -0300 Subject: [PATCH 15/18] fix: imbuement slot validation to prevent duplicate applications (#3316) --- src/creatures/players/player.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index d55cb8f5022..399dbeb28e3 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -2294,6 +2294,13 @@ void Player::onApplyImbuement(const Imbuement* imbuement, const std::shared_ptr< return; } + auto itemSlots = item->getImbuementSlot(); + if (slot >= itemSlots) { + g_logger().error("[Player::onApplyImbuement] - Player {} attempted to apply imbuement in an invalid slot ({})", this->getName(), slot); + this->sendImbuementResult("Invalid slot selection."); + return; + } + ImbuementInfo imbuementInfo; if (item->getImbuementInfo(slot, &imbuementInfo)) { g_logger().error("[Player::onApplyImbuement] - An error occurred while player with name {} try to apply imbuement, item already contains imbuement", this->getName()); @@ -2301,6 +2308,21 @@ void Player::onApplyImbuement(const Imbuement* imbuement, const std::shared_ptr< return; } + for (uint8_t i = 0; i < item->getImbuementSlot(); i++) { + if (i == slot) { + continue; + } + + ImbuementInfo existingImbuement; + if (item->getImbuementInfo(i, &existingImbuement) && existingImbuement.imbuement) { + if (existingImbuement.imbuement->getName() == imbuement->getName()) { + g_logger().error("[Player::onApplyImbuement] - Player {} attempted to apply the same imbuement in multiple slots", this->getName()); + this->sendImbuementResult("You cannot apply the same imbuement in multiple slots."); + return; + } + } + } + const auto &items = imbuement->getItems(); for (auto &[key, value] : items) { const ItemType &itemType = Item::items[key]; From 8157e52e1cabdcca5f03ce61280631c83fc6055d Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 6 Feb 2025 15:57:13 -0300 Subject: [PATCH 16/18] fix: set db version to last migration version (#3319) --- schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema.sql b/schema.sql index 9d8f3522f69..10efc5dce00 100644 --- a/schema.sql +++ b/schema.sql @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `server_config` ( CONSTRAINT `server_config_pk` PRIMARY KEY (`config`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '48'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); +INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '49'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); -- Table structure `accounts` CREATE TABLE IF NOT EXISTS `accounts` ( From 95cd92cdb5f43329f282715af115a9428283a358 Mon Sep 17 00:00:00 2001 From: "Leilani A." <168607226+kaleohanopahala@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:03:30 -0300 Subject: [PATCH 17/18] fix: add missing exit action on morguthis tomb (#3327) --- .../quests/the_ancient_tombs/action_morguthis_wall.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data-otservbr-global/scripts/quests/the_ancient_tombs/action_morguthis_wall.lua b/data-otservbr-global/scripts/quests/the_ancient_tombs/action_morguthis_wall.lua index 420a2f3fbc2..811efdd4b33 100644 --- a/data-otservbr-global/scripts/quests/the_ancient_tombs/action_morguthis_wall.lua +++ b/data-otservbr-global/scripts/quests/the_ancient_tombs/action_morguthis_wall.lua @@ -14,7 +14,7 @@ function morguthisWall.onUse(player, item, fromPosition, target, toPosition) wall:remove() else local creatures = tile:getCreatures() - if creatures then + if #creatures > 0 then for _, creature in ipairs(creatures) do local newPosition = Position(wallPosition.x, wallPosition.y + 1, wallPosition.z) creature:teleportTo(newPosition) @@ -22,7 +22,7 @@ function morguthisWall.onUse(player, item, fromPosition, target, toPosition) end local items = tile:getItems() - if items then + if #items > 0 then for _, tileItem in ipairs(items) do local newPosition = Position(wallPosition.x, wallPosition.y + 1, wallPosition.z) tileItem:moveTo(newPosition) @@ -36,4 +36,5 @@ function morguthisWall.onUse(player, item, fromPosition, target, toPosition) end morguthisWall:position(Position(33212, 32693, 13)) +morguthisWall:position(Position(33209, 32701, 13)) morguthisWall:register() From a17306668feaea5562213fa2ea39cbd4897a4503 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 6 Feb 2025 16:25:19 -0300 Subject: [PATCH 18/18] refactor: soulcore removal logic (#3326) --- data-otservbr-global/lib/others/soulpit.lua | 27 +++++++++++-------- .../quests/soulpit/ondroploot_soul_core.lua | 22 +++++++-------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/data-otservbr-global/lib/others/soulpit.lua b/data-otservbr-global/lib/others/soulpit.lua index b677b10fd9c..33d615ce92e 100644 --- a/data-otservbr-global/lib/others/soulpit.lua +++ b/data-otservbr-global/lib/others/soulpit.lua @@ -153,20 +153,25 @@ SoulPit = { return name:match("^(.-) soul core") end, onFuseSoulCores = function(player, item, target) - local itemName = item:getName() - local targetItemName = target:getName() + local itemCount = item:getCount(item:getId()) + if item:getId() == target:getId() and itemCount <= 1 then + return false + end - if SoulPit.getSoulCoreMonster(itemName) and SoulPit.getSoulCoreMonster(targetItemName) then - local randomSoulCore = SoulPit.soulCores[math.random(#SoulPit.soulCores)] - player:addItem(randomSoulCore:getId(), 1) - player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have received a %s soul core.", randomSoulCore:getName())) - item:remove(1) - target:remove(1) - return true + local itemSoulCore = SoulPit.getSoulCoreMonster(item:getName()) + local targetSoulCore = SoulPit.getSoulCoreMonster(target:getName()) + if not itemSoulCore or not targetSoulCore then + return false end - return false + local randomSoulCore = SoulPit.soulCores[math.random(#SoulPit.soulCores)] + player:addItem(randomSoulCore:getId(), 1) + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have received a %s soul core.", randomSoulCore:getName())) + + item:remove(1) + target:remove(1) + return true end, } diff --git a/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua b/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua index 9ddb479c117..beac3b3b9e2 100644 --- a/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua +++ b/data-otservbr-global/scripts/quests/soulpit/ondroploot_soul_core.lua @@ -4,23 +4,24 @@ function callback.monsterOnDropLoot(monster, corpse) if not monster or not corpse then return end + local player = Player(corpse:getCorpseOwner()) if not player or not player:canReceiveLoot() then return end + if monster:getMonsterForgeClassification() ~= FORGE_FIENDISH_MONSTER then return end - local soulCoreId = nil local trySameMonsterSoulCore = math.random(100) <= SoulPit.SoulCoresConfiguration.chanceToGetSameMonsterSoulCore local mType = monster:getType() local lootTable = {} if math.random(100) < SoulPit.SoulCoresConfiguration.chanceToDropSoulCore then + local soulCoreId if trySameMonsterSoulCore then - local itemName = monster:getName():lower() .. " soul core" - soulCoreId = getItemIdByName(itemName) + soulCoreId = getItemIdByName(string.format("%s soul core", monster:getName():lower())) end if not soulCoreId and not trySameMonsterSoulCore then @@ -29,16 +30,13 @@ function callback.monsterOnDropLoot(monster, corpse) if monstersInCategory and #monstersInCategory > 0 then local randomMonster = monstersInCategory[math.random(#monstersInCategory)] - local itemName = randomMonster:name():lower() .. " soul core" - soulCoreId = getItemIdByName(itemName) - logger.info("soulcoreId: " .. soulCoreId) + soulCoreId = getItemIdByName(string.format("%s soul core", randomMonster:name():lower())) end end if soulCoreId then - lootTable[soulCoreId] = { - count = 1, - } + lootTable[soulCoreId] = { count = 1 } + logger.debug("[monsterOnDropLoot.MonsterOnDropLootSoulCore] {} dropped {} for {}.", monster:getName(), ItemType(soulCoreId):getName(), player:getName()) else return {} end @@ -47,11 +45,11 @@ function callback.monsterOnDropLoot(monster, corpse) if math.random(100) < SoulPit.SoulCoresConfiguration.chanceToDropSoulPrism then local soulPrismId = getItemIdByName("soul prism") if soulPrismId then - lootTable[soulPrismId] = { - count = 1, - } + lootTable[soulPrismId] = { count = 1 } + logger.debug("[monsterOnDropLoot.MonsterOnDropLootSoulCore] {} dropped {} for {}.", monster:getName(), ItemType(soulPrismId):getName(), player:getName()) end end + corpse:addLoot(mType:generateLootRoll({}, lootTable, player)) end