18 |
-- |
-- |
19 |
-- '!' space outside level |
-- '!' space outside level |
20 |
-- ' ' normalfloor |
-- ' ' normalfloor |
21 |
|
-- '_' normalfloor (unreachable after pushing all boxes) |
22 |
-- '#' walls |
-- '#' walls |
23 |
-- 'o' boxes |
-- 'o' boxes |
24 |
-- '.' targets |
-- '.' targets |
44 |
|
|
45 |
shogunLaser = 0 -- if set to 1 then lasers are used to activate oxyds (this only works with shogun stones) |
shogunLaser = 0 -- if set to 1 then lasers are used to activate oxyds (this only works with shogun stones) |
46 |
|
|
47 |
-- some counters |
-- global variables |
48 |
triggers = 0 |
triggers = 0 |
49 |
doors = 0 |
doors = 0 |
50 |
lasers = 0 |
lasers = 0 |
52 |
|
|
53 |
triggerstate = "" -- current state of the triggers |
triggerstate = "" -- current state of the triggers |
54 |
shuffle = {} -- contains random permutation (to select trigger targets) |
shuffle = {} -- contains random permutation (to select trigger targets) |
55 |
|
shuffletrig = {} -- contains random permutation (to select triggers) |
56 |
|
|
57 |
|
position = {} -- positions of doors |
58 |
|
positions = 0 |
59 |
|
|
60 |
|
locked_door_triggered = 0 -- one of the doors is locked until ALL targets are covered |
61 |
|
locked_door = 1 |
62 |
|
|
63 |
|
function init_globals() |
64 |
|
triggers = 0 |
65 |
|
doors = 0 |
66 |
|
lasers = 0 |
67 |
|
space_count = 0 |
68 |
|
triggerstate = "" |
69 |
|
shuffle = {} |
70 |
|
shuffletrig = {} |
71 |
|
position = {} |
72 |
|
positions = 0 |
73 |
|
locked_door_triggered = 0 |
74 |
|
locked_door = 1 |
75 |
|
|
76 |
|
end |
77 |
|
|
78 |
|
----------------------------------------- |
79 |
|
|
80 |
function init_shuffle() |
function init_shuffle() |
81 |
local set = {} |
local set = {} |
82 |
for i=1,doors do |
for i=1,doors do set[i] = i end |
|
set[i] = i |
|
|
end |
|
83 |
|
|
84 |
local left = doors |
local left = doors |
85 |
for count=1,doors do |
for count=1,doors do |
89 |
left = left-1 |
left = left-1 |
90 |
debug("shuffle["..count.."]="..shuffle[count]) |
debug("shuffle["..count.."]="..shuffle[count]) |
91 |
end |
end |
|
end |
|
92 |
|
|
93 |
function yep(who) |
local settrig = {} |
94 |
debug("level done"); |
for i=1,triggers do settrig[i] = i end |
|
end |
|
95 |
|
|
96 |
locked_door_triggered = 0 -- one of the doors is locked until ALL targets are covered |
left = triggers |
97 |
|
for count=1,triggers do |
98 |
|
local sel = random(1,left) |
99 |
|
shuffletrig[count] = settrig[sel] |
100 |
|
settrig[sel] = settrig[left] |
101 |
|
left = left-1 |
102 |
|
debug("shuffletrig["..count.."]="..shuffletrig[count]) |
103 |
|
end |
104 |
|
end |
105 |
|
|
106 |
function trig_laser(which) |
function trig_laser(which) |
107 |
|
which = shuffletrig[which] |
108 |
local state = strsub(triggerstate,which,which) |
local state = strsub(triggerstate,which,which) |
109 |
if (state == "0") then state = "1" else state = "0" end |
if (state == "0") then state = "1" else state = "0" end |
110 |
triggerstate = strsub(triggerstate,1,which-1)..state..strsub(triggerstate,which+1) |
triggerstate = strsub(triggerstate,1,which-1)..state..strsub(triggerstate,which+1) |
118 |
end |
end |
119 |
|
|
120 |
function trig_door(which) |
function trig_door(which) |
121 |
|
which = shuffletrig[which] |
122 |
local state = strsub(triggerstate,which,which) |
local state = strsub(triggerstate,which,which) |
123 |
if (state == "0") then state = "1" else state = "0" end |
if (state == "0") then state = "1" else state = "0" end |
124 |
|
|
156 |
debug(triggerstate) |
debug(triggerstate) |
157 |
|
|
158 |
if (trig_door ~= -1) then |
if (trig_door ~= -1) then |
159 |
if (trig_door ~= 1) then |
if (trig_door ~= locked_door) then |
160 |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[trig_door]), "openclose", nil) |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[trig_door]), "openclose", nil) |
161 |
end |
end |
162 |
end |
end |
163 |
|
|
164 |
if (all_covered) then |
if (all_covered) then |
165 |
if (locked_door_triggered==0) then |
if (locked_door_triggered==0) then |
166 |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[1]), "open", nil) |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[locked_door]), "open", nil) |
167 |
locked_door_triggered = 1 |
locked_door_triggered = 1 |
168 |
end |
end |
169 |
else |
else |
170 |
if (locked_door_triggered==1) then |
if (locked_door_triggered==1) then |
171 |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[1]), "close", nil) |
enigma.SendMessage(enigma.GetNamedObject("door"..shuffle[locked_door]), "close", nil) |
172 |
locked_door_triggered = 0 |
locked_door_triggered = 0 |
173 |
end |
end |
174 |
end |
end |
199 |
set_soko_trigger(x,y) |
set_soko_trigger(x,y) |
200 |
end |
end |
201 |
|
|
202 |
spacemod = 2 |
--spacemod = 2 |
203 |
|
|
204 |
function set_spacecell(x,y) |
function set_spacecell(x,y) |
205 |
space_count = space_count+1 |
space_count = space_count+1 |
207 |
end |
end |
208 |
|
|
209 |
function init(num) |
function init(num) |
210 |
|
init_globals() |
211 |
|
|
212 |
local first = 0 |
local first = 0 |
213 |
if (num == -1) then |
if (num == -1) then |
214 |
first = 1 |
first = 1 |
250 |
cells={} |
cells={} |
251 |
cells["!"] = cell{parent = {set_spacecell}} |
cells["!"] = cell{parent = {set_spacecell}} |
252 |
cells[" "] = floorcell |
cells[" "] = floorcell |
253 |
|
cells["_"] = floorcell |
254 |
cells["#"] = cell{parent = floorcell, stone = {face = wallface}} |
cells["#"] = cell{parent = floorcell, stone = {face = wallface}} |
255 |
|
|
256 |
cells["o"] = cell{parent = floorcell, stone = {face = boxface}} |
cells["o"] = cell{parent = floorcell, stone = {face = boxface}} |
283 |
return strsub(level[y],x,x) |
return strsub(level[y],x,x) |
284 |
end |
end |
285 |
|
|
286 |
|
function rpeek(rx,ry) |
287 |
|
return peek(rx-xlo+1,ry-ylo+1) |
288 |
|
end |
289 |
|
|
290 |
function adjacent(x1,y1,x2,y2) -- returns TRUE if the two positions are adjacent |
function adjacent(x1,y1,x2,y2) -- returns TRUE if the two positions are adjacent |
291 |
local dx,dy = abs(x1-x2),abs(y1-y2) |
local dx,dy = abs(x1-x2),abs(y1-y2) |
292 |
return (dx==0 and dy==1) or (dx==1 and dy==0) |
return (dx==0 and dy==1) or (dx==1 and dy==0) |
301 |
xoff = { -1, 1, 0, 0 } |
xoff = { -1, 1, 0, 0 } |
302 |
yoff = { 0, 0, -1, 1 } |
yoff = { 0, 0, -1, 1 } |
303 |
|
|
304 |
function install_oxyds(w,h) -- uses Nat's method (see nat7.lua) |
function is_in_restricted_area(p) |
305 |
local position = {} |
local xd,yd = position[p][1],position[p][2] |
306 |
local positions = 0 |
local xo,yo = position[p][3],position[p][4] |
307 |
|
local xf,yf = xd+(xd-xo),yd+(yd-yo) |
308 |
|
|
309 |
|
debug("xf="..xf.." yf="..yf) |
310 |
|
|
311 |
|
local c = rpeek(xf,yf) |
312 |
|
if (c==' ') then return 0 end |
313 |
|
if (c=='_') then return 1 end |
314 |
|
|
315 |
|
return 2 -- unknown |
316 |
|
end |
317 |
|
|
318 |
|
function install_oxyds(w,h) -- uses Nat's method (see nat7.lua) |
319 |
for x=1,w do |
for x=1,w do |
320 |
for y=1,h do |
for y=1,h do |
321 |
if (peek(x,y)=='#') then |
if (peek(x,y)=='#') then |
337 |
spacehere = -1 |
spacehere = -1 |
338 |
end |
end |
339 |
end |
end |
340 |
if (state[n]=='o' or state[n]==' ' or state[n]=='@') then |
|
341 |
|
if (state[n]=='o' or state[n]==' ' or state[n]=='@' or state[n]=='_') then |
342 |
if (reachable == 0) then |
if (reachable == 0) then |
343 |
reachable = n |
reachable = n |
344 |
else |
else |
443 |
return 0 |
return 0 |
444 |
end |
end |
445 |
|
|
446 |
|
function correct_locked_door_position() |
447 |
|
while (locked_door <= doors) do |
448 |
|
local ld = shuffle[locked_door] |
449 |
|
local restricted = is_in_restricted_area(ld) |
450 |
|
|
451 |
|
local xd,yd = position[ld][1],position[ld][2] |
452 |
|
debug("[locked door] ld="..ld.." xd="..xd.." yd="..yd.." restricted="..restricted) |
453 |
|
|
454 |
|
if (restricted == 0) then return 1 end |
455 |
|
locked_door = locked_door+1 |
456 |
|
end |
457 |
|
debug("Could not correct position of locked door. Not playable!"); |
458 |
|
return 0 |
459 |
|
end |
460 |
|
|
461 |
|
function correct_multi_trigger_doors() |
462 |
|
if (doors == triggers) then return 1 end -- 1 triggers <-> 1 door => no problem |
463 |
|
|
464 |
|
local multiTriggeredDoors = triggers-doors |
465 |
|
if (multiTriggeredDoors > doors) then multiTriggeredDoors = doors end |
466 |
|
for mtd=1,multiTriggeredDoors do |
467 |
|
local ld = shuffle[mtd] |
468 |
|
local restricted = is_in_restricted_area(ld) |
469 |
|
|
470 |
|
local xd,yd = position[ld][1],position[ld][2] |
471 |
|
debug("[multit door] ld="..ld.." xd="..xd.." yd="..yd.." restricted="..restricted) |
472 |
|
|
473 |
|
if (restricted ~= 0) then return 0 end |
474 |
|
end |
475 |
|
return 1 |
476 |
|
end |
477 |
|
|
478 |
|
function correct_door_positions() |
479 |
|
if (shogunLaser==1) then return 1 end -- doesn't matter in shogunLaser mode |
480 |
|
|
481 |
|
local ok = correct_locked_door_position() |
482 |
|
if (ok==1) then ok = correct_multi_trigger_doors() end |
483 |
|
|
484 |
|
return ok |
485 |
|
end |
486 |
|
|
487 |
function play_sokoban(level,num) |
function play_sokoban(level,num) |
488 |
local w,h = get_map_size(level) |
local w,h = get_map_size(level) |
489 |
init(num-1) |
local tries = 100 |
490 |
randomseed(enigma.GetTicks()) |
local ok = 0 |
|
-- rs_create_world(level,cells,spacecell,spacecell) |
|
|
rs_create_world(level,cells,set_spacecell,set_spacecell) |
|
491 |
|
|
492 |
if (xlo > 0) then |
while (tries > 0 and ok == 0) do |
493 |
spl = 1 -- there's space at the left side |
init(num-1) |
494 |
space_count = space_count + maph |
randomseed(enigma.GetTicks()) |
495 |
end |
-- rs_create_world(level,cells,spacecell,spacecell) |
496 |
if (ylo > 0) then |
rs_create_world(level,cells,set_spacecell,set_spacecell) |
497 |
spt = 1 -- there's space at the top side |
|
498 |
space_count = space_count + mapw |
if (xlo > 0) then |
499 |
end |
spl = 1 -- there's space at the left side |
500 |
if ((xlo+mapw) < 20) then |
space_count = space_count + maph |
501 |
spr = 1 -- there's space at the right side |
end |
502 |
space_count = space_count + maph |
if (ylo > 0) then |
503 |
end |
spt = 1 -- there's space at the top side |
504 |
if ((ylo+maph) < 13) then |
space_count = space_count + mapw |
505 |
spb = 1 -- there's space at the bottom side |
end |
506 |
space_count = space_count + mapw |
if ((xlo+mapw) < 20) then |
507 |
end |
spr = 1 -- there's space at the right side |
508 |
|
space_count = space_count + maph |
509 |
|
end |
510 |
|
if ((ylo+maph) < 13) then |
511 |
|
spb = 1 -- there's space at the bottom side |
512 |
|
space_count = space_count + mapw |
513 |
|
end |
514 |
|
|
515 |
debug("Space aside: spl="..spl.." spr="..spr.." spt="..spt.." spb="..spb); |
debug("Space aside: spl="..spl.." spr="..spr.." spt="..spt.." spb="..spb); |
516 |
|
|
517 |
-- install oxyds |
-- install oxyds |
518 |
install_oxyds(w,h) |
install_oxyds(w,h) |
519 |
|
init_shuffle() -- mix trigger-door associations |
520 |
|
ok = correct_door_positions() |
521 |
|
if (ok == 0) then debug("re-initializing.."); end |
522 |
|
tries = tries - 1 |
523 |
|
end |
524 |
|
|
525 |
init_shuffle() -- mix trigger-door associations |
if (ok==0) then |
526 |
|
error("Sorry - couldn't correct door positions. Avoiding deadlock (try again)"); |
527 |
|
end |
528 |
|
|
529 |
triggerstate = strrep("0",triggers) |
triggerstate = strrep("0",triggers) |
530 |
display.SetFollowMode(display.FOLLOW_SCROLLING) |
display.SetFollowMode(display.FOLLOW_SCROLLING) |