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