1 /* Tower Toppler - Nebulus
2 * Copyright (C) 2000-2012 Andreas R�ver
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifndef CREATOR
20
21 #include "level.h"
22 #include "points.h"
23 #include "archi.h"
24 #include "configuration.h"
25 #include "screen.h"
26
27 #endif
28
29 #include "decl.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #define TOWERWID 16
35
36 /* tower block flags */
37 #define TBF_NONE 0x0000
38 #define TBF_EMPTY 0x0001 /* block is not solid */
39 #define TBF_PLATFORM 0x0002 /* block is a platform */
40 #define TBF_STATION 0x0004 /* block is a lift station */
41 #define TBF_DEADLY 0x0008 /* block is deadly */
42 #define TBF_ROBOT 0x0010 /* block is a robot */
43
44 struct _tblockdata {
45 const char *nam; /* name */
46 char ch; /* representation in saved tower file */
47 Uint16 tf; /* flags; TBF_foo */
48 } static towerblockdata[NUM_TBLOCKS] = {
49 { "space", ' ', TBF_EMPTY },
50 { "lift top stop", 'v', TBF_EMPTY|TBF_STATION },
51 { "lift middle stop", '+', TBF_EMPTY|TBF_STATION },
52 { "lift bottom stop", 0, TBF_EMPTY|TBF_STATION },
53 { "robot 1", '1', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
54 { "robot 2", '2', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
55 { "robot 3", '3', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
56 { "robot 4", '4', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
57 { "robot 5", '5', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
58 { "robot 6", '6', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
59 { "robot 7", '7', TBF_EMPTY|TBF_DEADLY|TBF_ROBOT },
60 { "stick", '!', /*TBF_PLATFORM*/ },
61 { "step", '-', TBF_PLATFORM },
62 { "vanisher step", '.', TBF_PLATFORM },
63 { "slider > step", '>', TBF_PLATFORM },
64 { "slider < step", '<', TBF_PLATFORM },
65 { "box", 'b', TBF_NONE },
66 { "door", '#', TBF_EMPTY },
67 { "target door", 'T', TBF_EMPTY },
68 { "stick top", 0, TBF_STATION/*|TBF_PLATFORM*/ },
69 { "stick middle", 0, TBF_STATION/*|TBF_PLATFORM*/ },
70 { "stick bottom", 0, TBF_STATION/*|TBF_PLATFORM*/ },
71 { "lift top", 0, TBF_STATION|TBF_PLATFORM },
72 { "lift middle", 0, TBF_STATION|TBF_PLATFORM },
73 { "lift bottom", '^', TBF_STATION|TBF_PLATFORM },
74 { "stick at door", 0, },
75 { "stick at target", 0, },
76 { "lift at door", 0 , TBF_STATION|TBF_PLATFORM },
77 { "lift at target", 0 , TBF_STATION|TBF_PLATFORM },
78 };
79
80 /* Sections in the data files; do not change the order,
81 * and always add new ones to the end, so that we keep
82 * compatibility with old towers/missions.
83 * (the loader silently ignores unrecognized sections)
84 */
85 enum towersection {
86 TSS_END,
87 TSS_TOWERNAME,
88 TSS_TOWERTIME,
89 TSS_TOWERCOLOR,
90 TSS_TOWERDATA,
91 TSS_DEMO,
92 TSS_ROBOT
93 };
94
95 char tss_string_name[] = "name";
96 char tss_string_time[] = "time";
97 char tss_string_color[] = "color";
98 char tss_string_data[] = "data";
99 char tss_string_demo[] = "demo";
100 char tss_string_robot[] = "robot";
101
102 static Uint8 * mission = NULL;
103 static Uint8 towerheight;
104 static Uint8 towerrobot;
105 static Uint8 tower[256][TOWERWID];
106 static char towername[TOWERNAMELEN+1];
107 static Uint8 towernumber;
108 static Uint8 towercolor_red, towercolor_green, towercolor_blue;
109 static Uint16 towertime;
110 static Uint16 *towerdemo = NULL;
111 static int towerdemo_len = 0;
112
113 typedef struct mission_node {
114 char name[30];
115 char fname[100];
116 bool archive; // is the mission inside the archive, or not
117 Uint8 prio; // the lower prio, the further in front the mission will be in the list
118 mission_node *next;
119 } mission_node;
120
121 mission_node * missions;
122
123 #ifndef CREATOR
124
missionfiles(const struct dirent * file)125 static int missionfiles (const struct dirent *file)
126 {
127 int len = strlen(file->d_name);
128
129 return ((len > 4) &&
130 (file->d_name[len - 1] == 'm') &&
131 (file->d_name[len - 2] == 't') &&
132 (file->d_name[len - 3] == 't') &&
133 (file->d_name[len - 4] == '.'));
134 }
135
136 #endif
137
conv_char2towercode(wchar_t ch)138 Uint8 conv_char2towercode(wchar_t ch) {
139 if (ch)
140 for (int x = 0; x < NUM_TBLOCKS; x++)
141 // we can do that because we use only chars below 128
142 if (ch == towerblockdata[x].ch) return x;
143 return TB_EMPTY;
144 }
145
conv_towercode2char(Uint8 code)146 char conv_towercode2char(Uint8 code) {
147 if ((code < NUM_TBLOCKS) && (towerblockdata[code].ch))
148 return towerblockdata[code].ch;
149 return towerblockdata[TB_EMPTY].ch;
150 }
151
152
add_mission(const char * fname,bool archive=false)153 static void add_mission(const char *fname, bool archive = false) {
154
155 char mname[30];
156 Uint8 prio;
157
158 if (archive) {
159
160 file f(dataarchive, fname);
161
162 unsigned char mnamelength;
163 f.read(&mnamelength, 1);
164
165 if (mnamelength > 29) mnamelength = 29;
166
167 f.read(mname, mnamelength);
168 mname[mnamelength] = 0;
169 f.read(&prio, 1);
170
171 } else {
172
173 FILE * f = fopen(fname, "rb");
174
175 if (!f) return;
176
177 unsigned char mnamelength;
178 fread(&mnamelength, 1, 1, f);
179
180 if (mnamelength > 29) mnamelength = 29;
181
182 fread(mname, mnamelength, 1, f);
183 mname[mnamelength] = 0;
184 fread(&prio, 1, 1, f);
185 fclose(f);
186 }
187
188 mission_node * m = missions;
189 mission_node * l = NULL;
190
191 /* first check if the mission is already there */
192 while (m) {
193
194 int erg = strcmp(m->name, mname);
195 /* no two missions with the same name */
196 if (erg == 0) {
197 return;
198 }
199 l = m;
200 m = m->next;
201 }
202
203 m = missions;
204 l = NULL;
205
206 while (m) {
207
208 /* we have passed our target, the current mission must
209 * be inserted before this mission
210 */
211 if (m->prio > prio) {
212 mission_node * n = new mission_node;
213 strcpy(n->name, mname);
214 strcpy(n->fname, fname);
215 n->prio = prio;
216 n->next = m;
217 n->archive = archive;
218
219 if (l)
220 l->next = n;
221 else
222 missions = n;
223
224 return;
225 }
226 l = m;
227 m = m->next;
228 }
229
230 /* insert at the end */
231 m = new mission_node;
232 strcpy(m->name, mname);
233 strcpy(m->fname, fname);
234 m->prio = prio;
235 m->next = NULL;
236 m->archive = archive;
237
238 if (l)
239 l->next = m;
240 else
241 missions = m;
242
243 }
244
245 #ifndef CREATOR
246
lev_findmissions()247 void lev_findmissions() {
248
249 char pathname[100];
250
251 struct dirent **eps = NULL;
252
253 missions = NULL;
254
255 /* check if already called, if so free the old list */
256 while (missions) {
257 mission_node *n = missions;
258 missions = missions->next;
259 delete n;
260 }
261
262 /* first check inside the archive */
263
264 for (int fn = 0; fn < dataarchive->fileNumber(); fn++) {
265 const char * n = dataarchive->fname(fn);
266
267 int len = strlen(n);
268
269 if ((len > 4) && (n[len - 1] == 'm') && (n[len - 2] == 't') &&
270 (n[len - 3] == 't') && (n[len - 4] == '.'))
271 add_mission(n, true);
272 }
273
274 #ifdef WIN32
275 {
276 char n[100];
277 getcwd(n, 100);
278 sprintf(pathname, "%s\\", n);
279 }
280 #else
281 sprintf(pathname, "%s", "./");
282 #endif
283
284 int n = alpha_scandir(pathname, &eps, missionfiles);
285
286 if (n >= 0) {
287
288 for (int i = 0; i < n; i++) {
289
290 char fname[200];
291 sprintf(fname, "%s%s", pathname, eps[i]->d_name);
292
293 add_mission(fname);
294
295 free(eps[i]);
296 }
297 }
298 free(eps);
299 eps = NULL;
300
301 #ifndef WIN32
302
303 snprintf(pathname, 100, "%s/.toppler/", homedir());
304 n = alpha_scandir(pathname, &eps, missionfiles);
305
306 if (n >= 0) {
307
308 for (int i = 0; i < n; i++) {
309
310 char fname[200];
311 snprintf(fname, 200, "%s%s", pathname, eps[i]->d_name);
312
313 add_mission(fname);
314 }
315 }
316 free(eps);
317 eps = NULL;
318
319 snprintf(pathname, 100, "%s/", TOP_DATADIR);
320 n = alpha_scandir(pathname, &eps, missionfiles);
321
322 if (n >= 0) {
323
324 for (int i = 0; i < n; i++) {
325
326 char fname[200];
327 snprintf(fname, 200, "%s%s", pathname, eps[i]->d_name);
328
329 add_mission(fname);
330 }
331 }
332 free(eps);
333 eps = NULL;
334
335 #endif
336
337 }
338
339 #endif
340
lev_done()341 void lev_done() {
342 if (mission) {
343 delete [] mission;
344 mission = NULL;
345 }
346
347 mission_node * m = missions;
348
349 while (m) {
350 m = m->next;
351 delete missions;
352 missions = m;
353 }
354
355 if (towerdemo) delete [] towerdemo;
356 }
357
358
lev_missionnumber()359 Uint16 lev_missionnumber() {
360 int num = 0;
361 mission_node * m = missions;
362
363 while (m) {
364 num++;
365 m = m->next;
366 }
367
368 return num;
369 }
370
lev_missionname(Uint16 num)371 const char * lev_missionname(Uint16 num) {
372 mission_node * m = missions;
373
374 while (num) {
375 m = m->next;
376 num--;
377 }
378
379 return m->name;
380 }
381
lev_loadmission(Uint16 num)382 bool lev_loadmission(Uint16 num) {
383
384 mission_node *m = missions;
385 while (num) {
386 num--;
387 m = m->next;
388 }
389
390 if (mission) delete [] mission;
391
392 if (m->archive) {
393
394 file f(dataarchive, m->fname);
395 int fsize = f.size();
396
397 mission = new unsigned char[fsize];
398 f.read(mission, fsize);
399
400 } else {
401
402 FILE * in = fopen(m->fname, "rb");
403
404 /* find out file size */
405 fseek(in, 0, SEEK_END);
406 int fsize = ftell(in);
407
408 /* get enough memory and load the whole file into memory */
409 mission = new unsigned char[fsize];
410 fseek(in, 0, SEEK_SET);
411 fread(mission, fsize, 1, in);
412
413 fclose(in);
414 }
415
416 for (int t = 0; t < lev_towercount(); t++) {
417 lev_selecttower(t);
418 for (int r = 0; r < towerheight; r++)
419 for (int c = 0; c < TOWERWID; c++)
420 if (tower[r][c] >= NUM_TBLOCKS)
421 return false;
422 }
423
424 return true;
425 }
426
lev_towercount(void)427 Uint8 lev_towercount(void) {
428 return mission[mission[0] + 2];
429 }
430
lev_selecttower(Uint8 number)431 void lev_selecttower(Uint8 number) {
432
433 Uint32 towerstart;
434
435 towernumber = number;
436 towerrobot = number;
437 Uint8 section;
438 Uint32 section_len;
439
440 lev_set_towerdemo(0, NULL);
441
442 // find start of towerdata in mission
443 {
444 Uint32 idxpos = 0;
445
446 idxpos += mission[mission[0] + 3];
447 idxpos += long(mission[mission[0] + 4]) << 8;
448 idxpos += long(mission[mission[0] + 5]) << 16;
449 idxpos += long(mission[mission[0] + 6]) << 24;
450
451 towerstart = mission[idxpos + 4 * number];
452 towerstart += long(mission[idxpos + 4 * number + 1]) << 8;
453 towerstart += long(mission[idxpos + 4 * number + 2]) << 16;
454 towerstart += long(mission[idxpos + 4 * number + 3]) << 24;
455 }
456
457 do {
458 section = mission[towerstart++];
459 section_len = mission[towerstart++];
460 section_len += Uint32(mission[towerstart++]) << 8;
461 section_len += Uint32(mission[towerstart++]) << 16;
462 section_len += Uint32(mission[towerstart++]) << 24;
463 switch ((towersection)section) {
464 case TSS_TOWERNAME:
465 memmove(towername, &mission[towerstart], section_len);
466 towername[section_len] = 0;
467 break;
468 case TSS_TOWERTIME:
469 towertime = mission[towerstart] + (int(mission[towerstart + 1]) << 8);
470 break;
471 case TSS_TOWERCOLOR:
472 towercolor_red = mission[towerstart];
473 towercolor_green = mission[towerstart + 1];
474 towercolor_blue = mission[towerstart + 2];
475 break;
476 case TSS_TOWERDATA:
477 {
478 towerheight = mission[towerstart];
479
480 Uint32 bitstart = towerstart + 1;
481 Uint32 bytestart = bitstart + 2 * towerheight;
482 Uint16 wpos = 0;
483 Uint16 bpos = 0;
484
485 lev_clear_tower();
486
487 for (Uint8 row = 0; row < towerheight; row++) {
488 for (Uint8 col = 0; col < TOWERWID; col++) {
489 if ((mission[bitstart + (bpos >> 3)] << (bpos & 7)) & 0x80)
490 tower[row][col] = mission[bytestart + wpos++];
491 else
492 tower[row][col] = 0;
493 bpos++;
494 }
495 }
496 break;
497 }
498 case TSS_DEMO:
499 {
500 // get tower demo
501 Uint16 *tmpbuf = NULL;
502 Uint16 tmpbuf_len = mission[towerstart];
503 tmpbuf_len += Uint16(mission[towerstart+1]) << 8;
504 Uint16 ofs = 2;
505
506 if (tmpbuf_len) {
507 tmpbuf = new Uint16[tmpbuf_len];
508 Uint16 idx = 0;
509 while (idx < tmpbuf_len) {
510 Uint8 run = mission[towerstart + ofs++];
511 Uint16 data = mission[towerstart + ofs++];
512 data += Uint16(mission[towerstart + ofs++]) << 8;
513
514 while (run) {
515 tmpbuf[idx++] = data;
516 run--;
517 }
518 }
519 }
520
521 lev_set_towerdemo(tmpbuf_len, tmpbuf);
522 break;
523 }
524 case TSS_ROBOT:
525 towerrobot = mission[towerstart];
526 #ifndef CREATOR
527 towerrobot %= scr_numrobots();
528 #endif
529 break;
530 case TSS_END:
531 default: break;
532 }
533 towerstart += section_len;
534 } while ((towersection)section != TSS_END);
535 }
536
537 char *
gen_passwd(int pwlen,const char * allowed,int buflen,char * buf)538 gen_passwd(int pwlen, const char *allowed, int buflen, char *buf)
539 {
540 static char passwd[PASSWORD_LEN + 1];
541 int len = buflen;
542 int alen;
543 int i;
544
545 if (!allowed) return NULL;
546
547 alen = strlen(allowed);
548
549 if (pwlen > PASSWORD_LEN) pwlen = PASSWORD_LEN;
550
551 if (buflen < (pwlen*5)) len = pwlen*5;
552
553 (void)memset(passwd, 0, PASSWORD_LEN);
554
555 for (i = 0; i < len; i++) {
556 passwd[i % pwlen] += buf[i % buflen];
557 if (passwd[i % pwlen] > alen) passwd[(i+1) % pwlen]++;
558 }
559
560 for (i = 0; i < pwlen; i++)
561 passwd[i] = allowed[abs(passwd[i]) % alen];
562
563 passwd[pwlen] = '\0';
564
565 return passwd;
566 }
567
lev_get_passwd(void)568 char *lev_get_passwd(void) {
569 return gen_passwd(PASSWORD_LEN, PASSWORD_CHARS, 256*TOWERWID, (char *)tower);
570 }
571
lev_show_passwd(int levnum)572 bool lev_show_passwd(int levnum) {
573 return ((levnum > 0) &&
574 (levnum < lev_towercount()) &&
575 ((levnum % 3) == 0));
576 }
577
lev_tower_passwd_entry(const char * passwd)578 int lev_tower_passwd_entry(const char *passwd) {
579 int i;
580 if (!passwd) return 0;
581 for (i = 0; i < lev_towercount(); i++) {
582 lev_selecttower(i);
583 if (!strcmp(passwd,lev_get_passwd())) return i;
584 }
585 return 0;
586 }
587
lev_clear_tower(void)588 void lev_clear_tower(void) {
589 memset(&tower, TB_EMPTY, 256*TOWERWID);
590 }
591
lev_set_towercol(Uint8 r,Uint8 g,Uint8 b)592 void lev_set_towercol(Uint8 r, Uint8 g, Uint8 b) {
593 towercolor_red = r;
594 towercolor_green = g;
595 towercolor_blue = b;
596 }
597
lev_towercol_red()598 Uint8 lev_towercol_red() {
599 return towercolor_red;
600 }
601
lev_towercol_green()602 Uint8 lev_towercol_green() {
603 return towercolor_green;
604 }
605
lev_towercol_blue()606 Uint8 lev_towercol_blue() {
607 return towercolor_blue;
608 }
609
lev_tower(Uint16 row,Uint8 column)610 Uint8 lev_tower(Uint16 row, Uint8 column) {
611 return tower[row][column];
612 }
613
lev_set_tower(Uint16 row,Uint8 column,Uint8 block)614 Uint8 lev_set_tower(Uint16 row, Uint8 column, Uint8 block) {
615 Uint8 tmp = tower[row][column];
616 tower[row][column] = block;
617 return tmp;
618 }
619
lev_towerrows(void)620 Uint8 lev_towerrows(void) {
621 return towerheight;
622 }
623
lev_towername(void)624 char * lev_towername(void) {
625 return towername;
626 }
627
lev_set_towerdemo(int demolen,Uint16 * demobuf)628 void lev_set_towerdemo(int demolen, Uint16 *demobuf) {
629 if (towerdemo) delete [] towerdemo;
630 towerdemo = demobuf;
631 towerdemo_len = demolen;
632 }
633
lev_get_towerdemo(int & demolen,Uint16 * & demobuf)634 void lev_get_towerdemo(int &demolen, Uint16 *&demobuf) {
635 demobuf = towerdemo;
636 demolen = towerdemo_len;
637 }
638
lev_set_towername(const char * str)639 void lev_set_towername(const char *str) {
640 (void) strncpy(towername, str, TOWERNAMELEN);
641 towername[TOWERNAMELEN] = '\0';
642 }
643
lev_towernr(void)644 Uint8 lev_towernr(void) {
645 return towernumber;
646 }
647
lev_lasttower(void)648 bool lev_lasttower(void) {
649 return (towernumber+1) == lev_towercount();
650 }
651
lev_robotnr(void)652 Uint8 lev_robotnr(void) {
653 return towerrobot;
654 }
655
lev_set_robotnr(Uint8 robot)656 void lev_set_robotnr(Uint8 robot) {
657 towerrobot = robot;
658 }
659
lev_towertime(void)660 Uint16 lev_towertime(void) {
661 return towertime;
662 }
663
lev_set_towertime(Uint16 time)664 void lev_set_towertime(Uint16 time) {
665 towertime = time;
666 }
667
lev_removelayer(Uint8 layer)668 void lev_removelayer(Uint8 layer) {
669 while (layer < towerheight) {
670 for (Uint8 c = 0; c < TOWERWID; c++)
671 tower[layer][c] = tower[layer + 1][c];
672 layer++;
673 }
674
675 towerheight--;
676 }
677
678 /* empties a cell in the tower */
lev_clear(int row,int col)679 void lev_clear(int row, int col) {
680 tower[row][col] = TB_EMPTY;
681 }
682
683 /* if the given position contains a vanishing step, remove it */
lev_removevanishstep(int row,int col)684 void lev_removevanishstep(int row, int col) {
685 if (tower[row][col] == TB_STEP_VANISHER)
686 tower[row][col] = TB_EMPTY;
687 }
688
689 /********** everything for doors ********/
690
691 /* returns true, if the given position is the upper end of a door
692 (a door is always 3 layers) */
lev_is_door_upperend(int row,int col)693 bool lev_is_door_upperend(int row, int col) {
694 return lev_is_door(row, col) &&
695 lev_is_door(row + 1, col) &&
696 lev_is_door(row + 2, col);
697 }
698
699 /* returns true if the given position contains a door */
lev_is_door(int row,int col)700 bool lev_is_door(int row, int col) {
701 return (tower[row][col] == TB_DOOR ||
702 tower[row][col] == TB_DOOR_TARGET ||
703 tower[row][col] == TB_STICK_DOOR);
704 }
705
706 /* returns true, if the given fiels contains a target door */
lev_is_targetdoor(int row,int col)707 bool lev_is_targetdoor(int row, int col) {
708 return tower[row][col] == TB_DOOR_TARGET;
709 }
710
711 /**************** everything for elevators ******************/
712
lev_is_station(int row,int col)713 bool lev_is_station(int row, int col) {
714 return ((towerblockdata[tower[row][col]].tf & TBF_STATION) != 0);
715 }
lev_is_up_station(int row,int col)716 bool lev_is_up_station(int row, int col) {
717 return ((tower[row][col] == TB_ELEV_BOTTOM) ||
718 (tower[row][col] == TB_ELEV_MIDDLE));
719 }
lev_is_down_station(int row,int col)720 bool lev_is_down_station(int row, int col) {
721 return ((tower[row][col] == TB_ELEV_TOP) ||
722 (tower[row][col] == TB_ELEV_MIDDLE));
723 }
lev_is_bottom_station(int row,int col)724 bool lev_is_bottom_station(int row, int col) {
725 return (tower[row][col] == TB_ELEV_BOTTOM);
726 }
727
lev_is_platform(int row,int col)728 bool lev_is_platform(int row, int col) {
729 return ((towerblockdata[tower[row][col]].tf & TBF_PLATFORM) != 0);
730 }
lev_is_stick(int row,int col)731 bool lev_is_stick(int row, int col) {
732 return ((tower[row][col] == TB_STICK) ||
733 (tower[row][col] == TB_STICK_TOP) ||
734 (tower[row][col] == TB_STICK_MIDDLE) ||
735 (tower[row][col] == TB_STICK_BOTTOM) ||
736 (tower[row][col] == TB_STICK_DOOR) ||
737 (tower[row][col] == TB_STICK_DOOR_TARGET));
738 }
739
lev_is_elevator(int row,int col)740 bool lev_is_elevator(int row, int col) {
741 return ((tower[row][col] == TB_STICK_BOTTOM) ||
742 (tower[row][col] == TB_STICK_MIDDLE) ||
743 (tower[row][col] == TB_STICK_TOP) ||
744 (tower[row][col] == TB_ELEV_BOTTOM) ||
745 (tower[row][col] == TB_ELEV_MIDDLE) ||
746 (tower[row][col] == TB_ELEV_TOP));
747 }
748
lev_platform2stick(int row,int col)749 void lev_platform2stick(int row, int col) {
750 if (tower[row][col] == TB_ELEV_TOP) tower[row][col] = TB_STICK_TOP;
751 else if (tower[row][col] == TB_ELEV_MIDDLE) tower[row][col] = TB_STICK_MIDDLE;
752 else if (tower[row][col] == TB_ELEV_BOTTOM) tower[row][col] = TB_STICK_BOTTOM;
753 else if (tower[row][col] == TB_STEP) tower[row][col] = TB_STICK;
754 }
lev_stick2platform(int row,int col)755 void lev_stick2platform(int row, int col) {
756 if (tower[row][col] == TB_STICK_TOP) tower[row][col] = TB_ELEV_TOP;
757 else if (tower[row][col] == TB_STICK_MIDDLE) tower[row][col] = TB_ELEV_MIDDLE;
758 else if (tower[row][col] == TB_STICK_BOTTOM) tower[row][col] = TB_ELEV_BOTTOM;
759 else if (tower[row][col] == TB_STICK_DOOR) tower[row][col] = TB_ELEV_DOOR;
760 else if (tower[row][col] == TB_STICK_DOOR_TARGET) tower[row][col] = TB_ELEV_DOOR_TARGET;
761 else if (tower[row][col] == TB_STICK) tower[row][col] = TB_STEP;
762 }
lev_stick2empty(int row,int col)763 void lev_stick2empty(int row, int col) {
764 if (tower[row][col] == TB_STICK_TOP) tower[row][col] = TB_STATION_TOP;
765 else if (tower[row][col] == TB_STICK_MIDDLE) tower[row][col] = TB_STATION_MIDDLE;
766 else if (tower[row][col] == TB_STICK_BOTTOM) tower[row][col] = TB_STATION_BOTTOM;
767 else if (tower[row][col] == TB_STICK_DOOR_TARGET) tower[row][col] = TB_DOOR_TARGET;
768 else if (tower[row][col] == TB_STICK_DOOR) tower[row][col] = TB_DOOR;
769 else if (tower[row][col] == TB_STICK) tower[row][col] = TB_EMPTY;
770 }
lev_empty2stick(int row,int col)771 void lev_empty2stick(int row, int col) {
772 if (tower[row][col] == TB_STATION_TOP) tower[row][col] = TB_STICK_TOP;
773 else if (tower[row][col] == TB_STATION_MIDDLE) tower[row][col] = TB_STICK_MIDDLE;
774 else if (tower[row][col] == TB_STATION_BOTTOM) tower[row][col] = TB_STICK_BOTTOM;
775 else if (tower[row][col] == TB_DOOR) tower[row][col] = TB_STICK_DOOR;
776 else if (tower[row][col] == TB_DOOR_TARGET) tower[row][col] = TB_STICK_DOOR_TARGET;
777 else if (tower[row][col] == TB_EMPTY) tower[row][col] = TB_STICK;
778 }
lev_platform2empty(int row,int col)779 void lev_platform2empty(int row, int col) {
780 if (tower[row][col] == TB_ELEV_TOP) tower[row][col] = TB_STATION_TOP;
781 else if (tower[row][col] == TB_ELEV_MIDDLE) tower[row][col] = TB_STATION_MIDDLE;
782 else if (tower[row][col] == TB_ELEV_BOTTOM) tower[row][col] = TB_STATION_BOTTOM;
783 else if (tower[row][col] == TB_ELEV_DOOR_TARGET) tower[row][col] = TB_DOOR_TARGET;
784 else if (tower[row][col] == TB_ELEV_DOOR) tower[row][col] = TB_DOOR;
785 else if (tower[row][col] == TB_STEP) tower[row][col] = TB_EMPTY;
786 }
787
788 /* misc questions */
lev_is_empty(int row,int col)789 bool lev_is_empty(int row, int col) {
790 return ((towerblockdata[tower[row][col]].tf & TBF_EMPTY));
791 }
792
lev_is_box(int row,int col)793 bool lev_is_box(int row, int col) {
794 return tower[row][col] == TB_BOX;
795 }
796
lev_is_sliding(int row,int col)797 int lev_is_sliding(int row, int col) {
798 return ((tower[row][col] == TB_STEP_LSLIDER) ? 1 :
799 (tower[row][col] == TB_STEP_RSLIDER) ? -1 :
800 0);
801 }
802
lev_is_robot(int row,int col)803 bool lev_is_robot(int row, int col) {
804 return ((towerblockdata[tower[row][col]].tf & TBF_ROBOT) != 0);
805 }
806
807
inside_cyclic_intervall(int x,int start,int end,int cycle)808 static bool inside_cyclic_intervall(int x, int start, int end, int cycle) {
809
810 while (x < start) x += cycle;
811 while (x >= end) x -= cycle;
812
813 return (x >= start) && (x < end);
814 }
815
816 #ifndef CREATOR
817
818 /* returns true, if the given figure can be at the given position
819 without colliding with fixed objects of the tower */
lev_testfigure(long angle,long vert,long back,long fore,long typ,long height,long width)820 bool lev_testfigure(long angle, long vert, long back,
821 long fore, long typ, long height, long width) {
822 long hinten, vorn, y, x = 0, k, t;
823
824 hinten = ((angle + back) >> 3) & 0xf;
825 vorn = (((angle + fore) >> 3) + 1) & 0xf;
826
827 y = vert / 4;
828 vert &= 3;
829
830 switch (typ) {
831
832 case 0: /* toppler */
833 x = (vert == 3) ? 3 : 2;
834 break;
835
836 case 1: /* robot */
837 x = (vert == 0) ? 1 : 2;
838 break;
839
840 case 2: /* snowball */
841 x = (vert == 0) ? 0 : 1;
842 break;
843 }
844
845 do {
846 k = x;
847 do {
848 if (lev_is_platform(k + y, hinten)) {
849 return false;
850 } else if (lev_is_stick(k + y, hinten)) {
851 t = hinten * 8 + height;
852 if (inside_cyclic_intervall(angle, t, t+width, 0x80))
853 return false;
854 } else if (lev_is_box(k + y, hinten)) {
855 t = hinten * 8 + height;
856 if (inside_cyclic_intervall(angle, t, t+width, 0x80)) {
857 if (typ == 2) {
858 // the snowball removes the box
859 lev_clear(k + y, hinten);
860 pts_add(50);
861 }
862 return false;
863 }
864 }
865 k--;
866 } while (k != -1);
867 hinten = (hinten + 1) & 0xf;
868 } while (hinten != vorn);
869
870 return true;
871 }
872
873 #endif
874
lev_putplatform(int row,int col)875 unsigned char lev_putplatform(int row, int col) {
876 unsigned char erg = tower[row][col];
877
878 tower[row][col] = TB_ELEV_BOTTOM;
879
880 return erg;
881 }
882
lev_restore(int row,int col,unsigned char bg)883 void lev_restore(int row, int col, unsigned char bg) {
884 tower[row][col] = bg;
885 }
886
887
888 /* load and save a tower */
lev_loadtower(const char * fname)889 bool lev_loadtower(const char *fname) {
890 FILE *in = open_local_data_file(fname);
891 char line[200];
892
893 if (in == NULL) return false;
894
895 lev_clear_tower();
896 lev_set_towerdemo(0, NULL);
897 towertime = 0;
898 towerheight = 0;
899 towerrobot = 0;
900
901 while (true) {
902
903 if (feof(in)) break;
904
905 /* look for next section start */
906 fgets(line, 200, in);
907 if (line[0] != '[')
908 continue;
909
910 if (strncmp(&line[1], tss_string_name, strlen(tss_string_name)) == 0) {
911 fgets(towername, TOWERNAMELEN+1, in);
912 /* remove not allowed characters */
913 {
914 int inp = 0;
915 int outp = 0;
916 while(towername[inp]) {
917 if ((towername[inp] >= 32) && (towername[inp] < 127))
918 towername[outp++] = towername[inp];
919 inp++;
920 }
921 towername[outp] = 0;
922 }
923 } else if (strncmp(&line[1], tss_string_color, strlen(tss_string_color)) == 0) {
924 fgets(line, 200, in);
925 sscanf(line, "%hhu, %hhu, %hhu\n", &towercolor_red, &towercolor_green, &towercolor_blue);
926 } else if (strncmp(&line[1], tss_string_time, strlen(tss_string_time)) == 0) {
927 fgets(line, 200, in);
928 sscanf(line, "%hu\n", &towertime);
929 } else if (strncmp(&line[1], tss_string_data, strlen(tss_string_data)) == 0) {
930
931 fgets(line, 200, in);
932 sscanf(line, "%hhu\n", &towerheight);
933
934 for (int row = towerheight - 1; row >= 0; row--) {
935
936 fgets(line, 200, in);
937
938 for (int col = 0; col < TOWERWID; col++)
939 tower[row][col] = conv_char2towercode(line[col]);
940 }
941 } else if (strncmp(&line[1], tss_string_demo, strlen(tss_string_demo)) == 0) {
942 if (fgets(line, 200, in)) {
943 sscanf(line, "%i\n", &towerdemo_len);
944
945 if (towerdemo_len > 0) {
946 towerdemo = new Uint16[towerdemo_len];
947
948 for (int idx = 0; idx < towerdemo_len; idx++) {
949 fgets(line, 200, in);
950 sscanf(line, "%hu\n", &towerdemo[idx]);
951 }
952 } else towerdemo = NULL;
953 }
954 } else if (strncmp(&line[1], tss_string_robot, strlen(tss_string_robot)) == 0) {
955 fgets(line, 200, in);
956 {
957 int i;
958 sscanf(line, "%u\n", &i);
959 #ifdef CREATOR
960 towerrobot = i & 0xFF;
961 #else
962 towerrobot = (i & 0xFF) % scr_numrobots();
963 #endif
964 }
965 }
966 }
967
968 fclose(in);
969 return true;
970 }
971
972 #ifndef CREATOR
973
lev_savetower(const char * fname)974 bool lev_savetower(const char *fname) {
975 FILE *out = create_local_data_file(fname);
976
977 if (out == NULL) return false;
978
979 fprintf(out, "[%s]\n", tss_string_name);
980 fprintf(out, "%s\n", towername);
981
982 fprintf(out, "[%s]\n", tss_string_color);
983 fprintf(out, "%hhu, %hhu, %hhu\n", towercolor_red, towercolor_green, towercolor_blue);
984
985 fprintf(out, "[%s]\n", tss_string_time);
986 fprintf(out, "%hu\n", towertime);
987
988 fprintf(out, "[%s]\n", tss_string_robot);
989 fprintf(out, "%hhu\n", towerrobot);
990
991 fprintf(out, "[%s]\n", tss_string_data);
992 fprintf(out, "%hhu\n", towerheight);
993 for (int row = towerheight - 1; row >= 0; row--) {
994 char line[TOWERWID+2];
995
996 for (int col = 0; col < TOWERWID; col++)
997 line[col] = conv_towercode2char(tower[row][col]);
998
999 line[TOWERWID] = '|';
1000 line[TOWERWID+1] = 0;
1001 fprintf(out, "%s\n", line);
1002 }
1003
1004 fprintf(out, "[%s]\n", tss_string_demo);
1005 fprintf(out, "%i\n", towerdemo_len);
1006 if (towerdemo && (towerdemo_len > 0)) {
1007 for (int idx = 0; idx < towerdemo_len; idx++) {
1008 fprintf(out, "%hu\n", towerdemo[idx]);
1009 }
1010 }
1011
1012 fclose(out);
1013
1014 return true;
1015 }
1016
1017 #endif
1018
1019 /* rotate row clock and counter clockwise */
lev_rotaterow(int row,bool clockwise)1020 void lev_rotaterow(int row, bool clockwise) {
1021 if (clockwise) {
1022 int k = tower[row][0];
1023 for (int i = 1; i < TOWERWID; i++)
1024 tower[row][i - 1] = tower[row][i];
1025 tower[row][TOWERWID-1] = k;
1026 } else {
1027 int k = tower[row][TOWERWID-1];
1028 for (int i = TOWERWID-1; i >= 0; i++)
1029 tower[row][i] = tower[row][i - 1];
1030 tower[row][0] = k;
1031 }
1032 }
1033
1034 /* insert and delete one row */
lev_insertrow(int position)1035 void lev_insertrow(int position) {
1036 if ((towerheight < 255) && (position < towerheight)) {
1037 int k = towerheight - 1;
1038 while (k >= position) {
1039 for (int i = 0; i < TOWERWID; i++)
1040 tower[k + 1][i] = tower[k][i];
1041 k--;
1042 }
1043 for (int i = 0; i < TOWERWID; i++)
1044 tower[position][i] = 0;
1045 towerheight++;
1046 return;
1047 }
1048 if (towerheight == 0) {
1049 for (int i = 0; i < TOWERWID; i++)
1050 tower[0][i] = 0;
1051 towerheight = 1;
1052 }
1053 }
1054
lev_deleterow(int position)1055 void lev_deleterow(int position) {
1056 if ((position < towerheight) && (position >= 0)) {
1057 int k = position + 1;
1058 while (k < towerheight) {
1059 for (int i = 0; i < TOWERWID; i++)
1060 tower[k - 1][i] = tower[k][i];
1061 k++;
1062 }
1063 towerheight--;
1064 }
1065 }
1066
lev_new(Uint8 hei)1067 void lev_new(Uint8 hei) {
1068 towerheight = hei;
1069 lev_clear_tower();
1070 }
1071
lev_putspace(int row,int col)1072 void lev_putspace(int row, int col) {
1073
1074 // always delete the whole door
1075 if (lev_is_door(row, col)) {
1076 int r = row - 1;
1077 while (lev_is_door(r, col)) {
1078 tower[r][col] = TB_EMPTY;
1079 r--;
1080 }
1081 r = row + 1;
1082 while (lev_is_door(r, col)) {
1083 tower[r][col] = TB_EMPTY;
1084 r++;
1085 }
1086 }
1087 tower[row][col] = TB_EMPTY;
1088 }
lev_putrobot1(int row,int col)1089 void lev_putrobot1(int row, int col) { tower[row][col] = TB_ROBOT1; }
lev_putrobot2(int row,int col)1090 void lev_putrobot2(int row, int col) { tower[row][col] = TB_ROBOT2; }
lev_putrobot3(int row,int col)1091 void lev_putrobot3(int row, int col) { tower[row][col] = TB_ROBOT3; }
lev_putrobot4(int row,int col)1092 void lev_putrobot4(int row, int col) { tower[row][col] = TB_ROBOT4; }
lev_putrobot5(int row,int col)1093 void lev_putrobot5(int row, int col) { tower[row][col] = TB_ROBOT5; }
lev_putrobot6(int row,int col)1094 void lev_putrobot6(int row, int col) { tower[row][col] = TB_ROBOT6; }
lev_putrobot7(int row,int col)1095 void lev_putrobot7(int row, int col) { tower[row][col] = TB_ROBOT7; }
lev_putstep(int row,int col)1096 void lev_putstep(int row, int col) { tower[row][col] = TB_STEP; }
lev_putvanishingstep(int row,int col)1097 void lev_putvanishingstep(int row, int col) { tower[row][col] = TB_STEP_VANISHER; }
lev_putslidingstep_left(int row,int col)1098 void lev_putslidingstep_left(int row, int col) { tower[row][col] = TB_STEP_LSLIDER; }
lev_putslidingstep_right(int row,int col)1099 void lev_putslidingstep_right(int row, int col) { tower[row][col] = TB_STEP_RSLIDER; }
1100
lev_putdoor(int row,int col)1101 void lev_putdoor(int row, int col) {
1102
1103 if (row + 2 < towerheight) {
1104
1105 tower[row][col] = TB_DOOR;
1106 tower[row + 1][col] = TB_DOOR;
1107 tower[row + 2][col] = TB_DOOR;
1108
1109 if ((tower[row][(col + (TOWERWID/2)) % TOWERWID] == 0) &&
1110 (tower[row + 1][(col + (TOWERWID/2)) % TOWERWID] == 0) &&
1111 (tower[row + 2][(col + (TOWERWID/2)) % TOWERWID] == 0)) {
1112 tower[row][(col + (TOWERWID/2)) % TOWERWID] = TB_DOOR;
1113 tower[row + 1][(col + (TOWERWID/2)) % TOWERWID] = TB_DOOR;
1114 tower[row + 2][(col + (TOWERWID/2)) % TOWERWID] = TB_DOOR;
1115 }
1116 }
1117 }
1118
lev_puttarget(int row,int col)1119 void lev_puttarget(int row, int col) {
1120 if (row + 2 < towerheight) {
1121 tower[row][col] = TB_DOOR_TARGET;
1122 tower[row + 1][col] = TB_DOOR_TARGET;
1123 tower[row + 2][col] = TB_DOOR_TARGET;
1124 }
1125 }
1126
lev_putstick(int row,int col)1127 void lev_putstick(int row, int col) { tower[row][col] = TB_STICK; }
lev_putbox(int row,int col)1128 void lev_putbox(int row, int col) { tower[row][col] = TB_BOX; }
lev_putelevator(int row,int col)1129 void lev_putelevator(int row, int col) { tower[row][col] = TB_ELEV_BOTTOM; }
lev_putmiddlestation(int row,int col)1130 void lev_putmiddlestation(int row, int col) { tower[row][col] = TB_STATION_MIDDLE; }
lev_puttopstation(int row,int col)1131 void lev_puttopstation(int row, int col) { tower[row][col] = TB_STATION_TOP; }
1132
1133
lev_save(unsigned char * & data)1134 void lev_save(unsigned char *&data) {
1135 data = new unsigned char[256*TOWERWID+1];
1136
1137 data[0] = towerheight;
1138 memmove(&data[1], tower, 256 * TOWERWID);
1139 }
1140
lev_restore(unsigned char * & data)1141 void lev_restore(unsigned char *&data) {
1142 memmove(tower, &data[1], 256 * TOWERWID);
1143 towerheight = data[0];
1144
1145 delete [] data;
1146 }
1147
lev_is_consistent(int & row,int & col)1148 lev_problem lev_is_consistent(int &row, int &col) {
1149
1150 int y;
1151 bool has_exit = false;
1152 // check first, if the starting point is correctly organized
1153 // so that there is no obstacle and we can survive there
1154 if ((tower[1][0] != TB_STICK) && (tower[1][0] != TB_STEP) &&
1155 (tower[1][0] != TB_STEP_LSLIDER) && (tower[1][0] != TB_STEP_RSLIDER) &&
1156 (tower[1][0] != TB_BOX) &&
1157 (tower[1][0] != TB_ELEV_BOTTOM) &&
1158 (tower[0][0] != TB_STICK) && (tower[0][0] != TB_STEP) &&
1159 (tower[0][0] != TB_STEP_LSLIDER) && (tower[0][0] != TB_STEP_RSLIDER) &&
1160 (tower[0][0] != TB_BOX) &&
1161 (tower[0][0] != TB_ELEV_BOTTOM)) {
1162 row = 1;
1163 col = 0;
1164 return TPROB_NOSTARTSTEP;
1165 }
1166 for (y = 2; y < 5; y++)
1167 if ((towerblockdata[tower[y][0]].tf & TBF_DEADLY) ||
1168 !(towerblockdata[tower[y][0]].tf & TBF_EMPTY)) {
1169 row = y;
1170 col = 0;
1171 return TPROB_STARTBLOCKED;
1172 }
1173
1174 if (towerheight < 4) return TPROB_SHORTTOWER;
1175
1176 for (int r = 0; r < towerheight; r++)
1177 for (int c = 0; c < TOWERWID; c++) {
1178 // check for undefined symbols
1179 if (tower[r][c] >= NUM_TBLOCKS) {
1180 row = r;
1181 col = c;
1182 return TPROB_UNDEFBLOCK;
1183 }
1184
1185 // check if elevators always have an opposing end without unremovable
1186 // obstacles
1187 if (tower[r][c] == TB_ELEV_BOTTOM) {
1188 int d = r + 1;
1189 while ((tower[d][c] != TB_STATION_TOP) && (d < towerheight)) {
1190 if ((tower[d][c] != TB_EMPTY) &&
1191 (tower[d][c] != TB_ROBOT1) &&
1192 (tower[d][c] != TB_ROBOT2) &&
1193 (tower[d][c] != TB_ROBOT3) &&
1194 (tower[d][c] != TB_ROBOT4) &&
1195 (tower[d][c] != TB_ROBOT5) &&
1196 (tower[d][c] != TB_ROBOT6) &&
1197 (tower[d][c] != TB_ROBOT7) &&
1198 (tower[d][c] != TB_BOX) &&
1199 (tower[d][c] != TB_STATION_MIDDLE) &&
1200 (tower[d][c] != TB_STEP_VANISHER) &&
1201 (tower[d][c] != TB_DOOR) &&
1202 (tower[d][c] != TB_DOOR_TARGET)) {
1203 row = r;
1204 col = c;
1205 return TPROB_ELEVATORBLOCKED;
1206 }
1207 d++;
1208 }
1209 if (d >= towerheight) {
1210 row = r;
1211 col = c;
1212 return TPROB_NOELEVATORSTOP;
1213 }
1214 }
1215
1216 if (tower[r][c] == TB_STATION_MIDDLE) {
1217 int d = r + 1;
1218 while ((tower[d][c] != TB_STATION_TOP) && (d < towerheight)) {
1219 if ((tower[d][c] != TB_EMPTY) &&
1220 (tower[d][c] != TB_ROBOT1) &&
1221 (tower[d][c] != TB_ROBOT2) &&
1222 (tower[d][c] != TB_ROBOT3) &&
1223 (tower[d][c] != TB_ROBOT4) &&
1224 (tower[d][c] != TB_ROBOT5) &&
1225 (tower[d][c] != TB_ROBOT6) &&
1226 (tower[d][c] != TB_ROBOT7) &&
1227 (tower[d][c] != TB_BOX) &&
1228 (tower[d][c] != TB_STATION_MIDDLE) &&
1229 (tower[d][c] != TB_DOOR) &&
1230 (tower[d][c] != TB_DOOR_TARGET) &&
1231 (tower[d][c] != TB_STEP_VANISHER)) {
1232 row = r;
1233 col = c;
1234 return TPROB_ELEVATORBLOCKED;
1235 }
1236 d++;
1237 }
1238 if (d >= towerheight) {
1239 row = r;
1240 col = c;
1241 return TPROB_NOELEVATORSTOP;
1242 }
1243 d = r - 1;
1244 while ((tower[d][c] != TB_ELEV_BOTTOM) && (d >= 0)) {
1245 if ((tower[d][c] != TB_EMPTY) &&
1246 (tower[d][c] != TB_ROBOT1) &&
1247 (tower[d][c] != TB_ROBOT2) &&
1248 (tower[d][c] != TB_ROBOT3) &&
1249 (tower[d][c] != TB_ROBOT4) &&
1250 (tower[d][c] != TB_ROBOT5) &&
1251 (tower[d][c] != TB_ROBOT6) &&
1252 (tower[d][c] != TB_ROBOT7) &&
1253 (tower[d][c] != TB_BOX) &&
1254 (tower[d][c] != TB_STATION_MIDDLE) &&
1255 (tower[d][c] != TB_DOOR) &&
1256 (tower[d][c] != TB_DOOR_TARGET) &&
1257 (tower[d][c] != TB_STEP_VANISHER)) {
1258 row = r;
1259 col = c;
1260 return TPROB_ELEVATORBLOCKED;
1261 }
1262 d--;
1263 }
1264 if (d < 0) {
1265 row = r;
1266 col = c;
1267 return TPROB_NOELEVATORSTOP;
1268 }
1269 }
1270
1271 if (tower[r][c] == TB_STATION_TOP) {
1272 int d = r - 1;
1273 while ((tower[d][c] != TB_ELEV_BOTTOM) && (d >= 0)) {
1274 if ((tower[d][c] != TB_EMPTY) &&
1275 (tower[d][c] != TB_ROBOT1) &&
1276 (tower[d][c] != TB_ROBOT2) &&
1277 (tower[d][c] != TB_ROBOT3) &&
1278 (tower[d][c] != TB_ROBOT4) &&
1279 (tower[d][c] != TB_ROBOT5) &&
1280 (tower[d][c] != TB_ROBOT6) &&
1281 (tower[d][c] != TB_ROBOT7) &&
1282 (tower[d][c] != TB_BOX) &&
1283 (tower[d][c] != TB_STATION_MIDDLE) &&
1284 (tower[d][c] != TB_DOOR) &&
1285 (tower[d][c] != TB_DOOR_TARGET) &&
1286 (tower[d][c] != TB_STEP_VANISHER)) {
1287 row = r;
1288 col = c;
1289 return TPROB_ELEVATORBLOCKED;
1290 }
1291 d--;
1292 }
1293 if (d < 0) {
1294 row = r;
1295 col = c;
1296 return TPROB_NOELEVATORSTOP;
1297 }
1298 }
1299
1300 /* check for exit, and that it's reachable */
1301 if (tower[r][c] == TB_DOOR_TARGET) {
1302 int d = r - 1;
1303
1304 if (d < 0) {
1305 row = 0;
1306 col = c;
1307 return TPROB_UNREACHABLEEXIT;
1308 }
1309
1310 while ((d >= 0) && (tower[d][c] == TB_DOOR_TARGET)) d--;
1311 if (d >= 0) {
1312 if ((tower[d][c] != TB_STICK) && (tower[d][c] != TB_STEP) &&
1313 (tower[d][c] != TB_BOX) && (tower[d][c] != TB_ELEV_BOTTOM) &&
1314 (tower[d][c] != TB_STICK)) {
1315 row = r;
1316 col = c;
1317 return TPROB_UNREACHABLEEXIT;
1318 }
1319 }
1320 has_exit = true;
1321 }
1322
1323 // check doors
1324 if ((tower[r][c] == TB_DOOR) &&
1325 !lev_is_door(r, (c + (TOWERWID/2)) % TOWERWID)) {
1326 row = r;
1327 col = c;
1328 return TPROB_NOOTHERDOOR;
1329 }
1330 if (lev_is_door(r,c)) {
1331 bool A = (r > 0) && (tower[r-1][c] == tower[r][c]);
1332 bool B = (r > 1) && (tower[r-2][c] == tower[r][c]);
1333 bool D = (r + 1 < towerheight) && (tower[r+1][c] == tower[r][c]);
1334 bool E = (r + 2 < towerheight) && (tower[r+2][c] == tower[r][c]);
1335
1336 if (!((A&&B)||(A&&D)||(D&&E))) {
1337 row = r;
1338 col = c;
1339 return TPROB_BROKENDOOR;
1340 }
1341 }
1342 }
1343
1344 if (!has_exit) return TPROB_NOEXIT;
1345
1346 /* other, non-tower related problems */
1347 if (lev_towertime() < 5) return TPROB_SHORTTIME;
1348 if (!strlen(lev_towername())) return TPROB_NONAME;
1349
1350 return TPROB_NONE;
1351 }
1352
1353 /* the functions for mission creation */
1354
1355 static FILE * fmission = NULL;
1356 static Uint8 nmission = 0;
1357 static Uint32 missionidx[256];
1358
lev_mission_new(char * name,Uint8 prio)1359 bool lev_mission_new(char * name, Uint8 prio) {
1360 assert_msg(!fmission, "called mission_finish twice");
1361
1362 char fname[200];
1363 snprintf(fname, 200, "%s.ttm", name);
1364
1365 fmission = create_local_data_file(fname);
1366
1367 if (!fmission) return false;
1368
1369 unsigned char tmp = strlen(name);
1370
1371 /* write out name */
1372 fwrite(&tmp, 1 ,1, fmission);
1373 fwrite(name, 1, tmp, fmission);
1374
1375 fwrite(&prio, 1, 1, fmission);
1376
1377 /* placeholders for towernumber and indexstart */
1378 fwrite(&tmp, 1, 1, fmission);
1379 fwrite(&tmp, 1, 4, fmission);
1380
1381 nmission = 0;
1382
1383 return true;
1384 }
1385
write_fmission_section(Uint8 section,Uint32 section_len)1386 void write_fmission_section(Uint8 section, Uint32 section_len) {
1387 Uint8 tmp;
1388 fwrite(§ion, 1, 1, fmission);
1389
1390 tmp = section_len & 0xff;
1391 fwrite(&tmp, 1, 1, fmission);
1392 tmp = (section_len >> 8) & 0xff;
1393 fwrite(&tmp, 1, 1, fmission);
1394 tmp = (section_len >> 16) & 0xff;
1395 fwrite(&tmp, 1, 1, fmission);
1396 tmp = (section_len >> 24) & 0xff;
1397 fwrite(&tmp, 1, 1, fmission);
1398 }
1399
lev_mission_addtower(char * name)1400 void lev_mission_addtower(char * name) {
1401 assert_msg(fmission, "called mission_addtower without mission_new");
1402
1403 Uint8 rows, col;
1404 Sint16 row;
1405 Uint8 namelen, tmp;
1406 Uint32 section_len;
1407 int idx;
1408
1409 missionidx[nmission] = ftell(fmission);
1410 nmission++;
1411
1412 if (!lev_loadtower(name)) return;
1413
1414 namelen = strlen(towername);
1415 write_fmission_section(TSS_TOWERNAME, namelen);
1416 fwrite(towername, 1, namelen, fmission);
1417
1418 write_fmission_section(TSS_ROBOT, 1);
1419 fwrite(&towerrobot, 1, 1, fmission);
1420
1421 write_fmission_section(TSS_TOWERTIME, 2);
1422 tmp = towertime & 0xff;
1423 fwrite(&tmp, 1, 1, fmission);
1424 tmp = (towertime >> 8) & 0xff;
1425 fwrite(&tmp, 1, 1, fmission);
1426
1427 write_fmission_section(TSS_TOWERCOLOR, 3);
1428 fwrite(&towercolor_red, 1, 1, fmission);
1429 fwrite(&towercolor_green, 1, 1, fmission);
1430 fwrite(&towercolor_blue, 1, 1, fmission);
1431
1432 rows = towerheight;
1433
1434 /* calculate tower data section length */
1435 section_len = 2*towerheight;
1436 for (row = 0; row < rows; row++)
1437 for (col = 0; col < TOWERWID; col++)
1438 if (tower[row][col]) section_len++;
1439 write_fmission_section(TSS_TOWERDATA, section_len + 1);
1440
1441
1442 fwrite(&towerheight, 1, 1, fmission);
1443
1444 /* output bitmap */
1445 for (row = 0; row < rows; row++) {
1446
1447 Uint8 c = 0;
1448 for (col = 0; col < 8; col ++)
1449 if (tower[row][col])
1450 c |= (0x80 >> col);
1451
1452 fwrite(&c, 1, 1, fmission);
1453
1454 c = 0;
1455 for (col = 0; col < 8; col ++)
1456 if (tower[row][col + 8])
1457 c |= (0x80 >> col);
1458
1459 fwrite(&c, 1, 1, fmission);
1460 }
1461
1462 /* output bytemap */
1463 for (row = 0; row < rows; row++)
1464 for (col = 0; col < TOWERWID; col++)
1465 if (tower[row][col])
1466 fwrite(&tower[row][col], 1, 1, fmission);
1467
1468 /* output towerdemo */
1469
1470 if (towerdemo && (towerdemo_len > 0)) {
1471 Uint8 run;
1472 Uint16 data;
1473
1474 /* calc data length */
1475 run = 1;
1476 data = towerdemo[0];
1477 section_len = 2;
1478
1479 for (idx = 1; idx < towerdemo_len; idx++) {
1480 if ((data != towerdemo[idx]) || (run == 0xff)) {
1481 section_len += 3;
1482
1483 data = towerdemo[idx];
1484 run = 1;
1485 } else
1486 run ++;
1487 }
1488 if (run) section_len += 3;
1489
1490 write_fmission_section(TSS_DEMO, section_len);
1491
1492 /* output length */
1493 tmp = towerdemo_len & 0xff;
1494 fwrite(&tmp, 1, 1, fmission);
1495 tmp = (towerdemo_len >> 8) & 0xff;
1496 fwrite(&tmp, 1, 1, fmission);
1497
1498 /* output data using a simple runlength encoder */
1499 run = 1;
1500 data = towerdemo[0];
1501
1502 for (idx = 1; idx < towerdemo_len; idx++) {
1503 if ((data != towerdemo[idx]) || (run == 0xff)) {
1504 fwrite(&run, 1, 1, fmission);
1505 tmp = data & 0xff;
1506 fwrite(&tmp, 1, 1, fmission);
1507 tmp = (data >> 8) & 0xff;
1508 fwrite(&tmp, 1, 1, fmission);
1509
1510 data = towerdemo[idx];
1511 run = 1;
1512 } else
1513 run ++;
1514 }
1515
1516 if (run) {
1517 fwrite(&run, 1, 1, fmission);
1518 tmp = data & 0xff;
1519 fwrite(&tmp, 1, 1, fmission);
1520 tmp = (data >> 8) & 0xff;
1521 fwrite(&tmp, 1, 1, fmission);
1522 }
1523 }
1524
1525 write_fmission_section(TSS_END, 0);
1526 }
1527
lev_mission_finish()1528 void lev_mission_finish() {
1529 assert_msg(fmission, "called mission_finish without mission_new");
1530
1531 Uint8 c;
1532
1533 /* save indexstart and write out index */
1534 Uint32 idxpos = ftell(fmission);
1535 for (Uint8 i = 0; i < nmission; i++) {
1536
1537 c = missionidx[i] & 0xff;
1538 fwrite(&c, 1, 1, fmission);
1539 c = (missionidx[i] >> 8) & 0xff;
1540 fwrite(&c, 1, 1, fmission);
1541 c = (missionidx[i] >> 16) & 0xff;
1542 fwrite(&c, 1, 1, fmission);
1543 c = (missionidx[i] >> 24) & 0xff;
1544 fwrite(&c, 1, 1, fmission);
1545 }
1546
1547 /* write out the number of towers in this mission */
1548 fseek(fmission, 0, SEEK_SET);
1549 fread(&c, 1, 1, fmission);
1550
1551 fseek(fmission, c + 2, SEEK_SET);
1552 fwrite(&nmission, 1, 1, fmission);
1553
1554 /* write out index position */
1555 c = idxpos & 0xff;
1556 fwrite(&c, 1, 1, fmission);
1557 c = (idxpos >> 8) & 0xff;
1558 fwrite(&c, 1, 1, fmission);
1559 c = (idxpos >> 16) & 0xff;
1560 fwrite(&c, 1, 1, fmission);
1561 c = (idxpos >> 24) & 0xff;
1562 fwrite(&c, 1, 1, fmission);
1563
1564 fclose(fmission);
1565
1566 fmission = NULL;
1567 }
1568
1569