-- How Many Spirals?
-- A level for Enigma
--
-- Copyright (c) 2005 Nat Pryce
-- Licensed under the GPL version 2.

Require("levels/lib/natmaze.lua")
randomseed( enigma.GetTicks() )


send_message = SendMessage

function send_message_to_group( group, message, arg )
    for i = 1, getn(group) do
        send_message( group[i], message, arg )
    end
end

function group_message( group, message )
    return function(arg)
        send_message_to_group( group, message, arg )
    end
end

set_oxyd = oxyd

function oxyd( x, y, tiles )
    return set_oxyd( x, y )
end

function nothing(x, y, tiles)
    -- create nothing
end

function horizontal_bolder(x,y,tiles)
    if random() >= 0.5 then
        return set_stone( "st-bolder-w", x, y )
    else
    	return set_stone( "st-bolder-e", x, y )
    end
end

function vertical_bolder(x,y,tiles)
    if random() >= 0.5 then
        return set_stone( "st-bolder-n", x, y )
    else
    	return set_stone( "st-bolder-s", x, y )
    end
end

function checkerboard_floor( type1, type2, attribs1, attribs2 )
    return function( x, y, tiles )
        if mod(x,2) == mod(y,2) then
            return set_floor( type1, x, y, attribs1 or {} )
        else
            return set_floor( type2, x, y, attribs2 or {} )
        end
    end
end

function floor( floor_type, attribs )
    return function( x, y, tiles )
        return set_floor( floor_type, x, y, attribs or {} )
    end
end

function stone( stone_type, attribs )
    return function( x, y, tiles )
        return set_stone( stone_type, x, y, attribs or {} )
    end
end

function item( item_type, attribs )
    return function( x, y, tiles )
        return set_item( item_type, x, y, attribs or {} )
    end
end

function actor( actor_type, attribs )
    return function( x, y, tiles )
        return set_actor( actor_type, x+0.5, y+0.5, attribs or {} )
    end
end

function gradient( gradient_type )
    return function( x, y, tiles )
        return set_floor( "fl-gradient", x, y, {type=gradient_type} )
    end
end

function inherit(tile_type)
    return function( x, y, tiles )
        return create_tile( tiles, x, y, tile_type )
    end
end

function group( array, constructor )
    return function( x, y, tiles )
        object = constructor( x, y, tiles )
    	tinsert( array, object )
    	return object
    end
end

function difficulty( d, constructor )
    if options.Difficulty == d then
    	return constructor
    else
    	return nothing
    end
end

function create_world_from_map( tiles, map )
    create_world( strlen(map[1]), getn(map) )
    
    for y = 1,getn(map) do
        local line = map[y]
        for x = 1,strlen(line) do
            local tile = strchar(strbyte(line,x))
            create_tile( tiles, x-1, y-1, tile )
        end
    end
end

function create_tile( tiles, x, y, tile_type )
    local constructors = tiles[tile_type]

    if constructors then
	for i = 1,getn(constructors) do
	    constructors[i](x,y,tiles)
	end
    else
	error("invalid tile identifier " .. tile )
    end
end

oxyd_default_flavor = "a"

dark_floor = floor("fl-leavesb")
light_floor = floor("fl-leaves")

doors_a = {}
doors_b = {}
doors_c = {}
doors_f = {}
lasers = {}

openclose_doors_a = group_message(doors_a, "openclose")
openclose_doors_b = group_message(doors_b, "openclose")
openclose_doors_c = group_message(doors_c, "openclose")
open_doors_f = group_message(doors_f, "open")
toggle_lasers = group_message(lasers, "onoff")


tiles = {}
tiles[" "] = {light_floor }
tiles["/"] = {floor("fl-leavesc1")}
tiles["("] = {floor("fl-leavesc2")}
tiles["`"] = {floor("fl-leavesc3")}
tiles[","] = {floor("fl-leavesc4")}
tiles["."] = {dark_floor}
tiles[";"] = {floor("fl-normal")}
tiles["+"] = {dark_floor, stone("st-grate1")}
tiles["#"] = {dark_floor, stone("st-rock2")}
tiles["-"] = {dark_floor, stone("st-rock2_hole")}
tiles["%"] = {light_floor, stone("st-rock3_hole")}
tiles["="] = {light_floor, stone("st-rock3")}
tiles["x"] = {light_floor, stone("st-rock3_break")}
tiles["*"] = {light_floor, oxyd}
tiles["e"] = {dark_floor, stone("st-laser", {on=TRUE,dir=EAST})}
tiles["w"] = {dark_floor, stone("st-laser", {on=TRUE,dir=WEST})}
tiles["n"] = {dark_floor, stone("st-laser", {on=TRUE,dir=NORTH})}
tiles["s"] = {dark_floor, stone("st-laser", {on=TRUE,dir=SOUTH})}
tiles["H"] = {light_floor, difficulty(HARD,horizontal_bolder)}
tiles["V"] = {light_floor, difficulty(HARD,vertical_bolder)}
tiles["h"] = {light_floor, horizontal_bolder}
tiles["v"] = {light_floor, vertical_bolder}
tiles["~"] = {floor("fl-water")}
tiles["}"] = {floor("fl-water"), stone("st-grate1")}
tiles["o"] = {light_floor, stone("st-wood")}
tiles["@"] = {light_floor, item("it-wormhole", {targetx=28.5,targety=18.5,range=1})}
tiles["u"] = {gradient(FLAT_FORCE_N)}
tiles["d"] = {gradient(FLAT_FORCE_S)}
tiles["l"] = {gradient(FLAT_FORCE_W)}
tiles["r"] = {gradient(FLAT_FORCE_E)}
tiles["U"] = {gradient(FLAT_FORCE_N), actor("ac-killerball", {controllers=0})}
tiles["D"] = {gradient(FLAT_FORCE_S), actor("ac-killerball", {controllers=0})}
tiles["L"] = {gradient(FLAT_FORCE_W), actor("ac-killerball", {controllers=0})}
tiles["R"] = {gradient(FLAT_FORCE_E), actor("ac-killerball", {controllers=0})}
tiles["J"] = {floor("fl-wood")}

tiles["A"] = {dark_floor, stone("st-coinslot",{action="callback",target="openclose_doors_a"})}
tiles["a"] = {dark_floor, group(doors_a, stone("st-door_b"))}
tiles["B"] = {light_floor, stone("st-switch",{action="callback",target="openclose_doors_b"})}
tiles["b"] = {light_floor, group(doors_b, stone("st-door_b"))}
tiles["C"] = {light_floor, stone("st-switch", {action="onoff", target="laser"})}
tiles["c"] = {dark_floor, stone("st-laser", {name="laser", on=FALSE,dir=EAST})}
tiles["F"] = {light_floor, item("it-trigger", {action="callback", target="open_doors_f"})}
tiles["f"] = {light_floor, group(doors_f, stone("st-door_b"))}

tiles["1"] = {inherit("%"), item("it-wormhole", {targetx=45.5, targety=31.5,range=1})}
tiles["2"] = {inherit("%"), item("it-coin1")}
tiles["3"] = {inherit("%"), item("it-wormhole", {targetx=29.5,targety=18.5,range=1})}
tiles["4"] = {inherit("x"), item("it-spring2")}
tiles["5"] = {floor("fl-gray"), item("it-seed")}
tiles["6"] = {inherit("x"), item("it-coin1")}
tiles["7"] = {inherit("%"), item("it-extinguisher")}


tiles["maze_wall"] = { stone("st-grate1") }


create_world_from_map( tiles, {
"##########################################################",
"#;;;;;;;;;;;;;;;;;;#..................-.....=~~~~~~~.....#",
"#;==============%=;#./              `.#.....a..~...~./ `.#",
"#;=%%%%%%%%%%%%=%=;#. xxxxxxxxxxxxxx .#.....=~.~.~.~. B .#",
"#;=%==========%=%=;#. x*xxx4xx6xxx*x .#.....=~.~.~.~.( ,.#",
"#;=%=%%%%%%%7=%=%=;#. xxxxxxxxxxxxxx .#.....=~.~.~.~.....#",
"#;=%=%========%=%=;#.(              ,.#.....=~.~.~.~.....#",
"#;=%=%=1%%%%%%%=%=;#..................#.....=~.~.~.~.....#",
"#;=%=%==========%=;#..................#.....=~.~.~.~.....#",
"#;=%=%%%%%%%%%%%%=;#..................#.....A~.~.~.~.....#",
"#;=%==============;#..................#.....=~...~.......#",
"#;;;;;;;;;;;;;;;;;;#..................#.....=~~~~~~~.....#",
"####-###############++++++++++++++++++####################",
"#*#~ +++++++++++++++e................s+..................#",
"# #~ +o           o+./      H       `.+..................#",
"# #~ +             +.       h        .+...../   `........#",
"# #~ +             +.       H        .+..... =f= ........#",
"# #~ +             +.       H        .+..... =*= ........#",
"#~~~~~             +.V v V V  V V v V.+..... C=c         #",
"# #~ +             +.        H       .+..... =*= ........#",
"# #~ +             +.        H       .+..... =f= ........#",
"# #~ +             +.        h       .+.....(   ,........#",
"# #~ +o           o+.(       H      ,.+..................#",
"#*#~ +++++++++++++++n................w+..................#",
"####################++++++++++++++++++####################",
"#~                 -..................#;;;;;;;;;;;;;;;;;;#",
"#~       }}}}}}}}}~#..................#;==============%=;#",
"#~       }DddlllL}~#..................#;=%%%%%%%%%%%%=%=;#",
"#}RrrrddD}dddllll}~#e................w#;=%==========%=%=;#",
"#}rrrrddd}dddllll}~#..................#;=%=%%%%%%%3=%=%=;#",
"#}rrrrddd}ddd5uuu}~#./              `.#;=%=%========%=%=;#",
"#}uuuFddd}rrrruuu}~#. ============== .#;=%=%=2%%%%%%%=%=;#",
"#}uuullll}rrrruuu}~#. b*==========*b .#;=%=%==========%=;#",
"#}uuullll}RrrruuU}~#. ============== .#;=%=%%%%%%%%%%%%=;#",
"#}UuulllL}       ~~#.(              ,.#;=%==============;#",
"#}}}}}}}}}       ~~-..................#;;;;;;;;;;;;;;;;;;#",
"##########################################################"
})

render_maze( new_kruskal_maze(7,5), 
    function(maze,cellx,celly)
	local x = 6 + cellx*2 
	local y = 14 + celly*2

        if not maze:can_go_east(cellx,celly) and maze:contains_cell(cellx+1,celly) then
            create_tile( tiles, x+1, y, "maze_wall" )
        end
        
        if not maze:can_go_south(cellx,celly) and maze:contains_cell(cellx,celly+1) then
            create_tile( tiles, x, y+1, "maze_wall" )
        end
	
	if maze:contains_cell(cellx+1,celly+1) then
            create_tile( tiles, x+1, y+1, "maze_wall" )
        end
    end )


startx = level_width/2
starty = level_height/2
set_actor( "ac-blackball", startx, starty, {player=0} )

oxyd_shuffle()















