-- Lever map and position
local levermap = {
{1, 2, 0, 5, 6},
{3, 4, 0, 7, 8},
{0, 0, 0, 0, 0},
{9, 10, 0, 13, 14},
{11, 12, 0, 15, 16},
}
local mappos = Position(115, 361, 6)
local nlevers = 16
-- Rock pos
local rocks = {
[1] = {id = 1354, pos = Position(124, 359, 6)},
[2] = {id = 1355, pos = Position(124, 361, 6)},
[3] = {id = 1354, pos = Position(124, 363, 6)},
[4] = {id = 1355, pos = Position(124, 365, 6)},
[5] = {id = 1354, pos = Position(124, 367, 6)},
}
-- Lever states
local leverstates = {
[0] = 1945,
[1] = 1946,
}
local transform = {
[9825] = 9826,
[9826] = 9825,
}
-- Tokens pos
local tokens = {
[1] = Position(126, 360, 6),
[2] = Position(127, 360, 6),
[3] = Position(128, 360, 6),
[4] = Position(127, 361, 6),
[5] = Position(128, 361, 6),
[6] = Position(127, 364, 6),
[7] = Position(128, 364, 6),
[8] = Position(126, 365, 6),
[9] = Position(127, 365, 6),
[10] = Position(128, 365, 6),
}
local tokenid = 2625
-- Safe pos
local safepos = Position(124, 358, 6)
-- Time to restore
local restoretime = 30 -- seconds
-- Reset combination after restore
local reset = true
-- Delay between uses
local delay = 2 -- seconds
-- functions
function setLeverStates()
if not LEVER_STATES then
LEVER_STATES = {}
local tmp = {}
for i = 1, 4 do
LEVER_STATES[i] = {}
for x = 1, math.random(2, 4) do
local rd = math.random(1, 16)
while tmp[rd] do
rd = math.random(1, 16)
end
tmp[rd] = true
LEVER_STATES[i][rd] = math.random(0, 1)
end
end
end
end
function removeToken(tokens)
for i = 1, #tokens do
local tile = Tile(tokens[i])
if tile then
local token = tile:getItemById(tokenid)
if token then
token:getPosition():sendMagicEffect(CONST_ME_POFF)
token:remove()
return true
end
end
end
return false
end
function teleportPlayers(rocks, safepos)
local startpos = rocks[1].pos
local endpos = rocks[#rocks].pos
for y = startpos.y, endpos.y do
for x = startpos.x, endpos.x do
local tile = Tile(x, y, startpos.z)
if tile then
local creatures = tile:getCreatures()
if creatures and #creatures > 0 then
for i = 1, #creatures do
if creatures[i]:isPlayer() then
creatures[i]:teleportTo(safepos)
end
end
end
end
end
end
end
function getCurrentStone(rocks)
for i = 1, #rocks do
local tile = Tile(rocks[i].pos)
local item = tile:getItemById(rocks[i].id)
if item then
return item, i
end
end
return false
end
function getMissingStones(rocks)
local ret = {}
for i = 1, #rocks do
local tile = Tile(rocks[i].pos)
local item = tile:getItemById(rocks[i].id)
if not item then
table.insert(ret, rocks[i])
end
end
return ret
end
function Tile:removeItems()
local items = self:getItems()
for i = 1, #items do
items[i]:remove()
end
end
function getLeverPosition(map, mappos, id)
for y = 1, #map do
for x = 1, #map[1] do
if map[y][x] == id then
return Position(mappos.x+x-1, mappos.y+y-1, mappos.z)
end
end
end
print("Warning - Lever id " .. id .. " not found.")
return false
end
function restorePuzzle(map, mappos, rocks, tokens, safepos, reset)
teleportPlayers(rocks, safepos)
if reset then
LEVER_STATES = nil
end
for i = 1, #rocks do
local tile = Tile(rocks[i].pos)
tile:removeItems()
Game.createItem(rocks[i].id, 1, rocks[i].pos)
end
for i = 1, #tokens do
local tile = Tile(tokens[i])
if tile then
tile:removeItems()
Game.createItem(tokenid, 1, tokens[i])
end
end
for y = 1, #map do
for x = 1, #map[1] do
if map[y][x] > 0 then
local tile = Tile(mappos.x+x-1, mappos.y+y-1, mappos.z)
local lever = tile:getItemById(1945) or tile:getItemById(1946)
if lever then
lever:transform(leverstates[0])
else
print("Warning - Map or mappos is wrong.")
end
end
end
end
end
function restoreRandomRock(rocks, safepos)
local missingstones = getMissingStones(rocks)
if #missingstones > 0 then
local rd = math.random(1, #missingstones)
Game.createItem(missingstones[rd].id, 1, missingstones[rd].pos)
teleportPlayers(rocks, safepos)
end
end
function randomizeLevers(map, mappos)
for y = 1, #map do
for x = 1, #map[1] do
if map[y][x] > 0 then
local tile = Tile(mappos.x+x-1, mappos.y+y-1, mappos.z)
local lever = tile:getItemById(1945) or tile:getItemById(1946)
if lever then
lever:transform(leverstates[math.random(0, 1)])
else
print("Warning - Map or mappos is wrong.")
end
end
end
end
end
function combinationStr()
local ret = ""
if LEVER_STATES then
for stoneid, states in ipairs(LEVER_STATES) do
local str = ""
for lever, state in pairs(states) do
str = string.format("%s %d - %d,", str, lever, state)
end
str = str:sub(1, #str-1)
ret = ret .. string.format("Stone %d:%s\n", stoneid, str)
end
end
return "\n" .. ret:sub(1, #ret-1)
end
local lastuse = 0
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
local itemid = item:getId()
if lastuse+delay > os.time() then
fromPosition:sendMagicEffect(CONST_ME_POFF)
return player:sendCancelMessage("You are exhausted.")
end
if transform[itemid] then
lastuse = os.time()
setLeverStates()
local curstone, stoneid = getCurrentStone(rocks)
if curstone then
if player:getGroup():getAccess() and player:getAccountType() >= ACCOUNT_TYPE_GOD then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, combinationStr())
end
if stoneid < 5 then
local curstates = LEVER_STATES[stoneid]
local fail = false
for id, state in pairs(curstates) do
local pos = getLeverPosition(levermap, mappos, id)
local tile = Tile(pos)
if tile then
local leveritem = tile:getItemById(leverstates[state])
if not leveritem then
fail = true
break
end
else
return print("Warning - Invalid map or mappos.")
end
end
if not fail then
curstone:remove()
else
curstone:getPosition():sendMagicEffect(CONST_ME_POFF)
fromPosition:sendMagicEffect(CONST_ME_POFF)
local ret = removeToken(tokens)
if not ret then
restorePuzzle(levermap, mappos, rocks, tokens, safepos)
elseif stoneid > 1 then
restoreRandomRock(rocks, safepos)
end
end
elseif stoneid == 5 then
local fail = false
for sid, states in ipairs(LEVER_STATES) do
for id, state in pairs(states) do
local pos = getLeverPosition(levermap, mappos, id)
local tile = Tile(pos)
if tile then
local leveritem = tile:getItemById(leverstates[state == 0 and 1 or 0])
if not leveritem then
fail = true
break
end
else
return print("Warning - Invalid map or mappos.")
end
end
end
if not fail then
curstone:remove()
addEvent(restorePuzzle, restoretime*1000, levermap, mappos, rocks, tokens, safepos, reset)
else
curstone:getPosition():sendMagicEffect(CONST_ME_POFF)
fromPosition:sendMagicEffect(CONST_ME_POFF)
local ret = removeToken(tokens)
if not ret then
restorePuzzle(levermap, mappos, rocks, tokens, safepos)
elseif stoneid > 1 then
restoreRandomRock(rocks, safepos)
end
end
end
randomizeLevers(levermap, mappos)
end
item:transform(transform[itemid])
end
return true
end