-- A level for Enigma -- Name: Enigris -- Filename: ralf04.lua -- Copyright: (C) Mar 2003 Ralf Westram -- Contact: amgine@reallysoft.de -- License: GPL v2.0 or above --warning_raises_error = 1 Require("levels/ralf.lua") -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- floorface = "fl-marble" areafloorface = "fl-sahara" prevfloorface = "fl-bluegray" uncountedface = "st-brick" countedface = "st-glass" wallface = "st-glass" floorcell = cell{floor={face=floorface}} areafloorcell = cell{floor={face=areafloorface}} prevfloorcell = cell{floor={face=prevfloorface}} marble = cell{actor={face="ac-blackball", attr={player=0}, mode=3}} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- level = { "O!!!!!!!!!!!O.......", "%!!!!!!!!!!!%.@@@@@.", "%!!!!!!!!!!!%.@@@@@.", "%!!!!!!!!!!!%.@@@@@.", "%!!!!!!!!!!!%.@@@@@.", "%!!!!!!!!!!!%.@@@@@.", "%!!!!!!!!!!!%...T...", "%!!!!!!!!!!!%.#####.", "%!!!!!!!!!!!%.#1 2#.", "%!!!!!!!!!!!%.# o #.", "%!!!!!!!!!!!%.#3 4#.", "%!!!!!!!!!!!%.##5##.", "L!!!!!!!!!!!L..###..", } cells={} cells["."] = abyss cells["o"] = marble cells["@"] = prevfloorcell cells["!"] = areafloorcell cells["%"] = cell{parent=areafloorcell,stone={face=uncountedface}} cells["L"] = cell{parent=areafloorcell,stone={face="st-laser",attr={on=TRUE, dir=enigma.NORTH,name="soundstone"}}} cells["O"] = cell{parent={areafloorcell,oxyd}} cells[" "] = floorcell cells["#"] = cell{parent=floorcell,stone={face=wallface}} cells["T"] = cell{parent=floorcell,stone={face="st-timer",attr={action="callback", target="tick",interval=0.1}}} cells["1"] = cell{parent=floorcell,item={face="it-trigger",attr={action="callback", target="trigger1"}}} cells["2"] = cell{parent=floorcell,item={face="it-trigger",attr={action="callback", target="trigger2"}}} cells["3"] = cell{parent=floorcell,item={face="it-trigger",attr={action="callback", target="trigger3"}}} cells["4"] = cell{parent=floorcell,item={face="it-trigger",attr={action="callback", target="trigger4"}}} cells["5"] = cell{parent=floorcell,item={face="it-trigger",attr={action="callback", target="trigger5"}}} triggers = 5 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- The drop field: dfieldx,dfieldy = 1,0 dfieldw,dfieldh = 11,13 -- The preview field: pfieldx,pfieldy = 14,0 pfieldw,pfieldh = 5,5 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- The stones: stone1={ "xx", "x ", "x ", } stone2={ "x ", "x ", "xx", } stone3={ "x", "x", "x", "x", } stone4={ "x ", "xx", " x", } stone5={ " x", "xx", "x ", } stone6={ " x ", "xxx", } stone7={ "xx", "xx", } --stone8={ -- " x ", -- "xxx", -- " x ", --} --stone9={ -- " x", -- "xxx", -- "x ", --} --stone10={ -- "x ", -- "xxx", -- " x", --} --stone10={ -- "x ", -- "xxxx", -- "x ", --} stonedef = { stone1, stone2, stone3, stone4, stone5, stone6, stone7, -- stone8, stone9, stone10 } -- list all stones here stoneface = { -- define different faces for the stones "st-brownie", "st-rock5", "st-glass", "st-bluegray", "st-wood_001", "st-rock2", "st-stone_break", "st-fakeoxyd", -- "st-wood", -- "st-brick", -- "st-grate1", -- "st-grate2", } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- randomseed(enigma.GetTicks()) realstonenum = getn(stonedef) -- number of real different stones stonefacenum = getn(stoneface) stonexsize = {} -- calculated below stoneysize = {} -- calculated below -- precalculate sizes of stones for s=1,realstonenum do stonexsize[s],stoneysize[s] = get_map_size(stonedef[s]) end -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- function sound(sound) enigma.EmitSound(enigma.GetNamedObject("soundstone"), sound) end function gen_map(width,height) local map={} for h=1,height do map[h] = strrep(" ",width) end return map end function plot_stone(smap,x,y) local row = smap[y] local nrow = strsub(row,1,x-1).."x"..strsub(row,x+1) smap[y] = nrow end -- generate rotated stones: stonenum = realstonenum*4 -- including rotated stones for s=realstonenum+1,stonenum do local left = s-realstonenum -- index of same stone (rotated leftwards) stonexsize[s],stoneysize[s] = stoneysize[left],stonexsize[left] stonedef[s] = gen_map(stonexsize[s],stoneysize[s]) for y=1,stoneysize[left] do local row = stonedef[left][y] for x=1,stonexsize[left] do if (strsub(row,x,x) == "x") then plot_stone(stonedef[s],stonexsize[s]-y+1,x) end end end end -- plots into a map -- returns 1 if successfull, 0 otherwise -- typ == 0 -> empty (always successfull) -- >= 1 -> number of stoneface function plot_map(tomap,x,y,typ) -- print(format("x=%i y=%i typ=%i",x,y,typ)) local row = tomap[y] if (typ > 0) then local pos = strsub(row,x,x) if (pos >= "1") then return 0 end -- error, pos already used end local nrow = strsub(row,1,x-1) if (typ==0) then nrow = nrow.."-" else nrow = nrow..tostring(typ) end nrow = nrow..strsub(row,x+1) tomap[y] = nrow return 1 end function dump_map(themap) for y,str in themap do print(y,"'",str,"'") end end -- inserts a stone into a map -- returns 1, if stone has been inserted function insert_stone(tomap,x0,y0,stonenr,facenr) local stone = stonedef[stonenr] -- print(format("x=%i y=%i stone=%i face=%i",x0,y0,stonenr,facenr)) for y=1,stoneysize[stonenr] do local idx = y+y0-1 if (idx >= 1) then local srow = stone[y] -- print(format("y=%i srow='%s'",y,srow)) for x=1,stonexsize[stonenr] do local c = strsub(srow,x,x) -- print(format("x=%i y=%i c=%s", x,y,c)) if (c=="x") then local ok = plot_map(tomap,x+x0-1,idx,facenr) if (ok == 0) then -- error occurred -> remove already inserted part local xe,ye = x,y -- error position for y=1,ye do idx = y+y0-1 if (idx >= 1) then local xm = stonexsize[stonenr] if (y==ye) then xm = xe-1 end srow = stone[y] for x=1,xm do if (strsub(srow,x,x)=="x") then plot_map(tomap,x+x0-1,idx,0) end end end end return 0 end end end end end -- dump_map(tomap) return 1 end function remove_stone(frommap,x,y,stonenr) return insert_stone(frommap,x,y,stonenr,0) end function ds(x,y,facenr) set_stone(stoneface[facenr],x,y) end function rs(x,y) enigma.KillStone(x,y) end function skull(x,y) enigma.KillStone(x,y) set_stone("st-death",x,y) sound("shatter"); end function breakout(x,y) enigma.KillStone(x,y) end function nothing(x,y) end -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- display defs for preview and game map dcells={} -- draw dcells[" "] = cell{{nothing}} dcells["-"] = cell{parent={{rs}}} dcells["S"] = cell{parent={{skull}}} dcells["X"] = cell{parent={{breakout}}} for i=1,stonefacenum do dcells[tostring(i)] = cell{parent={{ds,i}}} end pmap = gen_map(pfieldw,pfieldh) dmap = gen_map(dfieldw,dfieldh) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- curr_s = {} -- current stone next_s = {} -- next stone showx = { 3, 3, 2, 2, 1} showy = { 3, 3, 2, 2, 1} broken_lines = {} normalspeed = 10 points = 0 function show_points() local p = points local x1,x2 = 0,(dfieldx+dfieldw) for y=dfieldh-2,1,-1 do enigma.KillStone(x1,y) if (p>0) then set_stone(countedface,x1,y) p = p-1 else set_stone(uncountedface,x1,y) end end for y=dfieldh-2,1,-1 do enigma.KillStone(x2,y) if (p>0) then set_stone(countedface,x2,y) p = p-1 else set_stone(uncountedface,x2,y) end end end function check_breakouts() local oldpoints = points for y,str in dmap do local spacefound = 0 for x=1,dfieldw do local c = strsub(str,x,x) if ((c==" ") or (c=="-")) then spacefound = spacefound+1 end end if (spacefound == 0) then dmap[y] = strrep("X",dfieldw) broken_lines[y] = 1 points = points+1 end end if (oldpoints ~= points) then show_points() if (points ~= 0) then sound("stonetransform"); end end end function fit_broken_lines() local maxy = 99 for y,broken in broken_lines do if (broken == 1) then if (y < maxy) then maxy = y end end end if (maxy ~= 99) then broken_lines[maxy] = 0 for y=maxy-1,1,-1 do dmap[y+1] = dmap[y] end dmap[1] = strrep("-",dfieldw) else broken_lines = {} end end function stone_done(init) if (init==0) then remove_stone(pmap,next_s.x,next_s.y,next_s.stone) curr_s = next_s curr_s.x = random(1,dfieldw-stonexsize[curr_s.stone]+1) curr_s.y = 2-stoneysize[curr_s.stone] end local nr = random(1,stonenum) next_s = { x=showx[stonexsize[nr]], y=showy[stoneysize[nr]], stone=nr,face=random(1,stonefacenum)} check_breakouts() insert_stone(pmap,next_s.x,next_s.y,next_s.stone,next_s.face) draw_map(pfieldx,pfieldy,pmap,dcells) end game_over = 0 -- end of game flag -- triggerState player on perform -- trigger? action? -- 0 NO NO -- 1 YES YES -- 2 NO YES -- 3 YES YES -- -- triggerState changes by player: -- 0 -> 1 step onto trigger -- 1 -> 2 leave trigger (but signal stays valid) -- 2 -> 1 step again onto trigger before signal was received -- 3 -> 0 leave trigger after signal has been received -- -- triggerState changes by tick(): -- 0 -> 0 no trigger -> no action -- 1 -> 3 player on trigger, mark signal as received -- 2 -> 0 player already left trigger, nevertheless perform action -- 3 -> 3 player resting on trigger, perform action as long he rests there -- -- NOTE: odd trigger means: player is on trigger -- even trigger means: player is NOT on trigger triggerState = {} for x=1,triggers do triggerState[x] = 0 end -- reset triggers function trigger(which) -- by player if (triggerState[which]==0) then triggerState[which] = 1 elseif (triggerState[which]==1) then triggerState[which] = 2 elseif (triggerState[which]==2) then triggerState[which] = 1 elseif (triggerState[which]==3) then triggerState[which] = 0 end end function readTrigger(which) -- by tick() local action = 1 if (triggerState[which]==0) then action = 0 elseif (triggerState[which]==1) then triggerState[which] = 3 elseif (triggerState[which]==2) then triggerState[which] = 0 end return action end function trigger1() trigger(1) end -- move left function trigger2() trigger(2) end -- move right function trigger3() trigger(3) end -- turn left function trigger4() trigger(4) end -- turn right function trigger5() trigger(5) end -- drop/restart function end_game() if (game_over == 0) then game_over = 1 for key,str in dmap do dmap[key] = gsub(str,"%d","S") end end end speed = normalspeed ticker = 0 function game_tick(fall) if (game_over == 0) then local stop = 0 if ((curr_s.y + stoneysize[curr_s.stone]-1) >= dfieldh) then stop = 1 else remove_stone(dmap,curr_s.x,curr_s.y,curr_s.stone,curr_s.face) local lastx,lasty,laststone = curr_s.x,curr_s.y,curr_s.stone local next_sound = "" -- move/rotate stone local user_move = 0 if (fall == 1) then curr_s.y = curr_s.y+1 if (speed == 1) then next_sound = "pickup" else next_sound = "movebig" end end fit_broken_lines() if (speed ~= 1) then -- move left if ((readTrigger(1) == 1) and (curr_s.x > 1)) then curr_s.x = curr_s.x-1 user_move = 1 next_sound = "movebig" end -- move right if ((readTrigger(2) == 1) and ((curr_s.x + stonexsize[curr_s.stone]) <= dfieldw)) then curr_s.x = curr_s.x+1 user_move = 1 next_sound = "movebig" end local stoneRotated = 0 -- rotate left if (readTrigger(3) == 1) then curr_s.stone = curr_s.stone - realstonenum if (curr_s.stone < 1) then curr_s.stone = curr_s.stone + stonenum end stoneRotated = 1 next_sound = "mirrorturn" end -- rotate right if (readTrigger(4) == 1) then curr_s.stone = curr_s.stone + realstonenum if (curr_s.stone > stonenum) then curr_s.stone = curr_s.stone - stonenum end stoneRotated = 1 next_sound = "mirrorturn" end -- correct position if stone was rotated if (stoneRotated == 1) then if ((curr_s.x + stonexsize[curr_s.stone] - 1) > dfieldw) then curr_s.x = dfieldw - (stonexsize[curr_s.stone] - 1) end user_move = 1 end -- drop if (readTrigger(5) == 1) then speed = 1 ticker = 0 end end local ok = insert_stone(dmap,curr_s.x,curr_s.y,curr_s.stone,curr_s.face) if ((ok == 0) and (user_move == 1)) then -- try again with user move skipped curr_s.x = lastx curr_s.stone = laststone ok = insert_stone(dmap,curr_s.x,curr_s.y,curr_s.stone,curr_s.face) end if (ok == 0) then -- if error occurred while falling curr_s.x,curr_s.y = lastx,lasty insert_stone(dmap,curr_s.x,curr_s.y,curr_s.stone,curr_s.face) if (curr_s.y <= 1) then -- end of game end_game() else stop = 1 end else if (sound ~= "") then sound(next_sound) end end end if (stop == 1) then stone_done(0) sound("cloth") speed = ceil(normalspeed-(points/3)) insert_stone(dmap,curr_s.x,curr_s.y,curr_s.stone,curr_s.face) end draw_map(dfieldx,dfieldy,dmap,dcells) else if (readTrigger(5) == 1) then -- restart game game_over = 0 points = 0 show_points() local line = strrep("-", dfieldw) for y,str in dmap do dmap[y] = line end stone_done(0) draw_map(dfieldx,dfieldy,dmap,dcells) end end end function tick() ticker = ticker+1 local xmove1 = floor(speed/3) local xmove2 = floor(speed/3*2) if (ticker == speed) then game_tick(1) ticker = 0 else if ((ticker == xmove1) or (ticker == xmove2)) then game_tick(0) end end end -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- rs_create_world(level,cells,floorcell) stone_done(1) stone_done(0)