1: 2: logic 3: { 4: // NB. this must be at least big enough for the biggest layout 5: array board 6: { 7: 0, 0, 0, 0, 0, 0, 0, 0, 0, 8: 0, 0, 0, 0, 0, 0, 0, 0, 0, 9: 0, 0, 0, 0, 0, 0, 0, 0, 0, 10: 0, 0, 0, 0, 0, 0, 0, 0, 0, 11: 0, 0, 0, 0, 0, 0, 0, 0, 0, 12: 0, 0, 0, 0, 0, 0, 0, 0, 0, 13: 0, 0, 0, 0, 0, 0, 0, 0, 0, 14: 0, 0, 0, 0, 0, 0, 0, 0, 0, 15: 0, 0, 0, 0, 0, 0, 0, 0, 0 16: } 17: int boardwidth { 9 } 18: int boardheight { 9 } 19: 20: // 0 = floor 21: // 1 = wall 22: // 2 = crate 23: // 3 = target space 24: // 4 = player start 25: // Each layout must be surrounded by two rows of wall on all sides. 26: 27: // To add a new level: 28: // * Append its board to the array below 29: // * Append the width and height to layout_widths and layout_heights below 30: // * Append its title to the layout_names stringtable in the display section 31: // * Make sure the board, boardwidth and boardheight above are still big enough 32: // * Recompile and play 33: local array layouts 34: { 35: 1, 1, 1, 1, 1, 1, 1, 1, 36: 1, 1, 1, 1, 1, 1, 1, 1, 37: 1, 1, 0, 0, 0, 0, 1, 1, 38: 1, 1, 0, 2, 0, 4, 1, 1, 39: 1, 1, 0, 0, 0, 0, 1, 1, 40: 1, 1, 0, 3, 0, 0, 1, 1, 41: 1, 1, 1, 1, 1, 1, 1, 1, 42: 1, 1, 1, 1, 1, 1, 1, 1, 43: 44: 1, 1, 1, 1, 1, 1, 1, 1, 1, 45: 1, 1, 1, 1, 1, 1, 1, 1, 1, 46: 1, 1, 0, 0, 0, 3, 3, 1, 1, 47: 1, 1, 0, 0, 1, 0, 3, 1, 1, 48: 1, 1, 0, 2, 2, 0, 0, 1, 1, 49: 1, 1, 0, 0, 2, 1, 0, 1, 1, 50: 1, 1, 4, 0, 0, 0, 0, 1, 1, 51: 1, 1, 1, 1, 1, 1, 1, 1, 1, 52: 1, 1, 1, 1, 1, 1, 1, 1, 1 53: } 54: local int number_of_layouts { 2 } 55: local array layout_widths { 8, 9 } 56: local array layout_heights { 8, 9 } 57: 58: 59: int started { 0 } 60: int currentwidth { 0 } 61: int currentheight { 0 } 62: int location { 0 } 63: int crates_left { 0 } 64: int win { 0 } 65: 66: local int scratch { 0 } 67: 68: // Allow the user to start the game if it hasn't already been started 69: for layout ( 0 .. (number_of_layouts-1) ) 70: { 71: when { started == 0 } 72: allow 73: { 74: scratch = 0; 75: for i ( 0..(layout-1) ) 76: { 77: scratch = scratch + (layout_widths[i]*layout_heights[i]); 78: } 79: currentwidth = layout_widths[layout]; 80: currentheight = layout_heights[layout]; 81: for i ( 0..((currentwidth*currentheight)-1) ) 82: { 83: board[i] = layouts[scratch+i]; 84: if( board[i] == 2 ) 85: { 86: crates_left = crates_left + 1; 87: } 88: if( board[i] == 4 ) 89: { 90: location = i; 91: } 92: } 93: started = 1; 94: win = 0; 95: } 96: label { "Start " layout } 97: } 98: 99: // Allow the user to move when legal 100: when 101: { 102: (started == 1) 103: and 104: ( 105: (board[location-1] == 0) 106: ) 107: } 108: allow 109: { 110: board[location-1] = board[location]; 111: board[location] = 0; 112: location = location - 1; 113: } 114: label { "Move left" } 115: 116: when 117: { 118: (started == 1) 119: and 120: ( 121: (board[location+1] == 0) 122: ) 123: } 124: allow 125: { 126: board[location+1] = board[location]; 127: board[location] = 0; 128: location = location + 1; 129: } 130: label { "Move right" } 131: 132: when 133: { 134: (started == 1) 135: and 136: ( 137: (board[location-currentwidth] == 0) 138: ) 139: } 140: allow 141: { 142: board[location-currentwidth] = board[location]; 143: board[location] = 0; 144: location = location - (currentwidth); 145: } 146: label { "Move up" } 147: 148: 149: when 150: { 151: (started == 1) 152: and 153: ( 154: (board[location+currentwidth] == 0) 155: ) 156: } 157: allow 158: { 159: board[location+currentwidth] = board[location]; 160: board[location] = 0; 161: location = location + (currentwidth); 162: } 163: label { "Move down" } 164: 165: // Allow the user to push boxes when legal 166: // Use same labels as the move rules, because the board contents are mutually exclusive 167: // so only one of the two kinds of rules can be bound for each direction 168: when 169: { 170: (started == 1) 171: and 172: ( 173: (board[location-1] == 2) 174: and 175: ((board[location-2] == 0) or (board[location-2] == 3)) 176: ) 177: } 178: allow 179: { 180: scratch = board[location-2]; 181: board[location-2] = board[location-1]; 182: board[location-1] = board[location]; 183: board[location] = 0; 184: if( scratch == 3 ) 185: { 186: crates_left = crates_left - 1; 187: board[location-2] = 0; 188: } 189: location = location - 1; 190: } 191: label { "Move left" } 192: 193: when 194: { 195: (started == 1) 196: and 197: ( 198: (board[location+1] == 2) 199: and 200: ((board[location+2] == 0) or (board[location+2] == 3)) 201: ) 202: } 203: allow 204: { 205: scratch = board[location+2]; 206: board[location+2] = board[location+1]; 207: board[location+1] = board[location]; 208: board[location] = 0; 209: if( scratch == 3 ) 210: { 211: crates_left = crates_left - 1; 212: board[location+2] = 0; 213: } 214: location = location + 1; 215: } 216: label { "Move right" } 217: 218: when 219: { 220: (started == 1) 221: and 222: ( 223: (board[location-currentwidth] == 2) 224: and 225: ((board[location-(currentwidth*2)] == 0) or (board[location-(currentwidth*2)] == 3)) 226: ) 227: } 228: allow 229: { 230: scratch = board[location-(currentwidth*2)]; 231: board[location-(currentwidth*2)] = board[location-currentwidth]; 232: board[location-currentwidth] = board[location]; 233: board[location] = 0; 234: if( scratch == 3 ) 235: { 236: crates_left = crates_left - 1; 237: board[location-(currentwidth*2)] = 0; 238: } 239: location = location - currentwidth; 240: } 241: label { "Move up" } 242: 243: 244: when 245: { 246: (started == 1) 247: and 248: ( 249: (board[location+currentwidth] == 2) 250: and 251: ((board[location+(currentwidth*2)] == 0) or (board[location+(currentwidth*2)] == 3)) 252: ) 253: } 254: allow 255: { 256: scratch = board[location+(currentwidth*2)]; 257: board[location+(currentwidth*2)] = board[location+currentwidth]; 258: board[location+currentwidth] = board[location]; 259: board[location] = 0; 260: if( scratch == 3 ) 261: { 262: crates_left = crates_left - 1; 263: board[location+(currentwidth*2)] = 0; 264: } 265: location = location + currentwidth; 266: } 267: label { "Move down" } 268: 269: // Detect winning condition 270: when { (started == 1) and (crates_left <= 0) } 271: allow { win = 1; started = 0; } 272: label { "Win" } 273: 274: } 275: 276: display 277: { 278: stringtable layout_names 279: { 280: "Test level 1", 281: "Test level 2" 282: } 283: 284: stringtable pieces 285: { 286: " ", "#", "O", "+", "@" // TODO: we need some better pieces. 287: } 288: 289: // Title 290: box 291: { 292: content { "Sokoban" } 293: } 294: 295: newline 296: 297: // Menu 298: for layout ( 0 .. (number_of_layouts-1) ) 299: { 300: box 301: { 302: if( started == 0 ) 303: { 304: border { 1px solid black } 305: content { layout_names[layout] } 306: 307: bind_action { "Start " layout } 308: } 309: } 310: } 311: box 312: { 313: bind_action { "Win" } 314: while_active 315: { 316: border { 1px solid black } 317: content { "Well done! Click here for the menu." } 318: } 319: } 320: 321: newline 322: 323: // Board 324: for y ( 0 .. (boardheight-1) ) 325: { 326: for x ( 0 .. (boardwidth-1) ) 327: { 328: box 329: { 330: if( (started == 1) and (( x < currentwidth ) and ( y < currentheight )) ) 331: { 332: width { 1em } 333: height { 1em } 334: content { pieces[ board[(y*currentwidth)+x] ] } 335: } 336: } 337: } 338: newline 339: } 340: 341: // Controls 342: box 343: { 344: if( started == 1 ) 345: { 346: width { 2em } 347: height { 1em } 348: border { 1px solid black } 349: content { "←" } 350: bind_action { "Move left" } 351: } 352: } 353: box 354: { 355: if( started == 1 ) 356: { 357: width { 2em } 358: height { 1em } 359: border { 1px solid black } 360: content { "↑" } 361: bind_action { "Move up" } 362: } 363: } 364: box 365: { 366: if( started == 1 ) 367: { 368: width { 2em } 369: height { 1em } 370: border { 1px solid black } 371: content { "↓" } 372: bind_action { "Move down" } 373: } 374: } 375: box 376: { 377: if( started == 1 ) 378: { 379: width { 2em } 380: height { 1em } 381: border { 1px solid black } 382: content { "→" } 383: bind_action { "Move right" } 384: } 385: } 386: 387: newline 388: 389: box 390: { 391: if( started == 1 ) 392: { 393: content{ "You control the @. Push all the Os into the +s." } 394: } 395: } 396: }