1 /*
2  * game.c -- xrobots
3  *
4  * Copyright 1989 Brian Warkentine
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the author's name not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  The author makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
18  * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
19  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * The author's current employer has no connection with this software, as it
24  * was written before being employed at Sun.  The following address is for
25  * contacting the author only and does not imply any responsibility on the
26  * behalf of Sun Microsystems.
27  *
28  * Contact the author at:
29  * 	Brian Warkentine  (brianw@Sun.COM)
30  * 	Sun Microsystems
31  * 	2550 Garcia Avenue
32  * 	Mountain View, Ca 94043-1100
33  *
34  * HP-UX :- following two defines
35  */
36 
37 #include <X11/Intrinsic.h>
38 #include <stdlib.h>
39 #include "xrobots.h"
40 
41 /* some of these are global */
42 int human_x, human_y, last_human_x, last_human_y;
43 
44 int robot_array[MAXX][MAXY],
45     robot_array_bak[MAXX][MAXY];
46 	/* These arrays are filled with the robots and the heaps
47 	 * They do not include the player(human).
48 	 */
49 int	score,
50 	num_robots,
51 	level,
52 	game_active,
53 	sonic_used;
54 
55 static void autochase();
56 
57 /*----------------------------------------------------------------------*/
58 void
new_game()59 new_game()
60 {
61   score = 0;
62   level = 0;
63   sonic_used = 1;
64   game_active = 1;
65   new_level();
66   update_score(score);
67 }
68 
69 /*----------------------------------------------------------------------*/
70 void
add_score(n)71 add_score(n)
72   int n;
73 {
74   score += 10 * n; /* ten points for each wasted robot. */
75   num_robots -= n;
76   if(n) update_score(score);
77 }
78 
79 /*----------------------------------------------------------------------*/
80 void
new_level()81 new_level()
82 {
83   int x,y,tmp;
84 
85   reset_sonic_button();
86   if(!sonic_used) {
87     score += 50; 	/* bonus for not using sonic screwdriver on last level*/
88     update_score(score);
89   }
90   sonic_used = 0;
91   level++;
92   num_robots = tmp = level*5;
93 
94   for_each                            /* clean out both the robot arrays */
95   {
96     robot_array[x][y] = EMPTY;
97     robot_array_bak[x][y] = EMPTY;
98   }
99 
100   human_x = (int)random()%MAXX;                  /* assign human to new space */
101   human_y = (int)random()%MAXY;
102   robot_array[human_x][human_y] = ROBOT;
103 
104   while(tmp--)
105   {
106     x = (int)random()%MAXX;
107     y = (int)random()%MAXY;
108     if(robot_array[x][y] == ROBOT) tmp++;        /* space already occupied */
109     robot_array[x][y] = ROBOT;
110   }
111   robot_array[human_x][human_y] = EMPTY;
112   display_level();
113   display_possible_moves();
114 }
115 
116 /*----------------------------------------------------------------------*/
117 int
chase()118 chase()
119 {
120   /* chase() returns the number of robots that were wasted in each call. */
121   /* after each call, be sure to check if all the robots are dead */
122   int x,y;
123   int newx,newy;
124   int num_wasted = 0;
125 
126   for_each
127   {
128     robot_array_bak[x][y] = robot_array[x][y];
129     if(robot_array[x][y] != HEAP)
130       robot_array[x][y] = 0;
131   }
132 
133   for_each
134   {
135     if(robot_array_bak[x][y] != ROBOT)
136       continue;
137 
138     if(x>human_x)                           /* move toward the human */
139       newx = x-1;
140     else
141       if(x<human_x)
142         newx = x+1;
143       else
144         newx = x;
145 
146     if(y>human_y)
147       newy = y-1;
148     else
149       if(y<human_y)
150         newy = y+1;
151       else
152         newy = y;
153 
154 #   ifdef DEBUG
155     printf("moving (%d,%d) to (%d,%d)\n",x,y,newx,newy);
156 #   endif
157 
158     /* check to see if a robot or heap was already in that spot */
159     if(robot_array[newx][newy] == ROBOT)
160     {
161       robot_array[newx][newy] = HEAP;
162       num_wasted += 2;
163       continue;
164     }
165     if(robot_array[newx][newy] == HEAP)
166     {
167       num_wasted++;
168       continue;
169     }
170     /* move robot to new location */
171     robot_array[newx][newy] = ROBOT;
172   }
173 
174   return(num_wasted);
175 }
176 
177 /*----------------------------------------------------------------------*/
178 void
undo_chase()179 undo_chase()
180 {
181   int x,y;
182   for_each
183     robot_array[x][y] = robot_array_bak[x][y];
184 }
185 
186 /*----------------------------------------------------------------------*/
187 void
teleport()188 teleport()
189 {
190   int num_wasted;
191 
192   if(!game_active) return;
193   do
194   {
195     human_x = (int)random()%MAXX;        /* pick a spot not already occupied */
196     human_y = (int)random()%MAXY;
197   }
198   while(robot_array[human_x][human_y] != EMPTY);
199 
200   show_teleport();
201 
202   num_wasted = chase(0);
203 
204   if(robot_array[human_x][human_y] != EMPTY)
205   {
206     /* death... */
207     undo_chase();
208     /* it is a matter of preference to clear the screen when you die... */
209     display_level();
210     do_death();
211     check_score(score);
212     game_active = 0;
213     return;
214   }
215 
216   display_level();
217 
218   score += num_robots;       /* bonus for teleporting */
219   score += num_wasted * 10;  /* score for any that collided */
220   num_robots -= num_wasted;
221   update_score(score);
222 
223   if(!num_robots)
224     new_level();
225   else
226     display_possible_moves();
227   auto_teleport();
228   XFlush(display);
229 }
230 
231 /*----------------------------------------------------------------------*/
232 void
sonic_screwdriver()233 sonic_screwdriver()
234 {
235   /*
236    * a trick - remove the neighboring robots by calling chase() and
237    * letting them crash into each other in the human's spot, then clear out
238    * the human's position of the remains.
239    */
240   int num_wasted;
241 
242   if(!game_active) return;
243   if(sonic_used) return;
244   sonic_used = 1;
245   show_sonic();
246   num_wasted = chase(1);
247   if(robot_array[human_x][human_y] == ROBOT)
248     add_score(1);
249   robot_array[human_x][human_y] = EMPTY;
250 
251   last_human_x = human_x;
252   last_human_y = human_y;
253   show_movement();
254 
255   add_score(num_wasted);
256   if(!num_robots)
257     new_level();
258   else
259     display_possible_moves();
260   auto_teleport();
261   XFlush(display);
262 }
263 
264 /*----------------------------------------------------------------------*/
265 void
wait_for_em()266 wait_for_em()
267 {
268   /*
269    * the trick - call chase() until any robot is in the same spot as the
270    * human, then backout as if the last chase() didn't happen.
271    */
272   int num_wasted;
273 
274   if(!game_active) return;
275 
276   while(1) {
277     num_wasted = chase(1);
278     if(robot_array[human_x][human_y] != EMPTY) {
279       /* backout of latest chase() and break loop */
280       undo_chase();
281 
282       if(app_data.diewaiting) {  	/* for those risk takers out there */
283         display_level();
284         do_death();
285         check_score(score);
286         game_active = 0;
287         return;
288       }
289 
290       break;
291     }
292     add_score(num_wasted);
293     if(!num_robots)
294 	break;
295     if(app_data.showjumps)
296       show_movement();
297     XFlush(display);
298   }
299   if(!num_robots)
300     new_level();
301   else
302     if(!app_data.showjumps)
303       display_level();
304   display_possible_moves();
305   auto_teleport();
306   XFlush(display);
307 }
308 
309 /*----------------------------------------------------------------------*/
310 
311 
312 int
can_go(x,y)313 can_go(x,y)
314   int x,y;
315 {
316 /* check if (x,y) is a legit move. */
317   if( INYRANGE(y-1) ) {
318     if( INXRANGE(x-1) )
319       if(robot_array[x-1][y-1] == ROBOT)  return 0;
320     if( INXRANGE(x) )
321       if(robot_array[x][y-1] == ROBOT)  return 0;
322     if( INXRANGE(x+1) )
323       if(robot_array[x+1][y-1] == ROBOT)  return 0;
324   }
325 
326   if( INYRANGE(y) ) {
327     if( INXRANGE(x-1) )
328       if(robot_array[x-1][y] == ROBOT)  return 0;
329     if( INXRANGE(x) ) {
330       if(robot_array[x][y] == ROBOT)  return 0;
331       if(robot_array[x][y] == HEAP)   return 0;
332       }
333     if( INXRANGE(x+1) )
334       if(robot_array[x+1][y] == ROBOT)  return 0;
335   }
336 
337   if( INYRANGE(y+1) ) {
338     if( INXRANGE(x-1) )
339       if(robot_array[x-1][y+1] == ROBOT)  return 0;
340     if( INXRANGE(x) )
341       if(robot_array[x][y+1] == ROBOT)  return 0;
342     if( INXRANGE(x+1) )
343       if(robot_array[x+1][y+1] == ROBOT)  return 0;
344   }
345 
346   if( !INXRANGE(x) )  return 0;
347   if( !INYRANGE(y) )  return 0;
348 
349   return 1;
350 }
351 
352