• 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!

Lua Chain Reaction Bomberman System

kotz

New Member
Joined
Nov 11, 2010
Messages
17
Reaction score
1
Hi Guys i have a problem here.

if the player drop two or more bombs in same line, the bombs explodes two or more blocks like your lv of radious:

post-87502-0-21259800-1452189331.jpg
- >
post-87502-0-64111500-1452189331.jpg
like this...

This the code of broke blocks and start event again to chain reaction:


elseif block.itemid ~= 0 and isInArray(blocks, block.itemid) then
doSendMagicEffect(_pos, CONST_ME_BLOCKHIT)
doRemoveItem(getTileThingByPos(_pos).uid, 1)
local r = math.random(20)
if r < 4 then
doCreateItem(r==1 and 2153 or r==2 and 2154 or r==3 and 2155, 1, _pos)
end
return false
end
elseif getTileItemById(_pos, t.bombID).uid > 0 and getTileItemById(_pos, t.bombID).uid > 0 then
addEvent(boom, nil, getThingPos(getTileItemById(_pos, t.bombID).uid), cid)

i think this problem is caused by call event again, and no have more block then, he broke the next block.

Help me guys please ;\
 
First, why are you using addEvent with nil as delay? Second, what do you mean by chain reaction? Does the bomb's explosion sets off other bombs?

When you place two bombs in the same square it's only logical that they break two blocks (as long as they have the range to do so) because the first bomb explodes slightly earlier than the second one. If you want to "group" explosions so that two bombs placed in slightly different times won't destroy two blocks, I suggest you change the way you are doing things.

Create a function that will scan the map every "turn" searching for bombs that should explode when the turn ends, then you check which blocks each bomb should destroy, without destroying them now, simply mark them for destruction later. When you finish looping through all the bombs that should explode, you should have a list of blocks "marked" for destruction that you should now remove.

Assuming you are using an older TFS version, you can add an attribute to the bombs - "turns", for example, that counts down the bomb's lifespan. You can then decrease this counter every turn and whenever it reaches zero, that bomb should explode.
 
You are correctly "Does the bomb's explosion sets off other bombs".
But, the bombs explodes with delay of addEvent, i don't have idea how i'll make this function to scan line of the bomb explode ;\

The nil in add event is only test... kk
 
ye:

Code:
local function boom(pos, cid)
    local v = getTileItemById(pos, t.bombID).uid
    if v > 0 then
    if isPlayer(cid) and isInRange(getThingPos(cid), t.from, t.to) then
        setPlayerStorageValue(cid, t.storage.placed, getPlayerStorageValue(cid, t.storage.placed) - 1)
        doSendMagicEffect(pos, t.effect)
        local c = getTopCreature(pos).uid
        if isPlayer(c) and isInRange(getThingPos(c), t.from, t.to) then
            doSendMagicEffect(pos, 17)
            doTeleportThing(c, t.temple)
            doSendMagicEffect(t.temple, 10)
            local n1, n2 = getPlayerName(c), getPlayerName(cid)
            doBroadcastMessage(n1==n2 and n1 .. " killed " .. (getPlayerSex(c) == 0 and "her" or "him") .. "self!" or n1 .. " was killed by " .. n2 .. "!", MESSAGE_STATUS_WARNING)
        end
     
        local N, E, W, S, l = 1, 1, 1, 1, getPlayerStorageValue(cid, t.storage.radius)
        function loopDir(dir)
            local _pos = {x=pos.x+(dir=="E" and E or dir=="W" and -W or 0), y=pos.y+(dir=="N" and -N or dir=="S" and S or 0), z=pos.z, stackpos = 1}
            local block = getTileThingByPos(_pos)
            if queryTileAddThing(v, _pos, 4) == RETURNVALUE_NOERROR or isInArray(blocks, block.itemid) and v > 1 then
                doSendMagicEffect(_pos, t.effect)
                local c = getTopCreature(_pos).uid
                if isPlayer(c) and isInRange(getThingPos(c), t.from, t.to) then
                    doSendMagicEffect(_pos, 17)
                    doTeleportThing(c, t.temple)
                    doSendMagicEffect(t.temple, 10)
                    local n1, n2 = getPlayerName(c), getPlayerName(cid)
                    doBroadcastMessage(n1==n2 and n1 .. " killed " .. (getPlayerSex(c) == 0 and "her" or "him") .. "self!" or n1 .. " was killed by " .. n2 .. "!", MESSAGE_STATUS_WARNING)
                elseif isMonster(c) and isInRange(getThingPos(c), t.from, t.to) then
                   doSendMagicEffect(_pos, 2)
                   doRemoveCreature(c)
                elseif block.itemid ~= 0 and isInArray(blocks, block.itemid) then
                   doSendMagicEffect(_pos, CONST_ME_BLOCKHIT)
                   doRemoveItem(getTileThingByPos(_pos).uid, 1)
                local r = math.random(20)
                 if r < 4 then
                 doCreateItem(r==1 and 2153 or r==2 and 2154 or r==3 and 2155, 1, _pos)
                 end
                return false
                end
            elseif getTileItemById(_pos, t.bombID).uid > 0 and getTileItemById(_pos, t.bombID).uid > 0 then
                addEvent(boom, 1, getThingPos(getTileItemById(_pos, t.bombID).uid), cid)
           elseif queryTileAddThing(v, _pos, 4) == 3  then
            return false
            end
            return true
        end
        while N <= l do
            local q = loopDir("N")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                N = N + 1
            end
        end
        while E <= l do
            local q = loopDir("E")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                E = E + 1
            end
        end
        while W <= l do
            local q = loopDir("W")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                W = W + 1
            end
        end
        while S <= l do
            local q = loopDir("S")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                S = S + 1
            end
        end
    end
    doRemoveItem(v, 1)
            end
end
 
Last edited:
Take a look at this code, keep in mind that I can't test it right now so there might be some bugs:

Code:
local function doPlaceBomb(cid, bombId, position, turns)
    local item = doCreateitem(bombId, position)
    if item.uid ~= 0 then
        doItemSetAttribute(item.uid, "turns", turns)
        doItemSetAttribute(item.uid, "owner", cid)
        return true
    end
    return false
end

local function doExplosion(config, owner, position)
    doSendMagicEffect(position, config.effect)

    local cid = getTopCreature(position).uid
    if isPlayer(cid) then
        doSendMagicEffect(position, 17)
        doTeleportThing(cid, config.temple)
        doSendMagicEffect(config.temple, 10)

        local n1, n2 = getPlayerName(owner), getPlayerName(cid)
        doBroadcastMessage(n1 == n2 and (n1 .. " killed " .. (getPlayerSex(cid) == 0 and "her" or "him") .. "self!") or (n1 .. " was killed by " .. n2 .. "!"), MESSAGE_STATUS_WARNING)
    elseif isMonster(c) then
        doSendMagicEffect(position, 2)
        doRemoveCreature(cid)
    end

    local block = getTileThingByPos(position)
    if isInArray(config.blocks, block.itemid) then
        doSendMagicEffect(position, CONST_ME_BLOCKHIT)
        doRemoveItem(block.uid, 1)
        if math.random(100) <= config.powerChance then
            doCreateItem(config.powers[math.random(#config.powers)], 1, position)
        end
    end
end

local directions = {
    { 0, -1}, -- NORTH
    { 1,  0}, -- EAST
    { 0,  1}, -- SOUTH ,
    {-1,  0}, -- WEST 
}

local function onTurn(config)
    local explosions = {}

    for x = config.map.x, config.map.x + config.map.w do
        for y = config.map.y, config.map.y + config.map.h do
            local position = {x = x, y = y, z = config.map.z}
            local item = getTileItemById(position, config.bombId)
            if item.uid ~= 0 then
                local turns = getItemAttribute(item.uid, "turns")
                if turns == 1 then
                    local owner = getItemAttribute(item.uid, "owner")
                    local range = getPlayerStorageValue(owner, config.storage.radius)

                    table.insert(explosions, {position = position, owner = owner})
                    for _, offset in ipairs(directions) do
                        for n = 1, range do
                            local pos = {x = position.x + n * offset[1], y = position.y + n * offset[2], z = position.z}
                            if queryTileAddThing(item.uid, position, 4) == RETURNVALUE_NOTENOUGHROOM then
                                break
                            end
                            table.insert(explosions, {position = pos, owner = owner})
                        end
                    end

                    doRemoveItem(item.uid, 1)
                else
                    doItemSetAttribute(item.uid, "turns", turns - 1)
                end
            end
        end
    end

    for _, info in ipairs(explosion) do
        doExplosion(config, info.owner, info.position)
    end
end

Place the bombs using doPlaceBomb(cid, bombId, position, turns) and whenever you want to start the game:

Code:
local config = {
    map = {
        x = 0, w = 0, -- leftmost X coordinate and map width
        y = 0, h = 0, -- topmost Y coordinate and map height
        z = 0, -- Z coordinate
    },

    storage = {
        radius = 0, -- radius storage key
    },

    powers = {2153, 2154, 2155},
    powerChance = 15, -- percent chance of a block dropping a random power up

    effect = 0, -- explosion effect

    blocks = {0}, -- blocks that can be exploded

    temple = {x = 0, y = 0, z = 0}, -- position the player gets teleported to when he dies

    bombId = 0,

    turn = 500, -- turn time (in milliseconds)

}

function step(config)
    onTurn(config)
    addEvent(step, config.turn, config)
end

step(config)
 
how i can call this function? placeBombs?
i try like this:


Code:
function onSay(cid, words, param, channel)
local b = getTileItemById(getThingPos(cid), t.bombID).uid
if b > 1 then
return false
else
setPlayerStorageValue(cid, t.storage.placed, math.max(getPlayerStorageValue(cid, t.storage.placed), 0))
setPlayerStorageValue(cid, t.storage.max, math.max(getPlayerStorageValue(cid, t.storage.max), 1))
setPlayerStorageValue(cid, t.storage.radius, math.max(getPlayerStorageValue(cid, t.storage.radius), 1))
if getPlayerStorageValue(cid, t.storage.placed) < getPlayerStorageValue(cid, t.storage.max) then
doPlaceBomb(cid, t.bombID, getThingPos(cid), t.delay)
setPlayerStorageValue(cid, t.storage.placed, getPlayerStorageValue(cid, t.storage.placed) + 1)

end
return true
end
end

doCreateitem a mistake in write, i fixed this part
 
Last edited:
I can't use this:

Code:
for x = config.map.x, config.map.x + config.map.w do
        for y = config.map.y, config.map.y + config.map.h do
            local position = {x = x, y = y, z = config.map.z}

Is not a event, is a server, all map the players can drop bombs '-'
Run of time....kkk
 
Nothing Happens:


Code:
local config = {
    map = {
        x = 1002, w = 1012, -- leftmost X coordinate and map width
        y = 1027, h = 1018, -- topmost Y coordinate and map height
        z = 7, -- Z coordinate
    },

    storage = {
        radius = 10003, -- radius storage key
    },

    powers = {2153, 2154, 2155},
    powerChance = 15, -- percent chance of a block dropping a random power up

    effect = CONST_ME_FIREAREA, -- explosion effect

    blocks = {435, 387, 388, 389}, -- blocks that can be exploded

    temple =  {x = 1009, y = 1017, z = 7}, -- position the player gets teleported to when he dies

    bombId = 386,

    turn = 1, -- turn time (in milliseconds)

}

function step(config)
    onTurn(config)
    addEvent(step, config.turn, config)
end

local function doPlaceBomb(cid, bombId, position, turns)
doCreateItem(bombId, position)
local item = getTileItemById(position, bombID)
    if item.uid ~= 0 then
        doItemSetAttribute(item.uid, "turns", turns)
        doItemSetAttribute(item.uid, "owner", cid)
        step(config)
        return true
    end
    return false
end

local function doExplosion(config, owner, position)
    doSendMagicEffect(position, config.effect)

    local cid = getTopCreature(position).uid
    if isPlayer(cid) then
        doSendMagicEffect(position, 17)
        doTeleportThing(cid, config.temple)
        doSendMagicEffect(config.temple, 10)

        local n1, n2 = getPlayerName(owner), getPlayerName(cid)
        doBroadcastMessage(n1 == n2 and (n1 .. " killed " .. (getPlayerSex(cid) == 0 and "her" or "him") .. "self!") or (n1 .. " was killed by " .. n2 .. "!"), MESSAGE_STATUS_WARNING)
    elseif isMonster(c) then
        doSendMagicEffect(position, 2)
        doRemoveCreature(cid)
    end

    local block = getTileThingByPos(position)
    if isInArray(config.blocks, block.itemid) then
        doSendMagicEffect(position, CONST_ME_BLOCKHIT)
        doRemoveItem(block.uid, 1)
        if math.random(100) <= config.powerChance then
            doCreateItem(config.powers[math.random(#config.powers)], 1, position)
        end
    end
end

local directions = {
    { 0, -1}, -- NORTH
    { 1,  0}, -- EAST
    { 0,  1}, -- SOUTH ,
    {-1,  0}, -- WEST
}

local function onTurn(config)
    local explosions = {}

    for x = config.map.x, config.map.x + config.map.w do
        for y = config.map.y, config.map.y + config.map.h do
            local position = {x = x, y = y, z = config.map.z}
            local item = getTileItemById(position, config.bombId)
            if item.uid ~= 0 then
                local turns = getItemAttribute(item.uid, "turns")
                if turns == 1 then
                    local owner = getItemAttribute(item.uid, "owner")
                    local range = getPlayerStorageValue(owner, config.storage.radius)

                    table.insert(explosions, {position = position, owner = owner})
                    for _, offset in ipairs(directions) do
                        for n = 1, range do
                            local pos = {x = position.x + n * offset[1], y = position.y + n * offset[2], z = position.z}
                            if queryTileAddThing(item.uid, position, 4) == RETURNVALUE_NOTENOUGHROOM then
                                break
                            end
                            table.insert(explosions, {position = pos, owner = owner})
                        end
                    end

                    doRemoveItem(item.uid, 1)
                else
                    doItemSetAttribute(item.uid, "turns", turns - 1)
                end
            end
        end
    end

    for _, info in ipairs(explosion) do
        doExplosion(config, info.owner, info.position)
    end
end

function onSay(cid, words, param, channel)
doPlaceBomb(cid, config.bombId, getThingPos(cid), config.turn)
return true
end
 
You need to call step(config) once to start it.
And by the way, 1 millisecond as turn time is way too fast, you should use something over 500.
 
Bro i don't did with your code Thx :(

this all my code,
if you have a way to did it in my code ;\.


Code:
local t = {
from = {x=1, y=1, z=7},
to = {x=2905, y=2525, z=7},
storage = {placed = 10001, max = 10002, radius = 10003, speed = 10004},
delay = 4000, bombID = 386, effect = CONST_ME_FIREAREA, blockID = 435,
temple = {x = 1009, y = 1017, z = 7},
}   

local blocks = {435, 387, 388, 389}       

local function doExplosion(pos, cid)
    local v = getTileItemById(pos, t.bombID).uid
    if v > 0 then
    if isPlayer(cid) and isInRange(getThingPos(cid), t.from, t.to) then
        setPlayerStorageValue(cid, t.storage.placed, getPlayerStorageValue(cid, t.storage.placed) - 1)
        doSendMagicEffect(pos, t.effect)
        local c = getTopCreature(pos).uid
        if isPlayer(c) and isInRange(getThingPos(c), t.from, t.to) then
            doSendMagicEffect(pos, 17)
            doTeleportThing(c, t.temple)
            doSendMagicEffect(t.temple, 10)
            local n1, n2 = getPlayerName(c), getPlayerName(cid)
            doBroadcastMessage(n1==n2 and n1 .. " killed " .. (getPlayerSex(c) == 0 and "her" or "him") .. "self!" or n1 .. " was killed by " .. n2 .. "!", MESSAGE_STATUS_WARNING)
        end
       
        local N, E, W, S, l = 1, 1, 1, 1, getPlayerStorageValue(cid, t.storage.radius)
       
        function loopDir(dir)
            local _pos = {x=pos.x+(dir=="E" and E or dir=="W" and -W or 0), y=pos.y+(dir=="N" and -N or dir=="S" and S or 0), z=pos.z, stackpos = 1}
            local block = getTileThingByPos(_pos)
            local c = getTopCreature(_pos).uid
            if queryTileAddThing(v, _pos, 4) == RETURNVALUE_NOERROR then
              doSendMagicEffect(_pos, t.effect)
              if isPlayer(c) and v > 1 and isInRange(getThingPos(c), t.from, t.to) then
                doSendMagicEffect(_pos, 17)
                doTeleportThing(c, t.temple)
                doSendMagicEffect(t.temple, 10)
                local n1, n2 = getPlayerName(c), getPlayerName(cid)
                doBroadcastMessage(n1==n2 and n1 .. " killed " .. (getPlayerSex(c) == 0 and "her" or "him") .. "self!" or n1 .. " was killed by " .. n2 .. "!", MESSAGE_STATUS_WARNING)
              elseif isMonster(c) and v > 1 and isInRange(getThingPos(c), t.from, t.to) then
                doSendMagicEffect(_pos, 2)
                doRemoveCreature(c)
              end
            elseif queryTileAddThing(v, _pos, 4) == RETURNVALUE_NOERROR or getTileItemById(_pos, t.bombID).uid > 0 then
             addEvent(doExplosion, 1, getThingPos(getTileItemById(_pos, t.bombID).uid), cid)
            elseif queryTileAddThing(v, _pos, 4) == RETURNVALUE_NOERROR or isInArray(blocks, block.itemid) and v > 1 and block.itemid ~= 0 then
             doSendMagicEffect(_pos, CONST_ME_BLOCKHIT)
             doRemoveItem(getTileThingByPos(_pos).uid, 1)
              local r = math.random(20)
               if r < 4 then
                doCreateItem(r==1 and 2153 or r==2 and 2154 or r==3 and 2155, 1, _pos)
               end
             return false
            else--if queryTileAddThing(v, _pos, 4) == 3  then
         return false
        end
        return true
        end
       
        while N <= l do
            local q = loopDir("N")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                N = N + 1
            end
        end
        while E <= l do
            local q = loopDir("E")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                E = E + 1
            end
        end
        while W <= l do
            local q = loopDir("W")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                W = W + 1
            end
        end
        while S <= l do
            local q = loopDir("S")
            if q == "endgame" then
                return doRemoveItem(v, 1)
            elseif not q then
                break
            else
                S = S + 1
            end
        end
    end
    doRemoveItem(v, 1)
end
end
       
function onSay(cid, words, param, channel)
local b = getTileItemById(getThingPos(cid), t.bombID).uid
if b > 1 then
return true
else
setPlayerStorageValue(cid, t.storage.placed, math.max(getPlayerStorageValue(cid, t.storage.placed), 0))
setPlayerStorageValue(cid, t.storage.max, math.max(getPlayerStorageValue(cid, t.storage.max), 1))
setPlayerStorageValue(cid, t.storage.radius, math.max(getPlayerStorageValue(cid, t.storage.radius), 1))
if getPlayerStorageValue(cid, t.storage.placed) < getPlayerStorageValue(cid, t.storage.max) then
doCreateItem(t.bombID, 1, getThingPos(cid))
addEvent(doExplosion, t.delay, getThingPos(cid), cid)
setPlayerStorageValue(cid, t.storage.placed, getPlayerStorageValue(cid, t.storage.placed) + 1)

end
return true
end
end
 
Back
Top