diff --git a/data-otservbr-global/lib/core/storages.lua b/data-otservbr-global/lib/core/storages.lua index 69f1d7f7948..7b29268b2fe 100644 --- a/data-otservbr-global/lib/core/storages.lua +++ b/data-otservbr-global/lib/core/storages.lua @@ -3097,6 +3097,9 @@ GlobalStorage = { Yasir = 65014, IceCrack = 65016, UglyMonster = 65017, + FacelessBaneStepsOn = 65018, + FacelessBaneDeaths = 65019, + FacelessBaneResetSteps = 65020, KeysUpdate = 40000, -- Reserved storage from 40000 - 40000 } diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/faceless_bane.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/faceless_bane.lua index e4d8553c46a..d4720495edd 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/faceless_bane.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/faceless_bane.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Faceless Bane") local monster = {} monster.description = "Faceless Bane" -monster.experience = 30000 +monster.experience = 20000 monster.outfit = { lookType = 1119, lookHead = 0, @@ -22,7 +22,11 @@ monster.manaCost = 0 monster.changeTarget = { interval = 4000, - chance = 10, + chance = 20, +} + +monster.reflects = { + { type = COMBAT_DEATHDAMAGE, percent = 90 }, } monster.bosstiary = { @@ -131,11 +135,7 @@ monster.elements = { { type = COMBAT_DROWNDAMAGE, percent = 0 }, { type = COMBAT_ICEDAMAGE, percent = 0 }, { type = COMBAT_HOLYDAMAGE, percent = 0 }, - { type = COMBAT_DEATHDAMAGE, percent = 99 }, -} - -monster.heals = { - { type = COMBAT_DEATHDAMAGE, percent = 100 }, + { type = COMBAT_DEATHDAMAGE, percent = 50 }, } monster.immunities = { @@ -149,6 +149,11 @@ mType.onThink = function(monster, interval) end mType.onAppear = function(monster, creature) if monster:getType():isRewardBoss() then + -- reset global storage state to default / ensure sqm's reset for the next team + Game.setStorageValue(GlobalStorage.FacelessBaneDeaths, -1) + Game.setStorageValue(GlobalStorage.FacelessBaneStepsOn, -1) + Game.setStorageValue(GlobalStorage.FacelessBaneResetSteps, 1) + monster:registerEvent("facelessBaneImmunity") monster:setReward(true) end end diff --git a/data-otservbr-global/scripts/creaturescripts/monster/faceless_bane_immunity.lua b/data-otservbr-global/scripts/creaturescripts/monster/faceless_bane_immunity.lua new file mode 100644 index 00000000000..43a94756e95 --- /dev/null +++ b/data-otservbr-global/scripts/creaturescripts/monster/faceless_bane_immunity.lua @@ -0,0 +1,51 @@ +local bossName = "Faceless Bane" + +-- reset monster HP to 100% +function healBoss(creature) + creature:addHealth(creature:getMaxHealth()) + creature:getPosition():sendMagicEffect(CONST_ME_BLOCKHIT) + return true +end + +-- summon spectres +function createSummons(pos) + Game.createMonster("Gazer Spectre", pos) + Game.createMonster("Ripper Spectre", pos) + Game.createMonster("Burster Spectre", pos) + return true +end + +-- reset the monster HP and summon spectres upon death +function resetBoss(creature, deaths) + healBoss(creature) + createSummons(creature:getPosition()) + Game.setStorageValue(GlobalStorage.FacelessBaneDeaths, deaths + 1) + Game.setStorageValue(GlobalStorage.FacelessBaneStepsOn, 0) + Game.setStorageValue(GlobalStorage.FacelessBaneResetSteps, 1) + return true +end + +local facelessBaneImmunity = CreatureEvent("facelessBaneImmunity") + +-- ensure that the boss stay invulnerable when the mechanic has not been executed +function facelessBaneImmunity.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType) + if creature and creature:isMonster() and creature:getName() == bossName then + local creatureHealthPercent = (creature:getHealth() * 100) / creature:getMaxHealth() + local facelessBaneDeathsStorage = Game.getStorageValue(GlobalStorage.FacelessBaneDeaths) + + if creatureHealthPercent <= 20 and facelessBaneDeathsStorage < 1 then + resetBoss(creature, facelessBaneDeathsStorage) + return true + end + + if Game.getStorageValue(GlobalStorage.FacelessBaneStepsOn) < 1 then + healBoss(creature) + return true + else + return primaryDamage, primaryType, secondaryDamage, secondaryType + end + end + return true +end + +facelessBaneImmunity:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/the_dream_courts/faceless_bane_step_positions.lua b/data-otservbr-global/scripts/creaturescripts/quests/the_dream_courts/faceless_bane_step_positions.lua new file mode 100644 index 00000000000..ae810047d2e --- /dev/null +++ b/data-otservbr-global/scripts/creaturescripts/quests/the_dream_courts/faceless_bane_step_positions.lua @@ -0,0 +1,97 @@ +local walkedPositions = {} + +-- this variable controls the time to boss become immortal again, (after 1 minute, if dont die) +local lastResetTime = os.time() + +-- reset sqm's / make the boss immortal again +local function resetWalkedPositions() + if lastResetTime > os.time() then + return true + end + walkedPositions = {} + Game.setStorageValue(GlobalStorage.FacelessBaneStepsOn, 0) + lastResetTime = os.time() + (1 * 60) +end + +-- energy effect to make the boss mortal +local function sendEnergyEffect() + -- positions: pipes on room, that should be electrocuted + local pipePositions = { + Position(33612, 32568, 13), + Position(33612, 32567, 13), + Position(33612, 32566, 13), + Position(33612, 32565, 13), + Position(33612, 32564, 13), + Position(33612, 32563, 13), + Position(33612, 32562, 13), + Position(33612, 32561, 13), + Position(33612, 32560, 13), + Position(33612, 32559, 13), + Position(33612, 32558, 13), + Position(33612, 32557, 13), + Position(33612, 32556, 13), + Position(33622, 32556, 13), + Position(33622, 32557, 13), + Position(33622, 32558, 13), + Position(33622, 32559, 13), + Position(33622, 32560, 13), + Position(33622, 32561, 13), + Position(33622, 32562, 13), + Position(33622, 32563, 13), + Position(33622, 32564, 13), + Position(33622, 32565, 13), + Position(33622, 32566, 13), + Position(33622, 32567, 13), + Position(33622, 32568, 13), + } + + -- energy effect / sound on pipes + for _, pp in ipairs(pipePositions) do + pp:sendMagicEffect(CONST_ME_PURPLEENERGY) + pp:sendSingleSoundEffect(SOUND_EFFECT_TYPE_SPELL_GREAT_ENERGY_BEAM) + end + + return true +end + +local facelessBaneStepPositions = MoveEvent() + +-- capture steps in the specific SQM's to make the boss mortal +-- +function facelessBaneStepPositions.onStepIn(creature, item, position, fromPosition) + local player = creature:getPlayer() + if not player then + return true + end + + if Game.getStorageValue(GlobalStorage.FacelessBaneResetSteps) == 1 then + Game.setStorageValue(GlobalStorage.FacelessBaneResetSteps, 0) + lastResetTime = os.time() + resetWalkedPositions() + end + + if Game.getStorageValue(GlobalStorage.FacelessBaneStepsOn) < 1 then + if #walkedPositions > 0 then + for _, walkedPos in ipairs(walkedPositions) do + if walkedPos == position then + return true + end + end + end + + position:sendSingleSoundEffect(SOUND_EFFECT_TYPE_SPELL_BUZZ) + position:sendMagicEffect(CONST_ME_YELLOWENERGY) + table.insert(walkedPositions, position) + + if #walkedPositions == 13 then + Game.setStorageValue(GlobalStorage.FacelessBaneStepsOn, 1) + addEvent(resetWalkedPositions, 60 * 1000) + sendEnergyEffect() + end + end + return true +end + +-- positions: SQM's to step +facelessBaneStepPositions:position(Position(33615, 32567, 13), Position(33613, 32567, 13), Position(33611, 32563, 13), Position(33610, 32561, 13), Position(33611, 32558, 13), Position(33614, 32557, 13), Position(33617, 32558, 13), Position(33620, 32557, 13), Position(33623, 32558, 13), Position(33624, 32561, 13), Position(33623, 32563, 13), Position(33621, 32567, 13), Position(33619, 32567, 13)) +facelessBaneStepPositions:register()