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;