added key shortcuts to restart and replay/resume (before end) the game
[rocksndiamonds.git] / src / game_sp / SnikSnaks.c
1 // ----------------------------------------------------------------------------
2 // SnikSnaks.c
3 // ----------------------------------------------------------------------------
4
5 #include "SnikSnaks.h"
6
7
8 static void subDrawSnikSnakFromAbove(int, int);
9 static void subDrawSnikSnakFromBelow(int, int);
10 static void subDrawSnikSnakFromLeft(int, int);
11 static void subDrawSnikSnakFromRight(int, int);
12 static void subDrawSnikSnakTurnLeft(int, int);
13 static void subDrawSnikSnakTurnRight(int, int);
14 static void subSnikSnakFromAbove(int, int);
15 static void subSnikSnakFromBelow(int, int);
16 static void subSnikSnakFromLeft(int, int);
17 static void subSnikSnakFromRight(int, int);
18 static void subSnikSnakTurnLeft(int, int);
19 static void subSnikSnakTurnRight(int, int);
20
21 // static char *VB_Name = "modSnikSnak";
22
23 // --- Option Explicit
24 // ==========================================================================
25 //                              SUBROUTINE
26 // Animate/move Snik-Snaks
27 // ==========================================================================
28
29 void subAnimateSnikSnaks(int si)
30 {
31   int bx, Tmp;
32
33   if (SnikSnaksElectronsFrozen == 1)
34     return;
35
36   // (not sure why this was removed -- this broke several level solutions)
37   if (LowByte(PlayField16[si]) != fiSnikSnak)
38     return;
39
40   // If LowByte(PlayField16(si)) <> fiSnikSnak Then Exit Function
41   // Debug.Assert (LowByte(PlayField16[si]) == fiSnikSnak);
42
43   bx = HighByte(PlayField16[si]);
44   Tmp = bx / 8;
45   switch (Tmp)
46   {
47     case 0:
48       subSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
49       break;
50
51     case 1:
52       subSnikSnakTurnRight(si, bx); // turn right
53       break;
54
55     case 2:
56       subSnikSnakFromBelow(si, bx); // access si from below
57       break;
58
59     case 3:
60       subSnikSnakFromRight(si, bx); // access si from right
61       break;
62
63     case 4:
64       subSnikSnakFromAbove(si, bx); // access si from above
65       break;
66
67     case 5:
68       subSnikSnakFromLeft(si, bx); // access si from left
69       break;
70
71     default:
72       // Debug.Assert(False);
73       break;
74   }
75 }
76
77 void subDrawAnimatedSnikSnaks(int si)
78 {
79   int bx, Tmp;
80
81   // If SnikSnaksElectronsFrozen = 1 Then Exit Function
82
83   if (LowByte(PlayField16[si]) != fiSnikSnak)
84     return;
85
86   bx = HighByte(PlayField16[si]);
87   Tmp = bx / 8;
88   switch (Tmp)
89   {
90     case 0:
91       subDrawSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
92       break;
93
94     case 1:
95       subDrawSnikSnakTurnRight(si, bx); // turn right
96       break;
97
98     case 2:
99       subDrawSnikSnakFromBelow(si, bx); // access si from below
100       break;
101
102     case 3:
103       subDrawSnikSnakFromRight(si, bx); // access si from right
104       break;
105
106     case 4:
107       subDrawSnikSnakFromAbove(si, bx); // access si from above
108       break;
109
110     case 5:
111       subDrawSnikSnakFromLeft(si, bx); // access si from left
112       break;
113   }
114 }
115
116 static void subSnikSnakTurnLeft(int si, int bx)
117 {
118   int ax, ah, bl;
119
120   ax = (TimerVar & 3);
121   if (ax != 0)
122   {
123     if (ax == 3)
124       goto loc_g_7622;
125
126     return;
127   } // loc_g_75E0:
128
129   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
130   subDrawSnikSnakTurnLeft(si, bx);
131   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
132
133   bx = (bx + 1) & 0x7;
134   MovHighByte(&PlayField16[si], bx);
135
136   return;
137
138 locMayExplode760A:
139   ah = HighByte(ax);
140   if (ah == 0x1B)
141     return;
142
143   if (ah == 0x19)
144     return;
145
146   if (ah == 0x18)
147     return;
148
149   if (ah == 0x1A)
150     return;
151
152   ExplodeFieldSP(si); // Explode
153
154   return;
155
156 loc_g_7622:
157   bl = HighByte(PlayField16[si]);
158   if (bl == 0)
159     goto loc_g_763B;
160
161   if (bl == 2)
162     goto loc_g_765E;
163
164   if (bl == 4)
165     goto loc_g_7681;
166
167   if (bl == 6)
168     goto loc_g_76A7;
169
170   return;
171
172 loc_g_763B: // pointing up
173   ax = PlayField16[si - FieldWidth];
174   if (ax == 0) // above is empty -> go up
175     goto loc_g_764E;
176
177   if (LowByte(ax) == fiMurphy) // above is murphy -> explode
178     goto locMayExplode760A;
179
180   return;
181
182 loc_g_764E: // above is empty -> go up
183   PlayField16[si] = 0x1BB;
184   si = si - FieldWidth;
185   PlayField16[si] = 0x1011;
186
187   return;
188
189 loc_g_765E: // pointing left
190   ax = PlayField16[si - 1];
191   if (ax == 0) // left is empty -> go there
192     goto loc_g_7671;
193
194   if (LowByte(ax) == fiMurphy) // left is murphy -> explode
195     goto locMayExplode760A;
196
197   return;
198
199 loc_g_7671: // left is empty -> go there
200   PlayField16[si] = 0x2BB;
201   si = si - 1;
202   PlayField16[si] = 0x1811;
203
204   return;
205
206 loc_g_7681: // pointing down
207   ax = PlayField16[si + FieldWidth];
208   if (ax == 0) // below is empty -> go down
209     goto loc_g_7697;
210
211   if (LowByte(ax) == fiMurphy) // below is murphy -> explode
212     goto locMayExplode760A;
213
214   return;
215
216 loc_g_7697: // below is empty -> go down
217   PlayField16[si] = 0x3BB;
218   si = si + FieldWidth;
219   PlayField16[si] = 0x2011;
220
221   return;
222
223 loc_g_76A7: // pointing Right
224   ax = PlayField16[si + 1];
225   if (ax == 0) // right is empty -> go there
226     goto loc_g_76BD;
227
228   if (LowByte(ax) == fiMurphy) // right is murphy -> explode
229     goto locMayExplode760A;
230
231   return;
232
233 loc_g_76BD: // right is empty -> go there
234   PlayField16[si] = 0x4BB;
235   si = si + 1;
236   PlayField16[si] = 0x2811;
237 }
238
239 static void subSnikSnakTurnRight(int si, int bx)
240 {
241   int ax, ah, bl;
242
243   ax = (TimerVar & 3);
244   if (ax != 0)
245   {
246     if (ax == 3)
247       goto loc_g_771F;
248
249     return;
250   } // loc_g_76DB:
251
252   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
253   subDrawSnikSnakTurnRight(si, bx);
254   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
255
256   bx = ((bx + 1) & 0x7) | 8;
257   MovHighByte(&PlayField16[si], bx);
258
259   return;
260
261 locMayExplode7707:
262   ah = HighByte(ax);
263   if (ah == 0x1B)
264     return;
265
266   if (ah == 0x19)
267     return;
268
269   if (ah == 0x18)
270     return;
271
272   if (ah == 0x1A)
273     return;
274
275   ExplodeFieldSP(si); // Explode
276
277   return;
278
279 loc_g_771F:
280   bl = HighByte(PlayField16[si]);
281   if (bl == 0x8)
282     goto loc_g_7738;
283
284   if (bl == 0xA)
285     goto loc_g_77A4;
286
287   if (bl == 0xC)
288     goto loc_g_777E;
289
290   if (bl == 0xE)
291     goto loc_g_775B;
292
293   return;
294
295 loc_g_7738: // pointing up
296   ax = PlayField16[si - FieldWidth];
297   if (ax == 0) // above is empty -> go up
298     goto loc_g_774B;
299
300   if (LowByte(ax) == fiMurphy) // above is murphy -> explode
301     goto locMayExplode7707;
302
303   return;
304
305 loc_g_774B: // above is empty -> go up
306   PlayField16[si] = 0x1BB;
307   si = si - FieldWidth;
308   PlayField16[si] = 0x1011;
309
310   return;
311
312 loc_g_775B: // pointing left
313   ax = PlayField16[si - 1];
314   if (ax == 0) // left is empty -> go there
315     goto loc_g_776E;
316
317   if (LowByte(ax) == fiMurphy) // left is murphy -> explode
318     goto locMayExplode7707;
319
320   return;
321
322 loc_g_776E: // left is empty -> go there
323   PlayField16[si] = 0x2BB;
324   si = si - 1;
325   PlayField16[si] = 0x1811;
326
327   return;
328
329 loc_g_777E: // pointing down
330   ax = PlayField16[si + FieldWidth];
331   if (ax == 0) // below is empty -> go down
332     goto loc_g_7794;
333
334   if (LowByte(ax) == fiMurphy) // below is murphy -> explode
335     goto locMayExplode7707;
336
337   return;
338
339 loc_g_7794: // below is empty -> go down
340   PlayField16[si] = 0x3BB;
341   si = si + FieldWidth;
342   PlayField16[si] = 0x2011;
343
344   return;
345
346 loc_g_77A4: // pointing Right
347   ax = PlayField16[si + 1];
348   if (ax == 0) // right is empty -> go there
349     goto loc_g_77BA;
350
351   if (LowByte(ax) == fiMurphy) // right is murphy -> explode
352     goto locMayExplode7707;
353
354   return;
355
356 loc_g_77BA: // right is empty -> go there
357   PlayField16[si] = 0x4BB;
358   si = si + 1;
359   PlayField16[si] = 0x2811;
360 }
361
362 static void subSnikSnakFromBelow(int si, int bx)
363 {
364   int ax, bl;
365
366   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
367   subDrawSnikSnakFromBelow(si, bx);
368   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
369   bx = bx - 0xF;  // get and increment sequence#
370
371   bl = LowByte(bx);
372   if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion)
373   {
374     PlayField16[si + FieldWidth] = 0; // sniknak left that field
375   }
376
377   if (bl < 8) // sniksnak still goes up
378   {
379     bl = bl + 0x10;
380     MovHighByte(&PlayField16[si], bl);
381
382     return;
383   } // loc_g_7813
384
385   PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
386   ax = PlayField16[si - 1]; // check left field
387   if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
388   {
389     MovHighByte(&PlayField16[si], 1); // start to turn left
390
391     return;
392   } // loc_g_7826: and 'loc_g_7833:
393
394   ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above
395   if (ax == 0) // check if empty
396   {
397     PlayField16[si] = 0x1BB; // mark as "sniksnak leaving"
398     si = si - FieldWidth; // go up!
399     PlayField16[si] = 0x1011;
400
401     return;
402   } // loc_g_784A:
403
404   if (LowByte(ax) == fiMurphy) // check for murphy above
405   {
406     ExplodeFieldSP(si); // Explode
407
408     return;
409   } // loc_g_7855:
410
411   ax = PlayField16[si + 1]; // check right field
412   if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
413   {
414     MovHighByte(&PlayField16[si], 9); // start to turn right
415
416     return;
417   } // loc_g_7862: and 'loc_g_786F:
418
419   // else: no way to go, start turning around
420   MovHighByte(&PlayField16[si], 1);
421 }
422
423 static void subSnikSnakFromRight(int si, int bx)
424 {
425   int ax, bl;
426
427   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
428   subDrawSnikSnakFromRight(si, bx);
429   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
430   bx = bx - 0x17;  // get and increment sequence#
431
432   bl = LowByte(bx);
433   if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion)
434   {
435     PlayField16[si + 1] = 0; // sniknak left that field
436   } // loc_g_78AC:
437
438   if (bl < 8) // sniksnak still goes left
439   {
440     bl = bl + 0x18;
441     MovHighByte(&PlayField16[si], bl);
442
443     return;
444   } // loc_g_78B9:
445
446   PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
447   ax = PlayField16[si + FieldWidth]; // check below
448   if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy?
449   {
450     MovHighByte(&PlayField16[si], 3); // yes -> turn left down
451
452     return;
453   } // loc_g_78CC: and 'loc_g_78D9:
454
455   ax = PlayField16[si - 1]; // check left, etc ... see the comments on subSnikSnakFromBelow()
456   if (ax == 0)
457   {
458     PlayField16[si] = 0x2BB;
459     si = si - 1;                // 1 field left
460     PlayField16[si] = 0x1811;
461
462     return;
463   } // loc_g_78F0:
464
465   if (LowByte(ax) == fiMurphy)
466   {
467     ExplodeFieldSP(si);      // Explode
468
469     return;
470   } // loc_g_78FB:
471
472   ax = PlayField16[si - FieldWidth]; // check above
473   if (ax == 0 || LowByte(ax) == fiMurphy)
474   {
475     MovHighByte(&PlayField16[si], 0xF);
476
477     return;
478   } // loc_g_7908:loc_g_7915:
479
480   MovHighByte(&PlayField16[si], 3);
481 }
482
483 static void subSnikSnakFromAbove(int si, int bx)
484 {
485   int ax, bl;
486
487   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
488   subDrawSnikSnakFromAbove(si, bx);
489   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
490   bx = bx - 0x1F;  // get and increment sequence#
491
492   bl = LowByte(bx);
493   if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
494   {
495     PlayField16[si - FieldWidth] = 0; // sniknak left that field
496   }
497
498   if (bl < 8) // sniksnak still goes down
499   {
500     bl = bl + 0x20;
501     MovHighByte(&PlayField16[si], bl);
502
503     return;
504   } // loc_g_7813
505
506   PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
507   ax = PlayField16[si + 1]; // check right
508   if (ax == 0 || LowByte(ax) == fiMurphy)
509   {
510     MovHighByte(&PlayField16[si], 5);
511
512     return;
513   } // loc_g_7986:
514
515   ax = PlayField16[si + FieldWidth]; // check below
516   if (ax == 0)
517   {
518     PlayField16[si] = 0x3BB;
519     si = si + FieldWidth;                 // 1 field down
520     PlayField16[si] = 0x2011;
521
522     return;
523   } // loc_g_799D:
524
525   if (LowByte(ax) == fiMurphy)
526   {
527     ExplodeFieldSP(si);        // Explode
528
529     return;
530   } // loc_g_79A8:
531
532   ax = PlayField16[si - 1]; // check left
533   if (ax == 0 || LowByte(ax) == fiMurphy)
534   {
535     MovHighByte(&PlayField16[si], 0xD);
536
537     return;
538   } // loc_g_79C2:
539
540   MovHighByte(&PlayField16[si], 5);
541 }
542
543 static void subSnikSnakFromLeft(int si, int bx)
544 {
545   int ax, bl;
546
547   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
548   subDrawSnikSnakFromLeft(si, bx);
549   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
550   bx = bx - 0x27;  // get and increment sequence#
551
552   bl = LowByte(bx);
553   if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion)
554   {
555     PlayField16[si - 1] = 0; // sniknak left that field
556   }
557
558   if (bl < 8) // sniksnak still goes right
559   {
560     bl = bl + 0x28;
561     MovHighByte(&PlayField16[si], bl);
562
563     return;
564   } // loc_g_78B9:
565
566   PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
567   ax = PlayField16[si - FieldWidth]; // check above
568   if (ax == 0 || LowByte(ax) == fiMurphy)
569   {
570     MovHighByte(&PlayField16[si], 7);
571
572     return;
573   } // loc_g_7A2D:
574
575   ax = PlayField16[si + 1]; // check right(straight on)
576   if (ax == 0)
577   {
578     PlayField16[si] = 0x4BB;
579     si = si + 1;                   // 1 field right
580     PlayField16[si] = 0x2811;
581
582     return;
583   } // loc_g_7A44:
584
585   if (LowByte(ax) == fiMurphy)
586   {
587     ExplodeFieldSP(si);    // Explode
588
589     return;
590   } // loc_g_7A4F:
591
592   ax = PlayField16[si + FieldWidth]; // check below
593   if (ax == 0 || LowByte(ax) == fiMurphy)
594   {
595     MovHighByte(&PlayField16[si], 0xB);
596
597     return;
598   } // loc_g_7A69:
599
600   MovHighByte(&PlayField16[si], 7);
601 }
602
603 static void subDrawSnikSnakTurnLeft(int si, int bx)
604 {
605   int pos = ((bx + 7) % 8) / 2;
606
607   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
608   GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningLeft[pos];
609   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
610 }
611
612 static void subDrawSnikSnakTurnRight(int si, int bx)
613 {
614   int pos = ((bx - 1) % 8) / 2;
615
616   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
617   GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningRight[pos];
618   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
619 }
620
621 static void subDrawSnikSnakFromBelow(int si, int bx)
622 {
623   int X, Y;
624
625   bx = bx - 0xF; // get and anti-increment sequence#
626
627   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
628   X = GetStretchX(si);
629   Y = GetStretchY(si + FieldWidth);
630   DDSpriteBuffer_BltImg(X, Y, aniSpace, 0);
631   DDSpriteBuffer_BltImg(X, Y - bx * TwoPixels, aniSnikSnakUp, bx);
632   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
633 }
634
635 static void subDrawSnikSnakFromRight(int si, int bx)
636 {
637   int X, Y;
638
639   bx = bx - 0x17; // get and increment sequence#
640
641   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
642   X = GetStretchX(si + 1);
643   Y = GetStretchY(si);
644   DDSpriteBuffer_BltImg(X, Y, aniSpace, 0);
645   DDSpriteBuffer_BltImg(X - bx * TwoPixels, Y, aniSnikSnakLeft, bx);
646   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
647 }
648
649 static void subDrawSnikSnakFromAbove(int si, int bx)
650 {
651   int X, Y;
652
653   bx = bx - 0x1F; // get and increment sequence#
654
655   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
656   X = GetStretchX(si);
657   Y = GetStretchY(si - FieldWidth);
658   DDSpriteBuffer_BltImg(X, Y, aniSpace, 0);
659   DDSpriteBuffer_BltImg(X, Y + bx * TwoPixels, aniSnikSnakDown, bx);
660   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
661 }
662
663 static void subDrawSnikSnakFromLeft(int si, int bx)
664 {
665   int X, Y;
666
667   bx = bx - 0x27; // get and increment sequence#
668
669   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
670   X = GetStretchX(si - 1);
671   Y = GetStretchY(si);
672   DDSpriteBuffer_BltImg(X, Y, aniSpace, 0);
673   DDSpriteBuffer_BltImg(X + bx * TwoPixels, Y, aniSnikSnakRight, bx);
674   // +++++++++++++++++++++++++++++++++++++++++++++++++++++
675 }