Replace all casts of NULL to something with NULL.
[dragonfly.git] / games / hunt / huntd / execute.c
1 /*
2  * Copyright (c) 1983-2003, Regents of the University of California.
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without 
6  * modification, are permitted provided that the following conditions are 
7  * met:
8  * 
9  * + Redistributions of source code must retain the above copyright 
10  *   notice, this list of conditions and the following disclaimer.
11  * + Redistributions in binary form must reproduce the above copyright 
12  *   notice, this list of conditions and the following disclaimer in the 
13  *   documentation and/or other materials provided with the distribution.
14  * + Neither the name of the University of California, San Francisco nor 
15  *   the names of its contributors may be used to endorse or promote 
16  *   products derived from this software without specific prior written 
17  *   permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $OpenBSD: execute.c,v 1.8 2004/01/16 00:13:19 espie Exp $
32  * $NetBSD: execute.c,v 1.2 1997/10/10 16:33:13 lukem Exp $
33  * $DragonFly: src/games/hunt/huntd/execute.c,v 1.2 2008/09/04 16:12:51 swildner Exp $
34  */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <syslog.h>
39 #include "hunt.h"
40 #include "conf.h"
41 #include "server.h"
42
43 static void     cloak(PLAYER *);
44 static void     face(PLAYER *, int);
45 static void     fire(PLAYER *, int);
46 static void     fire_slime(PLAYER *, int);
47 static void     move_player(PLAYER *, int);
48 static void     pickup(PLAYER *, int, int, int, int);
49 static void     scan(PLAYER *);
50
51
52 /*
53  * mon_execute:
54  *      Execute a single monitor command
55  */
56 void
57 mon_execute(PLAYER *pp)
58 {
59         char    ch;
60
61         ch = pp->p_cbuf[pp->p_ncount++];
62
63         switch (ch) {
64           case CTRL('L'):
65                 /* Redraw messed-up screen */
66                 sendcom(pp, REDRAW);
67                 break;
68           case 'q':
69                 /* Quit client */
70                 (void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
71                 break;
72           default:
73                 /* Ignore everything else */
74                 ;
75         }
76 }
77
78 /*
79  * execute:
80  *      Execute a single command from a player
81  */
82 void
83 execute(PLAYER *pp)
84 {
85         char    ch;
86
87         ch = pp->p_cbuf[pp->p_ncount++];
88
89         /* When flying, only allow refresh and quit. */
90         if (pp->p_flying >= 0) {
91                 switch (ch) {
92                   case CTRL('L'):
93                         sendcom(pp, REDRAW);
94                         break;
95                   case 'q':
96                         (void) strlcpy(pp->p_death, "| Quit |", 
97                             sizeof pp->p_death);
98                         break;
99                 }
100                 return;
101         }
102
103         /* Decode the command character: */
104         switch (ch) {
105           case CTRL('L'):
106                 sendcom(pp, REDRAW);    /* Refresh */
107                 break;
108           case 'h':
109                 move_player(pp, LEFTS); /* Move left */
110                 break;
111           case 'H':
112                 face(pp, LEFTS);        /* Face left */
113                 break;
114           case 'j':
115                 move_player(pp, BELOW); /* Move down */
116                 break;
117           case 'J':
118                 face(pp, BELOW);        /* Face down */
119                 break;
120           case 'k':
121                 move_player(pp, ABOVE); /* Move up */
122                 break;
123           case 'K':
124                 face(pp, ABOVE);        /* Face up */
125                 break;
126           case 'l':
127                 move_player(pp, RIGHT); /* Move right */
128                 break;
129           case 'L':
130                 face(pp, RIGHT);        /* Face right */
131                 break;
132           case 'f':
133           case '1':
134                 fire(pp, 0);            /* SHOT */
135                 break;
136           case 'g':
137           case '2':
138                 fire(pp, 1);            /* GRENADE */
139                 break;
140           case 'F':
141           case '3':
142                 fire(pp, 2);            /* SATCHEL */
143                 break;
144           case 'G':
145           case '4':
146                 fire(pp, 3);            /* 7x7 BOMB */
147                 break;
148           case '5':
149                 fire(pp, 4);            /* 9x9 BOMB */
150                 break;
151           case '6':
152                 fire(pp, 5);            /* 11x11 BOMB */
153                 break;
154           case '7':
155                 fire(pp, 6);            /* 13x13 BOMB */
156                 break;
157           case '8':
158                 fire(pp, 7);            /* 15x15 BOMB */
159                 break;
160           case '9':
161                 fire(pp, 8);            /* 17x17 BOMB */
162                 break;
163           case '0':
164                 fire(pp, 9);            /* 19x19 BOMB */
165                 break;
166           case '@':
167                 fire(pp, 10);           /* 21x21 BOMB */
168                 break;
169           case 'o':
170                 fire_slime(pp, 0);      /* SLIME */
171                 break;
172           case 'O':
173                 fire_slime(pp, 1);      /* SSLIME */
174                 break;
175           case 'p':
176                 fire_slime(pp, 2);      /* large slime */
177                 break;
178           case 'P':
179                 fire_slime(pp, 3);      /* very large slime */
180                 break;
181           case 's':                     /* start scanning */
182                 scan(pp);
183                 break;
184           case 'c':                     /* start cloaking */
185                 cloak(pp);
186                 break;
187           case 'q':                     /* quit */
188                 (void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
189                 break;
190         }
191 }
192
193 /*
194  * move_player:
195  *      Try to move player 'pp' in direction 'dir'.
196  */
197 static void
198 move_player(PLAYER *pp, int dir)
199 {
200         PLAYER  *newp;
201         int     x, y;
202         FLAG    moved;
203         BULLET  *bp;
204
205         y = pp->p_y;
206         x = pp->p_x;
207
208         switch (dir) {
209           case LEFTS:
210                 x--;
211                 break;
212           case RIGHT:
213                 x++;
214                 break;
215           case ABOVE:
216                 y--;
217                 break;
218           case BELOW:
219                 y++;
220                 break;
221         }
222
223         moved = FALSE;
224
225         /* What would the player move over: */
226         switch (Maze[y][x]) {
227           /* Players can move through spaces and doors, no problem: */
228           case SPACE:
229           case DOOR:
230                 moved = TRUE;
231                 break;
232           /* Can't move through walls: */
233           case WALL1:
234           case WALL2:
235           case WALL3:
236           case WALL4:
237           case WALL5:
238                 break;
239           /* Moving over a mine - try to pick it up: */
240           case MINE:
241           case GMINE:
242                 if (dir == pp->p_face)
243                         /* facing it: 2% chance of trip */
244                         pickup(pp, y, x, conf_ptrip_face, Maze[y][x]);
245                 else if (opposite(dir, pp->p_face))
246                         /* facing away: 95% chance of trip */
247                         pickup(pp, y, x, conf_ptrip_back, Maze[y][x]);
248                 else
249                         /* facing sideways: 50% chance of trip */
250                         pickup(pp, y, x, conf_ptrip_side, Maze[y][x]);
251                 /* Remove the mine: */
252                 Maze[y][x] = SPACE;
253                 moved = TRUE;
254                 break;
255           /* Moving into a bullet: */
256           case SHOT:
257           case GRENADE:
258           case SATCHEL:
259           case BOMB:
260           case SLIME:
261           case DSHOT:
262                 /* Find which bullet: */
263                 bp = is_bullet(y, x);
264                 if (bp != NULL)
265                         /* Detonate it: */
266                         bp->b_expl = TRUE;
267                 /* Remove it: */
268                 Maze[y][x] = SPACE;
269                 moved = TRUE;
270                 break;
271           /* Moving into another player: */
272           case LEFTS:
273           case RIGHT:
274           case ABOVE:
275           case BELOW:
276                 if (dir != pp->p_face)
277                         /* Can't walk backwards/sideways into another player: */
278                         sendcom(pp, BELL);
279                 else {
280                         /* Stab the other player */
281                         newp = play_at(y, x);
282                         checkdam(newp, pp, pp->p_ident, conf_stabdam, KNIFE);
283                 }
284                 break;
285           /* Moving into a player flying overhead: */
286           case FLYER:
287                 newp = play_at(y, x);
288                 message(newp, "Oooh, there's a short guy waving at you!");
289                 message(pp, "You couldn't quite reach him!");
290                 break;
291           /* Picking up a boot, or two: */
292           case BOOT_PAIR:
293                 pp->p_nboots++;
294           case BOOT:
295                 pp->p_nboots++;
296                 for (newp = Boot; newp < &Boot[NBOOTS]; newp++) {
297                         if (newp->p_flying < 0)
298                                 continue;
299                         if (newp->p_y == y && newp->p_x == x) {
300                                 newp->p_flying = -1;
301                                 if (newp->p_undershot)
302                                         fixshots(y, x, newp->p_over);
303                         }
304                 }
305                 if (pp->p_nboots == 2)
306                         message(pp, "Wow!  A pair of boots!");
307                 else
308                         message(pp, "You can hobble around on one boot.");
309                 Maze[y][x] = SPACE;
310                 moved = TRUE;
311                 break;
312         }
313
314         /* Can the player be moved? */
315         if (moved) {
316                 /* Check the gun status: */
317                 if (pp->p_ncshot > 0)
318                         if (--pp->p_ncshot == conf_maxncshot)
319                                 outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ok");
320                 /* Check for bullets flying past: */
321                 if (pp->p_undershot) {
322                         fixshots(pp->p_y, pp->p_x, pp->p_over);
323                         pp->p_undershot = FALSE;
324                 }
325                 /* Erase the player: */
326                 drawplayer(pp, FALSE);
327                 /* Save under: */
328                 pp->p_over = Maze[y][x];
329                 /* Move the player: */
330                 pp->p_y = y;
331                 pp->p_x = x;
332                 /* Draw the player in their new position */
333                 drawplayer(pp, TRUE);
334         }
335 }
336
337 /*
338  * face:
339  *      Change the direction the player is facing
340  */
341 static void
342 face(PLAYER *pp, int dir)
343 {
344         if (pp->p_face != dir) {
345                 pp->p_face = dir;
346                 drawplayer(pp, TRUE);
347         }
348 }
349
350 /*
351  * fire:
352  *      Fire a shot of the given type in the given direction
353  */
354 static void
355 fire(PLAYER *pp, int req_index)
356 {
357         if (pp == NULL)
358                 return;
359
360         /* Drop the shot type down until we can afford it: */
361         while (req_index >= 0 && pp->p_ammo < shot_req[req_index])
362                 req_index--;
363
364         /* Can we shoot at all? */
365         if (req_index < 0) {
366                 message(pp, "Not enough charges.");
367                 return;
368         }
369
370         /* Check if the gun is too hot: */
371         if (pp->p_ncshot > conf_maxncshot)
372                 return;
373
374         /* Heat up the gun: */
375         if (pp->p_ncshot++ == conf_maxncshot) {
376                 /* The gun has overheated: */
377                 outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, "   ");
378         }
379
380         /* Use up some ammo: */
381         pp->p_ammo -= shot_req[req_index];
382         ammo_update(pp);
383
384         /* Start the bullet moving: */
385         add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face,
386                 shot_req[req_index], pp, FALSE, pp->p_face);
387         pp->p_undershot = TRUE;
388
389         /* Show the bullet to everyone: */
390         showexpl(pp->p_y, pp->p_x, shot_type[req_index]);
391         sendcom(ALL_PLAYERS, REFRESH);
392 }
393
394 /*
395  * fire_slime:
396  *      Fire a slime shot in the given direction
397  */
398 static void
399 fire_slime(PLAYER *pp, int req_index)
400 {
401         if (pp == NULL)
402                 return;
403
404         /* Check configuration: */
405         if (!conf_ooze)
406                 return;
407
408         /* Drop the slime type back util we can afford it: */
409         while (req_index >= 0 && pp->p_ammo < slime_req[req_index])
410                 req_index--;
411
412         /* Can we afford to slime at all? */
413         if (req_index < 0) {
414                 message(pp, "Not enough charges.");
415                 return;
416         }
417
418         /* Is the gun too hot? */
419         if (pp->p_ncshot > conf_maxncshot)
420                 return;
421
422         /* Heat up the gun: */
423         if (pp->p_ncshot++ == conf_maxncshot) {
424                 /* The gun has overheated: */
425                 outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, "   ");
426         }
427
428         /* Use up some ammo: */
429         pp->p_ammo -= slime_req[req_index];
430         ammo_update(pp);
431
432         /* Start the slime moving: */
433         add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face,
434                 slime_req[req_index] * conf_slimefactor, pp, FALSE, pp->p_face);
435         pp->p_undershot = TRUE;
436
437         /* Show the object to everyone: */
438         showexpl(pp->p_y, pp->p_x, SLIME);
439         sendcom(ALL_PLAYERS, REFRESH);
440 }
441
442 /*
443  * add_shot:
444  *      Create a shot with the given properties
445  */
446 void
447 add_shot(int type, int y, int x, char wface, int charge, PLAYER *owner,
448     int expl, char over)
449 {
450         BULLET  *bp;
451         int     size;
452
453         /* Determine the bullet's size based on its type and charge: */
454         switch (type) {
455           case SHOT:
456           case MINE:
457                 size = 1;
458                 break;
459           case GRENADE:
460           case GMINE:
461                 size = 2;
462                 break;
463           case SATCHEL:
464                 size = 3;
465                 break;
466           case BOMB:
467                 for (size = 3; size < MAXBOMB; size++)
468                         if (shot_req[size] >= charge)
469                                 break;
470                 size++;
471                 break;
472           default:
473                 size = 0;
474                 break;
475         }
476
477         /* Create the bullet: */
478         bp = create_shot(type, y, x, wface, charge, size, owner,
479                 (owner == NULL) ? NULL : owner->p_ident, expl, over);
480
481         /* Insert the bullet into the front of the bullet list: */
482         bp->b_next = Bullets;
483         Bullets = bp;
484 }
485
486 /*
487  * create_shot:
488  *      allocate storage for an (unlinked) bullet structure;
489  *      initialize and return it
490  */
491 BULLET *
492 create_shot(int type, int y, int x, char wface, int charge, int size,
493     PLAYER *owner, IDENT *score, int expl, char over)
494 {
495         BULLET  *bp;
496
497         bp = (BULLET *) malloc(sizeof (BULLET));        /* NOSTRICT */
498         if (bp == NULL) {
499                 logit(LOG_ERR, "malloc");
500                 if (owner != NULL)
501                         message(owner, "Out of memory");
502                 return NULL;
503         }
504
505         bp->b_face = wface;
506         bp->b_x = x;
507         bp->b_y = y;
508         bp->b_charge = charge;
509         bp->b_owner = owner;
510         bp->b_score = score;
511         bp->b_type = type;
512         bp->b_size = size;
513         bp->b_expl = expl;
514         bp->b_over = over;
515         bp->b_next = NULL;
516
517         return bp;
518 }
519
520 /*
521  * cloak:
522  *      Turn on or increase length of a cloak
523  */
524 static void
525 cloak(PLAYER *pp)
526 {
527         /* Check configuration: */
528         if (!conf_cloak)
529                 return;
530
531         /* Can we afford it?: */
532         if (pp->p_ammo <= 0) {
533                 message(pp, "No more charges");
534                 return;
535         }
536
537         /* Can't cloak with boots: */
538         if (pp->p_nboots > 0) {
539                 message(pp, "Boots are too noisy to cloak!");
540                 return;
541         }
542
543         /* Consume a unit of ammo: */
544         pp->p_ammo--;
545         ammo_update(pp);
546
547         /* Add to the duration of a cloak: */
548         pp->p_cloak += conf_cloaklen;
549
550         /* Disable scan, if enabled: */
551         if (pp->p_scan >= 0)
552                 pp->p_scan = -1;
553
554         /* Re-draw the player's scan/cloak status: */
555         showstat(pp);
556 }
557
558 /*
559  * scan:
560  *      Turn on or increase length of a scan
561  */
562 static void
563 scan(PLAYER *pp)
564 {
565         /* Check configuration: */
566         if (!conf_scan)
567                 return;
568
569         /* Can we afford it?: */
570         if (pp->p_ammo <= 0) {
571                 message(pp, "No more charges");
572                 return;
573         }
574
575         /* Consume one unit of ammo: */
576         pp->p_ammo--;
577         ammo_update(pp);
578
579         /* Increase the scan time: */
580         pp->p_scan += Nplayer * conf_scanlen;
581
582         /* Disable cloak, if enabled: */
583         if (pp->p_cloak >= 0)
584                 pp->p_cloak = -1;
585
586         /* Re-draw the player's scan/cloak status: */
587         showstat(pp);
588 }
589
590 /*
591  * pickup:
592  *      pick up a mine or grenade, with some probability of it exploding
593  */
594 static void
595 pickup(PLAYER *pp, int y, int x, int prob, int obj)
596 {
597         int     req;
598
599         /* Figure out how much ammo the player is trying to pick up: */
600         switch (obj) {
601           case MINE:
602                 req = BULREQ;
603                 break;
604           case GMINE:
605                 req = GRENREQ;
606                 break;
607           default:
608 #ifdef DIAGNOSTIC
609                 abort();
610 #endif
611                 return;
612         }
613
614         /* Does it explode? */
615         if (rand_num(100) < prob)
616                 /* Ooooh, unlucky: (Boom) */
617                 add_shot(obj, y, x, LEFTS, req, NULL, TRUE, pp->p_face);
618         else {
619                 /* Safely picked it up. Add to player's ammo: */
620                 pp->p_ammo += req;
621                 ammo_update(pp);
622         }
623 }
624
625 void
626 ammo_update(PLAYER *pp)
627 {
628         outyx(pp, STAT_AMMO_ROW, STAT_VALUE_COL - 1, "%4d", pp->p_ammo);
629 }