Merge branch 'vendor/OPENSSL'
[games.git] / games / larn / movem.c
1 /*
2  *      movem.c (move monster)          Larn is copyrighted 1986 by Noah Morgan.
3  * $FreeBSD: src/games/larn/movem.c,v 1.4 1999/11/16 02:57:23 billf Exp $
4  * $DragonFly: src/games/larn/movem.c,v 1.3 2006/08/26 17:05:05 pavalos Exp $
5  *
6  *      Here are the functions in this file:
7  *
8  *      movemonst()             Routine to move the monsters toward the player
9  *      movemt(x,y)             Function to move a monster at (x,y) -- must determine where
10  *      mmove(x,y,xd,yd)        Function to actually perform the monster movement
11  *      movsphere()             Function to look for and move spheres of annihilation
12  */
13 #include "header.h"
14
15 static void movemt(int, int);
16 static void mmove(int, int, int, int);
17 static void movsphere(void);
18
19 /*
20  *      movemonst()             Routine to move the monsters toward the player
21  *
22  *      This routine has the responsibility to determine which monsters are to
23  *      move, and call movemt() to do the move.
24  *      Returns no value.
25  */
26 static short w1[9], w1x[9], w1y[9];
27 static int tmp1, tmp2, tmp3, tmp4, distance;
28
29 void
30 movemonst(void)
31 {
32         int i, j;
33         if (c[TIMESTOP])        /* no action if time is stopped */
34                 return;
35         if (c[HASTESELF])
36                 if ((c[HASTESELF] & 1) == 0)
37                         return;
38         if (spheres)            /* move the spheres of annihilation if any */
39                 movsphere();
40         if (c[HOLDMONST])       /* no action if monsters are held */
41                 return;
42
43         if (c[AGGRAVATE]) {     /* determine window of monsters to move */
44                 tmp1 = playery - 5;
45                 tmp2 = playery + 6;
46                 tmp3 = playerx - 10;
47                 tmp4 = playerx + 11;
48                 distance = 40;  /* depth of intelligent monster movement */
49         } else {
50                 tmp1 = playery - 3;
51                 tmp2 = playery + 4;
52                 tmp3 = playerx - 5;
53                 tmp4 = playerx + 6;
54                 distance = 17;  /* depth of intelligent monster movement */
55         }
56
57         /* if on outside level monsters can move in perimeter */
58         if (level == 0) {
59                 if (tmp1 < 0)
60                         tmp1 = 0;
61                 if (tmp2 > MAXY)
62                         tmp2 = MAXY;
63                 if (tmp3 < 0)
64                         tmp3 = 0;
65                 if (tmp4 > MAXX)
66                         tmp4 = MAXX;
67         } else {        /* if in a dungeon monsters can't be on the perimeter (wall there) */
68                 if (tmp1 < 1)
69                         tmp1 = 1;
70                 if (tmp2 > MAXY - 1)
71                         tmp2 = MAXY - 1;
72                 if (tmp3 < 1)
73                         tmp3 = 1;
74                 if (tmp4 > MAXX - 1)
75                         tmp4 = MAXX - 1;
76         }
77
78         for (j = tmp1; j < tmp2; j++)   /* now reset monster moved flags */
79                 for (i = tmp3; i < tmp4; i++)
80                         moved[i][j] = 0;
81         moved[lasthx][lasthy] = 0;
82
83          /* who gets moved? split for efficiency */
84         if (c[AGGRAVATE] || !c[STEALTH]) {
85                 /* look thru all locations in window */
86                 for (j = tmp1; j < tmp2; j++)
87                         for (i = tmp3; i < tmp4; i++)
88                                 /* if there is a monster to move */
89                                 if (mitem[i][j])
90                                         /* if it has not already been moved */
91                                         if (moved[i][j] == 0)
92                                                 /* go and move the monster */
93                                                 movemt(i, j);
94         } else {                /* not aggravated and not stealth */
95                 /* look thru all locations in window */
96                 for (j = tmp1; j < tmp2; j++)
97                         for (i = tmp3; i < tmp4; i++)
98                                 /* if there is a monster to move */
99                                 if (mitem[i][j])
100                                         /* if it has not already been moved */
101                                         if (moved[i][j] == 0)
102                                                 /* if it is asleep due to stealth */
103                                                 if (stealth[i][j])
104                                                         /* go and move the monster */
105                                                         movemt(i, j);
106         }
107
108         /* now move monster last hit by player if not already moved */
109         if (mitem[lasthx][lasthy]) {
110                 /* if it has not already been moved */
111                 if (moved[lasthx][lasthy] == 0) {
112                         movemt(lasthx, lasthy);
113                         lasthx = w1x[0];
114                         lasthy = w1y[0];
115                 }
116         }
117 }
118
119 /*
120  *      movemt(x,y)             Function to move a monster at (x,y) -- must determine where
121  *              int x,y;
122  *
123  *      This routine is responsible for determining where one monster at (x,y) will
124  *      move to.  Enter with the monsters coordinates in (x,y).
125  *      Returns no value.
126  */
127 static int tmpitem, xl, xh, yl, yh;
128
129 static void
130 movemt(int i, int j)
131 {
132         int k, m, z, tmp, xtmp, ytmp, monst;
133         switch (monst = mitem[i][j]) {  /* for half speed monsters */
134         case TROGLODYTE:
135         case HOBGOBLIN:
136         case METAMORPH:
137         case XVART:
138         case INVISIBLESTALKER:
139         case ICELIZARD:
140                 if ((gtime & 1) == 1)
141                         return;
142         }
143
144         if (c[SCAREMONST]) {    /* choose destination randomly if scared */
145                 if ((xl = i + rnd(3) - 2) < 0)
146                         xl = 0;
147                 if (xl >= MAXX)
148                         xl = MAXX - 1;
149                 if ((yl = j + rnd(3) - 2) < 0)
150                         yl = 0;
151                 if (yl >= MAXY)
152                         yl = MAXY - 1;
153                 if ((tmp = item[xl][yl]) != OWALL)
154                         if (mitem[xl][yl] == 0)
155                                 if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
156                                         if (tmp != OCLOSEDDOOR)
157                                                 mmove(i, j, xl, yl);
158                 return;
159         }
160
161         if (monster[monst].intelligence > 10 - c[HARDGAME]) {   /* if smart monster */
162                 /* intelligent movement here -- first setup screen array */
163                 xl = tmp3 - 2;
164                 yl = tmp1 - 2;
165                 xh = tmp4 + 2;
166                 yh = tmp2 + 2;
167                 vxy(&xl, &yl);
168                 vxy(&xh, &yh);
169                 for (k = yl; k < yh; k++)
170                         for (m = xl; m < xh; m++) {
171                                 switch (item[m][k]) {
172                                 case OWALL:
173                                 case OPIT:
174                                 case OTRAPARROW:
175                                 case ODARTRAP:
176                                 case OCLOSEDDOOR:
177                                 case OTRAPDOOR:
178                                 case OTELEPORTER:
179 smm:                                    screen[m][k] = 127;
180                                         break;
181                                 case OMIRROR:
182                                         if (mitem[m][k] == VAMPIRE)
183                                                 goto smm;
184                                 default:
185                                         screen[m][k] = 0;
186                                         break;
187                                 }
188                         }
189                 screen[playerx][playery] = 1;
190
191                 /* now perform proximity ripple from playerx,playery to monster */
192                 xl = tmp3 - 1;
193                 yl = tmp1 - 1;
194                 xh = tmp4 + 1;
195                 yh = tmp2 + 1;
196                 vxy(&xl, &yl);
197                 vxy(&xh, &yh);
198                 for (tmp = 1; tmp < distance; tmp++)    /* only up to 20 squares away */
199                         for (k = yl; k < yh; k++)
200                                 for (m = xl; m < xh; m++)
201                                         /* if find proximity n advance it */
202                                         if (screen[m][k] == tmp)
203                                                 /* go around in a circle */
204                                                 for (z = 1; z < 9; z++) {
205                                                         if (screen[xtmp = m + diroffx[z]][ytmp = k + diroffy[z]] == 0)
206                                                                 screen[xtmp][ytmp] = tmp + 1;
207                                                         if (xtmp == i && ytmp == j)
208                                                                 goto out;
209                                                 }
210
211 out:            if (tmp < distance)     /* did find connectivity */
212                         /* now select lowest value around playerx,playery */
213                         for (z = 1; z < 9; z++) /* go around in a circle */
214                                 if (screen[xl = i + diroffx[z]][yl = j + diroffy[z]] == tmp)
215                                         if (!mitem[xl][yl]) {
216                                                 mmove(i, j, w1x[0] = xl, w1y[0] = yl);
217                                                 return;
218                                         }
219         }
220
221         /* dumb monsters move here */
222         xl = i - 1;
223         yl = j - 1;
224         xh = i + 2;
225         yh = j + 2;
226         if (i < playerx)
227                 xl++;
228         else if (i > playerx)
229                 --xh;
230         if (j < playery)
231                 yl++;
232         else if (j > playery)
233                 --yh;
234         for (k = 0; k < 9; k++)
235                 w1[k] = 10000;
236
237         for (k = xl; k < xh; k++)
238                 /* for each square compute distance to player */
239                 for (m = yl; m < yh; m++) {
240                         tmp = k - i + 4 + 3 * (m - j);
241                         tmpitem = item[k][m];
242                         if (tmpitem != OWALL || (k == playerx && m == playery))
243                                 if (mitem[k][m] == 0)
244                                         if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
245                                                 if (tmpitem != OCLOSEDDOOR) {
246                                                         w1[tmp] = (playerx - k) * (playerx - k) + (playery - m) * (playery - m);
247                                                         w1x[tmp] = k;
248                                                         w1y[tmp] = m;
249                                                 }
250                 }
251
252         tmp = 0;
253         for (k = 1; k < 9; k++)
254                 if (w1[tmp] > w1[k])
255                         tmp = k;
256
257         if (w1[tmp] < 10000)
258                 if ((i != w1x[tmp]) || (j != w1y[tmp]))
259                         mmove(i, j, w1x[tmp], w1y[tmp]);
260 }
261
262 /*
263  *      mmove(x,y,xd,yd)        Function to actually perform the monster movement
264  *              int x,y,xd,yd;
265  *
266  *      Enter with the from coordinates in (x,y) and the destination coordinates
267  *      in (xd,yd).
268  */
269 static void
270 mmove(int aa, int bb, int cc, int dd)
271 {
272         int tmp, i, flag;
273         const char *who = NULL, *p;
274         flag = 0;               /* set to 1 if monster hit by arrow trap */
275         if ((cc == playerx) && (dd == playery)) {
276                 hitplayer(aa, bb);
277                 moved[aa][bb] = 1;
278                 return;
279         }
280         i = item[cc][dd];
281         if ((i == OPIT) || (i == OTRAPDOOR))
282                 switch (mitem[aa][bb]) {
283                 case SPIRITNAGA:
284                 case PLATINUMDRAGON:
285                 case WRAITH:
286                 case VAMPIRE:
287                 case SILVERDRAGON:
288                 case POLTERGEIST:
289                 case DEMONLORD:
290                 case DEMONLORD + 1:
291                 case DEMONLORD + 2:
292                 case DEMONLORD + 3:
293                 case DEMONLORD + 4:
294                 case DEMONLORD + 5:
295                 case DEMONLORD + 6:
296                 case DEMONPRINCE:
297                         break;
298
299                 default:
300                         mitem[aa][bb] = 0;      /* fell in a pit or trapdoor */
301                 }
302         tmp = mitem[cc][dd] = mitem[aa][bb];
303         if (i == OANNIHILATION) {
304                 if (tmp >= DEMONLORD + 3) {     /* demons dispel spheres */
305                         cursors();
306                         lprintf("\nThe %s dispels the sphere!", monster[tmp].name);
307                         rmsphere(cc, dd);       /* delete the sphere */
308                 } else
309                         i = tmp = mitem[cc][dd] = 0;
310         }
311         stealth[cc][dd] = 1;
312         if ((hitp[cc][dd] = hitp[aa][bb]) < 0)
313                 hitp[cc][dd] = 1;
314         mitem[aa][bb] = 0;
315         moved[cc][dd] = 1;
316         if (tmp == LEPRECHAUN)
317                 switch (i) {
318                 case OGOLDPILE:
319                 case OMAXGOLD:
320                 case OKGOLD:
321                 case ODGOLD:
322                 case ODIAMOND:
323                 case ORUBY:
324                 case OEMERALD:
325                 case OSAPPHIRE:
326                         item[cc][dd] = 0;       /* leprechaun takes gold */
327                 }
328
329         if (tmp == TROLL)       /* if a troll regenerate him */
330                 if ((gtime & 1) == 0)
331                         if (monster[tmp].hitpoints > hitp[cc][dd])
332                                 hitp[cc][dd]++;
333
334         if (i == OTRAPARROW) {  /* arrow hits monster */
335                 who = "An arrow";
336                 if ((hitp[cc][dd] -= rnd(10) + level) <= 0) {
337                         mitem[cc][dd] = 0;
338                         flag = 2;
339                 } else
340                         flag = 1;
341         }
342         if (i == ODARTRAP) {    /* dart hits monster */
343                 who = "A dart";
344                 if ((hitp[cc][dd] -= rnd(6)) <= 0) {
345                         mitem[cc][dd] = 0;
346                         flag = 2;
347                 } else
348                         flag = 1;
349         }
350         if (i == OTELEPORTER) { /* monster hits teleport trap */
351                 flag = 3;
352                 fillmonst(mitem[cc][dd]);
353                 mitem[cc][dd] = 0;
354         }
355         if (c[BLINDCOUNT])      /* if blind don't show where monsters are */
356                 return;
357         if (know[cc][dd] & 1) {
358                 p = 0;
359                 if (flag)
360                         cursors();
361                 switch (flag) {
362                 case 1:
363                         p = "\n%s hits the %s";
364                         break;
365                 case 2:
366                         p = "\n%s hits and kills the %s";
367                         break;
368                 case 3:
369                         p = "\nThe %s%s gets teleported";
370                         who = "";
371                         break;
372                 }
373                 if (p) {
374                         lprintf(p, who, monster[tmp].name);
375                         beep();
376                 }
377         }
378         if (know[aa][bb] & 1)
379                 show1cell(aa, bb);
380         if (know[cc][dd] & 1)
381                 show1cell(cc, dd);
382 }
383
384 /*
385  *      movsphere()     Function to look for and move spheres of annihilation
386  *
387  *      This function works on the sphere linked list, first duplicating the list
388  *      (the act of moving changes the list), then processing each sphere in order
389  *      to move it.  They eat anything in their way, including stairs, volcanic
390  *      shafts, potions, etc, except for upper level demons, who can dispel
391  *      spheres.
392  *      No value is returned.
393  */
394 #define SPHMAX 20       /* maximum number of spheres movsphere can handle */
395 static void
396 movsphere(void)
397 {
398         int x, y, dir, len;
399         struct sphere *sp, *sp2;
400         struct sphere sph[SPHMAX];
401
402         /* first duplicate sphere list */
403         /* look through sphere list */
404         for (sp = 0, x = 0, sp2 = spheres; sp2; sp2 = sp2->p)
405                 if (sp2->lev == level) {        /* only if this level */
406                         sph[x] = *sp2;
407                         sph[x++].p = 0;         /* copy the struct */
408                         if (x > 1)
409                                 sph[x - 2].p = &sph[x - 1];     /* link pointers */
410                 }
411         if (x)          /* if any spheres, point to them */
412                 sp = sph;
413         else            /* no spheres */
414                 return;
415
416         for (sp = sph; sp; sp = sp->p) {        /* look through sphere list */
417                 x = sp->x;
418                 y = sp->y;
419                 if (item[x][y] != OANNIHILATION)        /* not really there */
420                         continue;
421                 if (--(sp->lifetime) < 0) {     /* has sphere run out of gas? */
422                         rmsphere(x, y);         /* delete sphere */
423                         continue;
424                 }
425                 /* time to move the sphere */
426                 switch (rnd((int)max(7, c[INTELLIGENCE] >> 1))) {
427                 case 1:
428                 case 2:         /* change direction to a random one */
429                         sp->dir = rnd(8);
430                 default:        /* move in normal direction */
431                         dir = sp->dir;
432                         len = sp->lifetime;
433                         rmsphere(x, y);
434                         newsphere(x + diroffx[dir], y + diroffy[dir], dir, len);
435                 }
436         }
437 }