1 /*        $NetBSD: expl.c,v 1.9 2021/05/02 12:50:45 rillig Exp $      */
2 /*
3  * Copyright (c) 1983-2003, Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * + Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * + Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * + Neither the name of the University of California, San Francisco nor
16  *   the names of its contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: expl.c,v 1.9 2021/05/02 12:50:45 rillig Exp $");
36 #endif /* not lint */
37 
38 #include <stdlib.h>
39 #include "hunt.h"
40 
41 
42 static EXPL *Expl[EXPLEN];              /* explosion lists */
43 static EXPL *Last_expl;                           /* last explosion on Expl[0] */
44 
45 static void remove_wall(int, int);
46 
47 
48 /*
49  * showexpl:
50  *        Show the explosions as they currently are
51  */
52 void
showexpl(int y,int x,char type)53 showexpl(int y, int x, char type)
54 {
55           PLAYER *pp;
56           EXPL *ep;
57 
58           if (y < 0 || y >= HEIGHT)
59                     return;
60           if (x < 0 || x >= WIDTH)
61                     return;
62           ep = malloc(sizeof(*ep));
63           ep->e_y = y;
64           ep->e_x = x;
65           ep->e_char = type;
66           ep->e_next = NULL;
67           if (Last_expl == NULL)
68                     Expl[0] = ep;
69           else
70                     Last_expl->e_next = ep;
71           Last_expl = ep;
72           for (pp = Player; pp < End_player; pp++) {
73                     if (pp->p_maze[y][x] == type)
74                               continue;
75                     pp->p_maze[y][x] = type;
76                     cgoto(pp, y, x);
77                     outch(pp, type);
78           }
79 #ifdef MONITOR
80           for (pp = Monitor; pp < End_monitor; pp++) {
81                     if (pp->p_maze[y][x] == type)
82                               continue;
83                     pp->p_maze[y][x] = type;
84                     cgoto(pp, y, x);
85                     outch(pp, type);
86           }
87 #endif
88           switch (Maze[y][x]) {
89             case WALL1:
90             case WALL2:
91             case WALL3:
92 #ifdef RANDOM
93             case DOOR:
94 #endif
95 #ifdef REFLECT
96             case WALL4:
97             case WALL5:
98 #endif
99                     if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND)
100                               remove_wall(y, x);
101                     break;
102           }
103 }
104 
105 /*
106  * rollexpl:
107  *        Roll the explosions over, so the next one in the list is at the
108  *        top
109  */
110 void
rollexpl(void)111 rollexpl(void)
112 {
113           EXPL *ep;
114           PLAYER *pp;
115           int y, x;
116           char c;
117           EXPL *nextep;
118 
119           for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) {
120                     nextep = ep->e_next;
121                     y = ep->e_y;
122                     x = ep->e_x;
123                     if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND)
124                               c = Maze[y][x];
125                     else
126                               c = SPACE;
127                     for (pp = Player; pp < End_player; pp++)
128                               if (pp->p_maze[y][x] == ep->e_char) {
129                                         pp->p_maze[y][x] = c;
130                                         cgoto(pp, y, x);
131                                         outch(pp, c);
132                               }
133 #ifdef MONITOR
134                     for (pp = Monitor; pp < End_monitor; pp++)
135                               check(pp, y, x);
136 #endif
137                     free(ep);
138           }
139           for (x = EXPLEN - 1; x > 0; x--)
140                     Expl[x] = Expl[x - 1];
141           Last_expl = Expl[0] = NULL;
142 }
143 
144 /* There's about 700 walls in the initial maze.  So we pick a number
145  * that keeps the maze relatively full. */
146 #define MAXREMOVE   40
147 
148 static REGEN removed[MAXREMOVE];
149 static REGEN *rem_index = removed;
150 
151 /*
152  * remove_wall - add a location where the wall was blown away.
153  *                   if there is no space left over, put the a wall at
154  *                   the location currently pointed at.
155  */
156 static void
remove_wall(int y,int x)157 remove_wall(int y, int x)
158 {
159           REGEN *r;
160 #if defined(MONITOR) || defined(FLY)
161           PLAYER *pp;
162 #endif
163 #ifdef FLY
164           char save_char = 0;
165 #endif
166 
167           r = rem_index;
168           while (r->r_y != 0) {
169 #ifdef FLY
170                     switch (Maze[r->r_y][r->r_x]) {
171                       case SPACE:
172                       case LEFTS:
173                       case RIGHT:
174                       case ABOVE:
175                       case BELOW:
176                       case FLYER:
177                               save_char = Maze[r->r_y][r->r_x];
178                               goto found;
179                     }
180 #else
181                     if (Maze[r->r_y][r->r_x] == SPACE)
182                               break;
183 #endif
184                     if (++r >= &removed[MAXREMOVE])
185                               r = removed;
186           }
187 
188 found:
189           if (r->r_y != 0) {
190                     /* Slot being used, put back this wall */
191 #ifdef FLY
192                     if (save_char == SPACE)
193                               Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
194                     else {
195                               pp = play_at(r->r_y, r->r_x);
196                               if (pp->p_flying >= 0)
197                                         pp->p_flying += rand_num(10);
198                               else {
199                                         pp->p_flying = rand_num(20);
200                                         pp->p_flyx = 2 * rand_num(6) - 5;
201                                         pp->p_flyy = 2 * rand_num(6) - 5;
202                               }
203                               pp->p_over = Orig_maze[r->r_y][r->r_x];
204                               pp->p_face = FLYER;
205                               Maze[r->r_y][r->r_x] = FLYER;
206                               showexpl(r->r_y, r->r_x, FLYER);
207                     }
208 #else
209                     Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
210 #endif
211 #ifdef RANDOM
212                     if (rand_num(100) == 0)
213                               Maze[r->r_y][r->r_x] = DOOR;
214 #endif
215 #ifdef REFLECT
216                     if (rand_num(100) == 0)                 /* one percent of the time */
217                               Maze[r->r_y][r->r_x] = WALL4;
218 #endif
219 #ifdef MONITOR
220                     for (pp = Monitor; pp < End_monitor; pp++)
221                               check(pp, r->r_y, r->r_x);
222 #endif
223           }
224 
225           r->r_y = y;
226           r->r_x = x;
227           if (++r >= &removed[MAXREMOVE])
228                     rem_index = removed;
229           else
230                     rem_index = r;
231 
232           Maze[y][x] = SPACE;
233 #ifdef MONITOR
234           for (pp = Monitor; pp < End_monitor; pp++)
235                     check(pp, y, x);
236 #endif
237 }
238 
239 /*
240  * clearwalls:
241  *        Clear out the walls array
242  */
243 void
clearwalls(void)244 clearwalls(void)
245 {
246           REGEN *rp;
247 
248           for (rp = removed; rp < &removed[MAXREMOVE]; rp++)
249                     rp->r_y = 0;
250           rem_index = removed;
251 }
252