1 /**
2  * @file missiles.cpp
3  *
4  * Implementation of missile functionality.
5  */
6 #include "all.h"
7 
8 DEVILUTION_BEGIN_NAMESPACE
9 
10 int missileactive[MAXMISSILES];
11 int missileavail[MAXMISSILES];
12 MissileStruct missile[MAXMISSILES];
13 int nummissiles;
14 bool ManashieldFlag;
15 ChainStruct chain[MAXMISSILES];
16 bool MissilePreFlag;
17 int numchains;
18 
19 /** Maps from direction to X-offset. */
20 const int XDirAdd[8] = { 1, 0, -1, -1, -1, 0, 1, 1 };
21 /** Maps from direction to Y-offset. */
22 const int YDirAdd[8] = { 1, 1, 1, 0, -1, -1, -1, 0 };
23 const int CrawlNum[19] = { 0, 3, 12, 45, 94, 159, 240, 337, 450, 579, 724, 885, 1062, 1255, 1464, 1689, 1930, 2187, 2460 };
24 
GetDamageAmt(int i,int * mind,int * maxd)25 void GetDamageAmt(int i, int *mind, int *maxd)
26 {
27 	int k, sl;
28 
29 	assert(myplr >= 0 && myplr < MAX_PLRS);
30 	assert(i >= 0 && i < 64);
31 	sl = plr[myplr]._pSplLvl[i] + plr[myplr]._pISplLvlAdd;
32 
33 	switch (i) {
34 	case SPL_FIREBOLT:
35 		*mind = (plr[myplr]._pMagic >> 3) + sl + 1;
36 		*maxd = (plr[myplr]._pMagic >> 3) + sl + 10;
37 		break;
38 	case SPL_HEAL: /// BUGFIX: healing calculation is unused
39 		*mind = plr[myplr]._pLevel + sl + 1;
40 		if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) {
41 			*mind <<= 1;
42 		} else if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) {
43 			*mind += *mind >> 1;
44 		}
45 		*maxd = 10;
46 		for (k = 0; k < plr[myplr]._pLevel; k++) {
47 			*maxd += 4;
48 		}
49 		for (k = 0; k < sl; k++) {
50 			*maxd += 6;
51 		}
52 		if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) {
53 			*maxd <<= 1;
54 		} else if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) {
55 			*maxd += *maxd >> 1;
56 		}
57 		*mind = -1;
58 		*maxd = -1;
59 		break;
60 	case SPL_LIGHTNING:
61 	case SPL_RUNELIGHT:
62 		*mind = 2;
63 		*maxd = plr[myplr]._pLevel + 2;
64 		break;
65 	case SPL_FLASH:
66 		*mind = plr[myplr]._pLevel;
67 		for (k = 0; k < sl; k++) {
68 			*mind += *mind >> 3;
69 		}
70 		*mind += *mind >> 1;
71 		*maxd = *mind * 2;
72 		break;
73 	case SPL_IDENTIFY:
74 	case SPL_TOWN:
75 	case SPL_STONE:
76 	case SPL_INFRA:
77 	case SPL_RNDTELEPORT:
78 	case SPL_MANASHIELD:
79 	case SPL_DOOMSERP:
80 	case SPL_BLODRIT:
81 	case SPL_INVISIBIL:
82 	case SPL_BLODBOIL:
83 	case SPL_TELEPORT:
84 	case SPL_ETHEREALIZE:
85 	case SPL_REPAIR:
86 	case SPL_RECHARGE:
87 	case SPL_DISARM:
88 	case SPL_RESURRECT:
89 	case SPL_TELEKINESIS:
90 	case SPL_BONESPIRIT:
91 	case SPL_WARP:
92 	case SPL_REFLECT:
93 	case SPL_BERSERK:
94 	case SPL_SEARCH:
95 	case SPL_RUNESTONE:
96 		*mind = -1;
97 		*maxd = -1;
98 		break;
99 	case SPL_FIREWALL:
100 	case SPL_LIGHTWALL:
101 	case SPL_FIRERING:
102 		*mind = 2 * plr[myplr]._pLevel + 4;
103 		*maxd = 2 * plr[myplr]._pLevel + 40;
104 		break;
105 	case SPL_FIREBALL:
106 	case SPL_RUNEFIRE:
107 		*mind = 2 * plr[myplr]._pLevel + 4;
108 		for (k = 0; k < sl; k++) {
109 			*mind += *mind >> 3;
110 		}
111 		*maxd = 2 * plr[myplr]._pLevel + 40;
112 		for (k = 0; k < sl; k++) {
113 			*maxd += *maxd >> 3;
114 		}
115 		break;
116 	case SPL_GUARDIAN:
117 		*mind = (plr[myplr]._pLevel >> 1) + 1;
118 		for (k = 0; k < sl; k++) {
119 			*mind += *mind >> 3;
120 		}
121 		*maxd = (plr[myplr]._pLevel >> 1) + 10;
122 		for (k = 0; k < sl; k++) {
123 			*maxd += *maxd >> 3;
124 		}
125 		break;
126 	case SPL_CHAIN:
127 		*mind = 4;
128 		*maxd = 2 * plr[myplr]._pLevel + 4;
129 		break;
130 	case SPL_WAVE:
131 		*mind = 6 * (plr[myplr]._pLevel + 1);
132 		*maxd = 6 * (plr[myplr]._pLevel + 10);
133 		break;
134 	case SPL_NOVA:
135 	case SPL_IMMOLAT:
136 	case SPL_RUNEIMMOLAT:
137 	case SPL_RUNENOVA:
138 		*mind = (plr[myplr]._pLevel + 5) >> 1;
139 		for (k = 0; k < sl; k++) {
140 			*mind += *mind >> 3;
141 		}
142 		*mind *= 5;
143 		*maxd = (plr[myplr]._pLevel + 30) >> 1;
144 		for (k = 0; k < sl; k++) {
145 			*maxd += *maxd >> 3;
146 		}
147 		*maxd *= 5;
148 		break;
149 	case SPL_FLAME:
150 		*mind = 3;
151 		*maxd = plr[myplr]._pLevel + 4;
152 		*maxd += *maxd >> 1;
153 		break;
154 	case SPL_GOLEM:
155 		*mind = 11;
156 		*maxd = 17;
157 		break;
158 	case SPL_APOCA:
159 		*mind = 0;
160 		for (k = 0; k < plr[myplr]._pLevel; k++) {
161 			*mind += 1;
162 		}
163 		*maxd = 0;
164 		for (k = 0; k < plr[myplr]._pLevel; k++) {
165 			*maxd += 6;
166 		}
167 		break;
168 	case SPL_ELEMENT:
169 		*mind = 2 * plr[myplr]._pLevel + 4;
170 		for (k = 0; k < sl; k++) {
171 			*mind += *mind >> 3;
172 		}
173 		/// BUGFIX: add here '*mind >>= 1;'
174 		*maxd = 2 * plr[myplr]._pLevel + 40;
175 		for (k = 0; k < sl; k++) {
176 			*maxd += *maxd >> 3;
177 		}
178 		/// BUGFIX: add here '*maxd >>= 1;'
179 		break;
180 	case SPL_CBOLT:
181 		*mind = 1;
182 		*maxd = (plr[myplr]._pMagic >> 2) + 1;
183 		break;
184 	case SPL_HBOLT:
185 		*mind = plr[myplr]._pLevel + 9;
186 		*maxd = plr[myplr]._pLevel + 18;
187 		break;
188 	case SPL_HEALOTHER: /// BUGFIX: healing calculation is unused
189 		*mind = plr[myplr]._pLevel + sl + 1;
190 		if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) {
191 			*mind <<= 1;
192 		}
193 		if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) {
194 			*mind += *mind >> 1;
195 		}
196 		*maxd = 10;
197 		for (k = 0; k < plr[myplr]._pLevel; k++) {
198 			*maxd += 4;
199 		}
200 		for (k = 0; k < sl; k++) {
201 			*maxd += 6;
202 		}
203 		if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) {
204 			*maxd <<= 1;
205 		}
206 		if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) {
207 			*maxd += *maxd >> 1;
208 		}
209 		*mind = -1;
210 		*maxd = -1;
211 		break;
212 	case SPL_FLARE:
213 		*mind = (plr[myplr]._pMagic >> 1) + 3 * sl - (plr[myplr]._pMagic >> 3);
214 		*maxd = *mind;
215 		break;
216 	}
217 }
218 
CheckBlock(int fx,int fy,int tx,int ty)219 BOOL CheckBlock(int fx, int fy, int tx, int ty)
220 {
221 	int pn;
222 	BOOL coll;
223 
224 	coll = FALSE;
225 	while (fx != tx || fy != ty) {
226 		pn = GetDirection(fx, fy, tx, ty);
227 		fx += XDirAdd[pn];
228 		fy += YDirAdd[pn];
229 		if (nSolidTable[dPiece[fx][fy]])
230 			coll = TRUE;
231 	}
232 
233 	return coll;
234 }
235 
FindClosest(int sx,int sy,int rad)236 int FindClosest(int sx, int sy, int rad)
237 {
238 	int j, i, mid, tx, ty, cr;
239 
240 	if (rad > 19)
241 		rad = 19;
242 
243 	for (i = 1; i < rad; i++) {
244 		cr = CrawlNum[i] + 2;
245 		for (j = (BYTE)CrawlTable[CrawlNum[i]]; j > 0; j--) {
246 			tx = sx + CrawlTable[cr - 1];
247 			ty = sy + CrawlTable[cr];
248 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
249 				mid = dMonster[tx][ty];
250 				if (mid > 0 && !CheckBlock(sx, sy, tx, ty))
251 					return mid - 1;
252 			}
253 			cr += 2;
254 		}
255 	}
256 	return -1;
257 }
258 
GetSpellLevel(int id,int sn)259 int GetSpellLevel(int id, int sn)
260 {
261 	int result;
262 
263 	if (id == myplr)
264 		result = plr[id]._pISplLvlAdd + plr[id]._pSplLvl[sn];
265 	else
266 		result = 1;
267 
268 	if (result < 0)
269 		result = 0;
270 
271 	return result;
272 }
273 
274 /**
275  * @brief Returns the direction a vector from p1(x1, y1) to p2(x2, y2) is pointing to.
276  *
277  *      W    SW     S
278  *            ^
279  *            |
280  *     NW ----+---> SE
281  *            |
282  *            |
283  *      N    NE     E
284  *
285  * @param x1 the x coordinate of p1
286  * @param y1 the y coordinate of p1
287  * @param x2 the x coordinate of p2
288  * @param y2 the y coordinate of p2
289  * @return the direction of the p1->p2 vector
290 */
GetDirection8(int x1,int y1,int x2,int y2)291 int GetDirection8(int x1, int y1, int x2, int y2)
292 {
293 	int mx, my, md;
294 
295 	mx = x2 - x1;
296 	my = y2 - y1;
297 	if (mx >= 0) {
298 		if (my >= 0) {
299 			if (5 * mx <= (my << 1)) // mx/my <= 0.4, approximation of tan(22.5)
300 				return 1;            // DIR_SW
301 			md = 0;                  // DIR_S
302 		} else {
303 			my = -my;
304 			if (5 * mx <= (my << 1))
305 				return 5; // DIR_NE
306 			md = 6;       // DIR_E
307 		}
308 		if (5 * my <= (mx << 1)) // my/mx <= 0.4
309 			md = 7;              // DIR_SE
310 	} else {
311 		mx = -mx;
312 		if (my >= 0) {
313 			if (5 * mx <= (my << 1))
314 				return 1; // DIR_SW
315 			md = 2;       // DIR_W
316 		} else {
317 			my = -my;
318 			if (5 * mx <= (my << 1))
319 				return 5; // DIR_NE
320 			md = 4;       // DIR_N
321 		}
322 		if (5 * my <= (mx << 1))
323 			md = 3; // DIR_NW
324 	}
325 	return md;
326 }
327 
328 /**
329  * @brief Returns the direction a vector from p1(x1, y1) to p2(x2, y2) is pointing to.
330  *
331  *      W  sW  SW   Sw  S
332  *              ^
333  *     nW       |       Se
334  *              |
335  *     NW ------+-----> SE
336  *              |
337  *     Nw       |       sE
338  *              |
339  *      N  Ne  NE   nE  E
340  *
341  * @param x1 the x coordinate of p1
342  * @param y1 the y coordinate of p1
343  * @param x2 the x coordinate of p2
344  * @param y2 the y coordinate of p2
345  * @return the direction of the p1->p2 vector
346 */
GetDirection16(int x1,int y1,int x2,int y2)347 int GetDirection16(int x1, int y1, int x2, int y2)
348 {
349 	int mx, my, md;
350 
351 	mx = x2 - x1;
352 	my = y2 - y1;
353 	if (mx >= 0) {
354 		if (my >= 0) {
355 			if (3 * mx <= (my << 1)) { // mx/my <= 2/3, approximation of tan(33.75)
356 				if (5 * mx < my)       // mx/my < 0.2, approximation of tan(11.25)
357 					return 2;          // DIR_SW;
358 				return 1;              // DIR_Sw;
359 			}
360 			md = 0; // DIR_S;
361 		} else {
362 			my = -my;
363 			if (3 * mx <= (my << 1)) {
364 				if (5 * mx < my)
365 					return 10; // DIR_NE;
366 				return 11;     // DIR_nE;
367 			}
368 			md = 12; // DIR_E;
369 		}
370 		if (3 * my <= (mx << 1)) {    // my/mx <= 2/3
371 			if (5 * my < mx)          // my/mx < 0.2
372 				return 14;            // DIR_SE;
373 			return md == 0 ? 15 : 13; // DIR_S ? DIR_Se : DIR_sE;
374 		}
375 	} else {
376 		mx = -mx;
377 		if (my >= 0) {
378 			if (3 * mx <= (my << 1)) {
379 				if (5 * mx < my)
380 					return 2; // DIR_SW;
381 				return 3;     // DIR_sW;
382 			}
383 			md = 4; // DIR_W;
384 		} else {
385 			my = -my;
386 			if (3 * mx <= (my << 1)) {
387 				if (5 * mx < my)
388 					return 10; // DIR_NE;
389 				return 9;      // DIR_Ne;
390 			}
391 			md = 8; // DIR_N;
392 		}
393 		if (3 * my <= (mx << 1)) {
394 			if (5 * my < mx)
395 				return 6;           // DIR_NW;
396 			return md == 4 ? 5 : 7; // DIR_W ? DIR_nW : DIR_Nw;
397 		}
398 	}
399 	return md;
400 }
401 
DeleteMissile(int mi,int i)402 void DeleteMissile(int mi, int i)
403 {
404 	int src;
405 
406 	if (missile[mi]._mitype == MIS_MANASHIELD) {
407 		src = missile[mi]._misource;
408 		if (src == myplr)
409 			NetSendCmd(TRUE, CMD_REMSHIELD);
410 		plr[src].pManaShield = FALSE;
411 	}
412 
413 	missileavail[MAXMISSILES - nummissiles] = mi;
414 	nummissiles--;
415 	if (nummissiles > 0 && i != nummissiles)
416 		missileactive[i] = missileactive[nummissiles];
417 }
418 
GetMissileVel(int i,int sx,int sy,int dx,int dy,int v)419 void GetMissileVel(int i, int sx, int sy, int dx, int dy, int v)
420 {
421 	double dxp, dyp, dr;
422 
423 	if (dx != sx || dy != sy) {
424 		dxp = (dx + sy - sx - dy) * (1 << 21);
425 		dyp = (dy + dx - sx - sy) * (1 << 21);
426 		dr = sqrt(dxp * dxp + dyp * dyp);
427 		missile[i]._mixvel = (dxp * (v << 16)) / dr;
428 		missile[i]._miyvel = (dyp * (v << 15)) / dr;
429 	} else {
430 		missile[i]._mixvel = 0;
431 		missile[i]._miyvel = 0;
432 	}
433 }
434 
PutMissile(int i)435 void PutMissile(int i)
436 {
437 	int x, y;
438 
439 	x = missile[i]._mix;
440 	y = missile[i]._miy;
441 	if (x <= 0 || y <= 0 || x >= MAXDUNX || y >= MAXDUNY)
442 		missile[i]._miDelFlag = TRUE;
443 	if (!missile[i]._miDelFlag) {
444 		dFlags[x][y] |= BFLAG_MISSILE;
445 		if (dMissile[x][y] == 0)
446 			dMissile[x][y] = i + 1;
447 		else
448 			dMissile[x][y] = -1;
449 		if (missile[i]._miPreFlag)
450 			MissilePreFlag = true;
451 	}
452 }
453 
GetMissilePos(int i)454 void GetMissilePos(int i)
455 {
456 	int mx, my, dx, dy, lx, ly;
457 
458 	mx = missile[i]._mitxoff >> 16;
459 	my = missile[i]._mityoff >> 16;
460 	dx = mx + 2 * my;
461 	dy = 2 * my - mx;
462 	if (dx < 0) {
463 		lx = -(-dx / 8);
464 		dx = -(-dx / 64);
465 	} else {
466 		lx = dx / 8;
467 		dx = dx / 64;
468 	}
469 	if (dy < 0) {
470 		ly = -(-dy / 8);
471 		dy = -(-dy / 64);
472 	} else {
473 		ly = dy / 8;
474 		dy = dy / 64;
475 	}
476 	missile[i]._mix = dx + missile[i]._misx;
477 	missile[i]._miy = dy + missile[i]._misy;
478 	missile[i]._mixoff = mx + (dy * 32) - (dx * 32);
479 	missile[i]._miyoff = my - (dx * 16) - (dy * 16);
480 	ChangeLightOff(missile[i]._mlid, lx - (dx * 8), ly - (dy * 8));
481 }
482 
MoveMissilePos(int i)483 void MoveMissilePos(int i)
484 {
485 	int dx, dy, x, y;
486 
487 	switch (missile[i]._mimfnum) {
488 	case DIR_S:
489 		dx = 1;
490 		dy = 1;
491 		break;
492 	case DIR_SW:
493 		dx = 1;
494 		dy = 1;
495 		break;
496 	case DIR_W:
497 		dx = 0;
498 		dy = 1;
499 		break;
500 	case DIR_NW:
501 		dx = 0;
502 		dy = 0;
503 		break;
504 	case DIR_N:
505 		dx = 0;
506 		dy = 0;
507 		break;
508 	case DIR_NE:
509 		dx = 0;
510 		dy = 0;
511 		break;
512 	case DIR_E:
513 		dx = 1;
514 		dy = 0;
515 		break;
516 	case DIR_SE:
517 		dx = 1;
518 		dy = 1;
519 		break;
520 	}
521 	x = missile[i]._mix + dx;
522 	y = missile[i]._miy + dy;
523 	if (PosOkMonst(missile[i]._misource, x, y)) {
524 		missile[i]._mix += dx;
525 		missile[i]._miy += dy;
526 		missile[i]._mixoff += (dy << 5) - (dx << 5);
527 		missile[i]._miyoff -= (dy << 4) + (dx << 4);
528 	}
529 }
530 
MonsterTrapHit(int m,int mindam,int maxdam,int dist,int t,BOOLEAN shift)531 BOOL MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, BOOLEAN shift)
532 {
533 	int hit, hper, dam, mor, mir;
534 	BOOL resist, ret;
535 
536 	resist = FALSE;
537 	if (monster[m].mtalkmsg) {
538 		return FALSE;
539 	}
540 	if (monster[m]._mhitpoints >> 6 <= 0) {
541 		return FALSE;
542 	}
543 	if (monster[m].MType->mtype == MT_ILLWEAV && monster[m]._mgoal == MGOAL_RETREAT)
544 		return FALSE;
545 	if (monster[m]._mmode == MM_CHARGE)
546 		return FALSE;
547 
548 	mir = missiledata[t].mResist;
549 	mor = monster[m].mMagicRes;
550 	if (mor & IMMUNE_MAGIC && mir == MISR_MAGIC
551 	    || mor & IMMUNE_FIRE && mir == MISR_FIRE
552 	    || mor & IMMUNE_LIGHTNING && mir == MISR_LIGHTNING) {
553 		return FALSE;
554 	}
555 
556 	if ((mor & RESIST_MAGIC && mir == MISR_MAGIC)
557 	    || (mor & RESIST_FIRE && mir == MISR_FIRE)
558 	    || (mor & RESIST_LIGHTNING && mir == MISR_LIGHTNING)) {
559 		resist = TRUE;
560 	}
561 
562 	hit = random_(68, 100);
563 	hper = 90 - (BYTE)monster[m].mArmorClass - dist;
564 	if (hper < 5)
565 		hper = 5;
566 	if (hper > 95)
567 		hper = 95;
568 	if (CheckMonsterHit(m, &ret)) {
569 		return ret;
570 	}
571 #ifdef _DEBUG
572 	else if (hit < hper || debug_mode_dollar_sign || debug_mode_key_inverted_v || monster[m]._mmode == MM_STONE) {
573 #else
574 	else if (hit < hper || monster[m]._mmode == MM_STONE) {
575 #endif
576 		dam = mindam + random_(68, maxdam - mindam + 1);
577 		if (!shift)
578 			dam <<= 6;
579 		if (resist)
580 			monster[m]._mhitpoints -= dam >> 2;
581 		else
582 			monster[m]._mhitpoints -= dam;
583 #ifdef _DEBUG
584 		if (debug_mode_dollar_sign || debug_mode_key_inverted_v)
585 			monster[m]._mhitpoints = 0;
586 #endif
587 		if (monster[m]._mhitpoints >> 6 <= 0) {
588 			if (monster[m]._mmode == MM_STONE) {
589 				M_StartKill(m, -1);
590 				monster[m]._mmode = MM_STONE;
591 			} else {
592 				M_StartKill(m, -1);
593 			}
594 		} else {
595 			if (resist) {
596 				PlayEffect(m, 1);
597 			} else if (monster[m]._mmode == MM_STONE) {
598 				if (m > MAX_PLRS - 1)
599 					M_StartHit(m, -1, dam);
600 				monster[m]._mmode = MM_STONE;
601 			} else {
602 				if (m > MAX_PLRS - 1)
603 					M_StartHit(m, -1, dam);
604 			}
605 		}
606 		return TRUE;
607 	} else {
608 		return FALSE;
609 	}
610 }
611 
612 BOOL MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, BOOLEAN shift)
613 {
614 	int hit, hper, dam, mor, mir;
615 	BOOL resist, ret;
616 
617 	resist = FALSE;
618 	if (monster[m].mtalkmsg
619 	    || monster[m]._mhitpoints >> 6 <= 0
620 	    || t == MIS_HBOLT && monster[m].MType->mtype != MT_DIABLO && monster[m].MData->mMonstClass != MC_UNDEAD) {
621 		return FALSE;
622 	}
623 	if (monster[m].MType->mtype == MT_ILLWEAV && monster[m]._mgoal == MGOAL_RETREAT)
624 		return FALSE;
625 	if (monster[m]._mmode == MM_CHARGE)
626 		return FALSE;
627 
628 	mor = monster[m].mMagicRes;
629 	mir = missiledata[t].mResist;
630 
631 	if (mor & IMMUNE_MAGIC && mir == MISR_MAGIC
632 	    || mor & IMMUNE_FIRE && mir == MISR_FIRE
633 	    || mor & IMMUNE_LIGHTNING && mir == MISR_LIGHTNING
634 	    || (mor & IMMUNE_ACID) && mir == MISR_ACID)
635 		return FALSE;
636 
637 	if (mor & RESIST_MAGIC && mir == MISR_MAGIC
638 	    || mor & RESIST_FIRE && mir == MISR_FIRE
639 	    || mor & RESIST_LIGHTNING && mir == MISR_LIGHTNING)
640 		resist = TRUE;
641 
642 	if (gbIsHellfire && t == MIS_HBOLT && (monster[m].MType->mtype == MT_DIABLO || monster[m].MType->mtype == MT_BONEDEMN))
643 		resist = TRUE;
644 
645 	hit = random_(69, 100);
646 	if (pnum != -1) {
647 		if (missiledata[t].mType == 0) {
648 			hper = plr[pnum]._pDexterity;
649 			hper += plr[pnum]._pIBonusToHit;
650 			hper += plr[pnum]._pLevel;
651 			hper -= monster[m].mArmorClass;
652 			hper -= (dist * dist) >> 1;
653 			hper += plr[pnum]._pIEnAc;
654 			hper += 50;
655 			if (plr[pnum]._pClass == PC_ROGUE)
656 				hper += 20;
657 			if (plr[pnum]._pClass == PC_WARRIOR || plr[pnum]._pClass == PC_BARD)
658 				hper += 10;
659 		} else {
660 			hper = plr[pnum]._pMagic - (monster[m].mLevel << 1) - dist + 50;
661 			if (plr[pnum]._pClass == PC_SORCERER)
662 				hper += 20;
663 			else if (plr[pnum]._pClass == PC_BARD)
664 				hper += 10;
665 		}
666 	} else {
667 		hper = random_(71, 75) - monster[m].mLevel * 2;
668 	}
669 
670 	if (hper < 5)
671 		hper = 5;
672 	if (hper > 95)
673 		hper = 95;
674 	if (monster[m]._mmode == MM_STONE)
675 		hit = 0;
676 	if (CheckMonsterHit(m, &ret))
677 		return ret;
678 #ifdef _DEBUG
679 	if (hit < hper || debug_mode_key_inverted_v || debug_mode_dollar_sign) {
680 #else
681 	if (hit < hper) {
682 #endif
683 		if (t == MIS_BONESPIRIT) {
684 			dam = monster[m]._mhitpoints / 3 >> 6;
685 		} else {
686 			dam = mindam + random_(70, maxdam - mindam + 1);
687 		}
688 		if (missiledata[t].mType == 0) {
689 			dam = plr[pnum]._pIBonusDamMod + dam * plr[pnum]._pIBonusDam / 100 + dam;
690 			if (plr[pnum]._pClass == PC_ROGUE)
691 				dam += plr[pnum]._pDamageMod;
692 			else
693 				dam += (plr[pnum]._pDamageMod >> 1);
694 		}
695 		if (!shift)
696 			dam <<= 6;
697 		if (resist)
698 			dam >>= 2;
699 		if (pnum == myplr)
700 			monster[m]._mhitpoints -= dam;
701 		if ((gbIsHellfire && plr[pnum]._pIFlags & ISPL_NOHEALMON) || (!gbIsHellfire && plr[pnum]._pIFlags & ISPL_FIRE_ARROWS))
702 			monster[m]._mFlags |= MFLAG_NOHEAL;
703 
704 		if (monster[m]._mhitpoints >> 6 <= 0) {
705 			if (monster[m]._mmode == MM_STONE) {
706 				M_StartKill(m, pnum);
707 				monster[m]._mmode = MM_STONE;
708 			} else {
709 				M_StartKill(m, pnum);
710 			}
711 		} else {
712 			if (resist) {
713 				PlayEffect(m, 1);
714 			} else if (monster[m]._mmode == MM_STONE) {
715 				if (m > MAX_PLRS - 1)
716 					M_StartHit(m, pnum, dam);
717 				monster[m]._mmode = MM_STONE;
718 			} else {
719 				if (missiledata[t].mType == 0 && plr[pnum]._pIFlags & ISPL_KNOCKBACK) {
720 					M_GetKnockback(m);
721 				}
722 				if (m > MAX_PLRS - 1)
723 					M_StartHit(m, pnum, dam);
724 			}
725 		}
726 
727 		if (monster[m]._msquelch == 0) {
728 			monster[m]._msquelch = UCHAR_MAX;
729 			monster[m]._lastx = plr[pnum]._px;
730 			monster[m]._lasty = plr[pnum]._py;
731 		}
732 		return TRUE;
733 	}
734 
735 	return FALSE;
736 }
737 
738 BOOL PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, BOOLEAN shift, int earflag, BOOLEAN *blocked)
739 {
740 	int hit, hper, tac, dam, blk, blkper, resper;
741 	*blocked = false;
742 
743 	if (plr[pnum]._pHitPoints >> 6 <= 0) {
744 		return FALSE;
745 	}
746 
747 	if (plr[pnum]._pInvincible) {
748 		return FALSE;
749 	}
750 
751 	if (plr[pnum]._pSpellFlags & 1 && missiledata[mtype].mType == 0) {
752 		return FALSE;
753 	}
754 
755 	hit = random_(72, 100);
756 #ifdef _DEBUG
757 	if (debug_mode_dollar_sign || debug_mode_key_inverted_v)
758 		hit = 1000;
759 #endif
760 	if (missiledata[mtype].mType == 0) {
761 		tac = plr[pnum]._pIAC + plr[pnum]._pIBonusAC + plr[pnum]._pDexterity / 5;
762 		if (m != -1) {
763 			hper = monster[m].mHit
764 			    + ((monster[m].mLevel - plr[pnum]._pLevel) * 2)
765 			    + 30
766 			    - (dist << 1) - tac;
767 		} else {
768 			hper = 100 - (tac >> 1) - (dist << 1);
769 		}
770 	} else {
771 		if (m != -1) {
772 			hper = +40 - (plr[pnum]._pLevel << 1) - (dist << 1) + (monster[m].mLevel << 1);
773 		} else {
774 			hper = 40;
775 		}
776 	}
777 
778 	if (hper < 10)
779 		hper = 10;
780 	if (currlevel == 14 && hper < 20) {
781 		hper = 20;
782 	}
783 	if (currlevel == 15 && hper < 25) {
784 		hper = 25;
785 	}
786 	if (currlevel == 16 && hper < 30) {
787 		hper = 30;
788 	}
789 
790 	if ((plr[pnum]._pmode == PM_STAND || plr[pnum]._pmode == PM_ATTACK) && plr[pnum]._pBlockFlag) {
791 		blk = random_(73, 100);
792 	} else {
793 		blk = 100;
794 	}
795 
796 	if (shift == TRUE)
797 		blk = 100;
798 	if (mtype == MIS_ACIDPUD)
799 		blk = 100;
800 	if (m != -1)
801 		blkper = plr[pnum]._pBaseToBlk + plr[pnum]._pDexterity - ((monster[m].mLevel - plr[pnum]._pLevel) * 2);
802 	else
803 		blkper = plr[pnum]._pBaseToBlk + plr[pnum]._pDexterity;
804 	if (blkper < 0)
805 		blkper = 0;
806 	if (blkper > 100)
807 		blkper = 100;
808 
809 	switch (missiledata[mtype].mResist) {
810 	case MISR_FIRE:
811 		resper = plr[pnum]._pFireResist;
812 		break;
813 	case MISR_LIGHTNING:
814 		resper = plr[pnum]._pLghtResist;
815 		break;
816 	case MISR_MAGIC:
817 	case MISR_ACID:
818 		resper = plr[pnum]._pMagResist;
819 		break;
820 	default:
821 		resper = 0;
822 		break;
823 	}
824 
825 	if (hit < hper) {
826 		if (mtype == MIS_BONESPIRIT) {
827 			dam = plr[pnum]._pHitPoints / 3;
828 		} else {
829 			if (shift == FALSE) {
830 
831 				dam = (mind << 6) + random_(75, (maxd - mind + 1) << 6);
832 				if (m == -1)
833 					if (plr[pnum]._pIFlags & ISPL_ABSHALFTRAP)
834 						dam >>= 1;
835 				dam += (plr[pnum]._pIGetHit * 64);
836 			} else {
837 				dam = mind + random_(75, maxd - mind + 1);
838 				if (m == -1)
839 					if (plr[pnum]._pIFlags & ISPL_ABSHALFTRAP)
840 						dam >>= 1;
841 				dam += plr[pnum]._pIGetHit;
842 			}
843 
844 			if (dam < 64)
845 				dam = 64;
846 		}
847 		if ((resper <= 0 || gbIsHellfire) && blk < blkper) {
848 			direction dir = plr[pnum]._pdir;
849 			if (m != -1) {
850 				dir = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[m]._mx, monster[m]._my);
851 			}
852 			*blocked = true;
853 			StartPlrBlock(pnum, dir);
854 			return TRUE;
855 		}
856 		if (resper > 0) {
857 
858 			dam = dam - dam * resper / 100;
859 			if (pnum == myplr) {
860 				plr[pnum]._pHitPoints -= dam;
861 				plr[pnum]._pHPBase -= dam;
862 			}
863 			if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) {
864 				plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
865 				plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
866 			}
867 
868 			if (plr[pnum]._pHitPoints >> 6 <= 0) {
869 				SyncPlrKill(pnum, earflag);
870 			} else {
871 				if (plr[pnum]._pClass == PC_WARRIOR) {
872 					PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);
873 				} else if (plr[pnum]._pClass == PC_ROGUE) {
874 					PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);
875 				} else if (plr[pnum]._pClass == PC_SORCERER) {
876 					PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py);
877 				} else if (plr[pnum]._pClass == PC_MONK) {
878 					PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py);
879 				} else if (plr[pnum]._pClass == PC_BARD) {
880 					PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);
881 				} else if (plr[pnum]._pClass == PC_BARBARIAN) {
882 					PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);
883 				}
884 				drawhpflag = TRUE;
885 			}
886 			return TRUE;
887 		}
888 		if (pnum == myplr) {
889 			plr[pnum]._pHitPoints -= dam;
890 			plr[pnum]._pHPBase -= dam;
891 		}
892 		if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) {
893 			plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
894 			plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
895 		}
896 		if (plr[pnum]._pHitPoints >> 6 <= 0) {
897 			SyncPlrKill(pnum, earflag);
898 		} else {
899 			StartPlrHit(pnum, dam, FALSE);
900 		}
901 		return TRUE;
902 	}
903 	return FALSE;
904 }
905 
906 BOOL Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, BOOLEAN shift, BOOLEAN *blocked)
907 {
908 	int dam, blk, blkper, hper, hit, resper;
909 
910 	if (!gbFriendlyFire && gbFriendlyMode)
911 		return false;
912 
913 	*blocked = false;
914 
915 	if (plr[p]._pInvincible) {
916 		return FALSE;
917 	}
918 
919 	if (mtype == MIS_HBOLT) {
920 		return FALSE;
921 	}
922 
923 	if (plr[p]._pSpellFlags & 1 && missiledata[mtype].mType == 0) {
924 		return FALSE;
925 	}
926 
927 	switch (missiledata[mtype].mResist) {
928 	case MISR_FIRE:
929 		resper = plr[p]._pFireResist;
930 		break;
931 	case MISR_LIGHTNING:
932 		resper = plr[p]._pLghtResist;
933 		break;
934 	case MISR_MAGIC:
935 	case MISR_ACID:
936 		resper = plr[p]._pMagResist;
937 		break;
938 	default:
939 		resper = 0;
940 		break;
941 	}
942 	hper = random_(69, 100);
943 	if (missiledata[mtype].mType == 0) {
944 		hit = plr[pnum]._pIBonusToHit
945 		    + plr[pnum]._pLevel
946 		    - (dist * dist >> 1)
947 		    - plr[p]._pDexterity / 5
948 		    - plr[p]._pIBonusAC
949 		    - plr[p]._pIAC
950 		    + plr[pnum]._pDexterity + 50;
951 		if (plr[pnum]._pClass == PC_ROGUE)
952 			hit += 20;
953 		if (plr[pnum]._pClass == PC_WARRIOR || plr[pnum]._pClass == PC_BARD)
954 			hit += 10;
955 	} else {
956 		hit = plr[pnum]._pMagic
957 		    - (plr[p]._pLevel << 1)
958 		    - dist
959 		    + 50;
960 		if (plr[pnum]._pClass == PC_SORCERER)
961 			hit += 20;
962 		else if (plr[pnum]._pClass == PC_BARD)
963 			hit += 10;
964 	}
965 	if (hit < 5)
966 		hit = 5;
967 	if (hit > 95)
968 		hit = 95;
969 	if (hper < hit) {
970 		if ((plr[p]._pmode == PM_STAND || plr[p]._pmode == PM_ATTACK) && plr[p]._pBlockFlag) {
971 			blkper = random_(73, 100);
972 		} else {
973 			blkper = 100;
974 		}
975 		if (shift == TRUE)
976 			blkper = 100;
977 		blk = plr[p]._pDexterity + plr[p]._pBaseToBlk + (plr[p]._pLevel << 1) - (plr[pnum]._pLevel << 1);
978 
979 		if (blk < 0) {
980 			blk = 0;
981 		}
982 		if (blk > 100) {
983 			blk = 100;
984 		}
985 
986 		if (mtype == MIS_BONESPIRIT) {
987 			dam = plr[p]._pHitPoints / 3;
988 		} else {
989 			dam = mindam + random_(70, maxdam - mindam + 1);
990 			if (missiledata[mtype].mType == 0)
991 				dam += plr[pnum]._pIBonusDamMod + plr[pnum]._pDamageMod + dam * plr[pnum]._pIBonusDam / 100;
992 			if (!shift)
993 				dam <<= 6;
994 		}
995 		if (missiledata[mtype].mType != 0)
996 			dam >>= 1;
997 		if (resper > 0) {
998 			dam -= (dam * resper) / 100;
999 			if (pnum == myplr)
1000 				NetSendCmdDamage(TRUE, p, dam);
1001 			if (plr[pnum]._pClass == PC_WARRIOR) {
1002 				PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);
1003 			} else if (plr[pnum]._pClass == PC_ROGUE) {
1004 				PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);
1005 			} else if (plr[pnum]._pClass == PC_SORCERER) {
1006 				PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py);
1007 			} else if (plr[pnum]._pClass == PC_MONK) {
1008 				PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py);
1009 			} else if (plr[pnum]._pClass == PC_BARD) {
1010 				PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);
1011 			} else if (plr[pnum]._pClass == PC_BARBARIAN) {
1012 				PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);
1013 			}
1014 			return TRUE;
1015 		} else {
1016 			if (blkper < blk) {
1017 				StartPlrBlock(p, GetDirection(plr[p]._px, plr[p]._py, plr[pnum]._px, plr[pnum]._py));
1018 				*blocked = true;
1019 			} else {
1020 				if (pnum == myplr)
1021 					NetSendCmdDamage(TRUE, p, dam);
1022 				StartPlrHit(p, dam, FALSE);
1023 			}
1024 			return TRUE;
1025 		}
1026 	}
1027 	return FALSE;
1028 }
1029 
1030 void CheckMissileCol(int i, int mindam, int maxdam, BOOL shift, int mx, int my, BOOLEAN nodel)
1031 {
1032 	int oi;
1033 	BOOLEAN blocked;
1034 	int dir, mAnimFAmt;
1035 
1036 	if (i >= MAXMISSILES || i < 0)
1037 		return;
1038 	if (mx >= MAXDUNX || mx < 0)
1039 		return;
1040 	if (my >= MAXDUNY || my < 0)
1041 		return;
1042 	if (missile[i]._micaster != TARGET_BOTH && missile[i]._misource != -1) {
1043 		if (missile[i]._micaster == TARGET_MONSTERS) {
1044 			if (dMonster[mx][my] > 0) {
1045 				if (MonsterMHit(
1046 				        missile[i]._misource,
1047 				        dMonster[mx][my] - 1,
1048 				        mindam,
1049 				        maxdam,
1050 				        missile[i]._midist,
1051 				        missile[i]._mitype,
1052 				        shift)) {
1053 					if (!nodel)
1054 						missile[i]._mirange = 0;
1055 					missile[i]._miHitFlag = TRUE;
1056 				}
1057 			} else {
1058 				if (dMonster[mx][my] < 0
1059 				    && monster[-(dMonster[mx][my] + 1)]._mmode == MM_STONE
1060 				    && MonsterMHit(
1061 				        missile[i]._misource,
1062 				        -(dMonster[mx][my] + 1),
1063 				        mindam,
1064 				        maxdam,
1065 				        missile[i]._midist,
1066 				        missile[i]._mitype,
1067 				        shift)) {
1068 					if (!nodel)
1069 						missile[i]._mirange = 0;
1070 					missile[i]._miHitFlag = TRUE;
1071 				}
1072 			}
1073 			if (dPlayer[mx][my] > 0
1074 			    && dPlayer[mx][my] - 1 != missile[i]._misource
1075 			    && Plr2PlrMHit(
1076 			        missile[i]._misource,
1077 			        dPlayer[mx][my] - 1,
1078 			        mindam,
1079 			        maxdam,
1080 			        missile[i]._midist,
1081 			        missile[i]._mitype,
1082 			        shift,
1083 			        &blocked)) {
1084 				if (gbIsHellfire && blocked) {
1085 					dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1);
1086 					mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt;
1087 					if (dir < 0)
1088 						dir = mAnimFAmt - 1;
1089 					else if (dir > mAnimFAmt)
1090 						dir = 0;
1091 
1092 					SetMissDir(i, dir);
1093 				} else if (!nodel) {
1094 					missile[i]._mirange = 0;
1095 				}
1096 				missile[i]._miHitFlag = TRUE;
1097 			}
1098 		} else {
1099 			if (monster[missile[i]._misource]._mFlags & MFLAG_TARGETS_MONSTER
1100 			    && dMonster[mx][my] > 0
1101 			    && monster[dMonster[mx][my] - 1]._mFlags & MFLAG_GOLEM
1102 			    && MonsterTrapHit(dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) {
1103 				if (!nodel)
1104 					missile[i]._mirange = 0;
1105 				missile[i]._miHitFlag = TRUE;
1106 			}
1107 			if (dPlayer[mx][my] > 0
1108 			    && PlayerMHit(
1109 			        dPlayer[mx][my] - 1,
1110 			        missile[i]._misource,
1111 			        missile[i]._midist,
1112 			        mindam,
1113 			        maxdam,
1114 			        missile[i]._mitype,
1115 			        shift,
1116 			        0,
1117 			        &blocked)) {
1118 				if (gbIsHellfire && blocked) {
1119 					dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1);
1120 					mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt;
1121 					if (dir < 0)
1122 						dir = mAnimFAmt - 1;
1123 					else if (dir > mAnimFAmt)
1124 						dir = 0;
1125 
1126 					SetMissDir(i, dir);
1127 				} else if (!nodel) {
1128 					missile[i]._mirange = 0;
1129 				}
1130 				missile[i]._miHitFlag = TRUE;
1131 			}
1132 		}
1133 	} else {
1134 		if (dMonster[mx][my] > 0) {
1135 			if (missile[i]._micaster == TARGET_BOTH) {
1136 				if (MonsterMHit(
1137 				        missile[i]._misource,
1138 				        dMonster[mx][my] - 1,
1139 				        mindam,
1140 				        maxdam,
1141 				        missile[i]._midist,
1142 				        missile[i]._mitype,
1143 				        shift)) {
1144 					if (!nodel)
1145 						missile[i]._mirange = 0;
1146 					missile[i]._miHitFlag = TRUE;
1147 				}
1148 			} else if (MonsterTrapHit(dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) {
1149 				if (!nodel)
1150 					missile[i]._mirange = 0;
1151 				missile[i]._miHitFlag = TRUE;
1152 			}
1153 		}
1154 		if (dPlayer[mx][my] > 0) {
1155 			if (PlayerMHit(
1156 			        dPlayer[mx][my] - 1,
1157 			        -1,
1158 			        missile[i]._midist,
1159 			        mindam,
1160 			        maxdam,
1161 			        missile[i]._mitype,
1162 			        shift,
1163 			        missile[i]._miAnimType == MFILE_FIREWAL || missile[i]._miAnimType == MFILE_LGHNING,
1164 			        &blocked)) {
1165 				if (gbIsHellfire && blocked) {
1166 					dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1);
1167 					mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt;
1168 					if (dir < 0)
1169 						dir = mAnimFAmt - 1;
1170 					else if (dir > mAnimFAmt)
1171 						dir = 0;
1172 
1173 					SetMissDir(i, dir);
1174 				} else if (!nodel) {
1175 					missile[i]._mirange = 0;
1176 				}
1177 				missile[i]._miHitFlag = TRUE;
1178 			}
1179 		}
1180 	}
1181 	if (dObject[mx][my] != 0) {
1182 		oi = dObject[mx][my] > 0 ? dObject[mx][my] - 1 : -(dObject[mx][my] + 1);
1183 		if (!object[oi]._oMissFlag) {
1184 			if (object[oi]._oBreak == 1)
1185 				BreakObject(-1, oi);
1186 			if (!nodel)
1187 				missile[i]._mirange = 0;
1188 			missile[i]._miHitFlag = FALSE;
1189 		}
1190 	}
1191 	if (nMissileTable[dPiece[mx][my]]) {
1192 		if (!nodel)
1193 			missile[i]._mirange = 0;
1194 		missile[i]._miHitFlag = FALSE;
1195 	}
1196 	if (missile[i]._mirange == 0 && missiledata[missile[i]._mitype].miSFX != -1)
1197 		PlaySfxLoc(missiledata[missile[i]._mitype].miSFX, missile[i]._mix, missile[i]._miy);
1198 }
1199 
1200 void SetMissAnim(int mi, int animtype)
1201 {
1202 	int dir = missile[mi]._mimfnum;
1203 
1204 	if (animtype > MFILE_NONE) {
1205 		animtype = MFILE_NONE;
1206 	}
1207 
1208 	missile[mi]._miAnimType = animtype;
1209 	missile[mi]._miAnimFlags = misfiledata[animtype].mFlags;
1210 	missile[mi]._miAnimData = misfiledata[animtype].mAnimData[dir];
1211 	missile[mi]._miAnimDelay = misfiledata[animtype].mAnimDelay[dir];
1212 	missile[mi]._miAnimLen = misfiledata[animtype].mAnimLen[dir];
1213 	missile[mi]._miAnimWidth = misfiledata[animtype].mAnimWidth[dir];
1214 	missile[mi]._miAnimWidth2 = misfiledata[animtype].mAnimWidth2[dir];
1215 	missile[mi]._miAnimCnt = 0;
1216 	missile[mi]._miAnimFrame = 1;
1217 }
1218 
1219 void SetMissDir(int mi, int dir)
1220 {
1221 	missile[mi]._mimfnum = dir;
1222 	SetMissAnim(mi, missile[mi]._miAnimType);
1223 }
1224 
1225 void LoadMissileGFX(BYTE mi)
1226 {
1227 	char pszName[256];
1228 	int i;
1229 	BYTE *file;
1230 	MisFileData *mfd;
1231 
1232 	mfd = &misfiledata[mi];
1233 	if (mfd->mFlags & MFLAG_ALLOW_SPECIAL) {
1234 		sprintf(pszName, "Missiles\\%s.CL2", mfd->mName);
1235 		file = LoadFileInMem(pszName, NULL);
1236 		for (i = 0; i < mfd->mAnimFAmt; i++)
1237 			mfd->mAnimData[i] = CelGetFrameStart(file, i);
1238 	} else if (mfd->mAnimFAmt == 1) {
1239 		sprintf(pszName, "Missiles\\%s.CL2", mfd->mName);
1240 		if (!mfd->mAnimData[0])
1241 			mfd->mAnimData[0] = LoadFileInMem(pszName, NULL);
1242 	} else {
1243 		for (i = 0; i < mfd->mAnimFAmt; i++) {
1244 			sprintf(pszName, "Missiles\\%s%i.CL2", mfd->mName, i + 1);
1245 			if (!mfd->mAnimData[i]) {
1246 				file = LoadFileInMem(pszName, NULL);
1247 				mfd->mAnimData[i] = file;
1248 			}
1249 		}
1250 	}
1251 }
1252 
1253 void InitMissileGFX()
1254 {
1255 	int mi;
1256 
1257 	for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) {
1258 		if (!gbIsHellfire && mi > MFILE_SCBSEXPD)
1259 			break;
1260 		if (!(misfiledata[mi].mFlags & MFLAG_HIDDEN))
1261 			LoadMissileGFX(mi);
1262 	}
1263 }
1264 
1265 void FreeMissileGFX(int mi)
1266 {
1267 	int i;
1268 	DWORD *p;
1269 
1270 	if (misfiledata[mi].mFlags & MFLAG_ALLOW_SPECIAL) {
1271 		if (misfiledata[mi].mAnimData[0]) {
1272 			p = (DWORD *)misfiledata[mi].mAnimData[0];
1273 			p -= misfiledata[mi].mAnimFAmt;
1274 			MemFreeDbg(p);
1275 			misfiledata[mi].mAnimData[0] = NULL;
1276 		}
1277 		return;
1278 	}
1279 
1280 	for (i = 0; i < misfiledata[mi].mAnimFAmt; i++) {
1281 		if (misfiledata[mi].mAnimData[i]) {
1282 			MemFreeDbg(misfiledata[mi].mAnimData[i]);
1283 		}
1284 	}
1285 }
1286 
1287 void FreeMissiles()
1288 {
1289 	int mi;
1290 
1291 	for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) {
1292 		if (!(misfiledata[mi].mFlags & MFLAG_HIDDEN))
1293 			FreeMissileGFX(mi);
1294 	}
1295 }
1296 
1297 void FreeMissiles2()
1298 {
1299 	int mi;
1300 
1301 	for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) {
1302 		if (misfiledata[mi].mFlags & MFLAG_HIDDEN)
1303 			FreeMissileGFX(mi);
1304 	}
1305 }
1306 
1307 void InitMissiles()
1308 {
1309 	int mi, src, i, j;
1310 
1311 	AutoMapShowItems = FALSE;
1312 	plr[myplr]._pSpellFlags &= ~0x1;
1313 	if (plr[myplr]._pInfraFlag == TRUE) {
1314 		for (i = 0; i < nummissiles; ++i) {
1315 			mi = missileactive[i];
1316 			if (missile[mi]._mitype == MIS_INFRA) {
1317 				src = missile[mi]._misource;
1318 				if (src == myplr)
1319 					CalcPlrItemVals(src, TRUE);
1320 			}
1321 		}
1322 	}
1323 
1324 	if ((plr[myplr]._pSpellFlags & 2) == 2 || (plr[myplr]._pSpellFlags & 4) == 4) {
1325 		plr[myplr]._pSpellFlags &= ~0x2;
1326 		plr[myplr]._pSpellFlags &= ~0x4;
1327 		for (i = 0; i < nummissiles; ++i) {
1328 			mi = missileactive[i];
1329 			if (missile[mi]._mitype == MIS_BLODBOIL) {
1330 				if (missile[mi]._misource == myplr) {
1331 					int missingHP = plr[myplr]._pMaxHP - plr[myplr]._pHitPoints;
1332 					CalcPlrItemVals(myplr, TRUE);
1333 					plr[myplr]._pHitPoints -= missingHP + missile[mi]._miVar2;
1334 					if (plr[myplr]._pHitPoints < 64) {
1335 						plr[myplr]._pHitPoints = 64;
1336 					}
1337 				}
1338 			}
1339 		}
1340 	}
1341 
1342 	nummissiles = 0;
1343 	for (i = 0; i < MAXMISSILES; i++) {
1344 		missileavail[i] = i;
1345 		missileactive[i] = 0;
1346 	}
1347 	numchains = 0;
1348 	for (i = 0; i < MAXMISSILES; i++) {
1349 		chain[i].idx = -1;
1350 		chain[i]._mitype = 0;
1351 		chain[i]._mirange = 0;
1352 	}
1353 	for (j = 0; j < MAXDUNY; j++) {
1354 		for (i = 0; i < MAXDUNX; i++) {
1355 			dFlags[i][j] &= ~BFLAG_MISSILE;
1356 		}
1357 	}
1358 	plr[myplr].wReflections = 0;
1359 }
1360 
1361 void AddHiveExplosion(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1362 {
1363 	AddMissile(80, 62, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0);
1364 	AddMissile(80, 63, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0);
1365 	AddMissile(81, 62, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0);
1366 	AddMissile(81, 63, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0);
1367 	missile[mi]._miDelFlag = TRUE;
1368 }
1369 
1370 static bool missiles_found_target(Sint32 mi, Sint32 *x, Sint32 *y, Sint32 rad)
1371 {
1372 	int i, j, k, tx, ty, dp;
1373 
1374 	bool found = false;
1375 
1376 	if (rad > 19)
1377 		rad = 19;
1378 
1379 	for (j = 0; j < rad; j++) {
1380 		if (found) {
1381 			break;
1382 		}
1383 		k = CrawlNum[j] + 2;
1384 		for (i = CrawlTable[CrawlNum[j]]; i > 0; i--, k += 2) {
1385 			tx = *x + CrawlTable[k - 1];
1386 			ty = *y + CrawlTable[k];
1387 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
1388 				dp = dPiece[tx][ty];
1389 				if (!nSolidTable[dp] && dObject[tx][ty] == 0 && dMissile[tx][ty] == 0) {
1390 					missile[mi]._mix = tx;
1391 					missile[mi]._miy = ty;
1392 					*x = tx;
1393 					*y = ty;
1394 					found = true;
1395 					break;
1396 				}
1397 			}
1398 		}
1399 	}
1400 	return found;
1401 }
1402 
1403 void AddFireRune(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1404 {
1405 	if (LineClear(sx, sy, dx, dy)) {
1406 		if (id >= 0)
1407 			UseMana(id, SPL_RUNEFIRE);
1408 		if (missiles_found_target(mi, &dx, &dy, 10)) {
1409 			missile[mi]._miVar1 = MIS_HIVEEXP;
1410 			missile[mi]._miDelFlag = FALSE;
1411 			missile[mi]._mlid = AddLight(dx, dy, 8);
1412 		} else {
1413 			missile[mi]._miDelFlag = TRUE;
1414 		}
1415 	} else {
1416 		missile[mi]._miDelFlag = TRUE;
1417 	}
1418 }
1419 
1420 void AddLightningRune(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1421 {
1422 	if (LineClear(sx, sy, dx, dy)) {
1423 		if (id >= 0)
1424 			UseMana(id, SPL_RUNELIGHT);
1425 		if (missiles_found_target(mi, &dx, &dy, 10)) {
1426 			missile[mi]._miVar1 = MIS_LIGHTBALL;
1427 			missile[mi]._miDelFlag = FALSE;
1428 			missile[mi]._mlid = AddLight(dx, dy, 8);
1429 		} else {
1430 			missile[mi]._miDelFlag = TRUE;
1431 		}
1432 	} else {
1433 		missile[mi]._miDelFlag = TRUE;
1434 	}
1435 }
1436 
1437 void AddGreatLightningRune(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1438 {
1439 	if (LineClear(sx, sy, dx, dy)) {
1440 		if (id >= 0)
1441 			UseMana(id, SPL_RUNENOVA);
1442 		if (missiles_found_target(mi, &dx, &dy, 10)) {
1443 			missile[mi]._miVar1 = MIS_NOVA;
1444 			missile[mi]._miDelFlag = FALSE;
1445 			missile[mi]._mlid = AddLight(dx, dy, 8);
1446 		} else {
1447 			missile[mi]._miDelFlag = TRUE;
1448 		}
1449 	} else {
1450 		missile[mi]._miDelFlag = TRUE;
1451 	}
1452 }
1453 
1454 void AddImmolationRune(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1455 {
1456 	if (LineClear(sx, sy, dx, dy)) {
1457 		if (id >= 0)
1458 			UseMana(id, SPL_RUNEIMMOLAT);
1459 		if (missiles_found_target(mi, &dx, &dy, 10)) {
1460 			missile[mi]._miVar1 = MIS_IMMOLATION;
1461 			missile[mi]._miDelFlag = FALSE;
1462 			missile[mi]._mlid = AddLight(dx, dy, 8);
1463 		} else {
1464 			missile[mi]._miDelFlag = TRUE;
1465 		}
1466 	} else {
1467 		missile[mi]._miDelFlag = TRUE;
1468 	}
1469 }
1470 
1471 void AddStoneRune(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1472 {
1473 	if (LineClear(sx, sy, dx, dy)) {
1474 		if (id >= 0)
1475 			UseMana(id, SPL_RUNESTONE);
1476 		if (missiles_found_target(mi, &dx, &dy, 10)) {
1477 			missile[mi]._miVar1 = MIS_STONE;
1478 			missile[mi]._miDelFlag = FALSE;
1479 			missile[mi]._mlid = AddLight(dx, dy, 8);
1480 		} else {
1481 			missile[mi]._miDelFlag = TRUE;
1482 		}
1483 	} else {
1484 		missile[mi]._miDelFlag = TRUE;
1485 	}
1486 }
1487 
1488 void AddReflection(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1489 {
1490 	int lvl;
1491 
1492 	if (id >= 0) {
1493 		if (missile[mi]._mispllvl)
1494 			lvl = missile[mi]._mispllvl;
1495 		else
1496 			lvl = 2;
1497 		plr[id].wReflections += lvl * plr[id]._pLevel;
1498 		UseMana(id, SPL_REFLECT);
1499 	}
1500 	missile[mi]._mirange = 0;
1501 	missile[mi]._miDelFlag = 0;
1502 }
1503 
1504 void AddBerserk(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1505 {
1506 	int i, j, k, tx, ty, dm, r;
1507 
1508 	if (id >= 0) {
1509 		missile[mi]._misource = id;
1510 		for (j = 0; j < 6; j++) {
1511 			k = CrawlNum[j] + 2;
1512 			for (i = CrawlTable[CrawlNum[j]]; i > 0; i--, k += 2) {
1513 				tx = dx + CrawlTable[k - 1];
1514 				ty = dy + CrawlTable[k];
1515 				if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
1516 					dm = dMonster[tx][ty];
1517 					dm = dm > 0 ? dm - 1 : -(dm + 1);
1518 					if (dm > 3) {
1519 						if (monster[dm]._uniqtype == 0 && monster[dm]._mAi != AI_DIABLO) {
1520 							if (monster[dm]._mmode != MM_FADEIN && monster[dm]._mmode != MM_FADEOUT) {
1521 								if (!(monster[dm].mMagicRes & IMMUNE_MAGIC)) {
1522 									if ((!(monster[dm].mMagicRes & RESIST_MAGIC) || (monster[dm].mMagicRes & RESIST_MAGIC) == 1 && !random_(99, 2)) && monster[dm]._mmode != MM_CHARGE) {
1523 										j = 6;
1524 										double slvl = (double)GetSpellLevel(id, SPL_BERSERK);
1525 										monster[dm]._mFlags |= MFLAG_BERSERK | MFLAG_GOLEM;
1526 										monster[dm].mMinDamage = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMinDamage + slvl;
1527 										monster[dm].mMaxDamage = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMaxDamage + slvl;
1528 										monster[dm].mMinDamage2 = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMinDamage2 + slvl;
1529 										monster[dm].mMaxDamage2 = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMaxDamage2 + slvl;
1530 										if (currlevel < 17 || currlevel > 20)
1531 											r = 3;
1532 										else
1533 											r = 9;
1534 										monster[dm].mlid = AddLight(monster[dm]._mx, monster[dm]._my, r);
1535 										UseMana(id, SPL_BERSERK);
1536 										break;
1537 									}
1538 								}
1539 							}
1540 						}
1541 					}
1542 				}
1543 			}
1544 		}
1545 	}
1546 	missile[mi]._mirange = 0;
1547 	missile[mi]._miDelFlag = TRUE;
1548 }
1549 
1550 void AddHorkSpawn(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1551 {
1552 	GetMissileVel(mi, sx, sy, dx, dy, 8);
1553 	missile[mi]._mirange = 9;
1554 	missile[mi]._miVar1 = midir;
1555 	PutMissile(mi);
1556 }
1557 
1558 void AddJester(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1559 {
1560 	int spell;
1561 
1562 	spell = MIS_FIREBOLT;
1563 	switch (random_(255, 10)) {
1564 	case 0:
1565 	case 1:
1566 		spell = MIS_FIREBOLT;
1567 		break;
1568 	case 2:
1569 		spell = MIS_FIREBALL;
1570 		break;
1571 	case 3:
1572 		spell = MIS_FIREWALLC;
1573 		break;
1574 	case 4:
1575 		spell = MIS_GUARDIAN;
1576 		break;
1577 	case 5:
1578 		spell = MIS_CHAIN;
1579 		break;
1580 	case 6:
1581 		spell = MIS_TOWN;
1582 		UseMana(id, SPL_TOWN);
1583 		break;
1584 	case 7:
1585 		spell = MIS_TELEPORT;
1586 		break;
1587 	case 8:
1588 		spell = MIS_APOCA;
1589 		break;
1590 	case 9:
1591 		spell = MIS_STONE;
1592 		break;
1593 	}
1594 	AddMissile(sx, sy, dx, dy, midir, spell, missile[mi]._micaster, missile[mi]._misource, 0, missile[mi]._mispllvl);
1595 	missile[mi]._miDelFlag = TRUE;
1596 	missile[mi]._mirange = 0;
1597 }
1598 
1599 void AddStealPotions(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1600 {
1601 	int i, l, k, j, tx, ty, si, ii, pnum;
1602 	BOOL hasPlayedSFX;
1603 
1604 	missile[mi]._misource = id;
1605 	for (i = 0; i < 3; i++) {
1606 		k = CrawlNum[i];
1607 		l = k + 2;
1608 		for (j = CrawlTable[k]; j > 0; j--, l += 2) {
1609 			tx = sx + CrawlTable[l - 1];
1610 			ty = sy + CrawlTable[l];
1611 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
1612 				pnum = dPlayer[tx][ty];
1613 				if (pnum) {
1614 					pnum = pnum > 0 ? pnum - 1 : -(pnum + 1);
1615 
1616 					hasPlayedSFX = FALSE;
1617 					for (si = 0; si < MAXBELTITEMS; si++) {
1618 						ii = -1;
1619 						if (plr[pnum].SpdList[si]._itype == ITYPE_MISC) {
1620 							if (random_(205, 2) == 0)
1621 								continue;
1622 							switch (plr[pnum].SpdList[si]._iMiscId) {
1623 							case IMISC_FULLHEAL:
1624 								ii = ItemMiscIdIdx(IMISC_HEAL);
1625 								break;
1626 							case IMISC_HEAL:
1627 							case IMISC_MANA:
1628 								RemoveSpdBarItem(pnum, si);
1629 								continue;
1630 							case IMISC_FULLMANA:
1631 								ii = ItemMiscIdIdx(IMISC_MANA);
1632 								break;
1633 							case IMISC_REJUV:
1634 								if (random_(205, 2) != 0) {
1635 									ii = ItemMiscIdIdx(IMISC_MANA);
1636 								} else {
1637 									ii = ItemMiscIdIdx(IMISC_HEAL);
1638 								}
1639 								ii = ItemMiscIdIdx(IMISC_HEAL);
1640 								break;
1641 							case IMISC_FULLREJUV:
1642 								switch (random_(205, 3)) {
1643 								case 0:
1644 									ii = ItemMiscIdIdx(IMISC_FULLMANA);
1645 									break;
1646 								case 1:
1647 									ii = ItemMiscIdIdx(IMISC_FULLHEAL);
1648 									break;
1649 								default:
1650 									ii = ItemMiscIdIdx(IMISC_REJUV);
1651 									break;
1652 								}
1653 								break;
1654 							default:
1655 								continue;
1656 							}
1657 						}
1658 						if (ii != -1) {
1659 							SetPlrHandItem(&plr[pnum].HoldItem, ii);
1660 							GetPlrHandSeed(&plr[pnum].HoldItem);
1661 							plr[pnum].HoldItem._iStatFlag = TRUE;
1662 							plr[pnum].SpdList[si] = plr[pnum].HoldItem;
1663 						}
1664 						if (!hasPlayedSFX) {
1665 							PlaySfxLoc(IS_POPPOP2, tx, ty);
1666 							hasPlayedSFX = TRUE;
1667 						}
1668 					}
1669 					force_redraw = 255;
1670 				}
1671 			}
1672 		}
1673 	}
1674 	missile[mi]._mirange = 0;
1675 	missile[mi]._miDelFlag = TRUE;
1676 }
1677 
1678 void AddManaTrap(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1679 {
1680 	int i, pn, k, j, tx, ty, pid;
1681 
1682 	missile[mi]._misource = id;
1683 	for (i = 0; i < 3; i++) {
1684 		k = CrawlNum[i];
1685 		pn = k + 2;
1686 		for (j = CrawlTable[k]; j > 0; j--) {
1687 			tx = sx + CrawlTable[pn - 1];
1688 			ty = sy + CrawlTable[pn];
1689 			if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) {
1690 				pid = dPlayer[tx][ty];
1691 				if (pid != 0) {
1692 					if (pid > 0)
1693 						pid = pid - 1;
1694 					else
1695 						pid = -(pid + 1);
1696 					plr[pid]._pMana = 0;
1697 					plr[pid]._pManaBase = plr[pid]._pMana + plr[pid]._pMaxManaBase - plr[pid]._pMaxMana;
1698 					CalcPlrInv(pid, FALSE);
1699 					drawmanaflag = TRUE;
1700 					PlaySfxLoc(TSFX_COW7, tx, ty);
1701 				}
1702 			}
1703 			pn += 2;
1704 		}
1705 	}
1706 	missile[mi]._mirange = 0;
1707 	missile[mi]._miDelFlag = TRUE;
1708 }
1709 
1710 void AddSpecArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1711 {
1712 	int av;
1713 
1714 	av = 0;
1715 	if (mienemy == TARGET_MONSTERS) {
1716 		if (plr[id]._pClass == PC_ROGUE)
1717 			av += (plr[id]._pLevel - 1) >> 2;
1718 		else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD)
1719 			av += (plr[id]._pLevel - 1) >> 3;
1720 
1721 		if (plr[id]._pIFlags & ISPL_QUICKATTACK)
1722 			av++;
1723 		if (plr[id]._pIFlags & ISPL_FASTATTACK)
1724 			av += 2;
1725 		if (plr[id]._pIFlags & ISPL_FASTERATTACK)
1726 			av += 4;
1727 		if (plr[id]._pIFlags & ISPL_FASTESTATTACK)
1728 			av += 8;
1729 	}
1730 	missile[mi]._mirange = 1;
1731 	missile[mi]._miVar1 = dx;
1732 	missile[mi]._miVar2 = dy;
1733 	missile[mi]._miVar3 = av;
1734 }
1735 
1736 void AddWarp(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1737 {
1738 	int tx, ty, fx, fy, i, dist;
1739 	TriggerStruct *trg;
1740 
1741 	dist = INT_MAX;
1742 	if (id >= 0) {
1743 		sx = plr[id]._px;
1744 		sy = plr[id]._py;
1745 	}
1746 	tx = sx;
1747 	ty = sy;
1748 
1749 	for (i = 0; i < numtrigs && i < MAXTRIGGERS; i++) {
1750 		trg = &trigs[i];
1751 		if (trg->_tmsg == 1032 || trg->_tmsg == 1027 || trg->_tmsg == 1026 || trg->_tmsg == 1028) {
1752 			if ((leveltype == 1 || leveltype == 2) && (trg->_tmsg == 1026 || trg->_tmsg == 1027 || trg->_tmsg == 1028)) {
1753 				fx = trg->_tx;
1754 				fy = trg->_ty + 1;
1755 			} else {
1756 				fx = trg->_tx + 1;
1757 				fy = trg->_ty;
1758 			}
1759 			int dify = (sy - fy);
1760 			int difx = (sx - fx);
1761 			int dif = dify * dify + difx * difx;
1762 			if (dif < dist) {
1763 				dist = dif;
1764 				tx = fx;
1765 				ty = fy;
1766 			}
1767 		}
1768 	}
1769 	missile[mi]._mirange = 2;
1770 	missile[mi]._miVar1 = 0;
1771 	missile[mi]._mix = tx;
1772 	missile[mi]._miy = ty;
1773 	if (mienemy == TARGET_MONSTERS)
1774 		UseMana(id, SPL_WARP);
1775 }
1776 
1777 void AddLightningWall(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1778 {
1779 	GetMissileVel(mi, sx, sy, dx, dy, 16);
1780 	missile[mi]._midam = dam;
1781 	missile[mi]._miAnimFrame = random_(63, 8) + 1;
1782 	missile[mi]._mirange = 255 * (missile[mi]._mispllvl + 1);
1783 	if (id < 0) {
1784 		missile[mi]._miVar1 = sx;
1785 		missile[mi]._miVar2 = sy;
1786 	} else {
1787 		missile[mi]._miVar1 = plr[id]._px;
1788 		missile[mi]._miVar2 = plr[id]._py;
1789 	}
1790 }
1791 
1792 void AddRuneExplosion(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1793 {
1794 	int i, dmg;
1795 
1796 	if (mienemy == TARGET_MONSTERS || mienemy == TARGET_BOTH) {
1797 		missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4;
1798 		for (i = missile[mi]._mispllvl; i > 0; i--) {
1799 			missile[mi]._midam += missile[mi]._midam >> 3;
1800 		}
1801 
1802 		dmg = missile[mi]._midam;
1803 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy - 1, 1);
1804 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy - 1, 1);
1805 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy - 1, 1);
1806 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy, 1);
1807 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy, 1);
1808 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy, 1);
1809 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy + 1, 1);
1810 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy + 1, 1);
1811 		CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy + 1, 1);
1812 	}
1813 	missile[mi]._mlid = AddLight(sx, sy, 8);
1814 	SetMissDir(mi, 0);
1815 	missile[mi]._miDelFlag = 0;
1816 	missile[mi]._mirange = missile[mi]._miAnimLen - 1;
1817 }
1818 
1819 void AddImmolation(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1820 {
1821 	int i;
1822 
1823 	if (sx == dx && sy == dy) {
1824 		dx += XDirAdd[midir];
1825 		dy += YDirAdd[midir];
1826 	}
1827 	if (mienemy == TARGET_MONSTERS) {
1828 		missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4;
1829 		for (i = missile[mi]._mispllvl; i > 0; i--) {
1830 			missile[mi]._midam += missile[mi]._midam >> 3;
1831 		}
1832 		i = 2 * missile[mi]._mispllvl + 16;
1833 		if (i > 50)
1834 			i = 50;
1835 		UseMana(id, SPL_FIREBALL);
1836 	} else {
1837 		i = 16;
1838 	}
1839 	GetMissileVel(mi, sx, sy, dx, dy, i);
1840 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
1841 	missile[mi]._mirange = 256;
1842 	missile[mi]._miVar1 = sx;
1843 	missile[mi]._miVar2 = sy;
1844 	missile[mi]._miVar3 = 0;
1845 	missile[mi]._miVar4 = sx;
1846 	missile[mi]._miVar5 = sy;
1847 	missile[mi]._miVar6 = 2;
1848 	missile[mi]._miVar7 = 2;
1849 	missile[mi]._mlid = AddLight(sx, sy, 8);
1850 }
1851 
1852 void AddFireNova(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1853 {
1854 	int i;
1855 
1856 	if (sx == dx && sy == dy) {
1857 		dx += XDirAdd[midir];
1858 		dy += YDirAdd[midir];
1859 	}
1860 	if (mienemy == TARGET_MONSTERS) {
1861 		i = missile[mi]._mispllvl + 16;
1862 		if (i > 50) {
1863 			i = 50;
1864 		}
1865 	} else {
1866 		i = 16;
1867 	}
1868 	GetMissileVel(mi, sx, sy, dx, dy, i);
1869 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
1870 	missile[mi]._mirange = 256;
1871 	missile[mi]._miVar1 = sx;
1872 	missile[mi]._miVar2 = sy;
1873 	missile[mi]._miVar3 = 0;
1874 	missile[mi]._miVar4 = sx;
1875 	missile[mi]._miVar5 = sy;
1876 	missile[mi]._mlid = AddLight(sx, sy, 8);
1877 }
1878 
1879 void AddLightningArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1880 {
1881 	if (sx == dx && sy == dy) {
1882 		dx += XDirAdd[midir];
1883 		dy += YDirAdd[midir];
1884 	}
1885 	GetMissileVel(mi, sx, sy, dx, dy, 32);
1886 	missile[mi]._miAnimFrame = random_(52, 8) + 1;
1887 	missile[mi]._mirange = 255;
1888 	if (id < 0) {
1889 		missile[mi]._miVar1 = sx;
1890 		missile[mi]._miVar2 = sy;
1891 	} else {
1892 		missile[mi]._miVar1 = plr[id]._px;
1893 		missile[mi]._miVar2 = plr[id]._py;
1894 	}
1895 	missile[mi]._midam <<= 6;
1896 }
1897 
1898 void AddFlashFront(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1899 {
1900 }
1901 
1902 void AddFlashBack(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1903 {
1904 	if (mienemy == TARGET_MONSTERS && id != -1) {
1905 		missile[mi]._midam = 0;
1906 		int lvl = 2;
1907 		if (id > -1)
1908 			lvl = plr[id]._pLevel * 2;
1909 		missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245;
1910 	}
1911 }
1912 
1913 void AddMana(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1914 {
1915 	int i, ManaAmount;
1916 
1917 	ManaAmount = (random_(57, 10) + 1) << 6;
1918 	for (i = 0; i < plr[id]._pLevel; i++) {
1919 		ManaAmount += (random_(57, 4) + 1) << 6;
1920 	}
1921 	for (i = 0; i < missile[mi]._mispllvl; i++) {
1922 		ManaAmount += (random_(57, 6) + 1) << 6;
1923 	}
1924 	if (plr[id]._pClass == PC_SORCERER)
1925 		ManaAmount <<= 1;
1926 	if (plr[id]._pClass == PC_ROGUE || plr[id]._pClass == PC_BARD)
1927 		ManaAmount += ManaAmount >> 1;
1928 	plr[id]._pMana += ManaAmount;
1929 	if (plr[id]._pMana > plr[id]._pMaxMana)
1930 		plr[id]._pMana = plr[id]._pMaxMana;
1931 	plr[id]._pManaBase += ManaAmount;
1932 	if (plr[id]._pManaBase > plr[id]._pMaxManaBase)
1933 		plr[id]._pManaBase = plr[id]._pMaxManaBase;
1934 	UseMana(id, SPL_MANA);
1935 	missile[mi]._miDelFlag = TRUE;
1936 	drawmanaflag = TRUE;
1937 }
1938 
1939 void AddMagi(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1940 {
1941 	plr[id]._pMana = plr[id]._pMaxMana;
1942 	plr[id]._pManaBase = plr[id]._pMaxManaBase;
1943 	UseMana(id, SPL_MAGI);
1944 	missile[mi]._miDelFlag = TRUE;
1945 	drawmanaflag = TRUE;
1946 }
1947 
1948 void AddRing(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1949 {
1950 	missile[mi]._miDelFlag = TRUE;
1951 	if (mienemy == TARGET_MONSTERS)
1952 		UseMana(id, SPL_FIRERING);
1953 	missile[mi]._miVar1 = sx;
1954 	missile[mi]._miVar2 = sy;
1955 	missile[mi]._miDelFlag = FALSE;
1956 	missile[mi]._miVar3 = 0;
1957 	missile[mi]._miVar4 = 0;
1958 	missile[mi]._miVar5 = 0;
1959 	missile[mi]._miVar6 = 0;
1960 	missile[mi]._miVar7 = 0;
1961 	missile[mi]._miVar8 = 0;
1962 	missile[mi]._mirange = 7;
1963 }
1964 
1965 void AddSearch(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
1966 {
1967 	int i, mx, r1, r2;
1968 	MissileStruct *mis;
1969 
1970 	missile[mi]._miDelFlag = FALSE;
1971 	missile[mi]._miVar1 = id;
1972 	missile[mi]._miVar2 = 0;
1973 	missile[mi]._miVar3 = 0;
1974 	missile[mi]._miVar4 = 0;
1975 	missile[mi]._miVar5 = 0;
1976 	missile[mi]._miVar6 = 0;
1977 	missile[mi]._miVar7 = 0;
1978 	missile[mi]._miVar8 = 0;
1979 	AutoMapShowItems = TRUE;
1980 	int lvl = 2;
1981 	if (id > -1)
1982 		lvl = plr[id]._pLevel * 2;
1983 	missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245;
1984 	if (mienemy == TARGET_MONSTERS)
1985 		UseMana(id, SPL_SEARCH);
1986 
1987 	for (i = 0; i < nummissiles; i++) {
1988 		mx = missileactive[i];
1989 		if (mx != mi) {
1990 			mis = &missile[mx];
1991 			if (mis->_miVar1 == id && mis->_mitype == 85) {
1992 				r1 = missile[mi]._mirange;
1993 				r2 = mis->_mirange;
1994 				if (r2 < INT_MAX - r1)
1995 					mis->_mirange = r1 + r2;
1996 				missile[mi]._miDelFlag = TRUE;
1997 				break;
1998 			}
1999 		}
2000 	}
2001 }
2002 
2003 void AddCboltArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2004 {
2005 	if (mienemy == TARGET_MONSTERS) {
2006 		if (id == myplr) {
2007 			missile[mi]._mirnd = random_(63, 15) + 1;
2008 		} else {
2009 			missile[mi]._mirnd = random_(63, 15) + 1;
2010 		}
2011 	} else {
2012 		missile[mi]._mirnd = random_(63, 15) + 1;
2013 		missile[mi]._midam = 15;
2014 	}
2015 	if (sx == dx && sy == dy) {
2016 		dx += XDirAdd[midir];
2017 		dy += YDirAdd[midir];
2018 	}
2019 	missile[mi]._miAnimFrame = random_(63, 8) + 1;
2020 	missile[mi]._mlid = AddLight(sx, sy, 5);
2021 	GetMissileVel(mi, sx, sy, dx, dy, 8);
2022 	missile[mi]._miVar1 = 5;
2023 	missile[mi]._miVar2 = midir;
2024 	missile[mi]._miVar3 = 0;
2025 	missile[mi]._mirange = 256;
2026 }
2027 
2028 void AddHboltArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2029 {
2030 	int i;
2031 
2032 	if (sx == dx && sy == dy) {
2033 		dx += XDirAdd[midir];
2034 		dy += YDirAdd[midir];
2035 	}
2036 
2037 	if (id != -1) {
2038 		i = 2 * missile[mi]._mispllvl + 16;
2039 		if (i >= 63) {
2040 			i = 63;
2041 		}
2042 	} else {
2043 		i = 16;
2044 	}
2045 
2046 	GetMissileVel(mi, sx, sy, dx, dy, i);
2047 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2048 	missile[mi]._mirange = 256;
2049 	missile[mi]._miVar1 = sx;
2050 	missile[mi]._miVar2 = sy;
2051 	missile[mi]._mlid = AddLight(sx, sy, 8);
2052 }
2053 
2054 void AddLArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2055 {
2056 	if (sx == dx && sy == dy) {
2057 		dx += XDirAdd[midir];
2058 		dy += YDirAdd[midir];
2059 	}
2060 	if (mienemy == TARGET_MONSTERS) {
2061 		int av = 32;
2062 
2063 		if (plr[id]._pClass == PC_ROGUE)
2064 			av += (plr[id]._pLevel) >> 2;
2065 		else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD)
2066 			av += (plr[id]._pLevel) >> 3;
2067 
2068 		if (gbIsHellfire) {
2069 			if (plr[id]._pIFlags & ISPL_QUICKATTACK)
2070 				av++;
2071 			if (plr[id]._pIFlags & ISPL_FASTATTACK)
2072 				av += 2;
2073 			if (plr[id]._pIFlags & ISPL_FASTERATTACK)
2074 				av += 4;
2075 			if (plr[id]._pIFlags & ISPL_FASTESTATTACK)
2076 				av += 8;
2077 		} else {
2078 			if (plr[id]._pClass == PC_ROGUE || plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD)
2079 				av -= 1;
2080 		}
2081 
2082 		GetMissileVel(mi, sx, sy, dx, dy, av);
2083 	} else
2084 		GetMissileVel(mi, sx, sy, dx, dy, 32);
2085 
2086 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2087 	missile[mi]._mirange = 256;
2088 	missile[mi]._miVar1 = sx;
2089 	missile[mi]._miVar2 = sy;
2090 	missile[mi]._mlid = AddLight(sx, sy, 5);
2091 }
2092 
2093 void AddArrow(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2094 {
2095 	int av;
2096 
2097 	if (sx == dx && sy == dy) {
2098 		dx += XDirAdd[midir];
2099 		dy += YDirAdd[midir];
2100 	}
2101 	if (mienemy == TARGET_MONSTERS) {
2102 		av = 32;
2103 		if (plr[id]._pIFlags & ISPL_RNDARROWVEL) {
2104 			av = random_(64, 32) + 16;
2105 		}
2106 		if (plr[id]._pClass == PC_ROGUE)
2107 			av += (plr[id]._pLevel - 1) >> 2;
2108 		else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD)
2109 			av += (plr[id]._pLevel - 1) >> 3;
2110 		if (gbIsHellfire) {
2111 			if (plr[id]._pIFlags & ISPL_QUICKATTACK)
2112 				av++;
2113 			if (plr[id]._pIFlags & ISPL_FASTATTACK)
2114 				av += 2;
2115 			if (plr[id]._pIFlags & ISPL_FASTERATTACK)
2116 				av += 4;
2117 			if (plr[id]._pIFlags & ISPL_FASTESTATTACK)
2118 				av += 8;
2119 		}
2120 		GetMissileVel(mi, sx, sy, dx, dy, av);
2121 	} else {
2122 		GetMissileVel(mi, sx, sy, dx, dy, 32);
2123 	}
2124 	missile[mi]._miAnimFrame = GetDirection16(sx, sy, dx, dy) + 1;
2125 	missile[mi]._mirange = 256;
2126 }
2127 
2128 void GetVileMissPos(int mi, int dx, int dy)
2129 {
2130 	int xx, yy, k, j, i;
2131 
2132 	for (k = 1; k < 50; k++) {
2133 		for (j = -k; j <= k; j++) {
2134 			yy = j + dy;
2135 			for (i = -k; i <= k; i++) {
2136 				xx = i + dx;
2137 				if (PosOkPlayer(myplr, xx, yy)) {
2138 					missile[mi]._mix = xx;
2139 					missile[mi]._miy = yy;
2140 					return;
2141 				}
2142 			}
2143 		}
2144 	}
2145 	missile[mi]._mix = dx;
2146 	missile[mi]._miy = dy;
2147 }
2148 
2149 void AddRndTeleport(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2150 {
2151 	int pn, r1, r2, nTries;
2152 
2153 	nTries = 0;
2154 	do {
2155 		nTries++;
2156 		if (nTries > 500) {
2157 			r1 = 0;
2158 			r2 = 0;
2159 			break; //BUGFIX: warps player to 0/0 in hellfire, change to return or use 1.09's version of the code
2160 		}
2161 		r1 = random_(58, 3) + 4;
2162 		r2 = random_(58, 3) + 4;
2163 		if (random_(58, 2) == 1)
2164 			r1 = -r1;
2165 		if (random_(58, 2) == 1)
2166 			r2 = -r2;
2167 
2168 		r1 += sx;
2169 		r2 += sy;
2170 		if (r1 < MAXDUNX && r1 >= 0 && r2 < MAXDUNY && r2 >= 0) { ///BUGFIX: < MAXDUNX / < MAXDUNY (fixed)
2171 			pn = dPiece[r1][r2];
2172 		}
2173 	} while (nSolidTable[pn] || dObject[r1][r2] != 0 || dMonster[r1][r2] != 0);
2174 
2175 	missile[mi]._mirange = 2;
2176 	missile[mi]._miVar1 = 0;
2177 	if (!setlevel || setlvlnum != SL_VILEBETRAYER) {
2178 		missile[mi]._mix = r1;
2179 		missile[mi]._miy = r2;
2180 		if (mienemy == TARGET_MONSTERS)
2181 			UseMana(id, SPL_RNDTELEPORT);
2182 	} else {
2183 		pn = dObject[dx][dy] - 1;
2184 		// BUGFIX: should only run magic circle check if dObject[dx][dy] is non-zero.
2185 		if (object[pn]._otype == OBJ_MCIRCLE1 || object[pn]._otype == OBJ_MCIRCLE2) {
2186 			missile[mi]._mix = dx;
2187 			missile[mi]._miy = dy;
2188 			if (!PosOkPlayer(myplr, dx, dy))
2189 				GetVileMissPos(mi, dx, dy);
2190 		}
2191 	}
2192 }
2193 
2194 void AddFirebolt(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 micaster, Sint32 id, Sint32 dam)
2195 {
2196 	int i, mx, sp;
2197 
2198 	if (sx == dx && sy == dy) {
2199 		dx += XDirAdd[midir];
2200 		dy += YDirAdd[midir];
2201 	}
2202 	if (!micaster) {
2203 		for (i = 0; i < nummissiles; i++) {
2204 			mx = missileactive[i];
2205 			if (missile[mx]._mitype == MIS_GUARDIAN && missile[mx]._misource == id && missile[mx]._miVar3 == mi)
2206 				break;
2207 		}
2208 		if (i == nummissiles)
2209 			UseMana(id, SPL_FIREBOLT);
2210 		if (id != -1) {
2211 			sp = 2 * missile[mi]._mispllvl + 16;
2212 			if (sp >= 63)
2213 				sp = 63;
2214 		} else {
2215 			sp = 16;
2216 		}
2217 	} else {
2218 		sp = 26;
2219 	}
2220 	GetMissileVel(mi, sx, sy, dx, dy, sp);
2221 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2222 	missile[mi]._mirange = 256;
2223 	missile[mi]._miVar1 = sx;
2224 	missile[mi]._miVar2 = sy;
2225 	missile[mi]._mlid = AddLight(sx, sy, 8);
2226 }
2227 
2228 void AddMagmaball(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2229 {
2230 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2231 	missile[mi]._mitxoff += 3 * missile[mi]._mixvel;
2232 	missile[mi]._mityoff += 3 * missile[mi]._miyvel;
2233 	GetMissilePos(mi);
2234 	if (!gbIsHellfire || missile[mi]._mixvel & 0xFFFF0000 || missile[mi]._miyvel & 0xFFFF0000)
2235 		missile[mi]._mirange = 256;
2236 	else
2237 		missile[mi]._mirange = 1;
2238 	missile[mi]._miVar1 = sx;
2239 	missile[mi]._miVar2 = sy;
2240 	missile[mi]._mlid = AddLight(sx, sy, 8);
2241 }
2242 
2243 void AddKrull(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2244 {
2245 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2246 	missile[mi]._mirange = 256;
2247 	missile[mi]._miVar1 = sx;
2248 	missile[mi]._miVar2 = sy;
2249 	PutMissile(mi);
2250 }
2251 
2252 void AddTeleport(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2253 {
2254 	int i, pn, k, j, tx, ty;
2255 
2256 	missile[mi]._miDelFlag = TRUE;
2257 	for (i = 0; i < 6; i++) {
2258 		k = CrawlNum[i];
2259 		pn = k + 2;
2260 		for (j = (BYTE)CrawlTable[k]; j > 0; j--) {
2261 			tx = dx + CrawlTable[pn - 1];
2262 			ty = dy + CrawlTable[pn];
2263 			if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) {
2264 				if ((nSolidTable[dPiece[tx][ty]] | dMonster[tx][ty] | dObject[tx][ty] | dPlayer[tx][ty]) == 0) {
2265 					missile[mi]._mix = tx;
2266 					missile[mi]._miy = ty;
2267 					missile[mi]._misx = tx;
2268 					missile[mi]._misy = ty;
2269 					missile[mi]._miDelFlag = FALSE;
2270 					i = 6;
2271 					break;
2272 				}
2273 			}
2274 			pn += 2;
2275 		}
2276 	}
2277 
2278 	if (!missile[mi]._miDelFlag) {
2279 		UseMana(id, SPL_TELEPORT);
2280 		missile[mi]._mirange = 2;
2281 	}
2282 }
2283 
2284 void AddLightball(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2285 {
2286 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2287 	missile[mi]._midam = dam;
2288 	missile[mi]._miAnimFrame = random_(63, 8) + 1;
2289 	missile[mi]._mirange = 255;
2290 	if (id < 0) {
2291 		missile[mi]._miVar1 = sx;
2292 		missile[mi]._miVar2 = sy;
2293 	} else {
2294 		missile[mi]._miVar1 = plr[id]._px;
2295 		missile[mi]._miVar2 = plr[id]._py;
2296 	}
2297 }
2298 
2299 void AddFirewall(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2300 {
2301 	int i;
2302 
2303 	missile[mi]._midam = random_(53, 10) + random_(53, 10) + 2;
2304 	missile[mi]._midam += id >= 0 ? plr[id]._pLevel : currlevel; // BUGFIX: missing parenthesis around ternary (fixed)
2305 	missile[mi]._midam <<= 3;
2306 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2307 	i = missile[mi]._mispllvl;
2308 	missile[mi]._mirange = 10;
2309 	if (i > 0)
2310 		missile[mi]._mirange *= i + 1;
2311 	if (mienemy == TARGET_PLAYERS || id < 0)
2312 		missile[mi]._mirange += currlevel;
2313 	else
2314 		missile[mi]._mirange += (plr[id]._pISplDur * missile[mi]._mirange) >> 7;
2315 	missile[mi]._mirange <<= 4;
2316 	missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen;
2317 	missile[mi]._miVar2 = 0;
2318 }
2319 
2320 void AddFireball(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2321 {
2322 	int i;
2323 
2324 	if (sx == dx && sy == dy) {
2325 		dx += XDirAdd[midir];
2326 		dy += YDirAdd[midir];
2327 	}
2328 	if (mienemy == TARGET_MONSTERS) {
2329 		missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4;
2330 		for (i = missile[mi]._mispllvl; i > 0; i--) {
2331 			missile[mi]._midam += missile[mi]._midam >> 3;
2332 		}
2333 		i = 2 * missile[mi]._mispllvl + 16;
2334 		if (i > 50)
2335 			i = 50;
2336 		UseMana(id, SPL_FIREBALL);
2337 	} else {
2338 		i = 16;
2339 	}
2340 	GetMissileVel(mi, sx, sy, dx, dy, i);
2341 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2342 	missile[mi]._mirange = 256;
2343 	missile[mi]._miVar1 = sx;
2344 	missile[mi]._miVar2 = sy;
2345 	missile[mi]._miVar3 = 0;
2346 	missile[mi]._miVar4 = sx;
2347 	missile[mi]._miVar5 = sy;
2348 	missile[mi]._mlid = AddLight(sx, sy, 8);
2349 }
2350 
2351 void AddLightctrl(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2352 {
2353 	if (!dam && mienemy == TARGET_MONSTERS)
2354 		UseMana(id, SPL_LIGHTNING);
2355 	missile[mi]._miVar1 = sx;
2356 	missile[mi]._miVar2 = sy;
2357 	GetMissileVel(mi, sx, sy, dx, dy, 32);
2358 	missile[mi]._miAnimFrame = random_(52, 8) + 1;
2359 	missile[mi]._mirange = 256;
2360 }
2361 
2362 void AddLightning(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2363 {
2364 	missile[mi]._misx = dx;
2365 	missile[mi]._misy = dy;
2366 	if (midir >= 0) {
2367 		missile[mi]._mixoff = missile[midir]._mixoff;
2368 		missile[mi]._miyoff = missile[midir]._miyoff;
2369 		missile[mi]._mitxoff = missile[midir]._mitxoff;
2370 		missile[mi]._mityoff = missile[midir]._mityoff;
2371 	}
2372 	missile[mi]._miAnimFrame = random_(52, 8) + 1;
2373 
2374 	if (midir < 0 || mienemy == TARGET_PLAYERS || id == -1) {
2375 		if (midir < 0 || id == -1)
2376 			missile[mi]._mirange = 8;
2377 		else
2378 			missile[mi]._mirange = 10;
2379 	} else {
2380 		missile[mi]._mirange = (missile[mi]._mispllvl >> 1) + 6;
2381 	}
2382 	missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 4);
2383 }
2384 
2385 void AddMisexp(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2386 {
2387 	CMonster *mon;
2388 
2389 	if (mienemy && id > 0) {
2390 		mon = monster[id].MType;
2391 		switch (mon->mtype) {
2392 		case MT_SUCCUBUS:
2393 			SetMissAnim(mi, MFILE_FLAREEXP);
2394 			break;
2395 		case MT_SNOWWICH:
2396 			SetMissAnim(mi, MFILE_SCBSEXPB);
2397 			break;
2398 		case MT_HLSPWN:
2399 			SetMissAnim(mi, MFILE_SCBSEXPD);
2400 			break;
2401 		case MT_SOLBRNR:
2402 			SetMissAnim(mi, MFILE_SCBSEXPC);
2403 			break;
2404 		}
2405 	}
2406 
2407 	missile[mi]._mix = missile[dx]._mix;
2408 	missile[mi]._miy = missile[dx]._miy;
2409 	missile[mi]._misx = missile[dx]._misx;
2410 	missile[mi]._misy = missile[dx]._misy;
2411 	missile[mi]._mixoff = missile[dx]._mixoff;
2412 	missile[mi]._miyoff = missile[dx]._miyoff;
2413 	missile[mi]._mitxoff = missile[dx]._mitxoff;
2414 	missile[mi]._mityoff = missile[dx]._mityoff;
2415 	missile[mi]._mixvel = 0;
2416 	missile[mi]._miyvel = 0;
2417 	missile[mi]._mirange = missile[mi]._miAnimLen;
2418 	missile[mi]._miVar1 = 0;
2419 }
2420 
2421 void AddWeapexp(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2422 {
2423 	missile[mi]._mix = sx;
2424 	missile[mi]._miy = sy;
2425 	missile[mi]._misx = sx;
2426 	missile[mi]._misy = sy;
2427 	missile[mi]._mixvel = 0;
2428 	missile[mi]._miyvel = 0;
2429 	missile[mi]._miVar1 = 0;
2430 	missile[mi]._miVar2 = dx;
2431 	missile[mi]._mimfnum = 0;
2432 	if (dx == 1)
2433 		SetMissAnim(mi, MFILE_MAGBLOS);
2434 	else
2435 		SetMissAnim(mi, MFILE_MINILTNG);
2436 	missile[mi]._mirange = missile[mi]._miAnimLen - 1;
2437 }
2438 
2439 BOOL CheckIfTrig(int x, int y)
2440 {
2441 	int i;
2442 
2443 	for (i = 0; i < numtrigs; i++) {
2444 		if ((x == trigs[i]._tx && y == trigs[i]._ty) || (abs(trigs[i]._tx - x) < 2 && abs(trigs[i]._ty - y) < 2))
2445 			return TRUE;
2446 	}
2447 	return FALSE;
2448 }
2449 
2450 void AddTown(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2451 {
2452 	int i, j, k, mx, tx, ty, dp;
2453 
2454 	if (currlevel != 0) {
2455 		missile[mi]._miDelFlag = TRUE;
2456 		for (j = 0; j < 6; j++) {
2457 			k = CrawlNum[j] + 2;
2458 			for (i = (BYTE)CrawlTable[CrawlNum[j]]; i > 0; i--) {
2459 				tx = dx + CrawlTable[k - 1];
2460 				ty = dy + CrawlTable[k];
2461 				if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
2462 					dp = dPiece[tx][ty];
2463 					if ((dMissile[tx][ty] | nSolidTable[dp] | nMissileTable[dp] | dObject[tx][ty] | dPlayer[tx][ty]) == 0) {
2464 						if (!CheckIfTrig(tx, ty)) {
2465 							missile[mi]._mix = tx;
2466 							missile[mi]._miy = ty;
2467 							missile[mi]._misx = tx;
2468 							missile[mi]._misy = ty;
2469 							missile[mi]._miDelFlag = FALSE;
2470 							j = 6;
2471 							break;
2472 						}
2473 					}
2474 				}
2475 				k += 2;
2476 			}
2477 		}
2478 	} else {
2479 		tx = dx;
2480 		ty = dy;
2481 		missile[mi]._mix = tx;
2482 		missile[mi]._miy = ty;
2483 		missile[mi]._misx = tx;
2484 		missile[mi]._misy = ty;
2485 		missile[mi]._miDelFlag = FALSE;
2486 	}
2487 	missile[mi]._mirange = 100;
2488 	missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen;
2489 	missile[mi]._miVar2 = 0;
2490 	for (i = 0; i < nummissiles; i++) {
2491 		mx = missileactive[i];
2492 		if (missile[mx]._mitype == MIS_TOWN && mx != mi && missile[mx]._misource == id)
2493 			missile[mx]._mirange = 0;
2494 	}
2495 	PutMissile(mi);
2496 	if (id == myplr && !missile[mi]._miDelFlag && currlevel != 0) {
2497 		if (!setlevel) {
2498 			NetSendCmdLocParam3(TRUE, CMD_ACTIVATEPORTAL, tx, ty, currlevel, leveltype, 0);
2499 		} else {
2500 			NetSendCmdLocParam3(TRUE, CMD_ACTIVATEPORTAL, tx, ty, setlvlnum, leveltype, 1);
2501 		}
2502 	}
2503 }
2504 
2505 void AddFlash(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2506 {
2507 	int i;
2508 
2509 	if (id != -1) {
2510 		if (mienemy == TARGET_MONSTERS) {
2511 			missile[mi]._midam = 0;
2512 			for (i = 0; i <= plr[id]._pLevel; i++) {
2513 				missile[mi]._midam += random_(55, 20) + 1;
2514 			}
2515 			for (i = missile[mi]._mispllvl; i > 0; i--) {
2516 				missile[mi]._midam += missile[mi]._midam >> 3;
2517 			}
2518 			missile[mi]._midam += missile[mi]._midam >> 1;
2519 			UseMana(id, SPL_FLASH);
2520 		} else {
2521 			missile[mi]._midam = monster[id].mLevel << 1;
2522 		}
2523 	} else {
2524 		missile[mi]._midam = currlevel >> 1;
2525 	}
2526 	missile[mi]._mirange = 19;
2527 }
2528 
2529 void AddFlash2(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2530 {
2531 	int i;
2532 
2533 	if (mienemy == TARGET_MONSTERS) {
2534 		if (id != -1) {
2535 			missile[mi]._midam = 0;
2536 			for (i = 0; i <= plr[id]._pLevel; i++) {
2537 				missile[mi]._midam += random_(56, 20) + 1;
2538 			}
2539 			for (i = missile[mi]._mispllvl; i > 0; i--) {
2540 				missile[mi]._midam += missile[mi]._midam >> 3;
2541 			}
2542 			missile[mi]._midam += missile[mi]._midam >> 1;
2543 		} else {
2544 			missile[mi]._midam = currlevel >> 1;
2545 		}
2546 	}
2547 	missile[mi]._miPreFlag = TRUE;
2548 	missile[mi]._mirange = 19;
2549 }
2550 
2551 void AddManashield(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2552 {
2553 	missile[mi]._mirange = 48 * plr[id]._pLevel;
2554 	missile[mi]._miVar1 = plr[id]._pHitPoints;
2555 	missile[mi]._miVar2 = plr[id]._pHPBase;
2556 	missile[mi]._miVar8 = -1;
2557 	if (mienemy == TARGET_MONSTERS)
2558 		UseMana(id, SPL_MANASHIELD);
2559 	if (id == myplr)
2560 		NetSendCmd(TRUE, CMD_SETSHIELD);
2561 	plr[id].pManaShield = TRUE;
2562 }
2563 
2564 void AddFiremove(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2565 {
2566 	missile[mi]._midam = random_(59, 10) + plr[id]._pLevel + 1;
2567 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2568 	missile[mi]._mirange = 255;
2569 	missile[mi]._miVar1 = 0;
2570 	missile[mi]._miVar2 = 0;
2571 	missile[mi]._mix++;
2572 	missile[mi]._miy++;
2573 	missile[mi]._miyoff -= 32;
2574 }
2575 
2576 void AddGuardian(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2577 {
2578 	int i, pn, k, j, tx, ty;
2579 
2580 	missile[mi]._midam = random_(62, 10) + (plr[id]._pLevel >> 1) + 1;
2581 	for (i = missile[mi]._mispllvl; i > 0; i--) {
2582 		missile[mi]._midam += missile[mi]._midam >> 3;
2583 	}
2584 
2585 	missile[mi]._miDelFlag = TRUE;
2586 	for (i = 0; i < 6; i++) {
2587 		pn = CrawlNum[i];
2588 		k = pn + 2;
2589 		for (j = (BYTE)CrawlTable[pn]; j > 0; j--) {
2590 			tx = dx + CrawlTable[k - 1];
2591 			ty = dy + CrawlTable[k];
2592 			pn = dPiece[tx][ty];
2593 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
2594 				if (LineClear(sx, sy, tx, ty)) {
2595 					if ((dMonster[tx][ty] | nSolidTable[pn] | nMissileTable[pn] | dObject[tx][ty] | dMissile[tx][ty]) == 0) {
2596 						missile[mi]._mix = tx;
2597 						missile[mi]._miy = ty;
2598 						missile[mi]._misx = tx;
2599 						missile[mi]._misy = ty;
2600 						missile[mi]._miDelFlag = FALSE;
2601 						UseMana(id, SPL_GUARDIAN);
2602 						i = 6;
2603 						break;
2604 					}
2605 				}
2606 			}
2607 			k += 2;
2608 		}
2609 	}
2610 
2611 	if (missile[mi]._miDelFlag != TRUE) {
2612 		missile[mi]._misource = id;
2613 		missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 1);
2614 		missile[mi]._mirange = missile[mi]._mispllvl + (plr[id]._pLevel >> 1);
2615 		missile[mi]._mirange += (missile[mi]._mirange * plr[id]._pISplDur) >> 7;
2616 
2617 		if (missile[mi]._mirange > 30)
2618 			missile[mi]._mirange = 30;
2619 		missile[mi]._mirange <<= 4;
2620 		if (missile[mi]._mirange < 30)
2621 			missile[mi]._mirange = 30;
2622 
2623 		missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen;
2624 		missile[mi]._miVar2 = 0;
2625 		missile[mi]._miVar3 = 1;
2626 	}
2627 }
2628 
2629 void AddChain(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2630 {
2631 	missile[mi]._miVar1 = dx;
2632 	missile[mi]._miVar2 = dy;
2633 	missile[mi]._mirange = 1;
2634 	UseMana(id, SPL_CHAIN);
2635 }
2636 
2637 void AddBloodStar(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2638 {
2639 	SetMissDir(mi, dx);
2640 	missile[mi]._midam = 0;
2641 	missile[mi]._miLightFlag = TRUE;
2642 	missile[mi]._mirange = 250;
2643 }
2644 
2645 void AddBone(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2646 {
2647 	if (dx > 3)
2648 		dx = 2;
2649 	SetMissDir(mi, dx);
2650 	missile[mi]._midam = 0;
2651 	missile[mi]._miLightFlag = TRUE;
2652 	missile[mi]._mirange = 250;
2653 }
2654 
2655 void AddMetlHit(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2656 {
2657 	if (dx > 3)
2658 		dx = 2;
2659 	SetMissDir(mi, dx);
2660 	missile[mi]._midam = 0;
2661 	missile[mi]._miLightFlag = TRUE;
2662 	missile[mi]._mirange = missile[mi]._miAnimLen;
2663 }
2664 
2665 void AddRhino(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2666 {
2667 	AnimStruct *anim;
2668 
2669 	if (monster[id].MType->mtype < MT_HORNED || monster[id].MType->mtype > MT_OBLORD) {
2670 		if (monster[id].MType->mtype < MT_NSNAKE || monster[id].MType->mtype > MT_GSNAKE) {
2671 			anim = &monster[id].MType->Anims[MA_WALK];
2672 		} else {
2673 			anim = &monster[id].MType->Anims[MA_ATTACK];
2674 		}
2675 	} else {
2676 		anim = &monster[id].MType->Anims[MA_SPECIAL];
2677 	}
2678 	GetMissileVel(mi, sx, sy, dx, dy, 18);
2679 	missile[mi]._mimfnum = midir;
2680 	missile[mi]._miAnimFlags = 0;
2681 	missile[mi]._miAnimData = anim->Data[midir];
2682 	missile[mi]._miAnimDelay = anim->Rate;
2683 	missile[mi]._miAnimLen = anim->Frames;
2684 	missile[mi]._miAnimWidth = monster[id].MType->width;
2685 	missile[mi]._miAnimWidth2 = monster[id].MType->width2;
2686 	missile[mi]._miAnimAdd = 1;
2687 	if (monster[id].MType->mtype >= MT_NSNAKE && monster[id].MType->mtype <= MT_GSNAKE)
2688 		missile[mi]._miAnimFrame = 7;
2689 	missile[mi]._miVar1 = 0;
2690 	missile[mi]._miVar2 = 0;
2691 	missile[mi]._miLightFlag = TRUE;
2692 	if (monster[id]._uniqtype != 0) {
2693 		missile[mi]._miUniqTrans = monster[id]._uniqtrans + 1;
2694 		missile[mi]._mlid = monster[id].mlid;
2695 	}
2696 	missile[mi]._mirange = 256;
2697 	PutMissile(mi);
2698 }
2699 
2700 void AddFireman(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2701 {
2702 	AnimStruct *anim;
2703 	MonsterStruct *mon;
2704 
2705 	anim = &monster[id].MType->Anims[MA_WALK];
2706 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2707 	missile[mi]._mimfnum = midir;
2708 	missile[mi]._miAnimFlags = 0;
2709 	missile[mi]._miAnimData = anim->Data[midir];
2710 	missile[mi]._miAnimDelay = anim->Rate;
2711 	missile[mi]._miAnimLen = anim->Frames;
2712 	missile[mi]._miAnimWidth = monster[id].MType->width;
2713 	missile[mi]._miAnimWidth2 = monster[id].MType->width2;
2714 	missile[mi]._miAnimAdd = 1;
2715 	missile[mi]._miVar1 = 0;
2716 	missile[mi]._miVar2 = 0;
2717 	missile[mi]._miLightFlag = TRUE;
2718 	if (monster[id]._uniqtype != 0)
2719 		missile[mi]._miUniqTrans = monster[id]._uniqtrans + 1;
2720 	mon = &monster[id];
2721 	dMonster[mon->_mx][mon->_my] = 0;
2722 	missile[mi]._mirange = 256;
2723 	PutMissile(mi);
2724 }
2725 
2726 void AddFlare(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2727 {
2728 	if (sx == dx && sy == dy) {
2729 		dx += XDirAdd[midir];
2730 		dy += YDirAdd[midir];
2731 	}
2732 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2733 	missile[mi]._mirange = 256;
2734 	missile[mi]._miVar1 = sx;
2735 	missile[mi]._miVar2 = sy;
2736 	missile[mi]._mlid = AddLight(sx, sy, 8);
2737 	if (mienemy == TARGET_MONSTERS) {
2738 		UseMana(id, SPL_FLARE);
2739 		plr[id]._pHitPoints -= 320;
2740 		plr[id]._pHPBase -= 320;
2741 		drawhpflag = TRUE;
2742 		if (plr[id]._pHitPoints <= 0)
2743 			SyncPlrKill(id, 0);
2744 	} else {
2745 		if (id > 0) {
2746 			if (monster[id].MType->mtype == MT_SUCCUBUS)
2747 				SetMissAnim(mi, MFILE_FLARE);
2748 			if (monster[id].MType->mtype == MT_SNOWWICH)
2749 				SetMissAnim(mi, MFILE_SCUBMISB);
2750 			if (monster[id].MType->mtype == MT_HLSPWN)
2751 				SetMissAnim(mi, MFILE_SCUBMISD);
2752 			if (monster[id].MType->mtype == MT_SOLBRNR)
2753 				SetMissAnim(mi, MFILE_SCUBMISC);
2754 		}
2755 	}
2756 
2757 	if (misfiledata[missile[mi]._miAnimType].mAnimFAmt == 16) {
2758 		SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2759 	}
2760 }
2761 
2762 void AddAcid(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2763 {
2764 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2765 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
2766 	if (!gbIsHellfire && missile[mi]._mixvel & 0xFFFF0000 || missile[mi]._miyvel & 0xFFFF0000)
2767 		missile[mi]._mirange = 5 * (monster[id]._mint + 4);
2768 	else
2769 		missile[mi]._mirange = 1;
2770 	missile[mi]._mlid = NO_LIGHT;
2771 	missile[mi]._miVar1 = sx;
2772 	missile[mi]._miVar2 = sy;
2773 	PutMissile(mi);
2774 }
2775 
2776 void AddFireWallA(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2777 {
2778 	missile[mi]._midam = dam;
2779 	missile[mi]._mixvel = 0;
2780 	missile[mi]._miyvel = 0;
2781 	missile[mi]._mirange = 50;
2782 	missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen;
2783 	missile[mi]._miVar2 = 0;
2784 }
2785 
2786 void AddAcidpud(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2787 {
2788 	int monst;
2789 
2790 	missile[mi]._mixvel = 0;
2791 	missile[mi]._miyvel = 0;
2792 	missile[mi]._mixoff = 0;
2793 	missile[mi]._miyoff = 0;
2794 	missile[mi]._miLightFlag = TRUE;
2795 	monst = missile[mi]._misource;
2796 	missile[mi]._mirange = random_(50, 15) + 40 * (monster[monst]._mint + 1);
2797 	missile[mi]._miPreFlag = TRUE;
2798 }
2799 
2800 void AddStone(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2801 {
2802 	int i, j, k, l, tx, ty, mid;
2803 
2804 	missile[mi]._misource = id;
2805 	for (i = 0; i < 6; i++) {
2806 		k = CrawlNum[i];
2807 		l = k + 2;
2808 		for (j = (BYTE)CrawlTable[k]; j > 0; j--) {
2809 			tx = dx + CrawlTable[l - 1];
2810 			ty = dy + CrawlTable[l];
2811 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
2812 				mid = dMonster[tx][ty];
2813 				mid = mid > 0 ? mid - 1 : -(mid + 1);
2814 				if (mid > MAX_PLRS - 1 && monster[mid]._mAi != AI_DIABLO && monster[mid].MType->mtype != MT_NAKRUL) {
2815 					if (monster[mid]._mmode != MM_FADEIN && monster[mid]._mmode != MM_FADEOUT && monster[mid]._mmode != MM_CHARGE) {
2816 						j = -99;
2817 						i = 6;
2818 						missile[mi]._miVar1 = monster[mid]._mmode;
2819 						missile[mi]._miVar2 = mid;
2820 						monster[mid]._mmode = MM_STONE;
2821 						break;
2822 					}
2823 				}
2824 			}
2825 			l += 2;
2826 		}
2827 	}
2828 
2829 	if (j != -99) {
2830 		missile[mi]._miDelFlag = TRUE;
2831 	} else {
2832 		missile[mi]._mix = tx;
2833 		missile[mi]._miy = ty;
2834 		missile[mi]._misx = missile[mi]._mix;
2835 		missile[mi]._misy = missile[mi]._miy;
2836 		missile[mi]._mirange = missile[mi]._mispllvl + 6;
2837 		missile[mi]._mirange += (missile[mi]._mirange * plr[id]._pISplDur) >> 7;
2838 
2839 		if (missile[mi]._mirange > 15)
2840 			missile[mi]._mirange = 15;
2841 		missile[mi]._mirange <<= 4;
2842 		UseMana(id, SPL_STONE);
2843 	}
2844 }
2845 
2846 void AddGolem(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2847 {
2848 	int i;
2849 	int mx;
2850 
2851 	missile[mi]._miDelFlag = FALSE;
2852 	for (i = 0; i < nummissiles; i++) {
2853 		mx = missileactive[i];
2854 		if (missile[mx]._mitype == MIS_GOLEM) {
2855 			if (mx != mi && missile[mx]._misource == id) {
2856 				missile[mi]._miDelFlag = TRUE;
2857 				return;
2858 			}
2859 		}
2860 	}
2861 	missile[mi]._miVar1 = sx;
2862 	missile[mi]._miVar2 = sy;
2863 	missile[mi]._miVar4 = dx;
2864 	missile[mi]._miVar5 = dy;
2865 	if ((monster[id]._mx != 1 || monster[id]._my) && id == myplr)
2866 		M_StartKill(id, id);
2867 	UseMana(id, SPL_GOLEM);
2868 }
2869 
2870 void AddEtherealize(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2871 {
2872 	int i;
2873 
2874 	missile[mi]._mirange = 16 * plr[id]._pLevel >> 1;
2875 	for (i = missile[mi]._mispllvl; i > 0; i--) {
2876 		missile[mi]._mirange += missile[mi]._mirange >> 3;
2877 	}
2878 	missile[mi]._mirange += missile[mi]._mirange * plr[id]._pISplDur >> 7;
2879 	missile[mi]._miVar1 = plr[id]._pHitPoints;
2880 	missile[mi]._miVar2 = plr[id]._pHPBase;
2881 	if (mienemy == TARGET_MONSTERS)
2882 		UseMana(id, SPL_ETHEREALIZE);
2883 }
2884 
2885 void AddDummy(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2886 {
2887 	missile[mi]._miDelFlag = TRUE;
2888 }
2889 
2890 void AddBlodbur(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2891 {
2892 	missile[mi]._midam = dam;
2893 	missile[mi]._mix = sx;
2894 	missile[mi]._miy = sy;
2895 	missile[mi]._misx = sx;
2896 	missile[mi]._misy = sy;
2897 	missile[mi]._misource = id;
2898 	if (dam == 1)
2899 		SetMissDir(mi, 0);
2900 	else
2901 		SetMissDir(mi, 1);
2902 	missile[mi]._miLightFlag = TRUE;
2903 	missile[mi]._mirange = missile[mi]._miAnimLen;
2904 }
2905 
2906 void AddBoom(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2907 {
2908 	missile[mi]._mix = dx;
2909 	missile[mi]._miy = dy;
2910 	missile[mi]._misx = dx;
2911 	missile[mi]._misy = dy;
2912 	missile[mi]._mixvel = 0;
2913 	missile[mi]._miyvel = 0;
2914 	missile[mi]._midam = dam;
2915 	missile[mi]._mirange = missile[mi]._miAnimLen;
2916 	missile[mi]._miVar1 = 0;
2917 }
2918 
2919 void AddHeal(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2920 {
2921 	int i;
2922 	int HealAmount;
2923 
2924 	HealAmount = (random_(57, 10) + 1) << 6;
2925 	for (i = 0; i < plr[id]._pLevel; i++) {
2926 		HealAmount += (random_(57, 4) + 1) << 6;
2927 	}
2928 	for (i = 0; i < missile[mi]._mispllvl; i++) {
2929 		HealAmount += (random_(57, 6) + 1) << 6;
2930 	}
2931 
2932 	if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARBARIAN || plr[id]._pClass == PC_MONK)
2933 		HealAmount <<= 1;
2934 	else if (plr[id]._pClass == PC_ROGUE || plr[id]._pClass == PC_BARD)
2935 		HealAmount += HealAmount >> 1;
2936 
2937 	plr[id]._pHitPoints += HealAmount;
2938 	if (plr[id]._pHitPoints > plr[id]._pMaxHP)
2939 		plr[id]._pHitPoints = plr[id]._pMaxHP;
2940 
2941 	plr[id]._pHPBase += HealAmount;
2942 	if (plr[id]._pHPBase > plr[id]._pMaxHPBase)
2943 		plr[id]._pHPBase = plr[id]._pMaxHPBase;
2944 
2945 	UseMana(id, SPL_HEAL);
2946 	missile[mi]._miDelFlag = TRUE;
2947 	drawhpflag = TRUE;
2948 }
2949 
2950 void AddHealOther(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2951 {
2952 	missile[mi]._miDelFlag = TRUE;
2953 	UseMana(id, SPL_HEALOTHER);
2954 	if (id == myplr) {
2955 		SetCursor_(CURSOR_HEALOTHER);
2956 		if (sgbControllerActive)
2957 			TryIconCurs();
2958 	}
2959 }
2960 
2961 void AddElement(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2962 {
2963 	int i;
2964 
2965 	if (sx == dx && sy == dy) {
2966 		dx += XDirAdd[midir];
2967 		dy += YDirAdd[midir];
2968 	}
2969 	missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4;
2970 	for (i = missile[mi]._mispllvl; i > 0; i--) {
2971 		missile[mi]._midam += missile[mi]._midam >> 3;
2972 	}
2973 	missile[mi]._midam >>= 1;
2974 	GetMissileVel(mi, sx, sy, dx, dy, 16);
2975 	SetMissDir(mi, GetDirection8(sx, sy, dx, dy));
2976 	missile[mi]._mirange = 256;
2977 	missile[mi]._miVar1 = sx;
2978 	missile[mi]._miVar2 = sy;
2979 	missile[mi]._miVar3 = 0;
2980 	missile[mi]._miVar4 = dx;
2981 	missile[mi]._miVar5 = dy;
2982 	missile[mi]._mlid = AddLight(sx, sy, 8);
2983 	UseMana(id, SPL_ELEMENT);
2984 }
2985 
2986 extern void FocusOnInventory();
2987 
2988 void AddIdentify(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
2989 {
2990 	missile[mi]._miDelFlag = TRUE;
2991 	UseMana(id, SPL_IDENTIFY);
2992 	if (id == myplr) {
2993 		if (sbookflag)
2994 			sbookflag = FALSE;
2995 		if (!invflag) {
2996 			invflag = TRUE;
2997 			if (sgbControllerActive)
2998 				FocusOnInventory();
2999 		}
3000 		SetCursor_(CURSOR_IDENTIFY);
3001 	}
3002 }
3003 
3004 void AddFirewallC(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3005 {
3006 	int i, j, k, tx, ty, pn;
3007 
3008 	missile[mi]._miDelFlag = TRUE;
3009 	for (i = 0; i < 6; i++) {
3010 		k = CrawlNum[i];
3011 		pn = k + 2;
3012 		for (j = (BYTE)CrawlTable[k]; j > 0; j--) {
3013 			tx = dx + CrawlTable[pn - 1];
3014 			ty = dy + CrawlTable[pn];
3015 			if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) {
3016 				k = dPiece[tx][ty];
3017 				if (LineClear(sx, sy, tx, ty)) {
3018 					if ((sx != tx || sy != ty) && (nSolidTable[k] | dObject[tx][ty]) == 0) {
3019 						missile[mi]._miVar1 = tx;
3020 						missile[mi]._miVar2 = ty;
3021 						missile[mi]._miVar5 = tx;
3022 						missile[mi]._miVar6 = ty;
3023 						missile[mi]._miDelFlag = FALSE;
3024 						i = 6;
3025 						break;
3026 					}
3027 				}
3028 			}
3029 			pn += 2;
3030 		}
3031 	}
3032 
3033 	if (missile[mi]._miDelFlag != TRUE) {
3034 		missile[mi]._miVar7 = 0;
3035 		missile[mi]._miVar8 = 0;
3036 		missile[mi]._miVar3 = (midir - 2) & 7;
3037 		missile[mi]._miVar4 = (midir + 2) & 7;
3038 		missile[mi]._mirange = 7;
3039 		UseMana(id, SPL_FIREWALL);
3040 	}
3041 }
3042 
3043 void AddInfra(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3044 {
3045 	int i;
3046 
3047 	missile[mi]._mirange = 1584;
3048 	for (i = missile[mi]._mispllvl; i > 0; i--) {
3049 		missile[mi]._mirange += missile[mi]._mirange >> 3;
3050 	}
3051 	missile[mi]._mirange += missile[mi]._mirange * plr[id]._pISplDur >> 7;
3052 	if (mienemy == TARGET_MONSTERS)
3053 		UseMana(id, SPL_INFRA);
3054 }
3055 
3056 void AddWave(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3057 {
3058 	missile[mi]._miVar1 = dx;
3059 	missile[mi]._miVar2 = dy;
3060 	missile[mi]._miVar3 = 0;
3061 	missile[mi]._miVar4 = 0;
3062 	missile[mi]._mirange = 1;
3063 	missile[mi]._miAnimFrame = 4;
3064 	UseMana(id, SPL_WAVE);
3065 }
3066 
3067 void AddNova(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3068 {
3069 	int k;
3070 
3071 	missile[mi]._miVar1 = dx;
3072 	missile[mi]._miVar2 = dy;
3073 	if (id != -1) {
3074 		missile[mi]._midam = (random_(66, 6) + random_(66, 6) + random_(66, 6) + random_(66, 6) + random_(66, 6));
3075 		missile[mi]._midam += plr[id]._pLevel + 5;
3076 		missile[mi]._midam >>= 1;
3077 		for (k = missile[mi]._mispllvl; k > 0; k--) {
3078 			missile[mi]._midam += missile[mi]._midam >> 3;
3079 		}
3080 		if (mienemy == TARGET_MONSTERS)
3081 			UseMana(id, SPL_NOVA);
3082 	} else {
3083 		missile[mi]._midam = ((DWORD)currlevel >> 1) + random_(66, 3) + random_(66, 3) + random_(66, 3);
3084 	}
3085 	missile[mi]._mirange = 1;
3086 }
3087 
3088 void AddBlodboil(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3089 {
3090 	if (id == -1 || plr[id]._pSpellFlags & 6 || plr[id]._pHitPoints <= plr[id]._pLevel << 6) {
3091 		missile[mi]._miDelFlag = TRUE;
3092 	} else {
3093 		int blodboilSFX[NUM_CLASSES] = {
3094 			PS_WARR70,
3095 			PS_ROGUE70,
3096 			PS_MAGE70,
3097 			PS_MONK70, // BUGFIX: PS_MONK70? (fixed)
3098 			PS_ROGUE70,
3099 			PS_WARR70
3100 		};
3101 		UseMana(id, 22);
3102 		missile[mi]._miVar1 = id;
3103 		int tmp = 3 * plr[id]._pLevel;
3104 		tmp <<= 7;
3105 		plr[id]._pSpellFlags |= 2u;
3106 		missile[mi]._miVar2 = tmp;
3107 		int lvl = 2;
3108 		if (id > -1)
3109 			lvl = plr[id]._pLevel * 2;
3110 		missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245;
3111 		CalcPlrItemVals(id, TRUE);
3112 		force_redraw = 255;
3113 		PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py);
3114 	}
3115 }
3116 
3117 void AddRepair(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3118 {
3119 	missile[mi]._miDelFlag = TRUE;
3120 	UseMana(id, SPL_REPAIR);
3121 	if (id == myplr) {
3122 		if (sbookflag)
3123 			sbookflag = FALSE;
3124 		if (!invflag) {
3125 			invflag = TRUE;
3126 			if (sgbControllerActive)
3127 				FocusOnInventory();
3128 		}
3129 		SetCursor_(CURSOR_REPAIR);
3130 	}
3131 }
3132 
3133 void AddRecharge(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3134 {
3135 	missile[mi]._miDelFlag = TRUE;
3136 	UseMana(id, SPL_RECHARGE);
3137 	if (id == myplr) {
3138 		if (sbookflag)
3139 			sbookflag = FALSE;
3140 		if (!invflag) {
3141 			invflag = TRUE;
3142 			if (sgbControllerActive)
3143 				FocusOnInventory();
3144 		}
3145 		SetCursor_(CURSOR_RECHARGE);
3146 	}
3147 }
3148 
3149 void AddDisarm(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3150 {
3151 	missile[mi]._miDelFlag = TRUE;
3152 	UseMana(id, SPL_DISARM);
3153 	if (id == myplr) {
3154 		SetCursor_(CURSOR_DISARM);
3155 		if (sgbControllerActive) {
3156 			if (pcursobj != -1)
3157 				NetSendCmdLocParam1(true, CMD_DISARMXY, cursmx, cursmy, pcursobj);
3158 			else
3159 				SetCursor_(CURSOR_HAND);
3160 		}
3161 	}
3162 }
3163 
3164 void AddApoca(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3165 {
3166 	int i;
3167 
3168 	missile[mi]._miVar1 = 8;
3169 	missile[mi]._miVar2 = sy - missile[mi]._miVar1;
3170 	missile[mi]._miVar3 = missile[mi]._miVar1 + sy;
3171 	missile[mi]._miVar4 = sx - missile[mi]._miVar1;
3172 	missile[mi]._miVar5 = missile[mi]._miVar1 + sx;
3173 	missile[mi]._miVar6 = missile[mi]._miVar4;
3174 	if (missile[mi]._miVar2 <= 0)
3175 		missile[mi]._miVar2 = 1;
3176 	if (missile[mi]._miVar3 >= MAXDUNY)
3177 		missile[mi]._miVar3 = MAXDUNY - 1;
3178 	if (missile[mi]._miVar4 <= 0)
3179 		missile[mi]._miVar4 = 1;
3180 	if (missile[mi]._miVar5 >= MAXDUNX)
3181 		missile[mi]._miVar5 = MAXDUNX - 1;
3182 	for (i = 0; i < plr[id]._pLevel; i++) {
3183 		missile[mi]._midam += random_(67, 6) + 1;
3184 	}
3185 	missile[mi]._mirange = 255;
3186 	missile[mi]._miDelFlag = FALSE;
3187 	UseMana(id, SPL_APOCA);
3188 }
3189 
3190 void AddFlame(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3191 {
3192 	int i;
3193 
3194 	missile[mi]._miVar2 = 0;
3195 	for (i = dam; i > 0; i--) {
3196 		missile[mi]._miVar2 += 5;
3197 	}
3198 	missile[mi]._misx = dx;
3199 	missile[mi]._misy = dy;
3200 	missile[mi]._mixoff = missile[midir]._mixoff;
3201 	missile[mi]._miyoff = missile[midir]._miyoff;
3202 	missile[mi]._mitxoff = missile[midir]._mitxoff;
3203 	missile[mi]._mityoff = missile[midir]._mityoff;
3204 	missile[mi]._mirange = missile[mi]._miVar2 + 20;
3205 	missile[mi]._mlid = AddLight(sx, sy, 1);
3206 	if (mienemy == TARGET_MONSTERS) {
3207 		i = random_(79, plr[id]._pLevel) + random_(79, 2);
3208 		missile[mi]._midam = 8 * i + 16 + ((8 * i + 16) >> 1);
3209 	} else {
3210 		missile[mi]._midam = monster[id].mMinDamage + random_(77, monster[id].mMaxDamage - monster[id].mMinDamage + 1);
3211 	}
3212 }
3213 
3214 void AddFlamec(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3215 {
3216 	if (sx == dx && sy == dy) {
3217 		dx += XDirAdd[midir];
3218 		dy += YDirAdd[midir];
3219 	}
3220 	GetMissileVel(mi, sx, sy, dx, dy, 32);
3221 	if (mienemy == TARGET_MONSTERS)
3222 		UseMana(id, SPL_FLAME);
3223 	missile[mi]._miVar1 = sx;
3224 	missile[mi]._miVar2 = sy;
3225 	missile[mi]._miVar3 = 0;
3226 	missile[mi]._mirange = 256;
3227 }
3228 
3229 void AddCbolt(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 micaster, Sint32 id, Sint32 dam)
3230 {
3231 	assert((DWORD)mi < MAXMISSILES);
3232 
3233 	if (micaster == 0) {
3234 		if (id == myplr) {
3235 			missile[mi]._mirnd = random_(63, 15) + 1;
3236 			missile[mi]._midam = random_(68, plr[id]._pMagic >> 2) + 1;
3237 		} else {
3238 			missile[mi]._mirnd = random_(63, 15) + 1;
3239 			missile[mi]._midam = random_(68, plr[id]._pMagic >> 2) + 1;
3240 		}
3241 	} else {
3242 		missile[mi]._mirnd = random_(63, 15) + 1;
3243 		missile[mi]._midam = 15;
3244 	}
3245 
3246 	if (sx == dx && sy == dy) {
3247 		dx += XDirAdd[midir];
3248 		dy += YDirAdd[midir];
3249 	}
3250 
3251 	missile[mi]._miAnimFrame = random_(63, 8) + 1;
3252 	missile[mi]._mlid = AddLight(sx, sy, 5);
3253 
3254 	GetMissileVel(mi, sx, sy, dx, dy, 8);
3255 	missile[mi]._miVar1 = 5;
3256 	missile[mi]._miVar2 = midir;
3257 	missile[mi]._miVar3 = 0;
3258 	missile[mi]._mirange = 256;
3259 }
3260 
3261 void AddHbolt(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 micaster, Sint32 id, Sint32 dam)
3262 {
3263 	int sp;
3264 
3265 	if (sx == dx && sy == dy) {
3266 		dx += XDirAdd[midir];
3267 		dy += YDirAdd[midir];
3268 	}
3269 	if (id != -1) {
3270 		sp = 2 * missile[mi]._mispllvl + 16;
3271 		if (sp >= 63) {
3272 			sp = 63;
3273 		}
3274 	} else {
3275 		sp = 16;
3276 	}
3277 	GetMissileVel(mi, sx, sy, dx, dy, sp);
3278 	SetMissDir(mi, GetDirection16(sx, sy, dx, dy));
3279 	missile[mi]._mirange = 256;
3280 	missile[mi]._miVar1 = sx;
3281 	missile[mi]._miVar2 = sy;
3282 	missile[mi]._mlid = AddLight(sx, sy, 8);
3283 	missile[mi]._midam = random_(69, 10) + plr[id]._pLevel + 9;
3284 	UseMana(id, SPL_HBOLT);
3285 }
3286 
3287 void AddResurrect(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3288 {
3289 	UseMana(id, SPL_RESURRECT);
3290 	if (id == myplr) {
3291 		SetCursor_(CURSOR_RESURRECT);
3292 		if (sgbControllerActive)
3293 			TryIconCurs();
3294 	}
3295 	missile[mi]._miDelFlag = TRUE;
3296 }
3297 
3298 void AddResurrectBeam(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3299 {
3300 	missile[mi]._mix = dx;
3301 	missile[mi]._miy = dy;
3302 	missile[mi]._misx = missile[mi]._mix;
3303 	missile[mi]._misy = missile[mi]._miy;
3304 	missile[mi]._mixvel = 0;
3305 	missile[mi]._miyvel = 0;
3306 	missile[mi]._mirange = misfiledata[MFILE_RESSUR1].mAnimLen[0];
3307 }
3308 
3309 void AddTelekinesis(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3310 {
3311 	missile[mi]._miDelFlag = TRUE;
3312 	UseMana(id, SPL_TELEKINESIS);
3313 	if (id == myplr)
3314 		SetCursor_(CURSOR_TELEKINESIS);
3315 }
3316 
3317 void AddBoneSpirit(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3318 {
3319 	if (sx == dx && sy == dy) {
3320 		dx = XDirAdd[midir] + dx;
3321 		dy = YDirAdd[midir] + dy;
3322 	}
3323 	missile[mi]._midam = 0;
3324 	GetMissileVel(mi, sx, sy, dx, dy, 16);
3325 	SetMissDir(mi, GetDirection8(sx, sy, dx, dy));
3326 	missile[mi]._mirange = 256;
3327 	missile[mi]._miVar1 = sx;
3328 	missile[mi]._miVar2 = sy;
3329 	missile[mi]._miVar3 = 0;
3330 	missile[mi]._miVar4 = dx;
3331 	missile[mi]._miVar5 = dy;
3332 	missile[mi]._mlid = AddLight(sx, sy, 8);
3333 	if (mienemy == TARGET_MONSTERS) {
3334 		UseMana(id, SPL_BONESPIRIT);
3335 		plr[id]._pHitPoints -= 384;
3336 		plr[id]._pHPBase -= 384;
3337 		drawhpflag = TRUE;
3338 		if (plr[id]._pHitPoints <= 0)
3339 			SyncPlrKill(id, 0);
3340 	}
3341 }
3342 
3343 void AddRportal(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3344 {
3345 	missile[mi]._mix = sx;
3346 	missile[mi]._miy = sy;
3347 	missile[mi]._misx = sx;
3348 	missile[mi]._misy = sy;
3349 	missile[mi]._mirange = 100;
3350 	missile[mi]._miVar1 = 100 - missile[mi]._miAnimLen;
3351 	missile[mi]._miVar2 = 0;
3352 	PutMissile(mi);
3353 }
3354 
3355 void AddDiabApoca(Sint32 mi, Sint32 sx, Sint32 sy, Sint32 dx, Sint32 dy, Sint32 midir, Sint8 mienemy, Sint32 id, Sint32 dam)
3356 {
3357 	int pnum;
3358 
3359 	int players = gbIsMultiplayer ? MAX_PLRS : 1;
3360 	for (pnum = 0; pnum < players; pnum++) {
3361 		if (plr[pnum].plractive) {
3362 			if (LineClear(sx, sy, plr[pnum]._pfutx, plr[pnum]._pfuty)) {
3363 				AddMissile(0, 0, plr[pnum]._pfutx, plr[pnum]._pfuty, 0, MIS_BOOM2, mienemy, id, dam, 0);
3364 			}
3365 		}
3366 	}
3367 	missile[mi]._miDelFlag = TRUE;
3368 }
3369 
3370 int AddMissile(int sx, int sy, int dx, int dy, int midir, int mitype, char micaster, int id, int midam, int spllvl)
3371 {
3372 	int i, mi;
3373 
3374 	if (nummissiles >= MAXMISSILES - 1)
3375 		return -1;
3376 
3377 	if (mitype == MIS_MANASHIELD && plr[id].pManaShield == TRUE) {
3378 		if (currlevel != plr[id].plrlevel)
3379 			return -1;
3380 
3381 		for (i = 0; i < nummissiles; i++) {
3382 			mi = missileactive[i];
3383 			if (missile[mi]._mitype == MIS_MANASHIELD && missile[mi]._misource == id)
3384 				return -1;
3385 		}
3386 	}
3387 
3388 	mi = missileavail[0];
3389 
3390 	missileavail[0] = missileavail[MAXMISSILES - nummissiles - 1];
3391 	missileactive[nummissiles] = mi;
3392 	nummissiles++;
3393 
3394 	memset(&missile[mi], 0, sizeof(*missile));
3395 
3396 	missile[mi]._mitype = mitype;
3397 	missile[mi]._micaster = micaster;
3398 	missile[mi]._misource = id;
3399 	missile[mi]._miAnimType = missiledata[mitype].mFileNum;
3400 	missile[mi]._miDrawFlag = missiledata[mitype].mDraw;
3401 	missile[mi]._mispllvl = spllvl;
3402 	missile[mi]._mimfnum = midir;
3403 
3404 	if (missile[mi]._miAnimType == MFILE_NONE || misfiledata[missile[mi]._miAnimType].mAnimFAmt < 8)
3405 		SetMissDir(mi, 0);
3406 	else
3407 		SetMissDir(mi, midir);
3408 
3409 	missile[mi]._mix = sx;
3410 	missile[mi]._miy = sy;
3411 	missile[mi]._mixoff = 0;
3412 	missile[mi]._miyoff = 0;
3413 	missile[mi]._misx = sx;
3414 	missile[mi]._misy = sy;
3415 	missile[mi]._mitxoff = 0;
3416 	missile[mi]._mityoff = 0;
3417 	missile[mi]._miDelFlag = FALSE;
3418 	missile[mi]._miAnimAdd = 1;
3419 	missile[mi]._miLightFlag = FALSE;
3420 	missile[mi]._miPreFlag = FALSE;
3421 	missile[mi]._miUniqTrans = 0;
3422 	missile[mi]._midam = midam;
3423 	missile[mi]._miHitFlag = FALSE;
3424 	missile[mi]._midist = 0;
3425 	missile[mi]._mlid = NO_LIGHT;
3426 	missile[mi]._mirnd = 0;
3427 
3428 	if (missiledata[mitype].mlSFX != -1) {
3429 		PlaySfxLoc(missiledata[mitype].mlSFX, missile[mi]._misx, missile[mi]._misy);
3430 	}
3431 
3432 	missiledata[mitype].mAddProc(mi, sx, sy, dx, dy, midir, micaster, id, midam);
3433 
3434 	return mi;
3435 }
3436 
3437 int Sentfire(int i, int sx, int sy)
3438 {
3439 	int ex, dir;
3440 
3441 	ex = 0;
3442 	if (LineClear(missile[i]._mix, missile[i]._miy, sx, sy)) {
3443 		if (dMonster[sx][sy] > 0 && monster[dMonster[sx][sy] - 1]._mhitpoints >> 6 > 0 && dMonster[sx][sy] - 1 > MAX_PLRS - 1) {
3444 			dir = GetDirection(missile[i]._mix, missile[i]._miy, sx, sy);
3445 			missile[i]._miVar3 = missileavail[0];
3446 			AddMissile(missile[i]._mix, missile[i]._miy, sx, sy, dir, MIS_FIREBOLT, TARGET_MONSTERS, missile[i]._misource, missile[i]._midam, GetSpellLevel(missile[i]._misource, SPL_FIREBOLT));
3447 			ex = -1;
3448 		}
3449 	}
3450 	if (ex == -1) {
3451 		SetMissDir(i, 2);
3452 		missile[i]._miVar2 = 3;
3453 	}
3454 
3455 	return ex;
3456 }
3457 
3458 void MI_Dummy(Sint32 i)
3459 {
3460 	return;
3461 }
3462 
3463 void MI_Golem(Sint32 i)
3464 {
3465 	int tx, ty, dp, l, m, src, k, tid;
3466 	const char *ct;
3467 
3468 	src = missile[i]._misource;
3469 	if (monster[src]._mx == 1 && !monster[src]._my) {
3470 		for (l = 0; l < 6; l++) {
3471 			k = CrawlNum[l];
3472 			tid = k + 2;
3473 			for (m = (BYTE)CrawlTable[k]; m > 0; m--) {
3474 				ct = &CrawlTable[tid];
3475 				tx = missile[i]._miVar4 + *(ct - 1);
3476 				ty = missile[i]._miVar5 + *ct;
3477 				if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) {
3478 					dp = dPiece[tx][ty];
3479 					if (LineClear(missile[i]._miVar1, missile[i]._miVar2, tx, ty)) {
3480 						if ((dMonster[tx][ty] | nSolidTable[dp] | dObject[tx][ty]) == 0) {
3481 							l = 6;
3482 							SpawnGolum(src, tx, ty, i);
3483 							break;
3484 						}
3485 					}
3486 				}
3487 				tid += 2;
3488 			}
3489 		}
3490 	}
3491 	missile[i]._miDelFlag = TRUE;
3492 }
3493 
3494 void MI_SetManashield(Sint32 i)
3495 {
3496 	ManashieldFlag = true;
3497 }
3498 
3499 void MI_LArrow(Sint32 i)
3500 {
3501 	int p, mind, maxd, rst;
3502 
3503 	missile[i]._mirange--;
3504 	p = missile[i]._misource;
3505 	if (missile[i]._miAnimType == MFILE_MINILTNG || missile[i]._miAnimType == MFILE_MAGBLOS) {
3506 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame + 5);
3507 		rst = missiledata[missile[i]._mitype].mResist;
3508 		if (missile[i]._mitype == MIS_LARROW) {
3509 			if (p != -1) {
3510 				mind = plr[p]._pILMinDam;
3511 				maxd = plr[p]._pILMaxDam;
3512 			} else {
3513 				mind = random_(68, 10) + 1 + currlevel;
3514 				maxd = random_(68, 10) + 1 + currlevel * 2;
3515 			}
3516 			missiledata[MIS_LARROW].mResist = MISR_LIGHTNING;
3517 			CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE);
3518 		}
3519 		if (missile[i]._mitype == MIS_FARROW) {
3520 			if (p != -1) {
3521 				mind = plr[p]._pIFMinDam;
3522 				maxd = plr[p]._pIFMaxDam;
3523 			} else {
3524 				mind = random_(68, 10) + 1 + currlevel;
3525 				maxd = random_(68, 10) + 1 + currlevel * 2;
3526 			}
3527 			missiledata[MIS_FARROW].mResist = MISR_FIRE;
3528 			CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE);
3529 		}
3530 		missiledata[missile[i]._mitype].mResist = rst;
3531 	} else {
3532 		missile[i]._midist++;
3533 		missile[i]._mitxoff += missile[i]._mixvel;
3534 		missile[i]._mityoff += missile[i]._miyvel;
3535 		GetMissilePos(i);
3536 
3537 		if (p != -1) {
3538 			if (missile[i]._micaster == TARGET_MONSTERS) {
3539 				mind = plr[p]._pIMinDam;
3540 				maxd = plr[p]._pIMaxDam;
3541 			} else {
3542 				mind = monster[p].mMinDamage;
3543 				maxd = monster[p].mMaxDamage;
3544 			}
3545 		} else {
3546 			mind = random_(68, 10) + 1 + currlevel;
3547 			maxd = random_(68, 10) + 1 + currlevel * 2;
3548 		}
3549 
3550 		if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) {
3551 			rst = missiledata[missile[i]._mitype].mResist;
3552 			missiledata[missile[i]._mitype].mResist = 0;
3553 			CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
3554 			missiledata[missile[i]._mitype].mResist = rst;
3555 		}
3556 		if (missile[i]._mirange == 0) {
3557 			missile[i]._mimfnum = 0;
3558 			missile[i]._mitxoff -= missile[i]._mixvel;
3559 			missile[i]._mityoff -= missile[i]._miyvel;
3560 			GetMissilePos(i);
3561 			if (missile[i]._mitype == MIS_LARROW)
3562 				SetMissAnim(i, MFILE_MINILTNG);
3563 			else
3564 				SetMissAnim(i, MFILE_MAGBLOS);
3565 			missile[i]._mirange = missile[i]._miAnimLen - 1;
3566 		} else {
3567 			if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
3568 				missile[i]._miVar1 = missile[i]._mix;
3569 				missile[i]._miVar2 = missile[i]._miy;
3570 				ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 5);
3571 			}
3572 		}
3573 	}
3574 	if (missile[i]._mirange == 0) {
3575 		missile[i]._miDelFlag = TRUE;
3576 		AddUnLight(missile[i]._mlid);
3577 	}
3578 	PutMissile(i);
3579 }
3580 
3581 void MI_Arrow(Sint32 i)
3582 {
3583 	int p, mind, maxd;
3584 
3585 	missile[i]._mirange--;
3586 	missile[i]._midist++;
3587 	missile[i]._mitxoff += missile[i]._mixvel;
3588 	missile[i]._mityoff += missile[i]._miyvel;
3589 	GetMissilePos(i);
3590 	p = missile[i]._misource;
3591 	if (p != -1) {
3592 		if (missile[i]._micaster == TARGET_MONSTERS) {
3593 			mind = plr[p]._pIMinDam;
3594 			maxd = plr[p]._pIMaxDam;
3595 		} else {
3596 			mind = monster[p].mMinDamage;
3597 			maxd = monster[p].mMaxDamage;
3598 		}
3599 	} else {
3600 		mind = currlevel;
3601 		maxd = 2 * currlevel;
3602 	}
3603 	if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy)
3604 		CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
3605 	if (missile[i]._mirange == 0)
3606 		missile[i]._miDelFlag = TRUE;
3607 	PutMissile(i);
3608 }
3609 
3610 void MI_Firebolt(Sint32 i)
3611 {
3612 	int omx, omy;
3613 	int d, p;
3614 
3615 	missile[i]._mirange--;
3616 	if (missile[i]._mitype != MIS_BONESPIRIT || missile[i]._mimfnum != 8) {
3617 		omx = missile[i]._mitxoff;
3618 		omy = missile[i]._mityoff;
3619 		missile[i]._mitxoff += missile[i]._mixvel;
3620 		missile[i]._mityoff += missile[i]._miyvel;
3621 		GetMissilePos(i);
3622 		p = missile[i]._misource;
3623 		if (p != -1) {
3624 			if (missile[i]._micaster == TARGET_MONSTERS) {
3625 				switch (missile[i]._mitype) {
3626 				case MIS_FIREBOLT:
3627 					d = random_(75, 10) + (plr[p]._pMagic >> 3) + missile[i]._mispllvl + 1;
3628 					break;
3629 				case MIS_FLARE:
3630 					d = 3 * missile[i]._mispllvl - (plr[p]._pMagic >> 3) + (plr[p]._pMagic >> 1);
3631 					break;
3632 				case MIS_BONESPIRIT:
3633 					d = 0;
3634 					break;
3635 				}
3636 			} else {
3637 				d = monster[p].mMinDamage + random_(77, monster[p].mMaxDamage - monster[p].mMinDamage + 1);
3638 			}
3639 		} else {
3640 			d = currlevel + random_(78, 2 * currlevel);
3641 		}
3642 		if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) {
3643 			CheckMissileCol(i, d, d, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
3644 		}
3645 		if (missile[i]._mirange == 0) {
3646 			missile[i]._miDelFlag = TRUE;
3647 			missile[i]._mitxoff = omx;
3648 			missile[i]._mityoff = omy;
3649 			GetMissilePos(i);
3650 			switch (missile[i]._mitype) {
3651 			case MIS_FIREBOLT:
3652 			case MIS_MAGMABALL:
3653 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP, missile[i]._micaster, missile[i]._misource, 0, 0);
3654 				break;
3655 			case MIS_FLARE:
3656 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP2, missile[i]._micaster, missile[i]._misource, 0, 0);
3657 				break;
3658 			case MIS_ACID:
3659 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP3, missile[i]._micaster, missile[i]._misource, 0, 0);
3660 				break;
3661 			case MIS_BONESPIRIT:
3662 				SetMissDir(i, 8);
3663 				missile[i]._mirange = 7;
3664 				missile[i]._miDelFlag = FALSE;
3665 				PutMissile(i);
3666 				return;
3667 			case MIS_LICH:
3668 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXORA1, missile[i]._micaster, missile[i]._misource, 0, 0);
3669 				break;
3670 			case MIS_PSYCHORB:
3671 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXBL2, missile[i]._micaster, missile[i]._misource, 0, 0);
3672 				break;
3673 			case MIS_NECROMORB:
3674 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXRED3, missile[i]._micaster, missile[i]._misource, 0, 0);
3675 				break;
3676 			case MIS_ARCHLICH:
3677 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXYEL2, missile[i]._micaster, missile[i]._misource, 0, 0);
3678 				break;
3679 			case MIS_BONEDEMON:
3680 				AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXBL3, missile[i]._micaster, missile[i]._misource, 0, 0);
3681 				break;
3682 			}
3683 			if (missile[i]._mlid != NO_LIGHT)
3684 				AddUnLight(missile[i]._mlid);
3685 			PutMissile(i);
3686 		} else {
3687 			if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
3688 				missile[i]._miVar1 = missile[i]._mix;
3689 				missile[i]._miVar2 = missile[i]._miy;
3690 				if (missile[i]._mlid != NO_LIGHT)
3691 					ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8);
3692 			}
3693 			PutMissile(i);
3694 		}
3695 	} else if (missile[i]._mirange == 0) {
3696 		if (missile[i]._mlid != NO_LIGHT)
3697 			AddUnLight(missile[i]._mlid);
3698 		missile[i]._miDelFlag = TRUE;
3699 		PlaySfxLoc(LS_BSIMPCT, missile[i]._mix, missile[i]._miy);
3700 		PutMissile(i);
3701 	} else
3702 		PutMissile(i);
3703 }
3704 
3705 void MI_Lightball(Sint32 i)
3706 {
3707 	int tx, ty, j, oi;
3708 	char obj;
3709 
3710 	tx = missile[i]._miVar1;
3711 	ty = missile[i]._miVar2;
3712 	missile[i]._mirange--;
3713 	missile[i]._mitxoff += missile[i]._mixvel;
3714 	missile[i]._mityoff += missile[i]._miyvel;
3715 	GetMissilePos(i);
3716 	j = missile[i]._mirange;
3717 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
3718 	if (missile[i]._miHitFlag == TRUE)
3719 		missile[i]._mirange = j;
3720 	obj = dObject[tx][ty];
3721 	if (obj && tx == missile[i]._mix && ty == missile[i]._miy) {
3722 		if (obj > 0) {
3723 			oi = obj - 1;
3724 		} else {
3725 			oi = -(obj + 1);
3726 		}
3727 		if (object[oi]._otype == OBJ_SHRINEL || object[oi]._otype == OBJ_SHRINER)
3728 			missile[i]._mirange = j;
3729 	}
3730 	if (missile[i]._mirange == 0)
3731 		missile[i]._miDelFlag = TRUE;
3732 	PutMissile(i);
3733 }
3734 
3735 void MI_Krull(Sint32 i)
3736 {
3737 	missile[i]._mirange--;
3738 	missile[i]._mitxoff += missile[i]._mixvel;
3739 	missile[i]._mityoff += missile[i]._miyvel;
3740 	GetMissilePos(i);
3741 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
3742 	if (missile[i]._mirange == 0)
3743 		missile[i]._miDelFlag = TRUE;
3744 	PutMissile(i);
3745 }
3746 
3747 void MI_Acidpud(Sint32 i)
3748 {
3749 	int range;
3750 
3751 	missile[i]._mirange--;
3752 	range = missile[i]._mirange;
3753 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE);
3754 	missile[i]._mirange = range;
3755 	if (range == 0) {
3756 		if (missile[i]._mimfnum != 0) {
3757 			missile[i]._miDelFlag = TRUE;
3758 		} else {
3759 			SetMissDir(i, 1);
3760 			missile[i]._mirange = missile[i]._miAnimLen;
3761 		}
3762 	}
3763 	PutMissile(i);
3764 }
3765 
3766 void MI_Firewall(Sint32 i)
3767 {
3768 	int ExpLight[14] = { 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 12 };
3769 
3770 	missile[i]._mirange--;
3771 	if (missile[i]._mirange == missile[i]._miVar1) {
3772 		SetMissDir(i, 1);
3773 		missile[i]._miAnimFrame = random_(83, 11) + 1;
3774 	}
3775 	if (missile[i]._mirange == missile[i]._miAnimLen - 1) {
3776 		SetMissDir(i, 0);
3777 		missile[i]._miAnimFrame = 13;
3778 		missile[i]._miAnimAdd = -1;
3779 	}
3780 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE);
3781 	if (missile[i]._mirange == 0) {
3782 		missile[i]._miDelFlag = TRUE;
3783 		AddUnLight(missile[i]._mlid);
3784 	}
3785 	if (missile[i]._mimfnum != 0 && missile[i]._mirange != 0 && missile[i]._miAnimAdd != -1 && missile[i]._miVar2 < 12) {
3786 		if (missile[i]._miVar2 == 0)
3787 			missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, ExpLight[0]);
3788 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]);
3789 		missile[i]._miVar2++;
3790 	}
3791 	PutMissile(i);
3792 }
3793 
3794 void MI_Fireball(Sint32 i)
3795 {
3796 	int dam, id, px, py, mx, my;
3797 
3798 	id = missile[i]._misource;
3799 	dam = missile[i]._midam;
3800 	missile[i]._mirange--;
3801 
3802 	if (missile[i]._micaster == TARGET_MONSTERS) {
3803 		px = plr[id]._px;
3804 		py = plr[id]._py;
3805 	} else {
3806 		px = monster[id]._mx;
3807 		py = monster[id]._my;
3808 	}
3809 
3810 	if (missile[i]._miAnimType == MFILE_BIGEXP) {
3811 		if (missile[i]._mirange == 0) {
3812 			missile[i]._miDelFlag = TRUE;
3813 			AddUnLight(missile[i]._mlid);
3814 		}
3815 	} else {
3816 		missile[i]._mitxoff += missile[i]._mixvel;
3817 		missile[i]._mityoff += missile[i]._miyvel;
3818 		GetMissilePos(i);
3819 		if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy)
3820 			CheckMissileCol(i, dam, dam, 0, missile[i]._mix, missile[i]._miy, 0);
3821 		if (missile[i]._mirange == 0) {
3822 			mx = missile[i]._mix;
3823 			my = missile[i]._miy;
3824 			ChangeLight(missile[i]._mlid, missile[i]._mix, my, missile[i]._miAnimFrame);
3825 			if (!CheckBlock(px, py, mx, my))
3826 				CheckMissileCol(i, dam, dam, 0, mx, my, 1);
3827 			if (!CheckBlock(px, py, mx, my + 1))
3828 				CheckMissileCol(i, dam, dam, 0, mx, my + 1, 1);
3829 			if (!CheckBlock(px, py, mx, my - 1))
3830 				CheckMissileCol(i, dam, dam, 0, mx, my - 1, 1);
3831 			if (!CheckBlock(px, py, mx + 1, my))
3832 				CheckMissileCol(i, dam, dam, 0, mx + 1, my, 1);
3833 			if (!CheckBlock(px, py, mx + 1, my - 1))
3834 				CheckMissileCol(i, dam, dam, 0, mx + 1, my - 1, 1);
3835 			if (!CheckBlock(px, py, mx + 1, my + 1))
3836 				CheckMissileCol(i, dam, dam, 0, mx + 1, my + 1, 1);
3837 			if (!CheckBlock(px, py, mx - 1, my))
3838 				CheckMissileCol(i, dam, dam, 0, mx - 1, my, 1);
3839 			if (!CheckBlock(px, py, mx - 1, my + 1))
3840 				CheckMissileCol(i, dam, dam, 0, mx - 1, my + 1, 1);
3841 			if (!CheckBlock(px, py, mx - 1, my - 1))
3842 				CheckMissileCol(i, dam, dam, 0, mx - 1, my - 1, 1);
3843 			if (!TransList[dTransVal[mx][my]]
3844 			    || (missile[i]._mixvel < 0 && ((TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]) || (TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])))) {
3845 				missile[i]._mix++;
3846 				missile[i]._miy++;
3847 				missile[i]._miyoff -= 32;
3848 			}
3849 			if (missile[i]._miyvel > 0
3850 			    && (TransList[dTransVal[mx + 1][my]] && nSolidTable[dPiece[mx + 1][my]]
3851 			        || TransList[dTransVal[mx - 1][my]] && nSolidTable[dPiece[mx - 1][my]])) {
3852 				missile[i]._miyoff -= 32;
3853 			}
3854 			if (missile[i]._mixvel > 0
3855 			    && (TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]
3856 			        || TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])) {
3857 				missile[i]._mixoff -= 32;
3858 			}
3859 			missile[i]._mimfnum = 0;
3860 			SetMissAnim(i, MFILE_BIGEXP);
3861 			missile[i]._mirange = missile[i]._miAnimLen - 1;
3862 		} else if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
3863 			missile[i]._miVar1 = missile[i]._mix;
3864 			missile[i]._miVar2 = missile[i]._miy;
3865 			ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8);
3866 		}
3867 	}
3868 
3869 	PutMissile(i);
3870 }
3871 
3872 void MI_HorkSpawn(Sint32 i)
3873 {
3874 	int t, j, k, tx, ty, dp;
3875 
3876 	missile[i]._mirange--;
3877 	CheckMissileCol(i, 0, 0, 0, missile[i]._mix, missile[i]._miy, 0);
3878 	if (missile[i]._mirange <= 0) {
3879 		missile[i]._miDelFlag = TRUE;
3880 		for (j = 0; j < 2; j++) {
3881 			k = CrawlNum[j] + 2;
3882 			for (t = CrawlTable[CrawlNum[j]]; t > 0; t--, k += 2) {
3883 				tx = missile[i]._mix + CrawlTable[k - 1];
3884 				ty = missile[i]._miy + CrawlTable[k];
3885 				if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
3886 					dp = dPiece[tx][ty];
3887 					if (!nSolidTable[dp] && dMonster[tx][ty] == 0 && dPlayer[tx][ty] == 0 && dObject[tx][ty] == 0) {
3888 						j = 6;
3889 						int mon = AddMonster(tx, ty, missile[i]._miVar1, 1, TRUE);
3890 						M_StartStand(mon, missile[i]._miVar1);
3891 						break;
3892 					}
3893 				}
3894 			}
3895 		}
3896 	} else {
3897 		missile[i]._midist++;
3898 		missile[i]._mitxoff += missile[i]._mixvel;
3899 		missile[i]._mityoff += missile[i]._miyvel;
3900 		GetMissilePos(i);
3901 	}
3902 	PutMissile(i);
3903 }
3904 
3905 void MI_Rune(Sint32 i)
3906 {
3907 	int mid, pid, dir, mx, my;
3908 
3909 	mx = missile[i]._mix;
3910 	my = missile[i]._miy;
3911 	mid = dMonster[mx][my];
3912 	pid = dPlayer[mx][my];
3913 	if (mid != 0 || pid != 0) {
3914 		if (mid != 0) {
3915 			if (mid > 0)
3916 				mid = mid - 1;
3917 			else
3918 				mid = -(mid + 1);
3919 			dir = GetDirection(missile[i]._mix, missile[i]._miy, monster[mid]._mx, monster[mid]._my);
3920 		} else {
3921 			if (pid > 0)
3922 				pid = pid - 1;
3923 			else
3924 				pid = -(pid + 1);
3925 			dir = GetDirection(missile[i]._mix, missile[i]._miy, plr[pid]._px, plr[pid]._py);
3926 		}
3927 		missile[i]._miDelFlag = TRUE;
3928 		AddUnLight(missile[i]._mlid);
3929 		AddMissile(mx, my, mx, my, dir, missile[i]._miVar1, TARGET_BOTH, missile[i]._misource, missile[i]._midam, missile[i]._mispllvl);
3930 	}
3931 	PutMissile(i);
3932 }
3933 
3934 void MI_LightningWall(Sint32 i)
3935 {
3936 	int range;
3937 
3938 	missile[i]._mirange--;
3939 	range = missile[i]._mirange;
3940 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 0);
3941 	if (missile[i]._miHitFlag == TRUE)
3942 		missile[i]._mirange = range;
3943 	if (missile[i]._mirange == 0)
3944 		missile[i]._miDelFlag = TRUE;
3945 	PutMissile(i);
3946 }
3947 
3948 void MI_HiveExplode(Sint32 i)
3949 {
3950 	missile[i]._mirange--;
3951 	if (missile[i]._mirange <= 0) {
3952 		missile[i]._miDelFlag = TRUE;
3953 		AddUnLight(missile[i]._mlid);
3954 	}
3955 	PutMissile(i);
3956 }
3957 
3958 void MI_Immolation(Sint32 i)
3959 {
3960 	int dam, id, px, py, mx, my, xof, yof;
3961 
3962 	id = missile[i]._misource;
3963 	dam = missile[i]._midam;
3964 
3965 	if (missile[i]._miVar7 < 0) {
3966 		int v = 2 * missile[i]._miVar6;
3967 		missile[i]._miVar6 = v;
3968 		missile[i]._miVar7 = v;
3969 		missile[i]._mimfnum--;
3970 		if (missile[i]._mimfnum < 0)
3971 			missile[i]._mimfnum = 7;
3972 	} else {
3973 		missile[i]._miVar7--;
3974 	}
3975 
3976 	switch (missile[i]._mimfnum) {
3977 	case DIR_S:
3978 		xof = missile[i]._mixvel;
3979 		yof = 0;
3980 		break;
3981 	case DIR_SW:
3982 		xof = missile[i]._mixvel;
3983 		yof = missile[i]._miyvel;
3984 		break;
3985 	case DIR_W:
3986 		xof = 0;
3987 		yof = missile[i]._miyvel;
3988 		break;
3989 	case DIR_NW:
3990 		xof = missile[i]._mixvel;
3991 		yof = missile[i]._miyvel;
3992 		break;
3993 	case DIR_N:
3994 		xof = missile[i]._mixvel;
3995 		yof = 0;
3996 		break;
3997 	case DIR_NE:
3998 		xof = missile[i]._mixvel;
3999 		yof = missile[i]._miyvel;
4000 		break;
4001 	case DIR_E:
4002 		xof = 0;
4003 		yof = missile[i]._miyvel;
4004 		break;
4005 	case DIR_SE:
4006 		xof = missile[i]._mixvel;
4007 		yof = missile[i]._miyvel;
4008 		break;
4009 	}
4010 	missile[i]._mirange--;
4011 
4012 	if (missile[i]._micaster == TARGET_MONSTERS) {
4013 		px = plr[id]._px;
4014 		py = plr[id]._py;
4015 	} else {
4016 		px = monster[id]._mx;
4017 		py = monster[id]._my;
4018 	}
4019 
4020 	if (missile[i]._miAnimType == MFILE_BIGEXP) {
4021 		if (missile[i]._mirange == 0) {
4022 			missile[i]._miDelFlag = TRUE;
4023 			AddUnLight(missile[i]._mlid);
4024 		}
4025 	} else {
4026 		missile[i]._mitxoff += xof;
4027 		missile[i]._mityoff += yof;
4028 		GetMissilePos(i);
4029 		if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy)
4030 			CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
4031 		if (missile[i]._mirange == 0) {
4032 			mx = missile[i]._mix;
4033 			my = missile[i]._miy;
4034 			ChangeLight(missile[i]._mlid, missile[i]._mix, my, missile[i]._miAnimFrame);
4035 			if (!CheckBlock(px, py, mx, my))
4036 				CheckMissileCol(i, dam, dam, FALSE, mx, my, TRUE);
4037 			if (!CheckBlock(px, py, mx, my + 1))
4038 				CheckMissileCol(i, dam, dam, FALSE, mx, my + 1, TRUE);
4039 			if (!CheckBlock(px, py, mx, my - 1))
4040 				CheckMissileCol(i, dam, dam, FALSE, mx, my - 1, TRUE);
4041 			if (!CheckBlock(px, py, mx + 1, my))
4042 				CheckMissileCol(i, dam, dam, FALSE, mx + 1, my, TRUE);
4043 			if (!CheckBlock(px, py, mx + 1, my - 1))
4044 				CheckMissileCol(i, dam, dam, FALSE, mx + 1, my - 1, TRUE);
4045 			if (!CheckBlock(px, py, mx + 1, my + 1))
4046 				CheckMissileCol(i, dam, dam, FALSE, mx + 1, my + 1, TRUE);
4047 			if (!CheckBlock(px, py, mx - 1, my))
4048 				CheckMissileCol(i, dam, dam, FALSE, mx - 1, my, TRUE);
4049 			if (!CheckBlock(px, py, mx - 1, my + 1))
4050 				CheckMissileCol(i, dam, dam, FALSE, mx - 1, my + 1, TRUE);
4051 			if (!CheckBlock(px, py, mx - 1, my - 1))
4052 				CheckMissileCol(i, dam, dam, FALSE, mx - 1, my - 1, TRUE);
4053 			if (!TransList[dTransVal[mx][my]]
4054 			    || (missile[i]._mixvel < 0 && ((TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]) || (TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])))) {
4055 				missile[i]._mix++;
4056 				missile[i]._miy++;
4057 				missile[i]._miyoff -= 32;
4058 			}
4059 			if (missile[i]._miyvel > 0
4060 			    && (TransList[dTransVal[mx + 1][my]] && nSolidTable[dPiece[mx + 1][my]]
4061 			        || TransList[dTransVal[mx - 1][my]] && nSolidTable[dPiece[mx - 1][my]])) {
4062 				missile[i]._miyoff -= 32;
4063 			}
4064 			if (missile[i]._mixvel > 0
4065 			    && (TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]
4066 			        || TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])) {
4067 				missile[i]._mixoff -= 32;
4068 			}
4069 			missile[i]._mimfnum = 0;
4070 			SetMissAnim(i, MFILE_BIGEXP);
4071 			missile[i]._mirange = missile[i]._miAnimLen - 1;
4072 		} else if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
4073 			missile[i]._miVar1 = missile[i]._mix;
4074 			missile[i]._miVar2 = missile[i]._miy;
4075 			ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8);
4076 		}
4077 		missile[i]._miDelFlag = TRUE;
4078 	}
4079 
4080 	PutMissile(i);
4081 }
4082 
4083 void MI_LightningArrow(Sint32 i)
4084 {
4085 	int pn, dam, mx, my;
4086 
4087 	missile[i]._mirange--;
4088 	missile[i]._mitxoff += missile[i]._mixvel;
4089 	missile[i]._mityoff += missile[i]._miyvel;
4090 	GetMissilePos(i);
4091 
4092 	mx = missile[i]._mix;
4093 	my = missile[i]._miy;
4094 	/// ASSERT: assert((DWORD)mx < MAXDUNX);
4095 	/// ASSERT: assert((DWORD)my < MAXDUNY);
4096 	pn = dPiece[mx][my];
4097 	/// ASSERT: assert((DWORD)pn <= MAXTILES);
4098 
4099 	if (missile[i]._misource == -1) {
4100 		if ((mx != missile[i]._misx || my != missile[i]._misy) && nMissileTable[pn]) {
4101 			missile[i]._mirange = 0;
4102 		}
4103 	} else if (nMissileTable[pn]) {
4104 		missile[i]._mirange = 0;
4105 	}
4106 
4107 	if (!nMissileTable[pn]) {
4108 		if ((mx != missile[i]._miVar1 || my != missile[i]._miVar2) && mx > 0 && my > 0 && mx < MAXDUNX && my < MAXDUNY) {
4109 			if (missile[i]._misource != -1) {
4110 				if (missile[i]._micaster == TARGET_PLAYERS
4111 				    && monster[missile[i]._misource].MType->mtype >= MT_STORM
4112 				    && monster[missile[i]._misource].MType->mtype <= MT_MAEL) {
4113 					AddMissile(
4114 					    missile[i]._mix,
4115 					    missile[i]._miy,
4116 					    missile[i]._misx,
4117 					    missile[i]._misy,
4118 					    i,
4119 					    MIS_LIGHTNING2,
4120 					    missile[i]._micaster,
4121 					    missile[i]._misource,
4122 					    missile[i]._midam,
4123 					    missile[i]._mispllvl);
4124 				} else {
4125 					AddMissile(
4126 					    missile[i]._mix,
4127 					    missile[i]._miy,
4128 					    missile[i]._misx,
4129 					    missile[i]._misy,
4130 					    i,
4131 					    MIS_LIGHTNING,
4132 					    missile[i]._micaster,
4133 					    missile[i]._misource,
4134 					    missile[i]._midam,
4135 					    missile[i]._mispllvl);
4136 				}
4137 			} else {
4138 				AddMissile(
4139 				    missile[i]._mix,
4140 				    missile[i]._miy,
4141 				    missile[i]._misx,
4142 				    missile[i]._misy,
4143 				    i,
4144 				    MIS_LIGHTNING,
4145 				    missile[i]._micaster,
4146 				    missile[i]._misource,
4147 				    missile[i]._midam,
4148 				    missile[i]._mispllvl);
4149 			}
4150 			missile[i]._miVar1 = missile[i]._mix;
4151 			missile[i]._miVar2 = missile[i]._miy;
4152 		}
4153 	}
4154 
4155 	if (missile[i]._mirange == 0 || mx <= 0 || my <= 0 || mx >= MAXDUNX || my > MAXDUNY) { // BUGFIX my >= MAXDUNY
4156 		missile[i]._miDelFlag = TRUE;
4157 	}
4158 }
4159 
4160 void MI_FlashFront(Sint32 i)
4161 {
4162 	int src;
4163 
4164 	src = missile[i]._misource;
4165 	if (missile[i]._micaster == TARGET_MONSTERS && src != -1) {
4166 		missile[i]._mix = plr[src]._px;
4167 		missile[i]._miy = plr[src]._py;
4168 		missile[i]._mitxoff = plr[src]._pxoff * 65536;
4169 		missile[i]._mityoff = plr[src]._pyoff * 65536;
4170 	}
4171 	missile[i]._mirange--;
4172 	if (missile[i]._mirange == 0) {
4173 		missile[i]._miDelFlag = TRUE;
4174 		if (missile[i]._micaster == TARGET_MONSTERS) {
4175 			src = missile[i]._misource;
4176 			if (src != -1)
4177 				plr[src]._pBaseToBlk -= 50;
4178 		}
4179 	}
4180 	PutMissile(i);
4181 }
4182 
4183 void MI_FlashBack(Sint32 i)
4184 {
4185 	if (missile[i]._micaster == TARGET_MONSTERS) {
4186 		if (missile[i]._misource != -1) {
4187 			missile[i]._mix = plr[missile[i]._misource]._pfutx;
4188 			missile[i]._miy = plr[missile[i]._misource]._pfuty;
4189 		}
4190 	}
4191 	missile[i]._mirange--;
4192 	if (missile[i]._mirange == 0)
4193 		missile[i]._miDelFlag = TRUE;
4194 	PutMissile(i);
4195 }
4196 
4197 void MI_Reflect(Sint32 i)
4198 {
4199 	int src;
4200 
4201 	src = missile[i]._misource;
4202 	missile[i]._mitxoff = plr[src]._pxoff * 65536;
4203 	missile[i]._mityoff = plr[src]._pyoff * 65536;
4204 	if (plr[src]._pmode == PM_WALK3) {
4205 		missile[i]._misx = plr[src]._pfutx + 2;
4206 		missile[i]._misy = plr[src]._pfuty - 1;
4207 	} else {
4208 		missile[i]._misx = plr[src]._px + 2;
4209 		missile[i]._misy = plr[src]._py - 1;
4210 	}
4211 	GetMissilePos(i);
4212 	if (plr[src]._pmode == PM_WALK3) {
4213 		if (plr[src]._pdir == DIR_W)
4214 			missile[i]._mix++;
4215 		else
4216 			missile[i]._miy++;
4217 	}
4218 	if (src != myplr && currlevel != plr[src].plrlevel)
4219 		missile[i]._miDelFlag = TRUE;
4220 	if (plr[src].wReflections <= 0) {
4221 		missile[i]._miDelFlag = TRUE;
4222 		NetSendCmd(TRUE, CMD_REFLECT);
4223 	}
4224 	PutMissile(i);
4225 }
4226 
4227 void MI_FireRing(Sint32 i)
4228 {
4229 	int src, tx, ty, dmg, k, j, dp, b;
4230 	BYTE lvl;
4231 
4232 	b = CrawlNum[3];
4233 	missile[i]._miDelFlag = 1;
4234 	src = missile[i]._micaster;
4235 	k = CrawlNum[3] + 1;
4236 	if (src > 0)
4237 		lvl = plr[src]._pLevel;
4238 	else
4239 		lvl = currlevel;
4240 	dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1;
4241 	for (j = CrawlTable[b]; j > 0; j--, k += 2) {
4242 		tx = missile[i]._miVar1 + CrawlTable[k - 1];
4243 		ty = missile[i]._miVar2 + CrawlTable[k];
4244 		if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
4245 			dp = dPiece[tx][ty];
4246 			if (!nSolidTable[dp] && dObject[tx][ty] == 0) {
4247 				if (LineClear(missile[i]._mix, missile[i]._miy, tx, ty)) {
4248 					if (nMissileTable[dp] || missile[i]._miVar8)
4249 						missile[i]._miVar8 = 1;
4250 					else
4251 						AddMissile(tx, ty, tx, ty, 0, MIS_FIREWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl);
4252 				}
4253 			}
4254 		}
4255 	}
4256 }
4257 
4258 void MI_LightningRing(Sint32 i)
4259 {
4260 	int src, tx, ty, dmg, k, j, dp, b;
4261 	BYTE lvl;
4262 
4263 	b = CrawlNum[3];
4264 	missile[i]._miDelFlag = 1;
4265 	src = missile[i]._micaster;
4266 	k = CrawlNum[3] + 1;
4267 	if (src > 0)
4268 		lvl = plr[src]._pLevel;
4269 	else
4270 		lvl = currlevel;
4271 	dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1;
4272 	for (j = CrawlTable[b]; j > 0; j--, k += 2) {
4273 		tx = missile[i]._miVar1 + CrawlTable[k - 1];
4274 		ty = missile[i]._miVar2 + CrawlTable[k];
4275 		if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
4276 			dp = dPiece[tx][ty];
4277 			if (!nSolidTable[dp] && dObject[tx][ty] == 0) {
4278 				if (LineClear(missile[i]._mix, missile[i]._miy, tx, ty)) {
4279 					if (nMissileTable[dp] || missile[i]._miVar8)
4280 						missile[i]._miVar8 = 1;
4281 					else
4282 						AddMissile(tx, ty, tx, ty, 0, MIS_LIGHTWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl);
4283 				}
4284 			}
4285 		}
4286 	}
4287 }
4288 
4289 void MI_Search(Sint32 i)
4290 {
4291 	missile[i]._mirange--;
4292 	if (missile[i]._mirange == 0) {
4293 		missile[i]._miDelFlag = TRUE;
4294 		PlaySfxLoc(IS_CAST7, plr[missile[i]._miVar1]._px, plr[missile[i]._miVar1]._py);
4295 		AutoMapShowItems = FALSE;
4296 	}
4297 }
4298 
4299 void MI_LightningWallC(Sint32 i)
4300 {
4301 	missile[i]._mirange--;
4302 	int id = missile[i]._misource;
4303 	int lvl = 0;
4304 	if (id > -1)
4305 		lvl = plr[id]._pLevel;
4306 	int dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2);
4307 	if (missile[i]._mirange == 0) {
4308 		missile[i]._miDelFlag = TRUE;
4309 	} else {
4310 		int dp = dPiece[missile[i]._miVar1][missile[i]._miVar2];
4311 		assert(dp <= MAXTILES && dp >= 0);
4312 		int tx = missile[i]._miVar1 + XDirAdd[missile[i]._miVar3];
4313 		int ty = missile[i]._miVar2 + YDirAdd[missile[i]._miVar3];
4314 		if (!nMissileTable[dp] && missile[i]._miVar8 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
4315 			AddMissile(missile[i]._miVar1, missile[i]._miVar2, missile[i]._miVar1, missile[i]._miVar2, plr[id]._pdir, MIS_LIGHTWALL, TARGET_BOTH, id, dmg, missile[i]._mispllvl);
4316 			missile[i]._miVar1 = tx;
4317 			missile[i]._miVar2 = ty;
4318 		} else {
4319 			missile[i]._miVar8 = 1;
4320 		}
4321 		dp = dPiece[missile[i]._miVar5][missile[i]._miVar6];
4322 		assert(dp <= MAXTILES && dp >= 0);
4323 		tx = missile[i]._miVar5 + XDirAdd[missile[i]._miVar4];
4324 		ty = missile[i]._miVar6 + YDirAdd[missile[i]._miVar4];
4325 		if (!nMissileTable[dp] && missile[i]._miVar7 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
4326 			AddMissile(missile[i]._miVar5, missile[i]._miVar6, missile[i]._miVar5, missile[i]._miVar6, plr[id]._pdir, MIS_LIGHTWALL, TARGET_BOTH, id, dmg, missile[i]._mispllvl);
4327 			missile[i]._miVar5 = tx;
4328 			missile[i]._miVar6 = ty;
4329 		} else {
4330 			missile[i]._miVar7 = 1;
4331 		}
4332 	}
4333 }
4334 
4335 void MI_FireNova(Sint32 i)
4336 {
4337 	int k, id, sx, sy, dir, en, sx1, sy1, dam;
4338 
4339 	sx1 = 0;
4340 	sy1 = 0;
4341 	id = missile[i]._misource;
4342 	dam = missile[i]._midam;
4343 	sx = missile[i]._mix;
4344 	sy = missile[i]._miy;
4345 	if (id != -1) {
4346 		dir = plr[id]._pdir;
4347 		en = TARGET_MONSTERS;
4348 	} else {
4349 		dir = 0;
4350 		en = TARGET_PLAYERS;
4351 	}
4352 	for (k = 0; k < 23; k++) {
4353 		if (sx1 != vCrawlTable[k][6] || sy1 != vCrawlTable[k][7]) {
4354 			AddMissile(sx, sy, sx + vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl);
4355 			AddMissile(sx, sy, sx - vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl);
4356 			AddMissile(sx, sy, sx - vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl);
4357 			AddMissile(sx, sy, sx + vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl);
4358 			sx1 = vCrawlTable[k][6];
4359 			sy1 = vCrawlTable[k][7];
4360 		}
4361 	}
4362 	missile[i]._mirange--;
4363 	if (missile[i]._mirange == 0)
4364 		missile[i]._miDelFlag = TRUE;
4365 }
4366 
4367 void MI_SpecArrow(Sint32 i)
4368 {
4369 	int dir, src, dam, sx, sy, dx, dy, spllvl, mitype, micaster;
4370 
4371 	src = missile[i]._misource;
4372 	dam = missile[i]._midam;
4373 	sx = missile[i]._mix;
4374 	sy = missile[i]._miy;
4375 	dx = missile[i]._miVar1;
4376 	dy = missile[i]._miVar2;
4377 	spllvl = missile[i]._miVar3;
4378 	mitype = 0;
4379 	if (src != -1) {
4380 		dir = plr[src]._pdir;
4381 		micaster = TARGET_MONSTERS;
4382 
4383 		switch (plr[src]._pILMinDam) {
4384 		case 0:
4385 			mitype = MIS_FIRENOVA;
4386 			break;
4387 		case 1:
4388 			mitype = MIS_LIGHTARROW;
4389 			break;
4390 		case 2:
4391 			mitype = MIS_CBOLTARROW;
4392 			break;
4393 		case 3:
4394 			mitype = MIS_HBOLTARROW;
4395 			break;
4396 		}
4397 	} else {
4398 		dir = 0;
4399 		micaster = TARGET_PLAYERS;
4400 	}
4401 	AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl);
4402 	if (mitype == MIS_CBOLTARROW) {
4403 		AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl);
4404 		AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl);
4405 	}
4406 	missile[i]._mirange--;
4407 	if (missile[i]._mirange == 0)
4408 		missile[i]._miDelFlag = TRUE;
4409 }
4410 
4411 void MI_Lightctrl(Sint32 i)
4412 {
4413 	int pn, dam, p, mx, my;
4414 
4415 	assert((DWORD)i < MAXMISSILES);
4416 	missile[i]._mirange--;
4417 
4418 	p = missile[i]._misource;
4419 	if (p != -1) {
4420 		if (missile[i]._micaster == TARGET_MONSTERS) {
4421 			dam = (random_(79, 2) + random_(79, plr[p]._pLevel) + 2) << 6;
4422 		} else {
4423 			dam = 2 * (monster[p].mMinDamage + random_(80, monster[p].mMaxDamage - monster[p].mMinDamage + 1));
4424 		}
4425 	} else {
4426 		dam = random_(81, currlevel) + 2 * currlevel;
4427 	}
4428 
4429 	missile[i]._mitxoff += missile[i]._mixvel;
4430 	missile[i]._mityoff += missile[i]._miyvel;
4431 	GetMissilePos(i);
4432 
4433 	mx = missile[i]._mix;
4434 	my = missile[i]._miy;
4435 	assert((DWORD)mx < MAXDUNX);
4436 	assert((DWORD)my < MAXDUNY);
4437 	pn = dPiece[mx][my];
4438 	assert((DWORD)pn <= MAXTILES);
4439 
4440 	if (missile[i]._misource == -1) {
4441 		if ((mx != missile[i]._misx || my != missile[i]._misy) && nMissileTable[pn]) {
4442 			missile[i]._mirange = 0;
4443 		}
4444 	} else if (nMissileTable[pn]) {
4445 		missile[i]._mirange = 0;
4446 	}
4447 	if (!nMissileTable[pn]) {
4448 		if ((mx != missile[i]._miVar1 || my != missile[i]._miVar2) && mx > 0 && my > 0 && mx < MAXDUNX && my < MAXDUNY) {
4449 			if (missile[i]._misource != -1) {
4450 				if (missile[i]._micaster == TARGET_PLAYERS
4451 				    && monster[missile[i]._misource].MType->mtype >= MT_STORM
4452 				    && monster[missile[i]._misource].MType->mtype <= MT_MAEL) {
4453 					AddMissile(
4454 					    missile[i]._mix,
4455 					    missile[i]._miy,
4456 					    missile[i]._misx,
4457 					    missile[i]._misy,
4458 					    i,
4459 					    MIS_LIGHTNING2,
4460 					    missile[i]._micaster,
4461 					    missile[i]._misource,
4462 					    dam,
4463 					    missile[i]._mispllvl);
4464 				} else {
4465 					AddMissile(
4466 					    missile[i]._mix,
4467 					    missile[i]._miy,
4468 					    missile[i]._misx,
4469 					    missile[i]._misy,
4470 					    i,
4471 					    MIS_LIGHTNING,
4472 					    missile[i]._micaster,
4473 					    missile[i]._misource,
4474 					    dam,
4475 					    missile[i]._mispllvl);
4476 				}
4477 			} else {
4478 				AddMissile(
4479 				    missile[i]._mix,
4480 				    missile[i]._miy,
4481 				    missile[i]._misx,
4482 				    missile[i]._misy,
4483 				    i,
4484 				    MIS_LIGHTNING,
4485 				    missile[i]._micaster,
4486 				    missile[i]._misource,
4487 				    dam,
4488 				    missile[i]._mispllvl);
4489 			}
4490 			missile[i]._miVar1 = missile[i]._mix;
4491 			missile[i]._miVar2 = missile[i]._miy;
4492 		}
4493 	}
4494 	if (missile[i]._mirange == 0 || mx <= 0 || my <= 0 || mx >= MAXDUNX || my > MAXDUNY) {
4495 		missile[i]._miDelFlag = TRUE;
4496 	}
4497 }
4498 
4499 void MI_Lightning(Sint32 i)
4500 {
4501 	int j;
4502 
4503 	missile[i]._mirange--;
4504 	j = missile[i]._mirange;
4505 	if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy)
4506 		CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE);
4507 	if (missile[i]._miHitFlag == TRUE)
4508 		missile[i]._mirange = j;
4509 	if (missile[i]._mirange == 0) {
4510 		missile[i]._miDelFlag = TRUE;
4511 		AddUnLight(missile[i]._mlid);
4512 	}
4513 	PutMissile(i);
4514 }
4515 
4516 void MI_Town(Sint32 i)
4517 {
4518 	int ExpLight[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15 };
4519 	int p;
4520 
4521 	if (missile[i]._mirange > 1)
4522 		missile[i]._mirange--;
4523 	if (missile[i]._mirange == missile[i]._miVar1)
4524 		SetMissDir(i, 1);
4525 	if (currlevel != 0 && missile[i]._mimfnum != 1 && missile[i]._mirange != 0) {
4526 		if (missile[i]._miVar2 == 0)
4527 			missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 1);
4528 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]);
4529 		missile[i]._miVar2++;
4530 	}
4531 
4532 	for (p = 0; p < MAX_PLRS; p++) {
4533 		if (plr[p].plractive && currlevel == plr[p].plrlevel && !plr[p]._pLvlChanging && plr[p]._pmode == PM_STAND && plr[p]._px == missile[i]._mix && plr[p]._py == missile[i]._miy) {
4534 			ClrPlrPath(p);
4535 			if (p == myplr) {
4536 				NetSendCmdParam1(TRUE, CMD_WARP, missile[i]._misource);
4537 				plr[p]._pmode = PM_NEWLVL;
4538 			}
4539 		}
4540 	}
4541 
4542 	if (missile[i]._mirange == 0) {
4543 		missile[i]._miDelFlag = TRUE;
4544 		AddUnLight(missile[i]._mlid);
4545 	}
4546 	PutMissile(i);
4547 }
4548 
4549 void MI_Flash(Sint32 i)
4550 {
4551 	if (missile[i]._micaster == TARGET_MONSTERS) {
4552 		if (missile[i]._misource != -1)
4553 			plr[missile[i]._misource]._pInvincible = TRUE;
4554 	}
4555 	missile[i]._mirange--;
4556 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy, TRUE);
4557 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE);
4558 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy, TRUE);
4559 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy + 1, TRUE);
4560 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy + 1, TRUE);
4561 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy + 1, TRUE);
4562 	if (missile[i]._mirange == 0) {
4563 		missile[i]._miDelFlag = TRUE;
4564 		if (missile[i]._micaster == TARGET_MONSTERS) {
4565 			if (missile[i]._misource != -1)
4566 				plr[missile[i]._misource]._pInvincible = FALSE;
4567 		}
4568 	}
4569 	PutMissile(i);
4570 }
4571 
4572 void MI_Flash2(Sint32 i)
4573 {
4574 	if (missile[i]._micaster == TARGET_MONSTERS) {
4575 		if (missile[i]._misource != -1)
4576 			plr[missile[i]._misource]._pInvincible = TRUE;
4577 	}
4578 	missile[i]._mirange--;
4579 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy - 1, TRUE);
4580 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy - 1, TRUE);
4581 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy - 1, TRUE);
4582 	if (missile[i]._mirange == 0) {
4583 		missile[i]._miDelFlag = TRUE;
4584 		if (missile[i]._micaster == TARGET_MONSTERS) {
4585 			if (missile[i]._misource != -1)
4586 				plr[missile[i]._misource]._pInvincible = FALSE;
4587 		}
4588 	}
4589 	PutMissile(i);
4590 }
4591 
4592 void MI_Manashield(Sint32 i)
4593 {
4594 	int id, diff;
4595 
4596 	id = missile[i]._misource;
4597 	missile[i]._mix = plr[id]._px;
4598 	missile[i]._miy = plr[id]._py;
4599 	missile[i]._mitxoff = plr[id]._pxoff * 65536;
4600 	missile[i]._mityoff = plr[id]._pyoff * 65536;
4601 	if (plr[id]._pmode == PM_WALK3) {
4602 		missile[i]._misx = plr[id]._pfutx;
4603 		missile[i]._misy = plr[id]._pfuty;
4604 	} else {
4605 		missile[i]._misx = plr[id]._px;
4606 		missile[i]._misy = plr[id]._py;
4607 	}
4608 	GetMissilePos(i);
4609 	if (plr[id]._pmode == PM_WALK3) {
4610 		if (plr[id]._pdir == DIR_W)
4611 			missile[i]._mix++;
4612 		else
4613 			missile[i]._miy++;
4614 	}
4615 	if (id != myplr) {
4616 		if (currlevel != plr[id].plrlevel)
4617 			missile[i]._miDelFlag = TRUE;
4618 	} else {
4619 		if (plr[id]._pMana <= 0 || !plr[id].plractive)
4620 			missile[i]._mirange = 0;
4621 		if (plr[id]._pHitPoints < missile[i]._miVar1) {
4622 			diff = missile[i]._miVar1 - plr[id]._pHitPoints;
4623 			if (missile[i]._mispllvl > 0) {
4624 				diff += diff / -3;
4625 			}
4626 
4627 			if (diff < 0)
4628 				diff = 0;
4629 			drawmanaflag = TRUE;
4630 			drawhpflag = TRUE;
4631 
4632 			if (plr[id]._pMana >= diff) {
4633 				plr[id]._pHitPoints = missile[i]._miVar1;
4634 				plr[id]._pHPBase = missile[i]._miVar2;
4635 				plr[id]._pMana -= diff;
4636 				plr[id]._pManaBase -= diff;
4637 			} else {
4638 				plr[id]._pHitPoints = plr[id]._pMana + missile[i]._miVar1 - diff;
4639 				plr[id]._pHPBase = plr[id]._pMana + missile[i]._miVar2 - diff;
4640 				plr[id]._pMana = 0;
4641 				plr[id]._pManaBase = plr[id]._pMaxManaBase - plr[id]._pMaxMana;
4642 				missile[i]._mirange = 0;
4643 				missile[i]._miDelFlag = TRUE;
4644 				if (plr[id]._pHitPoints < 0)
4645 					SetPlayerHitPoints(id, 0);
4646 				if ((plr[id]._pHitPoints >> 6) == 0 && id == myplr) {
4647 					SyncPlrKill(id, missile[i]._miVar8);
4648 				}
4649 			}
4650 		}
4651 
4652 		if (id == myplr && plr[id]._pHitPoints == 0 && missile[i]._miVar1 == 0 && plr[id]._pmode != PM_DEATH) {
4653 			missile[i]._mirange = 0;
4654 			missile[i]._miDelFlag = TRUE;
4655 			SyncPlrKill(id, -1);
4656 		}
4657 
4658 		missile[i]._miVar1 = plr[id]._pHitPoints;
4659 		missile[i]._miVar2 = plr[id]._pHPBase;
4660 		if (missile[i]._mirange == 0) {
4661 			missile[i]._miDelFlag = TRUE;
4662 			NetSendCmd(TRUE, CMD_ENDSHIELD);
4663 		}
4664 	}
4665 	PutMissile(i);
4666 }
4667 
4668 void MI_Etherealize(Sint32 i)
4669 {
4670 	int src;
4671 
4672 	missile[i]._mirange--;
4673 	src = missile[i]._misource;
4674 	missile[i]._mix = plr[src]._px;
4675 	missile[i]._miy = plr[src]._py;
4676 	missile[i]._mitxoff = plr[src]._pxoff * 65536;
4677 	missile[i]._mityoff = plr[src]._pyoff * 65536;
4678 	if (plr[src]._pmode == PM_WALK3) {
4679 		missile[i]._misx = plr[src]._pfutx;
4680 		missile[i]._misy = plr[src]._pfuty;
4681 	} else {
4682 		missile[i]._misx = plr[src]._px;
4683 		missile[i]._misy = plr[src]._py;
4684 	}
4685 	GetMissilePos(i);
4686 	if (plr[src]._pmode == PM_WALK3) {
4687 		if (plr[src]._pdir == DIR_W)
4688 			missile[i]._mix++;
4689 		else
4690 			missile[i]._miy++;
4691 	}
4692 	plr[src]._pSpellFlags |= 1;
4693 	if (missile[i]._mirange == 0 || plr[src]._pHitPoints <= 0) {
4694 		missile[i]._miDelFlag = TRUE;
4695 		plr[src]._pSpellFlags &= ~0x1;
4696 	}
4697 	PutMissile(i);
4698 }
4699 
4700 void MI_Firemove(Sint32 i)
4701 {
4702 	int j;
4703 	int ExpLight[14] = { 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 12 };
4704 
4705 	missile[i]._mix--;
4706 	missile[i]._miy--;
4707 	missile[i]._miyoff += 32;
4708 	missile[i]._miVar1++;
4709 	if (missile[i]._miVar1 == missile[i]._miAnimLen) {
4710 		SetMissDir(i, 1);
4711 		missile[i]._miAnimFrame = random_(82, 11) + 1;
4712 	}
4713 	missile[i]._mitxoff += missile[i]._mixvel;
4714 	missile[i]._mityoff += missile[i]._miyvel;
4715 	GetMissilePos(i);
4716 	j = missile[i]._mirange;
4717 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
4718 	if (missile[i]._miHitFlag == TRUE)
4719 		missile[i]._mirange = j;
4720 	if (missile[i]._mirange == 0) {
4721 		missile[i]._miDelFlag = TRUE;
4722 		AddUnLight(missile[i]._mlid);
4723 	}
4724 	if (missile[i]._mimfnum != 0 || missile[i]._mirange == 0) {
4725 		if (missile[i]._mix != missile[i]._miVar3 || missile[i]._miy != missile[i]._miVar4) {
4726 			missile[i]._miVar3 = missile[i]._mix;
4727 			missile[i]._miVar4 = missile[i]._miy;
4728 			ChangeLight(missile[i]._mlid, missile[i]._miVar3, missile[i]._miVar4, 8);
4729 		}
4730 	} else {
4731 		if (missile[i]._miVar2 == 0)
4732 			missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, ExpLight[0]);
4733 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]);
4734 		missile[i]._miVar2++;
4735 	}
4736 	missile[i]._mix++;
4737 	missile[i]._miy++;
4738 	missile[i]._miyoff -= 32;
4739 	PutMissile(i);
4740 }
4741 
4742 void MI_Guardian(Sint32 i)
4743 {
4744 	int j, k, sx, sy, sx1, sy1, ex;
4745 
4746 	assert((DWORD)i < MAXMISSILES);
4747 
4748 	sx1 = 0;
4749 	sy1 = 0;
4750 	missile[i]._mirange--;
4751 
4752 	if (missile[i]._miVar2 > 0) {
4753 		missile[i]._miVar2--;
4754 	}
4755 	if (missile[i]._mirange == missile[i]._miVar1 || missile[i]._mimfnum == MFILE_GUARD && missile[i]._miVar2 == 0) {
4756 		SetMissDir(i, 1);
4757 	}
4758 
4759 	if (!(missile[i]._mirange % 16)) {
4760 		ex = 0;
4761 		for (j = 0; j < 23 && ex != -1; j++) {
4762 			for (k = 10; k >= 0 && ex != -1 && (vCrawlTable[j][k] != 0 || vCrawlTable[j][k + 1] != 0); k -= 2) {
4763 				if (sx1 == vCrawlTable[j][k] && sy1 == vCrawlTable[j][k + 1]) {
4764 					continue;
4765 				}
4766 				sx = missile[i]._mix + vCrawlTable[j][k];
4767 				sy = missile[i]._miy + vCrawlTable[j][k + 1];
4768 				ex = Sentfire(i, sx, sy);
4769 				if (ex == -1) {
4770 					break;
4771 				}
4772 				sx = missile[i]._mix - vCrawlTable[j][k];
4773 				sy = missile[i]._miy - vCrawlTable[j][k + 1];
4774 				ex = Sentfire(i, sx, sy);
4775 				if (ex == -1) {
4776 					break;
4777 				}
4778 				sx = missile[i]._mix + vCrawlTable[j][k];
4779 				sy = missile[i]._miy - vCrawlTable[j][k + 1];
4780 				ex = Sentfire(i, sx, sy);
4781 				if (ex == -1) {
4782 					break;
4783 				}
4784 				sx = missile[i]._mix - vCrawlTable[j][k];
4785 				sy = missile[i]._miy + vCrawlTable[j][k + 1];
4786 				ex = Sentfire(i, sx, sy);
4787 				if (ex == -1) {
4788 					break;
4789 				}
4790 				sx1 = vCrawlTable[j][k];
4791 				sy1 = vCrawlTable[j][k + 1];
4792 			}
4793 		}
4794 	}
4795 
4796 	if (missile[i]._mirange == 14) {
4797 		SetMissDir(i, 0);
4798 		missile[i]._miAnimFrame = 15;
4799 		missile[i]._miAnimAdd = -1;
4800 	}
4801 
4802 	missile[i]._miVar3 += missile[i]._miAnimAdd;
4803 
4804 	if (missile[i]._miVar3 > 15) {
4805 		missile[i]._miVar3 = 15;
4806 	} else if (missile[i]._miVar3 > 0) {
4807 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miVar3);
4808 	}
4809 
4810 	if (missile[i]._mirange == 0) {
4811 		missile[i]._miDelFlag = TRUE;
4812 		AddUnLight(missile[i]._mlid);
4813 	}
4814 
4815 	PutMissile(i);
4816 }
4817 
4818 void MI_Chain(Sint32 i)
4819 {
4820 	int sx, sy, id, l, n, m, k, rad, tx, ty, dir;
4821 
4822 	id = missile[i]._misource;
4823 	sx = missile[i]._mix;
4824 	sy = missile[i]._miy;
4825 	dir = GetDirection(sx, sy, missile[i]._miVar1, missile[i]._miVar2);
4826 	AddMissile(sx, sy, missile[i]._miVar1, missile[i]._miVar2, dir, MIS_LIGHTCTRL, TARGET_MONSTERS, id, 1, missile[i]._mispllvl);
4827 	rad = missile[i]._mispllvl + 3;
4828 	if (rad > 19)
4829 		rad = 19;
4830 	for (m = 1; m < rad; m++) {
4831 		k = CrawlNum[m];
4832 		l = k + 2;
4833 		for (n = (BYTE)CrawlTable[k]; n > 0; n--) {
4834 			tx = sx + CrawlTable[l - 1];
4835 			ty = sy + CrawlTable[l];
4836 			if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY && dMonster[tx][ty] > 0) {
4837 				dir = GetDirection(sx, sy, tx, ty);
4838 				AddMissile(sx, sy, tx, ty, dir, MIS_LIGHTCTRL, TARGET_MONSTERS, id, 1, missile[i]._mispllvl);
4839 			}
4840 			l += 2;
4841 		}
4842 	}
4843 	missile[i]._mirange--;
4844 	if (missile[i]._mirange == 0)
4845 		missile[i]._miDelFlag = TRUE;
4846 }
4847 
4848 void MI_Blood(Sint32 i)
4849 {
4850 	missile[i]._mirange--;
4851 	if (missile[i]._mirange == 0)
4852 		missile[i]._miDelFlag = TRUE;
4853 	if (missile[i]._miAnimFrame == missile[i]._miAnimLen)
4854 		missile[i]._miPreFlag = TRUE;
4855 	PutMissile(i);
4856 }
4857 
4858 void MI_Weapexp(Sint32 i)
4859 {
4860 	int id, mind, maxd;
4861 	int ExpLight[10] = { 9, 10, 11, 12, 11, 10, 8, 6, 4, 2 };
4862 
4863 	missile[i]._mirange--;
4864 	id = missile[i]._misource;
4865 	if (missile[i]._miVar2 == 1) {
4866 		mind = plr[id]._pIFMinDam;
4867 		maxd = plr[id]._pIFMaxDam;
4868 		missiledata[missile[i]._mitype].mResist = MISR_FIRE;
4869 	} else {
4870 		mind = plr[id]._pILMinDam;
4871 		maxd = plr[id]._pILMaxDam;
4872 		missiledata[missile[i]._mitype].mResist = MISR_LIGHTNING;
4873 	}
4874 	CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
4875 	if (missile[i]._miVar1 == 0) {
4876 		missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 9);
4877 	} else {
4878 		if (missile[i]._mirange != 0)
4879 			ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar1]);
4880 	}
4881 	missile[i]._miVar1++;
4882 	if (missile[i]._mirange == 0) {
4883 		missile[i]._miDelFlag = TRUE;
4884 		AddUnLight(missile[i]._mlid);
4885 	} else {
4886 		PutMissile(i);
4887 	}
4888 }
4889 
4890 void MI_Misexp(Sint32 i)
4891 {
4892 	int ExpLight[] = { 9, 10, 11, 12, 11, 10, 8, 6, 4, 2, 1, 0, 0, 0, 0 };
4893 
4894 	missile[i]._mirange--;
4895 	if (missile[i]._mirange == 0) {
4896 		missile[i]._miDelFlag = TRUE;
4897 		AddUnLight(missile[i]._mlid);
4898 	} else {
4899 		if (missile[i]._miVar1 == 0)
4900 			missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 9);
4901 		else
4902 			ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar1]);
4903 		missile[i]._miVar1++;
4904 		PutMissile(i);
4905 	}
4906 }
4907 
4908 void MI_Acidsplat(Sint32 i)
4909 {
4910 	int monst, dam;
4911 
4912 	if (missile[i]._mirange == missile[i]._miAnimLen) {
4913 		missile[i]._mix++;
4914 		missile[i]._miy++;
4915 		missile[i]._miyoff -= 32;
4916 	}
4917 	missile[i]._mirange--;
4918 	if (missile[i]._mirange == 0) {
4919 		missile[i]._miDelFlag = TRUE;
4920 		monst = missile[i]._misource;
4921 		dam = (monster[monst].MData->mLevel >= 2 ? 2 : 1);
4922 		AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_ACIDPUD, TARGET_PLAYERS, monst, dam, missile[i]._mispllvl);
4923 	} else {
4924 		PutMissile(i);
4925 	}
4926 }
4927 
4928 void MI_Teleport(Sint32 i)
4929 {
4930 	int id;
4931 
4932 	id = missile[i]._misource;
4933 	missile[i]._mirange--;
4934 	if (missile[i]._mirange <= 0) {
4935 		missile[i]._miDelFlag = TRUE;
4936 	} else {
4937 		dPlayer[plr[id]._px][plr[id]._py] = 0;
4938 		PlrClrTrans(plr[id]._px, plr[id]._py);
4939 		plr[id]._px = missile[i]._mix;
4940 		plr[id]._py = missile[i]._miy;
4941 		plr[id]._pfutx = plr[id]._px;
4942 		plr[id]._pfuty = plr[id]._py;
4943 		plr[id]._poldx = plr[id]._px;
4944 		plr[id]._poldy = plr[id]._py;
4945 		PlrDoTrans(plr[id]._px, plr[id]._py);
4946 		missile[i]._miVar1 = 1;
4947 		dPlayer[plr[id]._px][plr[id]._py] = id + 1;
4948 		if (leveltype != DTYPE_TOWN) {
4949 			ChangeLightXY(plr[id]._plid, plr[id]._px, plr[id]._py);
4950 			ChangeVisionXY(plr[id]._pvid, plr[id]._px, plr[id]._py);
4951 		}
4952 		if (id == myplr) {
4953 			ViewX = plr[id]._px - ScrollInfo._sdx;
4954 			ViewY = plr[id]._py - ScrollInfo._sdy;
4955 		}
4956 	}
4957 }
4958 
4959 void MI_Stone(Sint32 i)
4960 {
4961 	int m;
4962 
4963 	missile[i]._mirange--;
4964 	m = missile[i]._miVar2;
4965 	if (monster[m]._mhitpoints == 0 && missile[i]._miAnimType != MFILE_SHATTER1) {
4966 		missile[i]._mimfnum = 0;
4967 		missile[i]._miDrawFlag = TRUE;
4968 		SetMissAnim(i, MFILE_SHATTER1);
4969 		missile[i]._mirange = 11;
4970 	}
4971 	if (monster[m]._mmode != MM_STONE) {
4972 		missile[i]._miDelFlag = TRUE;
4973 		return;
4974 	}
4975 
4976 	if (missile[i]._mirange == 0) {
4977 		missile[i]._miDelFlag = TRUE;
4978 		if (monster[m]._mhitpoints > 0)
4979 			monster[m]._mmode = (MON_MODE)missile[i]._miVar1;
4980 		else
4981 			AddDead(monster[m]._mx, monster[m]._my, stonendx, (direction)monster[m]._mdir);
4982 	}
4983 	if (missile[i]._miAnimType == MFILE_SHATTER1)
4984 		PutMissile(i);
4985 }
4986 
4987 void MI_Boom(Sint32 i)
4988 {
4989 	missile[i]._mirange--;
4990 	if (missile[i]._miVar1 == 0)
4991 		CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, TRUE);
4992 	if (missile[i]._miHitFlag == TRUE)
4993 		missile[i]._miVar1 = 1;
4994 	if (missile[i]._mirange == 0)
4995 		missile[i]._miDelFlag = TRUE;
4996 	PutMissile(i);
4997 }
4998 
4999 void MI_Rhino(Sint32 i)
5000 {
5001 	int mix, miy, mix2, miy2, omx, omy, monst;
5002 
5003 	monst = missile[i]._misource;
5004 	if (monster[monst]._mmode != MM_CHARGE) {
5005 		missile[i]._miDelFlag = TRUE;
5006 		return;
5007 	}
5008 	GetMissilePos(i);
5009 	mix = missile[i]._mix;
5010 	miy = missile[i]._miy;
5011 	dMonster[mix][miy] = 0;
5012 	if (monster[monst]._mAi == AI_SNAKE) {
5013 		missile[i]._mitxoff += 2 * missile[i]._mixvel;
5014 		missile[i]._mityoff += 2 * missile[i]._miyvel;
5015 		GetMissilePos(i);
5016 		mix2 = missile[i]._mix;
5017 		miy2 = missile[i]._miy;
5018 		missile[i]._mitxoff -= missile[i]._mixvel;
5019 		missile[i]._mityoff -= missile[i]._miyvel;
5020 	} else {
5021 		missile[i]._mitxoff += missile[i]._mixvel;
5022 		missile[i]._mityoff += missile[i]._miyvel;
5023 	}
5024 	GetMissilePos(i);
5025 	omx = missile[i]._mix;
5026 	omy = missile[i]._miy;
5027 	if (!PosOkMonst(monst, missile[i]._mix, missile[i]._miy) || (monster[monst]._mAi == AI_SNAKE && !PosOkMonst(monst, mix2, miy2))) {
5028 		MissToMonst(i, mix, miy);
5029 		missile[i]._miDelFlag = TRUE;
5030 		return;
5031 	}
5032 	monster[monst]._mfutx = omx;
5033 	monster[monst]._moldx = omx;
5034 	dMonster[omx][omy] = -(monst + 1);
5035 	monster[monst]._mx = omx;
5036 	monster[monst]._mfuty = omy;
5037 	monster[monst]._moldy = omy;
5038 	monster[monst]._my = omy;
5039 	if (monster[monst]._uniqtype != 0)
5040 		ChangeLightXY(missile[i]._mlid, omx, omy);
5041 	MoveMissilePos(i);
5042 	PutMissile(i);
5043 }
5044 
5045 void MI_Fireman(Sint32 i)
5046 {
5047 	int src, enemy, ax, ay, bx, by, cx, cy, j;
5048 
5049 	GetMissilePos(i);
5050 	ax = missile[i]._mix;
5051 	ay = missile[i]._miy;
5052 	missile[i]._mitxoff += missile[i]._mixvel;
5053 	missile[i]._mityoff += missile[i]._miyvel;
5054 	GetMissilePos(i);
5055 	src = missile[i]._misource;
5056 	bx = missile[i]._mix;
5057 	by = missile[i]._miy;
5058 	enemy = monster[src]._menemy;
5059 	if (!(monster[src]._mFlags & MFLAG_TARGETS_MONSTER)) {
5060 		cx = plr[enemy]._px;
5061 		cy = plr[enemy]._py;
5062 	} else {
5063 		cx = monster[enemy]._mx;
5064 		cy = monster[enemy]._my;
5065 	}
5066 	if ((bx != ax || by != ay) && (missile[i]._miVar1 & 1 && (abs(ax - cx) >= 4 || abs(ay - cy) >= 4) || missile[i]._miVar2 > 1) && PosOkMonst(missile[i]._misource, ax, ay)) {
5067 		MissToMonst(i, ax, ay);
5068 		missile[i]._miDelFlag = TRUE;
5069 	} else if (!(monster[src]._mFlags & MFLAG_TARGETS_MONSTER)) {
5070 		j = dPlayer[bx][by];
5071 	} else {
5072 		j = dMonster[bx][by];
5073 	}
5074 	if (!PosOkMissile(bx, by) || j > 0 && !(missile[i]._miVar1 & 1)) {
5075 		missile[i]._mixvel *= -1;
5076 		missile[i]._miyvel *= -1;
5077 		missile[i]._mimfnum = opposite[missile[i]._mimfnum];
5078 		missile[i]._miAnimData = monster[src].MType->Anims[MA_WALK].Data[missile[i]._mimfnum];
5079 		missile[i]._miVar2++;
5080 		if (j > 0)
5081 			missile[i]._miVar1 |= 1;
5082 	}
5083 	MoveMissilePos(i);
5084 	PutMissile(i);
5085 }
5086 
5087 void MI_FirewallC(Sint32 i)
5088 {
5089 	missile[i]._mirange--;
5090 	int id = missile[i]._misource;
5091 	if (missile[i]._mirange == 0) {
5092 		missile[i]._miDelFlag = TRUE;
5093 	} else {
5094 		int dp = dPiece[missile[i]._miVar1][missile[i]._miVar2];
5095 		assert(dp <= MAXTILES && dp >= 0);
5096 		int tx = missile[i]._miVar1 + XDirAdd[missile[i]._miVar3];
5097 		int ty = missile[i]._miVar2 + YDirAdd[missile[i]._miVar3];
5098 		if (!nMissileTable[dp] && missile[i]._miVar8 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
5099 			AddMissile(missile[i]._miVar1, missile[i]._miVar2, missile[i]._miVar1, missile[i]._miVar2, plr[id]._pdir, MIS_FIREWALL, TARGET_BOTH, id, 0, missile[i]._mispllvl);
5100 			missile[i]._miVar1 = tx;
5101 			missile[i]._miVar2 = ty;
5102 		} else {
5103 			missile[i]._miVar8 = 1;
5104 		}
5105 		dp = dPiece[missile[i]._miVar5][missile[i]._miVar6];
5106 		assert(dp <= MAXTILES && dp >= 0);
5107 		tx = missile[i]._miVar5 + XDirAdd[missile[i]._miVar4];
5108 		ty = missile[i]._miVar6 + YDirAdd[missile[i]._miVar4];
5109 		if (!nMissileTable[dp] && missile[i]._miVar7 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) {
5110 			AddMissile(missile[i]._miVar5, missile[i]._miVar6, missile[i]._miVar5, missile[i]._miVar6, plr[id]._pdir, MIS_FIREWALL, TARGET_BOTH, id, 0, missile[i]._mispllvl);
5111 			missile[i]._miVar5 = tx;
5112 			missile[i]._miVar6 = ty;
5113 		} else {
5114 			missile[i]._miVar7 = 1;
5115 		}
5116 	}
5117 }
5118 
5119 void MI_Infra(Sint32 i)
5120 {
5121 	missile[i]._mirange--;
5122 	plr[missile[i]._misource]._pInfraFlag = TRUE;
5123 	if (missile[i]._mirange == 0) {
5124 		missile[i]._miDelFlag = TRUE;
5125 		CalcPlrItemVals(missile[i]._misource, TRUE);
5126 	}
5127 }
5128 
5129 void MI_Apoca(Sint32 i)
5130 {
5131 	int j, k, id;
5132 	BOOL exit;
5133 
5134 	id = missile[i]._misource;
5135 	exit = FALSE;
5136 	for (j = missile[i]._miVar2; j < missile[i]._miVar3 && !exit; j++) {
5137 		for (k = missile[i]._miVar4; k < missile[i]._miVar5 && !exit; k++) {
5138 			if (dMonster[k][j] > MAX_PLRS - 1 && !nSolidTable[dPiece[k][j]]) {
5139 				if (!gbIsHellfire || LineClear(missile[i]._mix, missile[i]._miy, k, j)) {
5140 					AddMissile(k, j, k, j, plr[id]._pdir, MIS_BOOM, TARGET_MONSTERS, id, missile[i]._midam, 0);
5141 					exit = TRUE;
5142 				}
5143 			}
5144 		}
5145 		if (!exit) {
5146 			missile[i]._miVar4 = missile[i]._miVar6;
5147 		}
5148 	}
5149 
5150 	if (exit == TRUE) {
5151 		missile[i]._miVar2 = j - 1;
5152 		missile[i]._miVar4 = k;
5153 	} else {
5154 		missile[i]._miDelFlag = TRUE;
5155 	}
5156 }
5157 
5158 void MI_Wave(Sint32 i)
5159 {
5160 	int sx, sy, sd, nxa, nxb, nya, nyb, dira, dirb;
5161 	int j, id, pn;
5162 	BOOL f1, f2;
5163 	int v1, v2;
5164 
5165 	f1 = FALSE;
5166 	f2 = FALSE;
5167 	assert((DWORD)i < MAXMISSILES);
5168 
5169 	id = missile[i]._misource;
5170 	sx = missile[i]._mix;
5171 	sy = missile[i]._miy;
5172 	v1 = missile[i]._miVar1;
5173 	v2 = missile[i]._miVar2;
5174 	sd = GetDirection(sx, sy, v1, v2);
5175 	dira = (sd - 2) & 7;
5176 	dirb = (sd + 2) & 7;
5177 	nxa = sx + XDirAdd[sd];
5178 	nya = sy + YDirAdd[sd];
5179 	pn = dPiece[nxa][nya];
5180 	assert((DWORD)pn <= MAXTILES);
5181 	if (!nMissileTable[pn]) {
5182 		AddMissile(nxa, nya, nxa + XDirAdd[sd], nya + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl);
5183 		nxa += XDirAdd[dira];
5184 		nya += YDirAdd[dira];
5185 		nxb = sx + XDirAdd[sd] + XDirAdd[dirb];
5186 		nyb = sy + YDirAdd[sd] + YDirAdd[dirb];
5187 		for (j = 0; j < (missile[i]._mispllvl >> 1) + 2; j++) {
5188 			pn = dPiece[nxa][nya]; // BUGFIX: dPiece is accessed before check against dungeon size and 0
5189 			assert((DWORD)pn <= MAXTILES);
5190 			if (nMissileTable[pn] || f1 || nxa <= 0 || nxa >= MAXDUNX || nya <= 0 || nya >= MAXDUNY) {
5191 				f1 = TRUE;
5192 			} else {
5193 				AddMissile(nxa, nya, nxa + XDirAdd[sd], nya + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl);
5194 				nxa += XDirAdd[dira];
5195 				nya += YDirAdd[dira];
5196 			}
5197 			pn = dPiece[nxb][nyb]; // BUGFIX: dPiece is accessed before check against dungeon size and 0
5198 			assert((DWORD)pn <= MAXTILES);
5199 			if (nMissileTable[pn] || f2 || nxb <= 0 || nxb >= MAXDUNX || nyb <= 0 || nyb >= MAXDUNY) {
5200 				f2 = TRUE;
5201 			} else {
5202 				AddMissile(nxb, nyb, nxb + XDirAdd[sd], nyb + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl);
5203 				nxb += XDirAdd[dirb];
5204 				nyb += YDirAdd[dirb];
5205 			}
5206 		}
5207 	}
5208 	missile[i]._mirange--;
5209 	if (missile[i]._mirange == 0)
5210 		missile[i]._miDelFlag = TRUE;
5211 }
5212 
5213 void MI_Nova(Sint32 i)
5214 {
5215 	int k, id, sx, sy, dir, en, sx1, sy1, dam;
5216 
5217 	sx1 = 0;
5218 	sy1 = 0;
5219 	id = missile[i]._misource;
5220 	dam = missile[i]._midam;
5221 	sx = missile[i]._mix;
5222 	sy = missile[i]._miy;
5223 	if (id != -1) {
5224 		dir = plr[id]._pdir;
5225 		en = TARGET_MONSTERS;
5226 	} else {
5227 		dir = 0;
5228 		en = TARGET_PLAYERS;
5229 	}
5230 	for (k = 0; k < 23; k++) {
5231 		if (sx1 != vCrawlTable[k][6] || sy1 != vCrawlTable[k][7]) {
5232 			AddMissile(sx, sy, sx + vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl);
5233 			AddMissile(sx, sy, sx - vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl);
5234 			AddMissile(sx, sy, sx - vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl);
5235 			AddMissile(sx, sy, sx + vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl);
5236 			sx1 = vCrawlTable[k][6];
5237 			sy1 = vCrawlTable[k][7];
5238 		}
5239 	}
5240 	missile[i]._mirange--;
5241 	if (missile[i]._mirange == 0)
5242 		missile[i]._miDelFlag = TRUE;
5243 }
5244 
5245 void MI_Blodboil(Sint32 i)
5246 {
5247 	int id, hpdif;
5248 
5249 	missile[i]._mirange--;
5250 	if (missile[i]._mirange == 0) {
5251 		id = missile[i]._miVar1;
5252 		if ((plr[id]._pSpellFlags & 2) == 2) {
5253 			int blodboilSFX[NUM_CLASSES] = {
5254 				PS_WARR72,
5255 				PS_ROGUE72,
5256 				PS_MAGE72,
5257 				PS_MAGE72,
5258 				PS_ROGUE72,
5259 				PS_WARR72
5260 			};
5261 			plr[id]._pSpellFlags &= ~0x2;
5262 			plr[id]._pSpellFlags |= 4;
5263 			int lvl = 2;
5264 			if (id > -1)
5265 				lvl = plr[id]._pLevel * 2;
5266 			missile[i]._mirange = lvl + 10 * missile[i]._mispllvl + 245;
5267 			hpdif = plr[id]._pMaxHP - plr[id]._pHitPoints;
5268 			CalcPlrItemVals(id, TRUE);
5269 			plr[id]._pHitPoints -= hpdif;
5270 			if (plr[id]._pHitPoints < 64)
5271 				plr[id]._pHitPoints = 64;
5272 			force_redraw = 255;
5273 			PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py);
5274 		} else {
5275 			int blodboilSFX[NUM_CLASSES] = {
5276 				PS_WARR72,
5277 				PS_ROGUE72,
5278 				PS_MAGE72,
5279 				PS_MAGE72,
5280 				PS_ROGUE72,
5281 				PS_WARR72
5282 			};
5283 			missile[i]._miDelFlag = TRUE;
5284 			plr[id]._pSpellFlags &= ~0x4;
5285 			hpdif = plr[id]._pMaxHP - plr[id]._pHitPoints;
5286 			CalcPlrItemVals(id, TRUE);
5287 			plr[id]._pHitPoints -= hpdif + missile[i]._miVar2;
5288 			if (plr[id]._pHitPoints < 64)
5289 				plr[id]._pHitPoints = 64;
5290 			force_redraw = 255;
5291 			PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py);
5292 		}
5293 	}
5294 }
5295 
5296 void MI_Flame(Sint32 i)
5297 {
5298 	int k;
5299 
5300 	missile[i]._mirange--;
5301 	missile[i]._miVar2--;
5302 	k = missile[i]._mirange;
5303 	CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE);
5304 	if (missile[i]._mirange == 0 && missile[i]._miHitFlag == TRUE)
5305 		missile[i]._mirange = k;
5306 	if (missile[i]._miVar2 == 0)
5307 		missile[i]._miAnimFrame = 20;
5308 	if (missile[i]._miVar2 <= 0) {
5309 		k = missile[i]._miAnimFrame;
5310 		if (k > 11)
5311 			k = 24 - k;
5312 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, k);
5313 	}
5314 	if (missile[i]._mirange == 0) {
5315 		missile[i]._miDelFlag = TRUE;
5316 		AddUnLight(missile[i]._mlid);
5317 	}
5318 	if (missile[i]._miVar2 <= 0)
5319 		PutMissile(i);
5320 }
5321 
5322 void MI_Flamec(Sint32 i)
5323 {
5324 	int id, src;
5325 
5326 	missile[i]._mirange--;
5327 	src = missile[i]._misource;
5328 	missile[i]._mitxoff += missile[i]._mixvel;
5329 	missile[i]._mityoff += missile[i]._miyvel;
5330 	GetMissilePos(i);
5331 	if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
5332 		id = dPiece[missile[i]._mix][missile[i]._miy];
5333 		if (!nMissileTable[id]) {
5334 			AddMissile(
5335 			    missile[i]._mix,
5336 			    missile[i]._miy,
5337 			    missile[i]._misx,
5338 			    missile[i]._misy,
5339 			    i,
5340 			    MIS_FLAME,
5341 			    missile[i]._micaster,
5342 			    src,
5343 			    missile[i]._miVar3,
5344 			    missile[i]._mispllvl);
5345 		} else {
5346 			missile[i]._mirange = 0;
5347 		}
5348 		missile[i]._miVar1 = missile[i]._mix;
5349 		missile[i]._miVar2 = missile[i]._miy;
5350 		missile[i]._miVar3++;
5351 	}
5352 	if (missile[i]._mirange == 0 || missile[i]._miVar3 == 3)
5353 		missile[i]._miDelFlag = TRUE;
5354 }
5355 
5356 void MI_Cbolt(Sint32 i)
5357 {
5358 	int md;
5359 	int bpath[16] = { -1, 0, 1, -1, 0, 1, -1, -1, 0, 0, 1, 1, 0, 1, -1, 0 };
5360 
5361 	missile[i]._mirange--;
5362 	if (missile[i]._miAnimType != MFILE_LGHNING) {
5363 		if (missile[i]._miVar3 == 0) {
5364 			md = (missile[i]._miVar2 + bpath[missile[i]._mirnd]) & 7;
5365 			missile[i]._mirnd = (missile[i]._mirnd + 1) & 0xF;
5366 			GetMissileVel(i, missile[i]._mix, missile[i]._miy, missile[i]._mix + XDirAdd[md], missile[i]._miy + YDirAdd[md], 8);
5367 			missile[i]._miVar3 = 16;
5368 		} else {
5369 			missile[i]._miVar3--;
5370 		}
5371 		missile[i]._mitxoff += missile[i]._mixvel;
5372 		missile[i]._mityoff += missile[i]._miyvel;
5373 		GetMissilePos(i);
5374 		CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
5375 		if (missile[i]._miHitFlag == TRUE) {
5376 			missile[i]._miVar1 = 8;
5377 			missile[i]._mimfnum = 0;
5378 			missile[i]._mixoff = 0;
5379 			missile[i]._miyoff = 0;
5380 			SetMissAnim(i, MFILE_LGHNING);
5381 			missile[i]._mirange = missile[i]._miAnimLen;
5382 			GetMissilePos(i);
5383 		}
5384 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miVar1);
5385 	}
5386 	if (missile[i]._mirange == 0) {
5387 		missile[i]._miDelFlag = TRUE;
5388 		AddUnLight(missile[i]._mlid);
5389 	}
5390 	PutMissile(i);
5391 }
5392 
5393 void MI_Hbolt(Sint32 i)
5394 {
5395 	int dam;
5396 
5397 	missile[i]._mirange--;
5398 	if (missile[i]._miAnimType != MFILE_HOLYEXPL) {
5399 		missile[i]._mitxoff += missile[i]._mixvel;
5400 		missile[i]._mityoff += missile[i]._miyvel;
5401 		GetMissilePos(i);
5402 		dam = missile[i]._midam;
5403 		if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) {
5404 			CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE);
5405 		}
5406 		if (missile[i]._mirange == 0) {
5407 			missile[i]._mitxoff -= missile[i]._mixvel;
5408 			missile[i]._mityoff -= missile[i]._miyvel;
5409 			GetMissilePos(i);
5410 			missile[i]._mimfnum = 0;
5411 			SetMissAnim(i, MFILE_HOLYEXPL);
5412 			missile[i]._mirange = missile[i]._miAnimLen - 1;
5413 		} else {
5414 			if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) {
5415 				missile[i]._miVar1 = missile[i]._mix;
5416 				missile[i]._miVar2 = missile[i]._miy;
5417 				ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8);
5418 			}
5419 		}
5420 	} else {
5421 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame + 7);
5422 		if (missile[i]._mirange == 0) {
5423 			missile[i]._miDelFlag = TRUE;
5424 			AddUnLight(missile[i]._mlid);
5425 		}
5426 	}
5427 	PutMissile(i);
5428 }
5429 
5430 void MI_Element(Sint32 i)
5431 {
5432 	int mid, sd, dam, cx, cy, px, py, id;
5433 
5434 	missile[i]._mirange--;
5435 	dam = missile[i]._midam;
5436 	id = missile[i]._misource;
5437 	if (missile[i]._miAnimType == MFILE_BIGEXP) {
5438 		cx = missile[i]._mix;
5439 		cy = missile[i]._miy;
5440 		px = plr[id]._px;
5441 		py = plr[id]._py;
5442 		ChangeLight(missile[i]._mlid, cx, cy, missile[i]._miAnimFrame);
5443 		if (!CheckBlock(px, py, cx, cy))
5444 			CheckMissileCol(i, dam, dam, TRUE, cx, cy, TRUE);
5445 		if (!CheckBlock(px, py, cx, cy + 1))
5446 			CheckMissileCol(i, dam, dam, TRUE, cx, cy + 1, TRUE);
5447 		if (!CheckBlock(px, py, cx, cy - 1))
5448 			CheckMissileCol(i, dam, dam, TRUE, cx, cy - 1, TRUE);
5449 		if (!CheckBlock(px, py, cx + 1, cy))
5450 			CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy, TRUE); /* check x/y */
5451 		if (!CheckBlock(px, py, cx + 1, cy - 1))
5452 			CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy - 1, TRUE);
5453 		if (!CheckBlock(px, py, cx + 1, cy + 1))
5454 			CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy + 1, TRUE);
5455 		if (!CheckBlock(px, py, cx - 1, cy))
5456 			CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy, TRUE);
5457 		if (!CheckBlock(px, py, cx - 1, cy + 1))
5458 			CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy + 1, TRUE);
5459 		if (!CheckBlock(px, py, cx - 1, cy - 1))
5460 			CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy - 1, TRUE);
5461 		if (missile[i]._mirange == 0) {
5462 			missile[i]._miDelFlag = TRUE;
5463 			AddUnLight(missile[i]._mlid);
5464 		}
5465 	} else {
5466 		missile[i]._mitxoff += missile[i]._mixvel;
5467 		missile[i]._mityoff += missile[i]._miyvel;
5468 		GetMissilePos(i);
5469 		cx = missile[i]._mix;
5470 		cy = missile[i]._miy;
5471 		CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE);
5472 		if (missile[i]._miVar3 == 0 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5)
5473 			missile[i]._miVar3 = 1;
5474 		if (missile[i]._miVar3 == 1) {
5475 			missile[i]._miVar3 = 2;
5476 			missile[i]._mirange = 255;
5477 			mid = FindClosest(cx, cy, 19);
5478 			if (mid > 0) {
5479 				sd = GetDirection8(cx, cy, monster[mid]._mx, monster[mid]._my);
5480 				SetMissDir(i, sd);
5481 				GetMissileVel(i, cx, cy, monster[mid]._mx, monster[mid]._my, 16);
5482 			} else {
5483 				sd = plr[id]._pdir;
5484 				SetMissDir(i, sd);
5485 				GetMissileVel(i, cx, cy, cx + XDirAdd[sd], cy + YDirAdd[sd], 16);
5486 			}
5487 		}
5488 		if (cx != missile[i]._miVar1 || cy != missile[i]._miVar2) {
5489 			missile[i]._miVar1 = cx;
5490 			missile[i]._miVar2 = cy;
5491 			ChangeLight(missile[i]._mlid, cx, cy, 8);
5492 		}
5493 		if (missile[i]._mirange == 0) {
5494 			missile[i]._mimfnum = 0;
5495 			SetMissAnim(i, MFILE_BIGEXP);
5496 			missile[i]._mirange = missile[i]._miAnimLen - 1;
5497 		}
5498 	}
5499 	PutMissile(i);
5500 }
5501 
5502 void MI_Bonespirit(Sint32 i)
5503 {
5504 	int id, mid, sd, dam;
5505 	int cx, cy;
5506 
5507 	missile[i]._mirange--;
5508 	dam = missile[i]._midam;
5509 	id = missile[i]._misource;
5510 	if (missile[i]._mimfnum == 8) {
5511 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame);
5512 		if (missile[i]._mirange == 0) {
5513 			missile[i]._miDelFlag = TRUE;
5514 			AddUnLight(missile[i]._mlid);
5515 		}
5516 		PutMissile(i);
5517 	} else {
5518 		missile[i]._mitxoff += missile[i]._mixvel;
5519 		missile[i]._mityoff += missile[i]._miyvel;
5520 		GetMissilePos(i);
5521 		cx = missile[i]._mix;
5522 		cy = missile[i]._miy;
5523 		CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE);
5524 		if (missile[i]._miVar3 == 0 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5)
5525 			missile[i]._miVar3 = 1;
5526 		if (missile[i]._miVar3 == 1) {
5527 			missile[i]._miVar3 = 2;
5528 			missile[i]._mirange = 255;
5529 			mid = FindClosest(cx, cy, 19);
5530 			if (mid > 0) {
5531 				missile[i]._midam = monster[mid]._mhitpoints >> 7;
5532 				SetMissDir(i, GetDirection8(cx, cy, monster[mid]._mx, monster[mid]._my));
5533 				GetMissileVel(i, cx, cy, monster[mid]._mx, monster[mid]._my, 16);
5534 			} else {
5535 				sd = plr[id]._pdir;
5536 				SetMissDir(i, sd);
5537 				GetMissileVel(i, cx, cy, cx + XDirAdd[sd], cy + YDirAdd[sd], 16);
5538 			}
5539 		}
5540 		if (cx != missile[i]._miVar1 || cy != missile[i]._miVar2) {
5541 			missile[i]._miVar1 = cx;
5542 			missile[i]._miVar2 = cy;
5543 			ChangeLight(missile[i]._mlid, cx, cy, 8);
5544 		}
5545 		if (missile[i]._mirange == 0) {
5546 			SetMissDir(i, 8);
5547 			missile[i]._mirange = 7;
5548 		}
5549 		PutMissile(i);
5550 	}
5551 }
5552 
5553 void MI_ResurrectBeam(Sint32 i)
5554 {
5555 	missile[i]._mirange--;
5556 	if (missile[i]._mirange == 0)
5557 		missile[i]._miDelFlag = TRUE;
5558 	PutMissile(i);
5559 }
5560 
5561 void MI_Rportal(Sint32 i)
5562 {
5563 	int ExpLight[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15 };
5564 
5565 	if (missile[i]._mirange > 1)
5566 		missile[i]._mirange--;
5567 	if (missile[i]._mirange == missile[i]._miVar1)
5568 		SetMissDir(i, 1);
5569 
5570 	if (currlevel != 0 && missile[i]._mimfnum != 1 && missile[i]._mirange != 0) {
5571 		if (missile[i]._miVar2 == 0)
5572 			missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 1);
5573 		ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]);
5574 		missile[i]._miVar2++;
5575 	}
5576 	if (missile[i]._mirange == 0) {
5577 		missile[i]._miDelFlag = TRUE;
5578 		AddUnLight(missile[i]._mlid);
5579 	}
5580 	PutMissile(i);
5581 }
5582 
5583 void ProcessMissiles()
5584 {
5585 	int i, mi;
5586 
5587 	for (i = 0; i < nummissiles; i++) {
5588 		dFlags[missile[missileactive[i]]._mix][missile[missileactive[i]]._miy] &= ~BFLAG_MISSILE;
5589 		dMissile[missile[missileactive[i]]._mix][missile[missileactive[i]]._miy] = 0;
5590 		if (missile[missileactive[i]]._mix < 0 || missile[missileactive[i]]._mix >= MAXDUNX - 1 || missile[missileactive[i]]._miy < 0 || missile[missileactive[i]]._miy >= MAXDUNY - 1)
5591 			missile[missileactive[i]]._miDelFlag = TRUE;
5592 	}
5593 
5594 	i = 0;
5595 	while (i < nummissiles) {
5596 		if (missile[missileactive[i]]._miDelFlag) {
5597 			DeleteMissile(missileactive[i], i);
5598 			i = 0;
5599 		} else {
5600 			i++;
5601 		}
5602 	}
5603 
5604 	MissilePreFlag = false;
5605 	ManashieldFlag = false;
5606 
5607 	for (i = 0; i < nummissiles; i++) {
5608 		mi = missileactive[i];
5609 		missiledata[missile[mi]._mitype].mProc(missileactive[i]);
5610 		if (!(missile[mi]._miAnimFlags & MFLAG_LOCK_ANIMATION)) {
5611 			missile[mi]._miAnimCnt++;
5612 			if (missile[mi]._miAnimCnt >= missile[mi]._miAnimDelay) {
5613 				missile[mi]._miAnimCnt = 0;
5614 				missile[mi]._miAnimFrame += missile[mi]._miAnimAdd;
5615 				if (missile[mi]._miAnimFrame > missile[mi]._miAnimLen)
5616 					missile[mi]._miAnimFrame = 1;
5617 				if (missile[mi]._miAnimFrame < 1)
5618 					missile[mi]._miAnimFrame = missile[mi]._miAnimLen;
5619 			}
5620 		}
5621 	}
5622 
5623 	if (ManashieldFlag) {
5624 		for (i = 0; i < nummissiles; i++) {
5625 			if (missile[missileactive[i]]._mitype == MIS_MANASHIELD) {
5626 				MI_Manashield(missileactive[i]);
5627 			}
5628 		}
5629 	}
5630 
5631 	i = 0;
5632 	while (i < nummissiles) {
5633 		if (missile[missileactive[i]]._miDelFlag) {
5634 			DeleteMissile(missileactive[i], i);
5635 			i = 0;
5636 		} else {
5637 			i++;
5638 		}
5639 	}
5640 }
5641 
5642 void missiles_process_charge()
5643 {
5644 	CMonster *mon;
5645 	AnimStruct *anim;
5646 	MissileStruct *mis;
5647 	int i, mi;
5648 
5649 	for (i = 0; i < nummissiles; i++) {
5650 		mi = missileactive[i];
5651 		mis = &missile[mi];
5652 		mis->_miAnimData = misfiledata[mis->_miAnimType].mAnimData[mis->_mimfnum];
5653 		if (mis->_mitype == MIS_RHINO) {
5654 			mon = monster[mis->_misource].MType;
5655 			if (mon->mtype >= MT_HORNED && mon->mtype <= MT_OBLORD) {
5656 				anim = &mon->Anims[MA_SPECIAL];
5657 			} else {
5658 				if (mon->mtype >= MT_NSNAKE && mon->mtype <= MT_GSNAKE)
5659 					anim = &mon->Anims[MA_ATTACK];
5660 				else
5661 					anim = &mon->Anims[MA_WALK];
5662 			}
5663 			missile[mi]._miAnimData = anim->Data[mis->_mimfnum];
5664 		}
5665 	}
5666 }
5667 
5668 void ClearMissileSpot(int mi)
5669 {
5670 	dFlags[missile[mi]._mix][missile[mi]._miy] &= ~BFLAG_MISSILE;
5671 	dMissile[missile[mi]._mix][missile[mi]._miy] = 0;
5672 }
5673 
5674 DEVILUTION_END_NAMESPACE
5675