-- Flood Gates
-- A level for Enigma
-- Copyright (c) 2002 Nat Pryce
-- License: GPL v2.0 or above


level = {
"##########################~############$",
"#::::::::::::::::::::::::A~#::::::::::# ",
"#:#########################b::::::::::# ",
"#::::::::::::::::::::::::::B::::::*:::# ",
"###:#######################a::::::::::# ",
"#  :  ~~~~~~~~~~~~~~~~~~~~~#::::::::::# ",
"#  :  ====~~~=====~~~==    c########### ",
"###:####~=~~~=~~~=~~~=~# ###::::::::::# ",
"#::::::#~=====~~~=====~# #:=========2:# ",
"#::::::#~~~~~~~~~~~~~~~# #:=::::::::::# ",
"#::::::################# #:====:=====:# ",
"#::::::C:::::::::::::::# #::::=:=:::=:# ",
"#D####################:# #:====:=:===:# ",
"#:#::::::::::::::::::#:# #:=::::=:=:::# ",
"#:#:fff::::::::::::::#-# #:======:===:# ",
"#:#:f2f::::::::::::::&%& #::::::::::=:# ",
"#:#:fff::::::::::::::#-#+###########&-# ",
"#:#::::::::::::::::::#:::::::::::::-%-# ",
"#:####F############# ### ###########&## ",
"#:d1#~~~==           #3#              # ",
"#:###~~~=~############g#############+## ",
"#:#~~~~~=~# :::::::::::#ih :::::::::::# ",
"#:#~===~=~# :         :### :         :# ",
"#:#~=~=~=~# : :::::::::#   :   ::::: :# ",
"#:#~=~=~=~# : :  #######   :###I###: :# ",
"e:e~=~=~=~# : : :: + ::::  :#4:::5#: :# ",
"e:e~=~=~=~# : : :# # #  :  :#:::::#: :# ",
"e:e~=~=~=~# : : :# # #  :  :#::3::#: :# ",
"e:e~=~=~=~# : :::# # #  :  :#:::::#: :# ",
"e:e~=~=~=~# :    #+#+#  :  :#5:::4#: :# ",
"e:e~=~===~# :::::^:+:^:::  :#######: :# ",
"e:E~=~~~~~#      #:::#     ::::::::: :# ",
"#:## ##############G#################H# ",
"#:   #1:::::::::::::::::::::::::::::::@ ",
"#:###################################:# ",
"#:::::::::::::::::::::::::::::::::::::@ ",
"####################################### ",
}

channels = {} -- cells along which water can flow
flows = {}    -- cells onto which water will flow next tick
doors = {}    -- mapping from door names to cell identifiers

-- what can be on a channel cell
WATER = 0
CHANNEL = 1
BRIDGE = 2
GATE = 3


function set_channel( x, y, type )
    set_channel_cell( cell(x,y), type )
end

function set_channel_cell( cell, type )
    channels[cell] = type
end

function canal( x, y )
    set_floor( "fl-rough", x, y )
    set_channel( x, y, CHANNEL )
end

function water( x, y )
    set_floor( "fl-water", x, y )
    set_channel( x, y, WATER )
end

function gate_v( x, y, name )
    canal( x, y )
    doorv( x, y, {name=name} )
    
    cell_id = cell(x,y)
    doors[name] = cell_id
    set_channel( x, y, GATE )
end

function gate_h( x, y, name )
    canal( x, y )
    doorh( x, y, {name=name} )
    
    cell_id = cell(x,y)
    doors[name] = cell_id
    set_channel( x, y, GATE )
end

function open_lockgate( name )
    send_message( name, "open" )
    set_channel_cell( doors[name], CHANNEL )
    if is_next_to_water( doors[name] ) then
        tinsert( flows, doors[name] )
    end
end

function lockgate_type( name, factory_func )
    local gate_type = strupper(name)
    local switch_type = strlower(name)
    local callback_name = "open_gate_" .. gate_type
    local callback = function()
        open_lockgate( %gate_type )
    end
    
    setglobal( callback_name, callback )
    types[gate_type] = function( x, y )
        %factory_func( x, y, %gate_type )
    end
end

function switch_type( name )
    local gate_type = strupper(name)
    local switch_type = strlower(name)
    local callback_name = "open_gate_" .. gate_type
    
    types[switch_type] = function( x, y )
        set_stone( "st-switch", x, y,
                  {action="callback", target=%callback_name} )
    end
end

function trigger_type( name )
    local gate_type = strupper(name)
    local switch_type = strlower(name)
    local callback_name = "open_gate_" .. gate_type
    
    types[switch_type] = function( x, y )
        set_item( "it-trigger", x, y,
                  {action="callback", target=%callback_name} )
    end
end

function tick()
    local new_flows = {}
    
    for i,flow in flows do
        channel_type = channels[flow]
        if can_flow( flow ) then
            if channels[flow] == CHANNEL then
               set_floor( "fl-water", cell_x(flow), cell_y(flow) )
            end
            tinsert( new_flows, north(flow) )
            tinsert( new_flows, south(flow) )
            tinsert( new_flows, east(flow) )
            tinsert( new_flows, west(flow) )
            channels[flow] = WATER
        end
     end
     
     flows = new_flows
end

function can_flow( flow )
    return channels[flow] == CHANNEL or channels[flow] == BRIDGE
end

function is_next_to_water( cell )
    return channels[north(cell)] == WATER
        or channels[south(cell)] == WATER
        or channels[west(cell)] == WATER
        or channels[east(cell)] == WATER
end

function cell( x, y )
    return y * level_width + x
end

function cell_x( id )
    return mod( id, level_width )
end
function cell_y( id )
    return (id - cell_x(id)) / level_width
end

function cell_str( id )
    return "" .. id
end

function north( id )
    return id - level_width
end

function south( id )
    return id + level_width
end

function west( id )
    return id - 1
end

function east( id )
    return id + 1
end

function send_message( obj_name, message )
    --print( "sending message " .. message .. " to " .. obj_name )
    obj = enigma.GetNamedObject( obj_name )
    enigma.SendMessage( obj, message, nil )
end

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

types = {}
types[" "] = function( x, y )
   -- just the default floor
end
types["-"] = function( x, y )
    canal(x,y)
    set_stone( "st-invisible", x, y )
end
types[":"] = function( x, y )
    canal( x, y )
end
types["~"] = function( x, y )
    water( x, y )
end
types["@"] = function( x, y )
    set_floor( "fl-abyss",  x, y )
    set_stone( "st-grate1", x, y )
end
types["#"] = function( x, y )
    set_stone( "st-greenbrown", x, y )
end
types["="] = function( x, y )
    set_floor( "fl-normal", x, y )
    set_channel( x, y, BRIDGE )
end
types["^"] = function( x, y )
    canal( x, y )
    set_stone( "st-grate1", x, y )
end
types["&"] = function( x, y )
    set_floor( "fl-normal", x, y )
    set_stone( "st-grate1", x, y )
end
types["%"] = function( x, y )
    set_floor( "fl-normal", x, y )
    set_stone( "st-grate1", x, y )
    set_channel( x, y, BRIDGE )
end
types["*"] = function( x, y )
    set_floor( "fl-normal", x, y )
    set_actor( "ac-blackball", x+0.5, y+0.5, {player=0} )
end
types["+"] = function( x, y )
    set_stone( "st-wood", x, y )
end
types["x"] = function( x, y )
    canal( x, y )
    set_stone( "st-wood", x, y )
end
types["$"] = function( x, y )
    set_stone( "st-timer", x, y,
               {interval=0.1, action="callback", target="tick"} )
end
lockgate_type( "A", gate_v )
switch_type( "a" )
lockgate_type( "B", gate_v )
switch_type( "b" )
lockgate_type( "C", gate_v )
switch_type( "c" )
lockgate_type( "D", gate_h )
trigger_type( "d" )
lockgate_type(  "E", gate_v )
switch_type( "e" )
lockgate_type( "F", gate_h )
trigger_type( "f" )
lockgate_type( "G", gate_h )
trigger_type( "g" )
lockgate_type( "H", gate_h )
trigger_type( "h" )
lockgate_type( "I", gate_h )
switch_type( "i" )

for color=0,9 do
    types[""..color] = function( x, y )
        set_stone( "st-oxyd", x, y, {flavor="a", color=""..%color} )
    end
end


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

create_world( strlen(level[1]), getn(level) )
fill_floor( "fl-leaves", 0, 0, level_width, level_height )
for y,line in level do
    for x = 1,strlen(line) do
        type = strchar(strbyte(line,x))
        types[type]( x-1, y-1 )
    end
end
