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