1 /***************************************************************************
2 car.cpp - description
3 -------------------
4 begin : Mon Jan 3 2000
5 copyright : (C) 2000 by Perdig
6 email : perdig@linuxbr.com.br
7
8 $Id: car.c,v 1.4 2000/11/25 14:48:53 perdig Exp $
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20 #include "car.h"
21 #include "graphics.h"
22 #include "game.h"
23 #include "ai.h"
24 #include "config.h"
25
26 #ifdef USE_SOUND
27 #include "sound.h"
28 #endif
29
30 //#define OLD_INTERSECT
31
32 carStruct blue_car;
33 extern Image red_carImg[4];
34 extern int SPRITE_SIZE;
35 smoke_struct smoke;
36 bool crashed;
37
38 extern int mapResult;
39 extern aiStruct AI;
40 extern mapStruct *map;
41 extern bool ENDMAP;
42
43 int check_player_car();
44 bool fitsY(carStruct *Car);
45 bool fitsX(carStruct *Car);
46
47
changeDir(carStruct * Car,mapStruct * Map,int direction)48 bool changeDir(carStruct *Car, mapStruct *Map, int direction) {
49 Car->toGoDir = direction;
50 Car->aiguess = -1;
51 return true;
52 }
53
turn(carStruct * Car,mapStruct * Map)54 bool turn(carStruct *Car, mapStruct *Map) {
55 if (Car->aiguess >= 0) {
56 if (isClean(Map, Car, Car->aiguess, 0)) {
57 Car->direction = Car->aiguess;
58 Car->toGoDir = Car->direction;
59 Car->aiguess = -1;
60 return true;
61 }
62 }
63 if (Car->toGoDir != Car->direction) {
64 // Wants to turn
65 // Check if it should
66 if (isClean(Map, Car, Car->toGoDir, 0)) {
67 Car->direction = Car->toGoDir;
68 }
69 }
70 return true;
71 }
72
carAI(carStruct * Car,mapStruct * Map)73 bool carAI(carStruct *Car, mapStruct *Map) {
74 int a, tx, ty;
75 if (Car->ai >= 2)
76 return false;
77 if (fits(Car) && Car->ai <= 0) {
78 for (a = 0; a < 5; a++) {
79 if (a == 4) {
80 // Well, I give up! Turn back
81 changeDir(Car, Map, (Car->direction==1) ? 3 : abs(Car->direction -2));
82 break;
83 }
84 if (abs(a - Car->direction) != 2 && isClean(Map, Car, a, 0)) {
85 changeDir(Car, Map, a);
86 break;
87 }
88 }
89 } else {
90 tx = Car->x / SPRITE_SIZE;
91 ty = Car->y / SPRITE_SIZE;
92 switch (Car->direction) {
93 case UP:
94 if (passable(tx, ty-1)) {
95 changeDir(Car, Map, LEFT);
96 Car->aiguess = UP;
97 } else if (passable(tx+1, ty-1)) {
98 changeDir(Car, Map, RIGHT);
99 Car->aiguess = UP;
100 } else if (Car->ai<=0) {
101 changeDir(Car, Map, RIGHT);
102 }
103 break;
104 case RIGHT:
105 if (passable(tx+1, ty)) {
106 changeDir(Car, Map, UP);
107 Car->aiguess = RIGHT;
108 } else if (passable(tx+1, ty+1)) {
109 changeDir(Car, Map, DOWN);
110 Car->aiguess = RIGHT;
111 } else if (Car->ai<=0) {
112 changeDir(Car, Map, DOWN);
113 }
114 break;
115 case DOWN:
116 if (passable(tx, ty+1)) {
117 changeDir(Car, Map, LEFT);
118 Car->aiguess = DOWN;
119 } else if (passable(tx+1, ty+1)) {
120 changeDir(Car, Map, RIGHT);
121 Car->aiguess = DOWN;
122 } else if (Car->ai<=0) {
123 changeDir(Car, Map, LEFT);
124 }
125 break;
126 case LEFT:
127 if (passable(tx-1, ty)) {
128 changeDir(Car, Map, UP);
129 Car->aiguess = LEFT;
130 } else if (passable(tx-1, ty+1)) {
131 changeDir(Car, Map, DOWN);
132 Car->aiguess = LEFT;
133 } else if (Car->ai<=0) {
134 changeDir(Car, Map, UP);
135 }
136 break;
137 }
138 }
139 return true;
140 }
141
142 /* OLD STUFF (turn and carAI)
143 static int a = 0;
144 int oldDir;
145 bool test;
146 int oldX, oldY;
147 static bool tryOld = true;
148 // Check if it wants to turn
149 if (Car->toGoDir != Car->direction) {
150 if (isClean(Map, Car, Car->toGoDir, 0) && (fits(Car) || !restrictedArea(Map, Car)))
151 // Turns!
152 Car->direction = Car->toGoDir;
153 // Check if it is clean to turn and if it fits in the sprite
154 if (Car->toGoDir == LEFT || Car->toGoDir == RIGHT) {
155 if (isClean(Map, Car, Car->toGoDir, 0) && (fitsY(Car) || !restrictedArea(Map, Car)))
156 // Turns!
157 Car->direction = Car->toGoDir;
158 } else {
159 if (isClean(Map, Car, Car->toGoDir, 0) && (fitsX(Car) || !restrictedArea(Map, Car)))
160 // Turns!
161 Car->direction = Car->toGoDir;
162 }
163 }
164 // Check if it is clean to go in that direction
165 if (!isClean(Map, Car, Car->direction, 0) && fits(Car)) {
166 // It can't stop moving!!
167 a = (a == 3) ? a = 0 : a + 1;
168 if ((a == (Car->direction + 2) || a == (Car->direction - 2)) && tryOld) {
169 tryOld = false;
170 a = (a == 3) ? a = 0 : a + 1;
171 }
172 changeDir(Car, Map, a);
173 return carAI(Car, Map);
174 }
175 tryOld = true;
176 */
177
moveXY(int * x,int * y,int dir,int offset)178 void moveXY(int *x, int *y, int dir, int offset) {
179 switch (dir) {
180 case UP:
181 *y-=offset;
182 break;
183 case RIGHT:
184 *x+=offset;
185 break;
186 case DOWN:
187 *y+=offset;
188 break;
189 case LEFT:
190 *x-=offset;
191 break;
192 }
193 }
194
move(carStruct * Car,mapStruct * Map)195 bool move(carStruct *Car, mapStruct *Map) {
196 int a;
197 if (check_player_car()!=0)
198 return false;
199 for (a = 0; a < Car->vel; a++) {
200 turn(Car, Map);
201 if (Car->ai >= 0 && check_player_car()!=0)
202 return false;
203 if (isClean(Map, Car, Car->direction, 0)) {
204 // MOVE
205 moveXY(&Car->x, &Car->y, Car->direction, 1);
206 } else {
207 // EXIT
208 carAI(Car, Map);
209 return false;
210 }
211 }
212 return true;
213 }
214 /* OLD move STUFF
215 // Check if it can continue moving
216 if (!isClean(Map, Car, Car->direction, 0) && fits(Car)) {
217 return false;
218 }
219 // Move
220 switch (Car->direction) {
221 case UP:
222 // Move car
223 Car->y -= Car->vel;
224 break;
225 case RIGHT:
226 // Move car
227 Car->x += Car->vel;
228 break;
229 case DOWN:
230 // Move car
231 Car->y += Car->vel;
232 break;
233 case LEFT:
234 // Move car
235 Car->x -= Car->vel;
236 break;
237 default:
238 break;
239 }
240 return true;
241 */
242
fitsX(carStruct * Car)243 bool fitsX(carStruct *Car) {
244 carStruct car;
245 car = *Car;
246 car.y = toMap(toTile(Car->y));
247 return fits(&car);
248 }
249
fitsY(carStruct * Car)250 bool fitsY(carStruct *Car) {
251 carStruct car;
252 car = *Car;
253 car.x = toMap(toTile(Car->x));
254 return fits(&car);
255 }
256
fits(carStruct * Car)257 bool fits(carStruct *Car) {
258 int a, b;
259 a = toTile(Car->x);
260 a = toMap(a);
261 b = toTile(Car->y);
262 b = toMap(b);
263 a -= Car->x;
264 b -= Car->y;
265 if (abs(a) < Car->vel && abs(b) < Car->vel) {
266 Car->x += a;
267 Car->y += b;
268 return true;
269 } else
270 return false;
271 }
272
check(carStruct * Car,aiStruct * AI,mapStruct * Map)273 bool check(carStruct *Car, aiStruct *AI, mapStruct *Map) {
274 int a;
275 // Check is its a flag
276 if (Map->data[(toTile(Car->y)*Map->width) + toTile(Car->x)] == FLAG) {
277 getFlag(toTile(Car->x), toTile(Car->y));
278 #ifdef USE_SOUND
279 play_sound (SOUND_GETFLAG);
280 #endif
281 }
282
283 #ifdef PLAYABLE
284 // Check if got by a enemy
285 for (a = 0; a < AI->number; a++) {
286 if (AI->order[a] != CONFUSED && intersect(Car, &AI->bot[a])) {
287 ldbg("AI x: %d\ty: %d", AI->bot[a].x, AI->bot[a].y);
288 ldbg("Car x: %d\ty: %d", Car->x, Car->y);
289 crashed = true;
290 #ifdef USE_SOUND
291 play_sound(SOUND_CRASH);
292 #endif
293 return true;
294 }
295 }
296
297 // Check if its in a pit pit
298 if (Map->data[(toTile(Car->y)*Map->width) + toTile(Car->x)] == PIT) {
299 crashed = true;
300 #ifdef USE_SOUND
301 play_sound(SOUND_CRASH);
302 #endif
303 return true;
304 }
305 #endif
306
307 return false;
308
309 }
310
intersect(carStruct * Car,carStruct * AI)311 bool intersect(carStruct *Car, carStruct *AI) {
312 #ifdef OLD_INTERSECT
313 return abs(AI->x - Car->x) < SPRITE_SIZE && abs(AI->y - Car->y) < SPRITE_SIZE;
314 #else
315 return (toTile(Car->x) == toTile(AI->x)) && (toTile(Car->y) == toTile(AI->y));
316 #endif
317 }
318
carCheck(aiStruct * ai,mapStruct * map)319 void carCheck(aiStruct *ai, mapStruct *map) {
320 int a, b, value;
321 // Now check the enemys
322 for (a = 0; a < ai->number; a++) {
323 value = map->data[toTile(ai->bot[a].y)*map->width+toTile(ai->bot[a].x)];
324 // If just come out of confusion
325 if (ai->order[a] == CONFUSED && ai->data[a] != 0) {
326 // Already confused. Don't mess with it
327 continue;
328 } else if (ai->order[a] == CONFUSED && ai->data[a] == 0) {
329 // Just got out of confusion -> Half second to think about life
330 ai->order[a] = WANDER;
331 ai->data[a] = -(REST_TIME);
332 ai->bot[a].img[ai->bot[a].direction] = &red_carImg[ai->bot[a].direction];
333 changeDir(&ai->bot[a], map, random() % 4);
334 carAI(&ai->bot[a], map);
335 continue;
336 } else if (ai->data[a] < 0) {
337 // data < 0 -> Ai unvulnerable
338 // Increase the data
339 ai->data[a]++;
340 continue;
341 }
342 // Now check if it was got by another enemy or by smoke
343 // Check if the car hits another
344 // This really needs to be improved
345 for (b = 0; b < ai->number; b++) {
346 if (a == b)
347 continue;
348 if (intersect(&ai->bot[a], &ai->bot[b])) {
349 // dbg("Confusing car %d (crashed)", a);
350 ai->order[a] = ai->order[b] = CONFUSED;
351 // Rest for 2 seconds
352 ai->data[a] = ai->data[b] = (CONFUSED_TIME);
353 }
354 }
355 // Now check for smoke
356 for (b = 0; b < SMOKE_NUM; b++) {
357 if (smoke.x[b] < 0 || smoke.y[b] < 0)
358 continue;
359 // Car must be really got by smoke:
360 // abs(smoke.x - car.x) <= car.vel
361 if (abs(smoke.x[b] - ai->bot[a].x) < ai->bot[a].vel && abs(smoke.y[b] - ai->bot[a].y) < ai->bot[a].vel) {
362 // dbg("Confusing car %d (smoked)", a);
363 ai->order[a] = CONFUSED;
364 // Rest for 2 seconds
365 ai->data[a] = (CONFUSED_TIME);
366 }
367 }
368 // Now check for pit pits (smart AIS won't need to check for this)
369 if (value == PIT) {
370 ai->order[a] = CONFUSED;
371 // Rest for 2 seconds
372 ai->data[a] = (CONFUSED_TIME);
373 }
374 }
375
376 // Now update the smokes
377 for (b = 0; b < SMOKE_NUM; b++) {
378 if (smoke.x[b] >= 0 && smoke.y[b] >= 0)
379 smoke.left[b]--;
380 if (smoke.left[b] < 0) {
381 smoke.x[b] = -1;
382 smoke.y[b] = -1;
383 }
384 }
385 }
386
restrictedArea(mapStruct * Map,carStruct * Car)387 bool restrictedArea(mapStruct *Map, carStruct *Car) {
388 // Returns true if the area is restricted (must fit to make a turn)
389 // Check if turning up/down or left/right (never restricted)
390 int x, y;
391 x = toTile(Car->x);
392 y = toTile(Car->y);
393 if (abs(Car->direction - Car->toGoDir) == 2)
394 return false;
395 //if (isClean(Map, Car, Car->direction, -1) && isClean(Map, Car, Car->toGoDir, -1) && isClean(Map, Car, Car->toGoDir, 0))
396 // return false;
397 return true;
398 }
399
check_player_car()400 int check_player_car() {
401 if (check(&blue_car, &AI, map) || blue_car.vel <= 0) {
402 // LOST THE GAME !!!
403 mapResult = RESULT_LOSE;
404 ENDMAP = true;
405 ldbg("Ended map... lost!");
406 return -1;
407 }
408 if (map->flagLeft <= 0 && map->flagNum != 0) {
409 // WON THE GAME
410 mapResult = RESULT_WIN;
411 ldbg("Ended map... won!");
412 ENDMAP = true;
413 return 1;
414 }
415 return 0;
416 }
417