-WARNS6 cleanup (4670 warnings)
[dragonfly.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]) return;        /* no action if time is stopped */
34         if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
35         if (spheres) movsphere();       /* move the spheres of annihilation if any */
36         if (c[HOLDMONST])  return;      /* no action if monsters are held */
37
38         if (c[AGGRAVATE])       /* determine window of monsters to move */
39           {
40           tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
41           distance=40; /* depth of intelligent monster movement */
42           }
43         else
44           {
45           tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
46           distance=17; /* depth of intelligent monster movement */
47           }
48
49         if (level == 0) /* if on outside level monsters can move in perimeter */
50                 {
51                 if (tmp1 < 0) tmp1=0;            if (tmp2 > MAXY) tmp2=MAXY;
52                 if (tmp3 < 0) tmp3=0;            if (tmp4 > MAXX) tmp4=MAXX;
53                 }
54         else /* if in a dungeon monsters can't be on the perimeter (wall there) */
55                 {
56                 if (tmp1 < 1) tmp1=1;            if (tmp2 > MAXY-1) tmp2=MAXY-1;
57                 if (tmp3 < 1) tmp3=1;            if (tmp4 > MAXX-1) tmp4=MAXX-1;
58                 }
59
60         for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
61                 for (i=tmp3; i<tmp4; i++)
62                         moved[i][j] = 0;
63     moved[lasthx][lasthy]=0;
64
65         if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
66           {
67           for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
68             for (i=tmp3; i<tmp4; i++)
69                   if (mitem[i][j])      /* if there is a monster to move */
70                     if (moved[i][j]==0) /* if it has not already been moved */
71                           movemt(i,j);  /* go and move the monster */
72           }
73         else /* not aggravated and not stealth */
74           {
75           for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
76             for (i=tmp3; i<tmp4; i++)
77                   if (mitem[i][j])      /* if there is a monster to move */
78                     if (moved[i][j]==0) /* if it has not already been moved */
79                           if (stealth[i][j])    /* if it is asleep due to stealth */
80                             movemt(i,j);        /* go and move the monster */
81           }
82
83         if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
84                 {
85             if (moved[lasthx][lasthy]==0)       /* if it has not already been moved */
86                         {
87                         movemt(lasthx,lasthy);
88                         lasthx = w1x[0];   lasthy = w1y[0];
89                         }
90                 }
91         }
92
93 /*
94  *      movemt(x,y)             Function to move a monster at (x,y) -- must determine where
95  *              int x,y;
96  *
97  *      This routine is responsible for determining where one monster at (x,y) will
98  *      move to.  Enter with the monsters coordinates in (x,y).
99  *      Returns no value.
100  */
101 static int tmpitem,xl,xh,yl,yh;
102
103 static void
104 movemt(int i, int j)
105         {
106         int k,m,z,tmp,xtmp,ytmp,monst;
107         switch(monst=mitem[i][j])  /* for half speed monsters */
108                 {
109                 case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
110                 case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
111                 };
112
113         if (c[SCAREMONST]) /* choose destination randomly if scared */
114                 {
115                 if ((xl = i+rnd(3)-2) < 0) xl=0;  if (xl >= MAXX) xl=MAXX-1;
116                 if ((yl = j+rnd(3)-2) < 0) yl=0;  if (yl >= MAXY) yl=MAXY-1;
117                 if ((tmp=item[xl][yl]) != OWALL)
118                   if (mitem[xl][yl] == 0)
119                         if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
120                           if (tmp != OCLOSEDDOOR)               mmove(i,j,xl,yl);
121                 return;
122                 }
123
124         if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
125 /* intelligent movement here -- first setup screen array */
126           {
127           xl=tmp3-2; yl=tmp1-2; xh=tmp4+2;  yh=tmp2+2;
128           vxy(&xl,&yl);  vxy(&xh,&yh);
129           for (k=yl; k<yh; k++)
130             for (m=xl; m<xh; m++)
131                   {
132                   switch(item[m][k])
133                         {
134                         case OWALL: case OPIT: case OTRAPARROW: case ODARTRAP:
135                         case OCLOSEDDOOR: case OTRAPDOOR: case OTELEPORTER:
136                                 smm:      screen[m][k]=127;  break;
137                         case OMIRROR: if (mitem[m][k]==VAMPIRE) goto smm;
138                         default:  screen[m][k]=  0;  break;
139                         };
140                   }
141           screen[playerx][playery]=1;
142
143 /* now perform proximity ripple from playerx,playery to monster */
144           xl=tmp3-1; yl=tmp1-1; xh=tmp4+1;  yh=tmp2+1;
145           vxy(&xl,&yl);  vxy(&xh,&yh);
146           for (tmp=1; tmp<distance; tmp++)      /* only up to 20 squares away */
147             for (k=yl; k<yh; k++)
148               for (m=xl; m<xh; m++)
149                     if (screen[m][k]==tmp) /* if find proximity n advance it */
150                           for (z=1; z<9; z++) /* go around in a circle */
151                             {
152                             if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
153                                   screen[xtmp][ytmp]=tmp+1;
154                             if (xtmp==i && ytmp==j) goto out;
155                             }
156
157 out:  if (tmp<distance) /* did find connectivity */
158                 /* now select lowest value around playerx,playery */
159                 for (z=1; z<9; z++) /* go around in a circle */
160                   if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
161                         if (!mitem[xl][yl]) { mmove(i,j,w1x[0]=xl,w1y[0]=yl); return; }
162           }
163
164         /* dumb monsters move here */
165         xl=i-1;  yl=j-1;  xh=i+2;  yh=j+2;
166         if (i<playerx) xl++; else if (i>playerx) --xh;
167         if (j<playery) yl++; else if (j>playery) --yh;
168         for (k=0; k<9; k++) w1[k] = 10000;
169
170         for (k=xl; k<xh; k++)
171                 for (m=yl; m<yh; m++) /* for each square compute distance to player */
172                         {
173                         tmp = k-i+4+3*(m-j);
174                         tmpitem = item[k][m];
175                         if (tmpitem!=OWALL || (k==playerx && m==playery))
176                          if (mitem[k][m]==0)
177                           if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
178                                  if (tmpitem!=OCLOSEDDOOR)
179                                         {
180                                         w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
181                                         w1x[tmp] = k;  w1y[tmp] = m;
182                                         }
183                         }
184
185         tmp = 0;
186         for (k=1; k<9; k++)  if (w1[tmp] > w1[k])  tmp=k;
187
188         if (w1[tmp] < 10000)
189                 if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
190                         mmove(i,j,w1x[tmp],w1y[tmp]);
191         }
192
193 /*
194  *      mmove(x,y,xd,yd)        Function to actually perform the monster movement
195  *              int x,y,xd,yd;
196  *
197  *      Enter with the from coordinates in (x,y) and the destination coordinates
198  *      in (xd,yd).
199  */
200 static void
201 mmove(int aa, int bb, int cc, int dd)
202         {
203         int tmp,i,flag;
204         const char *who = NULL, *p;
205         flag=0; /* set to 1 if monster hit by arrow trap */
206         if ((cc==playerx) && (dd==playery))
207                 {
208                 hitplayer(aa,bb);  moved[aa][bb] = 1;  return;
209                 }
210         i=item[cc][dd];
211         if ((i==OPIT) || (i==OTRAPDOOR))
212           switch(mitem[aa][bb])
213                 {
214                 case SPIRITNAGA:        case PLATINUMDRAGON:    case WRAITH:
215                 case VAMPIRE:           case SILVERDRAGON:              case POLTERGEIST:
216                 case DEMONLORD:         case DEMONLORD+1:               case DEMONLORD+2:
217                 case DEMONLORD+3:       case DEMONLORD+4:               case DEMONLORD+5:
218                 case DEMONLORD+6:       case DEMONPRINCE:       break;
219
220                 default:        mitem[aa][bb]=0; /* fell in a pit or trapdoor */
221                 };
222         tmp = mitem[cc][dd] = mitem[aa][bb];
223         if (i==OANNIHILATION)
224                 {
225                 if (tmp>=DEMONLORD+3) /* demons dispel spheres */
226                         {
227                         cursors();
228                         lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
229                         rmsphere(cc,dd);        /* delete the sphere */
230                         }
231                 else i=tmp=mitem[cc][dd]=0;
232                 }
233         stealth[cc][dd]=1;
234         if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
235         mitem[aa][bb] = 0;                              moved[cc][dd] = 1;
236         if (tmp == LEPRECHAUN)
237                 switch(i)
238                         {
239                         case OGOLDPILE:  case OMAXGOLD:  case OKGOLD:  case ODGOLD:
240                         case ODIAMOND:   case ORUBY:     case OEMERALD: case OSAPPHIRE:
241                                         item[cc][dd] = 0; /* leprechaun takes gold */
242                         };
243
244         if (tmp == TROLL)  /* if a troll regenerate him */
245                 if ((gtime & 1) == 0)
246                         if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;
247
248         if (i==OTRAPARROW)      /* arrow hits monster */
249                 { who = "An arrow";  if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
250                         { mitem[cc][dd]=0;  flag=2; } else flag=1; }
251         if (i==ODARTRAP)        /* dart hits monster */
252                 { who = "A dart";  if ((hitp[cc][dd] -= rnd(6)) <= 0)
253                         { mitem[cc][dd]=0;  flag=2; } else flag=1; }
254         if (i==OTELEPORTER)     /* monster hits teleport trap */
255                 { flag=3; fillmonst(mitem[cc][dd]);  mitem[cc][dd]=0; }
256         if (c[BLINDCOUNT]) return;      /* if blind don't show where monsters are       */
257         if (know[cc][dd] & 1)
258                 {
259                 p=0;
260                 if (flag) cursors();
261                 switch(flag)
262                   {
263                   case 1: p="\n%s hits the %s";  break;
264                   case 2: p="\n%s hits and kills the %s";  break;
265                   case 3: p="\nThe %s%s gets teleported"; who="";  break;
266                   };
267                 if (p) { lprintf(p,who,monster[tmp].name); beep(); }
268                 }
269         if (know[aa][bb] & 1)   show1cell(aa,bb);
270         if (know[cc][dd] & 1)   show1cell(cc,dd);
271         }
272
273 /*
274  *      movsphere()     Function to look for and move spheres of annihilation
275  *
276  *      This function works on the sphere linked list, first duplicating the list
277  *      (the act of moving changes the list), then processing each sphere in order
278  *      to move it.  They eat anything in their way, including stairs, volcanic
279  *      shafts, potions, etc, except for upper level demons, who can dispel
280  *      spheres.
281  *      No value is returned.
282  */
283 #define SPHMAX 20       /* maximum number of spheres movsphere can handle */
284 static void
285 movsphere(void)
286         {
287         int x,y,dir,len;
288         struct sphere *sp,*sp2;
289         struct sphere sph[SPHMAX];
290
291         /* first duplicate sphere list */
292         for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p)     /* look through sphere list */
293           if (sp2->lev == level)        /* only if this level */
294                 {
295                 sph[x] = *sp2;  sph[x++].p = 0;  /* copy the struct */
296                 if (x>1)  sph[x-2].p = &sph[x-1]; /* link pointers */
297                 }
298         if (x) sp= sph; /* if any spheres, point to them */
299                 else return;    /* no spheres */
300
301         for (sp=sph; sp; sp=sp->p)      /* look through sphere list */
302                 {
303                 x = sp->x;        y = sp->y;
304                 if (item[x][y]!=OANNIHILATION) continue;        /* not really there */
305                 if (--(sp->lifetime) < 0)       /* has sphere run out of gas? */
306                         {
307                         rmsphere(x,y); /* delete sphere */
308                         continue;
309                         }
310                 switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) /* time to move the sphere */
311                         {
312                         case 1:
313                         case 2:         /* change direction to a random one */
314                                                 sp->dir = rnd(8);
315                         default:        /* move in normal direction */
316                                                 dir = sp->dir;          len = sp->lifetime;
317                                                 rmsphere(x,y);
318                                                 newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
319                         };
320                 }
321         }