1 /* GNU Robbo
2 * Copyright (C) 2002-2010 The GNU Robbo Team (see AUTHORS).
3 *
4 * GNU Robbo is free software - you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * GNU Robbo is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the impled 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 GNU CC; see the file COPYING. If not, write to the
16 * Free Software Foundation, 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 */
20
21 #include "game.h"
22
23 /* Defines */
24 /*
25 #define DEBUG_MONITOR_OBJECT_PROCESSING
26 #define DEBUG_INSPECT_OBJECT_CONTENTS
27 #define DEBUG_BEAR_LOGIC
28 */
29
30 #define MAX_TELEPORT_IDS 15 /* max number of teleports of one kind at level */
31
32 /*
33 * Variables
34 */
35
36
37 /*
38 * Function prototypes
39 */
40 int random_id (void);
41 int update_coords (struct Coords *coords, int direction);
42
43 void set_images (int type, int x, int y);
44 int can_move (struct Coords coords, int direction);
45 void move_object (int x, int y, struct Coords coords);
46 void shoot_object (int x, int y, int direction);
47 void blow_bomb (int x, int y);
48 void check_object_if_blowed (int x, int y);
49 int find_teleport (struct Coords *coords, int teleportnumber,
50 int teleportnumber2);
51 int is_robbo_killed (void);
52 void kill_robbo (void);
53
54
55 #ifdef LIGHTNINGENABLED
56 void
seteffect(int x,int y,int effect)57 seteffect (int x, int y, int effect)
58 {
59
60 board[x][y].effect =
61 ((effect > board[x][y].effect) ? effect : board[x][y].effect);
62 redraw_field(x,y);
63 }
64
65 void
seteffectsurround(int x,int y,int effect)66 seteffectsurround (int x, int y, int effect)
67 {
68 int x1 = (x - 1 > 0) ? x - 1 : 0;
69 int y1 = (y - 1 > 0) ? y - 1 : 0;
70 int x2 = (x + 1 > level.w) ? level.w : x + 1;
71 int y2 = (y + 1 > level.h) ? level.h : y + 1;
72 int c1, c2;
73 for (c1 = x1; c1 <= x2; c1++)
74 for (c2 = y1; c2 <= y2; c2++)
75 seteffect (c1, c2, effect);
76 }
77
78
79 #endif
80
81 /***************************************************************************
82 * Update Game *
83 ***************************************************************************/
84 /*
85 * Main function for the game - called every game cycle.
86 *
87 * Thunor: Objects that I have 'processed' checked that required it :- [x]
88 * - BEAR/_B [x] - BARRIER [x] - BIRD [x] - BUTTERFLY [x] - BLASTER [x] -
89 * LASER_L/D [x] - PUSH_BOX [x] - GUN
90 *
91 */
92
93 void
update_game(void)94 update_game (void)
95 {
96 int x_tmp, flag, sflag, temp_state = 0, temp_blowed = 0, temp_direction = 0;
97 struct Coords coords, coords_temp, dest, coords_side_behind, coords_behind;
98 int x, y, i, forceforward;
99
100 dest.x = 0; /* to avoid warnings */
101 dest.y = 0;
102 play_music ();
103 /*
104 * Firstly, update Robbo
105 */
106 if (is_robbo_killed ())
107 kill_robbo (); /* If Robbo has been killed then mark everything to be blown-up */
108 if (robbo.shooted > 0)
109 robbo.shooted--; /* Decrement shot delay */
110 if (robbo.moved > 0)
111 robbo.moved--; /* Decrement movement delay */
112 if (robbo.moved == 0)
113 {
114 robbo.teleporting = FALSE;
115 redraw_field (robbo.x, robbo.y);
116 /*
117 * Is Robbo currently being pulled by a magnet?
118 */
119 if (robbo.blocked == 1)
120 {
121
122 set_coords (&coords, robbo.x, robbo.y);
123 if (can_move (coords, robbo.blocked_direction))
124 {
125 play_sound (SFX_MAGNET, SND_NORM); /* play magnet sound */
126 switch (robbo.blocked_direction)
127 {
128 case 0:
129 robbo.x++;
130 break;
131 case 2:
132 robbo.x--;
133 break;
134 case 1:
135 robbo.y++;
136 break;
137 case 3:
138 robbo.y--;
139 break;
140 }
141 robbo.moved = DELAY_MAGNET_ATTRACT;
142 redraw_field (robbo.x, robbo.y);
143 }
144 else
145 {
146 kill_robbo ();
147 return; /* Thunor: this was already here; I didn't add this, but I did add some lower down */
148 }
149 }
150 }
151 else if (robbo.moved == DELAY_ROBBO_ANIMATE)
152 {
153 robbo.state = !robbo.state; /* Toggle Robbo's image */
154 redraw_field (robbo.x, robbo.y);
155 }
156
157 /*
158 * Now iterate through every board location updating objects
159 */
160 for (y = 0; y < level.h; y++)
161 { /* Thunor: I have swapped these around to process by rows */
162 for (x = 0; x < level.w; x++)
163 { /* Thunor: I have swapped these around to process by rows */
164 /*
165 * Thunor: I've added this check to filter out already
166 * processed objects. Additionally the object logic updates
167 * other objects and I have modified the code to mark those as
168 * processed too. The reason I am doing this is because objects
169 * can get moved ahead of the x/y loop resulting in them having
170 * at least their shooted/rotated/moved properties decremented
171 * more than once for this cycle and they go out of sync
172 */
173
174 /* if(board[x][y].effect>=0) {
175 for(x1=(x>0)?x-1:0;x1<=x+1;x1++)
176 for(y1=(y>0)?y-1:0;y1<=y+1;y1++) board[x1][y1].redraw=1;
177 }
178 */
179
180 if (board[x][y].processed != cycle_count)
181 {
182 board[x][y].processed = cycle_count;
183 #ifdef LIGHTNINGENABLED
184 if (board[x][y].effect >= 0)
185 {
186 redraw_field (x, y);
187 board[x][y].effect--;
188 }
189 #endif
190 /*
191 * GUN and BIRD objects can rotate and shoot so update
192 * their delays here
193 */
194 if (board[x][y].type == GUN || board[x][y].type == BIRD
195 || board[x][y].type == MAGNET)
196 {
197 if (board[x][y].shooted > 0)
198 board[x][y].shooted--; /* Decrement shot delay */
199 if (board[x][y].rotated > 0)
200 board[x][y].rotated--; /* Decrement rotation delay */
201 }
202
203 /*
204 * Decrement the object's delay and then check if it needs
205 * processing
206 */
207 if (board[x][y].moved > 0)
208 board[x][y].moved--;
209 if (board[x][y].moved <= 0)
210 {
211 check_object_if_blowed (x, y); /* blow objects marked for blowing */
212
213 set_coords (&coords, x, y);
214
215 switch (board[x][y].type)
216 {
217 /*********************/
218 /* BEAR/_B logic */
219 /*********************/
220 case BEAR:
221 case BEAR_B:
222 /*
223 * Left/right-hand rule maze traversal: this is
224 * the exact same way that the original Robbo does
225 * it. The bears will attempt to manoeuvre around
226 * all obstacles but this takes time and they will
227 * get killed by laser fire and push boxes
228 * especially if they meet them head-on
229 */
230 set_coords (&coords, x, y);
231 if (game_mode == GAME_ON)
232 {
233 if (board[x][y].type == BEAR)
234 {
235 update_coords (&coords, (board[x][y].direction + 3) & 3); /* Get coords of left board location */
236 }
237 else
238 {
239 update_coords (&coords, (board[x][y].direction + 1) & 3); /* Get coords of right board location */
240 }
241 }
242 forceforward = FALSE;
243 /*
244 * Are we implementing sensible_bears? In the
245 * Atari Robbo, there are two conditions that
246 * place bears into irritating states that become
247 * annoying: single bears in empty space going
248 * around themselves and two bears of the same
249 * type going around one another.
250 *
251 * |N| | = If this is a BEAR_B taking rights, it
252 * will go clockwise forever. | | | N is north.
253 *
254 * | |N| = If these are BEARs taking lefts, they
255 * will go anti-clockwise forever. |S| | N is
256 * north, S is south.
257 *
258 * sensible_bears detects the conditions that lead
259 * to these problems and fixes them by forcing the
260 * bears to go forward until they find another
261 * obstacle to navigate around
262 */
263 if (game_mechanics.sensible_bears)
264 {
265 set_coords (&coords_side_behind, coords.x,
266 coords.y);
267 update_coords (&coords_side_behind, (board[x][y].direction + 2) & 3); /* Get coords of side-behind board location */
268 set_coords (&coords_behind,
269 coords_side_behind.x,
270 coords_side_behind.y);
271 if (board[x][y].type == BEAR)
272 {
273 update_coords (&coords_behind, (board[x][y].direction + 1) & 3); /* Get coords of behind board location */
274 }
275 else
276 {
277 update_coords (&coords_behind, (board[x][y].direction + 3) & 3); /* Get coords of behind board location */
278 }
279 if (board[coords.x][coords.y].type ==
280 EMPTY_FIELD
281 && board[coords_behind.x][coords_behind.y].
282 type == EMPTY_FIELD
283 &&
284 (board[coords_side_behind.x]
285 [coords_side_behind.y].type == EMPTY_FIELD
286 || board[x][y].type ==
287 board[coords_side_behind.
288 x][coords_side_behind.y].type))
289 {
290 forceforward = TRUE;
291 }
292 }
293 #ifdef DEBUG_BEAR_LOGIC
294 if (board[x][y].type == BEAR)
295 {
296 printf ("|%02i| @| %06i: BEAR at %03i.%03i\n",
297 board[coords.x][coords.y].type,
298 cycle_count, x, y);
299 printf ("|%02i|%02i|\n",
300 board[coords_side_behind.x]
301 [coords_side_behind.y].type,
302 board[coords_behind.x][coords_behind.y].
303 type);
304 }
305 else if (board[x][y].type == BEAR_B)
306 {
307 printf ("| *|%02i| %06i: BEAR_B at %03i.%03i\n",
308 board[coords.x][coords.y].type,
309 cycle_count, x, y);
310 printf ("|%02i|%02i|\n",
311 board[coords_behind.x][coords_behind.y].
312 type,
313 board[coords_side_behind.x]
314 [coords_side_behind.y].type);
315 }
316 #endif
317 /*
318 * Check left/right and if it's clear then take it
319 */
320 if (board[coords.x][coords.y].type == EMPTY_FIELD
321 && !forceforward)
322 {
323 /*
324 * Left/right is clear so change to that
325 * direction and move there
326 */
327 if (board[x][y].type == BEAR)
328 {
329 board[x][y].direction = (board[x][y].direction + 3) & 3; /* Go left */
330 }
331 else
332 {
333 board[x][y].direction = (board[x][y].direction + 1) & 3; /* Go right */
334 }
335 board[x][y].moved = DELAY_BEAR;
336 negate_state (x, y);
337 move_object (x, y, coords);
338 }
339 else
340 {
341 /*
342 * Left/right is not clear so check forward
343 * and if it's clear then take it
344 */
345 set_coords (&coords, x, y);
346 update_coords (&coords, board[x][y].direction); /* Get coords of forward board location */
347 if (board[coords.x][coords.y].type == EMPTY_FIELD)
348 {
349 /*
350 * Forward is clear so move there
351 */
352 board[x][y].moved = DELAY_BEAR;
353 negate_state (x, y);
354 move_object (x, y, coords);
355 }
356 else
357 {
358 /*
359 * Forward is not clear so rotate
360 * rightward but don't move
361 */
362 if (board[x][y].type == BEAR)
363 {
364 board[x][y].direction = (board[x][y].direction + 1) & 3; /* Go forward */
365 }
366 else
367 {
368 board[x][y].direction = (board[x][y].direction + 3) & 3; /* Go forward */
369 }
370 board[x][y].moved = DELAY_BEAR;
371 board[x][y].processed = cycle_count; /* Because we're not moving, we do this manually */
372 negate_state (x, y);
373 }
374 }
375 break;
376
377 /*********************/
378 /* BARRIER logic */
379 /*********************/
380 case BARRIER:
381 flag = 0;
382 x_tmp = x;
383
384 if (board[x][y].direction == 0)
385 { /* East -> */
386 while (x_tmp < level.w
387 && board[x_tmp][y].type != WALL)
388 {
389 x_tmp++;
390 }
391 x_tmp--;
392
393 if (board[x_tmp][y].type == BARRIER)
394 {
395 temp_state = board[x_tmp][y].state;
396 temp_blowed = board[x_tmp][y].blowed;
397 temp_direction = board[x_tmp][y].direction;
398 clear_field (x_tmp, y);
399 negate_state (x_tmp, y);
400 flag = 1;
401 }
402
403 while (x_tmp >= 0 && board[x_tmp][y].type != WALL)
404 {
405 x_tmp--;
406
407 /*
408 * Thunor: I added "x_tmp >= 0 && " below
409 * to prevent referencing invalid array
410 * elements as x_tmp can be -1 here if the
411 * barrier is up against the left map
412 * edge. Following this block of code,
413 * x_tmp is incremented and so this is the
414 * most suitable solution
415 */
416 if (x_tmp >= 0
417 && board[x_tmp][y].type == BARRIER)
418 {
419 check_object_if_blowed (x_tmp, y);
420 dest.x = x_tmp + 1;
421 dest.y = y;
422
423 if ((dest.x == robbo.x)
424 && (dest.y == robbo.y))
425 {
426 kill_robbo ();
427 return; /* Thunor: Exiting here stops new barriers from being created */
428 }
429
430 move_object (x_tmp, y, dest);
431 /*
432 * board[dest.x][dest.y].direction =
433 * 0;
434 */
435 board[dest.x][dest.y].moved = DELAY_BARRIER;
436 board[dest.x][dest.y].processed = cycle_count; /* Thunor: Prevents this object from being processed again this cycle */
437 negate_state (dest.x, dest.y);
438 }
439 }
440
441 x_tmp++;
442
443 if (flag == 1)
444 {
445 if ((dest.x == robbo.x) && (dest.y == robbo.y))
446 {
447 kill_robbo ();
448 return; /* Thunor: Exiting here stops new barriers from being created */
449 }
450
451 if (robbo.x == x_tmp && robbo.y == y)
452 {
453 kill_robbo ();
454 return;
455 }
456
457 create_object (x_tmp, y, BARRIER);
458 board[x_tmp][y].state = temp_state;
459 board[x_tmp][y].blowed = temp_blowed;
460 board[x_tmp][y].direction = temp_direction;
461 board[x_tmp][y].moved = DELAY_BARRIER;
462 negate_state (x_tmp, y);
463 }
464 }
465 else if (board[x][y].direction == 2)
466 { /* <- West */
467 while (x_tmp >= 0 && board[x_tmp][y].type != WALL)
468 x_tmp--;
469
470 x_tmp++;
471
472 if (board[x_tmp][y].type == BARRIER)
473 {
474 temp_state = board[x_tmp][y].state;
475 temp_blowed = board[x_tmp][y].blowed;
476 temp_direction = board[x_tmp][y].direction;
477 clear_field (x_tmp, y);
478 negate_state (x_tmp, y);
479 flag = 1;
480 }
481
482 while (x_tmp < level.w
483 && board[x_tmp][y].type != WALL)
484 {
485 x_tmp++;
486
487 /*
488 * Thunor: I added "x_tmp < level.w && "
489 * below to prevent referencing invalid
490 * array elements as x_tmp can be level.w
491 * here if the barrier is up against the
492 * right map edge. Following this block of
493 * code, x_tmp is decremented and so this
494 * is the most suitable solution
495 */
496 if (x_tmp < level.w
497 && board[x_tmp][y].type == BARRIER)
498 {
499 check_object_if_blowed (x_tmp, y);
500 dest.x = x_tmp - 1;
501 dest.y = y;
502
503 if ((dest.x == robbo.x)
504 && (dest.y == robbo.y))
505 {
506 kill_robbo ();
507 return; /* Thunor: Exiting here stops new barriers from being created */
508 }
509
510 move_object (x_tmp, y, dest);
511 /*
512 * board[dest.x][dest.y].direction =
513 * 2;
514 */
515 board[dest.x][dest.y].moved = DELAY_BARRIER;
516 board[dest.x][dest.y].processed = cycle_count; /* Thunor: Prevents this object from being processed again this cycle */
517 negate_state (dest.x, dest.y);
518 }
519 }
520
521 x_tmp--;
522
523 if (flag == 1 && temp_blowed == 0)
524 {
525 if ((dest.x == robbo.x) && (dest.y == robbo.y))
526 {
527 kill_robbo ();
528 return; /* Thunor: Exiting here stops new barriers from being created */
529 }
530
531 if (robbo.x == x_tmp && robbo.y == y)
532 {
533 kill_robbo ();
534 return;
535 }
536
537 create_object (x_tmp, y, BARRIER);
538 board[x_tmp][y].state = temp_state;
539 board[x_tmp][y].moved = DELAY_BARRIER;
540 board[x_tmp][y].direction = temp_direction;
541 negate_state (x_tmp, y);
542 }
543 }
544 break;
545
546 /*********************/
547 /* BIRD logic */
548 /*********************/
549 case BIRD:
550 if (can_move (coords, board[x][y].direction))
551 {
552 update_coords (&coords, board[x][y].direction);
553 move_object (x, y, coords);
554
555 }
556 else
557 board[x][y].direction =
558 (board[x][y].direction + 2) & 0x03;
559
560 if (board[coords.x][coords.y].shooting)
561 {
562 if (board[coords.x][coords.y].shooted == 0)
563 {
564 if ((my_rand () & 0x07) == 0)
565 { /* bird shoots */
566 shoot_object (coords.x, coords.y,
567 board[coords.x][coords.y].
568 direction2);
569 if (in_viewport (x, y))
570 play_sound (SFX_BIRD, SND_NORM);
571 else
572 play_sound (SFX_BIRD, SND_QUIET);
573 }
574 else
575 board[coords.x][coords.y].shooted =
576 DELAY_LASER;
577 }
578 }
579 board[coords.x][coords.y].moved = DELAY_BIRD;
580 negate_state (coords.x, coords.y);
581 break;
582 /*********************/
583 /* BUTTERFLY logic */
584 /*********************/
585 case BUTTERFLY:
586 if (can_move (coords, board[x][y].direction))
587 {
588 update_coords (&coords, board[x][y].direction);
589 move_object (x, y, coords);
590 }
591
592 if (!(rand () & 0x07)) /* chances for random move */
593 board[coords.x][coords.y].direction = rand () & 0x03;
594
595 else if ((rand () & 0x01) == 0)
596 { /* if butterfly flies horizontally */
597 if (robbo.x > coords.x)
598 board[coords.x][coords.y].direction = 0;
599 else if (robbo.x < coords.x)
600 board[coords.x][coords.y].direction = 2;
601 }
602 else
603 { /* if butterfly flies vertically */
604 if (robbo.y > coords.y)
605 board[coords.x][coords.y].direction = 1;
606 else if (robbo.y < coords.y)
607 board[coords.x][coords.y].direction = 3;
608 }
609
610 board[coords.x][coords.y].moved = DELAY_BUTTERFLY;
611 negate_state (coords.x, coords.y);
612 break;
613 /*********************/
614 /* BLASTER logic */
615 /*********************/
616 case BLASTER:
617 redraw_field(x,y);
618 set_coords (&coords, x, y);
619 set_coords (&coords_temp, x, y); /* * neurocyp now we will check if the gun was removed during blaster shot, if so, we have to react */
620 temp_state = board[coords_temp.x][coords_temp.y].state;
621 while (board[coords_temp.x][coords_temp.y].type ==
622 BLASTER)
623 {
624 temp_state =
625 board[coords_temp.x][coords_temp.y].state;
626 update_coords (&coords_temp,
627 (board[coords_temp.x]
628 [coords_temp.y].direction + 2) % 4);
629 }
630 if (temp_state < 3
631 && board[coords_temp.x][coords_temp.y].type != GUN)
632 {
633 create_object (coords.x, coords.y, LITTLE_BOOM); /* so the gun was removed during shot? ok, clear it out */
634 board[coords.x][coords.y].moved = DELAY_BLASTER;
635 break;
636 }
637
638
639
640 if (!update_coords
641 (&coords, board[coords.x][coords.y].direction)
642 && board[x][y].state == 0)
643 {
644 if (robbo.x == coords.x && robbo.y == coords.y)
645 {
646 kill_robbo ();
647 return; /* Thunor: Exiting here stops new blasters from being created */
648 }
649 switch (board[coords.x][coords.y].type)
650 {
651 case DOOR:
652 case WALL:
653 case MAGNET:
654 case BOX:
655 case TELEPORT:
656 case PUSH_BOX:
657 case RADIOACTIVE_FIELD:
658 case STOP:
659 case GUN:
660 case LASER_D:
661 case LASER_L:
662 case BLASTER:
663 case SCREW:
664 case KEY:
665 case CAPSULE:
666 break;
667 case BOMB:
668 case BOMB2:
669 board[coords.x][coords.y].blowed =
670 DELAY_BLASTER;
671 break;
672 default:
673 clear_field (coords.x, coords.y);
674 create_object (coords.x, coords.y, BLASTER);
675 board[coords.x][coords.y].direction =
676 board[x][y].direction;
677 board[coords.x][coords.y].direction2 =
678 board[x][y].direction2;
679 board[coords.x][coords.y].moved = DELAY_BLASTER;
680 }
681 }
682 if (board[x][y].state < 4)
683 {
684 board[x][y].state++;
685 board[x][y].moved = DELAY_BLASTER;
686 }
687 else
688 {
689 clear_field (x, y);
690 }
691 break;
692 /*********************/
693 /* CAPSULE logic */
694 /*********************/
695 case CAPSULE:
696 if (robbo.exitopened)
697 {
698 negate_state (x, y);
699 board[x][y].moved = DELAY_CAPSULE;
700 redraw_field (x, y);
701
702 }
703 break;
704 /*********************/
705 /* LITTLE_BOOM logic */
706 /*********************/
707 case LITTLE_BOOM:
708
709 redraw_field (x, y);
710 if (board[x][y].state < 3)
711 {
712 board[x][y].state++;
713 board[x][y].moved = DELAY_LITTLE_BOOM;
714 }
715 else
716 clear_field (x, y);
717 break;
718 /*********************/
719 /* LASER_L/D logic */
720 /*********************/
721 case LASER_L:
722 case LASER_D:
723 redraw_field (x, y);
724 update_coords (&coords, board[x][y].direction);
725 board[x][y].moved = DELAY_LASER;
726
727 if ((coords.x == robbo.x) && (coords.y == robbo.y)
728 && !board[x][y].returnlaser
729 && robbo.teleporting == FALSE)
730 {
731 kill_robbo ();
732 return; /* Thunor: Exiting here stops new lasers from being created */
733 }
734 set_coords (&coords, x, y);
735 if (board[x][y].solidlaser == 0)
736 {
737 negate_state (x, y);
738
739 if (can_move (coords, board[x][y].direction))
740 { /* normal shooting */
741 update_coords (&coords, board[x][y].direction);
742 move_object (x, y, coords);
743 board[coords.x][coords.y].moved = DELAY_LASER;
744 }
745 else
746 { /* blow object if it's destroyable */
747 if (!update_coords
748 (&coords, board[x][y].direction)
749 && board[coords.x][coords.y].destroyable)
750 {
751 if ((board[coords.x][coords.y].type != BOMB)
752 && (board[coords.x][coords.y].type !=
753 BOMB2))
754 {
755 if (in_viewport (x, y))
756 {
757 play_sound (SFX_KILL, SND_NORM);
758 }
759 else
760 {
761 play_sound (SFX_KILL, SND_QUIET);
762 }
763 }
764 clear_field (x, y);
765 board[coords.x][coords.y].blowed = 1;
766 redraw_field (coords.x, coords.y);
767 }
768 else
769 {
770 clear_field (x, y); /* clear lasertrack */
771 create_object (x, y, LITTLE_BOOM);
772 board[x][y].moved = DELAY_LITTLE_BOOM;
773 break;
774 }
775 }
776 }
777 else
778 {
779 /* **************************** laser is solid ********************** */
780 set_coords (&coords_temp, x, y); /* first let's check that laser starts from a gun, if not, means gun was moved, or blown */
781 while (board[coords_temp.x][coords_temp.y].type ==
782 board[x][y].type && coords_temp.x >= 0
783 && coords_temp.y >= 0
784 && coords_temp.x <= level.w
785 && coords_temp.y <= level.h)
786 { /* move * on * laser */
787 if (update_coords
788 (&coords_temp,
789 (board[x][y].direction + 2) & 0x03))
790 break;
791 }
792 if (board[coords_temp.x][coords_temp.y].type != GUN)
793 { /* ok, now we are at the beginning of laser beam if it is not a gun, which is there, destroy laser */
794 create_object (x, y, LITTLE_BOOM);
795 break;
796 }
797 /* neurocyp: set the state for the whole beam (begin) */
798 set_coords (&coords_temp, x, y);
799 update_coords (&coords_temp,
800 (board[x][y].direction + 2) & 0x03);
801 if (board[coords_temp.x][coords_temp.y].type == GUN)
802 { /* are we at the beginning of the laser? */
803 temp_state = (board[x][y].state == 3) ? 2 : 3;
804 set_coords (&coords_temp, x, y); /* first let's check that laser starts from a gun, if not, means gun was moved, or blown */
805 while ((board[coords_temp.x][coords_temp.y].type
806 == board[x][y].type)
807 && board[coords_temp.x][coords_temp.
808 y].direction ==
809 board[x][y].direction
810 && coords_temp.x >= 0
811 && coords_temp.y >= 0
812 && coords_temp.x <= level.w
813 && coords_temp.y <= level.h)
814 { /* move * on * laser with the same direction and all */
815 redraw_field (coords_temp.x, coords_temp.y); /* we will have to redraw the whole beam, as we changed it's state */
816 board[coords_temp.x][coords_temp.y].state =
817 temp_state;
818 if (update_coords
819 (&coords_temp, board[x][y].direction))
820 break; /* just in case, if we are unable to update coords then we quit the loop */
821 }
822 }
823 /* neurocyp: set the state for the whole beam (end) */
824 if (can_move (coords, board[x][y].direction)
825 && board[x][y].returnlaser == 0)
826 { /* if can shoot */
827 update_coords (&coords, board[x][y].direction);
828 shoot_object (x, y, board[x][y].direction);
829 board[coords.x][coords.y].moved = DELAY_LASER;
830 }
831 else
832 {
833 if (board[x][y].returnlaser == 1)
834 {
835 set_coords (&coords, x, y); /* checking if laser is near gun */
836 update_coords (&coords,
837 (board[x][y].direction +
838 2) & 0x03);
839 clear_field (x, y);
840
841 if (board[coords.x][coords.y].type == GUN)
842 {
843 create_object (x, y, LITTLE_BOOM);
844 break;
845 }
846 if (board[coords.x][coords.y].type ==
847 LASER_D
848 || board[coords.x][coords.y].type ==
849 LASER_L)
850 {
851 board[coords.x][coords.y].returnlaser =
852 1;
853 board[coords.x][coords.y].moved =
854 DELAY_LASER;
855 board[coords.x][coords.y].processed = cycle_count; /* Thunor: Prevents this object from being processed again this cycle */
856 }
857 }
858 else
859 {
860 set_coords (&coords, x, y);
861 if (!update_coords
862 (&coords, board[x][y].direction))
863 {
864 if (board[coords.x][coords.y].type ==
865 LASER_D
866 || board[coords.x][coords.y].type ==
867 LASER_L)
868 {
869 if (board[coords.x]
870 [coords.y].direction ==
871 board[x][y].direction)
872 {
873 break;
874 }
875 }
876 if (board[coords.x]
877 [coords.y].destroyable)
878 {
879 board[coords.x][coords.y].blowed =
880 1;
881 if ((board[coords.x][coords.y].type
882 != BOMB)
883 &&
884 (board[coords.x][coords.y].type
885 != BOMB2))
886 {
887 if (in_viewport (x, y))
888 play_sound (SFX_KILL,
889 SND_NORM);
890 else
891 play_sound (SFX_KILL,
892 SND_QUIET);
893 }
894 }
895 }
896 board[x][y].returnlaser = 1;
897 }
898 }
899 }
900 break;
901 /*********************/
902 /* BIG_BOOM logic */
903 /*********************/
904 case BIG_BOOM:
905 redraw_field (x, y);
906
907 if (board[x][y].state < 4)
908 {
909 board[x][y].state++;
910 board[x][y].moved = DELAY_BIGBOOM;
911 }
912 else
913 {
914
915 i = board[x][y].id_questionmark; /* This is why create_object() doesn't clear this property */
916 if ((i > 0) && robbo.alive)
917 {
918 clear_field (x, y);
919 if (i == QUESTIONMARK)
920 board[x][y].id_questionmark = random_id ();
921 create_object (x, y, i);
922 switch (i)
923 {
924 case CAPSULE:
925 open_exit ();
926 break;
927 case GUN:
928 board[x][y].rotable = 1;
929 board[x][y].randomrotated = 1;
930 board[x][y].direction = rand () & 0x03;
931 break;
932 default:
933 break;
934 }
935 }
936 else
937 clear_field (x, y);
938 }
939 break;
940 /*********************/
941 /* RADIOACTIVE_FIELD logic */
942 /*********************/
943 case RADIOACTIVE_FIELD:
944 negate_state (x, y);
945 board[x][y].moved = DELAY_RADIOACTIVE_FIELD;
946 break;
947
948 /*********************/
949 /* TELEPORT logic */
950 /*********************/
951 case TELEPORT:
952 redraw_field (x, y);
953
954 negate_state (x, y);
955 board[x][y].moved = DELAY_TELEPORT;
956 break;
957 /*********************/
958 /* TELEPORTING logic */
959 /*********************/
960 case TELEPORTING:
961 redraw_field (x, y);
962 if (board[x][y].state < 4)
963 {
964
965 board[x][y].state++;
966 board[x][y].moved = DELAY_TELEPORTING;
967 }
968 else
969 {
970 clear_field (x, y);
971 }
972 break;
973 /*********************/
974 /* PUSH_BOX logic */
975 /*********************/
976 case PUSH_BOX:
977 if (board[x][y].state == 1)
978 { /* box is moving */
979 set_coords (&coords, x, y);
980 if (!update_coords (&coords, board[x][y].direction))
981 {
982 if (board[coords.x][coords.y].type ==
983 EMPTY_FIELD && (coords.x != robbo.x
984 || coords.y != robbo.y))
985 {
986 move_object (x, y, coords);
987 }
988 else
989 {
990 //if(coords.x==robbo.x && coords.y==robbo.y
991 shoot_object (x, y, board[x][y].direction);
992 board[x][y].state = 0;
993 board[x][y].redraw = 1;
994 }
995 }
996 else
997 board[x][y].state = 0;
998 board[x][y].redraw = 1;
999 if (in_viewport (x, y))
1000 play_sound (SFX_BOX, SND_NORM); /* play the sound */
1001 else
1002 play_sound (SFX_BOX, SND_QUIET);
1003 board[coords.x][coords.y].moved = DELAY_PUSHBOX;
1004 }
1005 break;
1006 /*********************/
1007 /* MAGNET logic */
1008 /*********************/
1009 case MAGNET:
1010 i = 0;
1011 if (robbo.blocked == 1)
1012 break; /* *neurocyp we are already locked on a magnet we ignore other blocks */
1013 if (board[x][y].rotable)
1014 { /* *neurocyp: we will not rotate, when we shoot */
1015 if (board[x][y].rotated == 0)
1016 {
1017 temp_direction = rand () & 0x03;
1018 board[x][y].direction = temp_direction;
1019 board[x][y].state = temp_direction;
1020 board[coords.x][coords.y].rotated =
1021 DELAY_ROTATION;
1022 redraw_field (coords.x, coords.y);
1023 }
1024 }
1025 while (i == 0)
1026 {
1027 if (!update_coords (&coords, board[x][y].direction))
1028 {
1029 if (robbo.x == coords.x && robbo.y == coords.y)
1030 {
1031 robbo.blocked = 1;
1032 robbo.blocked_direction =
1033 (board[x][y].direction + 2) & 0x03;
1034 }
1035 else
1036 switch (board[coords.x][coords.y].type)
1037 {
1038 /*
1039 * this things don't protect from
1040 * magnet
1041 */
1042 case EMPTY_FIELD:
1043 break;
1044 default:
1045 i = 1;
1046 break;
1047 }
1048
1049 }
1050 else
1051 i = 1;
1052 }
1053 break;
1054 /*********************/
1055 /* GUN logic */
1056 /*********************/
1057 case GUN:
1058
1059 set_coords (&coords, x, y);
1060 #ifdef DEBUG_MONITOR_OBJECT_PROCESSING
1061 printf
1062 ("cycle_count=%i: board[%i][%i].processed=%i\n",
1063 cycle_count, x, y, board[x][y].processed);
1064 #endif
1065 sflag = 0; /* shooting flag */
1066 /*
1067 * we need to make sure this would not rotate nor
1068 * move, when it is shooting solid laser
1069 */
1070 set_coords (&coords_temp, coords.x, coords.y);
1071 update_coords (&coords_temp,
1072 board[coords.x][coords.y].direction);
1073
1074 if (board[coords_temp.x][coords_temp.y].direction ==
1075 board[coords.x][coords.y].direction)
1076 switch (board[coords_temp.x][coords_temp.y].type)
1077 {
1078 case BLASTER:
1079 case SOLID_LASER_L:
1080 case SOLID_LASER_D:
1081 case LASER_L:
1082 case LASER_D:
1083 sflag = 1; /* *neurocyp: we are not supposed to move nor rotate */
1084 break;
1085 }
1086 if (sflag == 0)
1087 {
1088 if (board[coords.x][coords.y].movable)
1089 { /* *neurocyp: no move during solid laser or blaster shot */
1090
1091
1092 if (can_move (coords, board[x][y].direction2))
1093 { /* *neurocyp: here probably we should implement stopping during solid laser or blaster shot */
1094 update_coords (&coords,
1095 board[x][y].direction2);
1096 move_object (x, y, coords);
1097 board[coords.x][coords.y].moved = DELAY_GUN;
1098 board[coords.x][coords.y].state =
1099 board[x][y].direction | 0x04;
1100
1101 }
1102 else
1103 {
1104 board[coords.x][coords.y].direction2 =
1105 (board[coords.x][coords.y].direction2 +
1106 2) & 0x03;
1107 board[coords.x][coords.y].state =
1108 board[x][y].direction | 0x04;
1109 board[coords.x][coords.y].moved = DELAY_GUN;
1110 }
1111 }
1112 if (board[coords.x][coords.y].rotable)
1113 { /* *neurocyp: we will not rotate, when we shoot */
1114 if (board[coords.x][coords.y].rotated == 0)
1115 {
1116
1117 if (board[coords.x][coords.y].randomrotated)
1118 {
1119 temp_direction = rand () & 0x03;
1120 if (board[coords.x][coords.y].movable ==
1121 1)
1122 {
1123 board[coords.x][coords.
1124 y].direction2 =
1125 abs (board[coords.x]
1126 [coords.y].direction2 +
1127 (temp_direction -
1128 board[coords.x][coords.
1129 y].direction))
1130 % 4;
1131 }
1132 board[coords.x][coords.y].direction =
1133 temp_direction;
1134 }
1135 else
1136 {
1137 board[coords.x][coords.y].direction =
1138 (board[coords.x][coords.y].direction +
1139 1) & 0x03;
1140 }
1141 board[coords.x][coords.y].rotated =
1142 DELAY_ROTATION;
1143 redraw_field (coords.x, coords.y);
1144 }
1145 }
1146 }
1147 if (board[coords.x][coords.y].shooted == 0)
1148 {
1149 if (board[coords.x][coords.y].solidlaser == 2)
1150 {
1151 if (((rand ()) & 0x07) == 0)
1152 { /* it's blaster */
1153 if (in_viewport (x, y))
1154 play_sound (SFX_GUN, SND_NORM);
1155 else
1156 play_sound (SFX_GUN, SND_QUIET);
1157 set_coords (&coords_temp, coords.x,
1158 coords.y);
1159 update_coords (&coords_temp,
1160 board[coords.x][coords.
1161 y].direction);
1162 if (robbo.x == coords_temp.x
1163 && robbo.y == coords_temp.y
1164 && robbo.teleporting == FALSE)
1165 {
1166 kill_robbo ();
1167 return; /* Thunor: Exiting here stops new blasters from being created */
1168 }
1169 switch (board[coords_temp.x]
1170 [coords_temp.y].type)
1171 {
1172 case BLASTER:
1173 case TELEPORT:
1174 case MAGNET:
1175 case WALL:
1176 case BOX:
1177 case PUSH_BOX:
1178 case CAPSULE:
1179 case SCREW:
1180 case STOP:
1181 case RADIOACTIVE_FIELD:
1182 case KEY:
1183 case DOOR:
1184 case GUN:
1185 board[coords.x][coords.y].shooted =
1186 DELAY_LASER;
1187 break;
1188 case BOMB2:
1189 case BOMB:
1190 board[coords_temp.x][coords_temp.
1191 y].blowed =
1192 DELAY_LASER;
1193 break;
1194 default:
1195
1196 clear_field (coords_temp.x,
1197 coords_temp.y);
1198 create_object (coords_temp.x,
1199 coords_temp.y, BLASTER);
1200 board[coords_temp.x][coords_temp.y].direction = board[coords.x][coords.y].direction; /* we allow moving blaster guns! */
1201 board[coords_temp.x][coords_temp.
1202 y].direction2 =
1203 board[coords.x][coords.y].direction;
1204 board[coords_temp.x][coords_temp.
1205 y].moved =
1206 DELAY_BLASTER;
1207 board[coords.x][coords.y].shooted =
1208 DELAY_LASER;
1209 }
1210 }
1211 else
1212 board[coords.x][coords.y].shooted =
1213 DELAY_LASER;
1214 }
1215 else
1216 {
1217 if ((rand () & 0x07) == 0)
1218 {
1219 /*
1220 * gun shoots
1221 */
1222 if (in_viewport (x, y))
1223 play_sound (SFX_GUN, SND_NORM);
1224 else
1225 play_sound (SFX_GUN, SND_QUIET);
1226 shoot_object (coords.x, coords.y,
1227 board[coords.x][coords.
1228 y].direction);
1229 }
1230 else
1231 board[coords.x][coords.y].shooted =
1232 DELAY_LASER;
1233 #ifdef DEBUG_MONITOR_OBJECT_PROCESSING
1234 printf
1235 ("--cycle_count=%i: board[coords.x=%i][coords.y=%i].processed=%i\n",
1236 cycle_count, coords.x, coords.y,
1237 board[coords.x][coords.y].processed);
1238 if (board[coords.x][coords.y].processed !=
1239 cycle_count)
1240 printf
1241 ("--OBJECT NOT MARKED AS PROCESSED FOR THIS CYCLE! <<<<<<<<<<\n");
1242 /*
1243 * printf("--cycle_count=%i:
1244 * board[dest.x=%i][dest.y=%i].processed=%i\n",
1245 * cycle_count, dest.x, dest.y,
1246 * board[dest.x][dest.y].processed);
1247 */
1248 /*
1249 * if (board[dest.x][dest.y].processed !=
1250 * cycle_count) printf("--OBJECT NOT
1251 * MARKED AS PROCESSED FOR THIS CYCLE!
1252 * <<<<<<<<<<\n");
1253 */
1254 #endif
1255 }
1256 }
1257 if (board[coords.x][coords.y].type == GUN
1258 && board[coords.x][coords.y].movable == 1)
1259 board[coords.x][coords.y].state = board[coords.x][coords.y].direction + 0x04; /* neurocyp: we want movable guns to have different icons */
1260 else
1261 board[coords.x][coords.y].state =
1262 board[coords.x][coords.y].direction;
1263 break;
1264
1265 }
1266 }
1267 #ifdef LIGHTNINGENABLED
1268 switch (board[x][y].type)
1269 {
1270 case CAPSULE:
1271 if (robbo.exitopened == FALSE)
1272 break;
1273 case TELEPORT:
1274 case TELEPORTING:
1275 case LITTLE_BOOM:
1276 case BIG_BOOM:
1277 seteffectsurround (x, y, board[x][y].state + 1);
1278 }
1279 #endif
1280
1281 } /* .processed check */
1282 }
1283
1284
1285 }
1286 }
1287
1288 /************************************************************/
1289 /********** Init questionmark objects **********************/
1290 /************************************************************/
1291
1292 void
init_questionmarks(void)1293 init_questionmarks (void)
1294 {
1295 int i, j;
1296
1297 for (i = 0; i < level.w; i++)
1298 for (j = 0; j < level.h; j++)
1299 {
1300 if (board[i][j].type == QUESTIONMARK)
1301 {
1302 board[i][j].id_questionmark = random_id ();
1303 }
1304 }
1305 }
1306
1307 /***************************************************************************
1308 * Returning really random object *
1309 ***************************************************************************/
1310 /*
1311 * Function returning random object id
1312 */
1313
1314 int
random_id(void)1315 random_id (void)
1316 {
1317 int ids[11] = { EMPTY_FIELD, PUSH_BOX, SCREW, BULLET, KEY, BOMB, GROUND,
1318 BUTTERFLY, GUN,
1319 QUESTIONMARK, CAPSULE
1320 };
1321
1322 if (game_mechanics.sensible_questionmarks)
1323 {
1324 return ids[my_rand () % 10];
1325 }
1326 else
1327 {
1328 return ids[my_rand () % 11];
1329 }
1330 }
1331
1332 /******************************************************/
1333 /*
1334 * Update Coords *************************************
1335 */
1336 /******************************************************/
1337 /*
1338 * Note that if modifying the coords results in them going off-board then
1339 * the coords returned are the same as passed
1340 */
1341
1342 int
update_coords(struct Coords * coords,int direction)1343 update_coords (struct Coords *coords, int direction)
1344 {
1345 struct Coords coords_temp;
1346 coords_temp.x = coords->x;
1347 coords_temp.y = coords->y;
1348
1349 if (direction == 0)
1350 coords->x++;
1351 else if (direction == 1)
1352 coords->y++;
1353 else if (direction == 2)
1354 coords->x--;
1355 else
1356 coords->y--;
1357
1358 if (coords->x < 0 || coords->y < 0 || coords->x >= level.w
1359 || coords->y >= level.h)
1360 {
1361 set_coords (coords, coords_temp.x, coords_temp.y);
1362 return 1;
1363 }
1364 return 0;
1365 }
1366
1367 /******************************************************/
1368 /*
1369 * Set Coords ****************************************
1370 */
1371 /******************************************************/
1372
1373 void
set_coords(struct Coords * coords,int x,int y)1374 set_coords (struct Coords *coords, int x, int y)
1375 {
1376 coords->x = x;
1377 coords->y = y;
1378 }
1379
1380 /******************************************************/
1381 /*
1382 * Coords Out Of Range *******************************
1383 */
1384 /******************************************************/
1385
1386 int
coords_out_of_range(struct Coords coords)1387 coords_out_of_range (struct Coords coords)
1388 {
1389 if (coords.x < 0 || coords.x >= level.w || coords.y < 0
1390 || coords.y >= level.h)
1391 return 1;
1392 else
1393 return 0;
1394 }
1395
1396 /*************************************************************/
1397 /*
1398 * Negating object state (birds waves their wings etc.. *****
1399 */
1400 /*************************************************************/
1401
1402 void
negate_state(int x,int y)1403 negate_state (int x, int y)
1404 {
1405 if (x < level.w && y < level.h)
1406 {
1407 board[x][y].state = !board[x][y].state;
1408 board[x][y].redraw = TRUE;
1409 }
1410 }
1411
1412 /******************************************************/
1413 /*
1414 * Set Images ****************************************
1415 */
1416 /******************************************************/
1417 /*
1418 * translate coordinates in the icons file, so we do not have to know the
1419 * precise values, just where the icon is located
1420 */
1421 int
gcoord(int a)1422 gcoord (int a)
1423 { /* this should be a macro, but if we would change the border sizes, we should include it now for tile size 16 border size is 1 and for ts=32 the border size is 2 */
1424 return ((video.field_size / 16) * a) + ((a - 1) * video.field_size);
1425 }
1426
1427
1428 /*
1429 * Neurocyp: refactored it a bit, so it could be ready to increase the
1430 * tile size in the future
1431 */
1432 void
set_images(int type,int x,int y)1433 set_images (int type, int x, int y)
1434 {
1435
1436 switch (type)
1437 {
1438 case EMPTY_FIELD:
1439 set_coords (&board[x][y].icon[0], 0, 0);
1440 break;
1441 case WALL: /* setting coords for icon */
1442 set_coords (&board[x][y].icon[0], gcoord (3), gcoord (1)); /* WALL */
1443 set_coords (&board[x][y].icon[1], gcoord (4), gcoord (1)); /* WALL_RED */
1444 set_coords (&board[x][y].icon[2], gcoord (6), gcoord (3)); /* WALL_GREEN */
1445 set_coords (&board[x][y].icon[3], gcoord (8), gcoord (2)); /* BLACK_WALL */
1446 set_coords (&board[x][y].icon[4], gcoord (10), gcoord (2)); /* FAT_WALL */
1447 set_coords (&board[x][y].icon[5], gcoord (9), gcoord (6)); /* ROUND_WALL */
1448 set_coords (&board[x][y].icon[6], gcoord (10), gcoord (6)); /* BOULDER_WALL */
1449 set_coords (&board[x][y].icon[7], gcoord (11), gcoord (1)); /* SQUARE_WALL */
1450 set_coords (&board[x][y].icon[8], gcoord (11), gcoord (2)); /* LATTICE_WALL */
1451
1452 set_coords (&board[x][y].icon[9], gcoord (1), gcoord (9)); /* Special Wall1 */
1453 set_coords (&board[x][y].icon[10], gcoord (2), gcoord (9)); /* Special Wall1 */
1454 set_coords (&board[x][y].icon[11], gcoord (3), gcoord (9)); /* Special Wall1 */
1455 set_coords (&board[x][y].icon[12], gcoord (4), gcoord (9)); /* Special Wall1 */
1456 set_coords (&board[x][y].icon[13], gcoord (5), gcoord (9)); /* Special Wall1 */
1457 set_coords (&board[x][y].icon[14], gcoord (6), gcoord (9)); /* Special Wall1 */
1458 set_coords (&board[x][y].icon[15], gcoord (7), gcoord (9)); /* Special Wall1 */
1459 set_coords (&board[x][y].icon[16], gcoord (8), gcoord (9)); /* Special Wall1 */
1460 //set_coords(&board[x][y].icon[17], gcoord(8),gcoord(9)); /* Special Wall1 */
1461 set_coords (&board[x][y].icon[17], gcoord (1), gcoord (10)); /* Special Wall1 */
1462 set_coords (&board[x][y].icon[18], gcoord (2), gcoord (10)); /* Special Wall1 */
1463 set_coords (&board[x][y].icon[19], gcoord (3), gcoord (10)); /* Special Wall1 */
1464 set_coords (&board[x][y].icon[20], gcoord (4), gcoord (10)); /* Special Wall1 */
1465 set_coords (&board[x][y].icon[21], gcoord (5), gcoord (10)); /* Special Wall1 */
1466 set_coords (&board[x][y].icon[22], gcoord (6), gcoord (10)); /* Special Wall1 */
1467 set_coords (&board[x][y].icon[23], gcoord (7), gcoord (10)); /* Special Wall1 */
1468 set_coords (&board[x][y].icon[24], gcoord (8), gcoord (10)); /* Special Wall1 */
1469 break;
1470 case SCREW:
1471 set_coords (&board[x][y].icon[0], gcoord (5), gcoord (1));
1472 break;
1473 case BULLET:
1474 set_coords (&board[x][y].icon[0], gcoord (6), gcoord (1));
1475 break;
1476 case BOX:
1477 set_coords (&board[x][y].icon[0], gcoord (7), gcoord (1));
1478 break;
1479 case PUSH_BOX:
1480 set_coords (&board[x][y].icon[0], gcoord (7), gcoord (7));
1481 set_coords (&board[x][y].icon[1], gcoord (9), gcoord (2)); /* pushed box changes state */
1482 break;
1483 case KEY:
1484 set_coords (&board[x][y].icon[0], gcoord (8), gcoord (1));
1485 break;
1486 case BOMB2:
1487 set_coords (&board[x][y].icon[0], gcoord (8), gcoord (7));
1488 break;
1489 case BOMB:
1490 set_coords (&board[x][y].icon[0], gcoord (9), gcoord (1));
1491 break;
1492 case DOOR:
1493 set_coords (&board[x][y].icon[0], gcoord (10), gcoord (1));
1494 break;
1495 case QUESTIONMARK:
1496 set_coords (&board[x][y].icon[0], gcoord (1), gcoord (2));
1497 break;
1498
1499 case CAPSULE:
1500 set_coords (&board[x][y].icon[0], gcoord (6), gcoord (2));
1501 set_coords (&board[x][y].icon[1], gcoord (7), gcoord (2));
1502 break;
1503 case BEAR:
1504 set_coords (&board[x][y].icon[0], gcoord (2), gcoord (2));
1505 set_coords (&board[x][y].icon[1], gcoord (3), gcoord (2));
1506 break;
1507 case BIRD:
1508 set_coords (&board[x][y].icon[0], gcoord (4), gcoord (2));
1509 set_coords (&board[x][y].icon[1], gcoord (5), gcoord (2));
1510 break;
1511 case LITTLE_BOOM:
1512 set_coords (&board[x][y].icon[0], gcoord (2), gcoord (3));
1513 set_coords (&board[x][y].icon[1], gcoord (3), gcoord (3));
1514 set_coords (&board[x][y].icon[2], gcoord (4), gcoord (3));
1515 set_coords (&board[x][y].icon[3], gcoord (5), gcoord (3));
1516 break;
1517 case GROUND:
1518 set_coords (&board[x][y].icon[0], gcoord (6), gcoord (7));
1519 break;
1520 case BEAR_B:
1521 set_coords (&board[x][y].icon[0], gcoord (7), gcoord (3));
1522 set_coords (&board[x][y].icon[1], gcoord (8), gcoord (3));
1523 break;
1524 case BUTTERFLY:
1525 set_coords (&board[x][y].icon[0], gcoord (9), gcoord (3));
1526 set_coords (&board[x][y].icon[1], gcoord (10), gcoord (3));
1527 break;
1528 case LASER_L:
1529 set_coords (&board[x][y].icon[0], gcoord (1), gcoord (4));
1530 set_coords (&board[x][y].icon[1], gcoord (2), gcoord (4));
1531 set_coords (&board[x][y].icon[2], gcoord (1), gcoord (3)); /* Thunor: Added for solid lasers */
1532 set_coords (&board[x][y].icon[3], gcoord (6), gcoord (8));
1533 break;
1534 case LASER_D:
1535 set_coords (&board[x][y].icon[0], gcoord (3), gcoord (4));
1536 set_coords (&board[x][y].icon[1], gcoord (4), gcoord (4));
1537 set_coords (&board[x][y].icon[2], gcoord (6), gcoord (4)); /* Thunor: Added for solid lasers */
1538 set_coords (&board[x][y].icon[3], gcoord (7), gcoord (8)); /* Thunor: Added for solid lasers */
1539
1540 break;
1541 case TELEPORT:
1542 set_coords (&board[x][y].icon[0], gcoord (1), gcoord (5));
1543 set_coords (&board[x][y].icon[1], gcoord (2), gcoord (5));
1544 break;
1545 case TELEPORTING: /* Thunor: Added for dedicated teleport animation */
1546 set_coords (&board[x][y].icon[0], gcoord (11), gcoord (4));
1547 set_coords (&board[x][y].icon[1], gcoord (11), gcoord (5));
1548 set_coords (&board[x][y].icon[2], gcoord (11), gcoord (6));
1549 set_coords (&board[x][y].icon[3], gcoord (11), gcoord (7));
1550 set_coords (&board[x][y].icon[4], gcoord (11), gcoord (8));
1551 break;
1552 case BIG_BOOM:
1553 set_coords (&board[x][y].icon[0], gcoord (1), gcoord (8)); /* Neurocyp: Added to distinguish booms from blasters */
1554 set_coords (&board[x][y].icon[1], gcoord (2), gcoord (8));
1555 set_coords (&board[x][y].icon[2], gcoord (3), gcoord (8));
1556 set_coords (&board[x][y].icon[3], gcoord (4), gcoord (8));
1557 set_coords (&board[x][y].icon[4], gcoord (5), gcoord (8));
1558 break;
1559
1560 case GUN:
1561 set_coords (&board[x][y].icon[0], gcoord (6), gcoord (5));
1562 set_coords (&board[x][y].icon[1], gcoord (7), gcoord (5));
1563 set_coords (&board[x][y].icon[2], gcoord (8), gcoord (5));
1564 set_coords (&board[x][y].icon[3], gcoord (9), gcoord (5));
1565 set_coords (&board[x][y].icon[4], gcoord (9), gcoord (8));
1566 set_coords (&board[x][y].icon[5], gcoord (10), gcoord (7));
1567 set_coords (&board[x][y].icon[6], gcoord (10), gcoord (8));
1568 set_coords (&board[x][y].icon[7], gcoord (9), gcoord (7));
1569 break;
1570 case MAGNET:
1571 set_coords (&board[x][y].icon[0], gcoord (1), gcoord (1));
1572 set_coords (&board[x][y].icon[1], gcoord (1), gcoord (7));
1573 set_coords (&board[x][y].icon[2], gcoord (2), gcoord (1));
1574 set_coords (&board[x][y].icon[3], gcoord (2), gcoord (7));
1575 break;
1576 case BLASTER:
1577 set_coords (&board[x][y].icon[0], gcoord (3), gcoord (5));
1578 set_coords (&board[x][y].icon[1], gcoord (4), gcoord (5));
1579 set_coords (&board[x][y].icon[2], gcoord (5), gcoord (5));
1580 set_coords (&board[x][y].icon[3], gcoord (4), gcoord (5));
1581 set_coords (&board[x][y].icon[4], gcoord (3), gcoord (5));
1582 break;
1583 case BARRIER:
1584 set_coords (&board[x][y].icon[0], gcoord (10), gcoord (4));
1585 set_coords (&board[x][y].icon[1], gcoord (10), gcoord (5));
1586 break;
1587 case RADIOACTIVE_FIELD:
1588 set_coords (&board[x][y].icon[0], gcoord (3), gcoord (7));
1589 set_coords (&board[x][y].icon[1], gcoord (4), gcoord (7));
1590
1591 break;
1592 case STOP:
1593 set_coords (&board[x][y].icon[0], gcoord (5), gcoord (7));
1594 break;
1595
1596 }
1597
1598 }
1599
1600 /************************************************************/
1601 /*
1602 * This function checks if object can move on the field ****
1603 */
1604 /*
1605 * described by direction and coordinates, if not returns 0
1606 */
1607 /************************************************************/
1608
1609 int
can_move(struct Coords coords,int direction)1610 can_move (struct Coords coords, int direction)
1611 {
1612 if (update_coords (&coords, direction) ||
1613 (board[coords.x][coords.y].type != EMPTY_FIELD) ||
1614 ((robbo.x == coords.x) && (robbo.y == coords.y)) ||
1615 board[coords.x][coords.y].moved > 0)
1616 return 0;
1617 else
1618 return 1;
1619 }
1620
1621 /**************************************************/
1622 /*
1623 * Function moves object deleting object data ****
1624 */
1625 /*
1626 * from one field and moves them to another ******
1627 */
1628 /**************************************************/
1629
1630 void
move_object(int x,int y,struct Coords coords)1631 move_object (int x, int y, struct Coords coords)
1632 {
1633 int x1, y1;
1634
1635 if ((x == coords.x) && (y == coords.y)) /* move to the same place */
1636 return;
1637
1638 x1 = coords.x;
1639 y1 = coords.y;
1640
1641 board[x1][y1].type = board[x][y].type;
1642 board[x1][y1].state = board[x][y].state;
1643 board[x1][y1].direction = board[x][y].direction;
1644 board[x1][y1].destroyable = board[x][y].destroyable;
1645 board[x1][y1].blowable = board[x][y].blowable;
1646 board[x1][y1].killing = board[x][y].killing;
1647 board[x1][y1].moved = board[x][y].moved;
1648 board[x1][y1].blowed = board[x][y].blowed;
1649 board[x1][y1].shooted = board[x][y].shooted;
1650 board[x1][y1].rotated = board[x][y].rotated;
1651 board[x1][y1].solidlaser = board[x][y].solidlaser;
1652 board[x1][y1].rotable = board[x][y].rotable;
1653 board[x1][y1].randomrotated = board[x][y].randomrotated;
1654 /*
1655 * NOTE: teleportnumber is not being moved
1656 */
1657 /*
1658 * NOTE: teleportnumber2 is not being moved
1659 */
1660 board[x1][y1].id_questionmark = board[x][y].id_questionmark;
1661 board[x1][y1].direction2 = board[x][y].direction2;
1662 board[x1][y1].movable = board[x][y].movable;
1663 /*
1664 * NOTE: returnlaser is not being moved
1665 */
1666 board[x1][y1].shooting = board[x][y].shooting;
1667 board[x1][y1].processed = board[x][y].processed;
1668 board[x1][y1].redraw = TRUE;
1669
1670 set_images (board[x1][y1].type, x1, y1);
1671 clear_field (x, y);
1672
1673 }
1674
1675 /*************************************************************/
1676 /******* If objects shoots... ********************************/
1677 /*************************************************************/
1678
1679 void
shoot_object(int x,int y,int direction)1680 shoot_object (int x, int y, int direction)
1681 {
1682 struct Coords coords;
1683
1684 if (board[x][y].shooted > 0)
1685 return;
1686 #ifdef LIGHTNINGENABLED
1687 board[x][y].effect = EFX_SHOOT;
1688 #endif
1689 set_coords (&coords, x, y);
1690
1691 if (update_coords (&coords, direction))
1692 {
1693 board[coords.x][coords.y].shooted = DELAY_LASER;
1694 return;
1695 }
1696
1697 if ((coords.x == robbo.x) && (coords.y == robbo.y))
1698 {
1699 kill_robbo ();
1700 return; /* This prevents more lasers being created after Robbo dies */
1701 }
1702
1703 switch (board[coords.x][coords.y].destroyable)
1704 {
1705 case 1:
1706 if ((board[coords.x][coords.y].type != BOMB)
1707 && (board[coords.x][coords.y].type != BOMB2))
1708 {
1709 if (in_viewport (x, y))
1710 play_sound (SFX_KILL, SND_NORM);
1711 else
1712 play_sound (SFX_KILL, SND_QUIET);
1713 }
1714 board[coords.x][coords.y].blowed = 1;
1715 board[coords.x][coords.y].shooted = DELAY_LASER;
1716 if (board[x][y].solidlaser == 1)
1717 {
1718 board[x][y].moved = DELAY_LASER;
1719 }
1720 return;
1721 default:
1722 break;
1723 }
1724 switch (board[coords.x][coords.y].type)
1725 {
1726 case EMPTY_FIELD:
1727 if (direction == 0 || direction == 2)
1728 {
1729 clear_field (coords.x, coords.y);
1730 create_object (coords.x, coords.y, LASER_L);
1731 }
1732 else
1733 {
1734 clear_field (coords.x, coords.y);
1735 create_object (coords.x, coords.y, LASER_D);
1736 }
1737
1738 board[coords.x][coords.y].direction = direction;
1739 board[coords.x][coords.y].solidlaser = board[x][y].solidlaser;
1740
1741 board[x][y].shooted = DELAY_LASER;
1742 board[coords.x][coords.y].moved = DELAY_LASER;
1743 /*
1744 * Thunor: I decided to use different animation frame(s) for the
1745 * solid laser fire to make the graphics more interesting
1746 */
1747 if (board[coords.x][coords.y].solidlaser == 1)
1748 board[coords.x][coords.y].state =
1749 (board[x][y].state == 3) ? board[x][y].state : (rand () % 2) + 2;
1750
1751 break;
1752 case LASER_D:
1753 case LASER_L:
1754 break;
1755 }
1756 }
1757
1758 /****************************************************************/
1759 /*
1760 * Function marks all objects blowed around the bomb ***********
1761 */
1762 /****************************************************************/
1763
1764 void
blow_bomb(int x,int y)1765 blow_bomb (int x, int y)
1766 {
1767 struct Coords coords, laserpath;
1768 int i, x1, y1;
1769 if (robbo.alive)
1770 {
1771 if (in_viewport (x, y))
1772 play_sound (SFX_BOMB, SND_NORM);
1773 else
1774 play_sound (SFX_BOMB, SND_QUIET);
1775 }
1776 if (!robbo.alive)
1777 { /* neurocyp: Robbo is not alive, we do not blow the bomb, we just create BIG_BOOM in its place */
1778 create_object (x, y, BIG_BOOM);
1779 board[x][y].moved = DELAY_BIGBOOM;
1780 return;
1781 }
1782 for (i = 0; i < 9; i++)
1783 { /* neurocyp: here there was an ugly switch statement, now replaced with a little formula */
1784 x1 = (((i % 3) > 1) ? -1 : (i % 3));
1785 y1 = ((((i / 3) % 3) > 1) ? -1 : ((i / 3) % 3));
1786 coords.x = x + x1;
1787 coords.y = y + y1;
1788 /*
1789 * Robbo was near blowing up
1790 */
1791 if ((robbo.x == coords.x) && (robbo.y == coords.y))
1792 {
1793 kill_robbo ();
1794 }
1795
1796 /*
1797 * Blow-up the object
1798 */
1799 if (!coords_out_of_range (coords) && !board[coords.x][coords.y].blowed
1800 && board[coords.x][coords.y].blowable)
1801 {
1802 if (board[coords.x][coords.y].type == GUN)
1803 {
1804 board[coords.x][coords.y].blowed = 1;
1805 board[coords.x][coords.y].moved = DELAY_BOMB_TARGET;
1806 /*
1807 * Thunor: In Atari Robbo the solid laser fire is left
1808 * live when the gun is destroyed which is a bit
1809 * nonsensical so I have introduced an rcfile overrideable
1810 * game_mechanic.sensible_solid_lasers
1811 */
1812 if (board[coords.x][coords.y].solidlaser
1813 && game_mechanics.sensible_solid_lasers)
1814 {
1815 set_coords (&laserpath, coords.x, coords.y);
1816 while (!update_coords
1817 (&laserpath, (board[coords.x][coords.y].direction))
1818 && (board[laserpath.x][laserpath.y].type == LASER_D
1819 || board[laserpath.x][laserpath.y].type ==
1820 LASER_L)
1821 && board[laserpath.x][laserpath.y].solidlaser
1822 && board[laserpath.x][laserpath.y].direction ==
1823 board[coords.x][coords.y].direction)
1824 {
1825 board[laserpath.x][laserpath.y].blowed = 1;
1826 board[laserpath.x][laserpath.y].moved =
1827 DELAY_BOMB_TARGET;
1828 }
1829 }
1830 /*
1831 * Thunor: In Atari Robbo the solid laser is not blowable
1832 * but in GNU Robbo there is no solid laser type, so I
1833 * need to check the solidlaser property here
1834 */
1835 }
1836 else
1837 if (!
1838 ((board[coords.x][coords.y].type == LASER_D
1839 || board[coords.x][coords.y].type == LASER_L)
1840 && board[coords.x][coords.y].solidlaser))
1841 {
1842 board[coords.x][coords.y].blowed = 1;
1843 board[coords.x][coords.y].moved = DELAY_BOMB_TARGET;
1844 board[coords.x][coords.y].id_questionmark = 0; /* blowed questionmark doesn't uncover */
1845 }
1846 }
1847 }
1848 }
1849
1850 /* Robbo Alex has at leas two different bomb types, here is the place, where we blow these */
1851 /* routine is very similar to regular bomb */
1852 void
blow_bomb2(int x,int y)1853 blow_bomb2 (int x, int y)
1854 {
1855 struct Coords coords, laserpath;
1856 int i, direction = -1, x1, y1;
1857
1858 if (robbo.alive)
1859 {
1860 if (in_viewport (x, y))
1861 play_sound (SFX_BOMB, SND_NORM);
1862 else
1863 play_sound (SFX_BOMB, SND_QUIET);
1864 }
1865 if (!robbo.alive)
1866 { /* neurocyp: Robbo is not alive, we do not blow the bomb, we just create BIG_BOOM in its place */
1867 create_object (x, y, BIG_BOOM);
1868 board[x][y].moved = DELAY_BIGBOOM;
1869 return;
1870 }
1871 for (i = 0; i < 9; i++)
1872 {
1873 x1 = (((i % 3) > 1) ? -1 : (i % 3)); /* neurocyp: move on x axis */
1874 y1 = ((((i / 3) % 3) > 1) ? -1 : ((i / 3) % 3)); /* neurocyp: move on y axis */
1875 coords.x = x + x1;
1876 coords.y = y + y1;
1877 if (x1 == 0 || y1 == 0)
1878 direction = (x1 != 0) ? (-x1 + 1) : (-y1 + 2); /* calculate a direction */
1879 /* Robbo was near the bomb */
1880 if ((robbo.x == coords.x) && (robbo.y == coords.y))
1881 {
1882 kill_robbo ();
1883 }
1884
1885 /*
1886 * Blow-up the object
1887 */
1888 if (x1 != 0 && y1 != 0)
1889 {
1890 if (!coords_out_of_range (coords)
1891 && !board[coords.x][coords.y].blowed
1892 && board[coords.x][coords.y].blowable)
1893 {
1894 if (board[coords.x][coords.y].type == GUN)
1895 {
1896 board[coords.x][coords.y].blowed = 1;
1897 board[coords.x][coords.y].moved = DELAY_BOMB_TARGET;
1898 /*
1899 * Thunor: In Atari Robbo the solid laser fire is left
1900 * live when the gun is destroyed which is a bit
1901 * nonsensical so I have introduced an rcfile overrideable
1902 * game_mechanic.sensible_solid_lasers
1903 */
1904 if (board[coords.x][coords.y].solidlaser
1905 && game_mechanics.sensible_solid_lasers)
1906 {
1907 set_coords (&laserpath, coords.x, coords.y);
1908 while (!update_coords
1909 (&laserpath,
1910 (board[coords.x][coords.y].direction))
1911 && (board[laserpath.x][laserpath.y].type ==
1912 LASER_D
1913 || board[laserpath.x][laserpath.y].type ==
1914 LASER_L)
1915 && board[laserpath.x][laserpath.y].solidlaser
1916 && board[laserpath.x][laserpath.y].direction ==
1917 board[coords.x][coords.y].direction)
1918 {
1919 board[laserpath.x][laserpath.y].blowed = 1;
1920 board[laserpath.x][laserpath.y].moved =
1921 DELAY_BOMB_TARGET;
1922 }
1923 }
1924 /*
1925 * Thunor: In Atari Robbo the solid laser is not blowable
1926 * but in GNU Robbo there is no solid laser type, so I
1927 * need to check the solidlaser property here
1928 */
1929 }
1930 else
1931 if (!
1932 ((board[coords.x][coords.y].type == LASER_D
1933 || board[coords.x][coords.y].type == LASER_L)
1934 && board[coords.x][coords.y].solidlaser))
1935 {
1936 board[coords.x][coords.y].blowed = 1;
1937 board[coords.x][coords.y].moved = DELAY_BOMB_TARGET;
1938 board[coords.x][coords.y].id_questionmark = 0; /* blowed questionmark doesn't uncover */
1939 }
1940 }
1941 }
1942 else
1943 { /* we have to shoot in 4 directions */
1944 shoot_object (x, y, direction);
1945 board[coords.x][coords.y].moved = DELAY_BOMB_TARGET;
1946 if (i < 7)
1947 board[x][y].shooted = 0; /* yes, we want to shoot again this tiime, really fast, that is why we reset this */
1948 }
1949 }
1950 }
1951
1952 /*****************************************************/
1953 /**** Check Object If Blowed *************************/
1954 /*****************************************************/
1955 /*
1956 * Thunor: NOTE that the object that is being created here is not cleared
1957 * beforehand. The reason for this I have found is because once it has
1958 * blown-up, its id_questionmark property is checked to see if it was a
1959 * questionmark and if it needs to be recreated
1960 */
1961
1962 void
check_object_if_blowed(int x,int y)1963 check_object_if_blowed (int x, int y)
1964 {
1965 if (board[x][y].blowed && board[x][y].type != BIG_BOOM)
1966 {
1967 if (board[x][y].type == BOMB)
1968 blow_bomb (x, y);
1969 if (board[x][y].type == BOMB2)
1970 blow_bomb2 (x, y);
1971 create_object (x, y, BIG_BOOM);
1972 board[x][y].moved = DELAY_BIGBOOM;
1973 }
1974 }
1975
1976 /**********************************************************/
1977 /** If Robbo collects the last screw exit opens ***********/
1978 /**********************************************************/
1979
1980 void
open_exit(void)1981 open_exit (void)
1982 {
1983 robbo.exitopened = 1;
1984 level.now_is_blinking = DELAY_BLINKSCREEN;
1985 viewport_needs_redrawing ();
1986 }
1987
1988 /*************************************************************/
1989 /**** Function returning coords of finding teleport **********/
1990 /**** Updates coords of found teleport of 0 if not found *****/
1991 /*************************************************************/
1992
1993 int
find_teleport(struct Coords * coords,int teleportnumber,int teleportnumber2)1994 find_teleport (struct Coords *coords, int teleportnumber, int teleportnumber2)
1995 {
1996 int i, j;
1997
1998 for (i = 0; i < level.w; i++)
1999 for (j = 0; j < level.h; j++)
2000 {
2001 if (board[i][j].type == TELEPORT)
2002 {
2003 if (teleportnumber == board[i][j].teleportnumber)
2004 { /* found the same kind */
2005 if (teleportnumber2 == board[i][j].teleportnumber2)
2006 { /* next teleport */
2007 set_coords (coords, i, j);
2008 return 1; /* found exact_teleport */
2009 }
2010 }
2011 }
2012 }
2013
2014 return 0; /* teleport with this number has not been found... */
2015 }
2016
2017 /***************************************************************************
2018 * Robbo initialisation *
2019 ***************************************************************************/
2020 /*
2021 * Clear everything
2022 */
2023
2024 void
init_robbo(void)2025 init_robbo (void)
2026 {
2027 robbo.x = 0;
2028 robbo.y = 0;
2029 robbo.alive = 1;
2030 robbo.state = 0;
2031 robbo.direction = 0;
2032 robbo.screws = 0;
2033 robbo.keys = 0;
2034 robbo.bullets = 0;
2035 robbo.moved = DELAY_ROBBO;
2036 robbo.shooted = 0;
2037 robbo.exitopened = 0;
2038 robbo.blocked = 0;
2039 robbo.blocked_direction = 0;
2040 robbo.teleporting = 0;
2041 }
2042
2043 /********************************************************************/
2044 /*** Robbo moving function ******************************************/
2045 /********************************************************************/
2046
2047 void
move_robbo(int x,int y)2048 move_robbo (int x, int y)
2049 {
2050 int x_tmp, y_tmp, x2_tmp, y2_tmp;
2051 int i, j, k;
2052 int dir_tmp;
2053 struct Coords coords;
2054
2055 if (robbo.blocked || robbo.moved > 0)
2056 {
2057
2058 return;
2059 }
2060 // if (robbo.moved > 0)
2061 // /* robbo cannot move yet */
2062 // return;
2063
2064 x_tmp = robbo.x + x;
2065 y_tmp = robbo.y + y;
2066
2067 if ((x == 1) && (y == 0))
2068 robbo.direction = 0;
2069 else if ((x == 0) && (y == 1))
2070 robbo.direction = 2;
2071 else if ((x == -1) && (y == 0))
2072 robbo.direction = 4;
2073 else if ((x == 0) && (y == -1))
2074 robbo.direction = 6;
2075
2076 if (x_tmp < 0 || x_tmp >= level.w || y_tmp < 0 || y_tmp >= level.h)
2077 return;
2078
2079 redraw_field (robbo.x, robbo.y); /* Redraw the source field */
2080
2081 switch (board[x_tmp][y_tmp].type)
2082 {
2083 case STOP:
2084 clear_field (x_tmp, y_tmp);
2085 break;
2086 case RADIOACTIVE_FIELD:
2087 clear_field (x_tmp, y_tmp);
2088 kill_robbo ();
2089 break;
2090
2091 case EMPTY_FIELD:
2092 case ROBBO: /* Robbo can move there */
2093 redraw_field (x_tmp, y_tmp); /* Redraw destination field */
2094 break;
2095 case SCREW:
2096
2097 if (robbo.screws > 0)
2098 {
2099 robbo.screws--;
2100 }
2101
2102 if (robbo.screws == 0)
2103 { /* play sound for open exit */
2104 play_sound (SFX_EXIT_OPEN, SND_NORM);
2105 open_exit ();
2106 }
2107 else
2108 play_sound (SFX_SCREW, SND_NORM); /* play sound for collected screw */
2109
2110 scoreline.redraw |= SCORELINE_SCREWS;
2111 clear_field (x_tmp, y_tmp);
2112 break;
2113 case BULLET:
2114 play_sound (SFX_BULLET, SND_NORM); /* play sound for collected ammo */
2115 robbo.bullets += 9;
2116 scoreline.redraw |= SCORELINE_BULLETS;
2117 clear_field (x_tmp, y_tmp);
2118 break;
2119 case KEY:
2120 play_sound (SFX_KEY, SND_NORM); /* play sound for collected key */
2121 robbo.keys++;
2122 scoreline.redraw |= SCORELINE_KEYS;
2123 clear_field (x_tmp, y_tmp);
2124 break;
2125 case DOOR: /* Robbo cannot move */
2126 if (robbo.keys > 0)
2127 { /* should open the door first */
2128 robbo.keys--;
2129 scoreline.redraw |= SCORELINE_KEYS;
2130 clear_field (x_tmp, y_tmp);
2131 robbo.moved = DELAY_ROBBO;
2132 play_sound (SFX_DOOR, SND_NORM); /* play sound for door open */
2133 }
2134 return;
2135 case TELEPORT:
2136 if (board[x_tmp][y_tmp].teleportnumber == 0)
2137 break;
2138 play_sound (SFX_TELEPORT, SND_NORM); /* teleport sound */
2139 i = 0;
2140 j = board[x_tmp][y_tmp].teleportnumber2;
2141
2142 while (i == 0)
2143 {
2144 j++;
2145
2146 if (((find_teleport
2147 (&coords, board[x_tmp][y_tmp].teleportnumber, j)) == 0)
2148 && j != board[x_tmp][y_tmp].teleportnumber2)
2149 { /* teleport not found */
2150 if (j > MAX_TELEPORT_IDS)
2151 j = -1;
2152 continue;
2153 }
2154
2155 dir_tmp = (robbo.direction / 2); /* neurocyp * new teleport logic now it should be the same as original robbo logic */
2156 for (k = 0; k < 4; k++)
2157 { /* first time, the direction, where robbo tries to go is checked */
2158 if (can_move (coords, dir_tmp))
2159 {
2160 create_object (robbo.x, robbo.y, TELEPORTING); /* Create src teleporting animation */
2161 update_coords (&coords, dir_tmp);
2162 x_tmp = coords.x;
2163 y_tmp = coords.y;
2164 robbo.direction = (dir_tmp * 2);
2165 create_object (x_tmp, y_tmp, TELEPORTING); /* Create dest teleporting animation */
2166 robbo.moved = DELAY_TELEPORTING * 5; /* 5 frames of teleporting animation */
2167 viewport.cycles_to_dest = robbo.moved;
2168 robbo.teleporting = TRUE;
2169 i = 1;
2170 break;
2171 }
2172 dir_tmp = dir_tmp ^ (((k + 1) % 2) + 2);
2173 }
2174 if (j == board[x_tmp][y_tmp].teleportnumber2 && i == 0)
2175 { /* protect from freezing the game */
2176 create_object (robbo.x, robbo.y, TELEPORTING); /* Create src/dest teleporting animation */
2177 robbo.moved = DELAY_TELEPORTING * 5; /* 5 frames of teleporting animation */
2178 viewport.cycles_to_dest = robbo.moved;
2179 robbo.teleporting = TRUE;
2180 i = 1;
2181 return;
2182 }
2183 }
2184 break;
2185 case CAPSULE:
2186 if (robbo.exitopened)
2187 {
2188 play_sound (SFX_CAPSULE, SND_NORM);
2189 /*
2190 * Check for pack completion
2191 */
2192 if (level_packs[selected_pack].level_selected >=
2193 level_packs[selected_pack].last_level)
2194 {
2195 game_mode = END_SCREEN;
2196 return;
2197 }
2198 else
2199 {
2200 level_packs[selected_pack].level_selected++;
2201 if (level_packs[selected_pack].level_selected >
2202 level_packs[selected_pack].level_reached)
2203 {
2204 level_packs[selected_pack].level_reached =
2205 level_packs[selected_pack].level_selected;
2206 /*
2207 * Save rcfile now if requested -- recommended for
2208 * battery operated or unstable devices
2209 */
2210 if (rcfile.save_frequency == RCFILE_SAVE_ON_CHANGE)
2211 {
2212 save_resource_file (path_resource_file, FALSE);
2213 #if defined(PLATFORM_WIN32) || defined(PLATFORM_PC)
2214 #elif defined(PLATFORM_GP2X) || defined(PLATFORM_CAANOO)
2215 system ("sync");
2216 #elif defined(PLATFORM_ZAURUS)
2217 #elif defined(PLATFORM_PSP)
2218 #endif
2219 }
2220 }
2221 if (level_init ())
2222 {
2223 game_mode = INTRO_SCREEN;
2224 music_stop ();
2225 intro_screen.redraw |= REDRAW_INITIALISE;
2226 }
2227 else
2228 {
2229 game_area.redraw |= REDRAW_EVERYTHING;
2230 /*
2231 * Initialise the fade
2232 */
2233 show_game_area_fade (FADE_SUB_INITIALISE, 16);
2234 }
2235 return;
2236 }
2237 }
2238 case BOX: /* Moveable objects */
2239 case PUSH_BOX:
2240 case BOMB:
2241 case BOMB2:
2242 case QUESTIONMARK:
2243 case GUN:
2244 if ((board[x_tmp][y_tmp].type == GUN)
2245 && (board[x_tmp][y_tmp].movable == 0))
2246 return;
2247 y2_tmp = robbo.y + (2 * y);
2248 x2_tmp = robbo.x + (2 * x);
2249 if (x2_tmp < 0 || x2_tmp >= level.w || y2_tmp < 0 || y2_tmp >= level.h)
2250 return;
2251
2252 coords.x = x2_tmp;
2253 coords.y = y2_tmp;
2254
2255 if (board[x2_tmp][y2_tmp].type == EMPTY_FIELD)
2256 {
2257 play_sound (SFX_BOX, SND_NORM);
2258 if (board[x_tmp][y_tmp].type == PUSH_BOX)
2259 {
2260 board[x_tmp][y_tmp].state = 1; /* box is pushed */
2261 board[x_tmp][y_tmp].direction = (robbo.direction / 2);
2262 }
2263 move_object (x_tmp, y_tmp, coords);
2264 if (board[coords.x][coords.y].type != GUN)
2265 board[coords.x][coords.y].moved = DELAY_PUSHBOX;
2266 }
2267 else
2268 {
2269 robbo.moved = DELAY_ROBBO;
2270 return;
2271 }
2272 break;
2273 default: /* every else objects */
2274 return;
2275 }
2276
2277 robbo.x = x_tmp;
2278 robbo.y = y_tmp;
2279
2280 if (robbo.moved == 0)
2281 {
2282 robbo.moved = DELAY_ROBBO; /* delay robbo */
2283 if (!robbo.blocked)
2284 play_sound (SFX_ROBBO, SND_NORM);
2285 }
2286
2287 }
2288
2289 /*********************************************************/
2290 /** Robbo shoots - x, y means coords of Robbo ************/
2291 /*********************************************************/
2292
2293 void
shoot_robbo(int x,int y)2294 shoot_robbo (int x, int y)
2295 {
2296 int x_tmp, y_tmp;
2297
2298 if (robbo.shooted > 0)
2299 return;
2300
2301 /*
2302 * Is Robbo currently being pulled by a magnet or teleporting?
2303 */
2304 if (robbo.blocked || robbo.teleporting)
2305 return; /* Matches original Robbo */
2306
2307 x_tmp = robbo.x + x;
2308 y_tmp = robbo.y + y;
2309
2310 if ((x == 1) && (y == 0))
2311 robbo.direction = 0;
2312 else if ((x == 0) && (y == 1))
2313 robbo.direction = 2;
2314 else if ((x == -1) && (y == 0))
2315 robbo.direction = 4;
2316 else if ((x == 0) && (y == -1))
2317 robbo.direction = 6;
2318
2319 redraw_field (robbo.x, robbo.y);
2320
2321 if (robbo.bullets == 0)
2322 return;
2323 if (x_tmp < 0 || x_tmp >= level.w || y_tmp < 0 || y_tmp >= level.h)
2324 {
2325 robbo.bullets--;
2326 robbo.shooted = DELAY_LASER;
2327 return;
2328 }
2329
2330 switch (board[x_tmp][y_tmp].destroyable)
2331 {
2332 case 1: /* objects can be destroyed */
2333 board[x_tmp][y_tmp].blowed = 1;
2334 play_sound (SFX_SHOOT, SND_QUIET);
2335
2336 if (board[x_tmp][y_tmp].type != BOMB)
2337 {
2338 // printf("%d\n", board[x_tmp][y_tmp].type);
2339 play_sound (SFX_KILL, SND_NORM);
2340 }
2341 robbo.shooted = DELAY_LASER;
2342 robbo.bullets--;
2343 scoreline.redraw |= SCORELINE_BULLETS;
2344 return;
2345 case 0:
2346 play_sound (SFX_SHOOT, SND_NORM);
2347
2348 robbo.shooted = DELAY_LASER;
2349 robbo.bullets--;
2350 scoreline.redraw |= SCORELINE_BULLETS;
2351 break;
2352 }
2353
2354 switch (board[x_tmp][y_tmp].type)
2355 {
2356 case EMPTY_FIELD:
2357 if (robbo.direction == 0 || robbo.direction == 4)
2358 create_object (x_tmp, y_tmp, LASER_L);
2359 else
2360 create_object (x_tmp, y_tmp, LASER_D);
2361
2362 board[x_tmp][y_tmp].moved = DELAY_LASER;
2363 board[x_tmp][y_tmp].direction = robbo.direction / 2;
2364 break;
2365 }
2366 }
2367
2368 /***************************************************************************
2369 * Is Robbo Killed *
2370 ***************************************************************************/
2371 /*
2372 * This function checks to see if Robbo is next to an object that can kill
2373 * i.e. killing = 1. It is called every cycle from update_game()
2374 */
2375
2376 /*
2377 * On exit: returns TRUE if Robbo is next to an object that can kill else
2378 * returns FALSE
2379 */
2380
2381 int
is_robbo_killed(void)2382 is_robbo_killed (void)
2383 {
2384 int retval = FALSE;
2385
2386 if (!robbo.teleporting)
2387 {
2388 if ((robbo.x < level.w - 1 && board[robbo.x + 1][robbo.y].killing == 1) || /* Robbo's right */
2389 (robbo.x > 0 && board[robbo.x - 1][robbo.y].killing == 1) || /* Robbo's left */
2390 (robbo.y < level.h - 1 && board[robbo.x][robbo.y + 1].killing == 1) || /* Robbo's bottom */
2391 (robbo.y > 0 && board[robbo.x][robbo.y - 1].killing == 1))
2392 { /* Robbo's top */
2393 retval = TRUE;
2394 }
2395 }
2396
2397 return retval;
2398 }
2399
2400 /*************************************************/
2401 /*** Robbo doesn't like this function :) *********/
2402 /*************************************************/
2403 /*
2404 * Everything except EMPTY_FIELDs and WALLs is blown-up here. Once this
2405 * has been executed the once, repeated calls to this function do nothing.
2406 */
2407
2408 void
kill_robbo(void)2409 kill_robbo (void)
2410 {
2411 int x, y;
2412 if (robbo.alive == 0)
2413 return;
2414 robbo.alive = 0;
2415 robbo.blocked = 0;
2416 play_sound (SFX_BOMB, SND_NORM);
2417 create_object (robbo.x, robbo.y, BIG_BOOM);
2418 board[robbo.x][robbo.y].moved = DELAY_BIGBOOM;
2419
2420 for (x = 0; x < level.w; x++)
2421 for (y = 0; y < level.h; y++)
2422 switch (board[x][y].type)
2423 {
2424 case EMPTY_FIELD:
2425 case WALL:
2426 break;
2427 default:
2428 board[x][y].moved = DELAY_BIGBOOM;
2429 board[x][y].blowed = 1;
2430 }
2431
2432 viewport_needs_redrawing ();
2433
2434 restart_timeout = DELAY_RESTART;
2435
2436 }
2437
2438 /***************************************************************************
2439 * Viewport Needs Redrawing *
2440 ***************************************************************************/
2441 /*
2442 * This function marks every field for redrawing/refreshing in
2443 * show_game_area()
2444 */
2445
2446 #ifdef _SMOOTH_SCRL_
2447 void
viewport_needs_redrawing(void)2448 viewport_needs_redrawing (void)
2449 {
2450 int x, y, vx = floor ((float) viewport.x / SCRL_MULT2), vy =
2451 floor ((float) viewport.y / SCRL_MULT2);
2452 for (y = vy; y < vy + viewport.h + 1; y++)
2453 {
2454 for (x = vx; x < vx + viewport.w + 1; x++)
2455 {
2456 redraw_field (x, y);
2457 }
2458 }
2459 }
2460 #else
2461 void
viewport_needs_redrawing(void)2462 viewport_needs_redrawing (void)
2463 {
2464 int x, y;
2465
2466 for (y = viewport.y; y < viewport.y + viewport.h; y++)
2467 {
2468 for (x = viewport.x; x < viewport.x + viewport.w; x++)
2469 {
2470 redraw_field (x, y);
2471 }
2472 }
2473 }
2474 #endif
2475
2476 /***************************************************************************
2477 * Redraw Field *
2478 ***************************************************************************/
2479 /*
2480 * Marks an object for redrawing/refreshing in show_game_area()
2481 */
2482
2483 void
redraw_field(int x,int y)2484 redraw_field (int x, int y)
2485 {
2486 if (x >= 0 && y >= 0 && x < level.w && y < level.h)
2487 board[x][y].redraw = TRUE;
2488 }
2489
2490 /***************************************************************************
2491 * Field clearing *
2492 ***************************************************************************/
2493 /*
2494 * This creates a blowable EMPTY_FIELD. This function clears
2495 * id_questionmark whereas create_object() doesn't
2496 */
2497
2498 void
clear_field(int x,int y)2499 clear_field (int x, int y)
2500 {
2501 create_object (x, y, EMPTY_FIELD);
2502 board[x][y].id_questionmark = 0;
2503 }
2504
2505 /***************************************************************************
2506 * Create Object *
2507 ***************************************************************************/
2508 /*
2509 * Thunor: I have found that most of the time clear_field() has been
2510 * called before this function, but there are times when it hasn't such as
2511 * via check_object_if_blowed(). The reason for this is that the
2512 * id_questionmark property needs to be retained so that questionmarks can
2513 * be recreated, and that is why some property clearing is also done below
2514 * to compensate for this.
2515 *
2516 * What I have decided to do seeing as this is such an important function,
2517 * is to clear everything as in clear_field() EXCEPT id_questionmark.
2518 */
2519
2520 void
create_object(int x,int y,int type)2521 create_object (int x, int y, int type)
2522 {
2523 int count;
2524
2525 #ifdef DEBUG_INSPECT_OBJECT_CONTENTS
2526 if (board[x][y].icon[0].x != 0)
2527 {
2528 printf ("*** Start %s ***\n", __func__);
2529 printf ("type=%i\n", board[x][y].type);
2530 printf ("state=%i\n", board[x][y].state);
2531 printf ("direction=%i\n", board[x][y].direction);
2532 printf ("destroyable=%i\n", board[x][y].destroyable);
2533 printf ("blowable=%i\n", board[x][y].blowable);
2534 printf ("killing=%i\n", board[x][y].killing);
2535 printf ("moved=%i\n", board[x][y].moved);
2536 printf ("blowed=%i\n", board[x][y].blowed);
2537 printf ("shooted=%i\n", board[x][y].shooted);
2538 printf ("rotated=%i\n", board[x][y].rotated);
2539 printf ("solidlaser=%i\n", board[x][y].solidlaser);
2540 printf ("rotable=%i\n", board[x][y].rotable);
2541 printf ("randomrotated=%i\n", board[x][y].randomrotated);
2542 printf ("teleportnumber=%i\n", board[x][y].teleportnumber);
2543 printf ("teleportnumber2=%i\n", board[x][y].teleportnumber2);
2544 printf ("id_questionmark=%i\n", board[x][y].id_questionmark);
2545 printf ("direction2=%i\n", board[x][y].direction2);
2546 printf ("movable=%i\n", board[x][y].movable);
2547 printf ("returnlaser=%i\n", board[x][y].returnlaser);
2548 printf ("shooting=%i\n", board[x][y].shooting);
2549 printf ("processed=%i\n", board[x][y].processed);
2550 printf ("icon[0].x=%i icon[0].y=%i\n", board[x][y].icon[0].x,
2551 board[x][y].icon[0].y);
2552 printf ("icon[1].x=%i icon[1].y=%i\n", board[x][y].icon[1].x,
2553 board[x][y].icon[1].y);
2554 printf ("icon[2].x=%i icon[2].y=%i\n", board[x][y].icon[2].x,
2555 board[x][y].icon[2].y);
2556 printf ("icon[3].x=%i icon[3].y=%i\n", board[x][y].icon[3].x,
2557 board[x][y].icon[3].y);
2558 printf ("icon[4].x=%i icon[4].y=%i\n", board[x][y].icon[4].x,
2559 board[x][y].icon[4].y);
2560 printf ("icon[5].x=%i icon[5].y=%i\n", board[x][y].icon[5].x,
2561 board[x][y].icon[5].y);
2562 printf ("icon[6].x=%i icon[6].y=%i\n", board[x][y].icon[6].x,
2563 board[x][y].icon[6].y);
2564 printf ("icon[7].x=%i icon[7].y=%i\n", board[x][y].icon[7].x,
2565 board[x][y].icon[7].y);
2566 printf ("icon[8].x=%i icon[8].y=%i\n", board[x][y].icon[8].x,
2567 board[x][y].icon[8].y);
2568 printf ("*** Stop %s ***\n", __func__);
2569 }
2570 #endif
2571 #ifdef LIGHTNINGENABLED
2572 #endif
2573 board[x][y].type = type;
2574 board[x][y].state = 0;
2575 board[x][y].direction = 0;
2576 board[x][y].destroyable = 0;
2577 board[x][y].blowable = 0;
2578 board[x][y].killing = 0;
2579 board[x][y].moved = 0;
2580 board[x][y].blowed = 0;
2581 board[x][y].shooted = 0;
2582 board[x][y].rotated = 0;
2583 board[x][y].solidlaser = 0;
2584 board[x][y].rotable = 0;
2585 board[x][y].randomrotated = 0;
2586 board[x][y].teleportnumber = 0;
2587 board[x][y].teleportnumber2 = 0;
2588 #ifdef LIGHTNINGENABLED
2589 board[x][y].effect = 0; /* zero means effect is off */
2590 #endif
2591 /*
2592 * NOTE id_questionmark's value is retained
2593 */
2594 board[x][y].direction2 = 0;
2595 board[x][y].movable = 0;
2596 board[x][y].returnlaser = 0;
2597 board[x][y].shooting = 0;
2598 board[x][y].processed = cycle_count;
2599 board[x][y].redraw = TRUE;
2600 for (count = 0; count < MAX_ICONS; count++)
2601 {
2602 board[x][y].icon[count].x = 0;
2603 board[x][y].icon[count].y = 0;
2604 #ifdef LIGHTNINGENABLED
2605 board[x][y].effect = 0;
2606 #endif
2607 }
2608
2609 switch (type)
2610 {
2611 case ROBBO:
2612 robbo.x = x;
2613 robbo.y = y;
2614 robbo.state = 0;
2615 board[x][y].type = EMPTY_FIELD; /* Robbo isn't a board location, so set it to EMPTY_FIELD */
2616 board[x][y].id_questionmark = 0; /* May as well clear this as it's not required to be kept */
2617 return; /* QUIT NOW */
2618 case BEAR:
2619 case BEAR_B:
2620 case BIRD:
2621 case BUTTERFLY:
2622 board[x][y].killing = 1; /* Via their closeness */
2623 case BULLET: /* The breaks have been ommitted for a reason */
2624 case BOMB:
2625 case BOMB2:
2626 case QUESTIONMARK:
2627 case GROUND:
2628 case BARRIER:
2629 board[x][y].destroyable = 1; /* Via a shot or push box */
2630 case SCREW:
2631 case PUSH_BOX:
2632 case BOX:
2633 case KEY:
2634 case DOOR:
2635 case LASER_L:
2636 case LASER_D:
2637 case TELEPORT:
2638 case GUN:
2639 case EMPTY_FIELD:
2640 board[x][y].blowable = 1; /* Via a bomb */
2641 break;
2642 case STOP:
2643 case RADIOACTIVE_FIELD: // it probably would have its own logic
2644 board[x][y].blowable = 1;
2645 board[x][y].destroyable = 0;
2646 break;
2647
2648 }
2649
2650 set_images (board[x][y].type, x, y);
2651
2652 }
2653
2654 /***************************************************************************
2655 * Clear Entire Board *
2656 ***************************************************************************/
2657 /*
2658 * Clear everything
2659 */
2660
2661 void
clear_entire_board(void)2662 clear_entire_board (void)
2663 {
2664 int xpos, ypos;
2665
2666 /*
2667 * Fill the game board with EMPTY_FIELD objects
2668 */
2669 for (ypos = 0; ypos < MAX_H; ypos++)
2670 {
2671 for (xpos = 0; xpos < MAX_W; xpos++)
2672 {
2673 clear_field (xpos, ypos);
2674 }
2675 }
2676 }
2677
2678 /*
2679 * this will return zero if x/y is in viewport and non zero otherwise
2680 */
2681
2682 #ifdef _SMOOTH_SCRL_
2683 int
in_viewport(int x,int y)2684 in_viewport (int x, int y)
2685 {
2686 if (x - viewport.x / SCRL_MULT2 <= viewport.w
2687 && x - viewport.x / SCRL_MULT2 >= 0
2688 && y - viewport.y / SCRL_MULT2 <= viewport.h
2689 && y - viewport.y / SCRL_MULT2 >= 0)
2690 {
2691 return 1;
2692 }
2693 return 0;
2694 }
2695 #else
2696 int
in_viewport(int x,int y)2697 in_viewport (int x, int y)
2698 {
2699 if (x - viewport.x <= viewport.w && x - viewport.x >= 0 &&
2700 y - viewport.y <= viewport.h && y - viewport.y >= 0)
2701 {
2702 return 1;
2703 }
2704 return 0;
2705 }
2706 #endif
2707
2708 int
check_wall(int x,int y)2709 check_wall (int x, int y)
2710 {
2711 int res = -1;
2712 if (board[x][y].type == WALL && board[x][y].state >= 9)
2713 {
2714 res = 0;
2715 if (y > 0)
2716 if (board[x][y - 1].type == WALL && board[x][y - 1].state >= 9)
2717 {
2718 res = res + 1;
2719 };
2720 if (x + 1 < level.w)
2721 if (board[x + 1][y].type == WALL && board[x + 1][y].state >= 9)
2722 {
2723 res = res + 2;
2724 };
2725 if (y + 1 < level.h)
2726 if (board[x][y + 1].type == WALL && board[x][y + 1].state >= 9)
2727 {
2728 res = res + 4;
2729 };
2730 if (x > 0)
2731 if (board[x - 1][y].type == WALL && board[x - 1][y].state >= 9)
2732 {
2733 res = res + 8;
2734 };
2735 };
2736 return res;
2737
2738 }
2739
2740 int
rearange_walls()2741 rearange_walls ()
2742 {
2743 int x, y, w;
2744 for (x = 0; x < level.w; x++)
2745 {
2746 for (y = 0; y < level.h; y++)
2747 {
2748 if ((w = check_wall (x, y)) > 0)
2749 {
2750 board[x][y].state = w + 9;
2751 board[x][y].redraw = 1;
2752 }
2753 }
2754 }
2755 return 0;
2756 }
2757