1 #include "ladder.h"
2 
3 static struct
4 {
5     int row, col;           /* current coordinates */
6     int st_row, st_col;     /* start coordinates */
7     DIR dir;
8     int jst;
9 } lad;
10 
11 static char laddirs[] = "gbdqp";
12 
13 typedef struct
14 {
15     int row, col;
16     DIR dir;
17     int launch;
18 } DER;
19 static DER *ders = 0;
20 
21 typedef struct { int row, col; } RELEASE;
22 static RELEASE releases[3];
23 static int bonus;
24 static char bg[DIMROW][DIMCOL];
25 
26 /* these extra "00" in score & bonus are extremly silly -
27    but that is how the original did it */
stat_lads()28 static void stat_lads()     { mvprintw(DIMROW,0,"Lads  %3d",lads); }
stat_level()29 static void stat_level()    { mvprintw(DIMROW,14,"Level  %3d",level + 1); }
stat_score()30 static void stat_score()    { mvprintw(DIMROW,29,"Score  %4d00",score); }
stat_bonus()31 static void stat_bonus()    { mvprintw(DIMROW,59,"Bonus time  %4d00",bonus); }
32 
add_score(int add)33 static void add_score(int add)
34 {
35     if( score / 100 < (score + add) / 100 )
36         lads++, stat_lads();
37     score += add;
38     stat_score();
39 }
40 
ldscreen(void)41 static void ldscreen(void)
42 {
43     int row,i;
44     RELEASE *rel = releases;
45     char *s,*t;
46 
47     memset(bg,' ',sizeof(bg));
48     for( row = 0; row < DIMROW; row++ )
49     {
50         s = screens[scrno][row];
51         t = bg[row];
52         memcpy(t,unmerge(s),strlen(unmerge(s)));
53         t[DIMCOL-1] = '\0';
54         mvaddstr(row,0,t);
55 
56         /* find points of release */
57         for( s = t; (s = strchr(s,CRELEAS)); s++ )
58         {
59             rel->row = row;
60             rel->col = s - t;
61             rel++;
62         }
63     }
64     /* mark the rest of releases */
65     for( ; rel < &releases[DIM(releases)]; rel++ )
66         rel->row = rel->col = EOF;
67 
68     /* find lad */
69     for( row = 0; row < DIMROW; row++ )
70         for( s = t = bg[row]; (s = strchr(s,CLAD)); s++ )
71         {
72             /* nasty, check for CLAD's surrounded by CFREEs */
73             if( s[-1] != CFREE || s[1] != CFREE )
74                 continue;
75             lad.row = lad.st_row = row;
76             lad.col = lad.st_col = s - t;
77             lad.dir = NONE;
78             lad.jst = 0;
79             bg[lad.row][lad.col] = CFREE;
80             break;
81         }
82 
83     /* init ders */
84     if( !ders )
85     {
86         int hi = -1;
87         for( i = 0; i < DIMSCRN; i++ )
88             if( hi < hiders[i] )
89                 hi = hiders[i];
90         ders = malloc(sizeof(DER) * (hi + 1));
91         ders[hi].row = EOF;
92     }
93     for( i = 0; i < hiders[scrno]; i++ )
94     {
95         ders[i].launch = i + 1;
96         ders[i].dir = XDOWN;
97     }
98     for( ; ders[i].row != EOF; i++ )
99         ders[i].launch = -1;
100 
101     move(LINES - 1, 0);
102     refresh();
103 }
104 
reldscreen(void)105 static void reldscreen(void)
106 {
107     int row,i;
108 
109     for( row = 0; row < DIMROW; row++ )
110         mvaddstr(row,0,bg[row]);
111 
112     /* deal with lad */
113     lad.row = lad.st_row;
114     lad.col = lad.st_col;
115     lad.dir = NONE;
116     lad.jst = 0;
117     mvaddch(lad.row,lad.col,CLAD);
118 
119     /* deal with ders */
120     for( i = 0; i < hiders[scrno]; i++ )
121     {
122         ders[i].launch = i + 1;
123         ders[i].dir = XDOWN;
124     }
125 
126     move(LINES - 1, 0);
127     refresh();
128 }
129 
130 #define SOLID(C)    ((C) == CBAR || (C) == CGROUND || (C) == CTRAP1)
131 
132 /* drive a single der, tell whether it left the board or hit lad */
drv_der(DER * dp)133 static RESULT drv_der(DER *dp)
134 {
135 #define LorR    dchoice[rand() % 2]
136 #define LorRorD dchoice[rand() % 3]
137 
138     static DIR dchoice[] = {LEFT,RIGHT,XDOWN};
139     int row = dp->row,
140         col = dp->col;
141     DIR dir = dp->dir;
142     char c;
143 
144     c = bg[row][col];       /* restore prev content */
145     mvaddch(row,col,c);
146     if( c == CEXIT )
147         return EXIT;
148     for( ;; )
149     {
150         if( dir == XDOWN )
151         {
152             c = bg[row + 1][col];
153             if( SOLID(c) )
154             {
155                 dir = LorR;
156                 continue;
157             }
158             row++;
159             break;
160         }
161         if( dir == LEFT )
162         {
163             if( col == 0 || bg[row][col - 1] == CBAR )
164             {
165                 dir = RIGHT;
166                 continue;
167             }
168             col--;
169         }
170         if( dir == RIGHT )
171         {
172             if( col == DIMCOL - 2 || bg[row][col + 1] == CBAR )
173             {
174                 dir = LEFT;
175                 continue;
176             }
177             col++;
178         }
179         if( bg[row][col] == CLADDER )
180             dir = LorRorD;
181         else
182         {
183             c = bg[row + 1][col];
184             if( !SOLID(c) )
185                 dir = XDOWN;
186         }
187         break;
188     }
189     c = mvinch(row,col);
190     addch(CDER);
191     dp->row = row;
192     dp->col = col;
193     dp->dir = dir;
194     return strchr(laddirs,c) ? DEAD : NORMAL;
195 
196 #undef  LorR
197 #undef  LorRorD
198 }
199 
drv_ders(void)200 static RESULT drv_ders(void)
201 {
202     DER *derp;
203     for( derp = ders; derp->row != EOF; derp++ )
204     {
205         if( derp->launch == -1 )
206             continue;
207         if( derp->launch == 0 )
208         {
209             RESULT result = drv_der(derp);
210             if( result == DEAD )
211                 return DEAD;
212             if( result == EXIT )
213                 derp->launch = 5;       /* set new start time */
214             continue;
215         }
216         if( --derp->launch == 0 )
217             /* select a point of release */
218             for( ;; )
219             {
220                 int n = rand() % DIM(releases);
221                 if( releases[n].row != EOF )
222                 {
223                     derp->row = releases[n].row;
224                     derp->col = releases[n].col;
225                     derp->dir = XDOWN;
226                     break;
227                 }
228             }
229     }
230     return NOTHING_HAPPENED;
231 }
232 
lad_died(void)233 static void lad_died(void)
234 {
235     int i,j;
236     static char rot[] = "b+d+q+p+";
237     ctnplay();
238     for( i = 0; i < 5; i++ )
239         for( j = 0; j < DIM(rot) - 1; j++ )
240         {
241             mvaddch(lad.row,lad.col,rot[j]);
242             move(LINES - 1,0);
243             refresh();
244             waitct();
245         }
246 }
247 
do_the_hooka(void)248 static void do_the_hooka(void)
249 {
250     for( bonus-- ; bonus >= 0; bonus-- )
251     {
252         add_score(1);
253         stat_bonus();
254         move(DIMROW + 2,0);
255         if( bonus & 1 )
256             addstr("Hooka!");
257         else
258             clrtoeol();
259         move(LINES - 1,0);
260         refresh();
261         waitct();
262     }
263 }
264 
pause(void)265 static void pause(void)
266 {
267     mvaddstr(DIMROW + 2,0,"Type RETURN to continue: ");
268     refresh();
269     nodelay(stdscr,FALSE);
270     while( getch() != '\n' )
271         ;
272     nodelay(stdscr,TRUE);
273     move(DIMROW + 2,0);
274     clrtoeol();
275 
276 }
277 
over_der(int row,int col)278 static void over_der(int row,int col)
279 {
280     /* Funny how lad jumps over "Sc`o're" - avoid it? Na. */
281     if( mvinch(row + 1,col) == CDER || mvinch(row + 2,col) == CDER )
282         add_score(2);
283 }
284 
drv_lad(void)285 static RESULT drv_lad(void)
286 {
287     int row = lad.row;
288     int col = lad.col;
289     DIR dir = lad.dir;
290     int jst = lad.jst;
291     char c0,c1;
292     int ch;
293 
294     while((ch = getch()) != ERR )
295     {
296      switch(ch)
297      {
298         case ERR:   /* no key */
299             break;
300 
301         case 'h':
302         case '4':
303         case KEY_LEFT:
304             dir = LEFT;
305             break;
306 
307         case 'l':
308         case '6':
309         case KEY_RIGHT:
310             dir = RIGHT;
311             break;
312 
313         case 'k':
314         case '8':
315         case KEY_UP:
316             if( !jst )
317                 dir = XUP;
318             break;
319 
320         case 'j':
321         case '2':
322         case KEY_DOWN:
323             if( !jst )
324                 dir = XDOWN;
325             break;
326 
327         case ' ':
328             if( !jst )      /* not while we're jumping */
329                 jst = 1;
330             break;
331 
332         case 'R'-'@':
333         case 'L'-'@':
334         case KEY_CLEAR:
335             wrefresh(curscr);
336             break;
337 
338         case '['-'@':
339             return PAUSE;
340 
341         case 'C'-'@':       /* who does set INTR to ^C, anyway? */
342             for( ; lads >= 1; lads-- )
343             {
344                 stat_lads();
345                 move(LINES - 1, 0);
346                 refresh();
347                 waitct();
348             }
349             lads = 1;
350             return DEAD;
351 
352         default:
353             dir = STOP;
354      }
355     }
356 
357     c0 = bg[row][col];
358     c1 = bg[row + 1][col];
359     if( jst < 2 && !SOLID(c1) && c0 != CLADDER && !(jst == 1 && c0 == CHAZARD) )
360     {
361         /* then fall */
362         jst = 0;        /* no request for jumping */
363         row++;
364     }
365     else
366         if( jst >= 1 )   /* request for or within a jump */
367         {
368             if( jst == 1 && c1 == CFREE && c0 != CHAZARD )
369                 jst = 0;
370             else
371             {
372                 static jra[7] = { 0, -1, -1, 0, 0, 1, 1 };
373                 int jc,jr;
374 
375                 over_der(row,col);
376                 if( dir == XUP || dir == XDOWN )
377                     dir = STOP;
378                 for( ; jst != 7; jst++ )
379                 {
380                     jr = jra[jst];
381                     jc = dir == STOP ? 0 : (dir == LEFT ? -1 : 1);
382                     c0 = bg[row + jr][col + jc];
383                     if( c0 != CBAR && c0 != CGROUND && !(jr == 1 && c0 == CTRAP1) )
384                     {
385                         if( (row += jr) < 0 || row > DIMROW - 2 )
386                             row -= jr;
387                         if( (col += jc) < 0 || col > DIMCOL - 2 )
388                             col -= jc;
389                         break;
390                     }
391                 }
392                 if( ++jst >= 7 )
393                     jst = 0;
394                 if( bg[row][col] == CLADDER )
395                 {
396                     jst = 0;
397                     dir = STOP;
398                 }
399                 if( dir != STOP )
400                     over_der(row,col);
401             }
402         }
403         else
404         {
405             if( c1  == CTRAP1 )
406                 mvaddch(row + 1,col,bg[row + 1][col] = CFREE);
407             switch( dir )
408             {
409                 case LEFT:
410                     c1 = bg[row][col - 1];
411                     if( col != 0 && c1 != CBAR && c1 != CGROUND )
412                         col--;
413                     else
414                         dir = STOP;
415                     break;
416                 case RIGHT:
417                     c1 = bg[row][col + 1];
418                     if( col != DIMCOL - 2 && c1 != CBAR && c1 != CGROUND )
419                         col++;
420                     else
421                         dir = STOP;
422                     break;
423                 case XUP:
424                     if( c0 == CLADDER &&
425                         ((c0 = bg[row - 1][col]) == CLADDER || c0 == CTARGET) )
426                         row--;
427                     else
428                         dir = STOP;
429                     break;
430                 case XDOWN:
431                     if( c0 == CLADDER && c1 != CGROUND )
432                         row++;
433                     else
434                         dir = STOP;
435                     break;
436 				default:
437 					break;
438             }
439         }
440 
441     if( lad.row != row || lad.col != col || lad.dir != dir || lad.jst != jst )
442     {
443         mvaddch(lad.row,lad.col,bg[lad.row][lad.col]);
444         {
445             /* remove rubbish */
446             static char s[] = {CGOLD,CRELEAS,CLADDER,CTARGET,
447                 CEXIT,CBAR,CGROUND,CHAZARD,CTRAP0,CTRAP1,CFREE};
448             if( !strchr(s,bg[row][col]) )
449                 mvaddch(row,col,bg[row][col] = CFREE);
450         }
451         /* check for anything that matters */
452         if( bg[row][col] == CGOLD )
453         {
454             mvaddch(row,col,bg[row][col] = CFREE);
455             add_score(bonus);
456         }
457         if( bg[row][col] == CHAZARD )
458         {
459             dir = rand() & 1 ? LEFT : RIGHT;
460             jst = rand() & 1;
461         }
462         lad.row = row;
463         lad.col = col;
464         lad.dir = dir;
465         lad.jst = jst;
466         if( mvinch(row,col) == CDER )
467             return DEAD;
468         addch(laddirs[dir]);
469     }
470     switch( bg[row][col] )
471     {
472         case CTARGET:
473             return FINISH;
474         case CTRAP0:
475             return DEAD;
476     }
477     return NORMAL;
478 }
479 
lplay(void)480 RESULT lplay(void)
481 {
482     int tick;
483     RESULT result;
484 
485     ldscreen();
486 
487     while( lads > 0 )
488     {
489         bonus = boni[scrno];
490         ctplay();
491         stat_lads();
492         stat_level();
493         stat_score();
494         stat_bonus();
495         mvaddstr(DIMROW + 2,0,"Get ready! ");
496         refresh();
497         for( tick = 7; tick; tick-- )
498             waitct();
499         move(DIMROW + 2,0);
500         clrtoeol();
501 
502         for( tick = 20 * bonus; tick; tick-- )
503         {
504             if( !((tick - 1) % 20) )
505             {
506                 bonus--;
507                 stat_bonus();
508             }
509             if( (result = drv_ders()) != DEAD )
510                 result = drv_lad();
511             move(LINES - 1,0);
512             refresh();
513             waitct();
514             if( result == PAUSE )
515                 pause(),
516                 result = NORMAL;
517             if( result != NORMAL )
518                 break;
519         }
520         if( !tick )
521             result = DEAD;
522         if( result == DEAD )
523         {
524             lads--;
525             stat_lads();
526             lad_died();
527         }
528         if( result == FINISH )
529         {
530             do_the_hooka();
531             return NORMAL;
532         }
533         reldscreen();
534     }
535     return DEAD;
536 }
537