Bring hunt in from OpenBSD. The best multi-player terminal game ever!
[dragonfly.git] / games / hunt / huntd / expl.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: expl.c,v 1.9 2007/09/04 22:39:31 hshoexer Exp $
32  * $NetBSD: expl.c,v 1.2 1997/10/10 16:33:18 lukem Exp $
33  * $DragonFly: src/games/hunt/huntd/expl.c,v 1.1 2008/09/02 21:50:21 dillon Exp $
34  */
35
36 #include <stdlib.h>
37 #include <syslog.h>
38 #include <string.h>
39 #include "hunt.h"
40 #include "server.h"
41 #include "conf.h"
42
43 static  void    remove_wall(int, int);
44 static  void    init_removed(void);
45
46
47 /*
48  * showexpl:
49  *      Show the explosions as they currently are
50  */
51 void
52 showexpl(y, x, type)
53         int     y, x;
54         char    type;
55 {
56         PLAYER  *pp;
57         EXPL    *ep;
58
59         if (y < 0 || y >= HEIGHT)
60                 return;
61         if (x < 0 || x >= WIDTH)
62                 return;
63         ep = (EXPL *) malloc(sizeof (EXPL));    /* NOSTRICT */
64         if (ep == NULL) {
65                 logit(LOG_ERR, "malloc");
66                 return;
67         }
68         ep->e_y = y;
69         ep->e_x = x;
70         ep->e_char = type;
71         ep->e_next = NULL;
72         if (Last_expl == NULL)
73                 Expl[0] = ep;
74         else
75                 Last_expl->e_next = ep;
76         Last_expl = ep;
77         for (pp = Player; pp < End_player; pp++) {
78                 if (pp->p_maze[y][x] == type)
79                         continue;
80                 pp->p_maze[y][x] = type;
81                 cgoto(pp, y, x);
82                 outch(pp, type);
83         }
84         for (pp = Monitor; pp < End_monitor; pp++) {
85                 if (pp->p_maze[y][x] == type)
86                         continue;
87                 pp->p_maze[y][x] = type;
88                 cgoto(pp, y, x);
89                 outch(pp, type);
90         }
91         switch (Maze[y][x]) {
92           case WALL1:
93           case WALL2:
94           case WALL3:
95           case DOOR:
96           case WALL4:
97           case WALL5:
98                 if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND)
99                         remove_wall(y, x);
100                 break;
101         }
102 }
103
104 /*
105  * rollexpl:
106  *      Roll the explosions over, so the next one in the list is at the
107  *      top
108  */
109 void
110 rollexpl()
111 {
112         EXPL    *ep;
113         PLAYER  *pp;
114         int     y, x;
115         char    c;
116         EXPL    *nextep;
117
118         for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) {
119                 nextep = ep->e_next;
120                 y = ep->e_y;
121                 x = ep->e_x;
122                 if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND)
123                         c = Maze[y][x];
124                 else
125                         c = SPACE;
126                 for (pp = Player; pp < End_player; pp++)
127                         if (pp->p_maze[y][x] == ep->e_char) {
128                                 pp->p_maze[y][x] = c;
129                                 cgoto(pp, y, x);
130                                 outch(pp, c);
131                         }
132                 for (pp = Monitor; pp < End_monitor; pp++)
133                         check(pp, y, x);
134                 free((char *) ep);
135         }
136         memmove(&Expl[1], &Expl[0], (EXPLEN - 1) * sizeof Expl[0]);
137         /* for (x = EXPLEN - 1; x > 0; x--)
138                 Expl[x] = Expl[x - 1]; */
139         Last_expl = Expl[0] = NULL;
140 }
141
142 int
143 can_rollexpl()
144 {
145         int i;
146
147         for (i = EXPLEN - 1; i >= 0; i--)
148                 if (Expl[i] != NULL)
149                         return 1;
150         return 0;
151 }
152
153 static  REGEN   *removed = NULL;
154 static  REGEN   *rem_index = NULL;
155
156 static void
157 init_removed()
158 {
159         rem_index = removed = calloc(conf_maxremove, sizeof(REGEN));
160         if (rem_index == NULL) {
161                 logit(LOG_ERR, "malloc");
162                 cleanup(1);
163         }
164 }
165
166 /*
167  * remove_wall - add a location where the wall was blown away.
168  *               if there is no space left over, put the a wall at
169  *               the location currently pointed at.
170  */
171 static void
172 remove_wall(y, x)
173         int     y, x;
174 {
175         REGEN   *r;
176         PLAYER  *pp;
177         char    save_char = 0;
178
179         if (removed == NULL)
180                 clearwalls();
181
182         r = rem_index;
183         while (r->r_y != 0) {
184                 switch (Maze[r->r_y][r->r_x]) {
185                   case SPACE:
186                   case LEFTS:
187                   case RIGHT:
188                   case ABOVE:
189                   case BELOW:
190                   case FLYER:
191                         save_char = Maze[r->r_y][r->r_x];
192                         goto found;
193                 }
194                 if (++r >= removed + conf_maxremove)
195                         r = removed;
196         }
197
198 found:
199         if (r->r_y != 0) {
200                 /* Slot being used, put back this wall */
201                 if (save_char == SPACE)
202                         Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
203                 else {
204                         /* We throw the player off the wall: */
205                         pp = play_at(r->r_y, r->r_x);
206                         if (pp->p_flying >= 0)
207                                 pp->p_flying += rand_num(conf_flytime / 2);
208                         else {
209                                 pp->p_flying = rand_num(conf_flytime);
210                                 pp->p_flyx = 2 * rand_num(conf_flystep + 1) -
211                                     conf_flystep;
212                                 pp->p_flyy = 2 * rand_num(conf_flystep + 1) -
213                                     conf_flystep;
214                         }
215                         pp->p_over = Orig_maze[r->r_y][r->r_x];
216                         pp->p_face = FLYER;
217                         Maze[r->r_y][r->r_x] = FLYER;
218                         showexpl(r->r_y, r->r_x, FLYER);
219                 }
220                 Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
221                 if (conf_random && rand_num(100) < conf_prandom)
222                         Maze[r->r_y][r->r_x] = DOOR;
223                 if (conf_reflect && rand_num(100) == conf_preflect)
224                         Maze[r->r_y][r->r_x] = WALL4;
225                 for (pp = Monitor; pp < End_monitor; pp++)
226                         check(pp, r->r_y, r->r_x);
227         }
228
229         r->r_y = y;
230         r->r_x = x;
231         if (++r >= removed + conf_maxremove)
232                 rem_index = removed;
233         else
234                 rem_index = r;
235
236         Maze[y][x] = SPACE;
237         for (pp = Monitor; pp < End_monitor; pp++)
238                 check(pp, y, x);
239 }
240
241 /*
242  * clearwalls:
243  *      Clear out the walls array
244  */
245 void
246 clearwalls()
247 {
248         REGEN   *rp;
249
250         if (removed == NULL)
251                 init_removed();
252         for (rp = removed; rp < removed + conf_maxremove; rp++)
253                 rp->r_y = 0;
254         rem_index = removed;
255 }