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