24 #define MN_TN (MN__LAST-MN_DEMON)
29 SLEEP,GO,RUN,CLIMB,DIE,DEAD,ATTACK,SHOOT,PAIN,WAIT,REVIVE,RUNOUT
38 int aim,life,pain,ac,tx,ty,ammo;
43 int r,h,l,mp,rv,jv,sp,minp;
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",
53 "AABBCCDD","AABBCCDD","AABBDDAACCDD","AABBDDAACCDD","AABBDDCCDDBB",
54 "AABBDDAACCDD","AABBCCDD","AABBCCDD","A","AABB","AABBCCBB",
55 "AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF",
56 "AABB","A","DDEEFFGGHHIIJJKKLLAABBCC","ACDABD"
58 "H","H","G","G","G","G","H","H","F","E","G","I","I","J","L","Q","EECCDDCC",
61 "A","A","A","A","A","A","A","A","A","AABB","A","A","A","I","K","A","A",
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"
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"
76 "","NNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","",
77 "OOOPPPQQQRRRSSS","","","","","","","","","","","","","","OOPPQQRRSSTTUUVV"
79 "N","M","L","L","P","N","O","O","L","","","S","P","T","Q","Z","C","","D","N"
81 "","U","U","U","","T","","","","","","","","","","","","","","W"
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) {
121 for(n=MAXMN;--n;) if(mn[n].t) break;
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) {
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);
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;
149 #define GGAS_TOTAL (MN__LAST-MN_DEMON+16+10)
151 void MN_alloc(void) {
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"}
175 "SARG","TROO","POSS","SPOS","CYBR","CPOS","BOSS","BOS2","HEAD","SKUL",
176 "PAIN","SPID","BSPI","FATT","SKEL","VILE","FISH","BAR1","ROBO","PLAY"
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
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]);
190 for(i=4;i<14;++i) spr[j][i]=Z_getspr("BEXP",i/2-2,(i&1)+1,&sprd[j][i]);
192 if(sn[j][i][0]) snd[j][i]=Z_getsnd(sn[j][i]);
194 logo_gas(j+5,GGAS_TOTAL);
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);}
223 for(i=0;i<MAXMN;++i) {mn[i].t=0;mn[i].st=SLEEP;}
227 static void setst(int i,int st) {
233 if(st!=DEAD && st!=REVIVE) return;
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;
242 case RUN: case RUNOUT:
243 case GO: a=goanim[t];break;
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="[[\\\\]]";
251 if(g_map==9 && t==MN_BSP-1) Z_sound(pauksnd,128);
255 if(mn[i].ap==slopanim[t]) a=messanim[t];
256 if(t==MN_BARREL-1) {mn[i].t=0;}
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;
269 int MN_spawn(int x,int y,byte d,int t) {
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;
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;
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);
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;
294 int MN_spawn_deadpl(obj_t *o,byte c,int t) {
297 if((i=MN_spawn(o->x,o->y,c,t+MN_PL_DEAD))==-1) return -1;
301 static int isfriend(int a,int b) {
302 if(a==MN_BARREL || b==MN_BARREL) return 1;
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:
311 if(a==MN_SOUL && b==MN_PAIN) return 1;
312 if(b==MN_SOUL && a==MN_PAIN) return 1;
316 static int MN_findnewprey(int i) {
320 if(_2pl) b=!PL_isdead(&pl2); else b=0;
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;
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)
332 if(mn[i].aim<0) {mn[i].atm=MAX_ATM;return 0;} else mn[i].atm=0;
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;}
346 static void *wakeupsnd(int t) {
348 case MN_IMP: return impsitsnd[random(2)];
349 case MN_ZOMBY: case MN_SERG: case MN_CGUN:
350 return positsnd[random(3)];
355 static void *dthsnd(int t) {
357 case MN_IMP: return impdthsnd[random(2)];
358 case MN_ZOMBY: case MN_SERG: case MN_CGUN:
359 return podthsnd[random(3)];
364 static int canshoot(int t) {
366 case MN_DEMON: case MN_FISH: case MN_BARREL:
372 static int shoot(int i,obj_t *o,int n) {
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;
382 if(++mn[i].ammo>=50) mn[i].ammo=(mn[i].t==MN_ROBO)?-200:-50;
387 if(++mn[i].ammo>=5) mn[i].ammo=-50;
390 if(++mn[i].ammo>=100) mn[i].ammo=-50;
393 if(rand()&1) return 0;
394 if(++mn[i].ammo>=10) mn[i].ammo=-50;
396 case MN_BARON: case MN_KNIGHT:
397 if(rand()&7) return 0;
400 if(rand()&31) return 0;
403 if(rand()&7) return 0;
406 if(rand()&7) return 0;
409 if(rand()&15) return 0;
411 if(!Z_look(&mn[i].o,o,mn[i].d)) return 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;
417 case MN_IMP: case MN_BARON: case MN_KNIGHT: case MN_CACO:
418 setst(i,SHOOT);Z_sound(firsnd,128);break;
420 setst(i,SHOOT);Z_sound(snd[MN_SKEL-1][2],128);break;
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;
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;
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;
442 static int kick(int i,obj_t *o) {
445 setst(i,ATTACK);return 1;
447 setst(i,ATTACK);Z_sound(snd[0][2],128);return 1;
449 setst(i,ATTACK);Z_sound(snd[1][2],128);return 1;
451 setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
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;
461 static int iscorpse(obj_t *o,int n) {
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:
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);
488 for(i=0;i<MAXMN;++i) if((t=mn[i].t)!=0) {
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;
495 }z_mon=1;st=Z_moveobj(&mn[i].o);z_mon=0;
496 BM_mark(&mn[i].o,BM_MONSTER);
498 if(t==MN_ROBO) g_exit=1;
499 mn[i].t=0;--mnum;continue;
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);
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);
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) {
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
521 FX_bubble(mn[i].o.x,mn[i].o.y-mn[i].o.h*3/4,0,0,5);
523 // mn[i].o.h=mnsz[t].h;
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);
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;
534 if(st&Z_INWATER) mn[i].o.yv=-4;
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;}
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);}
551 if(--mn[i].s<0) setst(i,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;
558 if(!Z_getobjpos(mn[i].aim,&o) || mn[i].atm>MAX_ATM)
559 if(!MN_findnewprey(i)) {
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)) {
566 if(kick(i,&o)) break;
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;}
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;}
576 case MN_CACO: case MN_SOUL: case MN_PAIN: case MN_FISH:
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;}
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;}
589 if(!(st&Z_INWATER)) {
590 if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r)) {
592 mn[i].o.vx+=rand()%17-8;
593 }setst(i,PAIN);mn[i].pain+=50;break;
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;}
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;
607 if(!(rand()&7)) Z_sound(snd[t-1][0],128);
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;
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;
623 if(!(st&Z_BLOCK) && mn[i].s>0) mn[i].s=0;
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;
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;
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);
651 if(mn[i].st==REVIVE) {
652 if(--mn[i].ac==0) setst(i,GO);
654 if(!mn[i].ap[mn[i].ac]) switch(mn[i].st) {
657 case MN_SOUL: mn[i].ac=0;
660 if(Z_hit(&mn[i].o,15,i,HIT_SOME)) if(t==MN_SOUL) setst(i,GO);
663 if(Z_hit(&mn[i].o,10,i,HIT_SOME))
664 Z_sound(snd[MN_FISH-1][2],128);
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);
671 sx=iscorpse(&mn[i].o,1);
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);
677 }if(t!=MN_SOUL && mn[i].st!=DIE) setst(i,GO);
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);
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);
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);
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;
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);
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);
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);
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);
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);
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);
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);
716 WP_ball2(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
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;
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;
730 if(t==MN_PAIN || t==MN_SOUL) mn[i].ftime=0;
732 if((sx=MN_spawn(mn[i].o.x-15,mn[i].o.y,0,MN_SOUL))==-1) break;
734 if((sx=MN_spawn(mn[i].o.x+15,mn[i].o.y,1,MN_SOUL))==-1) break;
736 if((sx=MN_spawn(mn[i].o.x,mn[i].o.y-10,1,MN_SOUL))==-1) break;
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);
746 if(mn[i].ac==0 || mn[i].ac==12) Z_sound(snd[t-1][2],128);
754 for(i=0;i<MAXMN;++i) if(mn[i].t!=0) BM_mark(&mn[i].o,BM_MONSTER);
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);
765 if((mn[i].t!=MN_SOUL && mn[i].t!=MN_PAIN) || mn[i].st!=DEAD) {
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]);
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);
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);
783 static int MN_hit(int n,int d,int o,int t) {
786 if(mn[n].st==DEAD || mn[n].st==DIE) return 0;
788 if(t!=HIT_ROCKET && t!=HIT_ELECTRO) return 0;
789 if(mn[n].t==MN_CYBER || mn[n].t==MN_BARREL) return 1;
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:
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;
812 if(mn[n].pain>=mnsz[mn[n].t].minp) setst(n,PAIN);
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;
818 if(mn[n].t!=MN_BARREL)
819 if(o==-1) ++pl1.kills;
820 else if(o==-2) ++pl2.kills;
822 // if(mn[n].t==MN_BARREL)
823 // {Z_explode(mn[n].o.x,mn[n].o.y-8,30,o);}
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;
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)
834 case MN_IMP: case MN_ZOMBY: case MN_SERG: case MN_CGUN:
836 mn[n].ap=slopanim[mn[n].t-1];
837 Z_sound(slopsnd,128);
839 case MN_BSP: if(g_map==9) break;
841 Z_sound(dthsnd(mn[n].t),128);
843 else if(mn[n].t!=MN_BSP || g_map!=9) Z_sound(dthsnd(mn[n].t),128);
845 }else if(mn[n].st==SLEEP) {setst(n,GO);mn[n].pain=mnsz[mn[n].t].mp;}
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) {
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;}
865 static void goodsnd(void) {
870 int Z_hit(obj_t *o,int d,int own,int t) {
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();
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();
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;
897 void MN_killedp(void) {
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) {
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);
914 void Z_explode(int x,int y,int rad,int own) {
918 if(x<-100 || x>FLDW*CELW+100) return;
919 if(y<-100 || y>FLDH*CELH+100) return;
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);
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);
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);
948 void Z_bfg9000(int x,int y,int own) {
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);
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);
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);
979 int Z_chktrap(int t,int d,int o,int ht) {
984 if(Z_istrapped(pl1.o.x,pl1.o.y,pl1.o.r,pl1.o.h)) {
986 if(t) PL_hit(&pl1,d,o,ht);
988 if(_2pl) if(Z_istrapped(pl2.o.x,pl2.o.y,pl2.o.r,pl2.o.h)) {
990 if(t) PL_hit(&pl2,d,o,ht);
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)) {
996 if(t) MN_hit(i,d,o,ht);
1001 void Z_teleobj(int o,int x,int y) {
1005 else if(o==-2) p=&pl2.o;
1006 else if(o>=0 && o<MAXMN) p=&mn[o].o;
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) {
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;