• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

1.3 8.6 Spawn boss

denkan97

Well-Known Member
Joined
Dec 27, 2011
Messages
327
Solutions
2
Reaction score
50
Hello, i found this code here on otland made by: Snavy

Lua:
--[[
    [+] = done
    [-] = not done

    [+] random spawn location
    [+] lost hp% mob/item spawn
    [+] spawn items + monsters on death & start next spawn countdown
    [-] DPS
]]
local config = {

    SPAWN_AREAS = {
        {
            TOP_LEFT     = Position(1082, 1048, 7),
            BOTTOM_RIGHT = Position(1095, 1056, 7)
        }
    },

    BOSS_NAME = 'cyclops smith',

    -- How long after death should the boss respawn?
    SPAWN_INTERVAL = 5, -- seconds

    -- Item rewards
    MIN_REWARD_AMOUNT = 1,
    MAX_REWARD_AMOUNT = 3,
    REWARDS = {
        {2160,  1},
        {2159,  2},
        {8976,  1},
        {13537, 1},
        {2148,  5},
        {2135,  1}
    },

    -- What the boss will spawn
    SUMMONS = { 'rat', 'orc', 'troll', 'bear', 'wolf', 'snake', 'larva' },

    -- Minimum and maximum amount of mobs to be spawned.
    MIN_SUMMON_AMOUNT = 1,
    MAX_SUMMON_AMOUNT = 5,

    -- What will be created everytime a certain HP% is reached.
    SPAWN_CHOICE_ITEMS = 1,
    SPAWN_CHOICE_MOBS  = 2,
    SPAWN_CHOICE_BOTH  = 3,

    -- Radius to top-left & to bottom-right from boss position.
    SPAWN_OBJECT_RADIUS = 3
}

local DAMAGE_REWARD_CONFIG = {
    [1] = { hpPercent = 10 },
    [2] = { hpPercent = 30 },
    [3] = { hpPercent = 60 },
    [4] = { hpPercent = 90 }
}
------------------------------------------------------------------------------------
---------------------------------[  GLOBALEVENT  ]----------------------------------
------------------------------------------------------------------------------------
local function spawnLootBoss()
    local area = config.SPAWN_AREAS[math.random(1, #config.SPAWN_AREAS)]
    local spawnPos = Position(
        math.random(area.TOP_LEFT.x, area.BOTTOM_RIGHT.x),
        math.random(area.TOP_LEFT.y, area.BOTTOM_RIGHT.y),
        area.TOP_LEFT.z
    )
    Game.createMonster(config.BOSS_NAME, spawnPos, false, true)
    Game.broadcastMessage('The vicious boss '.. config.BOSS_NAME ..' has risen from the dead', MESSAGE_EVENT_ADVANCE)
    REWARDS_COLLECTED = {}
end

local lootBoss = GlobalEvent('lootBoss')
function lootBoss.onStartup()
    spawnLootBoss()
    return true
end
lootBoss:register()
------------------------------------------------------------------------------------
-------------------------------[  CREATURESCRIPTS  ]--------------------------------
------------------------------------------------------------------------------------
local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.mod(s, 3600)/60)
    local seconds = math.floor(math.mod(s, 60))
    return (hours   > 0 and (hours   .. ' hour'   .. (hours   > 1 and 's ' or ' ')) or '') ..
           (minutes > 0 and (minutes .. ' minute' .. (minutes > 1 and 's ' or ' ')) or '') ..
           (seconds > 0 and (seconds .. ' second' .. (seconds > 1 and 's ' or ' ')) or '')
end

local function getClosestFreeTile(pos, radius)
    for y = pos.y - radius, pos.y + radius do
        for x = pos.x - radius, pos.x + radius do
            local tile = Tile(x, y, pos.z)
            if tile and tile:isWalkable() then
                return Position(x, y, pos.z)
            end
        end
    end
    return nil
end

local function spawnItem(spawnObjectArea)
    local reward_idx = math.random(1, #config.REWARDS)
    local reward_item_pos = Position(
        math.random(spawnObjectArea.TOP_LEFT.x, spawnObjectArea.BOTTOM_RIGHT.x),
        math.random(spawnObjectArea.TOP_LEFT.y, spawnObjectArea.BOTTOM_RIGHT.y),
        spawnObjectArea.TOP_LEFT.z
    )

    local tile = Tile(reward_item_pos)
    if (not tile) or (not tile:isWalkable()) then
        reward_item_pos = getClosestFreeTile(reward_item_pos, 1)
    end

    if not reward_item_pos then
        return
    end

    Game.createItem(config.REWARDS[reward_idx][1], config.REWARDS[reward_idx][2], reward_item_pos)
    reward_item_pos:sendMagicEffect(CONST_ME_MAGIC_BLUE)
end

local function spawnMob(spawnObjectArea)
    local mob_pos = Position(
        math.random(spawnObjectArea.TOP_LEFT.x, spawnObjectArea.BOTTOM_RIGHT.x),
        math.random(spawnObjectArea.TOP_LEFT.y, spawnObjectArea.BOTTOM_RIGHT.y),
        spawnObjectArea.TOP_LEFT.z
    )

    local tile = Tile(mob_pos)
    if (not tile) or (not tile:isWalkable()) then
        mob_pos = getClosestFreeTile(mob_pos, 1)
    end

    if not mob_pos then
        return
    end

    Game.createMonster(config.SUMMONS[math.random(1, #config.SUMMONS)], mob_pos, true, true)
    mob_pos:sendMagicEffect(CONST_ME_MAGIC_BLUE)
end

------------------------------------------------------------------------------------

REWARDS_COLLECTED = {}
local lootBoss_ce = CreatureEvent('lootBossCE')
function lootBoss_ce.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    local hpAfterDmg = creature:getHealth() - (primaryDamage + secondaryDamage)
    local hpDiffPercent = math.floor((creature:getMaxHealth() - hpAfterDmg) * 100 / creature:getMaxHealth())
    local bossPos = creature:getPosition()

    for i = #DAMAGE_REWARD_CONFIG, 1, -1 do
        local f = (function(hpPercent)
        ----------------------------------------
        if hpDiffPercent < hpPercent then
            return false
        end

        if REWARDS_COLLECTED[i] then
            return false
        end

        REWARDS_COLLECTED[i] = 1

        local spawnObjectArea = {
            TOP_LEFT = Position(
                bossPos.x - config.SPAWN_OBJECT_RADIUS,
                bossPos.y - config.SPAWN_OBJECT_RADIUS,
                bossPos.z
            ),

            BOTTOM_RIGHT = Position(
                bossPos.x + config.SPAWN_OBJECT_RADIUS,
                bossPos.y + config.SPAWN_OBJECT_RADIUS,
                bossPos.z
            ),
        }

        local spawnChoice = math.random(config.SPAWN_CHOICE_ITEMS, config.SPAWN_CHOICE_BOTH)
        if spawnChoice == config.SPAWN_CHOICE_ITEMS then
            for ix = config.MIN_REWARD_AMOUNT, config.MAX_REWARD_AMOUNT do
                spawnItem(spawnObjectArea)
            end
            return true
        end

        if spawnChoice == config.SPAWN_CHOICE_MOBS then
            for ix = config.MIN_REWARD_AMOUNT, config.MAX_REWARD_AMOUNT do
                spawnMob(spawnObjectArea)
            end
            return true
        end

        if spawnChoice == config.SPAWN_CHOICE_BOTH then
            for ix = config.MIN_REWARD_AMOUNT, config.MAX_SUMMON_AMOUNT do
                spawnChoice = math.random(config.SPAWN_CHOICE_ITEMS, config.SPAWN_CHOICE_MOBS)
                if spawnChoice == config.SPAWN_CHOICE_ITEMS then
                    spawnItem(spawnObjectArea)
                else
                    spawnMob(spawnObjectArea)
                end
            end
            return true
        end
        ----------------------------------------
        end)(DAMAGE_REWARD_CONFIG[i].hpPercent)
        if f then break end
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end
lootBoss_ce:register()

local lootBossDeath = CreatureEvent('lootBossDeath')
function lootBossDeath.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    REWARDS_COLLECTED = {}

    local bossPos = creature:getPosition()
    local spawnObjectArea = {
        TOP_LEFT = Position(
            bossPos.x - config.SPAWN_OBJECT_RADIUS,
            bossPos.y - config.SPAWN_OBJECT_RADIUS,
            bossPos.z
        ),

        BOTTOM_RIGHT = Position(
            bossPos.x + config.SPAWN_OBJECT_RADIUS,
            bossPos.y + config.SPAWN_OBJECT_RADIUS,
            bossPos.z
        ),
    }

    for i = config.MIN_REWARD_AMOUNT, config.MAX_REWARD_AMOUNT * 2 do
        spawnItem(spawnObjectArea)
    end

    Game.broadcastMessage(creature:getName() .. ' has been killed. Next spawn in ' .. secondsToReadable(config.SPAWN_INTERVAL), MESSAGE_EVENT_ADVANCE)
    addEvent(spawnLootBoss, config.SPAWN_INTERVAL * 1000)
    return true
end
lootBossDeath:register()

And the problem is that when someone kill the boss it doesn't check if the tile is free to spawn on.
So sometimes it spawn in walls, stones, on water and in mountains
 
Change the function spawnLootBoss to:

Lua:
local function spawnLootBoss()
  local area = config.SPAWN_AREAS[math.random(1, #config.SPAWN_AREAS)]
  local spawnPos = Position(
      math.random(area.TOP_LEFT.x, area.BOTTOM_RIGHT.x),
      math.random(area.TOP_LEFT.y, area.BOTTOM_RIGHT.y),
      area.TOP_LEFT.z
  )
  for i=1, 100 do
    if spawnPos:isWalkable() then
      break
    else
      spawnPos = Position(
        math.random(area.TOP_LEFT.x, area.BOTTOM_RIGHT.x),
        math.random(area.TOP_LEFT.y, area.BOTTOM_RIGHT.y),
        area.TOP_LEFT.z
      )
    end
  end
  Game.createMonster(config.BOSS_NAME, spawnPos, false, true)
  Game.broadcastMessage('The vicious boss '.. config.BOSS_NAME ..' has risen from the dead', MESSAGE_EVENT_ADVANCE)
  REWARDS_COLLECTED = {}
end
 
Change the function spawnLootBoss to:

Lua:
local function spawnLootBoss()
  local area = config.SPAWN_AREAS[math.random(1, #config.SPAWN_AREAS)]
  local spawnPos = Position(
      math.random(area.TOP_LEFT.x, area.BOTTOM_RIGHT.x),
      math.random(area.TOP_LEFT.y, area.BOTTOM_RIGHT.y),
      area.TOP_LEFT.z
  )
  for i=1, 100 do
    if spawnPos:isWalkable() then
      break
    else
      spawnPos = Position(
        math.random(area.TOP_LEFT.x, area.BOTTOM_RIGHT.x),
        math.random(area.TOP_LEFT.y, area.BOTTOM_RIGHT.y),
        area.TOP_LEFT.z
      )
    end
  end
  Game.createMonster(config.BOSS_NAME, spawnPos, false, true)
  Game.broadcastMessage('The vicious boss '.. config.BOSS_NAME ..' has risen from the dead', MESSAGE_EVENT_ADVANCE)
  REWARDS_COLLECTED = {}
end

Thx for the answer but got an error.
And accidentally put the wrong tfs on description its 1.4

Lua:
Lua Script Error: [Scripts Interface]
C:\Users\denkan\Desktop\TFS-1.4-Downgrades-8.60\data\scripts\bosses\lootboss.lua:callback
...TFS-1.4-Downgrades-8.60\data\scripts\bosses\lootboss.lua:69: attempt to call method 'isWalkable' (a nil value)
stack traceback:
        [C]: in function 'isWalkable'
        ...TFS-1.4-Downgrades-8.60\data\scripts\bosses\lootboss.lua:69: in function 'spawnLootBoss'
        ...TFS-1.4-Downgrades-8.60\data\scripts\bosses\lootboss.lua:86: in function <...TFS-1.4-Downgrades-8.60\data\scripts\bosses\lootboss.lua:85>
 
It's a Tile function, not a Position function, which is why you're getting a nil value error.

function Tile.isWalkable(self)
 
Back
Top