From c8efb5484c1e839db50bc3d6f90febb6e3ede656 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 17:18:04 -0300 Subject: [PATCH 01/31] feat: full soul war quest --- .../scripts/lib/quests/soul-war.lua | 1343 +++++++++++++++++ 1 file changed, 1343 insertions(+) create mode 100644 data-otservbr-global/scripts/lib/quests/soul-war.lua diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua new file mode 100644 index 00000000000..ba44d49943f --- /dev/null +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -0,0 +1,1343 @@ +SoulWarQuest = { + -- Item ids + -- Goshnar's Hatred + bagYouDesireItemId = 34109, + goshnarsHatredSorrowId = 33793, + condensedRemorseId = 33792, + -- Goshnar's Spite + weepingSoulCorpseId = 33876, + searingFireId = 33877, + -- Goshnar's Cruelty + pulsatingEnergyId = 34005, + greedyMawId = 33890, + someMortalEssenceId = 33891, + theBloodOfCloakTerrorIds = { 33854, 34006, 34007 }, + -- Goshnar's Megalomania + deadAspectOfPowerCorpseId = 33949, + cleansedSanityItemId = 33950, + necromanticRemainsItemId = 33984, + + poolDamagePercentages = { + [33854] = 0.20, -- 20% of maximum health for the largest pool + [34006] = 0.15, -- 15% for a medium-sized pool + [34007] = 0.10, -- 10% for the smallest pool + }, + + timeToIncreaseCrueltyDefense = 15, -- In seconds, it will increase every 15 seconds if don't use mortal essence in greedy maw + useGreedMawCooldown = 30, -- In seconds + goshnarsCrueltyDefenseChange = 2, -- Defense change, the amount that will decrease or increase defense, the defense cannot decrease more than the monster's original defense amount + goshnarsCrueltyWaveInterval = 7, -- In seconds + + timeToReturnImmuneMegalomania = 70, -- In seconds + + baseBagYouDesireChance = 1, -- 1% base chance + bagYouDesireChancePerTaint = 1, -- Increases 1% per taint + bagYouDesireMonsters = { + "Bony Sea Devil", + "Brachiodemon", + "Branchy Crawler", + "Capricious Phantom", + "Cloak Of Terror", + "Courage Leech", + "Distorted Phantom", + "Druid's Apparition", + "Infernal Demon", + "Infernal Phantom", + "Knight's Apparition", + "Many Faces", + "Mould Phantom", + "Paladin's Apparition", + "Rotten Golem", + "Sorcerer's Apparition", + "Turbulent Elemental", + "Vibrant Phantom.", + }, + bagYouDesireBosses = { + "Goshnar's Cruelty", + "Goshnar's Spite", + "Goshnar's Malice", + "Goshnar's Hatred", + "Goshnar's Greed", + }, + + -- Goshnar's Cruelty pulsating energy monsters + pulsatingEnergyMonsters = { + "Vibrant Phantom", + "Cloak of Terror", + "Courage Leech", + }, + + finalRewards = { + { id = 34082, name = "soulcutter" }, + { id = 34083, name = "soulshredder" }, + { id = 34084, name = "soulbiter" }, + { id = 34085, name = "souleater" }, + { id = 34086, name = "soulcrusher" }, + { id = 34087, name = "soulmaimer" }, + { id = 34088, name = "soulbleeder" }, + { id = 34089, name = "soulpiercer" }, + { id = 34090, name = "soultainter" }, + { id = 34091, name = "soulhexer" }, + { id = 34092, name = "soulshanks" }, + { id = 34093, name = "soulstrider" }, + { id = 34094, name = "soulshell" }, + { id = 34095, name = "soulmantel" }, + { id = 34096, name = "soulshroud" }, + { id = 34097, name = "pair of soulwalkers" }, + { id = 34098, name = "pair of soulstalkers" }, + { id = 34099, name = "soulbastion" }, + }, + + kvSoulWar = KV.scoped("quest"):scoped("soul-war"), + -- Global KV for storage burning change form time + kvBurning = KV.scoped("quest"):scoped("soul-war"):scoped("burning-change-form"), + + rottenWastelandShrines = { + [33019] = { x = 33926, y = 31091, z = 13 }, + [33021] = { x = 33963, y = 31078, z = 13 }, + [33022] = { x = 33970, y = 30988, z = 13 }, + [33024] = { x = 33970, y = 31012, z = 13 }, + }, + + -- Lever room and teleports positions + goshnarsGreedAccessPosition = { from = { x = 33937, y = 31217, z = 11 }, to = { x = 33782, y = 31665, z = 14 } }, + goshnarsHatredAccessPosition = { from = { x = 33914, y = 31032, z = 12 }, to = { x = 33774, y = 31604, z = 14 } }, + -- Teleports from 1st/2nd/3rd floors + goshnarsCrueltyTeleportRoomPositions = { + { from = Position(33889, 31873, 3), to = Position(33830, 31881, 4), access = "first-floor-access", count = 40 }, + { from = Position(33829, 31880, 4), to = Position(33856, 31889, 5), access = "second-floor-access", count = 55 }, + { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, + }, + + -- Levers configuration + levers = { + goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, + goshnarsSpitePosition = { x = 33773, y = 31634, z = 14 }, + goshnarsGreedPosition = { x = 33775, y = 31665, z = 14 }, + goshnarsHatredPosition = { x = 33772, y = 31601, z = 14 }, + goshnarsCrueltyPosition = { x = 33853, y = 31854, z = 6 }, + goshnarsMegalomaniaPosition = { x = 33675, y = 31634, z = 14 }, + + -- Levers system + goshnarsSpite = { + boss = { + name = "Goshnar's Spite", + position = Position(33743, 31632, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33774, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33775, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33776, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33778, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33734, 31624, 14), + to = Position(33751, 31640, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsMalice = { + boss = { + name = "Goshnar's Malice", + position = Position(33709, 31599, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33679, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33681, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33682, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33683, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33699, 31590, 14), + to = Position(33718, 31607, 14), + }, + onUseExtra = function(player) + addEvent(SpawnSoulCage, 23000) + end, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsGreed = { + boss = { + name = "Goshnar's Greed", + position = Position(33746, 31666, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33776, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33778, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33779, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33780, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33737, 31658, 14), + to = Position(33755, 31673, 14), + }, + timeToFightAgain = 0, -- TODO: Remove later + onUseExtra = function() + CreateGoshnarsGreedMonster("Greedbeast", Position(33744, 31666, 14)) + CreateGoshnarsGreedMonster("Soulsnatcher", Position(33747, 31668, 14)) + CreateGoshnarsGreedMonster("Weak Soul", Position(33750, 31666, 14)) + end, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsHatred = { + boss = { + name = "Goshnar's Hatred", + position = Position(33744, 31599, 14), + }, + monsters = { + { name = "Ashes of Burning Hatred", pos = { x = 33743, y = 31599, z = 14 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33773, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33774, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33775, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33776, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33735, 31592, 14), + to = Position(33751, 31606, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + onUseExtra = function(player) + SoulWarQuest.kvBurning:set("time", 180) + logger.debug("Goshnar's Hatred burning change form time set to: {}", 180) + player:resetGoshnarSymbolTormentCounter() + end, + }, + goshnarsCruelty = { + boss = { + name = "Goshnar's Cruelty", + position = Position(33856, 31866, 7), + }, + monsters = { + { name = "A Greedy Eye", pos = { x = 33856, y = 31858, z = 7 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33854, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33855, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33856, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33857, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33858, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33847, 31858, 7), + to = Position(33864, 31874, 7), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + onUseExtra = function(player) + SoulWarQuest.kvSoulWar:remove("greedy-maw-action") + player:soulWarQuestKV():scoped("furious-crater"):remove("greedy-maw-action") + end, + }, + goshnarsMegalomania = { + boss = { + name = "Goshnar's Megalomania Purple", + position = Position(33710, 31634, 14), + }, + monsters = { + { name = "Aspect of Power", pos = { x = 33710, y = 31635, z = 14 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33676, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33677, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33678, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33679, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33701, 31626, 14), + to = Position(33719, 31642, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 72 * 60 * 60, -- 72 hours + onUseExtra = function(player) + player:resetGoshnarSymbolTormentCounter() + SoulWarQuest.kvSoulWar:remove("cleansed-sanity-action") + player:soulWarQuestKV():scoped("furious-crater"):remove("cleansed-sanity-action") + end, + }, + }, + + -- Goshnar's Greed + apparitionNames = { + "Druid's Apparition", + "Knight's Apparition", + "Paladin's Apparition", + "Sorcerer's Apparition", + }, + + burningTransformations = { + { 180, "Ashes of Burning Hatred" }, + { 135, "Spark of Burning Hatred" }, + { 90, "Flame of Burning Hatred" }, + { 45, "Blaze of Burning Hatred" }, + }, + + requiredCountPerApparition = 25, + + -- Ebb and flow + ebbAndFlow = { + zone = Zone("ebb-and-flow-zone"), + -- Positions to teleport into rooms when innundate map is loaded + centerRoomPositions = { + { conor = { x = 33929, y = 31020, z = 9 }, teleportPosition = { x = 33939, y = 31021, z = 8 } }, + { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33918, y = 31047, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, + { conor = { x = 33898, y = 31054, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, + { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33940, y = 31054, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33940, y = 31064, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, + { conor = { x = 33937, y = 31086, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, + { conor = { x = 33937, y = 31098, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33933, y = 31109, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33921, y = 31113, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33912, y = 31113, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, + { conor = { x = 33901, y = 31108, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, + { conor = { x = 33901, y = 31098, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, + { conor = { x = 33899, y = 31064, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, + }, + mapsPath = { + empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", + inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", + }, + + -- In Minutes + intervalChangeMap = 2, + waitPosition = Position(33893, 31020, 8), + + getZone = function() + return SoulWarQuest.ebbAndFlow.zone + end, + + reloadZone = function() + SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) + end, + + kv = KV.scoped("quest"):scoped("soul-war"):scoped("ebb-and-flow-maps"), + isActive = function() + return SoulWarQuest.ebbAndFlow.kv:get("is-active") + end, + isLoadedEmptyMap = function() + return SoulWarQuest.ebbAndFlow.kv:get("is-loaded-empty-map") + end, + setActive = function(value) + SoulWarQuest.ebbAndFlow.kv:set("is-active", value) + end, + setLoadedEmptyMap = function(value) + SoulWarQuest.ebbAndFlow.kv:set("is-loaded-empty-map", value) + end, + + updateZonePlayers = function() + if SoulWarQuest.ebbAndFlow.zone and SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then + SoulWarQuest.ebbAndFlow.reloadZone() + local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() + for _, player in ipairs(players) do + logger.debug("Updating player: {}", player:getName()) + player:sendCreatureAppear() + end + end + end, + + -- Add here more positions of the pools that must transform before innundate map is loaded + poolPositions = { + { x = 33906, y = 31026, z = 9 }, + { x = 33901, y = 31026, z = 9 }, + { x = 33932, y = 31011, z = 9 }, + { x = 33941, y = 31033, z = 9 }, + { x = 33946, y = 31037, z = 9 }, + { x = 33939, y = 31056, z = 9 }, + }, + + boatId = 7272, + doorId = 33767, + smallPoolId = 33772, + MediumPoolId = 33773, + }, + + changeBlueEvent = nil, + changePurpleEvent = nil, + + changeMegalomaniaBlue = function() + local boss = Creature("Goshnar's Megalomania") + if boss then + boss:teleportTo(SoulWarQuest.levers.goshnarsMegalomania.boss.position) + boss:say("ENOUGH! I WILL MAKE YOU SUFFER FOR YOUR INSOLENCE! NOW - I - WILL - ANIHILATE - YOU!") + boss:setType("Goshnar's Megalomania Blue") + local function changeBack() + boss:setType("Goshnar's Megalomania Purple") + end + + changePurpleEvent = addEvent(changeBack, 7000) + end + end, + + -- Chance to heal the life of the monster by stepping on the corpse of "weeping soul" + goshnarsSpiteHealChance = 10, + -- Percentage that will heal by stepping and the chance is successful + goshnarsSpiteHealPercentage = 10, + + goshnarSpiteEntrancePosition = { fromPos = Position(33950, 31109, 8), toPos = Position(33780, 31634, 14) }, + + waterElementalOutfit = { + lookType = 286, + lookHead = 0, + lookBody = 0, + lookLegs = 0, + lookFeet = 0, + lookAddons = 0, + lookMount = 0, + }, + + goshnarsSpiteFirePositions = { + -- North + { x = 33743, y = 31628, z = 14 }, + -- East + { x = 33736, y = 31632, z = 14 }, + -- West + { x = 33750, y = 31632, z = 14 }, + -- South + { x = 33742, y = 31637, z = 14 }, + }, + + -- Increased defense if the searing fire disappears + goshnarsSpiteIncreaseDefense = 10, + -- Count of monsters to kill for enter in the boss room + hardozousPanthomDeathCount = 20, + -- Time to fire created again + timeToCreateSearingFire = 14, -- In seconds + -- Time to remove the searing fire if player don't step on it + timeToRemoveSearingFire = 5, -- In seconds + cooldownToStepOnSearingFire = 56, -- In seconds (14 seconds x 4) + + -- Positions to teleport into rooms when innundate map is loaded + ebbAndFlowBoatTeleportPositions = { + -- First boat + -- Enter on boat + { register = { x = 33919, y = 31019, z = 8 }, teleportTo = { x = 33923, y = 31019, z = 8 } }, + { register = { x = 33919, y = 31020, z = 8 }, teleportTo = { x = 33923, y = 31020, z = 8 } }, + { register = { x = 33919, y = 31021, z = 8 }, teleportTo = { x = 33923, y = 31021, z = 8 } }, + { register = { x = 33919, y = 31022, z = 8 }, teleportTo = { x = 33923, y = 31022, z = 8 } }, + -- Back to innitial room + { register = { x = 33922, y = 31019, z = 8 }, teleportTo = { x = 33918, y = 31019, z = 8 } }, + { register = { x = 33922, y = 31020, z = 8 }, teleportTo = { x = 33918, y = 31020, z = 8 } }, + { register = { x = 33922, y = 31021, z = 8 }, teleportTo = { x = 33918, y = 31021, z = 8 } }, + { register = { x = 33922, y = 31022, z = 8 }, teleportTo = { x = 33918, y = 31022, z = 8 } }, + -- From boat to room + { register = { x = 33926, y = 31019, z = 8 }, teleportTo = { x = 33930, y = 31019, z = 8 } }, + { register = { x = 33926, y = 31020, z = 8 }, teleportTo = { x = 33930, y = 31020, z = 8 } }, + { register = { x = 33926, y = 31021, z = 8 }, teleportTo = { x = 33930, y = 31021, z = 8 } }, + { register = { x = 33926, y = 31022, z = 8 }, teleportTo = { x = 33930, y = 31022, z = 8 } }, + -- From room to boat + { register = { x = 33929, y = 31019, z = 8 }, teleportTo = { x = 33925, y = 31019, z = 8 } }, + { register = { x = 33929, y = 31020, z = 8 }, teleportTo = { x = 33925, y = 31020, z = 8 } }, + { register = { x = 33929, y = 31021, z = 8 }, teleportTo = { x = 33925, y = 31021, z = 8 } }, + { register = { x = 33929, y = 31022, z = 8 }, teleportTo = { x = 33925, y = 31022, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33929, y = 31045, z = 8 }, teleportTo = { x = 33925, y = 31045, z = 8 } }, + { register = { x = 33929, y = 31046, z = 8 }, teleportTo = { x = 33925, y = 31046, z = 8 } }, + { register = { x = 33929, y = 31047, z = 8 }, teleportTo = { x = 33925, y = 31047, z = 8 } }, + { register = { x = 33929, y = 31048, z = 8 }, teleportTo = { x = 33925, y = 31048, z = 8 } }, + -- Back to room + { register = { x = 33926, y = 31045, z = 8 }, teleportTo = { x = 33930, y = 31045, z = 8 } }, + { register = { x = 33926, y = 31046, z = 8 }, teleportTo = { x = 33930, y = 31046, z = 8 } }, + { register = { x = 33926, y = 31047, z = 8 }, teleportTo = { x = 33930, y = 31047, z = 8 } }, + { register = { x = 33926, y = 31048, z = 8 }, teleportTo = { x = 33930, y = 31048, z = 8 } }, + -- From boat to room + { register = { x = 33922, y = 31045, z = 8 }, teleportTo = { x = 33918, y = 31045, z = 8 } }, + { register = { x = 33922, y = 31046, z = 8 }, teleportTo = { x = 33918, y = 31046, z = 8 } }, + { register = { x = 33922, y = 31047, z = 8 }, teleportTo = { x = 33918, y = 31047, z = 8 } }, + { register = { x = 33922, y = 31048, z = 8 }, teleportTo = { x = 33918, y = 31048, z = 8 } }, + -- From room to boat + { register = { x = 33919, y = 31045, z = 8 }, teleportTo = { x = 33923, y = 31045, z = 8 } }, + { register = { x = 33919, y = 31046, z = 8 }, teleportTo = { x = 33923, y = 31046, z = 8 } }, + { register = { x = 33919, y = 31047, z = 8 }, teleportTo = { x = 33923, y = 31047, z = 8 } }, + { register = { x = 33919, y = 31048, z = 8 }, teleportTo = { x = 33923, y = 31048, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33896, y = 31055, z = 8 }, teleportTo = { x = 33896, y = 31059, z = 8 } }, + { register = { x = 33897, y = 31055, z = 8 }, teleportTo = { x = 33897, y = 31059, z = 8 } }, + { register = { x = 33898, y = 31055, z = 8 }, teleportTo = { x = 33898, y = 31059, z = 8 } }, + { register = { x = 33899, y = 31055, z = 8 }, teleportTo = { x = 33899, y = 31059, z = 8 } }, + { register = { x = 33900, y = 31055, z = 8 }, teleportTo = { x = 33900, y = 31059, z = 8 } }, + { register = { x = 33901, y = 31055, z = 8 }, teleportTo = { x = 33901, y = 31059, z = 8 } }, + -- Back to room + { register = { x = 33896, y = 31058, z = 8 }, teleportTo = { x = 33896, y = 31054, z = 8 } }, + { register = { x = 33897, y = 31058, z = 8 }, teleportTo = { x = 33897, y = 31054, z = 8 } }, + { register = { x = 33898, y = 31058, z = 8 }, teleportTo = { x = 33898, y = 31054, z = 8 } }, + { register = { x = 33899, y = 31058, z = 8 }, teleportTo = { x = 33899, y = 31054, z = 8 } }, + { register = { x = 33900, y = 31058, z = 8 }, teleportTo = { x = 33900, y = 31054, z = 8 } }, + { register = { x = 33901, y = 31058, z = 8 }, teleportTo = { x = 33901, y = 31054, z = 8 } }, + -- From boat to room + { register = { x = 33896, y = 31061, z = 8 }, teleportTo = { x = 33896, y = 31065, z = 8 } }, + { register = { x = 33897, y = 31061, z = 8 }, teleportTo = { x = 33897, y = 31065, z = 8 } }, + { register = { x = 33898, y = 31061, z = 8 }, teleportTo = { x = 33898, y = 31065, z = 8 } }, + { register = { x = 33899, y = 31061, z = 8 }, teleportTo = { x = 33899, y = 31065, z = 8 } }, + { register = { x = 33900, y = 31061, z = 8 }, teleportTo = { x = 33900, y = 31065, z = 8 } }, + { register = { x = 33901, y = 31061, z = 8 }, teleportTo = { x = 33901, y = 31065, z = 8 } }, + -- From room to boat + { register = { x = 33896, y = 31064, z = 8 }, teleportTo = { x = 33896, y = 31060, z = 8 } }, + { register = { x = 33897, y = 31064, z = 8 }, teleportTo = { x = 33897, y = 31060, z = 8 } }, + { register = { x = 33898, y = 31064, z = 8 }, teleportTo = { x = 33898, y = 31060, z = 8 } }, + { register = { x = 33899, y = 31064, z = 8 }, teleportTo = { x = 33899, y = 31060, z = 8 } }, + { register = { x = 33900, y = 31064, z = 8 }, teleportTo = { x = 33900, y = 31060, z = 8 } }, + { register = { x = 33901, y = 31064, z = 8 }, teleportTo = { x = 33901, y = 31060, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33899, y = 31099, z = 8 }, teleportTo = { x = 33899, y = 31103, z = 8 } }, + { register = { x = 33900, y = 31099, z = 8 }, teleportTo = { x = 33900, y = 31103, z = 8 } }, + { register = { x = 33901, y = 31099, z = 8 }, teleportTo = { x = 33901, y = 31103, z = 8 } }, + { register = { x = 33902, y = 31099, z = 8 }, teleportTo = { x = 33902, y = 31103, z = 8 } }, + { register = { x = 33903, y = 31099, z = 8 }, teleportTo = { x = 33903, y = 31103, z = 8 } }, + { register = { x = 33904, y = 31099, z = 8 }, teleportTo = { x = 33904, y = 31103, z = 8 } }, + { register = { x = 33905, y = 31099, z = 8 }, teleportTo = { x = 33905, y = 31103, z = 8 } }, + -- Back from boat to room + { register = { x = 33899, y = 31102, z = 8 }, teleportTo = { x = 33899, y = 31098, z = 8 } }, + { register = { x = 33900, y = 31102, z = 8 }, teleportTo = { x = 33900, y = 31098, z = 8 } }, + { register = { x = 33901, y = 31102, z = 8 }, teleportTo = { x = 33901, y = 31098, z = 8 } }, + { register = { x = 33902, y = 31102, z = 8 }, teleportTo = { x = 33902, y = 31098, z = 8 } }, + { register = { x = 33903, y = 31102, z = 8 }, teleportTo = { x = 33903, y = 31098, z = 8 } }, + { register = { x = 33904, y = 31102, z = 8 }, teleportTo = { x = 33904, y = 31098, z = 8 } }, + { register = { x = 33905, y = 31102, z = 8 }, teleportTo = { x = 33905, y = 31098, z = 8 } }, + -- From boat to room + { register = { x = 33899, y = 31105, z = 8 }, teleportTo = { x = 33899, y = 31109, z = 8 } }, + { register = { x = 33900, y = 31105, z = 8 }, teleportTo = { x = 33900, y = 31109, z = 8 } }, + { register = { x = 33901, y = 31105, z = 8 }, teleportTo = { x = 33901, y = 31109, z = 8 } }, + { register = { x = 33902, y = 31105, z = 8 }, teleportTo = { x = 33902, y = 31109, z = 8 } }, + { register = { x = 33903, y = 31105, z = 8 }, teleportTo = { x = 33903, y = 31109, z = 8 } }, + { register = { x = 33904, y = 31105, z = 8 }, teleportTo = { x = 33904, y = 31109, z = 8 } }, + { register = { x = 33905, y = 31105, z = 8 }, teleportTo = { x = 33905, y = 31109, z = 8 } }, + -- From room to boat + { register = { x = 33899, y = 31108, z = 8 }, teleportTo = { x = 33899, y = 31104, z = 8 } }, + { register = { x = 33900, y = 31108, z = 8 }, teleportTo = { x = 33900, y = 31104, z = 8 } }, + { register = { x = 33901, y = 31108, z = 8 }, teleportTo = { x = 33901, y = 31104, z = 8 } }, + { register = { x = 33902, y = 31108, z = 8 }, teleportTo = { x = 33902, y = 31104, z = 8 } }, + { register = { x = 33903, y = 31108, z = 8 }, teleportTo = { x = 33903, y = 31104, z = 8 } }, + { register = { x = 33904, y = 31108, z = 8 }, teleportTo = { x = 33904, y = 31104, z = 8 } }, + { register = { x = 33905, y = 31108, z = 8 }, teleportTo = { x = 33905, y = 31104, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33913, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, + { register = { x = 33913, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, + { register = { x = 33913, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, + { register = { x = 33913, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, + { register = { x = 33913, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, + -- Back to room + { register = { x = 33916, y = 31112, z = 8 }, teleportTo = { x = 33912, y = 31112, z = 8 } }, + { register = { x = 33916, y = 31113, z = 8 }, teleportTo = { x = 33912, y = 31113, z = 8 } }, + { register = { x = 33916, y = 31114, z = 8 }, teleportTo = { x = 33912, y = 31114, z = 8 } }, + { register = { x = 33916, y = 31115, z = 8 }, teleportTo = { x = 33912, y = 31115, z = 8 } }, + { register = { x = 33916, y = 31116, z = 8 }, teleportTo = { x = 33912, y = 31116, z = 8 } }, + -- From boat to room + { register = { x = 33918, y = 31112, z = 8 }, teleportTo = { x = 33922, y = 31112, z = 8 } }, + { register = { x = 33918, y = 31113, z = 8 }, teleportTo = { x = 33922, y = 31113, z = 8 } }, + { register = { x = 33918, y = 31114, z = 8 }, teleportTo = { x = 33922, y = 31114, z = 8 } }, + { register = { x = 33918, y = 31115, z = 8 }, teleportTo = { x = 33922, y = 31115, z = 8 } }, + { register = { x = 33918, y = 31116, z = 8 }, teleportTo = { x = 33922, y = 31116, z = 8 } }, + -- From room to boat + { register = { x = 33921, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, + { register = { x = 33921, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, + { register = { x = 33921, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, + { register = { x = 33921, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, + { register = { x = 33921, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33936, y = 31087, z = 8 }, teleportTo = { x = 33936, y = 31091, z = 8 } }, + { register = { x = 33937, y = 31087, z = 8 }, teleportTo = { x = 33937, y = 31091, z = 8 } }, + { register = { x = 33938, y = 31087, z = 8 }, teleportTo = { x = 33938, y = 31091, z = 8 } }, + { register = { x = 33939, y = 31087, z = 8 }, teleportTo = { x = 33939, y = 31091, z = 8 } }, + { register = { x = 33940, y = 31087, z = 8 }, teleportTo = { x = 33940, y = 31091, z = 8 } }, + { register = { x = 33941, y = 31087, z = 8 }, teleportTo = { x = 33941, y = 31091, z = 8 } }, + -- Back to room + { register = { x = 33936, y = 31090, z = 8 }, teleportTo = { x = 33936, y = 31086, z = 8 } }, + { register = { x = 33937, y = 31090, z = 8 }, teleportTo = { x = 33937, y = 31086, z = 8 } }, + { register = { x = 33938, y = 31090, z = 8 }, teleportTo = { x = 33938, y = 31086, z = 8 } }, + { register = { x = 33939, y = 31090, z = 8 }, teleportTo = { x = 33939, y = 31086, z = 8 } }, + { register = { x = 33940, y = 31090, z = 8 }, teleportTo = { x = 33940, y = 31086, z = 8 } }, + { register = { x = 33941, y = 31090, z = 8 }, teleportTo = { x = 33941, y = 31086, z = 8 } }, + -- From boat to room + { register = { x = 33936, y = 31095, z = 8 }, teleportTo = { x = 33934, y = 31099, z = 8 } }, + { register = { x = 33937, y = 31095, z = 8 }, teleportTo = { x = 33935, y = 31099, z = 8 } }, + { register = { x = 33938, y = 31095, z = 8 }, teleportTo = { x = 33936, y = 31099, z = 8 } }, + { register = { x = 33939, y = 31095, z = 8 }, teleportTo = { x = 33937, y = 31099, z = 8 } }, + { register = { x = 33940, y = 31095, z = 8 }, teleportTo = { x = 33938, y = 31099, z = 8 } }, + { register = { x = 33941, y = 31095, z = 8 }, teleportTo = { x = 33939, y = 31099, z = 8 } }, + -- From room to boat + { register = { x = 33934, y = 31098, z = 8 }, teleportTo = { x = 33936, y = 31094, z = 8 } }, + { register = { x = 33935, y = 31098, z = 8 }, teleportTo = { x = 33937, y = 31094, z = 8 } }, + { register = { x = 33936, y = 31098, z = 8 }, teleportTo = { x = 33938, y = 31094, z = 8 } }, + { register = { x = 33937, y = 31098, z = 8 }, teleportTo = { x = 33939, y = 31094, z = 8 } }, + { register = { x = 33938, y = 31098, z = 8 }, teleportTo = { x = 33940, y = 31094, z = 8 } }, + { register = { x = 33939, y = 31098, z = 8 }, teleportTo = { x = 33941, y = 31094, z = 8 } }, + { register = { x = 33940, y = 31098, z = 8 }, teleportTo = { x = 33942, y = 31094, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33939, y = 31064, z = 8 }, teleportTo = { x = 33939, y = 31060, z = 8 } }, + { register = { x = 33940, y = 31064, z = 8 }, teleportTo = { x = 33940, y = 31060, z = 8 } }, + { register = { x = 33941, y = 31064, z = 8 }, teleportTo = { x = 33941, y = 31060, z = 8 } }, + { register = { x = 33942, y = 31064, z = 8 }, teleportTo = { x = 33942, y = 31060, z = 8 } }, + { register = { x = 33943, y = 31064, z = 8 }, teleportTo = { x = 33943, y = 31060, z = 8 } }, + { register = { x = 33944, y = 31064, z = 8 }, teleportTo = { x = 33944, y = 31060, z = 8 } }, + -- Back to room + { register = { x = 33939, y = 31061, z = 8 }, teleportTo = { x = 33939, y = 31065, z = 8 } }, + { register = { x = 33940, y = 31061, z = 8 }, teleportTo = { x = 33940, y = 31065, z = 8 } }, + { register = { x = 33941, y = 31061, z = 8 }, teleportTo = { x = 33941, y = 31065, z = 8 } }, + { register = { x = 33942, y = 31061, z = 8 }, teleportTo = { x = 33942, y = 31065, z = 8 } }, + { register = { x = 33943, y = 31061, z = 8 }, teleportTo = { x = 33943, y = 31065, z = 8 } }, + { register = { x = 33944, y = 31061, z = 8 }, teleportTo = { x = 33944, y = 31065, z = 8 } }, + -- From boat to room + { register = { x = 33939, y = 31058, z = 8 }, teleportTo = { x = 33939, y = 31054, z = 8 } }, + { register = { x = 33940, y = 31058, z = 8 }, teleportTo = { x = 33940, y = 31054, z = 8 } }, + { register = { x = 33941, y = 31058, z = 8 }, teleportTo = { x = 33941, y = 31054, z = 8 } }, + { register = { x = 33942, y = 31058, z = 8 }, teleportTo = { x = 33942, y = 31054, z = 8 } }, + { register = { x = 33943, y = 31058, z = 8 }, teleportTo = { x = 33943, y = 31054, z = 8 } }, + { register = { x = 33944, y = 31058, z = 8 }, teleportTo = { x = 33944, y = 31054, z = 8 } }, + -- From room to boat + { register = { x = 33939, y = 31055, z = 8 }, teleportTo = { x = 33939, y = 31059, z = 8 } }, + { register = { x = 33940, y = 31055, z = 8 }, teleportTo = { x = 33940, y = 31059, z = 8 } }, + { register = { x = 33941, y = 31055, z = 8 }, teleportTo = { x = 33941, y = 31059, z = 8 } }, + { register = { x = 33942, y = 31055, z = 8 }, teleportTo = { x = 33942, y = 31059, z = 8 } }, + { register = { x = 33943, y = 31055, z = 8 }, teleportTo = { x = 33943, y = 31059, z = 8 } }, + { register = { x = 33944, y = 31055, z = 8 }, teleportTo = { x = 33944, y = 31059, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33934, y = 31108, z = 8 }, teleportTo = { x = 33938, y = 31108, z = 8 } }, + { register = { x = 33934, y = 31109, z = 8 }, teleportTo = { x = 33938, y = 31109, z = 8 } }, + { register = { x = 33934, y = 31110, z = 8 }, teleportTo = { x = 33938, y = 31110, z = 8 } }, + { register = { x = 33934, y = 31111, z = 8 }, teleportTo = { x = 33938, y = 31111, z = 8 } }, + { register = { x = 33934, y = 31112, z = 8 }, teleportTo = { x = 33938, y = 31112, z = 8 } }, + -- Back to room + { register = { x = 33937, y = 31108, z = 8 }, teleportTo = { x = 33933, y = 31108, z = 8 } }, + { register = { x = 33937, y = 31109, z = 8 }, teleportTo = { x = 33933, y = 31109, z = 8 } }, + { register = { x = 33937, y = 31110, z = 8 }, teleportTo = { x = 33933, y = 31110, z = 8 } }, + { register = { x = 33937, y = 31111, z = 8 }, teleportTo = { x = 33933, y = 31111, z = 8 } }, + { register = { x = 33937, y = 31112, z = 8 }, teleportTo = { x = 33933, y = 31112, z = 8 } }, + -- From boat to room + { register = { x = 33942, y = 31108, z = 8 }, teleportTo = { x = 33946, y = 31108, z = 8 } }, + { register = { x = 33942, y = 31109, z = 8 }, teleportTo = { x = 33946, y = 31109, z = 8 } }, + { register = { x = 33942, y = 31110, z = 8 }, teleportTo = { x = 33946, y = 31110, z = 8 } }, + { register = { x = 33942, y = 31111, z = 8 }, teleportTo = { x = 33946, y = 31111, z = 8 } }, + { register = { x = 33942, y = 31112, z = 8 }, teleportTo = { x = 33946, y = 31112, z = 8 } }, + -- From room to boat + { register = { x = 33945, y = 31108, z = 8 }, teleportTo = { x = 33941, y = 31108, z = 8 } }, + { register = { x = 33945, y = 31109, z = 8 }, teleportTo = { x = 33941, y = 31109, z = 8 } }, + { register = { x = 33945, y = 31110, z = 8 }, teleportTo = { x = 33941, y = 31110, z = 8 } }, + { register = { x = 33945, y = 31111, z = 8 }, teleportTo = { x = 33941, y = 31111, z = 8 } }, + { register = { x = 33945, y = 31112, z = 8 }, teleportTo = { x = 33941, y = 31112, z = 8 } }, + }, +} + +-- Initialize ebb and flow zone area +SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) + +SoulCagePosition = Position(33709, 31596, 14) +TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days +GreedbeastKills = 0 + +SoulWarReflectDamageMap = { + [COMBAT_PHYSICALDAMAGE] = 10, + [COMBAT_FIREDAMAGE] = 10, + [COMBAT_EARTHDAMAGE] = 10, + [COMBAT_ENERGYDAMAGE] = 10, + [COMBAT_ICEDAMAGE] = 10, + [COMBAT_HOLYDAMAGE] = 10, + [COMBAT_DEATHDAMAGE] = 10, +} + +local soulWarTaints = { + "taints-teleport", -- Taint 1 + "taints-spawn", -- Taint 2 + "taints-damage", -- Taint 3 + "taints-heal", -- Taint 4 + "taints-loss", -- Taint 5 +} + +SoulWarBosses = { + ["Goshnar's Malice"] = true, + ["Goshnar's Hatred"] = true, + ["Goshnar's Spite"] = true, + ["Goshnar's Cruelty"] = true, + ["Goshnar's Greed"] = true, +} + +GreedMonsters = { + ["Greedbeast"] = Position(33744, 31666, 14), + ["Soulsnatcher"] = Position(33747, 31668, 14), + ["Weak Soul"] = Position(33750, 31666, 14), + ["Strong Soul"] = Position(33750, 31666, 14), + ["Powerful Soul"] = Position(33750, 31666, 14), +} + +function CreateGoshnarsGreedMonster(name, position) + local function sendEffect() + position:sendMagicEffect(CONST_ME_TELEPORT) + end + + local function spawnMonster() + Game.createMonster(name, position, true, false) + logger.debug("Spawning {} in position {}", name, position:toString()) + end + + for i = 7, 9 do + addEvent(sendEffect, i * 1000) + end + + addEvent(spawnMonster, 10000) +end + +local soulWarSpawnMonsters = { + ["soulwars.claustrophobic-inferno"] = "Brachiodemon", + ["soulwars.mirrored-nightmare"] = "Many Faces", + ["soulwars.ebb-and-flow"] = "Bony Sea Devil", + ["soulwars.furious-crater"] = "Cloak of Terror", + ["soulwars.rotten-wasteland"] = "Branchy Crawler", + ["boss-rooms"] = "Dreadful Harvester", +} + +function RemoveSoulCageAndBuffMalice() + local tile = Tile(SoulCagePosition) + local creatures = tile:getCreatures() or {} + local soulCage + for i, creature in ipairs(creatures) do + if creature:getName() == "Soul Cage" then + soulCage = creature + logger.debug("Removing Soul Cage, the players not be able to kill him") + break + end + end + + local rangeX = 20 + local rangeY = 20 + local spectators = Game.getSpectators(Position(33709, 31599, 14), false, false, rangeX, rangeX, rangeY, rangeY) + if soulCage then + local malice + for i = 1, #spectators do + logger.debug("Specs found {}", i) + if spectators[i]:isMonster() then + logger.debug("Malice Spectators {}", spectators[i]:getName()) + if spectators[i]:getName() == "Goshnar's Malice" then + logger.debug("Found malice") + malice = Monster(spectators[i]) + break + end + end + end + + soulCage:remove() + addEvent(SpawnSoulCage, 23000) + + if malice then + logger.debug("Found malice, try adding reflect and defense") + for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do + malice:addReflectElement(elementType, reflectPercent) + end + malice:addDefense(10) + end + end +end + +function SpawnSoulCage() + local tile = Tile(SoulCagePosition) + local creatures = tile:getCreatures() or {} + local soulCage + for i, creature in ipairs(creatures) do + if creature:getName() == "Soul Cage" then + soulCage = true + break + end + end + + if not soulCage then + Game.createMonster("Soul Cage", SoulCagePosition, true, true) + logger.debug("Spawning Soul Cage in position {}", SoulCagePosition:toString()) + addEvent(RemoveSoulCageAndBuffMalice, 40000) + end +end + +local function shuffle(list) + for i = #list, 2, -1 do + local j = math.random(i) + list[i], list[j] = list[j], list[i] + end +end + +local function createConnectedGroup(startPos, groupPositions, groupSize) + local group = { startPos } + local lastPos = startPos + local directions = { + { x = 1, y = 0 }, + { x = -1, y = 0 }, -- Right and left + { x = 0, y = 1 }, + { x = 0, y = -1 }, -- Up and down + { x = 1, y = 1 }, + { x = -1, y = -1 }, -- Diagonals + { x = -1, y = 1 }, + { x = 1, y = -1 }, + } + + for i = 2, groupSize do + shuffle(directions) + local nextPos = nil + for _, dir in ipairs(directions) do + local potentialNextPos = Position(lastPos.x + dir.x, lastPos.y + dir.y, lastPos.z) + if table.contains(groupPositions, potentialNextPos) then + nextPos = potentialNextPos + break + end + end + + if nextPos then + table.insert(group, nextPos) + table.remove(groupPositions, table.find(groupPositions, nextPos)) + lastPos = nextPos + else + break + end + end + + return group +end + +local function generatePositionsInRange(center, range) + local positions = {} + for x = center.x - range, center.x + range do + for y = center.y - range, center.y + range do + table.insert(positions, Position(x, y, center.z)) + end + end + return positions +end + +local toRevertPositions = {} + +local function revertTilesAndApplyDamage(zonePositions) + for _, pos in ipairs(zonePositions) do + local tile = Tile(pos) + if tile and tile:getGround() and tile:getGround():getId() ~= 409 then + local creature = tile:getTopCreature() + if creature then + local player = creature:getPlayer() + if player then + pos:sendMagicEffect(CONST_ME_REDSMOKE) + player:addHealth(-8000, COMBAT_DEATHDAMAGE) + end + end + end + end + + for posString, itemId in pairs(toRevertPositions) do + local pos = posString:toPosition() + local tile = Tile(pos) + if tile and tile:getGround() and tile:getGround():getId() == 409 then + tile:getGround():transform(itemId) + toRevertPositions[pos:toString()] = nil + end + end +end + +function Monster:createSoulWarWhiteTiles(centerRoomPosition, zonePositions, executeInterval) + local groupPositions = generatePositionsInRange(centerRoomPosition, 7) + local totalTiles = 11 + local groupSize = 3 + local groupsCreated = 0 + + -- Run only for megalomania boss + if executeInterval then + -- Remove remains + for _, pos in ipairs(zonePositions) do + local tile = Tile(pos) + if tile and tile:getGround() then + local remains = tile:getItemById(33984) + if remains then + remains:remove() + end + end + end + end + + while #groupPositions > 0 and groupsCreated * groupSize < totalTiles do + local randomIndex = math.random(#groupPositions) + local startPos = groupPositions[randomIndex] + table.remove(groupPositions, randomIndex) + + local group = createConnectedGroup(startPos, groupPositions, groupSize) + for _, pos in ipairs(group) do + local tile = Tile(pos) + if tile then + toRevertPositions[pos:toString()] = tile:getGround():getId() + tile:getGround():transform(409) + end + end + + groupsCreated = groupsCreated + 1 + end + + addEvent(revertTilesAndApplyDamage, executeInterval or 3000, zonePositions) +end + +function Monster:generateBagYouDesireLoot(player) + local playerTaintLevel = player:getTaintLevel() + if not playerTaintLevel then + return {} + end + + local monsterName = self:getName() + local isMonsterValid = false + for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do + if monsterName == monster then + isMonsterValid = true + break + end + end + + if not isMonsterValid then + return {} + end + + -- Calculates the chances based on the number of taints + local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) + logger.debug("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + -- Generate loot + local loot = {} + if math.random(1, 100) <= totalChance then + local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) + if itemType then + loot[itemType:getId()] = { count = 1 } + logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) + end + end + + return loot +end + +local intervalBetweenExecutions = 10000 + +local accumulatedTime = 0 +local desiredInterval = 40000 +local bossSayInterval = 38000 + +function Monster:onThinkMegalomaniaWhiteTiles(interval, zonePositions, revertTime) + self:onThinkGoshnarTormentCounter(interval, 36, intervalBetweenExecutions, SoulWarQuest.levers.goshnarsMegalomania.boss.position) + + accumulatedTime = accumulatedTime + interval + + if accumulatedTime == bossSayInterval then + self:say("FEEL THE POWER OF MY WRATH!!") + end + -- Execute only after 40 seconds + if accumulatedTime >= desiredInterval then + self:createSoulWarWhiteTiles(SoulWarQuest.levers.goshnarsMegalomania.boss.position, zonePositions, revertTime) + accumulatedTime = 0 + end +end + +TaintTeleportCooldown = {} + +function Player:getTaintNameByNumber(taintNumber) + local haveTaintName = nil + local soulWarQuest = self:soulWarQuestKV() + local taintName = soulWarTaints[taintNumber] + if taintName and soulWarQuest:get(taintName) then + haveTaintName = taintName + end + + return haveTaintName +end + +function Player:addNextTaint() + local soulWarQuest = self:soulWarQuestKV() + for _, taint in ipairs(soulWarTaints) do + if not soulWarQuest:get(taint) then + soulWarQuest:set(taint, true) + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taint .. ".") + break + end + end +end + +function Player:getTaintLevel() + local taintLevel = nil + local soulWarQuest = self:soulWarQuestKV() + for i, taint in ipairs(soulWarTaints) do + if soulWarQuest:get(taint) then + taintLevel = i + end + end + + return taintLevel +end + +function Player:resetTaints() + local soulWarQuest = self:soulWarQuestKV() + local firstTaintTime = soulWarQuest:get("firstTaintTime") + if firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then + -- Reset all taints + for _, taint in ipairs(soulWarTaints) do + if soulWarQuest:get(taint) then + soulWarQuest:remove(taint) + end + end + + soulWarQuest:remove("firstTaintTime") + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") + end +end + +function Monster:tryTeleportToPlayer(sayMessage) + local range = 30 + local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) + local maxDistance = 0 + local farthestPlayer = nil + logger.debug("Checking teleport monster for monster {}", self:getName()) + for i, spectator in ipairs(spectators) do + if spectator:isPlayer() then + local player = spectator:getPlayer() + if player:getTaintNameByNumber(1) ~= nil then + local distance = self:getPosition():getDistance(player:getPosition()) + if distance > maxDistance then + maxDistance = distance + farthestPlayer = player + logger.debug("Found player {} to teleport", player:getName()) + end + end + end + end + + if farthestPlayer and math.random(100) <= 10 then + local playerPosition = farthestPlayer:getPosition() + if TaintTeleportCooldown[farthestPlayer:getId()] then + logger.debug("Cooldown is active to player {}", farthestPlayer:getName()) + return + end + + if not TaintTeleportCooldown[farthestPlayer:getId()] then + TaintTeleportCooldown[farthestPlayer:getId()] = true + + logger.debug("Scheduling player {} to teleport", farthestPlayer:getName()) + self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) + farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) + addEvent(function(playerId, monsterId) + local monsterEvent = Monster(monsterId) + local playerEvent = Player(playerId) + if monsterEvent and playerEvent then + local destinationTile = Tile(playerPosition) + if destinationTile and not (destinationTile:hasProperty(CONST_PROP_BLOCKPROJECTILE) or destinationTile:hasProperty(CONST_PROP_MOVEABLE)) then + monsterEvent:say(sayMessage) + monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + monsterEvent:teleportTo(playerPosition, true) + monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + end + end + end, 2000, farthestPlayer:getId(), self:getId()) + + addEvent(function(playerId) + local playerEvent = Player(playerId) + if not playerEvent then + return + end + + logger.debug("Cleaning player cooldown") + TaintTeleportCooldown[playerEvent:getId()] = nil + end, 10000, farthestPlayer:getId()) + end + end +end + +function Monster:getSoulWarKV() + return SoulWarQuest.kvSoulWar:scoped("monster"):scoped(self:getName()) +end + +function Monster:getHatredDamageMultiplier() + return self:getSoulWarKV():get("burning-hatred-empowered") or 0 +end + +function Monster:increaseHatredDamageMultiplier(multiplierCount) + local attackMultiplier = self:getHatredDamageMultiplier() + self:getSoulWarKV():set("burning-hatred-empowered", attackMultiplier + multiplierCount or 10) +end + +function Monster:resetHatredDamageMultiplier() + self:getSoulWarKV():remove("burning-hatred-empowered") +end + +function Position:increaseNecromaticMegalomaniaStrength() + local tile = Tile(self) + if tile then + local item = tile:getItemById(SoulWarQuest.necromanticRemainsId) + if item then + local boss = Creature("Goshnar's Megalomania") + if boss then + boss:increaseHatredDamageMultiplier(5) + item:remove() + logger.debug("Necromantic remains strength increased") + end + end + end +end + +local lastExecutionTime = 0 + +-- Damage 24 to 36 have a special damage +local damageTable = { + 1400, + 1600, + 1800, + 2200, + 2400, + 2600, + 3000, + 3400, + 3800, + 4200, + 4800, + 5200, + 5600, +} + +function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetweenExecutions, bossPosition) + local interval = os.time() * 1000 + if interval - lastExecutionTime < intervalBetweenExecutions then + return + end + + lastExecutionTime = interval + logger.debug("Icon time count {}", interval) + local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) + for i = 1, #spectators do + local player = spectators[i] + local tormentCounter = player:getGoshnarSymbolTormentCounter() + if tormentCounter <= maxLimit then + player:increaseGoshnarSymbolTormentCounter(maxLimit) + logger.debug("Player {} has {} damage counter", player:getName(), tormentCounter) + + if tormentCounter > 0 then + local damage = tormentCounter * 35 + if tormentCounter >= 24 then + damage = damageTable[tormentCounter - 23] + end + + logger.debug("Final damage {}", damage) + player:addHealth(-damage, COMBAT_DEATHDAMAGE) + player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) + end + end + + if tormentCounter == 5 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread starts to torment you! Don't let dread level reach critical value!") + elseif tormentCounter == 15 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment becomes unbearable!") + elseif tormentCounter == 24 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The Dread's torment begins to tear you apart!") + elseif tormentCounter == 30 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is killing you!") + elseif tormentCounter == 36 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is now lethal!") + end + end +end + +function Monster:increaseAspectOfPowerDeathCount() + local bossKV = self:getSoulWarKV() + local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 + local newCount = aspectDeathCount + 1 + logger.debug("Aspect of Power death count {}", newCount) + bossKV:set("aspect-of-power-death-count", newCount) + if newCount == 4 then + self:setType("Goshnar's Megalomania Green") + self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") + bossKV:set("aspect-of-power-death-count", 0) + logger.debug("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") + SoulWarQuest.changePurpleEvent = addEvent(function() + local boss = Creature("Goshnar's Megalomania") + if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then + boss:setType("Goshnar's Megalomania Purple") + boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") + logger.debug("Megalomania is now immune again") + end + end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) + end +end + +function Monster:goshnarsDefenseIncrease(kvName) + local currentTime = os.time() + -- Gets the time when the "Greedy Maw" item was last used. + local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 + -- Checks if more than config time have passed since the item was last used. + if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then + logger.debug("{} old defense {}", self:getName(), self:getDefense()) + self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) + logger.debug("{} new defense {}", self:getName(), self:getDefense()) + + --- Updates the KV to reflect the timing of the increase to maintain control. + SoulWarQuest.kvSoulWar:set(kvName, currentTime) + else + -- If config time have not passed, logs the increase has been skipped. + logger.debug("{} skips increase cooldown due to recent item use.", self:getName()) + end +end + +function Player:getSoulWarZoneMonster() + local zoneMonsterName = nil + for zoneName, monsterName in pairs(soulWarSpawnMonsters) do + local zone = Zone.getByName(zoneName) + if zone and zone:isInZone(self:getPosition()) then + zoneMonsterName = monsterName + break + end + end + + return zoneMonsterName +end + +function Player:isInBoatSpot() + -- Get ebb and flow zone and check if player is in zone + local zone = SoulWarQuest.ebbAndFlow.getZone() + local tile = Tile(self:getPosition()) + local groundId + if tile and tile:getGround() then + groundId = tile:getGround():getId() + end + if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then + logger.debug("Player {} is in boat spot", self:getName()) + return true + end + + logger.debug("Player {} is not in boat spot", self:getName()) + return false +end + +function Player:soulWarQuestKV() + return self:kv():scoped("quest"):scoped("soul-war") +end + +function Player:getGoshnarSymbolTormentCounter() + local soulWarKV = self:soulWarQuestKV() + return soulWarKV:get("goshnars-hatred-torment-count") or 0 +end + +function Player:increaseGoshnarSymbolTormentCounter(maxLimit) + local soulWarKV = self:soulWarQuestKV() + local tormentCount = self:getGoshnarSymbolTormentCounter() + if tormentCount == maxLimit then + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount) + return + end + + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount + 1) + soulWarKV:set("goshnars-hatred-torment-count", tormentCount + 1) +end + +function Player:removeGoshnarSymbolTormentCounter(count) + local soulWarKV = self:soulWarQuestKV() + local tormentCount = self:getGoshnarSymbolTormentCounter() + if tormentCount > count then + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount - count) + soulWarKV:set("goshnars-hatred-torment-count", tormentCount - count) + else + self:resetGoshnarSymbolTormentCounter() + end +end + +function Player:resetGoshnarSymbolTormentCounter() + local soulWarKV = self:soulWarQuestKV() + soulWarKV:remove("goshnars-hatred-torment-count") + self:removeIcon("goshnars-hatred-damage") +end + +function Player:furiousCraterKV() + return self:soulWarQuestKV():scoped("furius-crater") +end + +function Player:pulsatingEnergyKV() + return self:furiousCraterKV():scoped("pulsating-energy") +end + +function Zone:getRandomPlayer() + local players = self:getPlayers() + if #players == 0 then + return nil + end + + local randomIndex = math.random(#players) + return players[randomIndex] +end + +local function delayedCastSpell(cid, var, combat, targetId) + local creature = Creature(cid) + if not creature then + return + end + + local target = Player(targetId) + if target then + combat:execute(creature, positionToVariant(target:getPosition())) + end +end + +function Creature:applyZoneEffect(var, combat, zoneName) + local outfitConfig = { + outfit = { lookType = 242, lookHead = 0, lookBody = 0, lookLegs = 0, lookFeet = 0, lookAddons = 0 }, + time = 7000, + } + + local zone = Zone.getByName(zoneName) + if not zone then + logger.error("Could not find zone '" .. zoneName .. "', you need use the 'BossLever' system") + return false + end + + local target = zone:getRandomPlayer() + if not target then + return true + end + + local condition = Condition(CONDITION_OUTFIT) + condition:setTicks(outfitConfig.time) + condition:setOutfit(outfitConfig.outfit) + target:addCondition(condition) + target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + + addEvent(delayedCastSpell, SoulWarQuest.goshnarsCrueltyWaveInterval * 1000, self:getId(), var, combat, target:getId()) + + return true +end + +function string.toPosition(str) + local patterns = { + -- table format + "{%s*x%s*=%s*(%d+)%s*,%s*y%s*=%s*(%d+)%s*,%s*z%s*=%s*(%d+)%s*}", + -- Position format + "Position%s*%((%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)", + -- x, y, z format + "(%d+)%s*,%s*(%d+)%s*,%s*(%d+)", + } + + for _, pattern in ipairs(patterns) do + local x, y, z = string.match(str, pattern) + if x and y and z then + return Position(tonumber(x), tonumber(y), tonumber(z)) + end + end +end From 2032ec0ec77162865972057d63b2a1ad1532b9c8 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 20:47:19 -0300 Subject: [PATCH 02/31] fix: goshnar's malice damage white tiles and add zones --- .../scripts/lib/quests/soul-war.lua | 98 ++++++++++++++----- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index ba44d49943f..e4fcfe4d4bb 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -67,6 +67,14 @@ SoulWarQuest = { "Courage Leech", }, + miniBosses = { + ["Goshnar's Malice"] = true, + ["Goshnar's Hatred"] = true, + ["Goshnar's Spite"] = true, + ["Goshnar's Cruelty"] = true, + ["Goshnar's Greed"] = true, + }, + finalRewards = { { id = 34082, name = "soulcutter" }, { id = 34083, name = "soulshredder" }, @@ -109,6 +117,28 @@ SoulWarQuest = { { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, }, + areaZones = { + monsters = { + ["zone.claustrophobic-inferno"] = "Brachiodemon", + ["zone.mirrored-nightmare"] = "Many Faces", + ["zone.ebb-and-flow"] = "Bony Sea Devil", + ["zone.furious-crater"] = "Cloak of Terror", + ["zone.rotten-wasteland"] = "Branchy Crawler", + ["boss.goshnar's-malice"] = "Dreadful Harvester", + ["boss.goshnar's-spite"] = "Dreadful Harvester", + ["boss.goshnar's-greed"] = "Dreadful Harvester", + ["boss.goshnar's-hatred"] = "Dreadful Harvester", + ["boss.goshnar's-cruelty"] = "Dreadful Harvester", + ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", + }, + + caustrophobicInferno = Zone("zone.claustrophobic-inferno"), + mirroredNightmare = Zone("zone.mirrored-nightmare"), + ebbAndFlow = Zone("zone.ebb-and-flow"), + furiousCrater = Zone("zone.furious-crater"), + rottenWasteland = Zone("zone.rotten-wasteland"), + }, + -- Levers configuration levers = { goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, @@ -652,6 +682,17 @@ SoulWarQuest = { -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) +-- Initialize bosses access for taint check +SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) + +SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) + +SoulWarQuest.areaZones.furiousCrater:addArea({ x = 33814, y = 31819, z = 3 }, { x = 33907, y = 31920, z = 7 }) + +SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, { x = 33901, y = 31105, z = 12 }) + +SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) + SoulCagePosition = Position(33709, 31596, 14) TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days GreedbeastKills = 0 @@ -674,14 +715,6 @@ local soulWarTaints = { "taints-loss", -- Taint 5 } -SoulWarBosses = { - ["Goshnar's Malice"] = true, - ["Goshnar's Hatred"] = true, - ["Goshnar's Spite"] = true, - ["Goshnar's Cruelty"] = true, - ["Goshnar's Greed"] = true, -} - GreedMonsters = { ["Greedbeast"] = Position(33744, 31666, 14), ["Soulsnatcher"] = Position(33747, 31668, 14), @@ -707,15 +740,6 @@ function CreateGoshnarsGreedMonster(name, position) addEvent(spawnMonster, 10000) end -local soulWarSpawnMonsters = { - ["soulwars.claustrophobic-inferno"] = "Brachiodemon", - ["soulwars.mirrored-nightmare"] = "Many Faces", - ["soulwars.ebb-and-flow"] = "Bony Sea Devil", - ["soulwars.furious-crater"] = "Cloak of Terror", - ["soulwars.rotten-wasteland"] = "Branchy Crawler", - ["boss-rooms"] = "Dreadful Harvester", -} - function RemoveSoulCageAndBuffMalice() local tile = Tile(SoulCagePosition) local creatures = tile:getCreatures() or {} @@ -832,18 +856,41 @@ end local toRevertPositions = {} +local tileItemIds = { + 32906, + 33066, + 33067, + 33068, + 33069, + 33070, +} + local function revertTilesAndApplyDamage(zonePositions) for _, pos in ipairs(zonePositions) do local tile = Tile(pos) - if tile and tile:getGround() and tile:getGround():getId() ~= 409 then - local creature = tile:getTopCreature() - if creature then - local player = creature:getPlayer() - if player then - pos:sendMagicEffect(CONST_ME_REDSMOKE) - player:addHealth(-8000, COMBAT_DEATHDAMAGE) + if tile and tile:getGround() then + if tile:getGround():getId() ~= 409 then + local creature = tile:getTopCreature() + if creature then + local player = creature:getPlayer() + if player then + player:addHealth(-8000, COMBAT_DEATHDAMAGE) + end end end + + local itemFound = false + for i = 1, #tileItemIds do + local item = tile:getItemById(tileItemIds[i]) + if item then + itemFound = true + break + end + end + + if tile:getGround():getId() == 410 and not itemFound and not tile:getItemByTopOrder(1) and not tile:getItemByTopOrder(3) then + pos:sendMagicEffect(CONST_ME_REDSMOKE) + end end end @@ -1010,7 +1057,6 @@ function Monster:tryTeleportToPlayer(sayMessage) local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) local maxDistance = 0 local farthestPlayer = nil - logger.debug("Checking teleport monster for monster {}", self:getName()) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() @@ -1200,7 +1246,7 @@ end function Player:getSoulWarZoneMonster() local zoneMonsterName = nil - for zoneName, monsterName in pairs(soulWarSpawnMonsters) do + for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do local zone = Zone.getByName(zoneName) if zone and zone:isInZone(self:getPosition()) then zoneMonsterName = monsterName From ad4686e1e4a87a88257a06adfbb2e09458d5c462 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:27:31 -0300 Subject: [PATCH 03/31] fix: ebb and flow fixed map --- data-otservbr-global/scripts/lib/quests/soul-war.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index e4fcfe4d4bb..167d33eddc8 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -344,6 +344,7 @@ SoulWarQuest = { mapsPath = { empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", + ebbFlow = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm", }, -- In Minutes @@ -1060,12 +1061,12 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1) ~= nil then + if player:getTaintNameByNumber(1) then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance farthestPlayer = player - logger.debug("Found player {} to teleport", player:getName()) + logger.trace("Found player {} to teleport", player:getName()) end end end From 85fcab6c032ed54304beb7ad7b1f4462169ea67e Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:48:04 -0300 Subject: [PATCH 04/31] fix: simplify some functions, logs to trace and map fixes --- .../scripts/lib/quests/soul-war.lua | 81 ++++++------------- 1 file changed, 24 insertions(+), 57 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index 167d33eddc8..4a8a47ee131 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -242,7 +242,7 @@ SoulWarQuest = { timeToFightAgain = 20 * 60 * 60, -- 20 hours onUseExtra = function(player) SoulWarQuest.kvBurning:set("time", 180) - logger.debug("Goshnar's Hatred burning change form time set to: {}", 180) + logger.trace("Goshnar's Hatred burning change form time set to: {}", 180) player:resetGoshnarSymbolTormentCounter() end, }, @@ -378,7 +378,7 @@ SoulWarQuest = { SoulWarQuest.ebbAndFlow.reloadZone() local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() for _, player in ipairs(players) do - logger.debug("Updating player: {}", player:getName()) + logger.trace("Updating player: {}", player:getName()) player:sendCreatureAppear() end end @@ -731,7 +731,7 @@ function CreateGoshnarsGreedMonster(name, position) local function spawnMonster() Game.createMonster(name, position, true, false) - logger.debug("Spawning {} in position {}", name, position:toString()) + logger.trace("Spawning {} in position {}", name, position:toString()) end for i = 7, 9 do @@ -742,39 +742,13 @@ function CreateGoshnarsGreedMonster(name, position) end function RemoveSoulCageAndBuffMalice() - local tile = Tile(SoulCagePosition) - local creatures = tile:getCreatures() or {} - local soulCage - for i, creature in ipairs(creatures) do - if creature:getName() == "Soul Cage" then - soulCage = creature - logger.debug("Removing Soul Cage, the players not be able to kill him") - break - end - end - - local rangeX = 20 - local rangeY = 20 - local spectators = Game.getSpectators(Position(33709, 31599, 14), false, false, rangeX, rangeX, rangeY, rangeY) + local soulCage = Creature("Soul Cage") if soulCage then - local malice - for i = 1, #spectators do - logger.debug("Specs found {}", i) - if spectators[i]:isMonster() then - logger.debug("Malice Spectators {}", spectators[i]:getName()) - if spectators[i]:getName() == "Goshnar's Malice" then - logger.debug("Found malice") - malice = Monster(spectators[i]) - break - end - end - end - soulCage:remove() addEvent(SpawnSoulCage, 23000) - + local malice = Creature("Goshnar's Malice") if malice then - logger.debug("Found malice, try adding reflect and defense") + logger.trace("Found malice, try adding reflect and defense") for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do malice:addReflectElement(elementType, reflectPercent) end @@ -786,17 +760,10 @@ end function SpawnSoulCage() local tile = Tile(SoulCagePosition) local creatures = tile:getCreatures() or {} - local soulCage - for i, creature in ipairs(creatures) do - if creature:getName() == "Soul Cage" then - soulCage = true - break - end - end - + local soulCage = Creature("Soul Cage") if not soulCage then Game.createMonster("Soul Cage", SoulCagePosition, true, true) - logger.debug("Spawning Soul Cage in position {}", SoulCagePosition:toString()) + logger.trace("Spawning Soul Cage in position {}", SoulCagePosition:toString()) addEvent(RemoveSoulCageAndBuffMalice, 40000) end end @@ -966,7 +933,7 @@ function Monster:generateBagYouDesireLoot(player) -- Calculates the chances based on the number of taints local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - logger.debug("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) -- Generate loot local loot = {} if math.random(1, 100) <= totalChance then @@ -1075,14 +1042,14 @@ function Monster:tryTeleportToPlayer(sayMessage) if farthestPlayer and math.random(100) <= 10 then local playerPosition = farthestPlayer:getPosition() if TaintTeleportCooldown[farthestPlayer:getId()] then - logger.debug("Cooldown is active to player {}", farthestPlayer:getName()) + logger.trace("Cooldown is active to player {}", farthestPlayer:getName()) return end if not TaintTeleportCooldown[farthestPlayer:getId()] then TaintTeleportCooldown[farthestPlayer:getId()] = true - logger.debug("Scheduling player {} to teleport", farthestPlayer:getName()) + logger.trace("Scheduling player {} to teleport", farthestPlayer:getName()) self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) addEvent(function(playerId, monsterId) @@ -1105,7 +1072,7 @@ function Monster:tryTeleportToPlayer(sayMessage) return end - logger.debug("Cleaning player cooldown") + logger.trace("Cleaning player cooldown") TaintTeleportCooldown[playerEvent:getId()] = nil end, 10000, farthestPlayer:getId()) end @@ -1138,7 +1105,7 @@ function Position:increaseNecromaticMegalomaniaStrength() if boss then boss:increaseHatredDamageMultiplier(5) item:remove() - logger.debug("Necromantic remains strength increased") + logger.trace("Necromantic remains strength increased") end end end @@ -1170,14 +1137,14 @@ function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetwee end lastExecutionTime = interval - logger.debug("Icon time count {}", interval) + logger.trace("Icon time count {}", interval) local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) for i = 1, #spectators do local player = spectators[i] local tormentCounter = player:getGoshnarSymbolTormentCounter() if tormentCounter <= maxLimit then player:increaseGoshnarSymbolTormentCounter(maxLimit) - logger.debug("Player {} has {} damage counter", player:getName(), tormentCounter) + logger.trace("Player {} has {} damage counter", player:getName(), tormentCounter) if tormentCounter > 0 then local damage = tormentCounter * 35 @@ -1185,7 +1152,7 @@ function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetwee damage = damageTable[tormentCounter - 23] end - logger.debug("Final damage {}", damage) + logger.trace("Final damage {}", damage) player:addHealth(-damage, COMBAT_DEATHDAMAGE) player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) end @@ -1209,19 +1176,19 @@ function Monster:increaseAspectOfPowerDeathCount() local bossKV = self:getSoulWarKV() local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 local newCount = aspectDeathCount + 1 - logger.debug("Aspect of Power death count {}", newCount) + logger.trace("Aspect of Power death count {}", newCount) bossKV:set("aspect-of-power-death-count", newCount) if newCount == 4 then self:setType("Goshnar's Megalomania Green") self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") bossKV:set("aspect-of-power-death-count", 0) - logger.debug("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") + logger.trace("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") SoulWarQuest.changePurpleEvent = addEvent(function() local boss = Creature("Goshnar's Megalomania") if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then boss:setType("Goshnar's Megalomania Purple") boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") - logger.debug("Megalomania is now immune again") + logger.trace("Megalomania is now immune again") end end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) end @@ -1233,15 +1200,15 @@ function Monster:goshnarsDefenseIncrease(kvName) local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 -- Checks if more than config time have passed since the item was last used. if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then - logger.debug("{} old defense {}", self:getName(), self:getDefense()) + logger.trace("{} old defense {}", self:getName(), self:getDefense()) self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) - logger.debug("{} new defense {}", self:getName(), self:getDefense()) + logger.trace("{} new defense {}", self:getName(), self:getDefense()) --- Updates the KV to reflect the timing of the increase to maintain control. SoulWarQuest.kvSoulWar:set(kvName, currentTime) else -- If config time have not passed, logs the increase has been skipped. - logger.debug("{} skips increase cooldown due to recent item use.", self:getName()) + logger.trace("{} skips increase cooldown due to recent item use.", self:getName()) end end @@ -1267,11 +1234,11 @@ function Player:isInBoatSpot() groundId = tile:getGround():getId() end if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then - logger.debug("Player {} is in boat spot", self:getName()) + logger.trace("Player {} is in boat spot", self:getName()) return true end - logger.debug("Player {} is not in boat spot", self:getName()) + logger.trace("Player {} is not in boat spot", self:getName()) return false end From a84b216721c2c6cd83f49e2be93b56721e0c0f09 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 15 Apr 2024 18:45:29 -0300 Subject: [PATCH 05/31] fix: add condition for taint icon --- .../scripts/lib/quests/soul-war.lua | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index 4a8a47ee131..7ebe42b0441 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -970,11 +970,11 @@ end TaintTeleportCooldown = {} -function Player:getTaintNameByNumber(taintNumber) +function Player:getTaintNameByNumber(taintNumber, skipKvCheck) local haveTaintName = nil local soulWarQuest = self:soulWarQuestKV() local taintName = soulWarTaints[taintNumber] - if taintName and soulWarQuest:get(taintName) then + if skipKvCheck or taintName and soulWarQuest:get(taintName) then haveTaintName = taintName end @@ -983,15 +983,29 @@ end function Player:addNextTaint() local soulWarQuest = self:soulWarQuestKV() - for _, taint in ipairs(soulWarTaints) do - if not soulWarQuest:get(taint) then - soulWarQuest:set(taint, true) - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taint .. ".") + for _, taintName in ipairs(soulWarTaints) do + if not soulWarQuest:get(taintName) then + soulWarQuest:set(taintName, true) + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taintName .. ".") + self:setTaintIcon() break end end end +function Player:setTaintIcon(taintId) + self:resetTaintConditions() + local condition = Condition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, taintId or self:getTaintLevel()) + condition:setTicks(14 * 24 * 60 * 60 * 1000) + self:addCondition(condition) +end + +function Player:resetTaintConditions() + for i = 1, 5 do + self:removeCondition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, i) + end +end + function Player:getTaintLevel() local taintLevel = nil local soulWarQuest = self:soulWarQuestKV() @@ -1004,17 +1018,17 @@ function Player:getTaintLevel() return taintLevel end -function Player:resetTaints() +function Player:resetTaints(skipCheckTime) local soulWarQuest = self:soulWarQuestKV() local firstTaintTime = soulWarQuest:get("firstTaintTime") - if firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then - -- Reset all taints - for _, taint in ipairs(soulWarTaints) do - if soulWarQuest:get(taint) then - soulWarQuest:remove(taint) + if skipCheckTime or firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then + -- Reset all taints and remove condition + for _, taintName in ipairs(soulWarTaints) do + if soulWarQuest:get(taintName) then + soulWarQuest:remove(taintName) end end - + self:resetTaintConditions() soulWarQuest:remove("firstTaintTime") self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") end @@ -1028,7 +1042,7 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1) then + if player:getTaintNameByNumber(1, true) then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance From 9cfb4e303646d0f8c888aa684ae3125f476d9b33 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Tue, 16 Apr 2024 10:10:18 -0300 Subject: [PATCH 06/31] fix: change soul war table to lib folder --- .../scripts/lib/quests/soul-war.lua | 1371 ----------------- 1 file changed, 1371 deletions(-) delete mode 100644 data-otservbr-global/scripts/lib/quests/soul-war.lua diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua deleted file mode 100644 index 7ebe42b0441..00000000000 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ /dev/null @@ -1,1371 +0,0 @@ -SoulWarQuest = { - -- Item ids - -- Goshnar's Hatred - bagYouDesireItemId = 34109, - goshnarsHatredSorrowId = 33793, - condensedRemorseId = 33792, - -- Goshnar's Spite - weepingSoulCorpseId = 33876, - searingFireId = 33877, - -- Goshnar's Cruelty - pulsatingEnergyId = 34005, - greedyMawId = 33890, - someMortalEssenceId = 33891, - theBloodOfCloakTerrorIds = { 33854, 34006, 34007 }, - -- Goshnar's Megalomania - deadAspectOfPowerCorpseId = 33949, - cleansedSanityItemId = 33950, - necromanticRemainsItemId = 33984, - - poolDamagePercentages = { - [33854] = 0.20, -- 20% of maximum health for the largest pool - [34006] = 0.15, -- 15% for a medium-sized pool - [34007] = 0.10, -- 10% for the smallest pool - }, - - timeToIncreaseCrueltyDefense = 15, -- In seconds, it will increase every 15 seconds if don't use mortal essence in greedy maw - useGreedMawCooldown = 30, -- In seconds - goshnarsCrueltyDefenseChange = 2, -- Defense change, the amount that will decrease or increase defense, the defense cannot decrease more than the monster's original defense amount - goshnarsCrueltyWaveInterval = 7, -- In seconds - - timeToReturnImmuneMegalomania = 70, -- In seconds - - baseBagYouDesireChance = 1, -- 1% base chance - bagYouDesireChancePerTaint = 1, -- Increases 1% per taint - bagYouDesireMonsters = { - "Bony Sea Devil", - "Brachiodemon", - "Branchy Crawler", - "Capricious Phantom", - "Cloak Of Terror", - "Courage Leech", - "Distorted Phantom", - "Druid's Apparition", - "Infernal Demon", - "Infernal Phantom", - "Knight's Apparition", - "Many Faces", - "Mould Phantom", - "Paladin's Apparition", - "Rotten Golem", - "Sorcerer's Apparition", - "Turbulent Elemental", - "Vibrant Phantom.", - }, - bagYouDesireBosses = { - "Goshnar's Cruelty", - "Goshnar's Spite", - "Goshnar's Malice", - "Goshnar's Hatred", - "Goshnar's Greed", - }, - - -- Goshnar's Cruelty pulsating energy monsters - pulsatingEnergyMonsters = { - "Vibrant Phantom", - "Cloak of Terror", - "Courage Leech", - }, - - miniBosses = { - ["Goshnar's Malice"] = true, - ["Goshnar's Hatred"] = true, - ["Goshnar's Spite"] = true, - ["Goshnar's Cruelty"] = true, - ["Goshnar's Greed"] = true, - }, - - finalRewards = { - { id = 34082, name = "soulcutter" }, - { id = 34083, name = "soulshredder" }, - { id = 34084, name = "soulbiter" }, - { id = 34085, name = "souleater" }, - { id = 34086, name = "soulcrusher" }, - { id = 34087, name = "soulmaimer" }, - { id = 34088, name = "soulbleeder" }, - { id = 34089, name = "soulpiercer" }, - { id = 34090, name = "soultainter" }, - { id = 34091, name = "soulhexer" }, - { id = 34092, name = "soulshanks" }, - { id = 34093, name = "soulstrider" }, - { id = 34094, name = "soulshell" }, - { id = 34095, name = "soulmantel" }, - { id = 34096, name = "soulshroud" }, - { id = 34097, name = "pair of soulwalkers" }, - { id = 34098, name = "pair of soulstalkers" }, - { id = 34099, name = "soulbastion" }, - }, - - kvSoulWar = KV.scoped("quest"):scoped("soul-war"), - -- Global KV for storage burning change form time - kvBurning = KV.scoped("quest"):scoped("soul-war"):scoped("burning-change-form"), - - rottenWastelandShrines = { - [33019] = { x = 33926, y = 31091, z = 13 }, - [33021] = { x = 33963, y = 31078, z = 13 }, - [33022] = { x = 33970, y = 30988, z = 13 }, - [33024] = { x = 33970, y = 31012, z = 13 }, - }, - - -- Lever room and teleports positions - goshnarsGreedAccessPosition = { from = { x = 33937, y = 31217, z = 11 }, to = { x = 33782, y = 31665, z = 14 } }, - goshnarsHatredAccessPosition = { from = { x = 33914, y = 31032, z = 12 }, to = { x = 33774, y = 31604, z = 14 } }, - -- Teleports from 1st/2nd/3rd floors - goshnarsCrueltyTeleportRoomPositions = { - { from = Position(33889, 31873, 3), to = Position(33830, 31881, 4), access = "first-floor-access", count = 40 }, - { from = Position(33829, 31880, 4), to = Position(33856, 31889, 5), access = "second-floor-access", count = 55 }, - { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, - }, - - areaZones = { - monsters = { - ["zone.claustrophobic-inferno"] = "Brachiodemon", - ["zone.mirrored-nightmare"] = "Many Faces", - ["zone.ebb-and-flow"] = "Bony Sea Devil", - ["zone.furious-crater"] = "Cloak of Terror", - ["zone.rotten-wasteland"] = "Branchy Crawler", - ["boss.goshnar's-malice"] = "Dreadful Harvester", - ["boss.goshnar's-spite"] = "Dreadful Harvester", - ["boss.goshnar's-greed"] = "Dreadful Harvester", - ["boss.goshnar's-hatred"] = "Dreadful Harvester", - ["boss.goshnar's-cruelty"] = "Dreadful Harvester", - ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", - }, - - caustrophobicInferno = Zone("zone.claustrophobic-inferno"), - mirroredNightmare = Zone("zone.mirrored-nightmare"), - ebbAndFlow = Zone("zone.ebb-and-flow"), - furiousCrater = Zone("zone.furious-crater"), - rottenWasteland = Zone("zone.rotten-wasteland"), - }, - - -- Levers configuration - levers = { - goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, - goshnarsSpitePosition = { x = 33773, y = 31634, z = 14 }, - goshnarsGreedPosition = { x = 33775, y = 31665, z = 14 }, - goshnarsHatredPosition = { x = 33772, y = 31601, z = 14 }, - goshnarsCrueltyPosition = { x = 33853, y = 31854, z = 6 }, - goshnarsMegalomaniaPosition = { x = 33675, y = 31634, z = 14 }, - - -- Levers system - goshnarsSpite = { - boss = { - name = "Goshnar's Spite", - position = Position(33743, 31632, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33774, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33775, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33776, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33778, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33734, 31624, 14), - to = Position(33751, 31640, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsMalice = { - boss = { - name = "Goshnar's Malice", - position = Position(33709, 31599, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33679, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33680, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33681, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33682, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33683, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33699, 31590, 14), - to = Position(33718, 31607, 14), - }, - onUseExtra = function(player) - addEvent(SpawnSoulCage, 23000) - end, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsGreed = { - boss = { - name = "Goshnar's Greed", - position = Position(33746, 31666, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33776, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33778, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33779, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33780, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33737, 31658, 14), - to = Position(33755, 31673, 14), - }, - timeToFightAgain = 0, -- TODO: Remove later - onUseExtra = function() - CreateGoshnarsGreedMonster("Greedbeast", Position(33744, 31666, 14)) - CreateGoshnarsGreedMonster("Soulsnatcher", Position(33747, 31668, 14)) - CreateGoshnarsGreedMonster("Weak Soul", Position(33750, 31666, 14)) - end, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsHatred = { - boss = { - name = "Goshnar's Hatred", - position = Position(33744, 31599, 14), - }, - monsters = { - { name = "Ashes of Burning Hatred", pos = { x = 33743, y = 31599, z = 14 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33773, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33774, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33775, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33776, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33735, 31592, 14), - to = Position(33751, 31606, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - onUseExtra = function(player) - SoulWarQuest.kvBurning:set("time", 180) - logger.trace("Goshnar's Hatred burning change form time set to: {}", 180) - player:resetGoshnarSymbolTormentCounter() - end, - }, - goshnarsCruelty = { - boss = { - name = "Goshnar's Cruelty", - position = Position(33856, 31866, 7), - }, - monsters = { - { name = "A Greedy Eye", pos = { x = 33856, y = 31858, z = 7 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33854, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33855, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33856, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33857, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33858, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33847, 31858, 7), - to = Position(33864, 31874, 7), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - onUseExtra = function(player) - SoulWarQuest.kvSoulWar:remove("greedy-maw-action") - player:soulWarQuestKV():scoped("furious-crater"):remove("greedy-maw-action") - end, - }, - goshnarsMegalomania = { - boss = { - name = "Goshnar's Megalomania Purple", - position = Position(33710, 31634, 14), - }, - monsters = { - { name = "Aspect of Power", pos = { x = 33710, y = 31635, z = 14 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33676, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33677, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33678, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33679, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33680, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33701, 31626, 14), - to = Position(33719, 31642, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 72 * 60 * 60, -- 72 hours - onUseExtra = function(player) - player:resetGoshnarSymbolTormentCounter() - SoulWarQuest.kvSoulWar:remove("cleansed-sanity-action") - player:soulWarQuestKV():scoped("furious-crater"):remove("cleansed-sanity-action") - end, - }, - }, - - -- Goshnar's Greed - apparitionNames = { - "Druid's Apparition", - "Knight's Apparition", - "Paladin's Apparition", - "Sorcerer's Apparition", - }, - - burningTransformations = { - { 180, "Ashes of Burning Hatred" }, - { 135, "Spark of Burning Hatred" }, - { 90, "Flame of Burning Hatred" }, - { 45, "Blaze of Burning Hatred" }, - }, - - requiredCountPerApparition = 25, - - -- Ebb and flow - ebbAndFlow = { - zone = Zone("ebb-and-flow-zone"), - -- Positions to teleport into rooms when innundate map is loaded - centerRoomPositions = { - { conor = { x = 33929, y = 31020, z = 9 }, teleportPosition = { x = 33939, y = 31021, z = 8 } }, - { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33918, y = 31047, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, - { conor = { x = 33898, y = 31054, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, - { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33940, y = 31054, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33940, y = 31064, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, - { conor = { x = 33937, y = 31086, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, - { conor = { x = 33937, y = 31098, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33933, y = 31109, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33921, y = 31113, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33912, y = 31113, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, - { conor = { x = 33901, y = 31108, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, - { conor = { x = 33901, y = 31098, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, - { conor = { x = 33899, y = 31064, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, - }, - mapsPath = { - empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", - inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", - ebbFlow = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm", - }, - - -- In Minutes - intervalChangeMap = 2, - waitPosition = Position(33893, 31020, 8), - - getZone = function() - return SoulWarQuest.ebbAndFlow.zone - end, - - reloadZone = function() - SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) - end, - - kv = KV.scoped("quest"):scoped("soul-war"):scoped("ebb-and-flow-maps"), - isActive = function() - return SoulWarQuest.ebbAndFlow.kv:get("is-active") - end, - isLoadedEmptyMap = function() - return SoulWarQuest.ebbAndFlow.kv:get("is-loaded-empty-map") - end, - setActive = function(value) - SoulWarQuest.ebbAndFlow.kv:set("is-active", value) - end, - setLoadedEmptyMap = function(value) - SoulWarQuest.ebbAndFlow.kv:set("is-loaded-empty-map", value) - end, - - updateZonePlayers = function() - if SoulWarQuest.ebbAndFlow.zone and SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then - SoulWarQuest.ebbAndFlow.reloadZone() - local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() - for _, player in ipairs(players) do - logger.trace("Updating player: {}", player:getName()) - player:sendCreatureAppear() - end - end - end, - - -- Add here more positions of the pools that must transform before innundate map is loaded - poolPositions = { - { x = 33906, y = 31026, z = 9 }, - { x = 33901, y = 31026, z = 9 }, - { x = 33932, y = 31011, z = 9 }, - { x = 33941, y = 31033, z = 9 }, - { x = 33946, y = 31037, z = 9 }, - { x = 33939, y = 31056, z = 9 }, - }, - - boatId = 7272, - doorId = 33767, - smallPoolId = 33772, - MediumPoolId = 33773, - }, - - changeBlueEvent = nil, - changePurpleEvent = nil, - - changeMegalomaniaBlue = function() - local boss = Creature("Goshnar's Megalomania") - if boss then - boss:teleportTo(SoulWarQuest.levers.goshnarsMegalomania.boss.position) - boss:say("ENOUGH! I WILL MAKE YOU SUFFER FOR YOUR INSOLENCE! NOW - I - WILL - ANIHILATE - YOU!") - boss:setType("Goshnar's Megalomania Blue") - local function changeBack() - boss:setType("Goshnar's Megalomania Purple") - end - - changePurpleEvent = addEvent(changeBack, 7000) - end - end, - - -- Chance to heal the life of the monster by stepping on the corpse of "weeping soul" - goshnarsSpiteHealChance = 10, - -- Percentage that will heal by stepping and the chance is successful - goshnarsSpiteHealPercentage = 10, - - goshnarSpiteEntrancePosition = { fromPos = Position(33950, 31109, 8), toPos = Position(33780, 31634, 14) }, - - waterElementalOutfit = { - lookType = 286, - lookHead = 0, - lookBody = 0, - lookLegs = 0, - lookFeet = 0, - lookAddons = 0, - lookMount = 0, - }, - - goshnarsSpiteFirePositions = { - -- North - { x = 33743, y = 31628, z = 14 }, - -- East - { x = 33736, y = 31632, z = 14 }, - -- West - { x = 33750, y = 31632, z = 14 }, - -- South - { x = 33742, y = 31637, z = 14 }, - }, - - -- Increased defense if the searing fire disappears - goshnarsSpiteIncreaseDefense = 10, - -- Count of monsters to kill for enter in the boss room - hardozousPanthomDeathCount = 20, - -- Time to fire created again - timeToCreateSearingFire = 14, -- In seconds - -- Time to remove the searing fire if player don't step on it - timeToRemoveSearingFire = 5, -- In seconds - cooldownToStepOnSearingFire = 56, -- In seconds (14 seconds x 4) - - -- Positions to teleport into rooms when innundate map is loaded - ebbAndFlowBoatTeleportPositions = { - -- First boat - -- Enter on boat - { register = { x = 33919, y = 31019, z = 8 }, teleportTo = { x = 33923, y = 31019, z = 8 } }, - { register = { x = 33919, y = 31020, z = 8 }, teleportTo = { x = 33923, y = 31020, z = 8 } }, - { register = { x = 33919, y = 31021, z = 8 }, teleportTo = { x = 33923, y = 31021, z = 8 } }, - { register = { x = 33919, y = 31022, z = 8 }, teleportTo = { x = 33923, y = 31022, z = 8 } }, - -- Back to innitial room - { register = { x = 33922, y = 31019, z = 8 }, teleportTo = { x = 33918, y = 31019, z = 8 } }, - { register = { x = 33922, y = 31020, z = 8 }, teleportTo = { x = 33918, y = 31020, z = 8 } }, - { register = { x = 33922, y = 31021, z = 8 }, teleportTo = { x = 33918, y = 31021, z = 8 } }, - { register = { x = 33922, y = 31022, z = 8 }, teleportTo = { x = 33918, y = 31022, z = 8 } }, - -- From boat to room - { register = { x = 33926, y = 31019, z = 8 }, teleportTo = { x = 33930, y = 31019, z = 8 } }, - { register = { x = 33926, y = 31020, z = 8 }, teleportTo = { x = 33930, y = 31020, z = 8 } }, - { register = { x = 33926, y = 31021, z = 8 }, teleportTo = { x = 33930, y = 31021, z = 8 } }, - { register = { x = 33926, y = 31022, z = 8 }, teleportTo = { x = 33930, y = 31022, z = 8 } }, - -- From room to boat - { register = { x = 33929, y = 31019, z = 8 }, teleportTo = { x = 33925, y = 31019, z = 8 } }, - { register = { x = 33929, y = 31020, z = 8 }, teleportTo = { x = 33925, y = 31020, z = 8 } }, - { register = { x = 33929, y = 31021, z = 8 }, teleportTo = { x = 33925, y = 31021, z = 8 } }, - { register = { x = 33929, y = 31022, z = 8 }, teleportTo = { x = 33925, y = 31022, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33929, y = 31045, z = 8 }, teleportTo = { x = 33925, y = 31045, z = 8 } }, - { register = { x = 33929, y = 31046, z = 8 }, teleportTo = { x = 33925, y = 31046, z = 8 } }, - { register = { x = 33929, y = 31047, z = 8 }, teleportTo = { x = 33925, y = 31047, z = 8 } }, - { register = { x = 33929, y = 31048, z = 8 }, teleportTo = { x = 33925, y = 31048, z = 8 } }, - -- Back to room - { register = { x = 33926, y = 31045, z = 8 }, teleportTo = { x = 33930, y = 31045, z = 8 } }, - { register = { x = 33926, y = 31046, z = 8 }, teleportTo = { x = 33930, y = 31046, z = 8 } }, - { register = { x = 33926, y = 31047, z = 8 }, teleportTo = { x = 33930, y = 31047, z = 8 } }, - { register = { x = 33926, y = 31048, z = 8 }, teleportTo = { x = 33930, y = 31048, z = 8 } }, - -- From boat to room - { register = { x = 33922, y = 31045, z = 8 }, teleportTo = { x = 33918, y = 31045, z = 8 } }, - { register = { x = 33922, y = 31046, z = 8 }, teleportTo = { x = 33918, y = 31046, z = 8 } }, - { register = { x = 33922, y = 31047, z = 8 }, teleportTo = { x = 33918, y = 31047, z = 8 } }, - { register = { x = 33922, y = 31048, z = 8 }, teleportTo = { x = 33918, y = 31048, z = 8 } }, - -- From room to boat - { register = { x = 33919, y = 31045, z = 8 }, teleportTo = { x = 33923, y = 31045, z = 8 } }, - { register = { x = 33919, y = 31046, z = 8 }, teleportTo = { x = 33923, y = 31046, z = 8 } }, - { register = { x = 33919, y = 31047, z = 8 }, teleportTo = { x = 33923, y = 31047, z = 8 } }, - { register = { x = 33919, y = 31048, z = 8 }, teleportTo = { x = 33923, y = 31048, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33896, y = 31055, z = 8 }, teleportTo = { x = 33896, y = 31059, z = 8 } }, - { register = { x = 33897, y = 31055, z = 8 }, teleportTo = { x = 33897, y = 31059, z = 8 } }, - { register = { x = 33898, y = 31055, z = 8 }, teleportTo = { x = 33898, y = 31059, z = 8 } }, - { register = { x = 33899, y = 31055, z = 8 }, teleportTo = { x = 33899, y = 31059, z = 8 } }, - { register = { x = 33900, y = 31055, z = 8 }, teleportTo = { x = 33900, y = 31059, z = 8 } }, - { register = { x = 33901, y = 31055, z = 8 }, teleportTo = { x = 33901, y = 31059, z = 8 } }, - -- Back to room - { register = { x = 33896, y = 31058, z = 8 }, teleportTo = { x = 33896, y = 31054, z = 8 } }, - { register = { x = 33897, y = 31058, z = 8 }, teleportTo = { x = 33897, y = 31054, z = 8 } }, - { register = { x = 33898, y = 31058, z = 8 }, teleportTo = { x = 33898, y = 31054, z = 8 } }, - { register = { x = 33899, y = 31058, z = 8 }, teleportTo = { x = 33899, y = 31054, z = 8 } }, - { register = { x = 33900, y = 31058, z = 8 }, teleportTo = { x = 33900, y = 31054, z = 8 } }, - { register = { x = 33901, y = 31058, z = 8 }, teleportTo = { x = 33901, y = 31054, z = 8 } }, - -- From boat to room - { register = { x = 33896, y = 31061, z = 8 }, teleportTo = { x = 33896, y = 31065, z = 8 } }, - { register = { x = 33897, y = 31061, z = 8 }, teleportTo = { x = 33897, y = 31065, z = 8 } }, - { register = { x = 33898, y = 31061, z = 8 }, teleportTo = { x = 33898, y = 31065, z = 8 } }, - { register = { x = 33899, y = 31061, z = 8 }, teleportTo = { x = 33899, y = 31065, z = 8 } }, - { register = { x = 33900, y = 31061, z = 8 }, teleportTo = { x = 33900, y = 31065, z = 8 } }, - { register = { x = 33901, y = 31061, z = 8 }, teleportTo = { x = 33901, y = 31065, z = 8 } }, - -- From room to boat - { register = { x = 33896, y = 31064, z = 8 }, teleportTo = { x = 33896, y = 31060, z = 8 } }, - { register = { x = 33897, y = 31064, z = 8 }, teleportTo = { x = 33897, y = 31060, z = 8 } }, - { register = { x = 33898, y = 31064, z = 8 }, teleportTo = { x = 33898, y = 31060, z = 8 } }, - { register = { x = 33899, y = 31064, z = 8 }, teleportTo = { x = 33899, y = 31060, z = 8 } }, - { register = { x = 33900, y = 31064, z = 8 }, teleportTo = { x = 33900, y = 31060, z = 8 } }, - { register = { x = 33901, y = 31064, z = 8 }, teleportTo = { x = 33901, y = 31060, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33899, y = 31099, z = 8 }, teleportTo = { x = 33899, y = 31103, z = 8 } }, - { register = { x = 33900, y = 31099, z = 8 }, teleportTo = { x = 33900, y = 31103, z = 8 } }, - { register = { x = 33901, y = 31099, z = 8 }, teleportTo = { x = 33901, y = 31103, z = 8 } }, - { register = { x = 33902, y = 31099, z = 8 }, teleportTo = { x = 33902, y = 31103, z = 8 } }, - { register = { x = 33903, y = 31099, z = 8 }, teleportTo = { x = 33903, y = 31103, z = 8 } }, - { register = { x = 33904, y = 31099, z = 8 }, teleportTo = { x = 33904, y = 31103, z = 8 } }, - { register = { x = 33905, y = 31099, z = 8 }, teleportTo = { x = 33905, y = 31103, z = 8 } }, - -- Back from boat to room - { register = { x = 33899, y = 31102, z = 8 }, teleportTo = { x = 33899, y = 31098, z = 8 } }, - { register = { x = 33900, y = 31102, z = 8 }, teleportTo = { x = 33900, y = 31098, z = 8 } }, - { register = { x = 33901, y = 31102, z = 8 }, teleportTo = { x = 33901, y = 31098, z = 8 } }, - { register = { x = 33902, y = 31102, z = 8 }, teleportTo = { x = 33902, y = 31098, z = 8 } }, - { register = { x = 33903, y = 31102, z = 8 }, teleportTo = { x = 33903, y = 31098, z = 8 } }, - { register = { x = 33904, y = 31102, z = 8 }, teleportTo = { x = 33904, y = 31098, z = 8 } }, - { register = { x = 33905, y = 31102, z = 8 }, teleportTo = { x = 33905, y = 31098, z = 8 } }, - -- From boat to room - { register = { x = 33899, y = 31105, z = 8 }, teleportTo = { x = 33899, y = 31109, z = 8 } }, - { register = { x = 33900, y = 31105, z = 8 }, teleportTo = { x = 33900, y = 31109, z = 8 } }, - { register = { x = 33901, y = 31105, z = 8 }, teleportTo = { x = 33901, y = 31109, z = 8 } }, - { register = { x = 33902, y = 31105, z = 8 }, teleportTo = { x = 33902, y = 31109, z = 8 } }, - { register = { x = 33903, y = 31105, z = 8 }, teleportTo = { x = 33903, y = 31109, z = 8 } }, - { register = { x = 33904, y = 31105, z = 8 }, teleportTo = { x = 33904, y = 31109, z = 8 } }, - { register = { x = 33905, y = 31105, z = 8 }, teleportTo = { x = 33905, y = 31109, z = 8 } }, - -- From room to boat - { register = { x = 33899, y = 31108, z = 8 }, teleportTo = { x = 33899, y = 31104, z = 8 } }, - { register = { x = 33900, y = 31108, z = 8 }, teleportTo = { x = 33900, y = 31104, z = 8 } }, - { register = { x = 33901, y = 31108, z = 8 }, teleportTo = { x = 33901, y = 31104, z = 8 } }, - { register = { x = 33902, y = 31108, z = 8 }, teleportTo = { x = 33902, y = 31104, z = 8 } }, - { register = { x = 33903, y = 31108, z = 8 }, teleportTo = { x = 33903, y = 31104, z = 8 } }, - { register = { x = 33904, y = 31108, z = 8 }, teleportTo = { x = 33904, y = 31104, z = 8 } }, - { register = { x = 33905, y = 31108, z = 8 }, teleportTo = { x = 33905, y = 31104, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33913, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, - { register = { x = 33913, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, - { register = { x = 33913, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, - { register = { x = 33913, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, - { register = { x = 33913, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, - -- Back to room - { register = { x = 33916, y = 31112, z = 8 }, teleportTo = { x = 33912, y = 31112, z = 8 } }, - { register = { x = 33916, y = 31113, z = 8 }, teleportTo = { x = 33912, y = 31113, z = 8 } }, - { register = { x = 33916, y = 31114, z = 8 }, teleportTo = { x = 33912, y = 31114, z = 8 } }, - { register = { x = 33916, y = 31115, z = 8 }, teleportTo = { x = 33912, y = 31115, z = 8 } }, - { register = { x = 33916, y = 31116, z = 8 }, teleportTo = { x = 33912, y = 31116, z = 8 } }, - -- From boat to room - { register = { x = 33918, y = 31112, z = 8 }, teleportTo = { x = 33922, y = 31112, z = 8 } }, - { register = { x = 33918, y = 31113, z = 8 }, teleportTo = { x = 33922, y = 31113, z = 8 } }, - { register = { x = 33918, y = 31114, z = 8 }, teleportTo = { x = 33922, y = 31114, z = 8 } }, - { register = { x = 33918, y = 31115, z = 8 }, teleportTo = { x = 33922, y = 31115, z = 8 } }, - { register = { x = 33918, y = 31116, z = 8 }, teleportTo = { x = 33922, y = 31116, z = 8 } }, - -- From room to boat - { register = { x = 33921, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, - { register = { x = 33921, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, - { register = { x = 33921, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, - { register = { x = 33921, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, - { register = { x = 33921, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33936, y = 31087, z = 8 }, teleportTo = { x = 33936, y = 31091, z = 8 } }, - { register = { x = 33937, y = 31087, z = 8 }, teleportTo = { x = 33937, y = 31091, z = 8 } }, - { register = { x = 33938, y = 31087, z = 8 }, teleportTo = { x = 33938, y = 31091, z = 8 } }, - { register = { x = 33939, y = 31087, z = 8 }, teleportTo = { x = 33939, y = 31091, z = 8 } }, - { register = { x = 33940, y = 31087, z = 8 }, teleportTo = { x = 33940, y = 31091, z = 8 } }, - { register = { x = 33941, y = 31087, z = 8 }, teleportTo = { x = 33941, y = 31091, z = 8 } }, - -- Back to room - { register = { x = 33936, y = 31090, z = 8 }, teleportTo = { x = 33936, y = 31086, z = 8 } }, - { register = { x = 33937, y = 31090, z = 8 }, teleportTo = { x = 33937, y = 31086, z = 8 } }, - { register = { x = 33938, y = 31090, z = 8 }, teleportTo = { x = 33938, y = 31086, z = 8 } }, - { register = { x = 33939, y = 31090, z = 8 }, teleportTo = { x = 33939, y = 31086, z = 8 } }, - { register = { x = 33940, y = 31090, z = 8 }, teleportTo = { x = 33940, y = 31086, z = 8 } }, - { register = { x = 33941, y = 31090, z = 8 }, teleportTo = { x = 33941, y = 31086, z = 8 } }, - -- From boat to room - { register = { x = 33936, y = 31095, z = 8 }, teleportTo = { x = 33934, y = 31099, z = 8 } }, - { register = { x = 33937, y = 31095, z = 8 }, teleportTo = { x = 33935, y = 31099, z = 8 } }, - { register = { x = 33938, y = 31095, z = 8 }, teleportTo = { x = 33936, y = 31099, z = 8 } }, - { register = { x = 33939, y = 31095, z = 8 }, teleportTo = { x = 33937, y = 31099, z = 8 } }, - { register = { x = 33940, y = 31095, z = 8 }, teleportTo = { x = 33938, y = 31099, z = 8 } }, - { register = { x = 33941, y = 31095, z = 8 }, teleportTo = { x = 33939, y = 31099, z = 8 } }, - -- From room to boat - { register = { x = 33934, y = 31098, z = 8 }, teleportTo = { x = 33936, y = 31094, z = 8 } }, - { register = { x = 33935, y = 31098, z = 8 }, teleportTo = { x = 33937, y = 31094, z = 8 } }, - { register = { x = 33936, y = 31098, z = 8 }, teleportTo = { x = 33938, y = 31094, z = 8 } }, - { register = { x = 33937, y = 31098, z = 8 }, teleportTo = { x = 33939, y = 31094, z = 8 } }, - { register = { x = 33938, y = 31098, z = 8 }, teleportTo = { x = 33940, y = 31094, z = 8 } }, - { register = { x = 33939, y = 31098, z = 8 }, teleportTo = { x = 33941, y = 31094, z = 8 } }, - { register = { x = 33940, y = 31098, z = 8 }, teleportTo = { x = 33942, y = 31094, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33939, y = 31064, z = 8 }, teleportTo = { x = 33939, y = 31060, z = 8 } }, - { register = { x = 33940, y = 31064, z = 8 }, teleportTo = { x = 33940, y = 31060, z = 8 } }, - { register = { x = 33941, y = 31064, z = 8 }, teleportTo = { x = 33941, y = 31060, z = 8 } }, - { register = { x = 33942, y = 31064, z = 8 }, teleportTo = { x = 33942, y = 31060, z = 8 } }, - { register = { x = 33943, y = 31064, z = 8 }, teleportTo = { x = 33943, y = 31060, z = 8 } }, - { register = { x = 33944, y = 31064, z = 8 }, teleportTo = { x = 33944, y = 31060, z = 8 } }, - -- Back to room - { register = { x = 33939, y = 31061, z = 8 }, teleportTo = { x = 33939, y = 31065, z = 8 } }, - { register = { x = 33940, y = 31061, z = 8 }, teleportTo = { x = 33940, y = 31065, z = 8 } }, - { register = { x = 33941, y = 31061, z = 8 }, teleportTo = { x = 33941, y = 31065, z = 8 } }, - { register = { x = 33942, y = 31061, z = 8 }, teleportTo = { x = 33942, y = 31065, z = 8 } }, - { register = { x = 33943, y = 31061, z = 8 }, teleportTo = { x = 33943, y = 31065, z = 8 } }, - { register = { x = 33944, y = 31061, z = 8 }, teleportTo = { x = 33944, y = 31065, z = 8 } }, - -- From boat to room - { register = { x = 33939, y = 31058, z = 8 }, teleportTo = { x = 33939, y = 31054, z = 8 } }, - { register = { x = 33940, y = 31058, z = 8 }, teleportTo = { x = 33940, y = 31054, z = 8 } }, - { register = { x = 33941, y = 31058, z = 8 }, teleportTo = { x = 33941, y = 31054, z = 8 } }, - { register = { x = 33942, y = 31058, z = 8 }, teleportTo = { x = 33942, y = 31054, z = 8 } }, - { register = { x = 33943, y = 31058, z = 8 }, teleportTo = { x = 33943, y = 31054, z = 8 } }, - { register = { x = 33944, y = 31058, z = 8 }, teleportTo = { x = 33944, y = 31054, z = 8 } }, - -- From room to boat - { register = { x = 33939, y = 31055, z = 8 }, teleportTo = { x = 33939, y = 31059, z = 8 } }, - { register = { x = 33940, y = 31055, z = 8 }, teleportTo = { x = 33940, y = 31059, z = 8 } }, - { register = { x = 33941, y = 31055, z = 8 }, teleportTo = { x = 33941, y = 31059, z = 8 } }, - { register = { x = 33942, y = 31055, z = 8 }, teleportTo = { x = 33942, y = 31059, z = 8 } }, - { register = { x = 33943, y = 31055, z = 8 }, teleportTo = { x = 33943, y = 31059, z = 8 } }, - { register = { x = 33944, y = 31055, z = 8 }, teleportTo = { x = 33944, y = 31059, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33934, y = 31108, z = 8 }, teleportTo = { x = 33938, y = 31108, z = 8 } }, - { register = { x = 33934, y = 31109, z = 8 }, teleportTo = { x = 33938, y = 31109, z = 8 } }, - { register = { x = 33934, y = 31110, z = 8 }, teleportTo = { x = 33938, y = 31110, z = 8 } }, - { register = { x = 33934, y = 31111, z = 8 }, teleportTo = { x = 33938, y = 31111, z = 8 } }, - { register = { x = 33934, y = 31112, z = 8 }, teleportTo = { x = 33938, y = 31112, z = 8 } }, - -- Back to room - { register = { x = 33937, y = 31108, z = 8 }, teleportTo = { x = 33933, y = 31108, z = 8 } }, - { register = { x = 33937, y = 31109, z = 8 }, teleportTo = { x = 33933, y = 31109, z = 8 } }, - { register = { x = 33937, y = 31110, z = 8 }, teleportTo = { x = 33933, y = 31110, z = 8 } }, - { register = { x = 33937, y = 31111, z = 8 }, teleportTo = { x = 33933, y = 31111, z = 8 } }, - { register = { x = 33937, y = 31112, z = 8 }, teleportTo = { x = 33933, y = 31112, z = 8 } }, - -- From boat to room - { register = { x = 33942, y = 31108, z = 8 }, teleportTo = { x = 33946, y = 31108, z = 8 } }, - { register = { x = 33942, y = 31109, z = 8 }, teleportTo = { x = 33946, y = 31109, z = 8 } }, - { register = { x = 33942, y = 31110, z = 8 }, teleportTo = { x = 33946, y = 31110, z = 8 } }, - { register = { x = 33942, y = 31111, z = 8 }, teleportTo = { x = 33946, y = 31111, z = 8 } }, - { register = { x = 33942, y = 31112, z = 8 }, teleportTo = { x = 33946, y = 31112, z = 8 } }, - -- From room to boat - { register = { x = 33945, y = 31108, z = 8 }, teleportTo = { x = 33941, y = 31108, z = 8 } }, - { register = { x = 33945, y = 31109, z = 8 }, teleportTo = { x = 33941, y = 31109, z = 8 } }, - { register = { x = 33945, y = 31110, z = 8 }, teleportTo = { x = 33941, y = 31110, z = 8 } }, - { register = { x = 33945, y = 31111, z = 8 }, teleportTo = { x = 33941, y = 31111, z = 8 } }, - { register = { x = 33945, y = 31112, z = 8 }, teleportTo = { x = 33941, y = 31112, z = 8 } }, - }, -} - --- Initialize ebb and flow zone area -SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) - --- Initialize bosses access for taint check -SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) - -SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) - -SoulWarQuest.areaZones.furiousCrater:addArea({ x = 33814, y = 31819, z = 3 }, { x = 33907, y = 31920, z = 7 }) - -SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, { x = 33901, y = 31105, z = 12 }) - -SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) - -SoulCagePosition = Position(33709, 31596, 14) -TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days -GreedbeastKills = 0 - -SoulWarReflectDamageMap = { - [COMBAT_PHYSICALDAMAGE] = 10, - [COMBAT_FIREDAMAGE] = 10, - [COMBAT_EARTHDAMAGE] = 10, - [COMBAT_ENERGYDAMAGE] = 10, - [COMBAT_ICEDAMAGE] = 10, - [COMBAT_HOLYDAMAGE] = 10, - [COMBAT_DEATHDAMAGE] = 10, -} - -local soulWarTaints = { - "taints-teleport", -- Taint 1 - "taints-spawn", -- Taint 2 - "taints-damage", -- Taint 3 - "taints-heal", -- Taint 4 - "taints-loss", -- Taint 5 -} - -GreedMonsters = { - ["Greedbeast"] = Position(33744, 31666, 14), - ["Soulsnatcher"] = Position(33747, 31668, 14), - ["Weak Soul"] = Position(33750, 31666, 14), - ["Strong Soul"] = Position(33750, 31666, 14), - ["Powerful Soul"] = Position(33750, 31666, 14), -} - -function CreateGoshnarsGreedMonster(name, position) - local function sendEffect() - position:sendMagicEffect(CONST_ME_TELEPORT) - end - - local function spawnMonster() - Game.createMonster(name, position, true, false) - logger.trace("Spawning {} in position {}", name, position:toString()) - end - - for i = 7, 9 do - addEvent(sendEffect, i * 1000) - end - - addEvent(spawnMonster, 10000) -end - -function RemoveSoulCageAndBuffMalice() - local soulCage = Creature("Soul Cage") - if soulCage then - soulCage:remove() - addEvent(SpawnSoulCage, 23000) - local malice = Creature("Goshnar's Malice") - if malice then - logger.trace("Found malice, try adding reflect and defense") - for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do - malice:addReflectElement(elementType, reflectPercent) - end - malice:addDefense(10) - end - end -end - -function SpawnSoulCage() - local tile = Tile(SoulCagePosition) - local creatures = tile:getCreatures() or {} - local soulCage = Creature("Soul Cage") - if not soulCage then - Game.createMonster("Soul Cage", SoulCagePosition, true, true) - logger.trace("Spawning Soul Cage in position {}", SoulCagePosition:toString()) - addEvent(RemoveSoulCageAndBuffMalice, 40000) - end -end - -local function shuffle(list) - for i = #list, 2, -1 do - local j = math.random(i) - list[i], list[j] = list[j], list[i] - end -end - -local function createConnectedGroup(startPos, groupPositions, groupSize) - local group = { startPos } - local lastPos = startPos - local directions = { - { x = 1, y = 0 }, - { x = -1, y = 0 }, -- Right and left - { x = 0, y = 1 }, - { x = 0, y = -1 }, -- Up and down - { x = 1, y = 1 }, - { x = -1, y = -1 }, -- Diagonals - { x = -1, y = 1 }, - { x = 1, y = -1 }, - } - - for i = 2, groupSize do - shuffle(directions) - local nextPos = nil - for _, dir in ipairs(directions) do - local potentialNextPos = Position(lastPos.x + dir.x, lastPos.y + dir.y, lastPos.z) - if table.contains(groupPositions, potentialNextPos) then - nextPos = potentialNextPos - break - end - end - - if nextPos then - table.insert(group, nextPos) - table.remove(groupPositions, table.find(groupPositions, nextPos)) - lastPos = nextPos - else - break - end - end - - return group -end - -local function generatePositionsInRange(center, range) - local positions = {} - for x = center.x - range, center.x + range do - for y = center.y - range, center.y + range do - table.insert(positions, Position(x, y, center.z)) - end - end - return positions -end - -local toRevertPositions = {} - -local tileItemIds = { - 32906, - 33066, - 33067, - 33068, - 33069, - 33070, -} - -local function revertTilesAndApplyDamage(zonePositions) - for _, pos in ipairs(zonePositions) do - local tile = Tile(pos) - if tile and tile:getGround() then - if tile:getGround():getId() ~= 409 then - local creature = tile:getTopCreature() - if creature then - local player = creature:getPlayer() - if player then - player:addHealth(-8000, COMBAT_DEATHDAMAGE) - end - end - end - - local itemFound = false - for i = 1, #tileItemIds do - local item = tile:getItemById(tileItemIds[i]) - if item then - itemFound = true - break - end - end - - if tile:getGround():getId() == 410 and not itemFound and not tile:getItemByTopOrder(1) and not tile:getItemByTopOrder(3) then - pos:sendMagicEffect(CONST_ME_REDSMOKE) - end - end - end - - for posString, itemId in pairs(toRevertPositions) do - local pos = posString:toPosition() - local tile = Tile(pos) - if tile and tile:getGround() and tile:getGround():getId() == 409 then - tile:getGround():transform(itemId) - toRevertPositions[pos:toString()] = nil - end - end -end - -function Monster:createSoulWarWhiteTiles(centerRoomPosition, zonePositions, executeInterval) - local groupPositions = generatePositionsInRange(centerRoomPosition, 7) - local totalTiles = 11 - local groupSize = 3 - local groupsCreated = 0 - - -- Run only for megalomania boss - if executeInterval then - -- Remove remains - for _, pos in ipairs(zonePositions) do - local tile = Tile(pos) - if tile and tile:getGround() then - local remains = tile:getItemById(33984) - if remains then - remains:remove() - end - end - end - end - - while #groupPositions > 0 and groupsCreated * groupSize < totalTiles do - local randomIndex = math.random(#groupPositions) - local startPos = groupPositions[randomIndex] - table.remove(groupPositions, randomIndex) - - local group = createConnectedGroup(startPos, groupPositions, groupSize) - for _, pos in ipairs(group) do - local tile = Tile(pos) - if tile then - toRevertPositions[pos:toString()] = tile:getGround():getId() - tile:getGround():transform(409) - end - end - - groupsCreated = groupsCreated + 1 - end - - addEvent(revertTilesAndApplyDamage, executeInterval or 3000, zonePositions) -end - -function Monster:generateBagYouDesireLoot(player) - local playerTaintLevel = player:getTaintLevel() - if not playerTaintLevel then - return {} - end - - local monsterName = self:getName() - local isMonsterValid = false - for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do - if monsterName == monster then - isMonsterValid = true - break - end - end - - if not isMonsterValid then - return {} - end - - -- Calculates the chances based on the number of taints - local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) - -- Generate loot - local loot = {} - if math.random(1, 100) <= totalChance then - local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) - if itemType then - loot[itemType:getId()] = { count = 1 } - logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) - end - end - - return loot -end - -local intervalBetweenExecutions = 10000 - -local accumulatedTime = 0 -local desiredInterval = 40000 -local bossSayInterval = 38000 - -function Monster:onThinkMegalomaniaWhiteTiles(interval, zonePositions, revertTime) - self:onThinkGoshnarTormentCounter(interval, 36, intervalBetweenExecutions, SoulWarQuest.levers.goshnarsMegalomania.boss.position) - - accumulatedTime = accumulatedTime + interval - - if accumulatedTime == bossSayInterval then - self:say("FEEL THE POWER OF MY WRATH!!") - end - -- Execute only after 40 seconds - if accumulatedTime >= desiredInterval then - self:createSoulWarWhiteTiles(SoulWarQuest.levers.goshnarsMegalomania.boss.position, zonePositions, revertTime) - accumulatedTime = 0 - end -end - -TaintTeleportCooldown = {} - -function Player:getTaintNameByNumber(taintNumber, skipKvCheck) - local haveTaintName = nil - local soulWarQuest = self:soulWarQuestKV() - local taintName = soulWarTaints[taintNumber] - if skipKvCheck or taintName and soulWarQuest:get(taintName) then - haveTaintName = taintName - end - - return haveTaintName -end - -function Player:addNextTaint() - local soulWarQuest = self:soulWarQuestKV() - for _, taintName in ipairs(soulWarTaints) do - if not soulWarQuest:get(taintName) then - soulWarQuest:set(taintName, true) - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taintName .. ".") - self:setTaintIcon() - break - end - end -end - -function Player:setTaintIcon(taintId) - self:resetTaintConditions() - local condition = Condition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, taintId or self:getTaintLevel()) - condition:setTicks(14 * 24 * 60 * 60 * 1000) - self:addCondition(condition) -end - -function Player:resetTaintConditions() - for i = 1, 5 do - self:removeCondition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, i) - end -end - -function Player:getTaintLevel() - local taintLevel = nil - local soulWarQuest = self:soulWarQuestKV() - for i, taint in ipairs(soulWarTaints) do - if soulWarQuest:get(taint) then - taintLevel = i - end - end - - return taintLevel -end - -function Player:resetTaints(skipCheckTime) - local soulWarQuest = self:soulWarQuestKV() - local firstTaintTime = soulWarQuest:get("firstTaintTime") - if skipCheckTime or firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then - -- Reset all taints and remove condition - for _, taintName in ipairs(soulWarTaints) do - if soulWarQuest:get(taintName) then - soulWarQuest:remove(taintName) - end - end - self:resetTaintConditions() - soulWarQuest:remove("firstTaintTime") - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") - end -end - -function Monster:tryTeleportToPlayer(sayMessage) - local range = 30 - local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) - local maxDistance = 0 - local farthestPlayer = nil - for i, spectator in ipairs(spectators) do - if spectator:isPlayer() then - local player = spectator:getPlayer() - if player:getTaintNameByNumber(1, true) then - local distance = self:getPosition():getDistance(player:getPosition()) - if distance > maxDistance then - maxDistance = distance - farthestPlayer = player - logger.trace("Found player {} to teleport", player:getName()) - end - end - end - end - - if farthestPlayer and math.random(100) <= 10 then - local playerPosition = farthestPlayer:getPosition() - if TaintTeleportCooldown[farthestPlayer:getId()] then - logger.trace("Cooldown is active to player {}", farthestPlayer:getName()) - return - end - - if not TaintTeleportCooldown[farthestPlayer:getId()] then - TaintTeleportCooldown[farthestPlayer:getId()] = true - - logger.trace("Scheduling player {} to teleport", farthestPlayer:getName()) - self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) - farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) - addEvent(function(playerId, monsterId) - local monsterEvent = Monster(monsterId) - local playerEvent = Player(playerId) - if monsterEvent and playerEvent then - local destinationTile = Tile(playerPosition) - if destinationTile and not (destinationTile:hasProperty(CONST_PROP_BLOCKPROJECTILE) or destinationTile:hasProperty(CONST_PROP_MOVEABLE)) then - monsterEvent:say(sayMessage) - monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - monsterEvent:teleportTo(playerPosition, true) - monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - end - end - end, 2000, farthestPlayer:getId(), self:getId()) - - addEvent(function(playerId) - local playerEvent = Player(playerId) - if not playerEvent then - return - end - - logger.trace("Cleaning player cooldown") - TaintTeleportCooldown[playerEvent:getId()] = nil - end, 10000, farthestPlayer:getId()) - end - end -end - -function Monster:getSoulWarKV() - return SoulWarQuest.kvSoulWar:scoped("monster"):scoped(self:getName()) -end - -function Monster:getHatredDamageMultiplier() - return self:getSoulWarKV():get("burning-hatred-empowered") or 0 -end - -function Monster:increaseHatredDamageMultiplier(multiplierCount) - local attackMultiplier = self:getHatredDamageMultiplier() - self:getSoulWarKV():set("burning-hatred-empowered", attackMultiplier + multiplierCount or 10) -end - -function Monster:resetHatredDamageMultiplier() - self:getSoulWarKV():remove("burning-hatred-empowered") -end - -function Position:increaseNecromaticMegalomaniaStrength() - local tile = Tile(self) - if tile then - local item = tile:getItemById(SoulWarQuest.necromanticRemainsId) - if item then - local boss = Creature("Goshnar's Megalomania") - if boss then - boss:increaseHatredDamageMultiplier(5) - item:remove() - logger.trace("Necromantic remains strength increased") - end - end - end -end - -local lastExecutionTime = 0 - --- Damage 24 to 36 have a special damage -local damageTable = { - 1400, - 1600, - 1800, - 2200, - 2400, - 2600, - 3000, - 3400, - 3800, - 4200, - 4800, - 5200, - 5600, -} - -function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetweenExecutions, bossPosition) - local interval = os.time() * 1000 - if interval - lastExecutionTime < intervalBetweenExecutions then - return - end - - lastExecutionTime = interval - logger.trace("Icon time count {}", interval) - local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) - for i = 1, #spectators do - local player = spectators[i] - local tormentCounter = player:getGoshnarSymbolTormentCounter() - if tormentCounter <= maxLimit then - player:increaseGoshnarSymbolTormentCounter(maxLimit) - logger.trace("Player {} has {} damage counter", player:getName(), tormentCounter) - - if tormentCounter > 0 then - local damage = tormentCounter * 35 - if tormentCounter >= 24 then - damage = damageTable[tormentCounter - 23] - end - - logger.trace("Final damage {}", damage) - player:addHealth(-damage, COMBAT_DEATHDAMAGE) - player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) - end - end - - if tormentCounter == 5 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread starts to torment you! Don't let dread level reach critical value!") - elseif tormentCounter == 15 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment becomes unbearable!") - elseif tormentCounter == 24 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The Dread's torment begins to tear you apart!") - elseif tormentCounter == 30 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is killing you!") - elseif tormentCounter == 36 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is now lethal!") - end - end -end - -function Monster:increaseAspectOfPowerDeathCount() - local bossKV = self:getSoulWarKV() - local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 - local newCount = aspectDeathCount + 1 - logger.trace("Aspect of Power death count {}", newCount) - bossKV:set("aspect-of-power-death-count", newCount) - if newCount == 4 then - self:setType("Goshnar's Megalomania Green") - self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") - bossKV:set("aspect-of-power-death-count", 0) - logger.trace("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") - SoulWarQuest.changePurpleEvent = addEvent(function() - local boss = Creature("Goshnar's Megalomania") - if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then - boss:setType("Goshnar's Megalomania Purple") - boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") - logger.trace("Megalomania is now immune again") - end - end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) - end -end - -function Monster:goshnarsDefenseIncrease(kvName) - local currentTime = os.time() - -- Gets the time when the "Greedy Maw" item was last used. - local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 - -- Checks if more than config time have passed since the item was last used. - if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then - logger.trace("{} old defense {}", self:getName(), self:getDefense()) - self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) - logger.trace("{} new defense {}", self:getName(), self:getDefense()) - - --- Updates the KV to reflect the timing of the increase to maintain control. - SoulWarQuest.kvSoulWar:set(kvName, currentTime) - else - -- If config time have not passed, logs the increase has been skipped. - logger.trace("{} skips increase cooldown due to recent item use.", self:getName()) - end -end - -function Player:getSoulWarZoneMonster() - local zoneMonsterName = nil - for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do - local zone = Zone.getByName(zoneName) - if zone and zone:isInZone(self:getPosition()) then - zoneMonsterName = monsterName - break - end - end - - return zoneMonsterName -end - -function Player:isInBoatSpot() - -- Get ebb and flow zone and check if player is in zone - local zone = SoulWarQuest.ebbAndFlow.getZone() - local tile = Tile(self:getPosition()) - local groundId - if tile and tile:getGround() then - groundId = tile:getGround():getId() - end - if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then - logger.trace("Player {} is in boat spot", self:getName()) - return true - end - - logger.trace("Player {} is not in boat spot", self:getName()) - return false -end - -function Player:soulWarQuestKV() - return self:kv():scoped("quest"):scoped("soul-war") -end - -function Player:getGoshnarSymbolTormentCounter() - local soulWarKV = self:soulWarQuestKV() - return soulWarKV:get("goshnars-hatred-torment-count") or 0 -end - -function Player:increaseGoshnarSymbolTormentCounter(maxLimit) - local soulWarKV = self:soulWarQuestKV() - local tormentCount = self:getGoshnarSymbolTormentCounter() - if tormentCount == maxLimit then - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount) - return - end - - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount + 1) - soulWarKV:set("goshnars-hatred-torment-count", tormentCount + 1) -end - -function Player:removeGoshnarSymbolTormentCounter(count) - local soulWarKV = self:soulWarQuestKV() - local tormentCount = self:getGoshnarSymbolTormentCounter() - if tormentCount > count then - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount - count) - soulWarKV:set("goshnars-hatred-torment-count", tormentCount - count) - else - self:resetGoshnarSymbolTormentCounter() - end -end - -function Player:resetGoshnarSymbolTormentCounter() - local soulWarKV = self:soulWarQuestKV() - soulWarKV:remove("goshnars-hatred-torment-count") - self:removeIcon("goshnars-hatred-damage") -end - -function Player:furiousCraterKV() - return self:soulWarQuestKV():scoped("furius-crater") -end - -function Player:pulsatingEnergyKV() - return self:furiousCraterKV():scoped("pulsating-energy") -end - -function Zone:getRandomPlayer() - local players = self:getPlayers() - if #players == 0 then - return nil - end - - local randomIndex = math.random(#players) - return players[randomIndex] -end - -local function delayedCastSpell(cid, var, combat, targetId) - local creature = Creature(cid) - if not creature then - return - end - - local target = Player(targetId) - if target then - combat:execute(creature, positionToVariant(target:getPosition())) - end -end - -function Creature:applyZoneEffect(var, combat, zoneName) - local outfitConfig = { - outfit = { lookType = 242, lookHead = 0, lookBody = 0, lookLegs = 0, lookFeet = 0, lookAddons = 0 }, - time = 7000, - } - - local zone = Zone.getByName(zoneName) - if not zone then - logger.error("Could not find zone '" .. zoneName .. "', you need use the 'BossLever' system") - return false - end - - local target = zone:getRandomPlayer() - if not target then - return true - end - - local condition = Condition(CONDITION_OUTFIT) - condition:setTicks(outfitConfig.time) - condition:setOutfit(outfitConfig.outfit) - target:addCondition(condition) - target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) - - addEvent(delayedCastSpell, SoulWarQuest.goshnarsCrueltyWaveInterval * 1000, self:getId(), var, combat, target:getId()) - - return true -end - -function string.toPosition(str) - local patterns = { - -- table format - "{%s*x%s*=%s*(%d+)%s*,%s*y%s*=%s*(%d+)%s*,%s*z%s*=%s*(%d+)%s*}", - -- Position format - "Position%s*%((%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)", - -- x, y, z format - "(%d+)%s*,%s*(%d+)%s*,%s*(%d+)", - } - - for _, pattern in ipairs(patterns) do - local x, y, z = string.match(str, pattern) - if x and y and z then - return Position(tonumber(x), tonumber(y), tonumber(z)) - end - end -end From f12b06bb3e9c6770a128effce6168f54c140a931 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 12 May 2024 02:36:22 -0300 Subject: [PATCH 07/31] fix: mechanics and npc flickering soul changes: - Added taints removal with words "taints" and "penalties" to npc flickering soul - Fixed soul war mechanics that should not be applied when in safe places (before hunt teleport) - Removed bag you desire as loot of soul war monsters --- .../scripts/quests/soul_war/eventcallback_on_combat_taint.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 3e5ec34f930..936ab8502aa 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) From a5e4bd036db9b4467892a003e4cd4043f5a2333f Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 26 May 2024 17:10:01 -0300 Subject: [PATCH 08/31] improvement: claustrophobic inferno raids and safe zones --- .../scripts/quests/soul_war/eventcallback_on_combat_taint.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 936ab8502aa..3e5ec34f930 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) From 4974744d0515714034d539757375770b7e48976c Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 17:18:04 -0300 Subject: [PATCH 09/31] feat: full soul war quest --- .../scripts/lib/quests/soul-war.lua | 1343 +++++++++++++++++ 1 file changed, 1343 insertions(+) create mode 100644 data-otservbr-global/scripts/lib/quests/soul-war.lua diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua new file mode 100644 index 00000000000..ba44d49943f --- /dev/null +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -0,0 +1,1343 @@ +SoulWarQuest = { + -- Item ids + -- Goshnar's Hatred + bagYouDesireItemId = 34109, + goshnarsHatredSorrowId = 33793, + condensedRemorseId = 33792, + -- Goshnar's Spite + weepingSoulCorpseId = 33876, + searingFireId = 33877, + -- Goshnar's Cruelty + pulsatingEnergyId = 34005, + greedyMawId = 33890, + someMortalEssenceId = 33891, + theBloodOfCloakTerrorIds = { 33854, 34006, 34007 }, + -- Goshnar's Megalomania + deadAspectOfPowerCorpseId = 33949, + cleansedSanityItemId = 33950, + necromanticRemainsItemId = 33984, + + poolDamagePercentages = { + [33854] = 0.20, -- 20% of maximum health for the largest pool + [34006] = 0.15, -- 15% for a medium-sized pool + [34007] = 0.10, -- 10% for the smallest pool + }, + + timeToIncreaseCrueltyDefense = 15, -- In seconds, it will increase every 15 seconds if don't use mortal essence in greedy maw + useGreedMawCooldown = 30, -- In seconds + goshnarsCrueltyDefenseChange = 2, -- Defense change, the amount that will decrease or increase defense, the defense cannot decrease more than the monster's original defense amount + goshnarsCrueltyWaveInterval = 7, -- In seconds + + timeToReturnImmuneMegalomania = 70, -- In seconds + + baseBagYouDesireChance = 1, -- 1% base chance + bagYouDesireChancePerTaint = 1, -- Increases 1% per taint + bagYouDesireMonsters = { + "Bony Sea Devil", + "Brachiodemon", + "Branchy Crawler", + "Capricious Phantom", + "Cloak Of Terror", + "Courage Leech", + "Distorted Phantom", + "Druid's Apparition", + "Infernal Demon", + "Infernal Phantom", + "Knight's Apparition", + "Many Faces", + "Mould Phantom", + "Paladin's Apparition", + "Rotten Golem", + "Sorcerer's Apparition", + "Turbulent Elemental", + "Vibrant Phantom.", + }, + bagYouDesireBosses = { + "Goshnar's Cruelty", + "Goshnar's Spite", + "Goshnar's Malice", + "Goshnar's Hatred", + "Goshnar's Greed", + }, + + -- Goshnar's Cruelty pulsating energy monsters + pulsatingEnergyMonsters = { + "Vibrant Phantom", + "Cloak of Terror", + "Courage Leech", + }, + + finalRewards = { + { id = 34082, name = "soulcutter" }, + { id = 34083, name = "soulshredder" }, + { id = 34084, name = "soulbiter" }, + { id = 34085, name = "souleater" }, + { id = 34086, name = "soulcrusher" }, + { id = 34087, name = "soulmaimer" }, + { id = 34088, name = "soulbleeder" }, + { id = 34089, name = "soulpiercer" }, + { id = 34090, name = "soultainter" }, + { id = 34091, name = "soulhexer" }, + { id = 34092, name = "soulshanks" }, + { id = 34093, name = "soulstrider" }, + { id = 34094, name = "soulshell" }, + { id = 34095, name = "soulmantel" }, + { id = 34096, name = "soulshroud" }, + { id = 34097, name = "pair of soulwalkers" }, + { id = 34098, name = "pair of soulstalkers" }, + { id = 34099, name = "soulbastion" }, + }, + + kvSoulWar = KV.scoped("quest"):scoped("soul-war"), + -- Global KV for storage burning change form time + kvBurning = KV.scoped("quest"):scoped("soul-war"):scoped("burning-change-form"), + + rottenWastelandShrines = { + [33019] = { x = 33926, y = 31091, z = 13 }, + [33021] = { x = 33963, y = 31078, z = 13 }, + [33022] = { x = 33970, y = 30988, z = 13 }, + [33024] = { x = 33970, y = 31012, z = 13 }, + }, + + -- Lever room and teleports positions + goshnarsGreedAccessPosition = { from = { x = 33937, y = 31217, z = 11 }, to = { x = 33782, y = 31665, z = 14 } }, + goshnarsHatredAccessPosition = { from = { x = 33914, y = 31032, z = 12 }, to = { x = 33774, y = 31604, z = 14 } }, + -- Teleports from 1st/2nd/3rd floors + goshnarsCrueltyTeleportRoomPositions = { + { from = Position(33889, 31873, 3), to = Position(33830, 31881, 4), access = "first-floor-access", count = 40 }, + { from = Position(33829, 31880, 4), to = Position(33856, 31889, 5), access = "second-floor-access", count = 55 }, + { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, + }, + + -- Levers configuration + levers = { + goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, + goshnarsSpitePosition = { x = 33773, y = 31634, z = 14 }, + goshnarsGreedPosition = { x = 33775, y = 31665, z = 14 }, + goshnarsHatredPosition = { x = 33772, y = 31601, z = 14 }, + goshnarsCrueltyPosition = { x = 33853, y = 31854, z = 6 }, + goshnarsMegalomaniaPosition = { x = 33675, y = 31634, z = 14 }, + + -- Levers system + goshnarsSpite = { + boss = { + name = "Goshnar's Spite", + position = Position(33743, 31632, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33774, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33775, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33776, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33778, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33734, 31624, 14), + to = Position(33751, 31640, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsMalice = { + boss = { + name = "Goshnar's Malice", + position = Position(33709, 31599, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33679, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33681, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33682, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33683, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33699, 31590, 14), + to = Position(33718, 31607, 14), + }, + onUseExtra = function(player) + addEvent(SpawnSoulCage, 23000) + end, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsGreed = { + boss = { + name = "Goshnar's Greed", + position = Position(33746, 31666, 14), + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33776, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33778, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33779, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33780, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33737, 31658, 14), + to = Position(33755, 31673, 14), + }, + timeToFightAgain = 0, -- TODO: Remove later + onUseExtra = function() + CreateGoshnarsGreedMonster("Greedbeast", Position(33744, 31666, 14)) + CreateGoshnarsGreedMonster("Soulsnatcher", Position(33747, 31668, 14)) + CreateGoshnarsGreedMonster("Weak Soul", Position(33750, 31666, 14)) + end, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + }, + goshnarsHatred = { + boss = { + name = "Goshnar's Hatred", + position = Position(33744, 31599, 14), + }, + monsters = { + { name = "Ashes of Burning Hatred", pos = { x = 33743, y = 31599, z = 14 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33773, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33774, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33775, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33776, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33777, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33735, 31592, 14), + to = Position(33751, 31606, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + onUseExtra = function(player) + SoulWarQuest.kvBurning:set("time", 180) + logger.debug("Goshnar's Hatred burning change form time set to: {}", 180) + player:resetGoshnarSymbolTormentCounter() + end, + }, + goshnarsCruelty = { + boss = { + name = "Goshnar's Cruelty", + position = Position(33856, 31866, 7), + }, + monsters = { + { name = "A Greedy Eye", pos = { x = 33856, y = 31858, z = 7 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33854, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33855, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33856, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33857, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + { pos = Position(33858, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33847, 31858, 7), + to = Position(33864, 31874, 7), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 20 * 60 * 60, -- 20 hours + onUseExtra = function(player) + SoulWarQuest.kvSoulWar:remove("greedy-maw-action") + player:soulWarQuestKV():scoped("furious-crater"):remove("greedy-maw-action") + end, + }, + goshnarsMegalomania = { + boss = { + name = "Goshnar's Megalomania Purple", + position = Position(33710, 31634, 14), + }, + monsters = { + { name = "Aspect of Power", pos = { x = 33710, y = 31635, z = 14 } }, + }, + requiredLevel = 250, + playerPositions = { + { pos = Position(33676, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33677, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33678, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33679, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + { pos = Position(33680, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, + }, + specPos = { + from = Position(33701, 31626, 14), + to = Position(33719, 31642, 14), + }, + exit = Position(33621, 31427, 10), + timeToFightAgain = 72 * 60 * 60, -- 72 hours + onUseExtra = function(player) + player:resetGoshnarSymbolTormentCounter() + SoulWarQuest.kvSoulWar:remove("cleansed-sanity-action") + player:soulWarQuestKV():scoped("furious-crater"):remove("cleansed-sanity-action") + end, + }, + }, + + -- Goshnar's Greed + apparitionNames = { + "Druid's Apparition", + "Knight's Apparition", + "Paladin's Apparition", + "Sorcerer's Apparition", + }, + + burningTransformations = { + { 180, "Ashes of Burning Hatred" }, + { 135, "Spark of Burning Hatred" }, + { 90, "Flame of Burning Hatred" }, + { 45, "Blaze of Burning Hatred" }, + }, + + requiredCountPerApparition = 25, + + -- Ebb and flow + ebbAndFlow = { + zone = Zone("ebb-and-flow-zone"), + -- Positions to teleport into rooms when innundate map is loaded + centerRoomPositions = { + { conor = { x = 33929, y = 31020, z = 9 }, teleportPosition = { x = 33939, y = 31021, z = 8 } }, + { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33918, y = 31047, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, + { conor = { x = 33898, y = 31054, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, + { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33940, y = 31054, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, + { conor = { x = 33940, y = 31064, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, + { conor = { x = 33937, y = 31086, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, + { conor = { x = 33937, y = 31098, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33933, y = 31109, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33921, y = 31113, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, + { conor = { x = 33912, y = 31113, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, + { conor = { x = 33901, y = 31108, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, + { conor = { x = 33901, y = 31098, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, + { conor = { x = 33899, y = 31064, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, + }, + mapsPath = { + empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", + inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", + }, + + -- In Minutes + intervalChangeMap = 2, + waitPosition = Position(33893, 31020, 8), + + getZone = function() + return SoulWarQuest.ebbAndFlow.zone + end, + + reloadZone = function() + SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) + end, + + kv = KV.scoped("quest"):scoped("soul-war"):scoped("ebb-and-flow-maps"), + isActive = function() + return SoulWarQuest.ebbAndFlow.kv:get("is-active") + end, + isLoadedEmptyMap = function() + return SoulWarQuest.ebbAndFlow.kv:get("is-loaded-empty-map") + end, + setActive = function(value) + SoulWarQuest.ebbAndFlow.kv:set("is-active", value) + end, + setLoadedEmptyMap = function(value) + SoulWarQuest.ebbAndFlow.kv:set("is-loaded-empty-map", value) + end, + + updateZonePlayers = function() + if SoulWarQuest.ebbAndFlow.zone and SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then + SoulWarQuest.ebbAndFlow.reloadZone() + local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() + for _, player in ipairs(players) do + logger.debug("Updating player: {}", player:getName()) + player:sendCreatureAppear() + end + end + end, + + -- Add here more positions of the pools that must transform before innundate map is loaded + poolPositions = { + { x = 33906, y = 31026, z = 9 }, + { x = 33901, y = 31026, z = 9 }, + { x = 33932, y = 31011, z = 9 }, + { x = 33941, y = 31033, z = 9 }, + { x = 33946, y = 31037, z = 9 }, + { x = 33939, y = 31056, z = 9 }, + }, + + boatId = 7272, + doorId = 33767, + smallPoolId = 33772, + MediumPoolId = 33773, + }, + + changeBlueEvent = nil, + changePurpleEvent = nil, + + changeMegalomaniaBlue = function() + local boss = Creature("Goshnar's Megalomania") + if boss then + boss:teleportTo(SoulWarQuest.levers.goshnarsMegalomania.boss.position) + boss:say("ENOUGH! I WILL MAKE YOU SUFFER FOR YOUR INSOLENCE! NOW - I - WILL - ANIHILATE - YOU!") + boss:setType("Goshnar's Megalomania Blue") + local function changeBack() + boss:setType("Goshnar's Megalomania Purple") + end + + changePurpleEvent = addEvent(changeBack, 7000) + end + end, + + -- Chance to heal the life of the monster by stepping on the corpse of "weeping soul" + goshnarsSpiteHealChance = 10, + -- Percentage that will heal by stepping and the chance is successful + goshnarsSpiteHealPercentage = 10, + + goshnarSpiteEntrancePosition = { fromPos = Position(33950, 31109, 8), toPos = Position(33780, 31634, 14) }, + + waterElementalOutfit = { + lookType = 286, + lookHead = 0, + lookBody = 0, + lookLegs = 0, + lookFeet = 0, + lookAddons = 0, + lookMount = 0, + }, + + goshnarsSpiteFirePositions = { + -- North + { x = 33743, y = 31628, z = 14 }, + -- East + { x = 33736, y = 31632, z = 14 }, + -- West + { x = 33750, y = 31632, z = 14 }, + -- South + { x = 33742, y = 31637, z = 14 }, + }, + + -- Increased defense if the searing fire disappears + goshnarsSpiteIncreaseDefense = 10, + -- Count of monsters to kill for enter in the boss room + hardozousPanthomDeathCount = 20, + -- Time to fire created again + timeToCreateSearingFire = 14, -- In seconds + -- Time to remove the searing fire if player don't step on it + timeToRemoveSearingFire = 5, -- In seconds + cooldownToStepOnSearingFire = 56, -- In seconds (14 seconds x 4) + + -- Positions to teleport into rooms when innundate map is loaded + ebbAndFlowBoatTeleportPositions = { + -- First boat + -- Enter on boat + { register = { x = 33919, y = 31019, z = 8 }, teleportTo = { x = 33923, y = 31019, z = 8 } }, + { register = { x = 33919, y = 31020, z = 8 }, teleportTo = { x = 33923, y = 31020, z = 8 } }, + { register = { x = 33919, y = 31021, z = 8 }, teleportTo = { x = 33923, y = 31021, z = 8 } }, + { register = { x = 33919, y = 31022, z = 8 }, teleportTo = { x = 33923, y = 31022, z = 8 } }, + -- Back to innitial room + { register = { x = 33922, y = 31019, z = 8 }, teleportTo = { x = 33918, y = 31019, z = 8 } }, + { register = { x = 33922, y = 31020, z = 8 }, teleportTo = { x = 33918, y = 31020, z = 8 } }, + { register = { x = 33922, y = 31021, z = 8 }, teleportTo = { x = 33918, y = 31021, z = 8 } }, + { register = { x = 33922, y = 31022, z = 8 }, teleportTo = { x = 33918, y = 31022, z = 8 } }, + -- From boat to room + { register = { x = 33926, y = 31019, z = 8 }, teleportTo = { x = 33930, y = 31019, z = 8 } }, + { register = { x = 33926, y = 31020, z = 8 }, teleportTo = { x = 33930, y = 31020, z = 8 } }, + { register = { x = 33926, y = 31021, z = 8 }, teleportTo = { x = 33930, y = 31021, z = 8 } }, + { register = { x = 33926, y = 31022, z = 8 }, teleportTo = { x = 33930, y = 31022, z = 8 } }, + -- From room to boat + { register = { x = 33929, y = 31019, z = 8 }, teleportTo = { x = 33925, y = 31019, z = 8 } }, + { register = { x = 33929, y = 31020, z = 8 }, teleportTo = { x = 33925, y = 31020, z = 8 } }, + { register = { x = 33929, y = 31021, z = 8 }, teleportTo = { x = 33925, y = 31021, z = 8 } }, + { register = { x = 33929, y = 31022, z = 8 }, teleportTo = { x = 33925, y = 31022, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33929, y = 31045, z = 8 }, teleportTo = { x = 33925, y = 31045, z = 8 } }, + { register = { x = 33929, y = 31046, z = 8 }, teleportTo = { x = 33925, y = 31046, z = 8 } }, + { register = { x = 33929, y = 31047, z = 8 }, teleportTo = { x = 33925, y = 31047, z = 8 } }, + { register = { x = 33929, y = 31048, z = 8 }, teleportTo = { x = 33925, y = 31048, z = 8 } }, + -- Back to room + { register = { x = 33926, y = 31045, z = 8 }, teleportTo = { x = 33930, y = 31045, z = 8 } }, + { register = { x = 33926, y = 31046, z = 8 }, teleportTo = { x = 33930, y = 31046, z = 8 } }, + { register = { x = 33926, y = 31047, z = 8 }, teleportTo = { x = 33930, y = 31047, z = 8 } }, + { register = { x = 33926, y = 31048, z = 8 }, teleportTo = { x = 33930, y = 31048, z = 8 } }, + -- From boat to room + { register = { x = 33922, y = 31045, z = 8 }, teleportTo = { x = 33918, y = 31045, z = 8 } }, + { register = { x = 33922, y = 31046, z = 8 }, teleportTo = { x = 33918, y = 31046, z = 8 } }, + { register = { x = 33922, y = 31047, z = 8 }, teleportTo = { x = 33918, y = 31047, z = 8 } }, + { register = { x = 33922, y = 31048, z = 8 }, teleportTo = { x = 33918, y = 31048, z = 8 } }, + -- From room to boat + { register = { x = 33919, y = 31045, z = 8 }, teleportTo = { x = 33923, y = 31045, z = 8 } }, + { register = { x = 33919, y = 31046, z = 8 }, teleportTo = { x = 33923, y = 31046, z = 8 } }, + { register = { x = 33919, y = 31047, z = 8 }, teleportTo = { x = 33923, y = 31047, z = 8 } }, + { register = { x = 33919, y = 31048, z = 8 }, teleportTo = { x = 33923, y = 31048, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33896, y = 31055, z = 8 }, teleportTo = { x = 33896, y = 31059, z = 8 } }, + { register = { x = 33897, y = 31055, z = 8 }, teleportTo = { x = 33897, y = 31059, z = 8 } }, + { register = { x = 33898, y = 31055, z = 8 }, teleportTo = { x = 33898, y = 31059, z = 8 } }, + { register = { x = 33899, y = 31055, z = 8 }, teleportTo = { x = 33899, y = 31059, z = 8 } }, + { register = { x = 33900, y = 31055, z = 8 }, teleportTo = { x = 33900, y = 31059, z = 8 } }, + { register = { x = 33901, y = 31055, z = 8 }, teleportTo = { x = 33901, y = 31059, z = 8 } }, + -- Back to room + { register = { x = 33896, y = 31058, z = 8 }, teleportTo = { x = 33896, y = 31054, z = 8 } }, + { register = { x = 33897, y = 31058, z = 8 }, teleportTo = { x = 33897, y = 31054, z = 8 } }, + { register = { x = 33898, y = 31058, z = 8 }, teleportTo = { x = 33898, y = 31054, z = 8 } }, + { register = { x = 33899, y = 31058, z = 8 }, teleportTo = { x = 33899, y = 31054, z = 8 } }, + { register = { x = 33900, y = 31058, z = 8 }, teleportTo = { x = 33900, y = 31054, z = 8 } }, + { register = { x = 33901, y = 31058, z = 8 }, teleportTo = { x = 33901, y = 31054, z = 8 } }, + -- From boat to room + { register = { x = 33896, y = 31061, z = 8 }, teleportTo = { x = 33896, y = 31065, z = 8 } }, + { register = { x = 33897, y = 31061, z = 8 }, teleportTo = { x = 33897, y = 31065, z = 8 } }, + { register = { x = 33898, y = 31061, z = 8 }, teleportTo = { x = 33898, y = 31065, z = 8 } }, + { register = { x = 33899, y = 31061, z = 8 }, teleportTo = { x = 33899, y = 31065, z = 8 } }, + { register = { x = 33900, y = 31061, z = 8 }, teleportTo = { x = 33900, y = 31065, z = 8 } }, + { register = { x = 33901, y = 31061, z = 8 }, teleportTo = { x = 33901, y = 31065, z = 8 } }, + -- From room to boat + { register = { x = 33896, y = 31064, z = 8 }, teleportTo = { x = 33896, y = 31060, z = 8 } }, + { register = { x = 33897, y = 31064, z = 8 }, teleportTo = { x = 33897, y = 31060, z = 8 } }, + { register = { x = 33898, y = 31064, z = 8 }, teleportTo = { x = 33898, y = 31060, z = 8 } }, + { register = { x = 33899, y = 31064, z = 8 }, teleportTo = { x = 33899, y = 31060, z = 8 } }, + { register = { x = 33900, y = 31064, z = 8 }, teleportTo = { x = 33900, y = 31060, z = 8 } }, + { register = { x = 33901, y = 31064, z = 8 }, teleportTo = { x = 33901, y = 31060, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33899, y = 31099, z = 8 }, teleportTo = { x = 33899, y = 31103, z = 8 } }, + { register = { x = 33900, y = 31099, z = 8 }, teleportTo = { x = 33900, y = 31103, z = 8 } }, + { register = { x = 33901, y = 31099, z = 8 }, teleportTo = { x = 33901, y = 31103, z = 8 } }, + { register = { x = 33902, y = 31099, z = 8 }, teleportTo = { x = 33902, y = 31103, z = 8 } }, + { register = { x = 33903, y = 31099, z = 8 }, teleportTo = { x = 33903, y = 31103, z = 8 } }, + { register = { x = 33904, y = 31099, z = 8 }, teleportTo = { x = 33904, y = 31103, z = 8 } }, + { register = { x = 33905, y = 31099, z = 8 }, teleportTo = { x = 33905, y = 31103, z = 8 } }, + -- Back from boat to room + { register = { x = 33899, y = 31102, z = 8 }, teleportTo = { x = 33899, y = 31098, z = 8 } }, + { register = { x = 33900, y = 31102, z = 8 }, teleportTo = { x = 33900, y = 31098, z = 8 } }, + { register = { x = 33901, y = 31102, z = 8 }, teleportTo = { x = 33901, y = 31098, z = 8 } }, + { register = { x = 33902, y = 31102, z = 8 }, teleportTo = { x = 33902, y = 31098, z = 8 } }, + { register = { x = 33903, y = 31102, z = 8 }, teleportTo = { x = 33903, y = 31098, z = 8 } }, + { register = { x = 33904, y = 31102, z = 8 }, teleportTo = { x = 33904, y = 31098, z = 8 } }, + { register = { x = 33905, y = 31102, z = 8 }, teleportTo = { x = 33905, y = 31098, z = 8 } }, + -- From boat to room + { register = { x = 33899, y = 31105, z = 8 }, teleportTo = { x = 33899, y = 31109, z = 8 } }, + { register = { x = 33900, y = 31105, z = 8 }, teleportTo = { x = 33900, y = 31109, z = 8 } }, + { register = { x = 33901, y = 31105, z = 8 }, teleportTo = { x = 33901, y = 31109, z = 8 } }, + { register = { x = 33902, y = 31105, z = 8 }, teleportTo = { x = 33902, y = 31109, z = 8 } }, + { register = { x = 33903, y = 31105, z = 8 }, teleportTo = { x = 33903, y = 31109, z = 8 } }, + { register = { x = 33904, y = 31105, z = 8 }, teleportTo = { x = 33904, y = 31109, z = 8 } }, + { register = { x = 33905, y = 31105, z = 8 }, teleportTo = { x = 33905, y = 31109, z = 8 } }, + -- From room to boat + { register = { x = 33899, y = 31108, z = 8 }, teleportTo = { x = 33899, y = 31104, z = 8 } }, + { register = { x = 33900, y = 31108, z = 8 }, teleportTo = { x = 33900, y = 31104, z = 8 } }, + { register = { x = 33901, y = 31108, z = 8 }, teleportTo = { x = 33901, y = 31104, z = 8 } }, + { register = { x = 33902, y = 31108, z = 8 }, teleportTo = { x = 33902, y = 31104, z = 8 } }, + { register = { x = 33903, y = 31108, z = 8 }, teleportTo = { x = 33903, y = 31104, z = 8 } }, + { register = { x = 33904, y = 31108, z = 8 }, teleportTo = { x = 33904, y = 31104, z = 8 } }, + { register = { x = 33905, y = 31108, z = 8 }, teleportTo = { x = 33905, y = 31104, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33913, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, + { register = { x = 33913, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, + { register = { x = 33913, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, + { register = { x = 33913, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, + { register = { x = 33913, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, + -- Back to room + { register = { x = 33916, y = 31112, z = 8 }, teleportTo = { x = 33912, y = 31112, z = 8 } }, + { register = { x = 33916, y = 31113, z = 8 }, teleportTo = { x = 33912, y = 31113, z = 8 } }, + { register = { x = 33916, y = 31114, z = 8 }, teleportTo = { x = 33912, y = 31114, z = 8 } }, + { register = { x = 33916, y = 31115, z = 8 }, teleportTo = { x = 33912, y = 31115, z = 8 } }, + { register = { x = 33916, y = 31116, z = 8 }, teleportTo = { x = 33912, y = 31116, z = 8 } }, + -- From boat to room + { register = { x = 33918, y = 31112, z = 8 }, teleportTo = { x = 33922, y = 31112, z = 8 } }, + { register = { x = 33918, y = 31113, z = 8 }, teleportTo = { x = 33922, y = 31113, z = 8 } }, + { register = { x = 33918, y = 31114, z = 8 }, teleportTo = { x = 33922, y = 31114, z = 8 } }, + { register = { x = 33918, y = 31115, z = 8 }, teleportTo = { x = 33922, y = 31115, z = 8 } }, + { register = { x = 33918, y = 31116, z = 8 }, teleportTo = { x = 33922, y = 31116, z = 8 } }, + -- From room to boat + { register = { x = 33921, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, + { register = { x = 33921, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, + { register = { x = 33921, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, + { register = { x = 33921, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, + { register = { x = 33921, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33936, y = 31087, z = 8 }, teleportTo = { x = 33936, y = 31091, z = 8 } }, + { register = { x = 33937, y = 31087, z = 8 }, teleportTo = { x = 33937, y = 31091, z = 8 } }, + { register = { x = 33938, y = 31087, z = 8 }, teleportTo = { x = 33938, y = 31091, z = 8 } }, + { register = { x = 33939, y = 31087, z = 8 }, teleportTo = { x = 33939, y = 31091, z = 8 } }, + { register = { x = 33940, y = 31087, z = 8 }, teleportTo = { x = 33940, y = 31091, z = 8 } }, + { register = { x = 33941, y = 31087, z = 8 }, teleportTo = { x = 33941, y = 31091, z = 8 } }, + -- Back to room + { register = { x = 33936, y = 31090, z = 8 }, teleportTo = { x = 33936, y = 31086, z = 8 } }, + { register = { x = 33937, y = 31090, z = 8 }, teleportTo = { x = 33937, y = 31086, z = 8 } }, + { register = { x = 33938, y = 31090, z = 8 }, teleportTo = { x = 33938, y = 31086, z = 8 } }, + { register = { x = 33939, y = 31090, z = 8 }, teleportTo = { x = 33939, y = 31086, z = 8 } }, + { register = { x = 33940, y = 31090, z = 8 }, teleportTo = { x = 33940, y = 31086, z = 8 } }, + { register = { x = 33941, y = 31090, z = 8 }, teleportTo = { x = 33941, y = 31086, z = 8 } }, + -- From boat to room + { register = { x = 33936, y = 31095, z = 8 }, teleportTo = { x = 33934, y = 31099, z = 8 } }, + { register = { x = 33937, y = 31095, z = 8 }, teleportTo = { x = 33935, y = 31099, z = 8 } }, + { register = { x = 33938, y = 31095, z = 8 }, teleportTo = { x = 33936, y = 31099, z = 8 } }, + { register = { x = 33939, y = 31095, z = 8 }, teleportTo = { x = 33937, y = 31099, z = 8 } }, + { register = { x = 33940, y = 31095, z = 8 }, teleportTo = { x = 33938, y = 31099, z = 8 } }, + { register = { x = 33941, y = 31095, z = 8 }, teleportTo = { x = 33939, y = 31099, z = 8 } }, + -- From room to boat + { register = { x = 33934, y = 31098, z = 8 }, teleportTo = { x = 33936, y = 31094, z = 8 } }, + { register = { x = 33935, y = 31098, z = 8 }, teleportTo = { x = 33937, y = 31094, z = 8 } }, + { register = { x = 33936, y = 31098, z = 8 }, teleportTo = { x = 33938, y = 31094, z = 8 } }, + { register = { x = 33937, y = 31098, z = 8 }, teleportTo = { x = 33939, y = 31094, z = 8 } }, + { register = { x = 33938, y = 31098, z = 8 }, teleportTo = { x = 33940, y = 31094, z = 8 } }, + { register = { x = 33939, y = 31098, z = 8 }, teleportTo = { x = 33941, y = 31094, z = 8 } }, + { register = { x = 33940, y = 31098, z = 8 }, teleportTo = { x = 33942, y = 31094, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33939, y = 31064, z = 8 }, teleportTo = { x = 33939, y = 31060, z = 8 } }, + { register = { x = 33940, y = 31064, z = 8 }, teleportTo = { x = 33940, y = 31060, z = 8 } }, + { register = { x = 33941, y = 31064, z = 8 }, teleportTo = { x = 33941, y = 31060, z = 8 } }, + { register = { x = 33942, y = 31064, z = 8 }, teleportTo = { x = 33942, y = 31060, z = 8 } }, + { register = { x = 33943, y = 31064, z = 8 }, teleportTo = { x = 33943, y = 31060, z = 8 } }, + { register = { x = 33944, y = 31064, z = 8 }, teleportTo = { x = 33944, y = 31060, z = 8 } }, + -- Back to room + { register = { x = 33939, y = 31061, z = 8 }, teleportTo = { x = 33939, y = 31065, z = 8 } }, + { register = { x = 33940, y = 31061, z = 8 }, teleportTo = { x = 33940, y = 31065, z = 8 } }, + { register = { x = 33941, y = 31061, z = 8 }, teleportTo = { x = 33941, y = 31065, z = 8 } }, + { register = { x = 33942, y = 31061, z = 8 }, teleportTo = { x = 33942, y = 31065, z = 8 } }, + { register = { x = 33943, y = 31061, z = 8 }, teleportTo = { x = 33943, y = 31065, z = 8 } }, + { register = { x = 33944, y = 31061, z = 8 }, teleportTo = { x = 33944, y = 31065, z = 8 } }, + -- From boat to room + { register = { x = 33939, y = 31058, z = 8 }, teleportTo = { x = 33939, y = 31054, z = 8 } }, + { register = { x = 33940, y = 31058, z = 8 }, teleportTo = { x = 33940, y = 31054, z = 8 } }, + { register = { x = 33941, y = 31058, z = 8 }, teleportTo = { x = 33941, y = 31054, z = 8 } }, + { register = { x = 33942, y = 31058, z = 8 }, teleportTo = { x = 33942, y = 31054, z = 8 } }, + { register = { x = 33943, y = 31058, z = 8 }, teleportTo = { x = 33943, y = 31054, z = 8 } }, + { register = { x = 33944, y = 31058, z = 8 }, teleportTo = { x = 33944, y = 31054, z = 8 } }, + -- From room to boat + { register = { x = 33939, y = 31055, z = 8 }, teleportTo = { x = 33939, y = 31059, z = 8 } }, + { register = { x = 33940, y = 31055, z = 8 }, teleportTo = { x = 33940, y = 31059, z = 8 } }, + { register = { x = 33941, y = 31055, z = 8 }, teleportTo = { x = 33941, y = 31059, z = 8 } }, + { register = { x = 33942, y = 31055, z = 8 }, teleportTo = { x = 33942, y = 31059, z = 8 } }, + { register = { x = 33943, y = 31055, z = 8 }, teleportTo = { x = 33943, y = 31059, z = 8 } }, + { register = { x = 33944, y = 31055, z = 8 }, teleportTo = { x = 33944, y = 31059, z = 8 } }, + + -- Boat + -- Enter on boat + { register = { x = 33934, y = 31108, z = 8 }, teleportTo = { x = 33938, y = 31108, z = 8 } }, + { register = { x = 33934, y = 31109, z = 8 }, teleportTo = { x = 33938, y = 31109, z = 8 } }, + { register = { x = 33934, y = 31110, z = 8 }, teleportTo = { x = 33938, y = 31110, z = 8 } }, + { register = { x = 33934, y = 31111, z = 8 }, teleportTo = { x = 33938, y = 31111, z = 8 } }, + { register = { x = 33934, y = 31112, z = 8 }, teleportTo = { x = 33938, y = 31112, z = 8 } }, + -- Back to room + { register = { x = 33937, y = 31108, z = 8 }, teleportTo = { x = 33933, y = 31108, z = 8 } }, + { register = { x = 33937, y = 31109, z = 8 }, teleportTo = { x = 33933, y = 31109, z = 8 } }, + { register = { x = 33937, y = 31110, z = 8 }, teleportTo = { x = 33933, y = 31110, z = 8 } }, + { register = { x = 33937, y = 31111, z = 8 }, teleportTo = { x = 33933, y = 31111, z = 8 } }, + { register = { x = 33937, y = 31112, z = 8 }, teleportTo = { x = 33933, y = 31112, z = 8 } }, + -- From boat to room + { register = { x = 33942, y = 31108, z = 8 }, teleportTo = { x = 33946, y = 31108, z = 8 } }, + { register = { x = 33942, y = 31109, z = 8 }, teleportTo = { x = 33946, y = 31109, z = 8 } }, + { register = { x = 33942, y = 31110, z = 8 }, teleportTo = { x = 33946, y = 31110, z = 8 } }, + { register = { x = 33942, y = 31111, z = 8 }, teleportTo = { x = 33946, y = 31111, z = 8 } }, + { register = { x = 33942, y = 31112, z = 8 }, teleportTo = { x = 33946, y = 31112, z = 8 } }, + -- From room to boat + { register = { x = 33945, y = 31108, z = 8 }, teleportTo = { x = 33941, y = 31108, z = 8 } }, + { register = { x = 33945, y = 31109, z = 8 }, teleportTo = { x = 33941, y = 31109, z = 8 } }, + { register = { x = 33945, y = 31110, z = 8 }, teleportTo = { x = 33941, y = 31110, z = 8 } }, + { register = { x = 33945, y = 31111, z = 8 }, teleportTo = { x = 33941, y = 31111, z = 8 } }, + { register = { x = 33945, y = 31112, z = 8 }, teleportTo = { x = 33941, y = 31112, z = 8 } }, + }, +} + +-- Initialize ebb and flow zone area +SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) + +SoulCagePosition = Position(33709, 31596, 14) +TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days +GreedbeastKills = 0 + +SoulWarReflectDamageMap = { + [COMBAT_PHYSICALDAMAGE] = 10, + [COMBAT_FIREDAMAGE] = 10, + [COMBAT_EARTHDAMAGE] = 10, + [COMBAT_ENERGYDAMAGE] = 10, + [COMBAT_ICEDAMAGE] = 10, + [COMBAT_HOLYDAMAGE] = 10, + [COMBAT_DEATHDAMAGE] = 10, +} + +local soulWarTaints = { + "taints-teleport", -- Taint 1 + "taints-spawn", -- Taint 2 + "taints-damage", -- Taint 3 + "taints-heal", -- Taint 4 + "taints-loss", -- Taint 5 +} + +SoulWarBosses = { + ["Goshnar's Malice"] = true, + ["Goshnar's Hatred"] = true, + ["Goshnar's Spite"] = true, + ["Goshnar's Cruelty"] = true, + ["Goshnar's Greed"] = true, +} + +GreedMonsters = { + ["Greedbeast"] = Position(33744, 31666, 14), + ["Soulsnatcher"] = Position(33747, 31668, 14), + ["Weak Soul"] = Position(33750, 31666, 14), + ["Strong Soul"] = Position(33750, 31666, 14), + ["Powerful Soul"] = Position(33750, 31666, 14), +} + +function CreateGoshnarsGreedMonster(name, position) + local function sendEffect() + position:sendMagicEffect(CONST_ME_TELEPORT) + end + + local function spawnMonster() + Game.createMonster(name, position, true, false) + logger.debug("Spawning {} in position {}", name, position:toString()) + end + + for i = 7, 9 do + addEvent(sendEffect, i * 1000) + end + + addEvent(spawnMonster, 10000) +end + +local soulWarSpawnMonsters = { + ["soulwars.claustrophobic-inferno"] = "Brachiodemon", + ["soulwars.mirrored-nightmare"] = "Many Faces", + ["soulwars.ebb-and-flow"] = "Bony Sea Devil", + ["soulwars.furious-crater"] = "Cloak of Terror", + ["soulwars.rotten-wasteland"] = "Branchy Crawler", + ["boss-rooms"] = "Dreadful Harvester", +} + +function RemoveSoulCageAndBuffMalice() + local tile = Tile(SoulCagePosition) + local creatures = tile:getCreatures() or {} + local soulCage + for i, creature in ipairs(creatures) do + if creature:getName() == "Soul Cage" then + soulCage = creature + logger.debug("Removing Soul Cage, the players not be able to kill him") + break + end + end + + local rangeX = 20 + local rangeY = 20 + local spectators = Game.getSpectators(Position(33709, 31599, 14), false, false, rangeX, rangeX, rangeY, rangeY) + if soulCage then + local malice + for i = 1, #spectators do + logger.debug("Specs found {}", i) + if spectators[i]:isMonster() then + logger.debug("Malice Spectators {}", spectators[i]:getName()) + if spectators[i]:getName() == "Goshnar's Malice" then + logger.debug("Found malice") + malice = Monster(spectators[i]) + break + end + end + end + + soulCage:remove() + addEvent(SpawnSoulCage, 23000) + + if malice then + logger.debug("Found malice, try adding reflect and defense") + for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do + malice:addReflectElement(elementType, reflectPercent) + end + malice:addDefense(10) + end + end +end + +function SpawnSoulCage() + local tile = Tile(SoulCagePosition) + local creatures = tile:getCreatures() or {} + local soulCage + for i, creature in ipairs(creatures) do + if creature:getName() == "Soul Cage" then + soulCage = true + break + end + end + + if not soulCage then + Game.createMonster("Soul Cage", SoulCagePosition, true, true) + logger.debug("Spawning Soul Cage in position {}", SoulCagePosition:toString()) + addEvent(RemoveSoulCageAndBuffMalice, 40000) + end +end + +local function shuffle(list) + for i = #list, 2, -1 do + local j = math.random(i) + list[i], list[j] = list[j], list[i] + end +end + +local function createConnectedGroup(startPos, groupPositions, groupSize) + local group = { startPos } + local lastPos = startPos + local directions = { + { x = 1, y = 0 }, + { x = -1, y = 0 }, -- Right and left + { x = 0, y = 1 }, + { x = 0, y = -1 }, -- Up and down + { x = 1, y = 1 }, + { x = -1, y = -1 }, -- Diagonals + { x = -1, y = 1 }, + { x = 1, y = -1 }, + } + + for i = 2, groupSize do + shuffle(directions) + local nextPos = nil + for _, dir in ipairs(directions) do + local potentialNextPos = Position(lastPos.x + dir.x, lastPos.y + dir.y, lastPos.z) + if table.contains(groupPositions, potentialNextPos) then + nextPos = potentialNextPos + break + end + end + + if nextPos then + table.insert(group, nextPos) + table.remove(groupPositions, table.find(groupPositions, nextPos)) + lastPos = nextPos + else + break + end + end + + return group +end + +local function generatePositionsInRange(center, range) + local positions = {} + for x = center.x - range, center.x + range do + for y = center.y - range, center.y + range do + table.insert(positions, Position(x, y, center.z)) + end + end + return positions +end + +local toRevertPositions = {} + +local function revertTilesAndApplyDamage(zonePositions) + for _, pos in ipairs(zonePositions) do + local tile = Tile(pos) + if tile and tile:getGround() and tile:getGround():getId() ~= 409 then + local creature = tile:getTopCreature() + if creature then + local player = creature:getPlayer() + if player then + pos:sendMagicEffect(CONST_ME_REDSMOKE) + player:addHealth(-8000, COMBAT_DEATHDAMAGE) + end + end + end + end + + for posString, itemId in pairs(toRevertPositions) do + local pos = posString:toPosition() + local tile = Tile(pos) + if tile and tile:getGround() and tile:getGround():getId() == 409 then + tile:getGround():transform(itemId) + toRevertPositions[pos:toString()] = nil + end + end +end + +function Monster:createSoulWarWhiteTiles(centerRoomPosition, zonePositions, executeInterval) + local groupPositions = generatePositionsInRange(centerRoomPosition, 7) + local totalTiles = 11 + local groupSize = 3 + local groupsCreated = 0 + + -- Run only for megalomania boss + if executeInterval then + -- Remove remains + for _, pos in ipairs(zonePositions) do + local tile = Tile(pos) + if tile and tile:getGround() then + local remains = tile:getItemById(33984) + if remains then + remains:remove() + end + end + end + end + + while #groupPositions > 0 and groupsCreated * groupSize < totalTiles do + local randomIndex = math.random(#groupPositions) + local startPos = groupPositions[randomIndex] + table.remove(groupPositions, randomIndex) + + local group = createConnectedGroup(startPos, groupPositions, groupSize) + for _, pos in ipairs(group) do + local tile = Tile(pos) + if tile then + toRevertPositions[pos:toString()] = tile:getGround():getId() + tile:getGround():transform(409) + end + end + + groupsCreated = groupsCreated + 1 + end + + addEvent(revertTilesAndApplyDamage, executeInterval or 3000, zonePositions) +end + +function Monster:generateBagYouDesireLoot(player) + local playerTaintLevel = player:getTaintLevel() + if not playerTaintLevel then + return {} + end + + local monsterName = self:getName() + local isMonsterValid = false + for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do + if monsterName == monster then + isMonsterValid = true + break + end + end + + if not isMonsterValid then + return {} + end + + -- Calculates the chances based on the number of taints + local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) + logger.debug("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + -- Generate loot + local loot = {} + if math.random(1, 100) <= totalChance then + local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) + if itemType then + loot[itemType:getId()] = { count = 1 } + logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) + end + end + + return loot +end + +local intervalBetweenExecutions = 10000 + +local accumulatedTime = 0 +local desiredInterval = 40000 +local bossSayInterval = 38000 + +function Monster:onThinkMegalomaniaWhiteTiles(interval, zonePositions, revertTime) + self:onThinkGoshnarTormentCounter(interval, 36, intervalBetweenExecutions, SoulWarQuest.levers.goshnarsMegalomania.boss.position) + + accumulatedTime = accumulatedTime + interval + + if accumulatedTime == bossSayInterval then + self:say("FEEL THE POWER OF MY WRATH!!") + end + -- Execute only after 40 seconds + if accumulatedTime >= desiredInterval then + self:createSoulWarWhiteTiles(SoulWarQuest.levers.goshnarsMegalomania.boss.position, zonePositions, revertTime) + accumulatedTime = 0 + end +end + +TaintTeleportCooldown = {} + +function Player:getTaintNameByNumber(taintNumber) + local haveTaintName = nil + local soulWarQuest = self:soulWarQuestKV() + local taintName = soulWarTaints[taintNumber] + if taintName and soulWarQuest:get(taintName) then + haveTaintName = taintName + end + + return haveTaintName +end + +function Player:addNextTaint() + local soulWarQuest = self:soulWarQuestKV() + for _, taint in ipairs(soulWarTaints) do + if not soulWarQuest:get(taint) then + soulWarQuest:set(taint, true) + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taint .. ".") + break + end + end +end + +function Player:getTaintLevel() + local taintLevel = nil + local soulWarQuest = self:soulWarQuestKV() + for i, taint in ipairs(soulWarTaints) do + if soulWarQuest:get(taint) then + taintLevel = i + end + end + + return taintLevel +end + +function Player:resetTaints() + local soulWarQuest = self:soulWarQuestKV() + local firstTaintTime = soulWarQuest:get("firstTaintTime") + if firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then + -- Reset all taints + for _, taint in ipairs(soulWarTaints) do + if soulWarQuest:get(taint) then + soulWarQuest:remove(taint) + end + end + + soulWarQuest:remove("firstTaintTime") + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") + end +end + +function Monster:tryTeleportToPlayer(sayMessage) + local range = 30 + local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) + local maxDistance = 0 + local farthestPlayer = nil + logger.debug("Checking teleport monster for monster {}", self:getName()) + for i, spectator in ipairs(spectators) do + if spectator:isPlayer() then + local player = spectator:getPlayer() + if player:getTaintNameByNumber(1) ~= nil then + local distance = self:getPosition():getDistance(player:getPosition()) + if distance > maxDistance then + maxDistance = distance + farthestPlayer = player + logger.debug("Found player {} to teleport", player:getName()) + end + end + end + end + + if farthestPlayer and math.random(100) <= 10 then + local playerPosition = farthestPlayer:getPosition() + if TaintTeleportCooldown[farthestPlayer:getId()] then + logger.debug("Cooldown is active to player {}", farthestPlayer:getName()) + return + end + + if not TaintTeleportCooldown[farthestPlayer:getId()] then + TaintTeleportCooldown[farthestPlayer:getId()] = true + + logger.debug("Scheduling player {} to teleport", farthestPlayer:getName()) + self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) + farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) + addEvent(function(playerId, monsterId) + local monsterEvent = Monster(monsterId) + local playerEvent = Player(playerId) + if monsterEvent and playerEvent then + local destinationTile = Tile(playerPosition) + if destinationTile and not (destinationTile:hasProperty(CONST_PROP_BLOCKPROJECTILE) or destinationTile:hasProperty(CONST_PROP_MOVEABLE)) then + monsterEvent:say(sayMessage) + monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + monsterEvent:teleportTo(playerPosition, true) + monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + end + end + end, 2000, farthestPlayer:getId(), self:getId()) + + addEvent(function(playerId) + local playerEvent = Player(playerId) + if not playerEvent then + return + end + + logger.debug("Cleaning player cooldown") + TaintTeleportCooldown[playerEvent:getId()] = nil + end, 10000, farthestPlayer:getId()) + end + end +end + +function Monster:getSoulWarKV() + return SoulWarQuest.kvSoulWar:scoped("monster"):scoped(self:getName()) +end + +function Monster:getHatredDamageMultiplier() + return self:getSoulWarKV():get("burning-hatred-empowered") or 0 +end + +function Monster:increaseHatredDamageMultiplier(multiplierCount) + local attackMultiplier = self:getHatredDamageMultiplier() + self:getSoulWarKV():set("burning-hatred-empowered", attackMultiplier + multiplierCount or 10) +end + +function Monster:resetHatredDamageMultiplier() + self:getSoulWarKV():remove("burning-hatred-empowered") +end + +function Position:increaseNecromaticMegalomaniaStrength() + local tile = Tile(self) + if tile then + local item = tile:getItemById(SoulWarQuest.necromanticRemainsId) + if item then + local boss = Creature("Goshnar's Megalomania") + if boss then + boss:increaseHatredDamageMultiplier(5) + item:remove() + logger.debug("Necromantic remains strength increased") + end + end + end +end + +local lastExecutionTime = 0 + +-- Damage 24 to 36 have a special damage +local damageTable = { + 1400, + 1600, + 1800, + 2200, + 2400, + 2600, + 3000, + 3400, + 3800, + 4200, + 4800, + 5200, + 5600, +} + +function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetweenExecutions, bossPosition) + local interval = os.time() * 1000 + if interval - lastExecutionTime < intervalBetweenExecutions then + return + end + + lastExecutionTime = interval + logger.debug("Icon time count {}", interval) + local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) + for i = 1, #spectators do + local player = spectators[i] + local tormentCounter = player:getGoshnarSymbolTormentCounter() + if tormentCounter <= maxLimit then + player:increaseGoshnarSymbolTormentCounter(maxLimit) + logger.debug("Player {} has {} damage counter", player:getName(), tormentCounter) + + if tormentCounter > 0 then + local damage = tormentCounter * 35 + if tormentCounter >= 24 then + damage = damageTable[tormentCounter - 23] + end + + logger.debug("Final damage {}", damage) + player:addHealth(-damage, COMBAT_DEATHDAMAGE) + player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) + end + end + + if tormentCounter == 5 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread starts to torment you! Don't let dread level reach critical value!") + elseif tormentCounter == 15 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment becomes unbearable!") + elseif tormentCounter == 24 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The Dread's torment begins to tear you apart!") + elseif tormentCounter == 30 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is killing you!") + elseif tormentCounter == 36 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is now lethal!") + end + end +end + +function Monster:increaseAspectOfPowerDeathCount() + local bossKV = self:getSoulWarKV() + local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 + local newCount = aspectDeathCount + 1 + logger.debug("Aspect of Power death count {}", newCount) + bossKV:set("aspect-of-power-death-count", newCount) + if newCount == 4 then + self:setType("Goshnar's Megalomania Green") + self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") + bossKV:set("aspect-of-power-death-count", 0) + logger.debug("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") + SoulWarQuest.changePurpleEvent = addEvent(function() + local boss = Creature("Goshnar's Megalomania") + if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then + boss:setType("Goshnar's Megalomania Purple") + boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") + logger.debug("Megalomania is now immune again") + end + end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) + end +end + +function Monster:goshnarsDefenseIncrease(kvName) + local currentTime = os.time() + -- Gets the time when the "Greedy Maw" item was last used. + local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 + -- Checks if more than config time have passed since the item was last used. + if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then + logger.debug("{} old defense {}", self:getName(), self:getDefense()) + self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) + logger.debug("{} new defense {}", self:getName(), self:getDefense()) + + --- Updates the KV to reflect the timing of the increase to maintain control. + SoulWarQuest.kvSoulWar:set(kvName, currentTime) + else + -- If config time have not passed, logs the increase has been skipped. + logger.debug("{} skips increase cooldown due to recent item use.", self:getName()) + end +end + +function Player:getSoulWarZoneMonster() + local zoneMonsterName = nil + for zoneName, monsterName in pairs(soulWarSpawnMonsters) do + local zone = Zone.getByName(zoneName) + if zone and zone:isInZone(self:getPosition()) then + zoneMonsterName = monsterName + break + end + end + + return zoneMonsterName +end + +function Player:isInBoatSpot() + -- Get ebb and flow zone and check if player is in zone + local zone = SoulWarQuest.ebbAndFlow.getZone() + local tile = Tile(self:getPosition()) + local groundId + if tile and tile:getGround() then + groundId = tile:getGround():getId() + end + if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then + logger.debug("Player {} is in boat spot", self:getName()) + return true + end + + logger.debug("Player {} is not in boat spot", self:getName()) + return false +end + +function Player:soulWarQuestKV() + return self:kv():scoped("quest"):scoped("soul-war") +end + +function Player:getGoshnarSymbolTormentCounter() + local soulWarKV = self:soulWarQuestKV() + return soulWarKV:get("goshnars-hatred-torment-count") or 0 +end + +function Player:increaseGoshnarSymbolTormentCounter(maxLimit) + local soulWarKV = self:soulWarQuestKV() + local tormentCount = self:getGoshnarSymbolTormentCounter() + if tormentCount == maxLimit then + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount) + return + end + + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount + 1) + soulWarKV:set("goshnars-hatred-torment-count", tormentCount + 1) +end + +function Player:removeGoshnarSymbolTormentCounter(count) + local soulWarKV = self:soulWarQuestKV() + local tormentCount = self:getGoshnarSymbolTormentCounter() + if tormentCount > count then + self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount - count) + soulWarKV:set("goshnars-hatred-torment-count", tormentCount - count) + else + self:resetGoshnarSymbolTormentCounter() + end +end + +function Player:resetGoshnarSymbolTormentCounter() + local soulWarKV = self:soulWarQuestKV() + soulWarKV:remove("goshnars-hatred-torment-count") + self:removeIcon("goshnars-hatred-damage") +end + +function Player:furiousCraterKV() + return self:soulWarQuestKV():scoped("furius-crater") +end + +function Player:pulsatingEnergyKV() + return self:furiousCraterKV():scoped("pulsating-energy") +end + +function Zone:getRandomPlayer() + local players = self:getPlayers() + if #players == 0 then + return nil + end + + local randomIndex = math.random(#players) + return players[randomIndex] +end + +local function delayedCastSpell(cid, var, combat, targetId) + local creature = Creature(cid) + if not creature then + return + end + + local target = Player(targetId) + if target then + combat:execute(creature, positionToVariant(target:getPosition())) + end +end + +function Creature:applyZoneEffect(var, combat, zoneName) + local outfitConfig = { + outfit = { lookType = 242, lookHead = 0, lookBody = 0, lookLegs = 0, lookFeet = 0, lookAddons = 0 }, + time = 7000, + } + + local zone = Zone.getByName(zoneName) + if not zone then + logger.error("Could not find zone '" .. zoneName .. "', you need use the 'BossLever' system") + return false + end + + local target = zone:getRandomPlayer() + if not target then + return true + end + + local condition = Condition(CONDITION_OUTFIT) + condition:setTicks(outfitConfig.time) + condition:setOutfit(outfitConfig.outfit) + target:addCondition(condition) + target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) + + addEvent(delayedCastSpell, SoulWarQuest.goshnarsCrueltyWaveInterval * 1000, self:getId(), var, combat, target:getId()) + + return true +end + +function string.toPosition(str) + local patterns = { + -- table format + "{%s*x%s*=%s*(%d+)%s*,%s*y%s*=%s*(%d+)%s*,%s*z%s*=%s*(%d+)%s*}", + -- Position format + "Position%s*%((%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)", + -- x, y, z format + "(%d+)%s*,%s*(%d+)%s*,%s*(%d+)", + } + + for _, pattern in ipairs(patterns) do + local x, y, z = string.match(str, pattern) + if x and y and z then + return Position(tonumber(x), tonumber(y), tonumber(z)) + end + end +end From 8b6819b7e18461de75f14fe3fa3689652cea64bf Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 20:47:19 -0300 Subject: [PATCH 10/31] fix: goshnar's malice damage white tiles and add zones --- .../scripts/lib/quests/soul-war.lua | 98 ++++++++++++++----- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index ba44d49943f..e4fcfe4d4bb 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -67,6 +67,14 @@ SoulWarQuest = { "Courage Leech", }, + miniBosses = { + ["Goshnar's Malice"] = true, + ["Goshnar's Hatred"] = true, + ["Goshnar's Spite"] = true, + ["Goshnar's Cruelty"] = true, + ["Goshnar's Greed"] = true, + }, + finalRewards = { { id = 34082, name = "soulcutter" }, { id = 34083, name = "soulshredder" }, @@ -109,6 +117,28 @@ SoulWarQuest = { { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, }, + areaZones = { + monsters = { + ["zone.claustrophobic-inferno"] = "Brachiodemon", + ["zone.mirrored-nightmare"] = "Many Faces", + ["zone.ebb-and-flow"] = "Bony Sea Devil", + ["zone.furious-crater"] = "Cloak of Terror", + ["zone.rotten-wasteland"] = "Branchy Crawler", + ["boss.goshnar's-malice"] = "Dreadful Harvester", + ["boss.goshnar's-spite"] = "Dreadful Harvester", + ["boss.goshnar's-greed"] = "Dreadful Harvester", + ["boss.goshnar's-hatred"] = "Dreadful Harvester", + ["boss.goshnar's-cruelty"] = "Dreadful Harvester", + ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", + }, + + caustrophobicInferno = Zone("zone.claustrophobic-inferno"), + mirroredNightmare = Zone("zone.mirrored-nightmare"), + ebbAndFlow = Zone("zone.ebb-and-flow"), + furiousCrater = Zone("zone.furious-crater"), + rottenWasteland = Zone("zone.rotten-wasteland"), + }, + -- Levers configuration levers = { goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, @@ -652,6 +682,17 @@ SoulWarQuest = { -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) +-- Initialize bosses access for taint check +SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) + +SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) + +SoulWarQuest.areaZones.furiousCrater:addArea({ x = 33814, y = 31819, z = 3 }, { x = 33907, y = 31920, z = 7 }) + +SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, { x = 33901, y = 31105, z = 12 }) + +SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) + SoulCagePosition = Position(33709, 31596, 14) TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days GreedbeastKills = 0 @@ -674,14 +715,6 @@ local soulWarTaints = { "taints-loss", -- Taint 5 } -SoulWarBosses = { - ["Goshnar's Malice"] = true, - ["Goshnar's Hatred"] = true, - ["Goshnar's Spite"] = true, - ["Goshnar's Cruelty"] = true, - ["Goshnar's Greed"] = true, -} - GreedMonsters = { ["Greedbeast"] = Position(33744, 31666, 14), ["Soulsnatcher"] = Position(33747, 31668, 14), @@ -707,15 +740,6 @@ function CreateGoshnarsGreedMonster(name, position) addEvent(spawnMonster, 10000) end -local soulWarSpawnMonsters = { - ["soulwars.claustrophobic-inferno"] = "Brachiodemon", - ["soulwars.mirrored-nightmare"] = "Many Faces", - ["soulwars.ebb-and-flow"] = "Bony Sea Devil", - ["soulwars.furious-crater"] = "Cloak of Terror", - ["soulwars.rotten-wasteland"] = "Branchy Crawler", - ["boss-rooms"] = "Dreadful Harvester", -} - function RemoveSoulCageAndBuffMalice() local tile = Tile(SoulCagePosition) local creatures = tile:getCreatures() or {} @@ -832,18 +856,41 @@ end local toRevertPositions = {} +local tileItemIds = { + 32906, + 33066, + 33067, + 33068, + 33069, + 33070, +} + local function revertTilesAndApplyDamage(zonePositions) for _, pos in ipairs(zonePositions) do local tile = Tile(pos) - if tile and tile:getGround() and tile:getGround():getId() ~= 409 then - local creature = tile:getTopCreature() - if creature then - local player = creature:getPlayer() - if player then - pos:sendMagicEffect(CONST_ME_REDSMOKE) - player:addHealth(-8000, COMBAT_DEATHDAMAGE) + if tile and tile:getGround() then + if tile:getGround():getId() ~= 409 then + local creature = tile:getTopCreature() + if creature then + local player = creature:getPlayer() + if player then + player:addHealth(-8000, COMBAT_DEATHDAMAGE) + end end end + + local itemFound = false + for i = 1, #tileItemIds do + local item = tile:getItemById(tileItemIds[i]) + if item then + itemFound = true + break + end + end + + if tile:getGround():getId() == 410 and not itemFound and not tile:getItemByTopOrder(1) and not tile:getItemByTopOrder(3) then + pos:sendMagicEffect(CONST_ME_REDSMOKE) + end end end @@ -1010,7 +1057,6 @@ function Monster:tryTeleportToPlayer(sayMessage) local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) local maxDistance = 0 local farthestPlayer = nil - logger.debug("Checking teleport monster for monster {}", self:getName()) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() @@ -1200,7 +1246,7 @@ end function Player:getSoulWarZoneMonster() local zoneMonsterName = nil - for zoneName, monsterName in pairs(soulWarSpawnMonsters) do + for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do local zone = Zone.getByName(zoneName) if zone and zone:isInZone(self:getPosition()) then zoneMonsterName = monsterName From 4ce0e9506cd56317552a36543be7feeb159dc9ab Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:27:31 -0300 Subject: [PATCH 11/31] fix: ebb and flow fixed map --- data-otservbr-global/scripts/lib/quests/soul-war.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index e4fcfe4d4bb..167d33eddc8 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -344,6 +344,7 @@ SoulWarQuest = { mapsPath = { empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", + ebbFlow = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm", }, -- In Minutes @@ -1060,12 +1061,12 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1) ~= nil then + if player:getTaintNameByNumber(1) then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance farthestPlayer = player - logger.debug("Found player {} to teleport", player:getName()) + logger.trace("Found player {} to teleport", player:getName()) end end end From d09a1ae4873d7d54bd10c909c47d51ab086608a3 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:48:04 -0300 Subject: [PATCH 12/31] fix: simplify some functions, logs to trace and map fixes --- .../scripts/lib/quests/soul-war.lua | 81 ++++++------------- 1 file changed, 24 insertions(+), 57 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index 167d33eddc8..4a8a47ee131 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -242,7 +242,7 @@ SoulWarQuest = { timeToFightAgain = 20 * 60 * 60, -- 20 hours onUseExtra = function(player) SoulWarQuest.kvBurning:set("time", 180) - logger.debug("Goshnar's Hatred burning change form time set to: {}", 180) + logger.trace("Goshnar's Hatred burning change form time set to: {}", 180) player:resetGoshnarSymbolTormentCounter() end, }, @@ -378,7 +378,7 @@ SoulWarQuest = { SoulWarQuest.ebbAndFlow.reloadZone() local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() for _, player in ipairs(players) do - logger.debug("Updating player: {}", player:getName()) + logger.trace("Updating player: {}", player:getName()) player:sendCreatureAppear() end end @@ -731,7 +731,7 @@ function CreateGoshnarsGreedMonster(name, position) local function spawnMonster() Game.createMonster(name, position, true, false) - logger.debug("Spawning {} in position {}", name, position:toString()) + logger.trace("Spawning {} in position {}", name, position:toString()) end for i = 7, 9 do @@ -742,39 +742,13 @@ function CreateGoshnarsGreedMonster(name, position) end function RemoveSoulCageAndBuffMalice() - local tile = Tile(SoulCagePosition) - local creatures = tile:getCreatures() or {} - local soulCage - for i, creature in ipairs(creatures) do - if creature:getName() == "Soul Cage" then - soulCage = creature - logger.debug("Removing Soul Cage, the players not be able to kill him") - break - end - end - - local rangeX = 20 - local rangeY = 20 - local spectators = Game.getSpectators(Position(33709, 31599, 14), false, false, rangeX, rangeX, rangeY, rangeY) + local soulCage = Creature("Soul Cage") if soulCage then - local malice - for i = 1, #spectators do - logger.debug("Specs found {}", i) - if spectators[i]:isMonster() then - logger.debug("Malice Spectators {}", spectators[i]:getName()) - if spectators[i]:getName() == "Goshnar's Malice" then - logger.debug("Found malice") - malice = Monster(spectators[i]) - break - end - end - end - soulCage:remove() addEvent(SpawnSoulCage, 23000) - + local malice = Creature("Goshnar's Malice") if malice then - logger.debug("Found malice, try adding reflect and defense") + logger.trace("Found malice, try adding reflect and defense") for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do malice:addReflectElement(elementType, reflectPercent) end @@ -786,17 +760,10 @@ end function SpawnSoulCage() local tile = Tile(SoulCagePosition) local creatures = tile:getCreatures() or {} - local soulCage - for i, creature in ipairs(creatures) do - if creature:getName() == "Soul Cage" then - soulCage = true - break - end - end - + local soulCage = Creature("Soul Cage") if not soulCage then Game.createMonster("Soul Cage", SoulCagePosition, true, true) - logger.debug("Spawning Soul Cage in position {}", SoulCagePosition:toString()) + logger.trace("Spawning Soul Cage in position {}", SoulCagePosition:toString()) addEvent(RemoveSoulCageAndBuffMalice, 40000) end end @@ -966,7 +933,7 @@ function Monster:generateBagYouDesireLoot(player) -- Calculates the chances based on the number of taints local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - logger.debug("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) -- Generate loot local loot = {} if math.random(1, 100) <= totalChance then @@ -1075,14 +1042,14 @@ function Monster:tryTeleportToPlayer(sayMessage) if farthestPlayer and math.random(100) <= 10 then local playerPosition = farthestPlayer:getPosition() if TaintTeleportCooldown[farthestPlayer:getId()] then - logger.debug("Cooldown is active to player {}", farthestPlayer:getName()) + logger.trace("Cooldown is active to player {}", farthestPlayer:getName()) return end if not TaintTeleportCooldown[farthestPlayer:getId()] then TaintTeleportCooldown[farthestPlayer:getId()] = true - logger.debug("Scheduling player {} to teleport", farthestPlayer:getName()) + logger.trace("Scheduling player {} to teleport", farthestPlayer:getName()) self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) addEvent(function(playerId, monsterId) @@ -1105,7 +1072,7 @@ function Monster:tryTeleportToPlayer(sayMessage) return end - logger.debug("Cleaning player cooldown") + logger.trace("Cleaning player cooldown") TaintTeleportCooldown[playerEvent:getId()] = nil end, 10000, farthestPlayer:getId()) end @@ -1138,7 +1105,7 @@ function Position:increaseNecromaticMegalomaniaStrength() if boss then boss:increaseHatredDamageMultiplier(5) item:remove() - logger.debug("Necromantic remains strength increased") + logger.trace("Necromantic remains strength increased") end end end @@ -1170,14 +1137,14 @@ function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetwee end lastExecutionTime = interval - logger.debug("Icon time count {}", interval) + logger.trace("Icon time count {}", interval) local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) for i = 1, #spectators do local player = spectators[i] local tormentCounter = player:getGoshnarSymbolTormentCounter() if tormentCounter <= maxLimit then player:increaseGoshnarSymbolTormentCounter(maxLimit) - logger.debug("Player {} has {} damage counter", player:getName(), tormentCounter) + logger.trace("Player {} has {} damage counter", player:getName(), tormentCounter) if tormentCounter > 0 then local damage = tormentCounter * 35 @@ -1185,7 +1152,7 @@ function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetwee damage = damageTable[tormentCounter - 23] end - logger.debug("Final damage {}", damage) + logger.trace("Final damage {}", damage) player:addHealth(-damage, COMBAT_DEATHDAMAGE) player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) end @@ -1209,19 +1176,19 @@ function Monster:increaseAspectOfPowerDeathCount() local bossKV = self:getSoulWarKV() local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 local newCount = aspectDeathCount + 1 - logger.debug("Aspect of Power death count {}", newCount) + logger.trace("Aspect of Power death count {}", newCount) bossKV:set("aspect-of-power-death-count", newCount) if newCount == 4 then self:setType("Goshnar's Megalomania Green") self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") bossKV:set("aspect-of-power-death-count", 0) - logger.debug("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") + logger.trace("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") SoulWarQuest.changePurpleEvent = addEvent(function() local boss = Creature("Goshnar's Megalomania") if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then boss:setType("Goshnar's Megalomania Purple") boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") - logger.debug("Megalomania is now immune again") + logger.trace("Megalomania is now immune again") end end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) end @@ -1233,15 +1200,15 @@ function Monster:goshnarsDefenseIncrease(kvName) local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 -- Checks if more than config time have passed since the item was last used. if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then - logger.debug("{} old defense {}", self:getName(), self:getDefense()) + logger.trace("{} old defense {}", self:getName(), self:getDefense()) self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) - logger.debug("{} new defense {}", self:getName(), self:getDefense()) + logger.trace("{} new defense {}", self:getName(), self:getDefense()) --- Updates the KV to reflect the timing of the increase to maintain control. SoulWarQuest.kvSoulWar:set(kvName, currentTime) else -- If config time have not passed, logs the increase has been skipped. - logger.debug("{} skips increase cooldown due to recent item use.", self:getName()) + logger.trace("{} skips increase cooldown due to recent item use.", self:getName()) end end @@ -1267,11 +1234,11 @@ function Player:isInBoatSpot() groundId = tile:getGround():getId() end if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then - logger.debug("Player {} is in boat spot", self:getName()) + logger.trace("Player {} is in boat spot", self:getName()) return true end - logger.debug("Player {} is not in boat spot", self:getName()) + logger.trace("Player {} is not in boat spot", self:getName()) return false end From 6deea1428bcfcac89e91cbc2422809b5e26e7d14 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 15 Apr 2024 18:45:29 -0300 Subject: [PATCH 13/31] fix: add condition for taint icon --- .../scripts/lib/quests/soul-war.lua | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua index 4a8a47ee131..7ebe42b0441 100644 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ b/data-otservbr-global/scripts/lib/quests/soul-war.lua @@ -970,11 +970,11 @@ end TaintTeleportCooldown = {} -function Player:getTaintNameByNumber(taintNumber) +function Player:getTaintNameByNumber(taintNumber, skipKvCheck) local haveTaintName = nil local soulWarQuest = self:soulWarQuestKV() local taintName = soulWarTaints[taintNumber] - if taintName and soulWarQuest:get(taintName) then + if skipKvCheck or taintName and soulWarQuest:get(taintName) then haveTaintName = taintName end @@ -983,15 +983,29 @@ end function Player:addNextTaint() local soulWarQuest = self:soulWarQuestKV() - for _, taint in ipairs(soulWarTaints) do - if not soulWarQuest:get(taint) then - soulWarQuest:set(taint, true) - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taint .. ".") + for _, taintName in ipairs(soulWarTaints) do + if not soulWarQuest:get(taintName) then + soulWarQuest:set(taintName, true) + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taintName .. ".") + self:setTaintIcon() break end end end +function Player:setTaintIcon(taintId) + self:resetTaintConditions() + local condition = Condition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, taintId or self:getTaintLevel()) + condition:setTicks(14 * 24 * 60 * 60 * 1000) + self:addCondition(condition) +end + +function Player:resetTaintConditions() + for i = 1, 5 do + self:removeCondition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, i) + end +end + function Player:getTaintLevel() local taintLevel = nil local soulWarQuest = self:soulWarQuestKV() @@ -1004,17 +1018,17 @@ function Player:getTaintLevel() return taintLevel end -function Player:resetTaints() +function Player:resetTaints(skipCheckTime) local soulWarQuest = self:soulWarQuestKV() local firstTaintTime = soulWarQuest:get("firstTaintTime") - if firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then - -- Reset all taints - for _, taint in ipairs(soulWarTaints) do - if soulWarQuest:get(taint) then - soulWarQuest:remove(taint) + if skipCheckTime or firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then + -- Reset all taints and remove condition + for _, taintName in ipairs(soulWarTaints) do + if soulWarQuest:get(taintName) then + soulWarQuest:remove(taintName) end end - + self:resetTaintConditions() soulWarQuest:remove("firstTaintTime") self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") end @@ -1028,7 +1042,7 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1) then + if player:getTaintNameByNumber(1, true) then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance From 7addabd005a3022389f580bb7fa4694e733abda3 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Tue, 16 Apr 2024 10:10:18 -0300 Subject: [PATCH 14/31] fix: change soul war table to lib folder --- data-otservbr-global/lib/quests/soul_war.lua | 201 +-- .../scripts/lib/quests/soul-war.lua | 1371 ----------------- 2 files changed, 18 insertions(+), 1554 deletions(-) delete mode 100644 data-otservbr-global/scripts/lib/quests/soul-war.lua diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 319d731faf7..7ebe42b0441 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -51,12 +51,13 @@ SoulWarQuest = { "Sorcerer's Apparition", "Turbulent Elemental", "Vibrant Phantom.", + }, + bagYouDesireBosses = { "Goshnar's Cruelty", "Goshnar's Spite", "Goshnar's Malice", "Goshnar's Hatred", "Goshnar's Greed", - "Goshnar's Megalomania", }, -- Goshnar's Cruelty pulsating energy monsters @@ -116,108 +117,6 @@ SoulWarQuest = { { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, }, - claustrophobicInfernoRaids = { - [1] = { - zoneArea = { - { x = 33985, y = 31053, z = 9 }, - { x = 34045, y = 31077, z = 9 }, - }, - sandTimerPositions = { - { x = 34012, y = 31049, z = 9 }, - { x = 34013, y = 31049, z = 9 }, - { x = 34014, y = 31049, z = 9 }, - { x = 34015, y = 31049, z = 9 }, - }, - zone = Zone("raid.first-claustrophobic-inferno"), - spawns = { - Position(33991, 31064, 9), - Position(34034, 31060, 9), - Position(34028, 31067, 9), - Position(34020, 31067, 9), - Position(34008, 31067, 9), - Position(34001, 31059, 9), - Position(33992, 31069, 9), - Position(34002, 31072, 9), - Position(34013, 31074, 9), - Position(33998, 31060, 9), - Position(34039, 31065, 9), - Position(34032, 31072, 9), - }, - exitPosition = { x = 34009, y = 31083, z = 9 }, - getZone = function() - return SoulWarQuest.claustrophobicInfernoRaids[1].zone - end, - }, - [2] = { - zoneArea = { - { x = 33988, y = 31042, z = 10 }, - { x = 34043, y = 31068, z = 10 }, - }, - sandTimerPositions = { - { x = 34012, y = 31075, z = 10 }, - { x = 34011, y = 31075, z = 10 }, - { x = 34010, y = 31075, z = 10 }, - }, - zone = Zone("raid.second-claustrophobic-inferno"), - spawns = { - Position(33999, 31046, 10), - Position(34011, 31047, 10), - Position(34015, 31052, 10), - Position(34021, 31044, 10), - Position(34029, 31054, 10), - Position(34037, 31052, 10), - Position(34037, 31060, 10), - Position(34023, 31062, 10), - Position(34012, 31061, 10), - Position(33998, 31061, 10), - Position(34005, 31052, 10), - }, - exitPosition = { x = 34011, y = 31028, z = 10 }, - getZone = function() - return SoulWarQuest.claustrophobicInfernoRaids[2].zone - end, - }, - [3] = { - zoneArea = { - { x = 33987, y = 31043, z = 11 }, - { x = 34044, y = 31076, z = 11 }, - }, - sandTimerPositions = { - { x = 34009, y = 31036, z = 11 }, - { x = 34010, y = 31036, z = 11 }, - { x = 34011, y = 31036, z = 11 }, - { x = 34012, y = 31036, z = 11 }, - { x = 34013, y = 31036, z = 11 }, - { x = 34014, y = 31036, z = 11 }, - }, - zone = Zone("raid.third-claustrophobic-inferno"), - spawns = { - Position(34005, 31049, 11), - Position(33999, 31051, 11), - Position(33995, 31055, 11), - Position(33999, 31068, 11), - Position(34016, 31068, 11), - Position(34030, 31070, 11), - Position(34038, 31066, 11), - Position(34038, 31051, 11), - Position(34033, 31051, 11), - Position(34025, 31049, 11), - Position(34013, 31058, 11), - Position(34021, 31059, 11), - Position(34027, 31063, 11), - Position(34007, 31063, 11), - Position(34004, 31059, 11), - }, - exitPosition = { x = 34014, y = 31085, z = 11 }, - getZone = function() - return SoulWarQuest.claustrophobicInfernoRaids[3].zone - end, - }, - spawnTime = 10, -- seconds - suriviveTime = 2 * 60, -- 2 minutes - timeToKick = 5, -- seconds - }, - areaZones = { monsters = { ["zone.claustrophobic-inferno"] = "Brachiodemon", @@ -233,7 +132,7 @@ SoulWarQuest = { ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", }, - claustrophobicInferno = Zone("zone.claustrophobic-inferno"), + caustrophobicInferno = Zone("zone.claustrophobic-inferno"), mirroredNightmare = Zone("zone.mirrored-nightmare"), ebbAndFlow = Zone("zone.ebb-and-flow"), furiousCrater = Zone("zone.furious-crater"), @@ -781,52 +680,11 @@ SoulWarQuest = { }, } -function RegisterSoulWarBossesLevers() - -- Register levers - local goshnarsMaliceLever = BossLever(SoulWarQuest.levers.goshnarsMalice) - goshnarsMaliceLever:position(SoulWarQuest.levers.goshnarsMalicePosition) - goshnarsMaliceLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsMaliceLever:getZone():getName()) - - local goshnarsSpiteLever = BossLever(SoulWarQuest.levers.goshnarsSpite) - goshnarsSpiteLever:position(SoulWarQuest.levers.goshnarsSpitePosition) - goshnarsSpiteLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsSpiteLever:getZone():getName()) - - local goshnarsGreedLever = BossLever(SoulWarQuest.levers.goshnarsGreed) - goshnarsGreedLever:position(SoulWarQuest.levers.goshnarsGreedPosition) - goshnarsGreedLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsGreedLever:getZone():getName()) - - local goshnarsHatredLever = BossLever(SoulWarQuest.levers.goshnarsHatred) - goshnarsHatredLever:position(SoulWarQuest.levers.goshnarsHatredPosition) - goshnarsHatredLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsHatredLever:getZone():getName()) - - local goshnarsCrueltyLever = BossLever(SoulWarQuest.levers.goshnarsCruelty) - goshnarsCrueltyLever:position(SoulWarQuest.levers.goshnarsCrueltyPosition) - goshnarsCrueltyLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsCrueltyLever:getZone():getName()) - - local goshnarsMegalomaniaLever = BossLever(SoulWarQuest.levers.goshnarsMegalomania) - goshnarsMegalomaniaLever:position(SoulWarQuest.levers.goshnarsMegalomaniaPosition) - goshnarsMegalomaniaLever:register() - logger.debug("Registering soul war boss lever zone: {}", goshnarsMegalomaniaLever:getZone():getName()) -end - -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) --- Initialize claustrophobic inferno raid zones and add remove destination - -for _, raid in ipairs(SoulWarQuest.claustrophobicInfernoRaids) do - local zone = raid.getZone() - zone:addArea(raid.zoneArea[1], raid.zoneArea[2]) - zone:setRemoveDestination(raid.exitPosition) -end - -- Initialize bosses access for taint check -SoulWarQuest.areaZones.claustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) +SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) @@ -836,17 +694,6 @@ SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) --- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) -SoulWarQuest.areaZones.claustrophobicInferno:subtractArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) - -SoulWarQuest.areaZones.ebbAndFlow:subtractArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) - -SoulWarQuest.areaZones.furiousCrater:subtractArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) - -SoulWarQuest.areaZones.rottenWasteland:subtractArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) - -SoulWarQuest.areaZones.mirroredNightmare:subtractArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) - SoulCagePosition = Position(33709, 31596, 14) TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days GreedbeastKills = 0 @@ -1067,45 +914,33 @@ end function Monster:generateBagYouDesireLoot(player) local playerTaintLevel = player:getTaintLevel() - if not playerTaintLevel or playerTaintLevel == 0 then + if not playerTaintLevel then return {} end local monsterName = self:getName() - local isMonsterValid = table.contains(SoulWarQuest.bagYouDesireMonsters, monsterName) + local isMonsterValid = false + for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do + if monsterName == monster then + isMonsterValid = true + break + end + end + if not isMonsterValid then return {} end + -- Calculates the chances based on the number of taints + local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) + logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + -- Generate loot local loot = {} - local totalChance = SoulWarQuest.baseBagYouDesireChance - local soulWarQuest = player:soulWarQuestKV() - local megalomaniaKills = soulWarQuest:scoped("megalomania-kills"):get("count") or 0 - - if monsterName == "Goshnar's Megalomania" then - -- Special handling for Goshnar's Megalomania - totalChance = totalChance + megalomaniaKills * SoulWarQuest.bagYouDesireChancePerTaint - else - -- General handling for other monsters (bosses and non-bosses) - totalChance = totalChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - end - - logger.trace("Player {} killed {} with {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) - if math.random(1, 100) <= totalChance then local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) if itemType then loot[itemType:getId()] = { count = 1 } logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) - if monsterName == "Goshnar's Megalomania" then - -- Reset kill count on successful drop - soulWarQuest:scoped("megalomania-kills"):set("count", 0) - end - end - else - if monsterName == "Goshnar's Megalomania" then - -- Increment kill count for unsuccessful attempts - soulWarQuest:scoped("megalomania-kills"):set("count", megalomaniaKills + 1) end end @@ -1207,7 +1042,7 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1, true) and player:getSoulWarZoneMonster() ~= nil then + if player:getTaintNameByNumber(1, true) then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance diff --git a/data-otservbr-global/scripts/lib/quests/soul-war.lua b/data-otservbr-global/scripts/lib/quests/soul-war.lua deleted file mode 100644 index 7ebe42b0441..00000000000 --- a/data-otservbr-global/scripts/lib/quests/soul-war.lua +++ /dev/null @@ -1,1371 +0,0 @@ -SoulWarQuest = { - -- Item ids - -- Goshnar's Hatred - bagYouDesireItemId = 34109, - goshnarsHatredSorrowId = 33793, - condensedRemorseId = 33792, - -- Goshnar's Spite - weepingSoulCorpseId = 33876, - searingFireId = 33877, - -- Goshnar's Cruelty - pulsatingEnergyId = 34005, - greedyMawId = 33890, - someMortalEssenceId = 33891, - theBloodOfCloakTerrorIds = { 33854, 34006, 34007 }, - -- Goshnar's Megalomania - deadAspectOfPowerCorpseId = 33949, - cleansedSanityItemId = 33950, - necromanticRemainsItemId = 33984, - - poolDamagePercentages = { - [33854] = 0.20, -- 20% of maximum health for the largest pool - [34006] = 0.15, -- 15% for a medium-sized pool - [34007] = 0.10, -- 10% for the smallest pool - }, - - timeToIncreaseCrueltyDefense = 15, -- In seconds, it will increase every 15 seconds if don't use mortal essence in greedy maw - useGreedMawCooldown = 30, -- In seconds - goshnarsCrueltyDefenseChange = 2, -- Defense change, the amount that will decrease or increase defense, the defense cannot decrease more than the monster's original defense amount - goshnarsCrueltyWaveInterval = 7, -- In seconds - - timeToReturnImmuneMegalomania = 70, -- In seconds - - baseBagYouDesireChance = 1, -- 1% base chance - bagYouDesireChancePerTaint = 1, -- Increases 1% per taint - bagYouDesireMonsters = { - "Bony Sea Devil", - "Brachiodemon", - "Branchy Crawler", - "Capricious Phantom", - "Cloak Of Terror", - "Courage Leech", - "Distorted Phantom", - "Druid's Apparition", - "Infernal Demon", - "Infernal Phantom", - "Knight's Apparition", - "Many Faces", - "Mould Phantom", - "Paladin's Apparition", - "Rotten Golem", - "Sorcerer's Apparition", - "Turbulent Elemental", - "Vibrant Phantom.", - }, - bagYouDesireBosses = { - "Goshnar's Cruelty", - "Goshnar's Spite", - "Goshnar's Malice", - "Goshnar's Hatred", - "Goshnar's Greed", - }, - - -- Goshnar's Cruelty pulsating energy monsters - pulsatingEnergyMonsters = { - "Vibrant Phantom", - "Cloak of Terror", - "Courage Leech", - }, - - miniBosses = { - ["Goshnar's Malice"] = true, - ["Goshnar's Hatred"] = true, - ["Goshnar's Spite"] = true, - ["Goshnar's Cruelty"] = true, - ["Goshnar's Greed"] = true, - }, - - finalRewards = { - { id = 34082, name = "soulcutter" }, - { id = 34083, name = "soulshredder" }, - { id = 34084, name = "soulbiter" }, - { id = 34085, name = "souleater" }, - { id = 34086, name = "soulcrusher" }, - { id = 34087, name = "soulmaimer" }, - { id = 34088, name = "soulbleeder" }, - { id = 34089, name = "soulpiercer" }, - { id = 34090, name = "soultainter" }, - { id = 34091, name = "soulhexer" }, - { id = 34092, name = "soulshanks" }, - { id = 34093, name = "soulstrider" }, - { id = 34094, name = "soulshell" }, - { id = 34095, name = "soulmantel" }, - { id = 34096, name = "soulshroud" }, - { id = 34097, name = "pair of soulwalkers" }, - { id = 34098, name = "pair of soulstalkers" }, - { id = 34099, name = "soulbastion" }, - }, - - kvSoulWar = KV.scoped("quest"):scoped("soul-war"), - -- Global KV for storage burning change form time - kvBurning = KV.scoped("quest"):scoped("soul-war"):scoped("burning-change-form"), - - rottenWastelandShrines = { - [33019] = { x = 33926, y = 31091, z = 13 }, - [33021] = { x = 33963, y = 31078, z = 13 }, - [33022] = { x = 33970, y = 30988, z = 13 }, - [33024] = { x = 33970, y = 31012, z = 13 }, - }, - - -- Lever room and teleports positions - goshnarsGreedAccessPosition = { from = { x = 33937, y = 31217, z = 11 }, to = { x = 33782, y = 31665, z = 14 } }, - goshnarsHatredAccessPosition = { from = { x = 33914, y = 31032, z = 12 }, to = { x = 33774, y = 31604, z = 14 } }, - -- Teleports from 1st/2nd/3rd floors - goshnarsCrueltyTeleportRoomPositions = { - { from = Position(33889, 31873, 3), to = Position(33830, 31881, 4), access = "first-floor-access", count = 40 }, - { from = Position(33829, 31880, 4), to = Position(33856, 31889, 5), access = "second-floor-access", count = 55 }, - { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, - }, - - areaZones = { - monsters = { - ["zone.claustrophobic-inferno"] = "Brachiodemon", - ["zone.mirrored-nightmare"] = "Many Faces", - ["zone.ebb-and-flow"] = "Bony Sea Devil", - ["zone.furious-crater"] = "Cloak of Terror", - ["zone.rotten-wasteland"] = "Branchy Crawler", - ["boss.goshnar's-malice"] = "Dreadful Harvester", - ["boss.goshnar's-spite"] = "Dreadful Harvester", - ["boss.goshnar's-greed"] = "Dreadful Harvester", - ["boss.goshnar's-hatred"] = "Dreadful Harvester", - ["boss.goshnar's-cruelty"] = "Dreadful Harvester", - ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", - }, - - caustrophobicInferno = Zone("zone.claustrophobic-inferno"), - mirroredNightmare = Zone("zone.mirrored-nightmare"), - ebbAndFlow = Zone("zone.ebb-and-flow"), - furiousCrater = Zone("zone.furious-crater"), - rottenWasteland = Zone("zone.rotten-wasteland"), - }, - - -- Levers configuration - levers = { - goshnarsMalicePosition = { x = 33678, y = 31599, z = 14 }, - goshnarsSpitePosition = { x = 33773, y = 31634, z = 14 }, - goshnarsGreedPosition = { x = 33775, y = 31665, z = 14 }, - goshnarsHatredPosition = { x = 33772, y = 31601, z = 14 }, - goshnarsCrueltyPosition = { x = 33853, y = 31854, z = 6 }, - goshnarsMegalomaniaPosition = { x = 33675, y = 31634, z = 14 }, - - -- Levers system - goshnarsSpite = { - boss = { - name = "Goshnar's Spite", - position = Position(33743, 31632, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33774, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33775, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33776, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33778, 31634, 14), teleport = Position(33742, 31639, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33734, 31624, 14), - to = Position(33751, 31640, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsMalice = { - boss = { - name = "Goshnar's Malice", - position = Position(33709, 31599, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33679, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33680, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33681, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33682, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33683, 31599, 14), teleport = Position(33710, 31605, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33699, 31590, 14), - to = Position(33718, 31607, 14), - }, - onUseExtra = function(player) - addEvent(SpawnSoulCage, 23000) - end, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsGreed = { - boss = { - name = "Goshnar's Greed", - position = Position(33746, 31666, 14), - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33776, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33778, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33779, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33780, 31665, 14), teleport = Position(33747, 31671, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33737, 31658, 14), - to = Position(33755, 31673, 14), - }, - timeToFightAgain = 0, -- TODO: Remove later - onUseExtra = function() - CreateGoshnarsGreedMonster("Greedbeast", Position(33744, 31666, 14)) - CreateGoshnarsGreedMonster("Soulsnatcher", Position(33747, 31668, 14)) - CreateGoshnarsGreedMonster("Weak Soul", Position(33750, 31666, 14)) - end, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - }, - goshnarsHatred = { - boss = { - name = "Goshnar's Hatred", - position = Position(33744, 31599, 14), - }, - monsters = { - { name = "Ashes of Burning Hatred", pos = { x = 33743, y = 31599, z = 14 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33773, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33774, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33775, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33776, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33777, 31601, 14), teleport = Position(33743, 31604, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33735, 31592, 14), - to = Position(33751, 31606, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - onUseExtra = function(player) - SoulWarQuest.kvBurning:set("time", 180) - logger.trace("Goshnar's Hatred burning change form time set to: {}", 180) - player:resetGoshnarSymbolTormentCounter() - end, - }, - goshnarsCruelty = { - boss = { - name = "Goshnar's Cruelty", - position = Position(33856, 31866, 7), - }, - monsters = { - { name = "A Greedy Eye", pos = { x = 33856, y = 31858, z = 7 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33854, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33855, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33856, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33857, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - { pos = Position(33858, 31854, 6), teleport = Position(33856, 31872, 7), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33847, 31858, 7), - to = Position(33864, 31874, 7), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 20 * 60 * 60, -- 20 hours - onUseExtra = function(player) - SoulWarQuest.kvSoulWar:remove("greedy-maw-action") - player:soulWarQuestKV():scoped("furious-crater"):remove("greedy-maw-action") - end, - }, - goshnarsMegalomania = { - boss = { - name = "Goshnar's Megalomania Purple", - position = Position(33710, 31634, 14), - }, - monsters = { - { name = "Aspect of Power", pos = { x = 33710, y = 31635, z = 14 } }, - }, - requiredLevel = 250, - playerPositions = { - { pos = Position(33676, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33677, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33678, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33679, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - { pos = Position(33680, 31634, 14), teleport = Position(33710, 31639, 14), effect = CONST_ME_TELEPORT }, - }, - specPos = { - from = Position(33701, 31626, 14), - to = Position(33719, 31642, 14), - }, - exit = Position(33621, 31427, 10), - timeToFightAgain = 72 * 60 * 60, -- 72 hours - onUseExtra = function(player) - player:resetGoshnarSymbolTormentCounter() - SoulWarQuest.kvSoulWar:remove("cleansed-sanity-action") - player:soulWarQuestKV():scoped("furious-crater"):remove("cleansed-sanity-action") - end, - }, - }, - - -- Goshnar's Greed - apparitionNames = { - "Druid's Apparition", - "Knight's Apparition", - "Paladin's Apparition", - "Sorcerer's Apparition", - }, - - burningTransformations = { - { 180, "Ashes of Burning Hatred" }, - { 135, "Spark of Burning Hatred" }, - { 90, "Flame of Burning Hatred" }, - { 45, "Blaze of Burning Hatred" }, - }, - - requiredCountPerApparition = 25, - - -- Ebb and flow - ebbAndFlow = { - zone = Zone("ebb-and-flow-zone"), - -- Positions to teleport into rooms when innundate map is loaded - centerRoomPositions = { - { conor = { x = 33929, y = 31020, z = 9 }, teleportPosition = { x = 33939, y = 31021, z = 8 } }, - { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33918, y = 31047, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, - { conor = { x = 33898, y = 31054, z = 9 }, teleportPosition = { x = 33903, y = 31049, z = 8 } }, - { conor = { x = 33929, y = 31047, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33940, y = 31054, z = 9 }, teleportPosition = { x = 33938, y = 31047, z = 8 } }, - { conor = { x = 33940, y = 31064, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, - { conor = { x = 33937, y = 31086, z = 9 }, teleportPosition = { x = 33937, y = 31074, z = 8 } }, - { conor = { x = 33937, y = 31098, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33933, y = 31109, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33921, y = 31113, z = 9 }, teleportPosition = { x = 33929, y = 31109, z = 8 } }, - { conor = { x = 33912, y = 31113, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, - { conor = { x = 33901, y = 31108, z = 9 }, teleportPosition = { x = 33904, y = 31117, z = 8 } }, - { conor = { x = 33901, y = 31098, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, - { conor = { x = 33899, y = 31064, z = 9 }, teleportPosition = { x = 33904, y = 31082, z = 8 } }, - }, - mapsPath = { - empty = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-empty.otbm", - inundate = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow-inundate.otbm", - ebbFlow = "data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm", - }, - - -- In Minutes - intervalChangeMap = 2, - waitPosition = Position(33893, 31020, 8), - - getZone = function() - return SoulWarQuest.ebbAndFlow.zone - end, - - reloadZone = function() - SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) - end, - - kv = KV.scoped("quest"):scoped("soul-war"):scoped("ebb-and-flow-maps"), - isActive = function() - return SoulWarQuest.ebbAndFlow.kv:get("is-active") - end, - isLoadedEmptyMap = function() - return SoulWarQuest.ebbAndFlow.kv:get("is-loaded-empty-map") - end, - setActive = function(value) - SoulWarQuest.ebbAndFlow.kv:set("is-active", value) - end, - setLoadedEmptyMap = function(value) - SoulWarQuest.ebbAndFlow.kv:set("is-loaded-empty-map", value) - end, - - updateZonePlayers = function() - if SoulWarQuest.ebbAndFlow.zone and SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then - SoulWarQuest.ebbAndFlow.reloadZone() - local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() - for _, player in ipairs(players) do - logger.trace("Updating player: {}", player:getName()) - player:sendCreatureAppear() - end - end - end, - - -- Add here more positions of the pools that must transform before innundate map is loaded - poolPositions = { - { x = 33906, y = 31026, z = 9 }, - { x = 33901, y = 31026, z = 9 }, - { x = 33932, y = 31011, z = 9 }, - { x = 33941, y = 31033, z = 9 }, - { x = 33946, y = 31037, z = 9 }, - { x = 33939, y = 31056, z = 9 }, - }, - - boatId = 7272, - doorId = 33767, - smallPoolId = 33772, - MediumPoolId = 33773, - }, - - changeBlueEvent = nil, - changePurpleEvent = nil, - - changeMegalomaniaBlue = function() - local boss = Creature("Goshnar's Megalomania") - if boss then - boss:teleportTo(SoulWarQuest.levers.goshnarsMegalomania.boss.position) - boss:say("ENOUGH! I WILL MAKE YOU SUFFER FOR YOUR INSOLENCE! NOW - I - WILL - ANIHILATE - YOU!") - boss:setType("Goshnar's Megalomania Blue") - local function changeBack() - boss:setType("Goshnar's Megalomania Purple") - end - - changePurpleEvent = addEvent(changeBack, 7000) - end - end, - - -- Chance to heal the life of the monster by stepping on the corpse of "weeping soul" - goshnarsSpiteHealChance = 10, - -- Percentage that will heal by stepping and the chance is successful - goshnarsSpiteHealPercentage = 10, - - goshnarSpiteEntrancePosition = { fromPos = Position(33950, 31109, 8), toPos = Position(33780, 31634, 14) }, - - waterElementalOutfit = { - lookType = 286, - lookHead = 0, - lookBody = 0, - lookLegs = 0, - lookFeet = 0, - lookAddons = 0, - lookMount = 0, - }, - - goshnarsSpiteFirePositions = { - -- North - { x = 33743, y = 31628, z = 14 }, - -- East - { x = 33736, y = 31632, z = 14 }, - -- West - { x = 33750, y = 31632, z = 14 }, - -- South - { x = 33742, y = 31637, z = 14 }, - }, - - -- Increased defense if the searing fire disappears - goshnarsSpiteIncreaseDefense = 10, - -- Count of monsters to kill for enter in the boss room - hardozousPanthomDeathCount = 20, - -- Time to fire created again - timeToCreateSearingFire = 14, -- In seconds - -- Time to remove the searing fire if player don't step on it - timeToRemoveSearingFire = 5, -- In seconds - cooldownToStepOnSearingFire = 56, -- In seconds (14 seconds x 4) - - -- Positions to teleport into rooms when innundate map is loaded - ebbAndFlowBoatTeleportPositions = { - -- First boat - -- Enter on boat - { register = { x = 33919, y = 31019, z = 8 }, teleportTo = { x = 33923, y = 31019, z = 8 } }, - { register = { x = 33919, y = 31020, z = 8 }, teleportTo = { x = 33923, y = 31020, z = 8 } }, - { register = { x = 33919, y = 31021, z = 8 }, teleportTo = { x = 33923, y = 31021, z = 8 } }, - { register = { x = 33919, y = 31022, z = 8 }, teleportTo = { x = 33923, y = 31022, z = 8 } }, - -- Back to innitial room - { register = { x = 33922, y = 31019, z = 8 }, teleportTo = { x = 33918, y = 31019, z = 8 } }, - { register = { x = 33922, y = 31020, z = 8 }, teleportTo = { x = 33918, y = 31020, z = 8 } }, - { register = { x = 33922, y = 31021, z = 8 }, teleportTo = { x = 33918, y = 31021, z = 8 } }, - { register = { x = 33922, y = 31022, z = 8 }, teleportTo = { x = 33918, y = 31022, z = 8 } }, - -- From boat to room - { register = { x = 33926, y = 31019, z = 8 }, teleportTo = { x = 33930, y = 31019, z = 8 } }, - { register = { x = 33926, y = 31020, z = 8 }, teleportTo = { x = 33930, y = 31020, z = 8 } }, - { register = { x = 33926, y = 31021, z = 8 }, teleportTo = { x = 33930, y = 31021, z = 8 } }, - { register = { x = 33926, y = 31022, z = 8 }, teleportTo = { x = 33930, y = 31022, z = 8 } }, - -- From room to boat - { register = { x = 33929, y = 31019, z = 8 }, teleportTo = { x = 33925, y = 31019, z = 8 } }, - { register = { x = 33929, y = 31020, z = 8 }, teleportTo = { x = 33925, y = 31020, z = 8 } }, - { register = { x = 33929, y = 31021, z = 8 }, teleportTo = { x = 33925, y = 31021, z = 8 } }, - { register = { x = 33929, y = 31022, z = 8 }, teleportTo = { x = 33925, y = 31022, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33929, y = 31045, z = 8 }, teleportTo = { x = 33925, y = 31045, z = 8 } }, - { register = { x = 33929, y = 31046, z = 8 }, teleportTo = { x = 33925, y = 31046, z = 8 } }, - { register = { x = 33929, y = 31047, z = 8 }, teleportTo = { x = 33925, y = 31047, z = 8 } }, - { register = { x = 33929, y = 31048, z = 8 }, teleportTo = { x = 33925, y = 31048, z = 8 } }, - -- Back to room - { register = { x = 33926, y = 31045, z = 8 }, teleportTo = { x = 33930, y = 31045, z = 8 } }, - { register = { x = 33926, y = 31046, z = 8 }, teleportTo = { x = 33930, y = 31046, z = 8 } }, - { register = { x = 33926, y = 31047, z = 8 }, teleportTo = { x = 33930, y = 31047, z = 8 } }, - { register = { x = 33926, y = 31048, z = 8 }, teleportTo = { x = 33930, y = 31048, z = 8 } }, - -- From boat to room - { register = { x = 33922, y = 31045, z = 8 }, teleportTo = { x = 33918, y = 31045, z = 8 } }, - { register = { x = 33922, y = 31046, z = 8 }, teleportTo = { x = 33918, y = 31046, z = 8 } }, - { register = { x = 33922, y = 31047, z = 8 }, teleportTo = { x = 33918, y = 31047, z = 8 } }, - { register = { x = 33922, y = 31048, z = 8 }, teleportTo = { x = 33918, y = 31048, z = 8 } }, - -- From room to boat - { register = { x = 33919, y = 31045, z = 8 }, teleportTo = { x = 33923, y = 31045, z = 8 } }, - { register = { x = 33919, y = 31046, z = 8 }, teleportTo = { x = 33923, y = 31046, z = 8 } }, - { register = { x = 33919, y = 31047, z = 8 }, teleportTo = { x = 33923, y = 31047, z = 8 } }, - { register = { x = 33919, y = 31048, z = 8 }, teleportTo = { x = 33923, y = 31048, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33896, y = 31055, z = 8 }, teleportTo = { x = 33896, y = 31059, z = 8 } }, - { register = { x = 33897, y = 31055, z = 8 }, teleportTo = { x = 33897, y = 31059, z = 8 } }, - { register = { x = 33898, y = 31055, z = 8 }, teleportTo = { x = 33898, y = 31059, z = 8 } }, - { register = { x = 33899, y = 31055, z = 8 }, teleportTo = { x = 33899, y = 31059, z = 8 } }, - { register = { x = 33900, y = 31055, z = 8 }, teleportTo = { x = 33900, y = 31059, z = 8 } }, - { register = { x = 33901, y = 31055, z = 8 }, teleportTo = { x = 33901, y = 31059, z = 8 } }, - -- Back to room - { register = { x = 33896, y = 31058, z = 8 }, teleportTo = { x = 33896, y = 31054, z = 8 } }, - { register = { x = 33897, y = 31058, z = 8 }, teleportTo = { x = 33897, y = 31054, z = 8 } }, - { register = { x = 33898, y = 31058, z = 8 }, teleportTo = { x = 33898, y = 31054, z = 8 } }, - { register = { x = 33899, y = 31058, z = 8 }, teleportTo = { x = 33899, y = 31054, z = 8 } }, - { register = { x = 33900, y = 31058, z = 8 }, teleportTo = { x = 33900, y = 31054, z = 8 } }, - { register = { x = 33901, y = 31058, z = 8 }, teleportTo = { x = 33901, y = 31054, z = 8 } }, - -- From boat to room - { register = { x = 33896, y = 31061, z = 8 }, teleportTo = { x = 33896, y = 31065, z = 8 } }, - { register = { x = 33897, y = 31061, z = 8 }, teleportTo = { x = 33897, y = 31065, z = 8 } }, - { register = { x = 33898, y = 31061, z = 8 }, teleportTo = { x = 33898, y = 31065, z = 8 } }, - { register = { x = 33899, y = 31061, z = 8 }, teleportTo = { x = 33899, y = 31065, z = 8 } }, - { register = { x = 33900, y = 31061, z = 8 }, teleportTo = { x = 33900, y = 31065, z = 8 } }, - { register = { x = 33901, y = 31061, z = 8 }, teleportTo = { x = 33901, y = 31065, z = 8 } }, - -- From room to boat - { register = { x = 33896, y = 31064, z = 8 }, teleportTo = { x = 33896, y = 31060, z = 8 } }, - { register = { x = 33897, y = 31064, z = 8 }, teleportTo = { x = 33897, y = 31060, z = 8 } }, - { register = { x = 33898, y = 31064, z = 8 }, teleportTo = { x = 33898, y = 31060, z = 8 } }, - { register = { x = 33899, y = 31064, z = 8 }, teleportTo = { x = 33899, y = 31060, z = 8 } }, - { register = { x = 33900, y = 31064, z = 8 }, teleportTo = { x = 33900, y = 31060, z = 8 } }, - { register = { x = 33901, y = 31064, z = 8 }, teleportTo = { x = 33901, y = 31060, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33899, y = 31099, z = 8 }, teleportTo = { x = 33899, y = 31103, z = 8 } }, - { register = { x = 33900, y = 31099, z = 8 }, teleportTo = { x = 33900, y = 31103, z = 8 } }, - { register = { x = 33901, y = 31099, z = 8 }, teleportTo = { x = 33901, y = 31103, z = 8 } }, - { register = { x = 33902, y = 31099, z = 8 }, teleportTo = { x = 33902, y = 31103, z = 8 } }, - { register = { x = 33903, y = 31099, z = 8 }, teleportTo = { x = 33903, y = 31103, z = 8 } }, - { register = { x = 33904, y = 31099, z = 8 }, teleportTo = { x = 33904, y = 31103, z = 8 } }, - { register = { x = 33905, y = 31099, z = 8 }, teleportTo = { x = 33905, y = 31103, z = 8 } }, - -- Back from boat to room - { register = { x = 33899, y = 31102, z = 8 }, teleportTo = { x = 33899, y = 31098, z = 8 } }, - { register = { x = 33900, y = 31102, z = 8 }, teleportTo = { x = 33900, y = 31098, z = 8 } }, - { register = { x = 33901, y = 31102, z = 8 }, teleportTo = { x = 33901, y = 31098, z = 8 } }, - { register = { x = 33902, y = 31102, z = 8 }, teleportTo = { x = 33902, y = 31098, z = 8 } }, - { register = { x = 33903, y = 31102, z = 8 }, teleportTo = { x = 33903, y = 31098, z = 8 } }, - { register = { x = 33904, y = 31102, z = 8 }, teleportTo = { x = 33904, y = 31098, z = 8 } }, - { register = { x = 33905, y = 31102, z = 8 }, teleportTo = { x = 33905, y = 31098, z = 8 } }, - -- From boat to room - { register = { x = 33899, y = 31105, z = 8 }, teleportTo = { x = 33899, y = 31109, z = 8 } }, - { register = { x = 33900, y = 31105, z = 8 }, teleportTo = { x = 33900, y = 31109, z = 8 } }, - { register = { x = 33901, y = 31105, z = 8 }, teleportTo = { x = 33901, y = 31109, z = 8 } }, - { register = { x = 33902, y = 31105, z = 8 }, teleportTo = { x = 33902, y = 31109, z = 8 } }, - { register = { x = 33903, y = 31105, z = 8 }, teleportTo = { x = 33903, y = 31109, z = 8 } }, - { register = { x = 33904, y = 31105, z = 8 }, teleportTo = { x = 33904, y = 31109, z = 8 } }, - { register = { x = 33905, y = 31105, z = 8 }, teleportTo = { x = 33905, y = 31109, z = 8 } }, - -- From room to boat - { register = { x = 33899, y = 31108, z = 8 }, teleportTo = { x = 33899, y = 31104, z = 8 } }, - { register = { x = 33900, y = 31108, z = 8 }, teleportTo = { x = 33900, y = 31104, z = 8 } }, - { register = { x = 33901, y = 31108, z = 8 }, teleportTo = { x = 33901, y = 31104, z = 8 } }, - { register = { x = 33902, y = 31108, z = 8 }, teleportTo = { x = 33902, y = 31104, z = 8 } }, - { register = { x = 33903, y = 31108, z = 8 }, teleportTo = { x = 33903, y = 31104, z = 8 } }, - { register = { x = 33904, y = 31108, z = 8 }, teleportTo = { x = 33904, y = 31104, z = 8 } }, - { register = { x = 33905, y = 31108, z = 8 }, teleportTo = { x = 33905, y = 31104, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33913, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, - { register = { x = 33913, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, - { register = { x = 33913, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, - { register = { x = 33913, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, - { register = { x = 33913, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, - -- Back to room - { register = { x = 33916, y = 31112, z = 8 }, teleportTo = { x = 33912, y = 31112, z = 8 } }, - { register = { x = 33916, y = 31113, z = 8 }, teleportTo = { x = 33912, y = 31113, z = 8 } }, - { register = { x = 33916, y = 31114, z = 8 }, teleportTo = { x = 33912, y = 31114, z = 8 } }, - { register = { x = 33916, y = 31115, z = 8 }, teleportTo = { x = 33912, y = 31115, z = 8 } }, - { register = { x = 33916, y = 31116, z = 8 }, teleportTo = { x = 33912, y = 31116, z = 8 } }, - -- From boat to room - { register = { x = 33918, y = 31112, z = 8 }, teleportTo = { x = 33922, y = 31112, z = 8 } }, - { register = { x = 33918, y = 31113, z = 8 }, teleportTo = { x = 33922, y = 31113, z = 8 } }, - { register = { x = 33918, y = 31114, z = 8 }, teleportTo = { x = 33922, y = 31114, z = 8 } }, - { register = { x = 33918, y = 31115, z = 8 }, teleportTo = { x = 33922, y = 31115, z = 8 } }, - { register = { x = 33918, y = 31116, z = 8 }, teleportTo = { x = 33922, y = 31116, z = 8 } }, - -- From room to boat - { register = { x = 33921, y = 31112, z = 8 }, teleportTo = { x = 33917, y = 31112, z = 8 } }, - { register = { x = 33921, y = 31113, z = 8 }, teleportTo = { x = 33917, y = 31113, z = 8 } }, - { register = { x = 33921, y = 31114, z = 8 }, teleportTo = { x = 33917, y = 31114, z = 8 } }, - { register = { x = 33921, y = 31115, z = 8 }, teleportTo = { x = 33917, y = 31115, z = 8 } }, - { register = { x = 33921, y = 31116, z = 8 }, teleportTo = { x = 33917, y = 31116, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33936, y = 31087, z = 8 }, teleportTo = { x = 33936, y = 31091, z = 8 } }, - { register = { x = 33937, y = 31087, z = 8 }, teleportTo = { x = 33937, y = 31091, z = 8 } }, - { register = { x = 33938, y = 31087, z = 8 }, teleportTo = { x = 33938, y = 31091, z = 8 } }, - { register = { x = 33939, y = 31087, z = 8 }, teleportTo = { x = 33939, y = 31091, z = 8 } }, - { register = { x = 33940, y = 31087, z = 8 }, teleportTo = { x = 33940, y = 31091, z = 8 } }, - { register = { x = 33941, y = 31087, z = 8 }, teleportTo = { x = 33941, y = 31091, z = 8 } }, - -- Back to room - { register = { x = 33936, y = 31090, z = 8 }, teleportTo = { x = 33936, y = 31086, z = 8 } }, - { register = { x = 33937, y = 31090, z = 8 }, teleportTo = { x = 33937, y = 31086, z = 8 } }, - { register = { x = 33938, y = 31090, z = 8 }, teleportTo = { x = 33938, y = 31086, z = 8 } }, - { register = { x = 33939, y = 31090, z = 8 }, teleportTo = { x = 33939, y = 31086, z = 8 } }, - { register = { x = 33940, y = 31090, z = 8 }, teleportTo = { x = 33940, y = 31086, z = 8 } }, - { register = { x = 33941, y = 31090, z = 8 }, teleportTo = { x = 33941, y = 31086, z = 8 } }, - -- From boat to room - { register = { x = 33936, y = 31095, z = 8 }, teleportTo = { x = 33934, y = 31099, z = 8 } }, - { register = { x = 33937, y = 31095, z = 8 }, teleportTo = { x = 33935, y = 31099, z = 8 } }, - { register = { x = 33938, y = 31095, z = 8 }, teleportTo = { x = 33936, y = 31099, z = 8 } }, - { register = { x = 33939, y = 31095, z = 8 }, teleportTo = { x = 33937, y = 31099, z = 8 } }, - { register = { x = 33940, y = 31095, z = 8 }, teleportTo = { x = 33938, y = 31099, z = 8 } }, - { register = { x = 33941, y = 31095, z = 8 }, teleportTo = { x = 33939, y = 31099, z = 8 } }, - -- From room to boat - { register = { x = 33934, y = 31098, z = 8 }, teleportTo = { x = 33936, y = 31094, z = 8 } }, - { register = { x = 33935, y = 31098, z = 8 }, teleportTo = { x = 33937, y = 31094, z = 8 } }, - { register = { x = 33936, y = 31098, z = 8 }, teleportTo = { x = 33938, y = 31094, z = 8 } }, - { register = { x = 33937, y = 31098, z = 8 }, teleportTo = { x = 33939, y = 31094, z = 8 } }, - { register = { x = 33938, y = 31098, z = 8 }, teleportTo = { x = 33940, y = 31094, z = 8 } }, - { register = { x = 33939, y = 31098, z = 8 }, teleportTo = { x = 33941, y = 31094, z = 8 } }, - { register = { x = 33940, y = 31098, z = 8 }, teleportTo = { x = 33942, y = 31094, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33939, y = 31064, z = 8 }, teleportTo = { x = 33939, y = 31060, z = 8 } }, - { register = { x = 33940, y = 31064, z = 8 }, teleportTo = { x = 33940, y = 31060, z = 8 } }, - { register = { x = 33941, y = 31064, z = 8 }, teleportTo = { x = 33941, y = 31060, z = 8 } }, - { register = { x = 33942, y = 31064, z = 8 }, teleportTo = { x = 33942, y = 31060, z = 8 } }, - { register = { x = 33943, y = 31064, z = 8 }, teleportTo = { x = 33943, y = 31060, z = 8 } }, - { register = { x = 33944, y = 31064, z = 8 }, teleportTo = { x = 33944, y = 31060, z = 8 } }, - -- Back to room - { register = { x = 33939, y = 31061, z = 8 }, teleportTo = { x = 33939, y = 31065, z = 8 } }, - { register = { x = 33940, y = 31061, z = 8 }, teleportTo = { x = 33940, y = 31065, z = 8 } }, - { register = { x = 33941, y = 31061, z = 8 }, teleportTo = { x = 33941, y = 31065, z = 8 } }, - { register = { x = 33942, y = 31061, z = 8 }, teleportTo = { x = 33942, y = 31065, z = 8 } }, - { register = { x = 33943, y = 31061, z = 8 }, teleportTo = { x = 33943, y = 31065, z = 8 } }, - { register = { x = 33944, y = 31061, z = 8 }, teleportTo = { x = 33944, y = 31065, z = 8 } }, - -- From boat to room - { register = { x = 33939, y = 31058, z = 8 }, teleportTo = { x = 33939, y = 31054, z = 8 } }, - { register = { x = 33940, y = 31058, z = 8 }, teleportTo = { x = 33940, y = 31054, z = 8 } }, - { register = { x = 33941, y = 31058, z = 8 }, teleportTo = { x = 33941, y = 31054, z = 8 } }, - { register = { x = 33942, y = 31058, z = 8 }, teleportTo = { x = 33942, y = 31054, z = 8 } }, - { register = { x = 33943, y = 31058, z = 8 }, teleportTo = { x = 33943, y = 31054, z = 8 } }, - { register = { x = 33944, y = 31058, z = 8 }, teleportTo = { x = 33944, y = 31054, z = 8 } }, - -- From room to boat - { register = { x = 33939, y = 31055, z = 8 }, teleportTo = { x = 33939, y = 31059, z = 8 } }, - { register = { x = 33940, y = 31055, z = 8 }, teleportTo = { x = 33940, y = 31059, z = 8 } }, - { register = { x = 33941, y = 31055, z = 8 }, teleportTo = { x = 33941, y = 31059, z = 8 } }, - { register = { x = 33942, y = 31055, z = 8 }, teleportTo = { x = 33942, y = 31059, z = 8 } }, - { register = { x = 33943, y = 31055, z = 8 }, teleportTo = { x = 33943, y = 31059, z = 8 } }, - { register = { x = 33944, y = 31055, z = 8 }, teleportTo = { x = 33944, y = 31059, z = 8 } }, - - -- Boat - -- Enter on boat - { register = { x = 33934, y = 31108, z = 8 }, teleportTo = { x = 33938, y = 31108, z = 8 } }, - { register = { x = 33934, y = 31109, z = 8 }, teleportTo = { x = 33938, y = 31109, z = 8 } }, - { register = { x = 33934, y = 31110, z = 8 }, teleportTo = { x = 33938, y = 31110, z = 8 } }, - { register = { x = 33934, y = 31111, z = 8 }, teleportTo = { x = 33938, y = 31111, z = 8 } }, - { register = { x = 33934, y = 31112, z = 8 }, teleportTo = { x = 33938, y = 31112, z = 8 } }, - -- Back to room - { register = { x = 33937, y = 31108, z = 8 }, teleportTo = { x = 33933, y = 31108, z = 8 } }, - { register = { x = 33937, y = 31109, z = 8 }, teleportTo = { x = 33933, y = 31109, z = 8 } }, - { register = { x = 33937, y = 31110, z = 8 }, teleportTo = { x = 33933, y = 31110, z = 8 } }, - { register = { x = 33937, y = 31111, z = 8 }, teleportTo = { x = 33933, y = 31111, z = 8 } }, - { register = { x = 33937, y = 31112, z = 8 }, teleportTo = { x = 33933, y = 31112, z = 8 } }, - -- From boat to room - { register = { x = 33942, y = 31108, z = 8 }, teleportTo = { x = 33946, y = 31108, z = 8 } }, - { register = { x = 33942, y = 31109, z = 8 }, teleportTo = { x = 33946, y = 31109, z = 8 } }, - { register = { x = 33942, y = 31110, z = 8 }, teleportTo = { x = 33946, y = 31110, z = 8 } }, - { register = { x = 33942, y = 31111, z = 8 }, teleportTo = { x = 33946, y = 31111, z = 8 } }, - { register = { x = 33942, y = 31112, z = 8 }, teleportTo = { x = 33946, y = 31112, z = 8 } }, - -- From room to boat - { register = { x = 33945, y = 31108, z = 8 }, teleportTo = { x = 33941, y = 31108, z = 8 } }, - { register = { x = 33945, y = 31109, z = 8 }, teleportTo = { x = 33941, y = 31109, z = 8 } }, - { register = { x = 33945, y = 31110, z = 8 }, teleportTo = { x = 33941, y = 31110, z = 8 } }, - { register = { x = 33945, y = 31111, z = 8 }, teleportTo = { x = 33941, y = 31111, z = 8 } }, - { register = { x = 33945, y = 31112, z = 8 }, teleportTo = { x = 33941, y = 31112, z = 8 } }, - }, -} - --- Initialize ebb and flow zone area -SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) - --- Initialize bosses access for taint check -SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) - -SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) - -SoulWarQuest.areaZones.furiousCrater:addArea({ x = 33814, y = 31819, z = 3 }, { x = 33907, y = 31920, z = 7 }) - -SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, { x = 33901, y = 31105, z = 12 }) - -SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) - -SoulCagePosition = Position(33709, 31596, 14) -TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days -GreedbeastKills = 0 - -SoulWarReflectDamageMap = { - [COMBAT_PHYSICALDAMAGE] = 10, - [COMBAT_FIREDAMAGE] = 10, - [COMBAT_EARTHDAMAGE] = 10, - [COMBAT_ENERGYDAMAGE] = 10, - [COMBAT_ICEDAMAGE] = 10, - [COMBAT_HOLYDAMAGE] = 10, - [COMBAT_DEATHDAMAGE] = 10, -} - -local soulWarTaints = { - "taints-teleport", -- Taint 1 - "taints-spawn", -- Taint 2 - "taints-damage", -- Taint 3 - "taints-heal", -- Taint 4 - "taints-loss", -- Taint 5 -} - -GreedMonsters = { - ["Greedbeast"] = Position(33744, 31666, 14), - ["Soulsnatcher"] = Position(33747, 31668, 14), - ["Weak Soul"] = Position(33750, 31666, 14), - ["Strong Soul"] = Position(33750, 31666, 14), - ["Powerful Soul"] = Position(33750, 31666, 14), -} - -function CreateGoshnarsGreedMonster(name, position) - local function sendEffect() - position:sendMagicEffect(CONST_ME_TELEPORT) - end - - local function spawnMonster() - Game.createMonster(name, position, true, false) - logger.trace("Spawning {} in position {}", name, position:toString()) - end - - for i = 7, 9 do - addEvent(sendEffect, i * 1000) - end - - addEvent(spawnMonster, 10000) -end - -function RemoveSoulCageAndBuffMalice() - local soulCage = Creature("Soul Cage") - if soulCage then - soulCage:remove() - addEvent(SpawnSoulCage, 23000) - local malice = Creature("Goshnar's Malice") - if malice then - logger.trace("Found malice, try adding reflect and defense") - for elementType, reflectPercent in pairs(SoulWarReflectDamageMap) do - malice:addReflectElement(elementType, reflectPercent) - end - malice:addDefense(10) - end - end -end - -function SpawnSoulCage() - local tile = Tile(SoulCagePosition) - local creatures = tile:getCreatures() or {} - local soulCage = Creature("Soul Cage") - if not soulCage then - Game.createMonster("Soul Cage", SoulCagePosition, true, true) - logger.trace("Spawning Soul Cage in position {}", SoulCagePosition:toString()) - addEvent(RemoveSoulCageAndBuffMalice, 40000) - end -end - -local function shuffle(list) - for i = #list, 2, -1 do - local j = math.random(i) - list[i], list[j] = list[j], list[i] - end -end - -local function createConnectedGroup(startPos, groupPositions, groupSize) - local group = { startPos } - local lastPos = startPos - local directions = { - { x = 1, y = 0 }, - { x = -1, y = 0 }, -- Right and left - { x = 0, y = 1 }, - { x = 0, y = -1 }, -- Up and down - { x = 1, y = 1 }, - { x = -1, y = -1 }, -- Diagonals - { x = -1, y = 1 }, - { x = 1, y = -1 }, - } - - for i = 2, groupSize do - shuffle(directions) - local nextPos = nil - for _, dir in ipairs(directions) do - local potentialNextPos = Position(lastPos.x + dir.x, lastPos.y + dir.y, lastPos.z) - if table.contains(groupPositions, potentialNextPos) then - nextPos = potentialNextPos - break - end - end - - if nextPos then - table.insert(group, nextPos) - table.remove(groupPositions, table.find(groupPositions, nextPos)) - lastPos = nextPos - else - break - end - end - - return group -end - -local function generatePositionsInRange(center, range) - local positions = {} - for x = center.x - range, center.x + range do - for y = center.y - range, center.y + range do - table.insert(positions, Position(x, y, center.z)) - end - end - return positions -end - -local toRevertPositions = {} - -local tileItemIds = { - 32906, - 33066, - 33067, - 33068, - 33069, - 33070, -} - -local function revertTilesAndApplyDamage(zonePositions) - for _, pos in ipairs(zonePositions) do - local tile = Tile(pos) - if tile and tile:getGround() then - if tile:getGround():getId() ~= 409 then - local creature = tile:getTopCreature() - if creature then - local player = creature:getPlayer() - if player then - player:addHealth(-8000, COMBAT_DEATHDAMAGE) - end - end - end - - local itemFound = false - for i = 1, #tileItemIds do - local item = tile:getItemById(tileItemIds[i]) - if item then - itemFound = true - break - end - end - - if tile:getGround():getId() == 410 and not itemFound and not tile:getItemByTopOrder(1) and not tile:getItemByTopOrder(3) then - pos:sendMagicEffect(CONST_ME_REDSMOKE) - end - end - end - - for posString, itemId in pairs(toRevertPositions) do - local pos = posString:toPosition() - local tile = Tile(pos) - if tile and tile:getGround() and tile:getGround():getId() == 409 then - tile:getGround():transform(itemId) - toRevertPositions[pos:toString()] = nil - end - end -end - -function Monster:createSoulWarWhiteTiles(centerRoomPosition, zonePositions, executeInterval) - local groupPositions = generatePositionsInRange(centerRoomPosition, 7) - local totalTiles = 11 - local groupSize = 3 - local groupsCreated = 0 - - -- Run only for megalomania boss - if executeInterval then - -- Remove remains - for _, pos in ipairs(zonePositions) do - local tile = Tile(pos) - if tile and tile:getGround() then - local remains = tile:getItemById(33984) - if remains then - remains:remove() - end - end - end - end - - while #groupPositions > 0 and groupsCreated * groupSize < totalTiles do - local randomIndex = math.random(#groupPositions) - local startPos = groupPositions[randomIndex] - table.remove(groupPositions, randomIndex) - - local group = createConnectedGroup(startPos, groupPositions, groupSize) - for _, pos in ipairs(group) do - local tile = Tile(pos) - if tile then - toRevertPositions[pos:toString()] = tile:getGround():getId() - tile:getGround():transform(409) - end - end - - groupsCreated = groupsCreated + 1 - end - - addEvent(revertTilesAndApplyDamage, executeInterval or 3000, zonePositions) -end - -function Monster:generateBagYouDesireLoot(player) - local playerTaintLevel = player:getTaintLevel() - if not playerTaintLevel then - return {} - end - - local monsterName = self:getName() - local isMonsterValid = false - for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do - if monsterName == monster then - isMonsterValid = true - break - end - end - - if not isMonsterValid then - return {} - end - - -- Calculates the chances based on the number of taints - local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) - -- Generate loot - local loot = {} - if math.random(1, 100) <= totalChance then - local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) - if itemType then - loot[itemType:getId()] = { count = 1 } - logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) - end - end - - return loot -end - -local intervalBetweenExecutions = 10000 - -local accumulatedTime = 0 -local desiredInterval = 40000 -local bossSayInterval = 38000 - -function Monster:onThinkMegalomaniaWhiteTiles(interval, zonePositions, revertTime) - self:onThinkGoshnarTormentCounter(interval, 36, intervalBetweenExecutions, SoulWarQuest.levers.goshnarsMegalomania.boss.position) - - accumulatedTime = accumulatedTime + interval - - if accumulatedTime == bossSayInterval then - self:say("FEEL THE POWER OF MY WRATH!!") - end - -- Execute only after 40 seconds - if accumulatedTime >= desiredInterval then - self:createSoulWarWhiteTiles(SoulWarQuest.levers.goshnarsMegalomania.boss.position, zonePositions, revertTime) - accumulatedTime = 0 - end -end - -TaintTeleportCooldown = {} - -function Player:getTaintNameByNumber(taintNumber, skipKvCheck) - local haveTaintName = nil - local soulWarQuest = self:soulWarQuestKV() - local taintName = soulWarTaints[taintNumber] - if skipKvCheck or taintName and soulWarQuest:get(taintName) then - haveTaintName = taintName - end - - return haveTaintName -end - -function Player:addNextTaint() - local soulWarQuest = self:soulWarQuestKV() - for _, taintName in ipairs(soulWarTaints) do - if not soulWarQuest:get(taintName) then - soulWarQuest:set(taintName, true) - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have gained the " .. taintName .. ".") - self:setTaintIcon() - break - end - end -end - -function Player:setTaintIcon(taintId) - self:resetTaintConditions() - local condition = Condition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, taintId or self:getTaintLevel()) - condition:setTicks(14 * 24 * 60 * 60 * 1000) - self:addCondition(condition) -end - -function Player:resetTaintConditions() - for i = 1, 5 do - self:removeCondition(CONDITION_GOSHNARTAINT, CONDITIONID_DEFAULT, i) - end -end - -function Player:getTaintLevel() - local taintLevel = nil - local soulWarQuest = self:soulWarQuestKV() - for i, taint in ipairs(soulWarTaints) do - if soulWarQuest:get(taint) then - taintLevel = i - end - end - - return taintLevel -end - -function Player:resetTaints(skipCheckTime) - local soulWarQuest = self:soulWarQuestKV() - local firstTaintTime = soulWarQuest:get("firstTaintTime") - if skipCheckTime or firstTaintTime and os.time() >= (firstTaintTime + TaintDurationSeconds) then - -- Reset all taints and remove condition - for _, taintName in ipairs(soulWarTaints) do - if soulWarQuest:get(taintName) then - soulWarQuest:remove(taintName) - end - end - self:resetTaintConditions() - soulWarQuest:remove("firstTaintTime") - self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your goshnar's taints have been reset. You didn't finish the quest in 14 days") - end -end - -function Monster:tryTeleportToPlayer(sayMessage) - local range = 30 - local spectators = Game.getSpectators(self:getPosition(), false, false, range, range, range, range) - local maxDistance = 0 - local farthestPlayer = nil - for i, spectator in ipairs(spectators) do - if spectator:isPlayer() then - local player = spectator:getPlayer() - if player:getTaintNameByNumber(1, true) then - local distance = self:getPosition():getDistance(player:getPosition()) - if distance > maxDistance then - maxDistance = distance - farthestPlayer = player - logger.trace("Found player {} to teleport", player:getName()) - end - end - end - end - - if farthestPlayer and math.random(100) <= 10 then - local playerPosition = farthestPlayer:getPosition() - if TaintTeleportCooldown[farthestPlayer:getId()] then - logger.trace("Cooldown is active to player {}", farthestPlayer:getName()) - return - end - - if not TaintTeleportCooldown[farthestPlayer:getId()] then - TaintTeleportCooldown[farthestPlayer:getId()] = true - - logger.trace("Scheduling player {} to teleport", farthestPlayer:getName()) - self:getPosition():sendMagicEffect(CONST_ME_MORTAREA) - farthestPlayer:getPosition():sendMagicEffect(CONST_ME_MORTAREA) - addEvent(function(playerId, monsterId) - local monsterEvent = Monster(monsterId) - local playerEvent = Player(playerId) - if monsterEvent and playerEvent then - local destinationTile = Tile(playerPosition) - if destinationTile and not (destinationTile:hasProperty(CONST_PROP_BLOCKPROJECTILE) or destinationTile:hasProperty(CONST_PROP_MOVEABLE)) then - monsterEvent:say(sayMessage) - monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - monsterEvent:teleportTo(playerPosition, true) - monsterEvent:getPosition():sendMagicEffect(CONST_ME_TELEPORT) - end - end - end, 2000, farthestPlayer:getId(), self:getId()) - - addEvent(function(playerId) - local playerEvent = Player(playerId) - if not playerEvent then - return - end - - logger.trace("Cleaning player cooldown") - TaintTeleportCooldown[playerEvent:getId()] = nil - end, 10000, farthestPlayer:getId()) - end - end -end - -function Monster:getSoulWarKV() - return SoulWarQuest.kvSoulWar:scoped("monster"):scoped(self:getName()) -end - -function Monster:getHatredDamageMultiplier() - return self:getSoulWarKV():get("burning-hatred-empowered") or 0 -end - -function Monster:increaseHatredDamageMultiplier(multiplierCount) - local attackMultiplier = self:getHatredDamageMultiplier() - self:getSoulWarKV():set("burning-hatred-empowered", attackMultiplier + multiplierCount or 10) -end - -function Monster:resetHatredDamageMultiplier() - self:getSoulWarKV():remove("burning-hatred-empowered") -end - -function Position:increaseNecromaticMegalomaniaStrength() - local tile = Tile(self) - if tile then - local item = tile:getItemById(SoulWarQuest.necromanticRemainsId) - if item then - local boss = Creature("Goshnar's Megalomania") - if boss then - boss:increaseHatredDamageMultiplier(5) - item:remove() - logger.trace("Necromantic remains strength increased") - end - end - end -end - -local lastExecutionTime = 0 - --- Damage 24 to 36 have a special damage -local damageTable = { - 1400, - 1600, - 1800, - 2200, - 2400, - 2600, - 3000, - 3400, - 3800, - 4200, - 4800, - 5200, - 5600, -} - -function Monster:onThinkGoshnarTormentCounter(interval, maxLimit, intervalBetweenExecutions, bossPosition) - local interval = os.time() * 1000 - if interval - lastExecutionTime < intervalBetweenExecutions then - return - end - - lastExecutionTime = interval - logger.trace("Icon time count {}", interval) - local spectators = Game.getSpectators(bossPosition, false, true, 15, 15, 15, 15) - for i = 1, #spectators do - local player = spectators[i] - local tormentCounter = player:getGoshnarSymbolTormentCounter() - if tormentCounter <= maxLimit then - player:increaseGoshnarSymbolTormentCounter(maxLimit) - logger.trace("Player {} has {} damage counter", player:getName(), tormentCounter) - - if tormentCounter > 0 then - local damage = tormentCounter * 35 - if tormentCounter >= 24 then - damage = damageTable[tormentCounter - 23] - end - - logger.trace("Final damage {}", damage) - player:addHealth(-damage, COMBAT_DEATHDAMAGE) - player:getPosition():sendMagicEffect(CONST_ME_PINK_ENERGY_SPARK) - end - end - - if tormentCounter == 5 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread starts to torment you! Don't let dread level reach critical value!") - elseif tormentCounter == 15 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment becomes unbearable!") - elseif tormentCounter == 24 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The Dread's torment begins to tear you apart!") - elseif tormentCounter == 30 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is killing you!") - elseif tormentCounter == 36 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The dread's torment is now lethal!") - end - end -end - -function Monster:increaseAspectOfPowerDeathCount() - local bossKV = self:getSoulWarKV() - local aspectDeathCount = bossKV:get("aspect-of-power-death-count") or 0 - local newCount = aspectDeathCount + 1 - logger.trace("Aspect of Power death count {}", newCount) - bossKV:set("aspect-of-power-death-count", newCount) - if newCount == 4 then - self:setType("Goshnar's Megalomania Green") - self:say("THE DEATH OF ASPECTS DIMINISHES GOSHNAR'S POWER AND HE TURNS VULNERABLE!") - bossKV:set("aspect-of-power-death-count", 0) - logger.trace("Aspect of Power defeated all and Megalomania is now vulnerable, reseting death count.") - SoulWarQuest.changePurpleEvent = addEvent(function() - local boss = Creature("Goshnar's Megalomania") - if boss and boss:getTypeName() == "Goshnar's Megalomania Green" then - boss:setType("Goshnar's Megalomania Purple") - boss:say("GOSHNAR REGAINED ENOUGH POWER TO TURN INVULNERABLE AGAIN!") - logger.trace("Megalomania is now immune again") - end - end, SoulWarQuest.timeToReturnImmuneMegalomania * 1000) - end -end - -function Monster:goshnarsDefenseIncrease(kvName) - local currentTime = os.time() - -- Gets the time when the "Greedy Maw" item was last used. - local lastItemUseTime = SoulWarQuest.kvSoulWar:get(kvName) or 0 - -- Checks if more than config time have passed since the item was last used. - if currentTime >= lastItemUseTime + SoulWarQuest.timeToIncreaseCrueltyDefense then - logger.trace("{} old defense {}", self:getName(), self:getDefense()) - self:addDefense(SoulWarQuest.goshnarsCrueltyDefenseChange) - logger.trace("{} new defense {}", self:getName(), self:getDefense()) - - --- Updates the KV to reflect the timing of the increase to maintain control. - SoulWarQuest.kvSoulWar:set(kvName, currentTime) - else - -- If config time have not passed, logs the increase has been skipped. - logger.trace("{} skips increase cooldown due to recent item use.", self:getName()) - end -end - -function Player:getSoulWarZoneMonster() - local zoneMonsterName = nil - for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do - local zone = Zone.getByName(zoneName) - if zone and zone:isInZone(self:getPosition()) then - zoneMonsterName = monsterName - break - end - end - - return zoneMonsterName -end - -function Player:isInBoatSpot() - -- Get ebb and flow zone and check if player is in zone - local zone = SoulWarQuest.ebbAndFlow.getZone() - local tile = Tile(self:getPosition()) - local groundId - if tile and tile:getGround() then - groundId = tile:getGround():getId() - end - if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then - logger.trace("Player {} is in boat spot", self:getName()) - return true - end - - logger.trace("Player {} is not in boat spot", self:getName()) - return false -end - -function Player:soulWarQuestKV() - return self:kv():scoped("quest"):scoped("soul-war") -end - -function Player:getGoshnarSymbolTormentCounter() - local soulWarKV = self:soulWarQuestKV() - return soulWarKV:get("goshnars-hatred-torment-count") or 0 -end - -function Player:increaseGoshnarSymbolTormentCounter(maxLimit) - local soulWarKV = self:soulWarQuestKV() - local tormentCount = self:getGoshnarSymbolTormentCounter() - if tormentCount == maxLimit then - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount) - return - end - - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount + 1) - soulWarKV:set("goshnars-hatred-torment-count", tormentCount + 1) -end - -function Player:removeGoshnarSymbolTormentCounter(count) - local soulWarKV = self:soulWarQuestKV() - local tormentCount = self:getGoshnarSymbolTormentCounter() - if tormentCount > count then - self:setIcon("goshnars-hatred-damage", CreatureIconCategory_Quests, CreatureIconQuests_RedCross, tormentCount - count) - soulWarKV:set("goshnars-hatred-torment-count", tormentCount - count) - else - self:resetGoshnarSymbolTormentCounter() - end -end - -function Player:resetGoshnarSymbolTormentCounter() - local soulWarKV = self:soulWarQuestKV() - soulWarKV:remove("goshnars-hatred-torment-count") - self:removeIcon("goshnars-hatred-damage") -end - -function Player:furiousCraterKV() - return self:soulWarQuestKV():scoped("furius-crater") -end - -function Player:pulsatingEnergyKV() - return self:furiousCraterKV():scoped("pulsating-energy") -end - -function Zone:getRandomPlayer() - local players = self:getPlayers() - if #players == 0 then - return nil - end - - local randomIndex = math.random(#players) - return players[randomIndex] -end - -local function delayedCastSpell(cid, var, combat, targetId) - local creature = Creature(cid) - if not creature then - return - end - - local target = Player(targetId) - if target then - combat:execute(creature, positionToVariant(target:getPosition())) - end -end - -function Creature:applyZoneEffect(var, combat, zoneName) - local outfitConfig = { - outfit = { lookType = 242, lookHead = 0, lookBody = 0, lookLegs = 0, lookFeet = 0, lookAddons = 0 }, - time = 7000, - } - - local zone = Zone.getByName(zoneName) - if not zone then - logger.error("Could not find zone '" .. zoneName .. "', you need use the 'BossLever' system") - return false - end - - local target = zone:getRandomPlayer() - if not target then - return true - end - - local condition = Condition(CONDITION_OUTFIT) - condition:setTicks(outfitConfig.time) - condition:setOutfit(outfitConfig.outfit) - target:addCondition(condition) - target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE) - - addEvent(delayedCastSpell, SoulWarQuest.goshnarsCrueltyWaveInterval * 1000, self:getId(), var, combat, target:getId()) - - return true -end - -function string.toPosition(str) - local patterns = { - -- table format - "{%s*x%s*=%s*(%d+)%s*,%s*y%s*=%s*(%d+)%s*,%s*z%s*=%s*(%d+)%s*}", - -- Position format - "Position%s*%((%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)", - -- x, y, z format - "(%d+)%s*,%s*(%d+)%s*,%s*(%d+)", - } - - for _, pattern in ipairs(patterns) do - local x, y, z = string.match(str, pattern) - if x and y and z then - return Position(tonumber(x), tonumber(y), tonumber(z)) - end - end -end From 619668d17851852c788395a7705fbdc8e68af782 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Tue, 16 Apr 2024 11:22:39 -0300 Subject: [PATCH 15/31] fix: nil value with boss levers --- data-otservbr-global/lib/quests/soul_war.lua | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 7ebe42b0441..aa71fc36d95 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -680,6 +680,39 @@ SoulWarQuest = { }, } +function RegisterSoulWarBossesLevers() + -- Register levers + local goshnarsMaliceLever = BossLever(SoulWarQuest.levers.goshnarsMalice) + goshnarsMaliceLever:position(SoulWarQuest.levers.goshnarsMalicePosition) + goshnarsMaliceLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsMaliceLever:getZone():getName()) + + local goshnarsSpiteLever = BossLever(SoulWarQuest.levers.goshnarsSpite) + goshnarsSpiteLever:position(SoulWarQuest.levers.goshnarsSpitePosition) + goshnarsSpiteLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsSpiteLever:getZone():getName()) + + local goshnarsGreedLever = BossLever(SoulWarQuest.levers.goshnarsGreed) + goshnarsGreedLever:position(SoulWarQuest.levers.goshnarsGreedPosition) + goshnarsGreedLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsGreedLever:getZone():getName()) + + local goshnarsHatredLever = BossLever(SoulWarQuest.levers.goshnarsHatred) + goshnarsHatredLever:position(SoulWarQuest.levers.goshnarsHatredPosition) + goshnarsHatredLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsHatredLever:getZone():getName()) + + local goshnarsCrueltyLever = BossLever(SoulWarQuest.levers.goshnarsCruelty) + goshnarsCrueltyLever:position(SoulWarQuest.levers.goshnarsCrueltyPosition) + goshnarsCrueltyLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsCrueltyLever:getZone():getName()) + + local goshnarsMegalomaniaLever = BossLever(SoulWarQuest.levers.goshnarsMegalomania) + goshnarsMegalomaniaLever:position(SoulWarQuest.levers.goshnarsMegalomaniaPosition) + goshnarsMegalomaniaLever:register() + logger.debug("Registering soul war boss lever zone: {}", goshnarsMegalomaniaLever:getZone():getName()) +end + -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) From 5d4ea28f33e1121a22903cf7f0906b59a8a87543 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 12 May 2024 02:36:22 -0300 Subject: [PATCH 16/31] fix: mechanics and npc flickering soul changes: - Added taints removal with words "taints" and "penalties" to npc flickering soul - Fixed soul war mechanics that should not be applied when in safe places (before hunt teleport) - Removed bag you desire as loot of soul war monsters --- data-otservbr-global/lib/quests/soul_war.lua | 35 +++++++++++++++++-- data-otservbr-global/npc/flickering_soul.lua | 8 ++--- .../eventcallback_on_combat_taint.lua | 2 +- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index aa71fc36d95..987d65d5816 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -132,7 +132,15 @@ SoulWarQuest = { ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", }, - caustrophobicInferno = Zone("zone.claustrophobic-inferno"), + safe = { + claustrophobicInferno = Zone("safezone.claustrophobic-inferno"), + mirroredNightmare = Zone("safezone.mirrored-nightmare"), + ebbAndFlow = Zone("safezone.ebb-and-flow"), + furiousCrater = Zone("safezone.furious-crater"), + rottenWasteland = Zone("safezone.rotten-wasteland"), + }, + + claustrophobicInferno = Zone("zone.claustrophobic-inferno"), mirroredNightmare = Zone("zone.mirrored-nightmare"), ebbAndFlow = Zone("zone.ebb-and-flow"), furiousCrater = Zone("zone.furious-crater"), @@ -716,8 +724,19 @@ end -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) +-- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) +SoulWarQuest.areaZones.safe.ebbAndFlow:addArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) + +SoulWarQuest.areaZones.safe.claustrophobicInferno:addArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) + +SoulWarQuest.areaZones.safe.furiousCrater:addArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) + +SoulWarQuest.areaZones.safe.rottenWasteland:addArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) + +SoulWarQuest.areaZones.safe.mirroredNightmare:addArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) + -- Initialize bosses access for taint check -SoulWarQuest.areaZones.caustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) +SoulWarQuest.areaZones.claustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) SoulWarQuest.areaZones.ebbAndFlow:addArea({ x = 33873, y = 30994, z = 8 }, { x = 33968, y = 31150, z = 9 }) @@ -1075,7 +1094,7 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1, true) then + if player:getTaintNameByNumber(1, true) and not player:isInSafeZone() then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance @@ -1259,6 +1278,16 @@ function Monster:goshnarsDefenseIncrease(kvName) end end +function Player:isInSafeZone() + for zoneName, zone in pairs(SoulWarQuest.areaZones.safe) do + if zone and zone:isInZone(self:getPosition()) then + return true + end + end + + return false +end + function Player:getSoulWarZoneMonster() local zoneMonsterName = nil for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do diff --git a/data-otservbr-global/npc/flickering_soul.lua b/data-otservbr-global/npc/flickering_soul.lua index 2010198da6e..a00df70e338 100644 --- a/data-otservbr-global/npc/flickering_soul.lua +++ b/data-otservbr-global/npc/flickering_soul.lua @@ -182,13 +182,9 @@ local function playerSayCallback(npc, player, type, message) end npcHandler:say(message, npc, player) elseif MsgContains(message, "taints") or MsgContains(message, "penalties") then - if player:getTaintLevel() ~= nil then - player:resetTaints(true) - npcHandler:say("I have cleansed you from the taints that you carried with you. You are now free from the burden that you should not have to bear.", npc, player) - return + if player:getTaintLevel() == nil then + player:resetTaints() end - - npcHandler:say("You are not tainted by the darkness of the world. You are pure and free from the burdens that others carry.", npc, player) end return true end diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 3e5ec34f930..936ab8502aa 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) From 0fd2240244bf7dbc141f736daa331e17180a09b8 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 12 May 2024 10:48:42 -0300 Subject: [PATCH 17/31] feat: claustrophobic inferno boss access mechanics changes: - Added raid system to access boss on claustrophobic inferno --- data-otservbr-global/lib/quests/soul_war.lua | 118 +++++++++++++++--- .../moveevent-claustrophobic-inferno-raid.lua | 116 ++++++++++------- 2 files changed, 174 insertions(+), 60 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 987d65d5816..06ecc85fe04 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -117,6 +117,98 @@ SoulWarQuest = { { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, }, + safeZones = { + claustrophobicInferno = Zone("safe.claustrophobic-inferno"), + mirroredNightmare = Zone("safe.mirrored-nightmare"), + ebbAndFlow = Zone("safe.ebb-and-flow"), + furiousCrater = Zone("safe.furious-crater"), + rottenWasteland = Zone("safe.rotten-wasteland"), + }, + + raids = { + [1] = { + timerStarted = false, + sandTimerPositions = { + { x = 34012, y = 31049, z = 9 }, + { x = 34013, y = 31049, z = 9 }, + { x = 34014, y = 31049, z = 9 }, + { x = 34015, y = 31049, z = 9 }, + }, + zone = Zone("raid.first-claustrophobic-inferno"), + spawns = { + Position(33991, 31064, 9), Position(34034, 31060, 9), Position(34028, 31067, 9), Position(34020, 31067, 9), + Position(34008, 31067, 9), Position(34001, 31059, 9), Position(33992, 31069, 9), Position(34002, 31072, 9), + Position(34013, 31074, 9), Position(33998, 31060, 9), Position(34039, 31065, 9), Position(34032, 31072, 9), + }, + exitPosition = Position(34009, 31083, 9), + endEvent = nil, + kickEvent = nil, + spawnEvent = nil, + getZone = function() + return SoulWarQuest.raids[1].zone + end, + toggleTimer = function() + SoulWarQuest.raids[1].timerStarted = not SoulWarQuest.raids[1].timerStarted + end, + }, + [2] = { + timerStarted = false, + sandTimerPositions = { + { x = 34012, y = 31075, z = 10 }, + { x = 34011, y = 31075, z = 10 }, + { x = 34010, y = 31075, z = 10 }, + }, + zone = Zone("raid.second-claustrophobic-inferno"), + spawns = { + Position(33999, 31046, 10), Position(34011, 31047, 10), Position(34005, 31052, 10), Position(34015, 31052, 10), + Position(34021, 31044, 10), Position(34029, 31054, 10), Position(34037, 31052, 10), Position(34037, 31060, 10), + Position(34023, 31062, 10), Position(34012, 31061, 10), Position(33998, 31061, 10), Position(34005, 31052, 10), + }, + exitPosition = Position(34011, 31028, 10), + endEvent = nil, + kickEvent = nil, + spawnEvent = nil, + getZone = function() + return SoulWarQuest.raids[2].zone + end, + toggleTimer = function() + SoulWarQuest.raids[2].timerStarted = not SoulWarQuest.raids[2].timerStarted + end, + }, + [3] = { + timerStarted = false, + sandTimerPositions = { + { x = 34009, y = 31036, z = 11 }, + { x = 34010, y = 31036, z = 11 }, + { x = 34011, y = 31036, z = 11 }, + { x = 34012, y = 31036, z = 11 }, + { x = 34013, y = 31036, z = 11 }, + { x = 34014, y = 31036, z = 11 }, + }, + zone = Zone("raid.third-claustrophobic-inferno"), + spawns = { + Position(34005, 31049, 11), Position(33999, 31051, 11), Position(33995, 31055, 11), Position(33995, 31055, 11), + Position(34001, 31069, 11), Position(33999, 31068, 11), Position(34016, 31068, 11), Position(34029, 31071, 11), + Position(34030, 31070, 11), Position(34038, 31066, 11), Position(34038, 31051, 11), Position(34033, 31051, 11), + Position(34025, 31048, 11), Position(34025, 31049, 11), Position(34013, 31058, 11), Position(34021, 31059, 11), + Position(34027, 31063, 11), Position(34007, 31063, 11), Position(34004, 31059, 11), + }, + exitPosition = Position(34014, 31085, 11), + endEvent = nil, + kickEvent = nil, + spawnEvent = nil, + getZone = function() + return SoulWarQuest.raids[3].zone + end, + toggleTimer = function() + SoulWarQuest.raids[3].timerStarted = not SoulWarQuest.raids[3].timerStarted + end, + }, + spawnTime = 10, -- seconds + suriviveTime = 2 * 60, -- 2 minutes + timeToKick = 5, -- seconds + }, + areaZones = { monsters = { ["zone.claustrophobic-inferno"] = "Brachiodemon", @@ -132,14 +224,6 @@ SoulWarQuest = { ["boss.goshnar's-megalomania-purple"] = "Dreadful Harvester", }, - safe = { - claustrophobicInferno = Zone("safezone.claustrophobic-inferno"), - mirroredNightmare = Zone("safezone.mirrored-nightmare"), - ebbAndFlow = Zone("safezone.ebb-and-flow"), - furiousCrater = Zone("safezone.furious-crater"), - rottenWasteland = Zone("safezone.rotten-wasteland"), - }, - claustrophobicInferno = Zone("zone.claustrophobic-inferno"), mirroredNightmare = Zone("zone.mirrored-nightmare"), ebbAndFlow = Zone("zone.ebb-and-flow"), @@ -724,16 +808,22 @@ end -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) +-- Initialize claustrophobic inferno raid zones + +SoulWarQuest.raids[1].zone:addArea({ x = 33985, y = 31053, z = 9}, { x = 34045, y = 31077, z = 9}) +SoulWarQuest.raids[2].zone:addArea({ x = 33988, y = 31042, z = 10}, { x = 34043, y = 31068, z = 10}) +SoulWarQuest.raids[3].zone:addArea({ x = 33987, y = 31043, z = 11}, { x = 34044, y = 31076, z = 11}) + -- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) -SoulWarQuest.areaZones.safe.ebbAndFlow:addArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) +SoulWarQuest.safeZones.ebbAndFlow:addArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) -SoulWarQuest.areaZones.safe.claustrophobicInferno:addArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) +SoulWarQuest.safeZones.claustrophobicInferno:addArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) -SoulWarQuest.areaZones.safe.furiousCrater:addArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) +SoulWarQuest.safeZones.furiousCrater:addArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) -SoulWarQuest.areaZones.safe.rottenWasteland:addArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) +SoulWarQuest.safeZones.rottenWasteland:addArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) -SoulWarQuest.areaZones.safe.mirroredNightmare:addArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) +SoulWarQuest.safeZones.mirroredNightmare:addArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) -- Initialize bosses access for taint check SoulWarQuest.areaZones.claustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) @@ -1279,7 +1369,7 @@ function Monster:goshnarsDefenseIncrease(kvName) end function Player:isInSafeZone() - for zoneName, zone in pairs(SoulWarQuest.areaZones.safe) do + for zoneName, zone in pairs(SoulWarQuest.safeZones) do if zone and zone:isInZone(self:getPosition()) then return true end diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua index 0502d53e365..ea1d004b99a 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua @@ -4,58 +4,82 @@ local thirdRaid = MoveEvent() local spawnMonsterName = "Brachiodemon" --- Registering encounters, stages and move events -for raidNumber, raid in ipairs(SoulWarQuest.claustrophobicInfernoRaids) do - -- Registering encounter - local raidName = string.format("Claustrophobic Inferno Raid %d", raidNumber) - local encounter = Encounter(raidName, { - zone = raid.getZone(), - timeToSpawnMonsters = "3s", - }) - - local spawnTimes = SoulWarQuest.claustrophobicInfernoRaids.suriviveTime / SoulWarQuest.claustrophobicInfernoRaids.spawnTime - - -- Registering encounter stages - for i = 1, spawnTimes do - encounter - :addSpawnMonsters({ - { - name = spawnMonsterName, - positions = raid.spawns, - }, - }) - :autoAdvance(SoulWarQuest.claustrophobicInfernoRaids.spawnTime * 1000) - end +local firstRaidNumber = 1 +local secondRaidNumber = 2 +local thirdRaidNumber = 3 - function encounter:onReset(position) - encounter:removeMonsters() - addEvent(function(zone) - zone:refresh() - zone:removePlayers() - end, SoulWarQuest.claustrophobicInfernoRaids.timeToKick * 1000, raid.getZone()) - logger.debug("{} has ended", raidName) - end +local function createTeleportEffect(position) + position:sendMagicEffect(CONST_ME_TELEPORT) +end - encounter:register() +local function spawnMonsters(raidNumber) + if not SoulWarQuest.raids[raidNumber].timerStarted then return end + for _, spawnPosition in pairs(SoulWarQuest.raids[raidNumber].spawns) do + addEvent(createTeleportEffect, 1000, spawnPosition) + addEvent(createTeleportEffect, 2000, spawnPosition) + addEvent(createTeleportEffect, 3000, spawnPosition) + addEvent(Game.createMonster, 4000, spawnMonsterName, spawnPosition, true, true) + end + SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) +end - -- Registering move event - local raidMoveEvent = MoveEvent() +local function kickPlayers(zone, raidNumber) + SoulWarQuest.raids[raidNumber].toggleTimer() + for _, player in pairs(zone:getPlayers()) do + player:teleportTo(SoulWarQuest.raids[raidNumber].exitPosition) + end +end - function raidMoveEvent.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then - return true - end - if fromPosition.y == position.y - (raidNumber % 2 ~= 0 and -1 or 1) then -- if player comes from the raid zone don't start the raid - return +local function endRaid(zone, raidNumber) + if SoulWarQuest.raids[raidNumber].spawnEvent then stopEvent(SoulWarQuest.raids[raidNumber].spawnEvent) end + for _, monster in pairs(zone:getMonsters()) do + if not monster:getMaster() then + monster:getPosition():sendMagicEffect(CONST_ME_POFF) + monster:remove() end - logger.debug("{} has started", raidName) - encounter:start() - return true end + SoulWarQuest.raids[raidNumber].kickEvent = addEvent(kickPlayers, SoulWarQuest.raids.timeToKick * 1000, zone, raidNumber) + logger.debug("Claustrophobic Inferno Raid #{} ended", raidNumber) +end - for _, pos in pairs(raid.sandTimerPositions) do - raidMoveEvent:position(pos) - end +local function raid(zone, raidNumber) + if SoulWarQuest.raids[raidNumber].timerStarted then return end + logger.debug("Claustrophobic Inferno Raid #{} started", raidNumber) + SoulWarQuest.raids[raidNumber].toggleTimer() + SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) + SoulWarQuest.raids[raidNumber].endEvent = addEvent(endRaid, SoulWarQuest.raids.suriviveTime * 1000, zone, raidNumber) +end - raidMoveEvent:register() +function firstRaid.onStepIn(creature, item, position, fromPosition) + if not creature:getPlayer() then return true end + raid(SoulWarQuest.raids[firstRaidNumber].getZone(), firstRaidNumber) + return true end + +function secondRaid.onStepIn(creature, item, position, fromPosition) + if not creature:getPlayer() then return true end + raid(SoulWarQuest.raids[secondRaidNumber].getZone(), secondRaidNumber) + return true +end + +function thirdRaid.onStepIn(creature, item, position, fromPosition) + if not creature:getPlayer() then return true end + raid(SoulWarQuest.raids[thirdRaidNumber].getZone(), thirdRaidNumber) + return true +end + +for _, pos in pairs(SoulWarQuest.raids[firstRaidNumber].sandTimerPositions) do + firstRaid:position(pos) +end + +for _, pos in pairs(SoulWarQuest.raids[secondRaidNumber].sandTimerPositions) do + secondRaid:position(pos) +end + +for _, position in pairs(SoulWarQuest.raids[thirdRaidNumber].sandTimerPositions) do + thirdRaid:position(position) +end + +firstRaid:register() +secondRaid:register() +thirdRaid:register() From 73683979185105ecee04a6e6779452f4985c3143 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 26 May 2024 17:10:01 -0300 Subject: [PATCH 18/31] improvement: claustrophobic inferno raids and safe zones --- .../scripts/quests/soul_war/eventcallback_on_combat_taint.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 936ab8502aa..3e5ec34f930 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) From e9f4117c01ff59e20e8c9026e9974f6ae8e822a4 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 14 Jun 2024 22:36:39 -0300 Subject: [PATCH 19/31] fix: eventcallback and flickering soul --- data-otservbr-global/npc/flickering_soul.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data-otservbr-global/npc/flickering_soul.lua b/data-otservbr-global/npc/flickering_soul.lua index a00df70e338..2010198da6e 100644 --- a/data-otservbr-global/npc/flickering_soul.lua +++ b/data-otservbr-global/npc/flickering_soul.lua @@ -182,9 +182,13 @@ local function playerSayCallback(npc, player, type, message) end npcHandler:say(message, npc, player) elseif MsgContains(message, "taints") or MsgContains(message, "penalties") then - if player:getTaintLevel() == nil then - player:resetTaints() + if player:getTaintLevel() ~= nil then + player:resetTaints(true) + npcHandler:say("I have cleansed you from the taints that you carried with you. You are now free from the burden that you should not have to bear.", npc, player) + return end + + npcHandler:say("You are not tainted by the darkness of the world. You are pure and free from the burdens that others carry.", npc, player) end return true end From d744cb2c0cd07138eabe68d0d23d225db7398959 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sat, 15 Jun 2024 00:01:56 -0300 Subject: [PATCH 20/31] fix: megalomania drop for bag you desire --- data-otservbr-global/lib/quests/soul_war.lua | 41 +++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 06ecc85fe04..5501e093647 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -51,13 +51,12 @@ SoulWarQuest = { "Sorcerer's Apparition", "Turbulent Elemental", "Vibrant Phantom.", - }, - bagYouDesireBosses = { "Goshnar's Cruelty", "Goshnar's Spite", "Goshnar's Malice", "Goshnar's Hatred", "Goshnar's Greed", + "Goshnar's Megalomania", }, -- Goshnar's Cruelty pulsating energy monsters @@ -1056,33 +1055,45 @@ end function Monster:generateBagYouDesireLoot(player) local playerTaintLevel = player:getTaintLevel() - if not playerTaintLevel then + if not playerTaintLevel or playerTaintLevel == 0 then return {} end local monsterName = self:getName() - local isMonsterValid = false - for _, monster in ipairs(SoulWarQuest.bagYouDesireMonsters) do - if monsterName == monster then - isMonsterValid = true - break - end - end - + local isMonsterValid = table.contains(SoulWarQuest.bagYouDesireMonsters, monsterName) if not isMonsterValid then return {} end - -- Calculates the chances based on the number of taints - local totalChance = SoulWarQuest.baseBagYouDesireChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) - logger.trace("Player {} killed {} and has {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) - -- Generate loot local loot = {} + local totalChance = SoulWarQuest.baseBagYouDesireChance + local soulWarQuest = player:soulWarQuestKV() + local megalomaniaKills = soulWarQuest:scoped("megalomania-kills"):get("count") or 0 + + if monsterName == "Goshnar's Megalomania" then + -- Special handling for Goshnar's Megalomania + totalChance = totalChance + megalomaniaKills * SoulWarQuest.bagYouDesireChancePerTaint + else + -- General handling for other monsters (bosses and non-bosses) + totalChance = totalChance + (playerTaintLevel * SoulWarQuest.bagYouDesireChancePerTaint) + end + + logger.trace("Player {} killed {} with {} taints, loot chance {}", player:getName(), monsterName, playerTaintLevel, totalChance) + if math.random(1, 100) <= totalChance then local itemType = ItemType(SoulWarQuest.bagYouDesireItemId) if itemType then loot[itemType:getId()] = { count = 1 } logger.debug("Player {} killed {} and got a bag you desire with drop chance {}", player:getName(), monsterName, totalChance) + if monsterName == "Goshnar's Megalomania" then + -- Reset kill count on successful drop + soulWarQuest:scoped("megalomania-kills"):set("count", 0) + end + end + else + if monsterName == "Goshnar's Megalomania" then + -- Increment kill count for unsuccessful attempts + soulWarQuest:scoped("megalomania-kills"):set("count", megalomaniaKills + 1) end end From 7d0aa3a36305df9234ec504bf1a35f04e5448d1e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 12 May 2024 13:51:00 +0000 Subject: [PATCH 21/31] Lua code format - (Stylua) --- data-otservbr-global/lib/quests/soul_war.lua | 60 ++++++++++++++----- .../moveevent-claustrophobic-inferno-raid.lua | 24 ++++++-- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 5501e093647..3431cd1fb6b 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -135,9 +135,18 @@ SoulWarQuest = { }, zone = Zone("raid.first-claustrophobic-inferno"), spawns = { - Position(33991, 31064, 9), Position(34034, 31060, 9), Position(34028, 31067, 9), Position(34020, 31067, 9), - Position(34008, 31067, 9), Position(34001, 31059, 9), Position(33992, 31069, 9), Position(34002, 31072, 9), - Position(34013, 31074, 9), Position(33998, 31060, 9), Position(34039, 31065, 9), Position(34032, 31072, 9), + Position(33991, 31064, 9), + Position(34034, 31060, 9), + Position(34028, 31067, 9), + Position(34020, 31067, 9), + Position(34008, 31067, 9), + Position(34001, 31059, 9), + Position(33992, 31069, 9), + Position(34002, 31072, 9), + Position(34013, 31074, 9), + Position(33998, 31060, 9), + Position(34039, 31065, 9), + Position(34032, 31072, 9), }, exitPosition = Position(34009, 31083, 9), endEvent = nil, @@ -159,9 +168,18 @@ SoulWarQuest = { }, zone = Zone("raid.second-claustrophobic-inferno"), spawns = { - Position(33999, 31046, 10), Position(34011, 31047, 10), Position(34005, 31052, 10), Position(34015, 31052, 10), - Position(34021, 31044, 10), Position(34029, 31054, 10), Position(34037, 31052, 10), Position(34037, 31060, 10), - Position(34023, 31062, 10), Position(34012, 31061, 10), Position(33998, 31061, 10), Position(34005, 31052, 10), + Position(33999, 31046, 10), + Position(34011, 31047, 10), + Position(34005, 31052, 10), + Position(34015, 31052, 10), + Position(34021, 31044, 10), + Position(34029, 31054, 10), + Position(34037, 31052, 10), + Position(34037, 31060, 10), + Position(34023, 31062, 10), + Position(34012, 31061, 10), + Position(33998, 31061, 10), + Position(34005, 31052, 10), }, exitPosition = Position(34011, 31028, 10), endEvent = nil, @@ -186,11 +204,25 @@ SoulWarQuest = { }, zone = Zone("raid.third-claustrophobic-inferno"), spawns = { - Position(34005, 31049, 11), Position(33999, 31051, 11), Position(33995, 31055, 11), Position(33995, 31055, 11), - Position(34001, 31069, 11), Position(33999, 31068, 11), Position(34016, 31068, 11), Position(34029, 31071, 11), - Position(34030, 31070, 11), Position(34038, 31066, 11), Position(34038, 31051, 11), Position(34033, 31051, 11), - Position(34025, 31048, 11), Position(34025, 31049, 11), Position(34013, 31058, 11), Position(34021, 31059, 11), - Position(34027, 31063, 11), Position(34007, 31063, 11), Position(34004, 31059, 11), + Position(34005, 31049, 11), + Position(33999, 31051, 11), + Position(33995, 31055, 11), + Position(33995, 31055, 11), + Position(34001, 31069, 11), + Position(33999, 31068, 11), + Position(34016, 31068, 11), + Position(34029, 31071, 11), + Position(34030, 31070, 11), + Position(34038, 31066, 11), + Position(34038, 31051, 11), + Position(34033, 31051, 11), + Position(34025, 31048, 11), + Position(34025, 31049, 11), + Position(34013, 31058, 11), + Position(34021, 31059, 11), + Position(34027, 31063, 11), + Position(34007, 31063, 11), + Position(34004, 31059, 11), }, exitPosition = Position(34014, 31085, 11), endEvent = nil, @@ -809,9 +841,9 @@ SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 3396 -- Initialize claustrophobic inferno raid zones -SoulWarQuest.raids[1].zone:addArea({ x = 33985, y = 31053, z = 9}, { x = 34045, y = 31077, z = 9}) -SoulWarQuest.raids[2].zone:addArea({ x = 33988, y = 31042, z = 10}, { x = 34043, y = 31068, z = 10}) -SoulWarQuest.raids[3].zone:addArea({ x = 33987, y = 31043, z = 11}, { x = 34044, y = 31076, z = 11}) +SoulWarQuest.raids[1].zone:addArea({ x = 33985, y = 31053, z = 9 }, { x = 34045, y = 31077, z = 9 }) +SoulWarQuest.raids[2].zone:addArea({ x = 33988, y = 31042, z = 10 }, { x = 34043, y = 31068, z = 10 }) +SoulWarQuest.raids[3].zone:addArea({ x = 33987, y = 31043, z = 11 }, { x = 34044, y = 31076, z = 11 }) -- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) SoulWarQuest.safeZones.ebbAndFlow:addArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua index ea1d004b99a..944bd0dbda8 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua @@ -13,7 +13,9 @@ local function createTeleportEffect(position) end local function spawnMonsters(raidNumber) - if not SoulWarQuest.raids[raidNumber].timerStarted then return end + if not SoulWarQuest.raids[raidNumber].timerStarted then + return + end for _, spawnPosition in pairs(SoulWarQuest.raids[raidNumber].spawns) do addEvent(createTeleportEffect, 1000, spawnPosition) addEvent(createTeleportEffect, 2000, spawnPosition) @@ -31,7 +33,9 @@ local function kickPlayers(zone, raidNumber) end local function endRaid(zone, raidNumber) - if SoulWarQuest.raids[raidNumber].spawnEvent then stopEvent(SoulWarQuest.raids[raidNumber].spawnEvent) end + if SoulWarQuest.raids[raidNumber].spawnEvent then + stopEvent(SoulWarQuest.raids[raidNumber].spawnEvent) + end for _, monster in pairs(zone:getMonsters()) do if not monster:getMaster() then monster:getPosition():sendMagicEffect(CONST_ME_POFF) @@ -43,7 +47,9 @@ local function endRaid(zone, raidNumber) end local function raid(zone, raidNumber) - if SoulWarQuest.raids[raidNumber].timerStarted then return end + if SoulWarQuest.raids[raidNumber].timerStarted then + return + end logger.debug("Claustrophobic Inferno Raid #{} started", raidNumber) SoulWarQuest.raids[raidNumber].toggleTimer() SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) @@ -51,19 +57,25 @@ local function raid(zone, raidNumber) end function firstRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then return true end + if not creature:getPlayer() then + return true + end raid(SoulWarQuest.raids[firstRaidNumber].getZone(), firstRaidNumber) return true end function secondRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then return true end + if not creature:getPlayer() then + return true + end raid(SoulWarQuest.raids[secondRaidNumber].getZone(), secondRaidNumber) return true end function thirdRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then return true end + if not creature:getPlayer() then + return true + end raid(SoulWarQuest.raids[thirdRaidNumber].getZone(), thirdRaidNumber) return true end From 151c317ae80c5dd938cdf586898743cb75337787 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Mon, 13 May 2024 05:42:05 -0300 Subject: [PATCH 22/31] fix: dont start raid when player exits the raid zones changes: - Added checkage to not start raid when player pass on sandtimer from raid zones --- .../moveevent-claustrophobic-inferno-raid.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua index 944bd0dbda8..53684b1052e 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua @@ -46,11 +46,14 @@ local function endRaid(zone, raidNumber) logger.debug("Claustrophobic Inferno Raid #{} ended", raidNumber) end -local function raid(zone, raidNumber) +local function raid(zone, raidNumber, position, fromPosition) + if fromPosition.y == position.y - (raidNumber % 2 ~= 0 and -1 or 1) then -- if player comes from the raid zone don't start the raid + return + end if SoulWarQuest.raids[raidNumber].timerStarted then return end - logger.debug("Claustrophobic Inferno Raid #{} started", raidNumber) + logger.warn("Claustrophobic Inferno Raid #{} started", raidNumber) SoulWarQuest.raids[raidNumber].toggleTimer() SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) SoulWarQuest.raids[raidNumber].endEvent = addEvent(endRaid, SoulWarQuest.raids.suriviveTime * 1000, zone, raidNumber) @@ -60,7 +63,7 @@ function firstRaid.onStepIn(creature, item, position, fromPosition) if not creature:getPlayer() then return true end - raid(SoulWarQuest.raids[firstRaidNumber].getZone(), firstRaidNumber) + raid(SoulWarQuest.raids[firstRaidNumber].getZone(), firstRaidNumber, position, fromPosition) return true end @@ -68,7 +71,7 @@ function secondRaid.onStepIn(creature, item, position, fromPosition) if not creature:getPlayer() then return true end - raid(SoulWarQuest.raids[secondRaidNumber].getZone(), secondRaidNumber) + raid(SoulWarQuest.raids[secondRaidNumber].getZone(), secondRaidNumber, position, fromPosition) return true end @@ -76,7 +79,7 @@ function thirdRaid.onStepIn(creature, item, position, fromPosition) if not creature:getPlayer() then return true end - raid(SoulWarQuest.raids[thirdRaidNumber].getZone(), thirdRaidNumber) + raid(SoulWarQuest.raids[thirdRaidNumber].getZone(), thirdRaidNumber, position, fromPosition) return true end From f157c5f4bfcb8e3ee29ea7f09871b7fe347d56f9 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 26 May 2024 17:10:01 -0300 Subject: [PATCH 23/31] improvement: claustrophobic inferno raids and safe zones --- data-otservbr-global/lib/quests/soul_war.lua | 79 ++++------- .../moveevent-claustrophobic-inferno-raid.lua | 133 ++++++------------ 2 files changed, 75 insertions(+), 137 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 3431cd1fb6b..424a66db7b3 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -116,15 +116,7 @@ SoulWarQuest = { { from = Position(33856, 31884, 5), to = Position(33857, 31865, 6), access = "third-floor-access", count = 70 }, }, - safeZones = { - claustrophobicInferno = Zone("safe.claustrophobic-inferno"), - mirroredNightmare = Zone("safe.mirrored-nightmare"), - ebbAndFlow = Zone("safe.ebb-and-flow"), - furiousCrater = Zone("safe.furious-crater"), - rottenWasteland = Zone("safe.rotten-wasteland"), - }, - - raids = { + claustrophobicInfernoRaids = { [1] = { timerStarted = false, sandTimerPositions = { @@ -148,15 +140,12 @@ SoulWarQuest = { Position(34039, 31065, 9), Position(34032, 31072, 9), }, - exitPosition = Position(34009, 31083, 9), - endEvent = nil, - kickEvent = nil, - spawnEvent = nil, + exitPosition = { x = 34009, y = 31083, z = 9 }, getZone = function() - return SoulWarQuest.raids[1].zone + return SoulWarQuest.claustrophobicInfernoRaids[1].zone end, toggleTimer = function() - SoulWarQuest.raids[1].timerStarted = not SoulWarQuest.raids[1].timerStarted + SoulWarQuest.claustrophobicInfernoRaids[1].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[1].timerStarted end, }, [2] = { @@ -181,15 +170,12 @@ SoulWarQuest = { Position(33998, 31061, 10), Position(34005, 31052, 10), }, - exitPosition = Position(34011, 31028, 10), - endEvent = nil, - kickEvent = nil, - spawnEvent = nil, + exitPosition = { x = 34011, y = 31028, z = 10 }, getZone = function() - return SoulWarQuest.raids[2].zone + return SoulWarQuest.claustrophobicInfernoRaids[2].zone end, toggleTimer = function() - SoulWarQuest.raids[2].timerStarted = not SoulWarQuest.raids[2].timerStarted + SoulWarQuest.claustrophobicInfernoRaids[2].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[2].timerStarted end, }, [3] = { @@ -224,15 +210,12 @@ SoulWarQuest = { Position(34007, 31063, 11), Position(34004, 31059, 11), }, - exitPosition = Position(34014, 31085, 11), - endEvent = nil, - kickEvent = nil, - spawnEvent = nil, + exitPosition = { x = 34014, y = 31085, z = 11 }, getZone = function() - return SoulWarQuest.raids[3].zone + return SoulWarQuest.claustrophobicInfernoRaids[3].zone end, toggleTimer = function() - SoulWarQuest.raids[3].timerStarted = not SoulWarQuest.raids[3].timerStarted + SoulWarQuest.claustrophobicInfernoRaids[3].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[3].timerStarted end, }, spawnTime = 10, -- seconds @@ -841,20 +824,15 @@ SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 3396 -- Initialize claustrophobic inferno raid zones -SoulWarQuest.raids[1].zone:addArea({ x = 33985, y = 31053, z = 9 }, { x = 34045, y = 31077, z = 9 }) -SoulWarQuest.raids[2].zone:addArea({ x = 33988, y = 31042, z = 10 }, { x = 34043, y = 31068, z = 10 }) -SoulWarQuest.raids[3].zone:addArea({ x = 33987, y = 31043, z = 11 }, { x = 34044, y = 31076, z = 11 }) - --- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) -SoulWarQuest.safeZones.ebbAndFlow:addArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) - -SoulWarQuest.safeZones.claustrophobicInferno:addArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) +SoulWarQuest.claustrophobicInfernoRaids[1].zone:addArea({ x = 33985, y = 31053, z = 9 }, { x = 34045, y = 31077, z = 9 }) +SoulWarQuest.claustrophobicInfernoRaids[2].zone:addArea({ x = 33988, y = 31042, z = 10 }, { x = 34043, y = 31068, z = 10 }) +SoulWarQuest.claustrophobicInfernoRaids[3].zone:addArea({ x = 33987, y = 31043, z = 11 }, { x = 34044, y = 31076, z = 11 }) -SoulWarQuest.safeZones.furiousCrater:addArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) +-- Add remove destination -SoulWarQuest.safeZones.rottenWasteland:addArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) - -SoulWarQuest.safeZones.mirroredNightmare:addArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) +SoulWarQuest.claustrophobicInfernoRaids[1].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[1].exitPosition) +SoulWarQuest.claustrophobicInfernoRaids[2].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[2].exitPosition) +SoulWarQuest.claustrophobicInfernoRaids[3].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[3].exitPosition) -- Initialize bosses access for taint check SoulWarQuest.areaZones.claustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) @@ -867,6 +845,17 @@ SoulWarQuest.areaZones.rottenWasteland:addArea({ x = 33980, y = 30986, z = 11 }, SoulWarQuest.areaZones.mirroredNightmare:addArea({ x = 33877, y = 31164, z = 9 }, { x = 33991, y = 31241, z = 13 }) +-- Initialize safe areas (should not spawn monster, teleport, take damage from taint, etc) +SoulWarQuest.areaZones.claustrophobicInferno:subtractArea({ x = 34002, y = 31008, z = 9 }, { x = 34019, y = 31019, z = 9 }) + +SoulWarQuest.areaZones.ebbAndFlow:subtractArea({ x = 33887, y = 31015, z = 8 }, { x = 33920, y = 31024, z = 8 }) + +SoulWarQuest.areaZones.furiousCrater:subtractArea({ x = 33854, y = 31828, z = 3 }, { x = 33869, y = 31834, z = 3 }) + +SoulWarQuest.areaZones.rottenWasteland:subtractArea({ x = 33967, y = 31037, z = 11 }, { x = 33977, y = 31051, z = 11 }) + +SoulWarQuest.areaZones.mirroredNightmare:subtractArea({ x = 33884, y = 31181, z = 10 }, { x = 33892, y = 31198, z = 10 }) + SoulCagePosition = Position(33709, 31596, 14) TaintDurationSeconds = 14 * 24 * 60 * 60 -- 14 days GreedbeastKills = 0 @@ -1227,7 +1216,7 @@ function Monster:tryTeleportToPlayer(sayMessage) for i, spectator in ipairs(spectators) do if spectator:isPlayer() then local player = spectator:getPlayer() - if player:getTaintNameByNumber(1, true) and not player:isInSafeZone() then + if player:getTaintNameByNumber(1, true) and player:getSoulWarZoneMonster() ~= nil then local distance = self:getPosition():getDistance(player:getPosition()) if distance > maxDistance then maxDistance = distance @@ -1411,16 +1400,6 @@ function Monster:goshnarsDefenseIncrease(kvName) end end -function Player:isInSafeZone() - for zoneName, zone in pairs(SoulWarQuest.safeZones) do - if zone and zone:isInZone(self:getPosition()) then - return true - end - end - - return false -end - function Player:getSoulWarZoneMonster() local zoneMonsterName = nil for zoneName, monsterName in pairs(SoulWarQuest.areaZones.monsters) do diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua index 53684b1052e..4f0cac5a3f0 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua @@ -4,97 +4,56 @@ local thirdRaid = MoveEvent() local spawnMonsterName = "Brachiodemon" -local firstRaidNumber = 1 -local secondRaidNumber = 2 -local thirdRaidNumber = 3 - -local function createTeleportEffect(position) - position:sendMagicEffect(CONST_ME_TELEPORT) -end - -local function spawnMonsters(raidNumber) - if not SoulWarQuest.raids[raidNumber].timerStarted then - return - end - for _, spawnPosition in pairs(SoulWarQuest.raids[raidNumber].spawns) do - addEvent(createTeleportEffect, 1000, spawnPosition) - addEvent(createTeleportEffect, 2000, spawnPosition) - addEvent(createTeleportEffect, 3000, spawnPosition) - addEvent(Game.createMonster, 4000, spawnMonsterName, spawnPosition, true, true) - end - SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) -end - -local function kickPlayers(zone, raidNumber) - SoulWarQuest.raids[raidNumber].toggleTimer() - for _, player in pairs(zone:getPlayers()) do - player:teleportTo(SoulWarQuest.raids[raidNumber].exitPosition) - end -end - -local function endRaid(zone, raidNumber) - if SoulWarQuest.raids[raidNumber].spawnEvent then - stopEvent(SoulWarQuest.raids[raidNumber].spawnEvent) - end - for _, monster in pairs(zone:getMonsters()) do - if not monster:getMaster() then - monster:getPosition():sendMagicEffect(CONST_ME_POFF) - monster:remove() +-- Registering encounters, stages and move events +for raidNumber, raid in ipairs(SoulWarQuest.claustrophobicInfernoRaids) do + -- Registering encounter + local raidName = string.format("Claustrophobic Inferno Raid %d", raidNumber) + local encounter = Encounter(raidName, { + zone = raid.getZone(), + timeToSpawnMonsters = "3s" + }) + + local spawnTimes = (SoulWarQuest.claustrophobicInfernoRaids.suriviveTime) / SoulWarQuest.claustrophobicInfernoRaids.spawnTime + + -- Registering encounter stages + for i = 1, spawnTimes do + encounter:addSpawnMonsters({ + { + name = spawnMonsterName, + positions = raid.spawns + }, + }):autoAdvance(SoulWarQuest.claustrophobicInfernoRaids.spawnTime * 1000) + end + + function encounter:onReset(position) + encounter:removeMonsters() + addEvent(function(zone) + zone:refresh() + zone:removePlayers() + end, SoulWarQuest.claustrophobicInfernoRaids.timeToKick * 1000, raid.getZone()) + logger.debug("{} has ended", raidName) + end + + encounter:register() + + -- Registering move event + local raidMoveEvent = MoveEvent() + + function raidMoveEvent.onStepIn(creature, item, position, fromPosition) + if not creature:getPlayer() then + return true end - end - SoulWarQuest.raids[raidNumber].kickEvent = addEvent(kickPlayers, SoulWarQuest.raids.timeToKick * 1000, zone, raidNumber) - logger.debug("Claustrophobic Inferno Raid #{} ended", raidNumber) -end - -local function raid(zone, raidNumber, position, fromPosition) - if fromPosition.y == position.y - (raidNumber % 2 ~= 0 and -1 or 1) then -- if player comes from the raid zone don't start the raid - return - end - if SoulWarQuest.raids[raidNumber].timerStarted then - return - end - logger.warn("Claustrophobic Inferno Raid #{} started", raidNumber) - SoulWarQuest.raids[raidNumber].toggleTimer() - SoulWarQuest.raids[raidNumber].spawnEvent = addEvent(spawnMonsters, SoulWarQuest.raids.spawnTime * 1000, raidNumber) - SoulWarQuest.raids[raidNumber].endEvent = addEvent(endRaid, SoulWarQuest.raids.suriviveTime * 1000, zone, raidNumber) -end - -function firstRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then + if fromPosition.y == position.y - (raidNumber % 2 ~= 0 and -1 or 1) then -- if player comes from the raid zone don't start the raid + return + end + logger.debug("{} has started", raidName) + encounter:start() return true end - raid(SoulWarQuest.raids[firstRaidNumber].getZone(), firstRaidNumber, position, fromPosition) - return true -end -function secondRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then - return true + for _, pos in pairs(raid.sandTimerPositions) do + raidMoveEvent:position(pos) end - raid(SoulWarQuest.raids[secondRaidNumber].getZone(), secondRaidNumber, position, fromPosition) - return true -end -function thirdRaid.onStepIn(creature, item, position, fromPosition) - if not creature:getPlayer() then - return true - end - raid(SoulWarQuest.raids[thirdRaidNumber].getZone(), thirdRaidNumber, position, fromPosition) - return true + raidMoveEvent:register() end - -for _, pos in pairs(SoulWarQuest.raids[firstRaidNumber].sandTimerPositions) do - firstRaid:position(pos) -end - -for _, pos in pairs(SoulWarQuest.raids[secondRaidNumber].sandTimerPositions) do - secondRaid:position(pos) -end - -for _, position in pairs(SoulWarQuest.raids[thirdRaidNumber].sandTimerPositions) do - thirdRaid:position(position) -end - -firstRaid:register() -secondRaid:register() -thirdRaid:register() From 7f7b2182d1d8eb15942b2fcd2a5004648be2ddba Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 26 May 2024 22:21:50 -0300 Subject: [PATCH 24/31] fix: removed duplicated spawns and some improvements --- data-otservbr-global/lib/quests/soul_war.lua | 45 ++++++++------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index 424a66db7b3..319d731faf7 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -118,7 +118,10 @@ SoulWarQuest = { claustrophobicInfernoRaids = { [1] = { - timerStarted = false, + zoneArea = { + { x = 33985, y = 31053, z = 9 }, + { x = 34045, y = 31077, z = 9 }, + }, sandTimerPositions = { { x = 34012, y = 31049, z = 9 }, { x = 34013, y = 31049, z = 9 }, @@ -144,12 +147,12 @@ SoulWarQuest = { getZone = function() return SoulWarQuest.claustrophobicInfernoRaids[1].zone end, - toggleTimer = function() - SoulWarQuest.claustrophobicInfernoRaids[1].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[1].timerStarted - end, }, [2] = { - timerStarted = false, + zoneArea = { + { x = 33988, y = 31042, z = 10 }, + { x = 34043, y = 31068, z = 10 }, + }, sandTimerPositions = { { x = 34012, y = 31075, z = 10 }, { x = 34011, y = 31075, z = 10 }, @@ -159,7 +162,6 @@ SoulWarQuest = { spawns = { Position(33999, 31046, 10), Position(34011, 31047, 10), - Position(34005, 31052, 10), Position(34015, 31052, 10), Position(34021, 31044, 10), Position(34029, 31054, 10), @@ -174,12 +176,12 @@ SoulWarQuest = { getZone = function() return SoulWarQuest.claustrophobicInfernoRaids[2].zone end, - toggleTimer = function() - SoulWarQuest.claustrophobicInfernoRaids[2].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[2].timerStarted - end, }, [3] = { - timerStarted = false, + zoneArea = { + { x = 33987, y = 31043, z = 11 }, + { x = 34044, y = 31076, z = 11 }, + }, sandTimerPositions = { { x = 34009, y = 31036, z = 11 }, { x = 34010, y = 31036, z = 11 }, @@ -193,16 +195,12 @@ SoulWarQuest = { Position(34005, 31049, 11), Position(33999, 31051, 11), Position(33995, 31055, 11), - Position(33995, 31055, 11), - Position(34001, 31069, 11), Position(33999, 31068, 11), Position(34016, 31068, 11), - Position(34029, 31071, 11), Position(34030, 31070, 11), Position(34038, 31066, 11), Position(34038, 31051, 11), Position(34033, 31051, 11), - Position(34025, 31048, 11), Position(34025, 31049, 11), Position(34013, 31058, 11), Position(34021, 31059, 11), @@ -214,9 +212,6 @@ SoulWarQuest = { getZone = function() return SoulWarQuest.claustrophobicInfernoRaids[3].zone end, - toggleTimer = function() - SoulWarQuest.claustrophobicInfernoRaids[3].timerStarted = not SoulWarQuest.claustrophobicInfernoRaids[3].timerStarted - end, }, spawnTime = 10, -- seconds suriviveTime = 2 * 60, -- 2 minutes @@ -822,17 +817,13 @@ end -- Initialize ebb and flow zone area SoulWarQuest.ebbAndFlow.zone:addArea({ x = 33869, y = 30991, z = 8 }, { x = 33964, y = 31147, z = 9 }) --- Initialize claustrophobic inferno raid zones - -SoulWarQuest.claustrophobicInfernoRaids[1].zone:addArea({ x = 33985, y = 31053, z = 9 }, { x = 34045, y = 31077, z = 9 }) -SoulWarQuest.claustrophobicInfernoRaids[2].zone:addArea({ x = 33988, y = 31042, z = 10 }, { x = 34043, y = 31068, z = 10 }) -SoulWarQuest.claustrophobicInfernoRaids[3].zone:addArea({ x = 33987, y = 31043, z = 11 }, { x = 34044, y = 31076, z = 11 }) +-- Initialize claustrophobic inferno raid zones and add remove destination --- Add remove destination - -SoulWarQuest.claustrophobicInfernoRaids[1].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[1].exitPosition) -SoulWarQuest.claustrophobicInfernoRaids[2].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[2].exitPosition) -SoulWarQuest.claustrophobicInfernoRaids[3].zone:setRemoveDestination(SoulWarQuest.claustrophobicInfernoRaids[3].exitPosition) +for _, raid in ipairs(SoulWarQuest.claustrophobicInfernoRaids) do + local zone = raid.getZone() + zone:addArea(raid.zoneArea[1], raid.zoneArea[2]) + zone:setRemoveDestination(raid.exitPosition) +end -- Initialize bosses access for taint check SoulWarQuest.areaZones.claustrophobicInferno:addArea({ x = 33982, y = 30981, z = 9 }, { x = 34051, y = 31110, z = 11 }) From c6201322be14b468d5b521d44edcbaa37649dda4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 26 May 2024 20:11:27 +0000 Subject: [PATCH 25/31] Lua code format - (Stylua) --- .../moveevent-claustrophobic-inferno-raid.lua | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua index 4f0cac5a3f0..0502d53e365 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-claustrophobic-inferno-raid.lua @@ -10,19 +10,21 @@ for raidNumber, raid in ipairs(SoulWarQuest.claustrophobicInfernoRaids) do local raidName = string.format("Claustrophobic Inferno Raid %d", raidNumber) local encounter = Encounter(raidName, { zone = raid.getZone(), - timeToSpawnMonsters = "3s" + timeToSpawnMonsters = "3s", }) - local spawnTimes = (SoulWarQuest.claustrophobicInfernoRaids.suriviveTime) / SoulWarQuest.claustrophobicInfernoRaids.spawnTime + local spawnTimes = SoulWarQuest.claustrophobicInfernoRaids.suriviveTime / SoulWarQuest.claustrophobicInfernoRaids.spawnTime -- Registering encounter stages for i = 1, spawnTimes do - encounter:addSpawnMonsters({ - { - name = spawnMonsterName, - positions = raid.spawns - }, - }):autoAdvance(SoulWarQuest.claustrophobicInfernoRaids.spawnTime * 1000) + encounter + :addSpawnMonsters({ + { + name = spawnMonsterName, + positions = raid.spawns, + }, + }) + :autoAdvance(SoulWarQuest.claustrophobicInfernoRaids.spawnTime * 1000) end function encounter:onReset(position) From 94cee38450d62d74055e0872a6ad9e6264e51faa Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 20:47:19 -0300 Subject: [PATCH 26/31] fix: goshnar's malice damage white tiles and add zones --- .../scripts/quests/soul_war/moveevent-soul_war_entrances.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua index 0d2bd4fffec..ccf56ea6a3b 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua @@ -67,7 +67,7 @@ function soul_war_megalomania_entrance.onStepIn(creature, item, position, fromPo local text = "" local soulWarCount = 0 - for bossName, completed in pairs(SoulWarQuest.miniBosses) do + for bossName, completed in pairs(SoulWarBosses) do if soulWarQuest:get(bossName) == completed then soulWarCount = soulWarCount + 1 else @@ -88,6 +88,9 @@ soul_war_megalomania_entrance:position({ x = 33611, y = 31430, z = 10 }) soul_war_megalomania_entrance:register() local claustrophobicInfernoTeleportPositions = { + [Position(34013, 31049, 9)] = Position(34014, 31058, 9), + [Position(34010, 31073, 10)] = Position(34012, 31063, 10), + [Position(34009, 31038, 11)] = Position(34012, 31047, 11), [Position(34022, 31091, 11)] = Position(33685, 31599, 14), } From c6c8b272265fd034a78d0b51902e4e8413534ef4 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:27:31 -0300 Subject: [PATCH 27/31] fix: ebb and flow fixed map --- .../quest/soul_war/ebb_and_flow/ebb-flow.otbm | Bin 181546 -> 181554 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm b/data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm index b8ba1414d09e6bdea0cf36d80dfe9f1b39ab8e17..7fbac6bb391d7259a4e6c818564a58b83570a320 100644 GIT binary patch delta 120 zcmZ40#l5MEd&0Jj=TEgTvrJ6gJhN5YfHhkJ#N4#?wmMj>_wH;~Fhk>Ul^2MyeUUEX wUsW(`elTN;0hp!S!dM^&W=&qim@ExuecQ_ztqo=czGS?i4`yjfGBK_J0A%DXV*mgE delta 100 zcmV-q0Gt1^iVLcW3y`)JL;ynv{sp7`{{9A?2MC0OEqMt4|NpVG&4jaqg%>aa=YzAK zwc97NechV{vm4`jO1GFT0sSSnm{S3SFt;Cs0dO9-lA-})8@Kqq0b47#R_OuQFSjun G0s*XBbuFy` From 10eba9719d696fd5d74c73f4539e232ee9fd6137 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 10 Apr 2024 22:48:04 -0300 Subject: [PATCH 28/31] fix: simplify some functions, logs to trace and map fixes --- .../quest/soul_war/ebb_and_flow/ebb-flow.otbm | Bin 181554 -> 181546 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm b/data-otservbr-global/world/quest/soul_war/ebb_and_flow/ebb-flow.otbm index 7fbac6bb391d7259a4e6c818564a58b83570a320..b8ba1414d09e6bdea0cf36d80dfe9f1b39ab8e17 100644 GIT binary patch delta 100 zcmV-q0Gt1^iVLcW3y`)JL;ynv{sp7`{{9A?2MC0OEqMt4|NpVG&4jaqg%>aa=YzAK zwc97NechV{vm4`jO1GFT0sSSnm{S3SFt;Cs0dO9-lA-})8@Kqq0b47#R_OuQFSjun G0s*XBbuFy` delta 120 zcmZ40#l5MEd&0Jj=TEgTvrJ6gJhN5YfHhkJ#N4#?wmMj>_wH;~Fhk>Ul^2MyeUUEX wUsW(`elTN;0hp!S!dM^&W=&qim@ExuecQ_ztqo=czGS?i4`yjfGBK_J0A%DXV*mgE From cdbf439d8dc38302cf36851bf55e59efa3629619 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Thu, 11 Apr 2024 14:42:18 -0300 Subject: [PATCH 29/31] fix: miniBosses table --- .../scripts/quests/soul_war/moveevent-soul_war_entrances.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua index ccf56ea6a3b..a6792315882 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua @@ -67,7 +67,7 @@ function soul_war_megalomania_entrance.onStepIn(creature, item, position, fromPo local text = "" local soulWarCount = 0 - for bossName, completed in pairs(SoulWarBosses) do + for bossName, completed in pairs(SoulWarQuest.miniBosses) do if soulWarQuest:get(bossName) == completed then soulWarCount = soulWarCount + 1 else From 1aefe43b7dd7e342eccdc20a5f4aa277b53c2977 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 12 May 2024 02:36:22 -0300 Subject: [PATCH 30/31] fix: mechanics and npc flickering soul changes: - Added taints removal with words "taints" and "penalties" to npc flickering soul - Fixed soul war mechanics that should not be applied when in safe places (before hunt teleport) - Removed bag you desire as loot of soul war monsters --- .../scripts/quests/soul_war/eventcallback_on_combat_taint.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 3e5ec34f930..936ab8502aa 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) From ce39480cd04a25db4b41bc063df65e8f9a6060bd Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 26 May 2024 17:10:01 -0300 Subject: [PATCH 31/31] improvement: claustrophobic inferno raids and safe zones --- .../scripts/quests/soul_war/eventcallback_on_combat_taint.lua | 2 +- .../scripts/quests/soul_war/moveevent-soul_war_entrances.lua | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua index 936ab8502aa..3e5ec34f930 100644 --- a/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua +++ b/data-otservbr-global/scripts/quests/soul_war/eventcallback_on_combat_taint.lua @@ -111,7 +111,7 @@ function callback.playerOnThink(player, interval) if accumulatedTime[playerId] >= 10000 then local soulWarQuest = player:soulWarQuestKV() - if player:getSoulWarZoneMonster() ~= nil and not player:isInSafeZone() and player:getTaintNameByNumber(5) ~= nil then + if player:getSoulWarZoneMonster() ~= nil and player:getTaintNameByNumber(5) ~= nil then local hpLoss = math.ceil(player:getHealth() * 0.1) local manaLoss = math.ceil(player:getMana() * 0.1) player:addHealth(-hpLoss) diff --git a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua index a6792315882..0d2bd4fffec 100644 --- a/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua +++ b/data-otservbr-global/scripts/quests/soul_war/moveevent-soul_war_entrances.lua @@ -88,9 +88,6 @@ soul_war_megalomania_entrance:position({ x = 33611, y = 31430, z = 10 }) soul_war_megalomania_entrance:register() local claustrophobicInfernoTeleportPositions = { - [Position(34013, 31049, 9)] = Position(34014, 31058, 9), - [Position(34010, 31073, 10)] = Position(34012, 31063, 10), - [Position(34009, 31038, 11)] = Position(34012, 31047, 11), [Position(34022, 31091, 11)] = Position(33685, 31599, 14), }