Skip to content

Commit

Permalink
feat: soul pit arena/animus mastery/soul core (#3230)
Browse files Browse the repository at this point in the history
SoulPit fighting arena along with Animus Mastery Logic.

---------

Co-authored-by: Pedro Henrique Alves Cruz <[email protected]>
  • Loading branch information
FelipePaluco and phacUFPE authored Jan 28, 2025
1 parent e00ec0d commit 7a51fdb
Show file tree
Hide file tree
Showing 51 changed files with 1,510 additions and 58 deletions.
11 changes: 11 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions data-otservbr-global/lib/others/load.lua
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
dofile(DATA_DIRECTORY .. "/lib/others/dawnport.lua")
dofile(DATA_DIRECTORY .. "/lib/others/soulpit.lua")
174 changes: 174 additions & 0 deletions data-otservbr-global/lib/others/soulpit.lua
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 5 additions & 0 deletions data-otservbr-global/migrations/49.lua
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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()
57 changes: 57 additions & 0 deletions data-otservbr-global/scripts/actions/soulpit/soulpit_entrance.lua
Original file line number Diff line number Diff line change
@@ -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()
92 changes: 92 additions & 0 deletions data-otservbr-global/scripts/quests/soulpit/exalted_core.lua
Original file line number Diff line number Diff line change
@@ -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()
Loading

0 comments on commit 7a51fdb

Please sign in to comment.