1 ///////////////////////////////////////////////
2 //
3 // Snipe2d ludum dare 48h compo entry
4 //
5 // Jari Komppa aka Sol
6 // http://iki.fi/sol
7 //
8 ///////////////////////////////////////////////
9 // License
10 ///////////////////////////////////////////////
11 //
12 // This software is provided 'as-is', without any express or implied
13 // warranty. In no event will the authors be held liable for any damages
14 // arising from the use of this software.
15 //
16 // Permission is granted to anyone to use this software for any purpose,
17 // including commercial applications, and to alter it and redistribute it
18 // freely, subject to the following restrictions:
19 //
20 // 1. The origin of this software must not be misrepresented; you must not
21 // claim that you wrote the original software. If you use this software
22 // in a product, an acknowledgment in the product documentation would be
23 // appreciated but is not required.
24 // 2. Altered source versions must be plainly marked as such, and must not be
25 // misrepresented as being the original software.
26 // 3. This notice may not be removed or altered from any source distribution.
27 //
28 // (eg. same as ZLIB license)
29 //
30 ///////////////////////////////////////////////
31 //
32 // Houses are taken from a satellite picture of glasgow.
33 //
34 // The sources are a mess, as I didn't even try to do anything
35 // really organized here.. and hey, it's a 48h compo =)
36 //
37 #include "snipe2d.h"
38 //#define DRAW_DEBUGLINES
39
route(int x1,int y1,int x2,int y2)40 int route(int x1,int y1,int x2, int y2)
41 {
42 if ( SDL_LockSurface(Game.AIMap) < 0 )
43 return 0;
44
45 char *t = (char*)Game.AIMap->pixels;
46
47 int x, y;
48 int xinc;
49 int yinc;
50 int len,i;
51
52 len = abs(x2 - x1);
53 i = abs(y2 - y1);
54 if (i > len) len = i;
55 if (len == 0) return 0;
56
57 xinc = ((x2 - x1) << SHIFT_AMOUNT) / len;
58 yinc = ((y2 - y1) << SHIFT_AMOUNT) / len;
59
60 x = (x1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
61 y = (y1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
62
63 for (i = 1; i <= len; i++)
64 {
65 if ((t[(x >> SHIFT_AMOUNT) +
66 (y >> SHIFT_AMOUNT) *
67 (Game.AIMap->pitch)] & 0xff) == 1)
68 return 0;
69 x = x + xinc;
70 y = y + yinc;
71 }
72
73 SDL_UnlockSurface(Game.AIMap);
74 return len;
75 }
76
drawLine(SDL_Surface * aTarget,int x1,int y1,int x2,int y2,int clr)77 void drawLine(SDL_Surface * aTarget, int x1,int y1,int x2, int y2, int clr)
78 {
79 if ( SDL_LockSurface(aTarget) < 0 )
80 return;
81
82 short *t = (short*)aTarget->pixels;
83
84 int x, y;
85 int xinc;
86 int yinc;
87 int len,i;
88
89 len = abs(x2 - x1);
90 i = abs(y2 - y1);
91 if (i > len) len = i;
92 if (len == 0) return;
93
94 xinc = ((x2 - x1) << SHIFT_AMOUNT) / len;
95 yinc = ((y2 - y1) << SHIFT_AMOUNT) / len;
96
97 x = (x1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
98 y = (y1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
99
100 for (i = 1; i <= len; i++)
101 {
102 t[(x >> SHIFT_AMOUNT) +
103 (y >> SHIFT_AMOUNT) *
104 (aTarget->pitch / 2)] = clr;
105
106 x = x + xinc;
107 y = y + yinc;
108 }
109
110 SDL_UnlockSurface(aTarget);
111 }
112
113
114
precalc_ai()115 void precalc_ai()
116 {
117 if ( SDL_LockSurface(Game.AIMap) < 0 )
118 return;
119 // Count waypoints
120
121 Game.num_waypoints = 0;
122 Game.num_spawnpoints = 0;
123 int i,j;
124 for (j = 0; j < 600; j++)
125 {
126 int ofs = j * Game.AIMap->pitch;
127 for (i = 0; i < 800; i++)
128 {
129 switch (*((char*)Game.AIMap->pixels + ofs) & 0xff)
130 {
131 case 0: // street
132 break;
133 case 1: // house
134 break;
135 case 2: // bad guys spawn points
136 Game.num_spawnpoints++;
137 Game.baddy.spawn++;
138 break;
139 case 3: // VIP spawn points
140 Game.num_spawnpoints++;
141 Game.vip.spawn++;
142 break;
143 case 4: // waypoints
144 Game.num_waypoints++;
145 break;
146 case 5: // neutral spawn points
147 Game.num_spawnpoints++;
148 Game.pedestrian.spawn++;
149 break;
150 }
151 ofs++;
152 }
153 }
154 Game.spawnpoints= (SPAWNPOINT*)calloc(Game.num_spawnpoints, sizeof(SPAWNPOINT));
155 Game.waypoints = (WAYPOINT*)calloc(Game.num_waypoints, sizeof(WAYPOINT));
156 int waypoint = 0;
157 int spawnpoint = 0;
158 for (j = 0; j < 600; j++)
159 {
160 int ofs = j * Game.AIMap->pitch;
161 for (i = 0; i < 800; i++)
162 {
163 switch (*((char*)Game.AIMap->pixels + ofs) & 0xff)
164 {
165 case 0: // street
166 break;
167 case 1: // house
168 break;
169 case 2: // bad guys spawn points
170 Game.spawnpoints[spawnpoint].mX = i;
171 Game.spawnpoints[spawnpoint].mY = j;
172 Game.spawnpoints[spawnpoint].mType = CHAR_BADGUY;
173 spawnpoint++;
174 break;
175 case 3: // VIP spawn points
176 Game.spawnpoints[spawnpoint].mX = i;
177 Game.spawnpoints[spawnpoint].mY = j;
178 Game.spawnpoints[spawnpoint].mType = CHAR_VIP;
179 spawnpoint++;
180 break;
181 case 4: // waypoints
182 Game.waypoints[waypoint].mX = i;
183 Game.waypoints[waypoint].mY = j;
184 waypoint++;
185 break;
186 case 5: // neutral spawn points
187 Game.spawnpoints[spawnpoint].mX = i;
188 Game.spawnpoints[spawnpoint].mY = j;
189 Game.spawnpoints[spawnpoint].mType = 2;
190 spawnpoint++;
191 break;
192 }
193 ofs++;
194 }
195 }
196
197 // Find and store connections
198
199 for (i = 0; i < Game.num_waypoints; i++)
200 {
201 waypoint = 0;
202 for (j = 0; j < Game.num_waypoints; j++)
203 if (route(Game.waypoints[i].mX, Game.waypoints[i].mY, Game.waypoints[j].mX, Game.waypoints[j].mY))
204 waypoint++;
205
206 Game.waypoints[i].mConnections = waypoint;
207 Game.waypoints[i].mConnection = (int*)calloc(waypoint, sizeof(int));
208
209 waypoint = 0;
210 for (j = 0; j < Game.num_waypoints; j++)
211 if (route(Game.waypoints[i].mX, Game.waypoints[i].mY, Game.waypoints[j].mX, Game.waypoints[j].mY))
212 {
213 #ifdef DRAW_DEBUGLINES
214 drawLine(Game.Map, Game.waypoints[i].mX, Game.waypoints[i].mY, Game.waypoints[j].mX, Game.waypoints[j].mY, 0xffff);
215 #endif
216 Game.waypoints[i].mConnection[waypoint] = j;
217 waypoint++;
218 }
219 }
220
221 for (i = 0; i < Game.num_spawnpoints; i++)
222 {
223 int spawndist = 10000;
224 for (j = 0; j < Game.num_waypoints; j++)
225 {
226 int newdist = route(Game.spawnpoints[i].mX, Game.spawnpoints[i].mY, Game.waypoints[j].mX, Game.waypoints[j].mY);
227 if (newdist && newdist < spawndist)
228 {
229 spawndist = newdist;
230 Game.spawnpoints[i].mClosestWaypoint = j;
231 }
232 }
233 }
234 #ifdef DRAW_DEBUGLINES
235 for (i = 0; i < Game.num_spawnpoints; i++)
236 drawLine(Game.Map, Game.spawnpoints[i].mX, Game.spawnpoints[i].mY, Game.waypoints[Game.spawnpoints[i].mClosestWaypoint].mX, Game.waypoints[Game.spawnpoints[i].mClosestWaypoint].mY, 0xf << (Game.spawnpoints[i].mType * 6));
237 #endif
238
239 SDL_UnlockSurface(Game.AIMap);
240 }
241
distance(float aX1,float aY1,float aX2,float aY2)242 float distance(float aX1, float aY1, float aX2, float aY2)
243 {
244 return (float)sqrt((aX2 - aX1) * (aX2 - aX1) + (aY2 - aY1) * (aY2 - aY1));
245 }
246
distance_wp(int aWaypoint,float aX,float aY)247 float distance_wp(int aWaypoint, float aX, float aY)
248 {
249 return distance((float)Game.waypoints[aWaypoint].mX, (float)Game.waypoints[aWaypoint].mY, aX, aY);
250 }
251
distance_wpwp(int aWaypoint1,int aWaypoint2)252 float distance_wpwp(int aWaypoint1, int aWaypoint2)
253 {
254 return distance((float)Game.waypoints[aWaypoint1].mX, (float)Game.waypoints[aWaypoint1].mY, (float)Game.waypoints[aWaypoint2].mX, (float)Game.waypoints[aWaypoint2].mY);
255 }
256
validateWaypoint(CHARACTER & c,int & next)257 void validateWaypoint(CHARACTER &c, int &next)
258 {
259 int valid = 0;
260 int candidate = next;
261 while (!valid)
262 {
263 valid = 1;
264 int i;
265 for (i = 0; i < 7; i++)
266 if (c.mLastWaypoints[i] == Game.waypoints[c.mNextWaypoint].mConnection[candidate])
267 valid = 0;
268 if (!valid)
269 {
270 candidate++;
271 if (candidate >= Game.waypoints[c.mNextWaypoint].mConnections)
272 candidate = 0;
273 if (candidate == next) // no valid waypoints
274 return;
275 }
276 }
277 next = candidate;
278 }
279
handle_ai(CHARACTER & c)280 void handle_ai(CHARACTER &c)
281 {
282 // is this AI inactive?
283 if (c.mType == -1)
284 return;
285
286 // Kludge: hit position sign
287 if (c.mType == 3 || c.mType == 4)
288 {
289
290 c.mTTL--;
291 if (c.mTTL < 0)
292 c.mType = -1;
293 return;
294 }
295
296 // Pedestrian AI
297 // Pedestrians just walk around, and try not to walk
298 // in circles.
299 if (c.mType == 2)
300 {
301 float dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
302 // Have we arrived at waypoint?
303 if (dist < 4)
304 {
305
306 #ifdef RECYCLE_PEDESTRIANS
307 // Reduce time to live..
308 c.mTTL--;
309 if (c.mTTL <= 0)
310 {
311 // Wipe and recycle..
312 spa(2);
313 c.mType = -1;
314 return;
315 }
316 #endif
317 // Store current waypoint in old waypoints list..
318 c.mLastWaypoints[c.mLastWaypoint] = c.mNextWaypoint;
319 c.mLastWaypoint++;
320 if (c.mLastWaypoint >= 7)
321 c.mLastWaypoint = 0;
322 // Find a new waypoint
323
324 int next = rand() % Game.waypoints[c.mNextWaypoint].mConnections;
325 validateWaypoint(c, next);
326 c.mNextWaypoint = Game.waypoints[c.mNextWaypoint].mConnection[next];
327 // Calculate vector..
328 dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
329 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
330 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
331
332 }
333 }
334
335 // VIP AI
336 // VIPs try to find their way to their exit point.
337 if (c.mType == CHAR_VIP)
338 {
339 if (c.mNextWaypoint == -1)
340 {
341 // Have we arrived home?
342 float dist = distance((float)Game.spawnpoints[c.mTarget].mX, (float)Game.spawnpoints[c.mTarget].mY, c.mX, c.mY);
343 if (dist < 4)
344 {
345 // arrived safely.
346 c.mType = -1;
347 Game.Score += (int)((float)5000*Game.ScoreMod);
348 Game.vip.count--;
349 Game.vip.goal++;
350 }
351 }
352 else
353 {
354 float dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
355 // Have we arrived at waypoint?
356 if (dist < 4)
357 {
358 // Store current waypoint in old waypoints list..
359 c.mLastWaypoints[c.mLastWaypoint] = c.mNextWaypoint;
360 c.mLastWaypoint++;
361 if (c.mLastWaypoint >= 7)
362 c.mLastWaypoint = 0;
363 // Find a new waypoint
364
365 // Can we get to the final destination from here?
366 if (route((int)c.mX, (int)c.mY, Game.spawnpoints[c.mTarget].mX, Game.spawnpoints[c.mTarget].mY))
367 {
368 // Yep, calculate vector to home
369 c.mNextWaypoint = -1;
370 dist = distance((float)Game.spawnpoints[c.mTarget].mX, (float)Game.spawnpoints[c.mTarget].mY, c.mX, c.mY);
371 c.mXi = ((Game.spawnpoints[c.mTarget].mX - c.mX) / dist) * c.mSpeed;
372 c.mYi = ((Game.spawnpoints[c.mTarget].mY - c.mY) / dist) * c.mSpeed;
373 }
374 else
375 {
376 // Nope, try to figure out the closest waypoint to target that's connected from here
377 int next = 0;
378 dist = distance_wp(Game.waypoints[c.mNextWaypoint].mConnection[0], (float)Game.spawnpoints[c.mTarget].mX, (float)Game.spawnpoints[c.mTarget].mY);
379 int i;
380 for (i = 1; i < Game.waypoints[c.mNextWaypoint].mConnections; i++)
381 {
382 float newdist = distance_wp(Game.waypoints[c.mNextWaypoint].mConnection[i], (float)Game.spawnpoints[c.mTarget].mX, (float)Game.spawnpoints[c.mTarget].mY);
383 if (newdist < dist)
384 {
385 dist = newdist;
386 next = i;
387 }
388 }
389 // Make sure we're not walking in circles:
390 validateWaypoint(c, next);
391 c.mNextWaypoint = Game.waypoints[c.mNextWaypoint].mConnection[next];
392 // Calculate vector..
393 dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
394 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
395 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
396 }
397
398 }
399 }
400 }
401
402 // Bad guy AI
403 // Bad guys try to find their way to a VIP.
404 if (c.mType == CHAR_BADGUY)
405 {
406 if (c.mTarget != -1 && Game.characters[c.mTarget].mType != 1)
407 {
408 // Lost target
409 c.mTarget = -1;
410 }
411
412 if (c.mTarget == -1) // Bad guy without a target
413 {
414 if (Game.vip.count == 0)
415 {
416 // No VIPs to pester, walk around randomly
417
418 if (c.mNextWaypoint == -1)
419 {
420 // We were walking towards a VIP last time, so
421 // we'll need to find the closest waypoint and walk to that.
422 c.mNextWaypoint = 0;
423 int i;
424 float dist = distance_wp(0, c.mX, c.mY);
425 for (i = 1; i < Game.num_waypoints; i++)
426 {
427 float newdist = distance_wp(i, c.mX, c.mY);
428 if (newdist < dist && route(Game.waypoints[i].mX, Game.waypoints[i].mY, (int)c.mX, (int)c.mY))
429 {
430 dist = newdist;
431 c.mNextWaypoint = i;
432 }
433 }
434 // Calculate vector towards the closest waypoint
435 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
436 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
437 }
438 else // just walk towards the next waypoint normally
439 {
440 float dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
441 // Have we arrived at waypoint?
442 if (dist < 4)
443 {
444 int next = rand() % Game.waypoints[c.mNextWaypoint].mConnections;
445 // Bad guys have nowhere to go, so they might
446 // as well walk in circles.. (hence, no validatewaypoint)
447 c.mNextWaypoint = Game.waypoints[c.mNextWaypoint].mConnection[next];
448 // Calculate vector..
449 dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
450 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
451 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
452 }
453 }
454 }
455 else // target a VIP
456 {
457 int t = rand() % Game.vip.count;
458 int i = 0;
459 while (t > 0 || Game.characters[i].mType != CHAR_VIP)
460 {
461 if (Game.characters[i].mType == CHAR_VIP)
462 t--;
463 i++;
464 }
465 c.mTarget = i;
466 // Avoid sudden death:
467 if (distance(c.mX, c.mY, Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY) < 20)
468 {
469 c.mTarget = -1;
470 if (c.mNextWaypoint == -1)
471 {
472 c.mXi = 0;
473 c.mYi = 0;
474 }
475 }
476 }
477 }
478
479 int nolineofsight = 1;
480
481 // Do we have line of sight to the VIP?
482 if (c.mTarget != -1 && route((int)c.mX, (int)c.mY, (int)Game.characters[c.mTarget].mX, (int)Game.characters[c.mTarget].mY))
483 {
484 nolineofsight = 0;
485 // Calculate new vector to it
486 float dist = distance(Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY, c.mX, c.mY);
487 c.mXi = ((Game.characters[c.mTarget].mX - c.mX) / dist) * c.mSpeed;
488 c.mYi = ((Game.characters[c.mTarget].mY - c.mY) / dist) * c.mSpeed;
489 c.mNextWaypoint = -1;
490 }
491
492
493 if (c.mNextWaypoint == -1)
494 {
495 // Caught up with the VIP?
496 float dist = distance((float)Game.characters[c.mTarget].mX, (float)Game.characters[c.mTarget].mY, c.mX, c.mY);
497 if (dist < 3)
498 {
499 // arrived safely.
500 c.mType = -1;
501 Game.Score -= (int)((float)10000*Game.ScoreMod); // +game over
502 Game.vip.count--;
503 Game.baddy.count--;
504 Game.characters[c.mTarget].mType = -1;
505 #ifdef DISPLAY_GAMEOVER_SCREEN
506 // gameoverscreen(2);
507 Game.GameOverReason = OESREASON_NEGLIGENT;
508 // draw_gameoverscreen(Game.Screen);
509 return;
510 #endif
511 }
512 else
513 {
514 if (nolineofsight)
515 {
516 // Lost the VIP. Find closest accessible waypoint.
517 c.mNextWaypoint = 0;
518 int i;
519 float dist = distance_wp(0, Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY);
520 for (i = 1; i < Game.num_waypoints; i++)
521 {
522 float newdist = distance_wp(i, Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY);
523 if (newdist < dist && route(Game.waypoints[i].mX, Game.waypoints[i].mY, (int)c.mX, (int)c.mY))
524 {
525 dist = newdist;
526 c.mNextWaypoint = i;
527 }
528 }
529 // Calculate vector towards the closest waypoint
530 dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
531 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
532 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
533 }
534 }
535 }
536 else
537 {
538 float dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
539 // Have we arrived at waypoint?
540 if (dist < 4)
541 {
542 // Find a new waypoint
543
544 if (c.mTarget == -1)
545 {
546 int oldWaypoint = c.mNextWaypoint;
547
548 // just choose the next-closest waypoint in the area (I know: we'll cycle).
549 c.mNextWaypoint = 0;
550 int i;
551 float dist = distance_wp(0, c.mX, c.mY);
552 for (i = 1; i < Game.num_waypoints; i++)
553 {
554 if (i != oldWaypoint) {
555 float newdist = distance_wp(i, c.mX, c.mY);
556 if (newdist < dist && route(Game.waypoints[i].mX, Game.waypoints[i].mY, (int)c.mX, (int)c.mY))
557 {
558 dist = newdist;
559 c.mNextWaypoint = i;
560 }
561 }
562 }
563 // Calculate vector towards the closest waypoint
564 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
565 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
566 }
567 else if (nolineofsight)
568 {
569 // Can't see the VIP, try to figure out the closest waypoint to target that's connected from here
570 int next = 0;
571 dist = distance_wp(Game.waypoints[c.mNextWaypoint].mConnection[0], Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY);
572 int i;
573 for (i = 1; i < Game.waypoints[c.mNextWaypoint].mConnections; i++)
574 {
575 float newdist = distance_wp(Game.waypoints[c.mNextWaypoint].mConnection[i], Game.characters[c.mTarget].mX, Game.characters[c.mTarget].mY);
576 if (newdist < dist)
577 {
578 dist = newdist;
579 next = i;
580 }
581 }
582 // Note: bad guys MAY run in circles.
583 c.mNextWaypoint = Game.waypoints[c.mNextWaypoint].mConnection[next];
584 // Calculate vector..
585 dist = distance_wp(c.mNextWaypoint, c.mX, c.mY);
586 c.mXi = ((Game.waypoints[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
587 c.mYi = ((Game.waypoints[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
588 }
589
590 }
591 }
592 }
593
594
595 // Make 'em walk
596 c.mX += c.mXi;
597 c.mY += c.mYi;
598 }
599
findspawnpoint(int aIndex,int aType)600 int findspawnpoint(int aIndex, int aType)
601 {
602 int i, j;
603 j = 0;
604 i = 0;
605 while (i < Game.num_spawnpoints)
606 {
607 if (Game.spawnpoints[i].mType == aType)
608 j++;
609 if (j > aIndex)
610 return i;
611 i++;
612 }
613 return i;
614 }
615
spawn_ai(int aType)616 int spawn_ai(int aType)
617 {
618
619 // find empty slot
620 int slot = 0;
621 while (slot < Game.num_characters && Game.characters[slot].mType != -1) slot++;
622 Game.characters[slot].mType = -1; // Overwrite the last slot if all slots were in use
623 Game.characters[slot].mLastWaypoint = 0;
624 int i;
625 for (i = 0; i < 7; i++)
626 Game.characters[slot].mLastWaypoints[i] = -1;
627
628 if (aType == CHAR_BADGUY)
629 {
630 Game.baddy.count++;
631 // spawn a bad guy
632 int spawnpoint = 0;
633 int i = rand() % Game.baddy.spawn;
634 spawnpoint = findspawnpoint(i, CHAR_BADGUY);
635
636 Game.characters[slot].mType = CHAR_BADGUY;
637 Game.characters[slot].mX = (float)Game.spawnpoints[spawnpoint].mX;
638 Game.characters[slot].mY = (float)Game.spawnpoints[spawnpoint].mY;
639 Game.characters[slot].mTarget = -1; // find target at next handle_ai pass
640 Game.characters[slot].mNextWaypoint = Game.spawnpoints[spawnpoint].mClosestWaypoint;
641 }
642
643 if (aType == CHAR_VIP)
644 {
645 if (Game.vip.count >= 3)
646 return 0; // 3 vips at a time, thanks
647 Game.vip.count++;
648 // spawn a VIP
649 int spawnpoint = 0;
650 int i = rand() % Game.vip.spawn;
651 spawnpoint = findspawnpoint(i, CHAR_VIP);
652
653 Game.characters[slot].mType = CHAR_VIP;
654 Game.characters[slot].mX = (float)Game.spawnpoints[spawnpoint].mX;
655 Game.characters[slot].mY = (float)Game.spawnpoints[spawnpoint].mY;
656 Game.characters[slot].mNextWaypoint = Game.spawnpoints[spawnpoint].mClosestWaypoint;
657
658 int targetspawnpoint = 0;
659 float dist = 0;
660 // find target waypont, avoiding free score
661 while (dist < 20)
662 {
663 i = rand() % Game.vip.spawn;
664 targetspawnpoint = findspawnpoint(i, 1);
665 dist = distance(Game.characters[slot].mX, Game.characters[slot].mY, (float)Game.spawnpoints[targetspawnpoint].mX, (float)Game.spawnpoints[targetspawnpoint].mY);
666 }
667 Game.characters[slot].mTarget = targetspawnpoint;
668 }
669
670 if (aType == CHAR_PEDESTRIAN)
671 {
672 // spawn a pedestrian
673 int spawnpoint = 0;
674 int i = rand() % Game.pedestrian.spawn;
675 spawnpoint = findspawnpoint(i, CHAR_PEDESTRIAN);
676 Game.characters[slot].mType = CHAR_PEDESTRIAN;
677 Game.characters[slot].mX = (float)Game.spawnpoints[spawnpoint].mX;
678 Game.characters[slot].mY = (float)Game.spawnpoints[spawnpoint].mY;
679 Game.characters[slot].mTTL = rand() % 10 + 5;
680 Game.characters[slot].mNextWaypoint = Game.spawnpoints[spawnpoint].mClosestWaypoint;
681 }
682 float dist = distance_wp(Game.characters[slot].mNextWaypoint, Game.characters[slot].mX, Game.characters[slot].mY);
683 Game.characters[slot].mSpeed = (((((rand()%32768)/32768.0)) + 0.5f) * 0.5f) /
684 5.0f;
685 // slow down pedestrians, they're not in a hurry..
686 if (aType == CHAR_PEDESTRIAN) Game.characters[slot].mSpeed *= 0.5f;
687 Game.characters[slot].mXi = ((Game.waypoints[Game.characters[slot].mNextWaypoint].mX - Game.characters[slot].mX) / dist) * Game.characters[slot].mSpeed;
688 Game.characters[slot].mYi = ((Game.waypoints[Game.characters[slot].mNextWaypoint].mY - Game.characters[slot].mY) / dist) * Game.characters[slot].mSpeed;
689 return slot;
690 }
691
692
693
shoot()694 void shoot()
695 {
696 Game.WobbleIndex += 2048;
697 Game.Reloading = Game.ReloadTime;
698 #ifdef CAMERA_RECOIL
699 if (Game.MouseZ < 0.25f) Game.MouseZ = 0.25f;
700 #ifndef CAMERA_STEPS
701 Game.CoordScale = Game.MouseZ;
702 #else
703 Game.CoordScale = ((int)(Game.MouseZ * 4)) / 4.0f;
704 if (Game.CoordScale < 0.05f) Game.CoordScale = 0.05f;
705 #endif
706 #endif
707 int slot = 0;
708 while (Game.characters[slot].mType != -1) slot++;
709 Game.characters[slot].mLastWaypoint = 0;
710
711 float worldx = Game.MouseX + Game.WobbleX + Game.CenterX + 320 * Game.CoordScale;
712 float worldy = Game.MouseY + Game.WobbleY + Game.CenterY + 240 * Game.CoordScale;
713
714 int hit = 0;
715 int gameover = 0;
716 int i;
717 for (i = 0; i < Game.num_characters; i++)
718 {
719 if (Game.characters[i].mType != -1)
720 {
721 if (Game.characters[i].mX > worldx - 1 &&
722 Game.characters[i].mX < worldx + 1 &&
723 Game.characters[i].mY > worldy - 1 &&
724 Game.characters[i].mY < worldy + 1)
725 {
726 if (Game.characters[i].mType == CHAR_BADGUY)
727 {
728 Game.Score += (int)((float)1000*Game.ScoreMod);
729 Game.baddy.count--;
730 Game.baddy.dead++;
731 }
732 if (Game.characters[i].mType == CHAR_VIP)
733 {
734 Game.Score -= (int)((float)100000*Game.ScoreMod); // +game over
735 gameover = 1;
736 Game.vip.count--;
737 }
738 if (Game.characters[i].mType == CHAR_PEDESTRIAN)
739 {
740 Game.pedestrian.dead++;
741 Game.Score -= (int)((float)100*Game.ScoreMod);
742 #ifdef RECYCLE_PEDESTRIANS
743 spawn_ai(2); // spawn a new pedestrian
744 #endif
745 }
746 Game.characters[i].mType = -1;
747 hit = 1;
748 }
749 }
750 }
751 #ifdef DISPLAY_GAMEOVER_SCREEN
752 if (gameover)
753 {
754 // gameoverscreen(1);
755 Game.GameOverReason = OESREASON_FRAG;
756 // draw_gameoverscreen(Game.Screen);
757 }
758 #endif
759
760 Game.characters[slot].mType = hit?3:4; // hit marker
761 Game.characters[slot].mX = worldx;
762 Game.characters[slot].mY = worldy;
763 Game.characters[slot].mTTL = 100;
764 }
765