diff --git a/data-otservbr-global/lib/others/soulpit.lua b/data-otservbr-global/lib/others/soulpit.lua index 3f17178354a..d9554c2ef3f 100644 --- a/data-otservbr-global/lib/others/soulpit.lua +++ b/data-otservbr-global/lib/others/soulpit.lua @@ -1,65 +1,110 @@ SoulPit = { + SoulCoresConfiguration = { + chanceToGetSameMonsterSoulCore = 30, -- 30% + chanceToDropSoulCore = 50, -- 50% + chanceToGetOminousSoulCore = 5, -- 5% + 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(32371, 31155, 8), teleport = Position(32373, 31138, 8), effect = CONST_ME_TELEPORT }, - { pos = Position(32371, 31156, 8), teleport = Position(32373, 31138, 8), effect = CONST_ME_TELEPORT }, - { pos = Position(32371, 31157, 8), teleport = Position(32373, 31138, 8), effect = CONST_ME_TELEPORT }, - { pos = Position(32371, 31158, 8), teleport = Position(32373, 31138, 8), effect = CONST_ME_TELEPORT }, - { pos = Position(32371, 31159, 8), teleport = Position(32373, 31138, 8), effect = CONST_ME_TELEPORT }, + { + pos = Position(32371, 31155, 8), + teleport = Position(32373, 31138, 8), + effect = CONST_ME_TELEPORT + }, + { + pos = Position(32371, 31156, 8), + teleport = Position(32373, 31138, 8), + effect = CONST_ME_TELEPORT + }, + { + pos = Position(32371, 31157, 8), + teleport = Position(32373, 31138, 8), + effect = CONST_ME_TELEPORT + }, + { + pos = Position(32371, 31158, 8), + teleport = Position(32373, 31138, 8), + effect = CONST_ME_TELEPORT + }, + { + pos = Position(32371, 31159, 8), + teleport = Position(32373, 31138, 8), + effect = CONST_ME_TELEPORT + } }, waves = { [1] = { stacks = { - [1] = 7, - }, + [1] = 7 + } }, [2] = { stacks = { [1] = 4, - [5] = 3, - }, + [5] = 3 + } }, [3] = { stacks = { [1] = 5, - [15] = 2, - }, + [15] = 2 + } }, [4] = { stacks = { [1] = 3, [5] = 3, - [40] = 1, - }, - }, + [40] = 1 + } + } }, effects = { [1] = CONST_ME_TELEPORT, [5] = CONST_ME_ORANGETELEPORT, [15] = CONST_ME_REDTELEPORT, - [40] = CONST_ME_PURPLETELEPORT, + [40] = CONST_ME_PURPLETELEPORT }, possibleAbilities = { "overpowerSoulPit", "enrageSoulPit", - "opressorSoulPit", + "opressorSoulPit" }, bossAbilities = { - ["overpowerSoulPit"] = { + overpowerSoulPit = { player = true, - monster = false, + monster = false }, - ["enrageSoulPit"] = { + enrageSoulPit = { player = false, - monster = true, + monster = true }, - ["opressorSoulPit"] = { + opressorSoulPit = { player = false, - monster = true, - }, + monster = true + } }, timeToKick = 3 * 1000, -- 3 seconds checkMonstersDelay = 4.5 * 1000, -- 4.5 seconds | The check delay should never be less than the timeToSpawnMonsters. diff --git a/data-otservbr-global/scripts/actions/soulpit/soulpit_fight.lua b/data-otservbr-global/scripts/actions/soulpit/soulpit_fight.lua index 0a803e4ec29..d4ba27b4735 100644 --- a/data-otservbr-global/scripts/actions/soulpit/soulpit_fight.lua +++ b/data-otservbr-global/scripts/actions/soulpit/soulpit_fight.lua @@ -153,6 +153,8 @@ function soulPitAction.onUse(player, item, fromPosition, target, toPosition, isH end for _, itemType in pairs(SoulPit.soulCores) do - soulPitAction:id(itemType:getId()) + if itemType:getId() ~= 49164 then -- TO-DO: currently Game.getSoulCoreItems() it's returning soul prism item in the results, we don't want this. + soulPitAction:id(itemType:getId()) + end end soulPitAction:register() diff --git a/data/items/items.xml b/data/items/items.xml index c1b8e8a63ba..46f1c95a9d3 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -79730,5 +79730,9 @@ Granted by TibiaGoals.com"/> + + + + diff --git a/data/scripts/actions/items/soul_prism.lua b/data/scripts/actions/items/soul_prism.lua new file mode 100644 index 00000000000..b4db7df71a9 --- /dev/null +++ b/data/scripts/actions/items/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 = monsterName .. " soul core" + 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 = itemName:match("^(.-) soul core") + + 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:getBestiaryStars() + local nextDifficultyLevel = getNextDifficultyLevel(currentDifficulty) + local nextDifficultyMonsters = nil + + if nextDifficultyLevel then + nextDifficultyMonsters = monsterType:getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[nextDifficultyLevel]) + else + nextDifficultyLevel = currentDifficulty + nextDifficultyMonsters = monsterType:getMonstersByBestiaryStars(SoulPit.SoulCoresConfiguration.monstersDifficulties[currentDifficulty]) + end + + if #nextDifficultyMonsters == 0 then + player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, "No monsters available for the next difficulty level. Please contact an administrator.") + 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. Please contact an administrator.") + 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) + player:removeItem(target:getId(), 1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have received a " .. newMonsterType:getName() .. " soul core.") + end + player:removeItem(item:getId(), 1) + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + return true +end + +soulPrism:id(49164) +soulPrism:register() \ No newline at end of file diff --git a/data/scripts/eventcallbacks/monster/ondroploot_soul_core.lua b/data/scripts/eventcallbacks/monster/ondroploot_soul_core.lua index 41678f28c0e..eafa067bc98 100644 --- a/data/scripts/eventcallbacks/monster/ondroploot_soul_core.lua +++ b/data/scripts/eventcallbacks/monster/ondroploot_soul_core.lua @@ -1,5 +1,4 @@ local callback = EventCallback("MonsterOnDropLootSoulCore") -local soulCores = Game.getSoulCoreItems() function callback.monsterOnDropLoot(monster, corpse) if not monster or not corpse then @@ -14,11 +13,11 @@ function callback.monsterOnDropLoot(monster, corpse) end local soulCoreId = nil - local trySameMonsterSoulCore = math.random() <= 0.3 -- 30% of chance to drop the same monster soul core | WIP: Externalize this to a lib like libs/soulpit.lua + local trySameMonsterSoulCore = math.random(100) <= SoulPit.SoulCoresConfiguration.chanceToGetSameMonsterSoulCore local mType = monster:getType() local lootTable = {} - if math.random() < 0.5 then -- WIP: Externalize this to a lib like libs/soulpit.lua + if math.random(100) < SoulPit.SoulCoresConfiguration.chanceToDropSoulCore then if trySameMonsterSoulCore then local itemName = monster:getName():lower() .. " soul core" soulCoreId = getItemIdByName(itemName) diff --git a/src/lua/functions/creatures/monster/monster_type_functions.cpp b/src/lua/functions/creatures/monster/monster_type_functions.cpp index 3cdd75723b9..86749cfc98d 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.cpp @@ -1896,6 +1896,7 @@ int MonsterTypeFunctions::luaMonsterTypeGetMonstersByBestiaryStars(lua_State* L) int index = 0; for (const auto &monsterType : monstersByStars) { Lua::pushUserdata(L, monsterType); + Lua::setMetatable(L, -1, "MonsterType"); lua_rawseti(L, -2, ++index); } return 1;