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