install: add install sources and resources
[doom2d-restoration.git] / GAME / MONSTER.C
blob8eef582c0cda732788cea2d6ff276209a2264f49
1 #include "glob.h"
2 //#include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "vga.h"
6 #include "files.h"
7 #include "error.h"
8 #include "view.h"
9 #include "bmap.h"
10 #include "dots.h"
11 #include "weapons.h"
12 #include "player.h"
13 #include "monster.h"
14 #include "items.h"
15 #include "switch.h"
16 #include "misc.h"
17 #include "fx.h"
18 #include "smoke.h"
20 #define MANCOLOR 0xD0
22 #define MAX_ATM 90
24 #define MN_TN (MN__LAST-MN_DEMON)
26 extern byte z_mon;
28 enum{
29   SLEEP,GO,RUN,CLIMB,DIE,DEAD,ATTACK,SHOOT,PAIN,WAIT,REVIVE,RUNOUT
32 typedef struct{
33   obj_t o;
34   byte t,d,st,ftime;
35   int fobj;
36   int s;
37   char *ap;
38   int aim,life,pain,ac,tx,ty,ammo;
39   short atm;
40 }mn_t;
42 typedef struct{
43   int r,h,l,mp,rv,jv,sp,minp;
44 }mnsz_t;
46 byte nomon=1;
48 static char *sleepanim[MN_TN]={
49   "AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
50   "A","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
51   "A","A","AAABBB"
52 }, *goanim[MN_TN]={
53   "AABBCCDD","AABBCCDD","AABBDDAACCDD","AABBDDAACCDD","AABBDDCCDDBB",
54   "AABBDDAACCDD","AABBCCDD","AABBCCDD","A","AABB","AABBCCBB",
55   "AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF",
56   "AABB","A","DDEEFFGGHHIIJJKKLLAABBCC","ACDABD"
57 }, *painanim[MN_TN]={
58   "H","H","G","G","G","G","H","H","F","E","G","I","I","J","L","Q","EECCDDCC",
59   "A","D","G"
60 }, *waitanim[MN_TN]={
61   "A","A","A","A","A","A","A","A","A","AABB","A","A","A","I","K","A","A",
62   "A","D","E"
63 }, *attackanim[MN_TN]={
64   "EEFFGG","EEFFGG","EEEEEF","EEEEEF","EEEEEF","EF","EEFFGG","EEFFGG",
65   "BBCCDD","CCDD","DDEEFF","GH","GH","GGGGHH","GGHHII",
66   "QQGGGHHHIIJJKKLLMMNNOOPP","BBFFAA","A","OOPPQQ","EEEEFF"
67 }, *dieanim[MN_TN]={
68   "IIIJJJKKKLLLMMM","IIIJJJKKKLLL","HHHIIIJJJKKK","HHHIIIJJJKKK",
69   "HHHIIIJJJKKKLLLMMMNNNOOO","HHHIIIJJJKKKLLLMMM",
70   "IIIJJJKKKLLLMMMNNN","IIIJJJKKKLLLMMMNNN","GGGHHHIIIJJJKKK",
71   "FFFGGGHHHIIIJJJKKK","HHHIIIJJJKKKLLLMMM",
72   "JJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRR","JJJKKKLLLMMMNNNOOO",
73   "KKKLLLMMMNNNOOOPPPRRRSSS","MMMNNNOOOPPP","RRRSSSTTTUUUVVVWWWXXXYYY",
74   "DDDD","CCCDDDEEEFFFGGG","D","HHHHIIIIJJJJKKKKLLLLMMMM"
75 }, *slopanim[MN_TN]={
76   "","NNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","",
77   "OOOPPPQQQRRRSSS","","","","","","","","","","","","","","OOPPQQRRSSTTUUVV"
78 }, *deadanim[MN_TN]={
79   "N","M","L","L","P","N","O","O","L","","","S","P","T","Q","Z","C","","D","N"
80 }, *messanim[MN_TN]={
81   "","U","U","U","","T","","","","","","","","","","","","","","W"
84 int hit_xv,hit_yv;
86 static void *spr[MN_TN][29*2],*fspr[8],*fsnd,*pauksnd,*trupsnd,*sgun[2];
87 static char sprd[MN_TN][29*2];
88 static void *snd[MN_TN][5],*impsitsnd[2],*impdthsnd[2],*firsnd,*slopsnd,*gsnd[4];
89 static void *swgsnd,*pchsnd,*pl_spr[2],*telesnd;
90 static void *positsnd[3],*podthsnd[3];
91 static mn_t mn[MAXMN];
92 static int mnum,gsndt;
93 static mnsz_t mnsz[MN_TN+1]={
94 //rad  ht  life  pain rv jv  slop min_pn
95     0,  0,    0,    0, 0, 0,    0,    0,        // none
96    15, 28,   60,   20, 7,10,    0,   10,        // demon
97    10, 28,   25,   15, 3,10,   30,    0,        // imp
98    10, 28,   15,   10, 3,10,   30,    0,        // zomby
99    10, 28,   20,   10, 3,10,   30,    0,        // sergeant
100    20, 55,  500,   70, 5,10,    0,   50,        // cyberdemon
101    12, 28,   60,   20, 3,10,   30,   10,        // chaingunner
102    12, 32,  150,   40, 3,10,    0,   30,        // baron of hell
103    12, 32,   75,   40, 3,10,    0,   30,        // hell knight
104    15, 28,  100,   10, 4, 4,    0,    0,        // cacodemon
105     8, 18,   60,   10, 4, 4,    0,    0,        // lost soul
106    15, 28,  100,   10, 4, 4,    0,    0,        // pain elemental
107    64, 50,  500,   70, 4,10,    0,   50,        // spider mastermind
108    25, 27,  150,   20, 4,10,    0,    0,        // arachnotron
109    18, 30,  200,   40, 3, 7,    0,   20,        // mancubus
110    17, 36,  200,   40, 6,11,    0,   20,        // revenant
111    17, 36,  150,   30, 7,12,    0,   10,        // archvile
112     5,  5,   35,   20,14, 6,    0,   10,        // fish
113     5, 17,   20,    0, 7, 6,    0,    0,        // barrel
114    17, 38,   20,   40, 3, 6,    0,   20,        // robot
115     8, 26,  400,   70, 8,10,   30,   50         // man
118 void MN_savegame(int h) {
119   int n;
121   for(n=MAXMN;--n;) if(mn[n].t) break;
122   ++n;write(h,&n,4);
123 //  printf("Monsters: %d\n",n);
124   write(h,mn,n*sizeof(mn[0]));
125   write(h,&mnum,4);write(h,&gsndt,4);
128 static void setst(int,int);
130 void MN_loadgame(int h) {
131   int n,c;
133   read(h,&n,4);
134 //  printf("Monsters: %d\n",n);
135   read(h,mn,n*sizeof(mn[0]));
136 //  for(c=0;c<n;++c) {
137 //    printf("#%d: %d (%d,%d, %d,%d, %d) %d %d life=%d\n",c,mn[c].t,
138 //      mn[c].o.x,mn[c].o.y,
139 //      mn[c].o.r,mn[c].o.h,
140 //      mn[c].d,mn[c].st,mn[c].s,mn[c].life);
141 //  }
142   read(h,&mnum,4);read(h,&gsndt,4);
143 //  printf("mnum=%d\n",mnum);
144   for(n=0;n<MAXMN;++n) if(mn[n].t) {
145     c=mn[n].ac;setst(n,mn[n].st);mn[n].ac=c;
146   }
149 #define GGAS_TOTAL (MN__LAST-MN_DEMON+16+10)
151 void MN_alloc(void) {
152   int i,j;
153   static char sn[MN_TN][5][6]={
154         {"DMACT","DMPAIN","SGTATK","SGTSIT","SGTDTH"},
155         {"BGACT","POPAIN","CLAW","",""},
156         {"POSACT","POPAIN","","",""},
157         {"POSACT","POPAIN","","",""},
158         {"","DMPAIN","HOOF","CYBSIT","CYBDTH"},
159         {"POSACT","POPAIN","","",""},
160         {"","DMPAIN","","BRSSIT","BRSDTH"},
161         {"","DMPAIN","","KNTSIT","KNTDTH"},
162         {"DMACT","DMPAIN","","CACSIT","CACDTH"},
163         {"DMACT","DMPAIN","SKLATK","SKLATK","FIRXPL"},
164         {"DMACT","PEPAIN","","PESIT","PEDTH"},
165         {"","DMPAIN","METAL","SPISIT","SPIDTH"},
166         {"BSPACT","DMPAIN","BSPWLK","BSPSIT","BSPDTH"},
167         {"DMACT","MNPAIN","MANATK","MANSIT","MANDTH"},
168         {"SKEACT","POPAIN","SKEATK","SKESIT","SKEDTH"},
169         {"VILACT","VIPAIN","VILATK","VILSIT","VILDTH"},
170         {"","","BITE1","",""},
171         {"","","","","BAREXP"},
172         {"BSPACT","","BSPWLK","BSPSIT","BSPDTH"},
173         {"HAHA1","PLPAIN","","STOP1","PDIEHI"}
174   },msn[MN_TN][4]={
175         "SARG","TROO","POSS","SPOS","CYBR","CPOS","BOSS","BOS2","HEAD","SKUL",
176         "PAIN","SPID","BSPI","FATT","SKEL","VILE","FISH","BAR1","ROBO","PLAY"
177   };
178   static char gsn[6]="GOOD0";
179   static int mms[MN_TN]={
180         14*2,21*2,21*2,21*2,16*2,20*2,15*2,15*2,12*2,11*2,13*2,19*2,16*2,
181         20*2,17*2,29*2,6*2,2*2,17*2,23*2
182   };
184 //  logo("size of monster: %d\n",sizeof(mn[0]));
185   sgun[0]=Z_getspr("PWP4",0,1,NULL);
186   sgun[1]=Z_getspr("PWP4",1,1,NULL);
187   for(j=0;j<MN_TN;++j) {
188     for(i=0;i<mms[j];++i) spr[j][i]=Z_getspr(msn[j],i/2,(i&1)+1,&sprd[j][i]);
189     if(j==MN_BARREL-1)
190       for(i=4;i<14;++i) spr[j][i]=Z_getspr("BEXP",i/2-2,(i&1)+1,&sprd[j][i]);
191     for(i=0;i<5;++i)
192       if(sn[j][i][0]) snd[j][i]=Z_getsnd(sn[j][i]);
193         else snd[j][i]=NULL;
194     logo_gas(j+5,GGAS_TOTAL);
195   }
196   for(i=0;i<8;++i) fspr[i]=Z_getspr("FIRE",i,0,NULL);
197   pl_spr[0]=Z_getspr("PLAY",'N'-'A',0,NULL);
198   pl_spr[1]=Z_getspr("PLAY",'W'-'A',0,NULL);
199   impsitsnd[0]=Z_getsnd("BGSIT1");
200   impsitsnd[1]=Z_getsnd("BGSIT2");
201   impdthsnd[0]=Z_getsnd("BGDTH1");
202   impdthsnd[1]=Z_getsnd("BGDTH2");
203   positsnd[0]=Z_getsnd("POSIT1");
204   positsnd[1]=Z_getsnd("POSIT2");
205   positsnd[2]=Z_getsnd("POSIT3");
206   podthsnd[0]=Z_getsnd("PODTH1");
207   podthsnd[1]=Z_getsnd("PODTH2");
208   podthsnd[2]=Z_getsnd("PODTH3");
209   fsnd=Z_getsnd("FLAME");
210   firsnd=Z_getsnd("FIRSHT");
211   slopsnd=Z_getsnd("SLOP");
212   swgsnd=Z_getsnd("SKESWG");
213   pchsnd=Z_getsnd("SKEPCH");
214   telesnd=Z_getsnd("TELEPT");
215   pauksnd=Z_getsnd("PAUK1");
216   trupsnd=Z_getsnd("UTRUP");
217   for(i=0;i<4;++i) {gsn[4]=i+'1';gsnd[i]=Z_getsnd(gsn);}
220 void MN_init(void) {
221   int i;
223   for(i=0;i<MAXMN;++i) {mn[i].t=0;mn[i].st=SLEEP;}
224   gsndt=mnum=0;
227 static void setst(int i,int st) {
228   char *a;
229   int t;
231   switch(mn[i].st) {
232     case DIE: case DEAD:
233       if(st!=DEAD && st!=REVIVE) return;
234   }
235   mn[i].ac=0;
236   t=mn[i].t-1;
237   switch(mn[i].st=st) {
238         case SLEEP: a=sleepanim[t];break;
239         case PAIN: a=painanim[t];break;
240         case WAIT: a=waitanim[t];break;
241         case CLIMB:
242         case RUN: case RUNOUT:
243         case GO: a=goanim[t];break;
244         case SHOOT:
245           if(t==MN_SKEL-1) {a="KKKKJJ";break;}
246           if(t==MN_ROBO-1) {a="MN";break;}
247         case ATTACK: a=attackanim[t];
248           if(st==ATTACK && t==MN_VILE-1) a="[[\\\\]]";
249           break;
250         case DIE:
251           if(g_map==9 && t==MN_BSP-1) Z_sound(pauksnd,128);
252           a=dieanim[t];break;
253         case DEAD:
254           a=deadanim[t];
255           if(mn[i].ap==slopanim[t]) a=messanim[t];
256           if(t==MN_BARREL-1) {mn[i].t=0;}
257           break;
258         case REVIVE:
259           a=(mn[i].ap==messanim[t])?slopanim[t]:dieanim[t];
260           mn[i].ac=strlen(a)-1;
261           mn[i].o.r=mnsz[t+1].r;mn[i].o.h=mnsz[t+1].h;
262           mn[i].life=mnsz[t+1].l;mn[i].ammo=mn[i].pain=0;
263           ++mnum;
264           break;
265   }
266   mn[i].ap=a;
269 int MN_spawn(int x,int y,byte d,int t) {
270   int i;
272   if(g_dm && nomon && t<MN_PL_DEAD) return -1;
273   for(i=0;i<MAXMN;++i) if(!mn[i].t) goto ok;
274   for(i=0;i<MAXMN;++i) if(mn[i].t>=MN_PL_DEAD) goto ok;
275   return -1;
277   mn[i].o.x=x;mn[i].o.y=y;
278   mn[i].o.xv=mn[i].o.yv=mn[i].o.vx=mn[i].o.vy=0;
279   mn[i].d=d;mn[i].t=t;
280   mn[i].st=SLEEP;
281   if(t<MN_PL_DEAD) {
282     mn[i].o.r=mnsz[t].r;mn[i].o.h=mnsz[t].h;
283     mn[i].life=mnsz[t].l;
284     setst(i,SLEEP);mn[i].s=random(18);
285     ++mnum;
286   }else {mn[i].o.r=8;mn[i].o.h=6;mn[i].life=0;mn[i].st=DEAD;}
287   mn[i].aim=-3;mn[i].atm=0;
288   mn[i].pain=0;
289   mn[i].ammo=0;
290   mn[i].ftime=0;
291   return i;
294 int MN_spawn_deadpl(obj_t *o,byte c,int t) {
295   int i;
297   if((i=MN_spawn(o->x,o->y,c,t+MN_PL_DEAD))==-1) return -1;
298   mn[i].o=*o;return i;
301 static int isfriend(int a,int b) {
302   if(a==MN_BARREL || b==MN_BARREL) return 1;
303   if(a==b) switch(a) {
304     case MN_IMP: case MN_DEMON:
305     case MN_BARON: case MN_KNIGHT:
306     case MN_CACO: case MN_SOUL:
307     case MN_MANCUB: case MN_SKEL:
308     case MN_FISH:
309       return 1;
310   }
311   if(a==MN_SOUL && b==MN_PAIN) return 1;
312   if(b==MN_SOUL && a==MN_PAIN) return 1;
313   return 0;
316 static int MN_findnewprey(int i) {
317   int a,b,l;
319   a=!PL_isdead(&pl1);
320   if(_2pl) b=!PL_isdead(&pl2); else b=0;
321   if(a) {
322         if(b) mn[i].aim=(abs(mn[i].o.x-pl1.o.x)+abs(mn[i].o.y-pl1.o.y)
323             <= abs(mn[i].o.x-pl2.o.x)+abs(mn[i].o.y-pl2.o.y))?-1:-2;
324         else mn[i].aim=-1;
325   }else{
326         if(b) mn[i].aim=-2;
327         else{
328           for(a=0,b=32000,mn[i].aim=-3;a<MAXMN;++a)
329             if(mn[a].t && mn[a].st!=DEAD && a!=i && !isfriend(mn[a].t,mn[i].t))
330               if((l=abs(mn[i].o.x-mn[a].o.x)+abs(mn[i].o.y-mn[a].o.y))<b)
331                 {mn[i].aim=a;b=l;}
332           if(mn[i].aim<0) {mn[i].atm=MAX_ATM;return 0;} else mn[i].atm=0;
333         }
334   }
335   return 1;
338 int Z_getobjpos(int i,obj_t *o) {
339   if(i==-1) {*o=pl1.o;return !PL_isdead(&pl1);}
340   if(_2pl) if(i==-2) {*o=pl2.o;return !PL_isdead(&pl2);}
341   if(i>=0 && i<MAXMN) if(mn[i].t && mn[i].st!=DEAD)
342         {*o=mn[i].o;return 1;}
343   return 0;
346 static void *wakeupsnd(int t) {
347   switch(t) {
348         case MN_IMP: return impsitsnd[random(2)];
349         case MN_ZOMBY: case MN_SERG: case MN_CGUN:
350           return positsnd[random(3)];
351   }
352   return snd[t-1][3];
355 static void *dthsnd(int t) {
356   switch(t) {
357         case MN_IMP: return impdthsnd[random(2)];
358         case MN_ZOMBY: case MN_SERG: case MN_CGUN:
359           return podthsnd[random(3)];
360   }
361   return snd[t-1][4];
364 static int canshoot(int t) {
365   switch(t) {
366         case MN_DEMON: case MN_FISH: case MN_BARREL:
367           return 0;
368   }
369   return 1;
372 static int shoot(int i,obj_t *o,int n) {
373   int xd,yd,m;
375   if(mn[i].ammo<0) return 0;
376   if(!n) switch(mn[i].t) {
377         case MN_FISH: case MN_BARREL:
378         case MN_DEMON: return 0;
379         case MN_CGUN:
380         case MN_BSP:
381         case MN_ROBO:
382           if(++mn[i].ammo>=50) mn[i].ammo=(mn[i].t==MN_ROBO)?-200:-50;
383           break;
384         case MN_MAN:
385           break;
386         case MN_MANCUB:
387           if(++mn[i].ammo>=5) mn[i].ammo=-50;
388           break;
389         case MN_SPIDER:
390           if(++mn[i].ammo>=100) mn[i].ammo=-50;
391           break;
392         case MN_CYBER:
393           if(rand()&1) return 0;
394           if(++mn[i].ammo>=10) mn[i].ammo=-50;
395           break;
396         case MN_BARON: case MN_KNIGHT:
397           if(rand()&7) return 0;
398           break;
399         case MN_SKEL:
400           if(rand()&31) return 0;
401           break;
402         case MN_VILE:
403           if(rand()&7) return 0;
404           break;
405         case MN_PAIN:
406           if(rand()&7) return 0;
407           break;
408         default:
409           if(rand()&15) return 0;
410   }
411   if(!Z_look(&mn[i].o,o,mn[i].d)) return 0;
412   mn[i].atm=0;
413   mn[i].tx=o->x+(o->xv+o->vx)*6;mn[i].ty=o->y-o->h/2+(o->yv+o->vy)*6;
414   if(abs(mn[i].tx-mn[i].o.x)<abs(mn[i].ty-mn[i].o.y+mn[i].o.h/2)) return 0;
415 //  if(Z_sign(mn[i].tx-mn[i].o.x)!=mn[i].d*2-1) return 0;
416   switch(mn[i].t) {
417         case MN_IMP: case MN_BARON: case MN_KNIGHT: case MN_CACO:
418           setst(i,SHOOT);Z_sound(firsnd,128);break;
419         case MN_SKEL:
420           setst(i,SHOOT);Z_sound(snd[MN_SKEL-1][2],128);break;
421         case MN_VILE:
422           mn[i].tx=o->x;mn[i].ty=o->y;
423           setst(i,SHOOT);Z_sound(fsnd,128);
424           Z_sound(snd[MN_VILE-1][2],128);break;
425         case MN_SOUL:
426           setst(i,ATTACK);Z_sound(snd[MN_SOUL-1][2],128);
427           yd=mn[i].ty-mn[i].o.y+mn[i].o.h/2;xd=mn[i].tx-mn[i].o.x;
428           if(!(m=max(abs(xd),abs(yd)))) m=1;
429           mn[i].o.xv=xd*16/m;mn[i].o.yv=yd*16/m;
430           break;
431         case MN_MANCUB: if(mn[i].ammo==1) Z_sound(snd[MN_MANCUB-1][2],128);
432         case MN_ZOMBY: case MN_SERG: case MN_BSP: case MN_ROBO:
433         case MN_CYBER: case MN_CGUN: case MN_SPIDER:
434         case MN_PAIN: case MN_MAN:
435           setst(i,SHOOT);break;
436         default:
437           return 0;
438   }
439   return 1;
442 static int kick(int i,obj_t *o) {
443   switch(mn[i].t) {
444         case MN_FISH:
445           setst(i,ATTACK);return 1;
446         case MN_DEMON:
447           setst(i,ATTACK);Z_sound(snd[0][2],128);return 1;
448         case MN_IMP:
449           setst(i,ATTACK);Z_sound(snd[1][2],128);return 1;
450         case MN_SKEL:
451           setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
452         case MN_ROBO:
453           setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
454         case MN_BARON: case MN_KNIGHT: case MN_CACO: case MN_MANCUB:
455 //        o->xv=o->vx=o->yv=o->vy=0;
456           return shoot(i,o,1);
457   }
458   return 0;
461 static int iscorpse(obj_t *o,int n) {
462   int i;
464   if(!n) if(rand()&7) return -3;
465   for(i=0;i<MAXMN;++i) if(mn[i].t) if(mn[i].st==DEAD)
466     if(Z_overlap(o,&mn[i].o)) switch(mn[i].t) {
467       case MN_SOUL: case MN_PAIN:
468       case MN_CYBER: case MN_SPIDER:
469       case MN_PL_DEAD: case MN_PL_MESS:
470       case MN_VILE: case MN_BARREL:
471         continue;
472       default:
473         return i;
474     }
475   return -3;
478 void MN_act(void) {
479   int i,st,sx,sy,t;
480   static obj_t o;
481   static int pt_x=0,pt_xs=1,pt_y=0,pt_ys=1;
483   if(abs(pt_x+=pt_xs) > 123) pt_xs=-pt_xs;
484   if(abs(pt_y+=pt_ys) > 50) pt_ys=-pt_ys;
485   if(gsndt>0) if(--gsndt==0) {
486         Z_sound(gsnd[random(4)],128);
487   }
488   for(i=0;i<MAXMN;++i) if((t=mn[i].t)!=0) {
489   switch(t) {
490         case MN_FISH:
491           if(!Z_inwater(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h)) break;
492         case MN_SOUL: case MN_PAIN: case MN_CACO:
493           if(mn[i].st!=DIE && mn[i].st!=DEAD) --mn[i].o.yv;
494           break;
495   }z_mon=1;st=Z_moveobj(&mn[i].o);z_mon=0;
496   BM_mark(&mn[i].o,BM_MONSTER);
497   if(st&Z_FALLOUT) {
498     if(t==MN_ROBO) g_exit=1;
499     mn[i].t=0;--mnum;continue;
500   }
501   if(st&Z_HITWATER) Z_splash(&mn[i].o,mn[i].o.r+mn[i].o.h);
502   SW_press(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h,8,i);
503   if(mn[i].ftime) {
504     --mn[i].ftime;
505     SMK_flame(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,
506       mn[i].o.xv+mn[i].o.vx,mn[i].o.yv+mn[i].o.vy,
507       mn[i].o.r/2,mn[i].o.h/2,rand()%(200*2+1)-200,-500,1,mn[i].fobj);
508   }
509   if(st&Z_INWATER) mn[i].ftime=0;
510   if(mn[i].st==DEAD) continue;
511   if(st&Z_INWATER) if(!(rand()&31)) switch(t) {
512     case MN_FISH:
513       if(rand()&3) break;
514     case MN_ROBO: case MN_BARREL:
515     case MN_PL_DEAD: case MN_PL_MESS:
516       FX_bubble(mn[i].o.x+((rand()&1)*2-1)*random(mn[i].o.r+1),
517         mn[i].o.y-random(mn[i].o.h+1),0,0,1
518       );
519       break;
520     default:
521       FX_bubble(mn[i].o.x,mn[i].o.y-mn[i].o.h*3/4,0,0,5);
522   }
523 //  mn[i].o.h=mnsz[t].h;
524   if(t==MN_BARREL) {
525 //    BM_mark(&mn[i].o,BM_MONSTER);
526     if(!mn[i].ap[++mn[i].ac]) {
527       mn[i].ac=0;if(mn[i].st==DIE || mn[i].st==DEAD) {mn[i].t=0;}
528     }else if(mn[i].st==DIE && mn[i].ac==2) Z_explode(mn[i].o.x,mn[i].o.y-8,30,mn[i].aim);
529     continue;
530   }
531   if(t==MN_SOUL) if(st&Z_HITAIR) Z_set_speed(&mn[i].o,16);
532   if(mn[i].ammo<0) ++mn[i].ammo;
533   if(mn[i].o.yv<0)
534         if(st&Z_INWATER) mn[i].o.yv=-4;
535   ++mn[i].atm;
536   switch(mn[i].st) {
537    case PAIN:
538         if(mn[i].pain>=mnsz[t].mp)
539           {mn[i].pain=mnsz[t].mp;Z_sound(snd[t-1][1],128);}
540         if((mn[i].pain-=5)<=mnsz[t].minp)
541           {setst(i,GO);mn[i].pain=0;mn[i].ammo=-9;}
542         break;
543    case SLEEP:
544         if(++mn[i].s>=18) mn[i].s=0; else break;
545         if(Z_look(&mn[i].o,&pl1.o,mn[i].d))
546           {setst(i,GO);mn[i].aim=-1;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
547         if(_2pl) if(Z_look(&mn[i].o,&pl2.o,mn[i].d))
548           {setst(i,GO);mn[i].aim=-2;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
549         break;
550    case WAIT:
551         if(--mn[i].s<0) setst(i,GO);
552         break;
553    case GO:
554         if(st&Z_BLOCK) {mn[i].d^=1;setst(i,RUNOUT);mn[i].s=40;break;}
555         if(t==MN_VILE) if(iscorpse(&mn[i].o,0)>=0) {
556           setst(i,ATTACK);mn[i].o.xv=0;break;
557         }
558         if(!Z_getobjpos(mn[i].aim,&o) || mn[i].atm>MAX_ATM)
559           if(!MN_findnewprey(i)) {
560                 mn[i].aim=-3;
561                 o.x=mn[i].o.x+pt_x;o.y=mn[i].o.y+pt_y;
562                 o.xv=o.vx=o.yv=o.vy=o.r=0;o.h=1;
563           }else Z_getobjpos(mn[i].aim,&o);
564           if(Z_overlap(&mn[i].o,&o)) {
565             mn[i].atm=0;
566             if(kick(i,&o)) break;
567           }
568           sx=o.x-mn[i].o.x;
569           sy=o.y-o.h/2-mn[i].o.y+mn[i].o.h/2;
570           if(!(st&Z_BLOCK)) if(abs(sx)<20)
571             if(t!=MN_FISH) {setst(i,RUN);mn[i].s=15;mn[i].d=rand()&1;break;}
572           if(st&Z_HITWALL) {
573                 if(SW_press(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h,2,i))
574                   {setst(i,WAIT);mn[i].s=4;break;}
575                 switch(t) {
576                   case MN_CACO: case MN_SOUL: case MN_PAIN: case MN_FISH:
577                         break;
578                   default:
579                         if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
580                           {mn[i].o.yv=-mnsz[t].jv;setst(i,CLIMB);break;}
581                 }break;
582           }
583           mn[i].d=(sx>0)?1:0;
584           if(canshoot(t))
585                 if(abs(sx)>abs(sy)) if(shoot(i,&o,0)) break;
586 //        if(st&Z_BLOCK) {mn[i].o.xv=0;mn[i].ap=waitanim[t-1];mn[i].ac=0;break;}
587           switch(t) {
588                 case MN_FISH:
589                   if(!(st&Z_INWATER)) {
590                     if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r)) {
591                       mn[i].o.yv=-6;
592                       mn[i].o.vx+=rand()%17-8;
593                     }setst(i,PAIN);mn[i].pain+=50;break;
594                   }
595                 case MN_CACO: case MN_SOUL: case MN_PAIN:
596                   if(abs(sy)>4) mn[i].o.yv=(sy<0)?-4:4; else mn[i].o.yv=0;
597                   if(t==MN_FISH) if(mn[i].o.yv<0)
598                     if(!Z_inwater(mn[i].o.x,mn[i].o.y-8,mn[i].o.r,mn[i].o.h))
599                       {mn[i].o.yv=0;setst(i,RUN);mn[i].d=rand()&1;mn[i].s=20;}
600                   break;
601                 default:
602                   if(sy<-20) if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
603                         if(!(rand()&3)) mn[i].o.yv=-mnsz[t].jv;
604           }
605         if(++mn[i].s>=8) {
606           mn[i].s=0;
607           if(!(rand()&7)) Z_sound(snd[t-1][0],128);
608         }
609         mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
610         if(st&Z_INWATER) mn[i].o.xv/=2;
611           else if(t==MN_FISH) mn[i].o.xv=0;
612         break;
613    case RUN:
614         if(st&Z_BLOCK) {setst(i,RUNOUT);mn[i].d^=1;mn[i].s=40;break;}
615         if(--mn[i].s<=0 || ((st&Z_HITWALL) && mn[i].o.yv+mn[i].o.vy==0)) {
616           setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
617           if(!(rand()&7)) Z_sound(snd[t-1][0],128);
618         }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
619         if(st&Z_INWATER) mn[i].o.xv/=2;
620           else if(t==MN_FISH) mn[i].o.xv=0;
621         break;
622    case RUNOUT:
623         if(!(st&Z_BLOCK) && mn[i].s>0) mn[i].s=0;
624         if(--mn[i].s<=-18) {
625           setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
626           if(!(rand()&7)) Z_sound(snd[t-1][0],128);
627         }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
628         if(st&Z_INWATER) mn[i].o.xv/=2;
629           else if(t==MN_FISH) mn[i].o.xv=0;
630         break;
631    case CLIMB:
632         if(mn[i].o.yv+mn[i].o.vy>=0 || !(st&Z_HITWALL)) {
633           setst(i,GO);mn[i].s=0;
634           if(st&(Z_HITWALL|Z_BLOCK)) {mn[i].d^=1;setst(i,RUN);mn[i].s=15;}
635         }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
636         if(st&Z_INWATER) mn[i].o.xv/=2;
637           else if(t==MN_FISH) mn[i].o.xv=0;
638         break;
639    case ATTACK:
640    case SHOOT:
641         if(t==MN_SOUL) {if(st&(Z_HITWALL|Z_HITCEIL|Z_HITLAND)) setst(i,GO); break;}
642         if(t!=MN_FISH) mn[i].o.xv=Z_dec(mn[i].o.xv,1);
643         if(t==MN_VILE && mn[i].st==SHOOT) {
644           if(!Z_getobjpos(mn[i].aim,&o)) {setst(i,GO);break;}
645           if(!Z_look(&mn[i].o,&o,mn[i].d)) {setst(i,GO);break;}
646           if(Z_inwater(o.x,o.y,o.r,o.h)) {setst(i,GO);break;}
647           mn[i].tx=o.x;mn[i].ty=o.y;
648           Z_hitobj(mn[i].aim,2,i,HIT_SOME);
649         }break;
650   }
651   if(mn[i].st==REVIVE) {
652     if(--mn[i].ac==0) setst(i,GO);
653   }else ++mn[i].ac;
654   if(!mn[i].ap[mn[i].ac]) switch(mn[i].st) {
655         case ATTACK:
656           switch(t) {
657                 case MN_SOUL: mn[i].ac=0;
658                 case MN_IMP:
659                 case MN_DEMON:
660                   if(Z_hit(&mn[i].o,15,i,HIT_SOME)) if(t==MN_SOUL) setst(i,GO);
661                   break;
662                 case MN_FISH:
663                   if(Z_hit(&mn[i].o,10,i,HIT_SOME))
664                     Z_sound(snd[MN_FISH-1][2],128);
665                   break;
666                 case MN_SKEL: case MN_ROBO:
667                   o=mn[i].o;o.xv=mn[i].d?50:-50;
668                   if(Z_hit(&o,50,i,HIT_SOME)) Z_sound(pchsnd,128);
669                   break;
670                 case MN_VILE:
671                   sx=iscorpse(&mn[i].o,1);
672                   if(sx==-3) break;
673                   if(!mn[sx].t || mn[sx].st!=DEAD) break;
674                   setst(sx,REVIVE);Z_sound(slopsnd,128);
675                   hit_xv=hit_yv=0;MN_hit(i,5,-3,HIT_SOME);
676                   break;
677           }if(t!=MN_SOUL && mn[i].st!=DIE) setst(i,GO);
678           break;
679         case SHOOT:
680           switch(t) {
681                 case MN_IMP:
682                   WP_ball1(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
683                   break;
684                 case MN_ZOMBY:
685                   WP_pistol(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
686                   break;
687                 case MN_SERG:
688                   WP_shotgun(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
689                   break;
690                 case MN_MAN:
691                   WP_dshotgun(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
692                   mn[i].ammo=-36;break;
693                 case MN_CYBER:
694                   WP_rocket(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
695                   break;
696                 case MN_SKEL:
697                   WP_revf(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i,mn[i].aim);
698                   break;
699                 case MN_CGUN:
700                 case MN_SPIDER:
701                   WP_mgun(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
702                   break;
703                 case MN_BSP:
704                   WP_aplasma(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
705                   break;
706                 case MN_ROBO:
707                   WP_plasma(mn[i].o.x+(mn[i].d*2-1)*15,mn[i].o.y-30,mn[i].tx,mn[i].ty,i);
708                   break;
709                 case MN_MANCUB:
710                   WP_manfire(mn[i].o.x+(mn[i].d*2-1)*mn[i].o.r,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
711                   break;
712                 case MN_BARON: case MN_KNIGHT:
713                   WP_ball7(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
714                   break;
715                 case MN_CACO:
716                   WP_ball2(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
717                   break;
718                 case MN_PAIN:
719                   if((sx=MN_spawn(mn[i].o.x,mn[i].o.y,mn[i].d,MN_SOUL))==-1) break;
720                   Z_getobjpos(mn[sx].aim=mn[i].aim,&o);mn[sx].atm=0;
721                   shoot(sx,&o,1);
722                   break;
723           }
724           if(t==MN_CGUN || t==MN_SPIDER || t==MN_BSP || t==MN_MANCUB || t==MN_ROBO)
725              if(!Z_getobjpos(mn[i].aim,&o)) MN_findnewprey(i);
726                 else if(shoot(i,&o,0)) break;
727           setst(i,GO);break;
728         case DIE:
729           setst(i,DEAD);
730           if(t==MN_PAIN || t==MN_SOUL) mn[i].ftime=0;
731           if(t==MN_PAIN) {
732                 if((sx=MN_spawn(mn[i].o.x-15,mn[i].o.y,0,MN_SOUL))==-1) break;
733                 setst(sx,GO);
734                 if((sx=MN_spawn(mn[i].o.x+15,mn[i].o.y,1,MN_SOUL))==-1) break;
735                 setst(sx,GO);
736                 if((sx=MN_spawn(mn[i].o.x,mn[i].o.y-10,1,MN_SOUL))==-1) break;
737                 setst(sx,GO);
738           }break;
739         default: mn[i].ac=0;
740   }
741   switch(mn[i].st) {
742         case GO: case RUN: case CLIMB: case RUNOUT:
743           if(t==MN_CYBER || t==MN_SPIDER || t==MN_BSP) {
744             if(mn[i].ac==0 || mn[i].ac==6) Z_sound(snd[t-1][2],128);
745           }else if(t==MN_ROBO)
746             if(mn[i].ac==0 || mn[i].ac==12) Z_sound(snd[t-1][2],128);
747   }
748   }
751 void MN_mark(void) {
752   int i;
754   for(i=0;i<MAXMN;++i) if(mn[i].t!=0) BM_mark(&mn[i].o,BM_MONSTER);
757 void MN_draw(void) {
758   int i;
760   for(i=0;i<MAXMN;++i) if(mn[i].t) {
761         if(mn[i].t>=MN_PL_DEAD) {
762           Z_drawmanspr(mn[i].o.x,mn[i].o.y,pl_spr[mn[i].t-MN_PL_DEAD],0,mn[i].d);
763           continue;
764         }
765         if((mn[i].t!=MN_SOUL && mn[i].t!=MN_PAIN) || mn[i].st!=DEAD) {
766           if(mn[i].t!=MN_MAN)
767             Z_drawspr(mn[i].o.x,mn[i].o.y,
768                 spr[mn[i].t-1][(mn[i].ap[mn[i].ac]-'A')*2+mn[i].d],
769                 sprd[mn[i].t-1][(mn[i].ap[mn[i].ac]-'A')*2+mn[i].d]);
770           else{
771             if(mn[i].ap[mn[i].ac]=='E' || mn[i].ap[mn[i].ac]=='F')
772               Z_drawspr(mn[i].o.x,mn[i].o.y,sgun[mn[i].ap[mn[i].ac]-'E'],mn[i].d);
773             Z_drawmanspr(mn[i].o.x,mn[i].o.y,
774                 spr[mn[i].t-1][(mn[i].ap[mn[i].ac]-'A')*2+mn[i].d],
775                 sprd[mn[i].t-1][(mn[i].ap[mn[i].ac]-'A')*2+mn[i].d],MANCOLOR);
776           }
777         }
778         if(mn[i].t==MN_VILE && mn[i].st==SHOOT)
779           Z_drawspr(mn[i].tx,mn[i].ty,fspr[mn[i].ac/3],0);
780   }
783 static int MN_hit(int n,int d,int o,int t) {
784   int i;
786   if(mn[n].st==DEAD || mn[n].st==DIE) return 0;
787   if(o==n) {
788         if(t!=HIT_ROCKET && t!=HIT_ELECTRO) return 0;
789         if(mn[n].t==MN_CYBER || mn[n].t==MN_BARREL) return 1;
790   }
791   if(o>=0) {
792         if(mn[o].t==MN_SOUL && mn[n].t==MN_PAIN) return 0;
793         if(mn[o].t==mn[n].t) switch(mn[n].t) {
794           case MN_IMP: case MN_DEMON:
795           case MN_BARON: case MN_KNIGHT:
796           case MN_CACO: case MN_SOUL:
797           case MN_MANCUB: case MN_SKEL:
798           case MN_FISH:
799                 return 0;
800         }
801   }
802   if(t==HIT_FLAME) if(mn[n].ftime && mn[n].fobj==o) {if(g_time&31) return 1;}
803     else {mn[n].ftime=255;mn[n].fobj=o;}
804   if(t==HIT_ELECTRO) if(mn[n].t==MN_FISH)
805     {setst(n,RUN);mn[n].s=20;mn[n].d=rand()&1;return 1;}
806   if(t==HIT_TRAP) mn[n].life=-100;
807   if(mn[n].t==MN_ROBO) d=0;
808   if((mn[n].life-=d)<=0) --mnum;
809   if(!mn[n].pain) mn[n].pain=3;
810   mn[n].pain+=d;
811   if(mn[n].st!=PAIN) {
812         if(mn[n].pain>=mnsz[mn[n].t].minp) setst(n,PAIN);
813   }
814   if(mn[n].t!=MN_BARREL)
815     DOT_blood(mn[n].o.x,mn[n].o.y-mn[n].o.h/2,hit_xv,hit_yv,d*2);
816   mn[n].aim=o;mn[n].atm=0;
817   if(mn[n].life<=0) {
818         if(mn[n].t!=MN_BARREL)
819           if(o==-1) ++pl1.kills;
820           else if(o==-2) ++pl2.kills;
821         setst(n,DIE);
822 //      if(mn[n].t==MN_BARREL)
823 //        {Z_explode(mn[n].o.x,mn[n].o.y-8,30,o);}
824         switch(mn[n].t) {
825           case MN_ZOMBY: i=I_CLIP;break;
826           case MN_SERG: i=I_SGUN;break;
827           case MN_CGUN: i=I_MGUN;break;
828           case MN_MAN: i=I_KEYR;break;
829           default: i=0;
830         }if(i) IT_spawn(mn[n].o.x,mn[n].o.y,i);
831         mn[n].o.xv=0;mn[n].o.h=6;//mn[n].o.r=8;
832         if(mn[n].life<=-mnsz[mn[n].t].sp)
833           switch(mn[n].t) {
834                 case MN_IMP: case MN_ZOMBY: case MN_SERG: case MN_CGUN:
835                 case MN_MAN:
836                   mn[n].ap=slopanim[mn[n].t-1];
837                   Z_sound(slopsnd,128);
838                   break;
839                 case MN_BSP: if(g_map==9) break;
840                 default:
841                   Z_sound(dthsnd(mn[n].t),128);
842           }
843         else if(mn[n].t!=MN_BSP || g_map!=9) Z_sound(dthsnd(mn[n].t),128);
844         mn[n].life=0;
845   }else if(mn[n].st==SLEEP) {setst(n,GO);mn[n].pain=mnsz[mn[n].t].mp;}
846   return 1;
849 #define hit(o,x,y) (y<=o.y && y>o.y-o.h && x>=o.x-o.r && x<=o.x+o.r)
851 int Z_gunhit(int x,int y,int o,int xv,int yv) {
852   int i;
854   if(o!=-1) if(hit(pl1.o,x,y)) if(PL_hit(&pl1,3,o,HIT_SOME))
855     {pl1.o.vx+=xv;pl1.o.vy+=yv;return -1;}
856   if(_2pl && o!=-2) if(hit(pl2.o,x,y)) if(PL_hit(&pl2,3,o,HIT_SOME))
857     {pl2.o.vx+=xv;pl2.o.vy+=yv;return -2;}
858 //  if(!mnum) return 0;
859   for(i=0;i<MAXMN;++i) if(mn[i].t && o!=i)
860     if(hit(mn[i].o,x,y)) if(MN_hit(i,3,o,HIT_SOME))
861       {mn[i].o.vx+=xv;mn[i].o.vy+=yv;return 1;}
862   return 0;
865 static void goodsnd(void) {
866   if(!g_dm) return;
867   gsndt=18;
870 int Z_hit(obj_t *o,int d,int own,int t) {
871   int i;
873   hit_xv=o->xv+o->vx;
874   hit_yv=o->yv+o->vy;
875   if(Z_overlap(o,&pl1.o)) if(PL_hit(&pl1,d,own,t)) {
876         pl1.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
877         pl1.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
878         if(t==HIT_BFG) goodsnd();
879         return -1;
880   }
881   if(_2pl) if(Z_overlap(o,&pl2.o)) if(PL_hit(&pl2,d,own,t)) {
882         pl2.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
883         pl2.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
884         if(t==HIT_BFG) goodsnd();
885         return -2;
886   }
887 //  if(!mnum) return 0;
888   for(i=0;i<MAXMN;++i) if(mn[i].t)
889     if(Z_overlap(o,&mn[i].o)) if(MN_hit(i,d,own,t)) {
890           mn[i].o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
891           mn[i].o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
892           return 1;
893     }
894   return 0;
897 void MN_killedp(void) {
898   int i;
900   for(i=0;i<MAXMN;++i) if(mn[i].t==MN_MAN)
901     if(mn[i].st!=DEAD && mn[i].st!=DIE && mn[i].st!=SLEEP)
902       Z_sound(trupsnd,128);
905 int Z_hitobj(int obj,int d,int own,int t) {
906   hit_xv=hit_yv=0;
907   if(obj==-1) return PL_hit(&pl1,d,own,t);
908   else if(obj==-2 && _2pl) return PL_hit(&pl2,d,own,t);
909   else if(obj<0 || obj>=MAXMN) return 0;
910   if(mn[obj].t) return MN_hit(obj,d,own,t);
911   return 0;
914 void Z_explode(int x,int y,int rad,int own) {
915   long r;
916   int dx,dy,m,i;
918   if(x<-100 || x>FLDW*CELW+100) return;
919   if(y<-100 || y>FLDH*CELH+100) return;
920   r=(long)rad*rad;
921   dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
922   if((long)dx*dx+(long)dy*dy<r) {
923     if(!(m=max(abs(dx),abs(dy)))) m=1;
924         pl1.o.vx+=hit_xv=dx*10/m;
925         pl1.o.vy+=hit_yv=dy*10/m;
926         PL_hit(&pl1,100*(rad-m)/rad,own,HIT_ROCKET);
927   }
928   if(_2pl) {
929     dx=pl2.o.x-x;dy=pl2.o.y-pl2.o.h/2-y;
930     if((long)dx*dx+(long)dy*dy<r) {
931       if(!(m=max(abs(dx),abs(dy)))) m=1;
932           pl2.o.vx+=hit_xv=dx*10/m;
933           pl2.o.vy+=hit_yv=dy*10/m;
934       PL_hit(&pl2,100*(rad-m)/rad,own,HIT_ROCKET);
935     }
936   }
937   for(i=0;i<MAXMN;++i) if(mn[i].t) {
938     dx=mn[i].o.x-x;dy=mn[i].o.y-mn[i].o.h/2-y;
939     if((long)dx*dx+(long)dy*dy<r) {
940       if(!(m=max(abs(dx),abs(dy)))) m=1;
941           mn[i].o.vx+=hit_xv=dx*10/m;
942           mn[i].o.vy+=hit_yv=dy*10/m;
943           MN_hit(i,mn[i].o.r*10*(rad-m)/rad,own,HIT_ROCKET);
944     }
945   }
948 void Z_bfg9000(int x,int y,int own) {
949   int dx,dy,i;
951   hit_xv=hit_yv=0;
952   if(x<-100 || x>FLDW*CELW+100) return;
953   if(y<-100 || y>FLDH*CELH+100) return;
954   dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
955   if(own!=-1) if((long)dx*dx+(long)dy*dy<16000)
956    if(Z_cansee(x,y,pl1.o.x,pl1.o.y-pl1.o.h/2)) {
957     if(PL_hit(&pl1,50,own,HIT_SOME))
958       WP_bfghit(pl1.o.x,pl1.o.y-pl1.o.h/2,own);
959   }
960   if(_2pl) {
961     dx=pl2.o.x-x;dy=pl2.o.y-pl2.o.h/2-y;
962     if(own!=-2) if((long)dx*dx+(long)dy*dy<16000)
963      if(Z_cansee(x,y,pl2.o.x,pl2.o.y-pl2.o.h/2)) {
964       if(PL_hit(&pl2,50,own,HIT_SOME))
965         WP_bfghit(pl2.o.x,pl2.o.y-pl2.o.h/2,own);
966     }
967   }
968 //  if(!mnum) return;
969   for(i=0;i<MAXMN;++i) if(mn[i].t && own!=i) {
970     dx=mn[i].o.x-x;dy=mn[i].o.y-mn[i].o.h/2-y;
971     if((long)dx*dx+(long)dy*dy<16000)
972      if(Z_cansee(x,y,mn[i].o.x,mn[i].o.y-mn[i].o.h/2)) {
973       if(MN_hit(i,50,own,HIT_SOME))
974         WP_bfghit(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,own);
975     }
976   }
979 int Z_chktrap(int t,int d,int o,int ht) {
980   int i,s;
982   hit_xv=hit_yv=0;
983   s=0;
984   if(Z_istrapped(pl1.o.x,pl1.o.y,pl1.o.r,pl1.o.h)) {
985     s=1;
986         if(t) PL_hit(&pl1,d,o,ht);
987   }
988   if(_2pl) if(Z_istrapped(pl2.o.x,pl2.o.y,pl2.o.r,pl2.o.h)) {
989         s=1;
990         if(t) PL_hit(&pl2,d,o,ht);
991   }
992 //  if(!mnum) return s;
993   for(i=0;i<MAXMN;++i) if(mn[i].t && mn[i].st!=DEAD)
994     if(Z_istrapped(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h)) {
995       s=1;
996           if(t) MN_hit(i,d,o,ht);
997         }
998   return s;
1001 void Z_teleobj(int o,int x,int y) {
1002   obj_t *p;
1004   if(o==-1) p=&pl1.o;
1005   else if(o==-2) p=&pl2.o;
1006   else if(o>=0 && o<MAXMN) p=&mn[o].o;
1007   else return;
1008   FX_tfog(p->x,p->y);FX_tfog(p->x=x,p->y=y);
1009   Z_sound(telesnd,128);
1012 void MN_warning(int l,int t,int r,int b) {
1013   int i;
1015   for(i=0;i<MAXMN;++i) if(mn[i].t && mn[i].t!=MN_CACO && mn[i].t!=MN_SOUL
1016       && mn[i].t!=MN_PAIN && mn[i].t!=MN_FISH)
1017     if(mn[i].st!=DIE && mn[i].st!=DEAD && mn[i].st!=SLEEP)
1018       if(mn[i].o.x+mn[i].o.r>=l && mn[i].o.x-mn[i].o.r<=r
1019       && mn[i].o.y>=t && mn[i].o.y-mn[i].o.h<=b)
1020         if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
1021           mn[i].o.yv=-mnsz[mn[i].t].jv;