Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: faceless bane mechanics and quest #2466

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions data-otservbr-global/lib/core/storages.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3097,6 +3097,9 @@ GlobalStorage = {
Yasir = 65014,
IceCrack = 65016,
UglyMonster = 65017,
FacelessBaneStepsOn = 65018,
FacelessBaneDeaths = 65019,
FacelessBaneResetSteps = 65020,
KeysUpdate = 40000, -- Reserved storage from 40000 - 40000
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -22,7 +22,11 @@ monster.manaCost = 0

monster.changeTarget = {
interval = 4000,
chance = 10,
chance = 20,
}

monster.reflects = {
{ type = COMBAT_DEATHDAMAGE, percent = 90 },
}

monster.bosstiary = {
Expand Down Expand Up @@ -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 = {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not that it will make a big difference, but if you leave the positions inside the function they will be related every time you call the function, I would leave them outside the function

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()
Loading