/* Copyright (C) 1996-1997 Aleksey Volynskov
* Copyright (C) 2011 Rambo
* Copyright (C) 2020 SovietPony
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "glob.h"
#include
#include
#include "files.h"
#include "view.h"
#include "bmap.h"
#include "dots.h"
#include "weapons.h"
#include "player.h"
#include "monster.h"
#include "items.h"
#include "switch.h"
#include "misc.h"
#include "fx.h"
#include "smoke.h"
#include "my.h"
#include "player.h"
#include "error.h"
#include "game.h"
#define MAX_ATM 90
enum{
SLEEP,GO,RUN,CLIMB,DIE,DEAD,ATTACK,SHOOT,PAIN,WAIT,REVIVE,RUNOUT
};
typedef struct {
int r, h, l, mp, rv, jv, sp, minp;
} mnsz_t;
byte nomon = 1;
static char *sleepanim[MN_TN]={
"AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
"A","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
"A","A","AAABBB"
}, *goanim[MN_TN]={
"AABBCCDD","AABBCCDD","AABBDDAACCDD","AABBDDAACCDD","AABBDDCCDDBB",
"AABBDDAACCDD","AABBCCDD","AABBCCDD","A","AABB","AABBCCBB",
"AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF",
"AABB","A","DDEEFFGGHHIIJJKKLLAABBCC","ACDABD"
}, *painanim[MN_TN]={
"H","H","G","G","G","G","H","H","F","E","G","I","I","J","L","Q","EECCDDCC",
"A","D","G"
}, *waitanim[MN_TN]={
"A","A","A","A","A","A","A","A","A","AABB","A","A","A","I","K","A","A",
"A","D","E"
}, *attackanim[MN_TN]={
"EEFFGG","EEFFGG","EEEEEF","EEEEEF","EEEEEF","EF","EEFFGG","EEFFGG",
"BBCCDD","CCDD","DDEEFF","GH","GH","GGGGHH","GGHHII",
"QQGGGHHHIIJJKKLLMMNNOOPP","BBFFAA","A","OOPPQQ","EEEEFF"
}, *dieanim[MN_TN]={
"IIIJJJKKKLLLMMM","IIIJJJKKKLLL","HHHIIIJJJKKK","HHHIIIJJJKKK",
"HHHIIIJJJKKKLLLMMMNNNOOO","HHHIIIJJJKKKLLLMMM",
"IIIJJJKKKLLLMMMNNN","IIIJJJKKKLLLMMMNNN","GGGHHHIIIJJJKKK",
"FFFGGGHHHIIIJJJKKK","HHHIIIJJJKKKLLLMMM",
"JJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRR","JJJKKKLLLMMMNNNOOO",
"KKKLLLMMMNNNOOOPPPRRRSSS","MMMNNNOOOPPP","RRRSSSTTTUUUVVVWWWXXXYYY",
"DDDD","CCCDDDEEEFFFGGG","D","HHHHIIIIJJJJKKKKLLLLMMMM"
}, *slopanim[MN_TN]={
"","NNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","",
"OOOPPPQQQRRRSSS","","","","","","","","","","","","","","OOPPQQRRSSTTUUVV"
}, *deadanim[MN_TN]={
"N","M","L","L","P","N","O","O","L","","","S","P","T","Q","Z","C","","D","N"
}, *messanim[MN_TN]={
"","U","U","U","","T","","","","","","","","","","","","","","W"
};
int hit_xv, hit_yv;
mn_t mn[MAXMN];
int mnum, gsndt;
static void *fsnd,*pauksnd,*trupsnd;
static void *snd[MN_TN][5],*impsitsnd[2],*impdthsnd[2],*firsnd,*slopsnd,*gsnd[4];
static void *swgsnd,*pchsnd,*telesnd;
static void *positsnd[3],*podthsnd[3];
static mnsz_t mnsz[MN_TN+1]={
//rad ht life pain rv jv slop min_pn
0, 0, 0, 0, 0, 0, 0, 0, // none
15, 28, 60, 20, 7,10, 0, 10, // demon
10, 28, 25, 15, 3,10, 30, 0, // imp
10, 28, 15, 10, 3,10, 30, 0, // zomby
10, 28, 20, 10, 3,10, 30, 0, // sergeant
20, 55, 500, 70, 5,10, 0, 50, // cyberdemon
12, 28, 60, 20, 3,10, 30, 10, // chaingunner
12, 32, 150, 40, 3,10, 0, 30, // baron of hell
12, 32, 75, 40, 3,10, 0, 30, // hell knight
15, 28, 100, 10, 4, 4, 0, 0, // cacodemon
8, 18, 60, 10, 4, 4, 0, 0, // lost soul
15, 28, 100, 10, 4, 4, 0, 0, // pain elemental
64, 50, 500, 70, 4,10, 0, 50, // spider mastermind
25, 27, 150, 20, 4,10, 0, 0, // arachnotron
18, 30, 200, 40, 3, 7, 0, 20, // mancubus
17, 36, 200, 40, 6,11, 0, 20, // revenant
17, 36, 150, 30, 7,12, 0, 10, // archvile
5, 5, 35, 20,14, 6, 0, 10, // fish
5, 17, 20, 0, 7, 6, 0, 0, // barrel
17, 38, 20, 40, 3, 6, 0, 20, // robot
8, 26, 400, 70, 8,10, 30, 50 // man
};
void setst (int i, int st) {
char *a;
int t;
switch(mn[i].st) {
case DIE: case DEAD:
if(st!=DEAD && st!=REVIVE) return;
}
mn[i].ac=0;
t=mn[i].t-1;
switch(mn[i].st=st) {
case SLEEP: a=sleepanim[t];break;
case PAIN: a=painanim[t];break;
case WAIT: a=waitanim[t];break;
case CLIMB:
case RUN: case RUNOUT:
case GO: a=goanim[t];break;
case SHOOT:
if(t==MN_SKEL-1) {a="KKKKJJ";break;}
if(t==MN_ROBO-1) {a="MN";break;}
case ATTACK: a=attackanim[t];
if(st==ATTACK && t==MN_VILE-1) a="[[\\\\]]";
break;
case DIE:
if(g_map==9 && t==MN_BSP-1) Z_sound(pauksnd,128);
a=dieanim[t];break;
case DEAD:
a=deadanim[t];
if(mn[i].ap==slopanim[t]) a=messanim[t];
if(t==MN_BARREL-1) {mn[i].t=0;}
break;
case REVIVE:
a=(mn[i].ap==messanim[t])?slopanim[t]:dieanim[t];
mn[i].ac=strlen(a)-1;
mn[i].o.r=mnsz[t+1].r;mn[i].o.h=mnsz[t+1].h;
mn[i].life=mnsz[t+1].l;mn[i].ammo=mn[i].pain=0;
++mnum;
break;
}
mn[i].ap=a;
}
#define GGAS_TOTAL (MN__LAST-MN_DEMON+16+10)
void MN_alloc (void) {
int i,j;
static char sn[MN_TN][5][6]={
{"DMACT","DMPAIN","SGTATK","SGTSIT","SGTDTH"},
{"BGACT","POPAIN","CLAW","",""},
{"POSACT","POPAIN","","",""},
{"POSACT","POPAIN","","",""},
{"","DMPAIN","HOOF","CYBSIT","CYBDTH"},
{"POSACT","POPAIN","","",""},
{"","DMPAIN","","BRSSIT","BRSDTH"},
{"","DMPAIN","","KNTSIT","KNTDTH"},
{"DMACT","DMPAIN","","CACSIT","CACDTH"},
{"DMACT","DMPAIN","SKLATK","SKLATK","FIRXPL"},
{"DMACT","PEPAIN","","PESIT","PEDTH"},
{"","DMPAIN","METAL","SPISIT","SPIDTH"},
{"BSPACT","DMPAIN","BSPWLK","BSPSIT","BSPDTH"},
{"DMACT","MNPAIN","MANATK","MANSIT","MANDTH"},
{"SKEACT","POPAIN","SKEATK","SKESIT","SKEDTH"},
{"VILACT","VIPAIN","VILATK","VILSIT","VILDTH"},
{"","","BITE1","",""},
{"","","","","BAREXP"},
{"BSPACT","","BSPWLK","BSPSIT","BSPDTH"},
{"HAHA1","PLPAIN","","STOP1","PDIEHI"}
};
static char gsn[6]="GOOD0";
for(j=0;j=MN_PL_DEAD) goto ok;
return -1;
ok:
mn[i].o.x=x;mn[i].o.y=y;
mn[i].o.xv=mn[i].o.yv=mn[i].o.vx=mn[i].o.vy=0;
mn[i].d=d;mn[i].t=t;
mn[i].st=SLEEP;
if(tx,o->y,c,t+MN_PL_DEAD))==-1) return -1;
mn[i].o=*o;return i;
}
static int isfriend(int a,int b) {
if(a==MN_BARREL || b==MN_BARREL) return 1;
if(a==b) switch(a) {
case MN_IMP: case MN_DEMON:
case MN_BARON: case MN_KNIGHT:
case MN_CACO: case MN_SOUL:
case MN_MANCUB: case MN_SKEL:
case MN_FISH:
return 1;
}
if(a==MN_SOUL && b==MN_PAIN) return 1;
if(b==MN_SOUL && a==MN_PAIN) return 1;
return 0;
}
static int MN_findnewprey(int i) {
int a,b,l;
a=!PL_isdead(&pl1);
if(_2pl) b=!PL_isdead(&pl2); else b=0;
if(a) {
if(b) mn[i].aim=(abs(mn[i].o.x-pl1.o.x)+abs(mn[i].o.y-pl1.o.y)
<= abs(mn[i].o.x-pl2.o.x)+abs(mn[i].o.y-pl2.o.y))?-1:-2;
else mn[i].aim=-1;
}else{
if(b) mn[i].aim=-2;
else{
for(a=0,b=32000,mn[i].aim=-3;a=0 && i=50) mn[i].ammo=(mn[i].t==MN_ROBO)?-200:-50;
break;
case MN_MAN:
break;
case MN_MANCUB:
if(++mn[i].ammo>=5) mn[i].ammo=-50;
break;
case MN_SPIDER:
if(++mn[i].ammo>=100) mn[i].ammo=-50;
break;
case MN_CYBER:
if(rand()&1) return 0;
if(++mn[i].ammo>=10) mn[i].ammo=-50;
break;
case MN_BARON: case MN_KNIGHT:
if(rand()&7) return 0;
break;
case MN_SKEL:
if(rand()&31) return 0;
break;
case MN_VILE:
if(rand()&7) return 0;
break;
case MN_PAIN:
if(rand()&7) return 0;
break;
default:
if(rand()&15) return 0;
}
if(!Z_look(&mn[i].o,o,mn[i].d)) return 0;
mn[i].atm=0;
mn[i].tx=o->x+(o->xv+o->vx)*6;mn[i].ty=o->y-o->h/2+(o->yv+o->vy)*6;
if(abs(mn[i].tx-mn[i].o.x)x;mn[i].ty=o->y;
setst(i,SHOOT);Z_sound(fsnd,128);
Z_sound(snd[MN_VILE-1][2],128);break;
case MN_SOUL:
setst(i,ATTACK);Z_sound(snd[MN_SOUL-1][2],128);
yd=mn[i].ty-mn[i].o.y+mn[i].o.h/2;xd=mn[i].tx-mn[i].o.x;
if(!(m=max(abs(xd),abs(yd)))) m=1;
mn[i].o.xv=xd*16/m;mn[i].o.yv=yd*16/m;
break;
case MN_MANCUB: if(mn[i].ammo==1) Z_sound(snd[MN_MANCUB-1][2],128);
case MN_ZOMBY: case MN_SERG: case MN_BSP: case MN_ROBO:
case MN_CYBER: case MN_CGUN: case MN_SPIDER:
case MN_PAIN: case MN_MAN:
setst(i,SHOOT);break;
default:
return 0;
}
return 1;
}
static int kick(int i,obj_t *o) {
switch(mn[i].t) {
case MN_FISH:
setst(i,ATTACK);return 1;
case MN_DEMON:
setst(i,ATTACK);Z_sound(snd[0][2],128);return 1;
case MN_IMP:
setst(i,ATTACK);Z_sound(snd[1][2],128);return 1;
case MN_SKEL:
setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
case MN_ROBO:
setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
case MN_BARON: case MN_KNIGHT: case MN_CACO: case MN_MANCUB:
return shoot(i,o,1);
}
return 0;
}
static int iscorpse(obj_t *o,int n) {
int i;
if(!n) if(rand()&7) return -3;
for(i=0;i=MAXMN) return 0;
if(mn[obj].t) return MN_hit(obj,d,own,t);
return 0;
}
void MN_act (void) {
int i,st,sx,sy,t;
static obj_t o;
static int pt_x=0,pt_xs=1,pt_y=0,pt_ys=1;
if(abs(pt_x+=pt_xs) > 123) pt_xs=-pt_xs;
if(abs(pt_y+=pt_ys) > 50) pt_ys=-pt_ys;
if(gsndt>0) if(--gsndt==0) {
Z_sound(gsnd[myrand(4)],128);
}
for(i=0;i=mnsz[t].mp)
{mn[i].pain=mnsz[t].mp;Z_sound(snd[t-1][1],128);}
if((mn[i].pain-=5)<=mnsz[t].minp)
{setst(i,GO);mn[i].pain=0;mn[i].ammo=-9;}
break;
case SLEEP:
if(++mn[i].s>=18) mn[i].s=0; else break;
if(Z_look(&mn[i].o,&pl1.o,mn[i].d))
{setst(i,GO);mn[i].aim=-1;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
if(_2pl) if(Z_look(&mn[i].o,&pl2.o,mn[i].d))
{setst(i,GO);mn[i].aim=-2;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
break;
case WAIT:
if(--mn[i].s<0) setst(i,GO);
break;
case GO:
if(st&Z_BLOCK) {mn[i].d^=1;setst(i,RUNOUT);mn[i].s=40;break;}
if(t==MN_VILE) if(iscorpse(&mn[i].o,0)>=0) {
setst(i,ATTACK);mn[i].o.xv=0;break;
}
if(!Z_getobjpos(mn[i].aim,&o) || mn[i].atm>MAX_ATM)
if(!MN_findnewprey(i)) {
mn[i].aim=-3;
o.x=mn[i].o.x+pt_x;o.y=mn[i].o.y+pt_y;
o.xv=o.vx=o.yv=o.vy=o.r=0;o.h=1;
}else Z_getobjpos(mn[i].aim,&o);
if(Z_overlap(&mn[i].o,&o)) {
mn[i].atm=0;
if(kick(i,&o)) break;
}
sx=o.x-mn[i].o.x;
sy=o.y-o.h/2-mn[i].o.y+mn[i].o.h/2;
if(!(st&Z_BLOCK)) if(abs(sx)<20)
if(t!=MN_FISH) {setst(i,RUN);mn[i].s=15;mn[i].d=rand()&1;break;}
if(st&Z_HITWALL) {
if(SW_press(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h,2,i))
{setst(i,WAIT);mn[i].s=4;break;}
switch(t) {
case MN_CACO: case MN_SOUL: case MN_PAIN: case MN_FISH:
break;
default:
if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
{mn[i].o.yv=-mnsz[t].jv;setst(i,CLIMB);break;}
}break;
}
mn[i].d=(sx>0)?1:0;
if(canshoot(t))
if(abs(sx)>abs(sy)) if(shoot(i,&o,0)) break;
switch(t) {
case MN_FISH:
if(!(st&Z_INWATER)) {
if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r)) {
mn[i].o.yv=-6;
mn[i].o.vx+=rand()%17-8;
}setst(i,PAIN);mn[i].pain+=50;break;
}
case MN_CACO: case MN_SOUL: case MN_PAIN:
if(abs(sy)>4) mn[i].o.yv=(sy<0)?-4:4; else mn[i].o.yv=0;
if(t==MN_FISH) if(mn[i].o.yv<0)
if(!Z_inwater(mn[i].o.x,mn[i].o.y-8,mn[i].o.r,mn[i].o.h))
{mn[i].o.yv=0;setst(i,RUN);mn[i].d=rand()&1;mn[i].s=20;}
break;
default:
if(sy<-20) if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
if(!(rand()&3)) mn[i].o.yv=-mnsz[t].jv;
}
if(++mn[i].s>=8) {
mn[i].s=0;
if(!(rand()&7)) Z_sound(snd[t-1][0],128);
}
mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
if(st&Z_INWATER) mn[i].o.xv/=2;
else if(t==MN_FISH) mn[i].o.xv=0;
break;
case RUN:
if(st&Z_BLOCK) {setst(i,RUNOUT);mn[i].d^=1;mn[i].s=40;break;}
if(--mn[i].s<=0 || ((st&Z_HITWALL) && mn[i].o.yv+mn[i].o.vy==0)) {
setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
if(!(rand()&7)) Z_sound(snd[t-1][0],128);
}mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
if(st&Z_INWATER) mn[i].o.xv/=2;
else if(t==MN_FISH) mn[i].o.xv=0;
break;
case RUNOUT:
if(!(st&Z_BLOCK) && mn[i].s>0) mn[i].s=0;
if(--mn[i].s<=-18) {
setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
if(!(rand()&7)) Z_sound(snd[t-1][0],128);
}mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
if(st&Z_INWATER) mn[i].o.xv/=2;
else if(t==MN_FISH) mn[i].o.xv=0;
break;
case CLIMB:
if(mn[i].o.yv+mn[i].o.vy>=0 || !(st&Z_HITWALL)) {
setst(i,GO);mn[i].s=0;
if(st&(Z_HITWALL|Z_BLOCK)) {mn[i].d^=1;setst(i,RUN);mn[i].s=15;}
}mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
if(st&Z_INWATER) mn[i].o.xv/=2;
else if(t==MN_FISH) mn[i].o.xv=0;
break;
case ATTACK:
case SHOOT:
if(t==MN_SOUL) {if(st&(Z_HITWALL|Z_HITCEIL|Z_HITLAND)) setst(i,GO); break;}
if(t!=MN_FISH) mn[i].o.xv=Z_dec(mn[i].o.xv,1);
if(t==MN_VILE && mn[i].st==SHOOT) {
if(!Z_getobjpos(mn[i].aim,&o)) {setst(i,GO);break;}
if(!Z_look(&mn[i].o,&o,mn[i].d)) {setst(i,GO);break;}
if(Z_inwater(o.x,o.y,o.r,o.h)) {setst(i,GO);break;}
mn[i].tx=o.x;mn[i].ty=o.y;
Z_hitobj(mn[i].aim,2,i,HIT_SOME);
}break;
}
if(mn[i].st==REVIVE) {
if(--mn[i].ac==0) setst(i,GO);
}else ++mn[i].ac;
if(!mn[i].ap[mn[i].ac]) switch(mn[i].st) {
case ATTACK:
switch(t) {
case MN_SOUL: mn[i].ac=0;
case MN_IMP:
case MN_DEMON:
if(Z_hit(&mn[i].o,15,i,HIT_SOME)) if(t==MN_SOUL) setst(i,GO);
break;
case MN_FISH:
if(Z_hit(&mn[i].o,10,i,HIT_SOME))
Z_sound(snd[MN_FISH-1][2],128);
break;
case MN_SKEL: case MN_ROBO:
o=mn[i].o;o.xv=mn[i].d?50:-50;
if(Z_hit(&o,50,i,HIT_SOME)) Z_sound(pchsnd,128);
break;
case MN_VILE:
sx=iscorpse(&mn[i].o,1);
if(sx==-3) break;
if(!mn[sx].t || mn[sx].st!=DEAD) break;
setst(sx,REVIVE);Z_sound(slopsnd,128);
hit_xv=hit_yv=0;MN_hit(i,5,-3,HIT_SOME);
break;
}if(t!=MN_SOUL && mn[i].st!=DIE) setst(i,GO);
break;
case SHOOT:
switch(t) {
case MN_IMP:
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);
break;
case MN_ZOMBY:
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);
break;
case MN_SERG:
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);
break;
case MN_MAN:
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);
mn[i].ammo=-36;break;
case MN_CYBER:
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);
break;
case MN_SKEL:
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);
break;
case MN_CGUN:
case MN_SPIDER:
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);
break;
case MN_BSP:
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);
break;
case MN_ROBO:
WP_plasma(mn[i].o.x+(mn[i].d*2-1)*15,mn[i].o.y-30,mn[i].tx,mn[i].ty,i);
break;
case MN_MANCUB:
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);
break;
case MN_BARON: case MN_KNIGHT:
WP_ball7(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
break;
case MN_CACO:
WP_ball2(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
break;
case MN_PAIN:
if((sx=MN_spawn(mn[i].o.x,mn[i].o.y,mn[i].d,MN_SOUL))==-1) break;
Z_getobjpos(mn[sx].aim=mn[i].aim,&o);mn[sx].atm=0;
shoot(sx,&o,1);
break;
}
if(t==MN_CGUN || t==MN_SPIDER || t==MN_BSP || t==MN_MANCUB || t==MN_ROBO)
if(!Z_getobjpos(mn[i].aim,&o)) MN_findnewprey(i);
else if(shoot(i,&o,0)) break;
setst(i,GO);break;
case DIE:
setst(i,DEAD);
if(t==MN_PAIN || t==MN_SOUL) mn[i].ftime=0;
if(t==MN_PAIN) {
if((sx=MN_spawn(mn[i].o.x-15,mn[i].o.y,0,MN_SOUL))==-1) break;
setst(sx,GO);
if((sx=MN_spawn(mn[i].o.x+15,mn[i].o.y,1,MN_SOUL))==-1) break;
setst(sx,GO);
if((sx=MN_spawn(mn[i].o.x,mn[i].o.y-10,1,MN_SOUL))==-1) break;
setst(sx,GO);
}break;
default: mn[i].ac=0;
}
switch(mn[i].st) {
case GO: case RUN: case CLIMB: case RUNOUT:
if(t==MN_CYBER || t==MN_SPIDER || t==MN_BSP) {
if(mn[i].ac==0 || mn[i].ac==6) Z_sound(snd[t-1][2],128);
}else if(t==MN_ROBO)
if(mn[i].ac==0 || mn[i].ac==12) Z_sound(snd[t-1][2],128);
}
}
}
void MN_mark (void) {
int i;
for(i=0;i=0) {
if(mn[o].t==MN_SOUL && mn[n].t==MN_PAIN) return 0;
if(mn[o].t==mn[n].t) switch(mn[n].t) {
case MN_IMP: case MN_DEMON:
case MN_BARON: case MN_KNIGHT:
case MN_CACO: case MN_SOUL:
case MN_MANCUB: case MN_SKEL:
case MN_FISH:
return 0;
}
}
if(t==HIT_FLAME) if(mn[n].ftime && mn[n].fobj==o) {if(g_time&31) return 1;}
else {mn[n].ftime=255;mn[n].fobj=o;}
if(t==HIT_ELECTRO) if(mn[n].t==MN_FISH)
{setst(n,RUN);mn[n].s=20;mn[n].d=rand()&1;return 1;}
if(t==HIT_TRAP) mn[n].life=-100;
if(mn[n].t==MN_ROBO) d=0;
if((mn[n].life-=d)<=0) --mnum;
if(!mn[n].pain) mn[n].pain=3;
mn[n].pain+=d;
if(mn[n].st!=PAIN) {
if(mn[n].pain>=mnsz[mn[n].t].minp) setst(n,PAIN);
}
if(mn[n].t!=MN_BARREL)
DOT_blood(mn[n].o.x,mn[n].o.y-mn[n].o.h/2,hit_xv,hit_yv,d*2);
mn[n].aim=o;mn[n].atm=0;
if(mn[n].life<=0) {
if(mn[n].t!=MN_BARREL)
if(o==-1) ++pl1.kills;
else if(o==-2) ++pl2.kills;
setst(n,DIE);
switch(mn[n].t) {
case MN_ZOMBY: i=I_CLIP;break;
case MN_SERG: i=I_SGUN;break;
case MN_CGUN: i=I_MGUN;break;
case MN_MAN: i=I_KEYR;break;
default: i=0;
}if(i) IT_spawn(mn[n].o.x,mn[n].o.y,i);
mn[n].o.xv=0;mn[n].o.h=6;
if(mn[n].life<=-mnsz[mn[n].t].sp)
switch(mn[n].t) {
case MN_IMP: case MN_ZOMBY: case MN_SERG: case MN_CGUN:
case MN_MAN:
mn[n].ap=slopanim[mn[n].t-1];
Z_sound(slopsnd,128);
break;
case MN_BSP: if(g_map==9) break;
default:
Z_sound(dthsnd(mn[n].t),128);
}
else if(mn[n].t!=MN_BSP || g_map!=9) Z_sound(dthsnd(mn[n].t),128);
mn[n].life=0;
}else if(mn[n].st==SLEEP) {setst(n,GO);mn[n].pain=mnsz[mn[n].t].mp;}
return 1;
}
#define hit(o,x,y) (y<=o.y && y>o.y-o.h && x>=o.x-o.r && x<=o.x+o.r)
int Z_gunhit (int x, int y, int o, int xv, int yv) {
int i;
if(o!=-1) if(hit(pl1.o,x,y)) if(PL_hit(&pl1,3,o,HIT_SOME))
{pl1.o.vx+=xv;pl1.o.vy+=yv;return -1;}
if(_2pl && o!=-2) if(hit(pl2.o,x,y)) if(PL_hit(&pl2,3,o,HIT_SOME))
{pl2.o.vx+=xv;pl2.o.vy+=yv;return -2;}
for(i=0;ixv+o->vx;
hit_yv=o->yv+o->vy;
if(Z_overlap(o,&pl1.o)) if(PL_hit(&pl1,d,own,t)) {
pl1.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
pl1.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
if(t==HIT_BFG) goodsnd();
return -1;
}
if(_2pl) if(Z_overlap(o,&pl2.o)) if(PL_hit(&pl2,d,own,t)) {
pl2.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
pl2.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
if(t==HIT_BFG) goodsnd();
return -2;
}
for(i=0;ixv+o->vx)*((t==HIT_BFG)?8:1)/4;
mn[i].o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
return 1;
}
return 0;
}
void MN_killedp (void) {
int i;
for(i=0;iFLDW*CELW+100) return;
if(y<-100 || y>FLDH*CELH+100) return;
r=(long)rad*rad;
dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
if((long)dx*dx+(long)dy*dyFLDW*CELW+100) return;
if(y<-100 || y>FLDH*CELH+100) return;
dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
if(own!=-1) if((long)dx*dx+(long)dy*dy<16000)
if(Z_cansee(x,y,pl1.o.x,pl1.o.y-pl1.o.h/2)) {
if(PL_hit(&pl1,50,own,HIT_SOME))
WP_bfghit(pl1.o.x,pl1.o.y-pl1.o.h/2,own);
}
if(_2pl) {
dx=pl2.o.x-x;dy=pl2.o.y-pl2.o.h/2-y;
if(own!=-2) if((long)dx*dx+(long)dy*dy<16000)
if(Z_cansee(x,y,pl2.o.x,pl2.o.y-pl2.o.h/2)) {
if(PL_hit(&pl2,50,own,HIT_SOME))
WP_bfghit(pl2.o.x,pl2.o.y-pl2.o.h/2,own);
}
}
for(i=0;i=0 && ox,p->y);FX_tfog(p->x=x,p->y=y);
Z_sound(telesnd,128);
}
void MN_warning (int l,int t,int r,int b) {
int i;
for(i=0;i=l && mn[i].o.x-mn[i].o.r<=r
&& mn[i].o.y>=t && mn[i].o.y-mn[i].o.h<=b)
if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
mn[i].o.yv=-mnsz[mn[i].t].jv;
}