DEADSOFTWARE

portability: avoid errors on some compilers
[flatwaifu.git] / src / monster.c
1 /* Copyright (C) 1996-1997 Aleksey Volynskov
2 * Copyright (C) 2011 Rambo
3 * Copyright (C) 2020 SovietPony
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
18 #include "glob.h"
19 #include <stdlib.h>
20 #include <string.h>
21 #include "files.h"
22 #include "view.h"
23 #include "bmap.h"
24 #include "dots.h"
25 #include "weapons.h"
26 #include "player.h"
27 #include "monster.h"
28 #include "items.h"
29 #include "switch.h"
30 #include "misc.h"
31 #include "fx.h"
32 #include "smoke.h"
33 #include "player.h"
34 #include "error.h"
35 #include "game.h"
37 #define MAX_ATM 90
39 enum{
40 SLEEP,GO,RUN,CLIMB,DIE,DEAD,ATTACK,SHOOT,PAIN,WAIT,REVIVE,RUNOUT
41 };
43 typedef struct {
44 int r, h, l, mp, rv, jv, sp, minp;
45 } mnsz_t;
47 byte nomon = 1;
49 static char *sleepanim[MN_TN]={
50 "AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
51 "A","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB","AAABBB",
52 "A","A","AAABBB"
53 }, *goanim[MN_TN]={
54 "AABBCCDD","AABBCCDD","AABBDDAACCDD","AABBDDAACCDD","AABBDDCCDDBB",
55 "AABBDDAACCDD","AABBCCDD","AABBCCDD","A","AABB","AABBCCBB",
56 "AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF","AABBCCDDEEFF",
57 "AABB","A","DDEEFFGGHHIIJJKKLLAABBCC","ACDABD"
58 }, *painanim[MN_TN]={
59 "H","H","G","G","G","G","H","H","F","E","G","I","I","J","L","Q","EECCDDCC",
60 "A","D","G"
61 }, *waitanim[MN_TN]={
62 "A","A","A","A","A","A","A","A","A","AABB","A","A","A","I","K","A","A",
63 "A","D","E"
64 }, *attackanim[MN_TN]={
65 "EEFFGG","EEFFGG","EEEEEF","EEEEEF","EEEEEF","EF","EEFFGG","EEFFGG",
66 "BBCCDD","CCDD","DDEEFF","GH","GH","GGGGHH","GGHHII",
67 "QQGGGHHHIIJJKKLLMMNNOOPP","BBFFAA","A","OOPPQQ","EEEEFF"
68 }, *dieanim[MN_TN]={
69 "IIIJJJKKKLLLMMM","IIIJJJKKKLLL","HHHIIIJJJKKK","HHHIIIJJJKKK",
70 "HHHIIIJJJKKKLLLMMMNNNOOO","HHHIIIJJJKKKLLLMMM",
71 "IIIJJJKKKLLLMMMNNN","IIIJJJKKKLLLMMMNNN","GGGHHHIIIJJJKKK",
72 "FFFGGGHHHIIIJJJKKK","HHHIIIJJJKKKLLLMMM",
73 "JJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRR","JJJKKKLLLMMMNNNOOO",
74 "KKKLLLMMMNNNOOOPPPRRRSSS","MMMNNNOOOPPP","RRRSSSTTTUUUVVVWWWXXXYYY",
75 "DDDD","CCCDDDEEEFFFGGG","D","HHHHIIIIJJJJKKKKLLLLMMMM"
76 }, *slopanim[MN_TN]={
77 "","NNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","MMMNNNOOOPPPRRRSSSTTT","",
78 "OOOPPPQQQRRRSSS","","","","","","","","","","","","","","OOPPQQRRSSTTUUVV"
79 }, *deadanim[MN_TN]={
80 "N","M","L","L","P","N","O","O","L","","","S","P","T","Q","Z","C","","D","N"
81 }, *messanim[MN_TN]={
82 "","U","U","U","","T","","","","","","","","","","","","","","W"
83 };
85 int hit_xv, hit_yv;
86 mn_t mn[MAXMN];
87 int mnum, gsndt;
89 static void *fsnd,*pauksnd,*trupsnd;
90 static void *snd[MN_TN][5],*impsitsnd[2],*impdthsnd[2],*firsnd,*slopsnd,*gsnd[4];
91 static void *swgsnd,*pchsnd,*telesnd;
92 static void *positsnd[3],*podthsnd[3];
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
116 };
118 void setst (int i, int st) {
119 char *a;
120 int t;
122 switch(mn[i].st) {
123 case DIE: case DEAD:
124 if(st!=DEAD && st!=REVIVE) return;
126 mn[i].ac=0;
127 t=mn[i].t-1;
128 switch(mn[i].st=st) {
129 case SLEEP: a=sleepanim[t];break;
130 case PAIN: a=painanim[t];break;
131 case WAIT: a=waitanim[t];break;
132 case CLIMB:
133 case RUN: case RUNOUT:
134 case GO: a=goanim[t];break;
135 case SHOOT:
136 if(t==MN_SKEL-1) {a="KKKKJJ";break;}
137 if(t==MN_ROBO-1) {a="MN";break;}
138 case ATTACK: a=attackanim[t];
139 if(st==ATTACK && t==MN_VILE-1) a="[[\\\\]]";
140 break;
141 case DIE:
142 if(g_map==9 && t==MN_BSP-1) Z_sound(pauksnd,128);
143 a=dieanim[t];break;
144 case DEAD:
145 a=deadanim[t];
146 if(mn[i].ap==slopanim[t]) a=messanim[t];
147 if(t==MN_BARREL-1) {mn[i].t=0;}
148 break;
149 case REVIVE:
150 a=(mn[i].ap==messanim[t])?slopanim[t]:dieanim[t];
151 mn[i].ac=strlen(a)-1;
152 mn[i].o.r=mnsz[t+1].r;mn[i].o.h=mnsz[t+1].h;
153 mn[i].life=mnsz[t+1].l;mn[i].ammo=mn[i].pain=0;
154 ++mnum;
155 break;
157 mn[i].ap=a;
160 #define GGAS_TOTAL (MN__LAST-MN_DEMON+16+10)
162 void MN_alloc (void) {
163 int i,j;
164 static char sn[MN_TN][5][6]={
165 {"DMACT","DMPAIN","SGTATK","SGTSIT","SGTDTH"},
166 {"BGACT","POPAIN","CLAW","",""},
167 {"POSACT","POPAIN","","",""},
168 {"POSACT","POPAIN","","",""},
169 {"","DMPAIN","HOOF","CYBSIT","CYBDTH"},
170 {"POSACT","POPAIN","","",""},
171 {"","DMPAIN","","BRSSIT","BRSDTH"},
172 {"","DMPAIN","","KNTSIT","KNTDTH"},
173 {"DMACT","DMPAIN","","CACSIT","CACDTH"},
174 {"DMACT","DMPAIN","SKLATK","SKLATK","FIRXPL"},
175 {"DMACT","PEPAIN","","PESIT","PEDTH"},
176 {"","DMPAIN","METAL","SPISIT","SPIDTH"},
177 {"BSPACT","DMPAIN","BSPWLK","BSPSIT","BSPDTH"},
178 {"DMACT","MNPAIN","MANATK","MANSIT","MANDTH"},
179 {"SKEACT","POPAIN","SKEATK","SKESIT","SKEDTH"},
180 {"VILACT","VIPAIN","VILATK","VILSIT","VILDTH"},
181 {"","","BITE1","",""},
182 {"","","","","BAREXP"},
183 {"BSPACT","","BSPWLK","BSPSIT","BSPDTH"},
184 {"HAHA1","PLPAIN","","STOP1","PDIEHI"}
185 };
186 static char gsn[6]="GOOD0";
187 for(j=0;j<MN_TN;++j) {
188 for(i=0;i<5;++i)
189 if(sn[j][i][0])
190 snd[j][i]=Z_getsnd(sn[j][i]);
191 else
192 snd[j][i]=NULL;
193 logo_gas(j+5,GGAS_TOTAL);
195 impsitsnd[0]=Z_getsnd("BGSIT1");
196 impsitsnd[1]=Z_getsnd("BGSIT2");
197 impdthsnd[0]=Z_getsnd("BGDTH1");
198 impdthsnd[1]=Z_getsnd("BGDTH2");
199 positsnd[0]=Z_getsnd("POSIT1");
200 positsnd[1]=Z_getsnd("POSIT2");
201 positsnd[2]=Z_getsnd("POSIT3");
202 podthsnd[0]=Z_getsnd("PODTH1");
203 podthsnd[1]=Z_getsnd("PODTH2");
204 podthsnd[2]=Z_getsnd("PODTH3");
205 fsnd=Z_getsnd("FLAME");
206 firsnd=Z_getsnd("FIRSHT");
207 slopsnd=Z_getsnd("SLOP");
208 swgsnd=Z_getsnd("SKESWG");
209 pchsnd=Z_getsnd("SKEPCH");
210 telesnd=Z_getsnd("TELEPT");
211 pauksnd=Z_getsnd("PAUK1");
212 trupsnd=Z_getsnd("UTRUP");
213 for(i=0;i<4;++i) {gsn[4]=i+'1';gsnd[i]=Z_getsnd(gsn);}
216 void MN_init (void) {
217 int i;
218 for(i=0;i<MAXMN;++i) {mn[i].t=0;mn[i].st=SLEEP;}
219 gsndt=mnum=0;
222 int MN_spawn (int x, int y, byte d, int t) {
223 int i;
225 if(g_dm && nomon && t<MN_PL_DEAD) return -1;
226 for(i=0;i<MAXMN;++i) if(!mn[i].t) goto ok;
227 for(i=0;i<MAXMN;++i) if(mn[i].t>=MN_PL_DEAD) goto ok;
228 return -1;
229 ok:
230 mn[i].o.x=x;mn[i].o.y=y;
231 mn[i].o.xv=mn[i].o.yv=mn[i].o.vx=mn[i].o.vy=0;
232 mn[i].d=d;mn[i].t=t;
233 mn[i].st=SLEEP;
234 if(t<MN_PL_DEAD) {
235 mn[i].o.r=mnsz[t].r;mn[i].o.h=mnsz[t].h;
236 mn[i].life=mnsz[t].l;
237 setst(i,SLEEP);mn[i].s=myrand(18);
238 ++mnum;
239 }else {mn[i].o.r=8;mn[i].o.h=6;mn[i].life=0;mn[i].st=DEAD;}
240 mn[i].aim=-3;mn[i].atm=0;
241 mn[i].pain=0;
242 mn[i].ammo=0;
243 mn[i].ftime=0;
244 return i;
247 int MN_spawn_deadpl (obj_t *o, byte c, int t) {
248 int i;
250 if((i=MN_spawn(o->x,o->y,c,t+MN_PL_DEAD))==-1) return -1;
251 mn[i].o=*o;return i;
254 static int isfriend(int a,int b) {
255 if(a==MN_BARREL || b==MN_BARREL) return 1;
256 if(a==b) switch(a) {
257 case MN_IMP: case MN_DEMON:
258 case MN_BARON: case MN_KNIGHT:
259 case MN_CACO: case MN_SOUL:
260 case MN_MANCUB: case MN_SKEL:
261 case MN_FISH:
262 return 1;
264 if(a==MN_SOUL && b==MN_PAIN) return 1;
265 if(b==MN_SOUL && a==MN_PAIN) return 1;
266 return 0;
269 static int MN_findnewprey(int i) {
270 int a,b,l;
272 a=!PL_isdead(&pl1);
273 if(_2pl) b=!PL_isdead(&pl2); else b=0;
274 if(a) {
275 if(b) mn[i].aim=(abs(mn[i].o.x-pl1.o.x)+abs(mn[i].o.y-pl1.o.y)
276 <= abs(mn[i].o.x-pl2.o.x)+abs(mn[i].o.y-pl2.o.y))?-1:-2;
277 else mn[i].aim=-1;
278 }else{
279 if(b) mn[i].aim=-2;
280 else{
281 for(a=0,b=32000,mn[i].aim=-3;a<MAXMN;++a)
282 if(mn[a].t && mn[a].st!=DEAD && a!=i && !isfriend(mn[a].t,mn[i].t))
283 if((l=abs(mn[i].o.x-mn[a].o.x)+abs(mn[i].o.y-mn[a].o.y))<b)
284 {mn[i].aim=a;b=l;}
285 if(mn[i].aim<0) {mn[i].atm=MAX_ATM;return 0;} else mn[i].atm=0;
288 return 1;
291 int Z_getobjpos (int i, obj_t *o) {
292 if(i==-1) {*o=pl1.o;return !PL_isdead(&pl1);}
293 if(_2pl) if(i==-2) {*o=pl2.o;return !PL_isdead(&pl2);}
294 if(i>=0 && i<MAXMN) if(mn[i].t && mn[i].st!=DEAD)
295 {*o=mn[i].o;return 1;}
296 return 0;
299 static void *wakeupsnd(int t) {
300 switch(t) {
301 case MN_IMP: return impsitsnd[myrand(2)];
302 case MN_ZOMBY: case MN_SERG: case MN_CGUN:
303 return positsnd[myrand(3)];
305 return snd[t-1][3];
308 static void *dthsnd(int t) {
309 switch(t) {
310 case MN_IMP: return impdthsnd[myrand(2)];
311 case MN_ZOMBY: case MN_SERG: case MN_CGUN:
312 return podthsnd[myrand(3)];
314 return snd[t-1][4];
317 static int canshoot(int t) {
318 switch(t) {
319 case MN_DEMON: case MN_FISH: case MN_BARREL:
320 return 0;
322 return 1;
325 static int shoot(int i,obj_t *o,int n) {
326 int xd,yd,m;
328 if(mn[i].ammo<0) return 0;
329 if(!n) switch(mn[i].t) {
330 case MN_FISH: case MN_BARREL:
331 case MN_DEMON: return 0;
332 case MN_CGUN:
333 case MN_BSP:
334 case MN_ROBO:
335 if(++mn[i].ammo>=50) mn[i].ammo=(mn[i].t==MN_ROBO)?-200:-50;
336 break;
337 case MN_MAN:
338 break;
339 case MN_MANCUB:
340 if(++mn[i].ammo>=5) mn[i].ammo=-50;
341 break;
342 case MN_SPIDER:
343 if(++mn[i].ammo>=100) mn[i].ammo=-50;
344 break;
345 case MN_CYBER:
346 if(rand()&1) return 0;
347 if(++mn[i].ammo>=10) mn[i].ammo=-50;
348 break;
349 case MN_BARON: case MN_KNIGHT:
350 if(rand()&7) return 0;
351 break;
352 case MN_SKEL:
353 if(rand()&31) return 0;
354 break;
355 case MN_VILE:
356 if(rand()&7) return 0;
357 break;
358 case MN_PAIN:
359 if(rand()&7) return 0;
360 break;
361 default:
362 if(rand()&15) return 0;
364 if(!Z_look(&mn[i].o,o,mn[i].d)) return 0;
365 mn[i].atm=0;
366 mn[i].tx=o->x+(o->xv+o->vx)*6;mn[i].ty=o->y-o->h/2+(o->yv+o->vy)*6;
367 if(abs(mn[i].tx-mn[i].o.x)<abs(mn[i].ty-mn[i].o.y+mn[i].o.h/2)) return 0;
368 switch(mn[i].t) {
369 case MN_IMP: case MN_BARON: case MN_KNIGHT: case MN_CACO:
370 setst(i,SHOOT);Z_sound(firsnd,128);break;
371 case MN_SKEL:
372 setst(i,SHOOT);Z_sound(snd[MN_SKEL-1][2],128);break;
373 case MN_VILE:
374 mn[i].tx=o->x;mn[i].ty=o->y;
375 setst(i,SHOOT);Z_sound(fsnd,128);
376 Z_sound(snd[MN_VILE-1][2],128);break;
377 case MN_SOUL:
378 setst(i,ATTACK);Z_sound(snd[MN_SOUL-1][2],128);
379 yd=mn[i].ty-mn[i].o.y+mn[i].o.h/2;xd=mn[i].tx-mn[i].o.x;
380 if(!(m=max(abs(xd),abs(yd)))) m=1;
381 mn[i].o.xv=xd*16/m;mn[i].o.yv=yd*16/m;
382 break;
383 case MN_MANCUB: if(mn[i].ammo==1) Z_sound(snd[MN_MANCUB-1][2],128);
384 case MN_ZOMBY: case MN_SERG: case MN_BSP: case MN_ROBO:
385 case MN_CYBER: case MN_CGUN: case MN_SPIDER:
386 case MN_PAIN: case MN_MAN:
387 setst(i,SHOOT);break;
388 default:
389 return 0;
391 return 1;
394 static int kick(int i,obj_t *o) {
395 switch(mn[i].t) {
396 case MN_FISH:
397 setst(i,ATTACK);return 1;
398 case MN_DEMON:
399 setst(i,ATTACK);Z_sound(snd[0][2],128);return 1;
400 case MN_IMP:
401 setst(i,ATTACK);Z_sound(snd[1][2],128);return 1;
402 case MN_SKEL:
403 setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
404 case MN_ROBO:
405 setst(i,ATTACK);Z_sound(swgsnd,128);return 1;
406 case MN_BARON: case MN_KNIGHT: case MN_CACO: case MN_MANCUB:
407 return shoot(i,o,1);
409 return 0;
412 static int iscorpse(obj_t *o,int n) {
413 int i;
415 if(!n) if(rand()&7) return -3;
416 for(i=0;i<MAXMN;++i) if(mn[i].t) if(mn[i].st==DEAD)
417 if(Z_overlap(o,&mn[i].o)) switch(mn[i].t) {
418 case MN_SOUL: case MN_PAIN:
419 case MN_CYBER: case MN_SPIDER:
420 case MN_PL_DEAD: case MN_PL_MESS:
421 case MN_VILE: case MN_BARREL:
422 continue;
423 default:
424 return i;
426 return -3;
429 static int Z_hitobj (int obj, int d, int own, int t) {
430 hit_xv=hit_yv=0;
431 if(obj==-1) return PL_hit(&pl1,d,own,t);
432 else if(obj==-2 && _2pl) return PL_hit(&pl2,d,own,t);
433 else if(obj<0 || obj>=MAXMN) return 0;
434 if(mn[obj].t) return MN_hit(obj,d,own,t);
435 return 0;
438 void MN_act (void) {
439 int i,st,sx,sy,t;
440 static obj_t o;
441 static int pt_x=0,pt_xs=1,pt_y=0,pt_ys=1;
443 if(abs(pt_x+=pt_xs) > 123) pt_xs=-pt_xs;
444 if(abs(pt_y+=pt_ys) > 50) pt_ys=-pt_ys;
445 if(gsndt>0) if(--gsndt==0) {
446 Z_sound(gsnd[myrand(4)],128);
448 for(i=0;i<MAXMN;++i) if((t=mn[i].t)!=0) {
449 switch(t) {
450 case MN_FISH:
451 if(!Z_inwater(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h)) break;
452 case MN_SOUL: case MN_PAIN: case MN_CACO:
453 if(mn[i].st!=DIE && mn[i].st!=DEAD) --mn[i].o.yv;
454 break;
455 }z_mon=1;st=Z_moveobj(&mn[i].o);z_mon=0;
456 BM_mark(&mn[i].o,BM_MONSTER);
457 if(st&Z_FALLOUT) {
458 if(t==MN_ROBO) g_exit=1;
459 mn[i].t=0;--mnum;continue;
461 if(st&Z_HITWATER) Z_splash(&mn[i].o,mn[i].o.r+mn[i].o.h);
462 SW_press(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h,8,i);
463 if(mn[i].ftime) {
464 --mn[i].ftime;
465 SMK_flame(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,
466 mn[i].o.xv+mn[i].o.vx,mn[i].o.yv+mn[i].o.vy,
467 mn[i].o.r/2,mn[i].o.h/2,rand()%(200*2+1)-200,-500,1,mn[i].fobj);
469 if(st&Z_INWATER) mn[i].ftime=0;
470 if(mn[i].st==DEAD) continue;
471 if(st&Z_INWATER) if(!(rand()&31)) switch(t) {
472 case MN_FISH:
473 if(rand()&3) break;
474 case MN_ROBO: case MN_BARREL:
475 case MN_PL_DEAD: case MN_PL_MESS:
476 FX_bubble(mn[i].o.x+((rand()&1)*2-1)*myrand(mn[i].o.r+1),
477 mn[i].o.y-myrand(mn[i].o.h+1),0,0,1
478 );
479 break;
480 default:
481 FX_bubble(mn[i].o.x,mn[i].o.y-mn[i].o.h*3/4,0,0,5);
484 if(t==MN_BARREL) {
486 if(!mn[i].ap[++mn[i].ac]) {
487 mn[i].ac=0;if(mn[i].st==DIE || mn[i].st==DEAD) {mn[i].t=0;}
488 }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);
489 continue;
491 if(t==MN_SOUL) if(st&Z_HITAIR) Z_set_speed(&mn[i].o,16);
492 if(mn[i].ammo<0) ++mn[i].ammo;
493 if(mn[i].o.yv<0)
494 if(st&Z_INWATER) mn[i].o.yv=-4;
495 ++mn[i].atm;
496 switch(mn[i].st) {
497 case PAIN:
498 if(mn[i].pain>=mnsz[t].mp)
499 {mn[i].pain=mnsz[t].mp;Z_sound(snd[t-1][1],128);}
500 if((mn[i].pain-=5)<=mnsz[t].minp)
501 {setst(i,GO);mn[i].pain=0;mn[i].ammo=-9;}
502 break;
503 case SLEEP:
504 if(++mn[i].s>=18) mn[i].s=0; else break;
505 if(Z_look(&mn[i].o,&pl1.o,mn[i].d))
506 {setst(i,GO);mn[i].aim=-1;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
507 if(_2pl) if(Z_look(&mn[i].o,&pl2.o,mn[i].d))
508 {setst(i,GO);mn[i].aim=-2;mn[i].atm=0;Z_sound(wakeupsnd(t),128);}
509 break;
510 case WAIT:
511 if(--mn[i].s<0) setst(i,GO);
512 break;
513 case GO:
514 if(st&Z_BLOCK) {mn[i].d^=1;setst(i,RUNOUT);mn[i].s=40;break;}
515 if(t==MN_VILE) if(iscorpse(&mn[i].o,0)>=0) {
516 setst(i,ATTACK);mn[i].o.xv=0;break;
518 if(!Z_getobjpos(mn[i].aim,&o) || mn[i].atm>MAX_ATM)
519 if(!MN_findnewprey(i)) {
520 mn[i].aim=-3;
521 o.x=mn[i].o.x+pt_x;o.y=mn[i].o.y+pt_y;
522 o.xv=o.vx=o.yv=o.vy=o.r=0;o.h=1;
523 }else Z_getobjpos(mn[i].aim,&o);
524 if(Z_overlap(&mn[i].o,&o)) {
525 mn[i].atm=0;
526 if(kick(i,&o)) break;
528 sx=o.x-mn[i].o.x;
529 sy=o.y-o.h/2-mn[i].o.y+mn[i].o.h/2;
530 if(!(st&Z_BLOCK)) if(abs(sx)<20)
531 if(t!=MN_FISH) {setst(i,RUN);mn[i].s=15;mn[i].d=rand()&1;break;}
532 if(st&Z_HITWALL) {
533 if(SW_press(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h,2,i))
534 {setst(i,WAIT);mn[i].s=4;break;}
535 switch(t) {
536 case MN_CACO: case MN_SOUL: case MN_PAIN: case MN_FISH:
537 break;
538 default:
539 if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
540 {mn[i].o.yv=-mnsz[t].jv;setst(i,CLIMB);break;}
541 }break;
543 mn[i].d=(sx>0)?1:0;
544 if(canshoot(t))
545 if(abs(sx)>abs(sy)) if(shoot(i,&o,0)) break;
547 switch(t) {
548 case MN_FISH:
549 if(!(st&Z_INWATER)) {
550 if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r)) {
551 mn[i].o.yv=-6;
552 mn[i].o.vx+=rand()%17-8;
553 }setst(i,PAIN);mn[i].pain+=50;break;
555 case MN_CACO: case MN_SOUL: case MN_PAIN:
556 if(abs(sy)>4) mn[i].o.yv=(sy<0)?-4:4; else mn[i].o.yv=0;
557 if(t==MN_FISH) if(mn[i].o.yv<0)
558 if(!Z_inwater(mn[i].o.x,mn[i].o.y-8,mn[i].o.r,mn[i].o.h))
559 {mn[i].o.yv=0;setst(i,RUN);mn[i].d=rand()&1;mn[i].s=20;}
560 break;
561 default:
562 if(sy<-20) if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
563 if(!(rand()&3)) mn[i].o.yv=-mnsz[t].jv;
565 if(++mn[i].s>=8) {
566 mn[i].s=0;
567 if(!(rand()&7)) Z_sound(snd[t-1][0],128);
569 mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
570 if(st&Z_INWATER) mn[i].o.xv/=2;
571 else if(t==MN_FISH) mn[i].o.xv=0;
572 break;
573 case RUN:
574 if(st&Z_BLOCK) {setst(i,RUNOUT);mn[i].d^=1;mn[i].s=40;break;}
575 if(--mn[i].s<=0 || ((st&Z_HITWALL) && mn[i].o.yv+mn[i].o.vy==0)) {
576 setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
577 if(!(rand()&7)) Z_sound(snd[t-1][0],128);
578 }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
579 if(st&Z_INWATER) mn[i].o.xv/=2;
580 else if(t==MN_FISH) mn[i].o.xv=0;
581 break;
582 case RUNOUT:
583 if(!(st&Z_BLOCK) && mn[i].s>0) mn[i].s=0;
584 if(--mn[i].s<=-18) {
585 setst(i,GO);mn[i].s=0;if(st&(Z_HITWALL|Z_BLOCK)) mn[i].d^=1;
586 if(!(rand()&7)) Z_sound(snd[t-1][0],128);
587 }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
588 if(st&Z_INWATER) mn[i].o.xv/=2;
589 else if(t==MN_FISH) mn[i].o.xv=0;
590 break;
591 case CLIMB:
592 if(mn[i].o.yv+mn[i].o.vy>=0 || !(st&Z_HITWALL)) {
593 setst(i,GO);mn[i].s=0;
594 if(st&(Z_HITWALL|Z_BLOCK)) {mn[i].d^=1;setst(i,RUN);mn[i].s=15;}
595 }mn[i].o.xv=((mn[i].d)?1:-1)*mnsz[t].rv;
596 if(st&Z_INWATER) mn[i].o.xv/=2;
597 else if(t==MN_FISH) mn[i].o.xv=0;
598 break;
599 case ATTACK:
600 case SHOOT:
601 if(t==MN_SOUL) {if(st&(Z_HITWALL|Z_HITCEIL|Z_HITLAND)) setst(i,GO); break;}
602 if(t!=MN_FISH) mn[i].o.xv=Z_dec(mn[i].o.xv,1);
603 if(t==MN_VILE && mn[i].st==SHOOT) {
604 if(!Z_getobjpos(mn[i].aim,&o)) {setst(i,GO);break;}
605 if(!Z_look(&mn[i].o,&o,mn[i].d)) {setst(i,GO);break;}
606 if(Z_inwater(o.x,o.y,o.r,o.h)) {setst(i,GO);break;}
607 mn[i].tx=o.x;mn[i].ty=o.y;
608 Z_hitobj(mn[i].aim,2,i,HIT_SOME);
609 }break;
611 if(mn[i].st==REVIVE) {
612 if(--mn[i].ac==0) setst(i,GO);
613 }else ++mn[i].ac;
614 if(!mn[i].ap[mn[i].ac]) switch(mn[i].st) {
615 case ATTACK:
616 switch(t) {
617 case MN_SOUL: mn[i].ac=0;
618 case MN_IMP:
619 case MN_DEMON:
620 if(Z_hit(&mn[i].o,15,i,HIT_SOME)) if(t==MN_SOUL) setst(i,GO);
621 break;
622 case MN_FISH:
623 if(Z_hit(&mn[i].o,10,i,HIT_SOME))
624 Z_sound(snd[MN_FISH-1][2],128);
625 break;
626 case MN_SKEL: case MN_ROBO:
627 o=mn[i].o;o.xv=mn[i].d?50:-50;
628 if(Z_hit(&o,50,i,HIT_SOME)) Z_sound(pchsnd,128);
629 break;
630 case MN_VILE:
631 sx=iscorpse(&mn[i].o,1);
632 if(sx==-3) break;
633 if(!mn[sx].t || mn[sx].st!=DEAD) break;
634 setst(sx,REVIVE);Z_sound(slopsnd,128);
635 hit_xv=hit_yv=0;MN_hit(i,5,-3,HIT_SOME);
636 break;
637 }if(t!=MN_SOUL && mn[i].st!=DIE) setst(i,GO);
638 break;
639 case SHOOT:
640 switch(t) {
641 case MN_IMP:
642 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);
643 break;
644 case MN_ZOMBY:
645 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);
646 break;
647 case MN_SERG:
648 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);
649 break;
650 case MN_MAN:
651 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);
652 mn[i].ammo=-36;break;
653 case MN_CYBER:
654 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);
655 break;
656 case MN_SKEL:
657 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);
658 break;
659 case MN_CGUN:
660 case MN_SPIDER:
661 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);
662 break;
663 case MN_BSP:
664 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);
665 break;
666 case MN_ROBO:
667 WP_plasma(mn[i].o.x+(mn[i].d*2-1)*15,mn[i].o.y-30,mn[i].tx,mn[i].ty,i);
668 break;
669 case MN_MANCUB:
670 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);
671 break;
672 case MN_BARON: case MN_KNIGHT:
673 WP_ball7(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
674 break;
675 case MN_CACO:
676 WP_ball2(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,mn[i].tx,mn[i].ty,i);
677 break;
678 case MN_PAIN:
679 if((sx=MN_spawn(mn[i].o.x,mn[i].o.y,mn[i].d,MN_SOUL))==-1) break;
680 Z_getobjpos(mn[sx].aim=mn[i].aim,&o);mn[sx].atm=0;
681 shoot(sx,&o,1);
682 break;
684 if(t==MN_CGUN || t==MN_SPIDER || t==MN_BSP || t==MN_MANCUB || t==MN_ROBO)
685 if(!Z_getobjpos(mn[i].aim,&o)) MN_findnewprey(i);
686 else if(shoot(i,&o,0)) break;
687 setst(i,GO);break;
688 case DIE:
689 setst(i,DEAD);
690 if(t==MN_PAIN || t==MN_SOUL) mn[i].ftime=0;
691 if(t==MN_PAIN) {
692 if((sx=MN_spawn(mn[i].o.x-15,mn[i].o.y,0,MN_SOUL))==-1) break;
693 setst(sx,GO);
694 if((sx=MN_spawn(mn[i].o.x+15,mn[i].o.y,1,MN_SOUL))==-1) break;
695 setst(sx,GO);
696 if((sx=MN_spawn(mn[i].o.x,mn[i].o.y-10,1,MN_SOUL))==-1) break;
697 setst(sx,GO);
698 }break;
699 default: mn[i].ac=0;
701 switch(mn[i].st) {
702 case GO: case RUN: case CLIMB: case RUNOUT:
703 if(t==MN_CYBER || t==MN_SPIDER || t==MN_BSP) {
704 if(mn[i].ac==0 || mn[i].ac==6) Z_sound(snd[t-1][2],128);
705 }else if(t==MN_ROBO)
706 if(mn[i].ac==0 || mn[i].ac==12) Z_sound(snd[t-1][2],128);
711 void MN_mark (void) {
712 int i;
713 for(i=0;i<MAXMN;++i) if(mn[i].t!=0) BM_mark(&mn[i].o,BM_MONSTER);
716 int MN_hit(int n,int d,int o,int t) {
717 int i;
719 if(mn[n].st==DEAD || mn[n].st==DIE) return 0;
720 if(o==n) {
721 if(t!=HIT_ROCKET && t!=HIT_ELECTRO) return 0;
722 if(mn[n].t==MN_CYBER || mn[n].t==MN_BARREL) return 1;
724 if(o>=0) {
725 if(mn[o].t==MN_SOUL && mn[n].t==MN_PAIN) return 0;
726 if(mn[o].t==mn[n].t) switch(mn[n].t) {
727 case MN_IMP: case MN_DEMON:
728 case MN_BARON: case MN_KNIGHT:
729 case MN_CACO: case MN_SOUL:
730 case MN_MANCUB: case MN_SKEL:
731 case MN_FISH:
732 return 0;
735 if(t==HIT_FLAME) if(mn[n].ftime && mn[n].fobj==o) {if(g_time&31) return 1;}
736 else {mn[n].ftime=255;mn[n].fobj=o;}
737 if(t==HIT_ELECTRO) if(mn[n].t==MN_FISH)
738 {setst(n,RUN);mn[n].s=20;mn[n].d=rand()&1;return 1;}
739 if(t==HIT_TRAP) mn[n].life=-100;
740 if(mn[n].t==MN_ROBO) d=0;
741 if((mn[n].life-=d)<=0) --mnum;
742 if(!mn[n].pain) mn[n].pain=3;
743 mn[n].pain+=d;
744 if(mn[n].st!=PAIN) {
745 if(mn[n].pain>=mnsz[mn[n].t].minp) setst(n,PAIN);
747 if(mn[n].t!=MN_BARREL)
748 DOT_blood(mn[n].o.x,mn[n].o.y-mn[n].o.h/2,hit_xv,hit_yv,d*2);
749 mn[n].aim=o;mn[n].atm=0;
750 if(mn[n].life<=0) {
751 if(mn[n].t!=MN_BARREL)
752 if(o==-1) ++pl1.kills;
753 else if(o==-2) ++pl2.kills;
754 setst(n,DIE);
755 switch(mn[n].t) {
756 case MN_ZOMBY: i=I_CLIP;break;
757 case MN_SERG: i=I_SGUN;break;
758 case MN_CGUN: i=I_MGUN;break;
759 case MN_MAN: i=I_KEYR;break;
760 default: i=0;
761 }if(i) IT_spawn(mn[n].o.x,mn[n].o.y,i);
762 mn[n].o.xv=0;mn[n].o.h=6;
763 if(mn[n].life<=-mnsz[mn[n].t].sp)
764 switch(mn[n].t) {
765 case MN_IMP: case MN_ZOMBY: case MN_SERG: case MN_CGUN:
766 case MN_MAN:
767 mn[n].ap=slopanim[mn[n].t-1];
768 Z_sound(slopsnd,128);
769 break;
770 case MN_BSP: if(g_map==9) break;
771 default:
772 Z_sound(dthsnd(mn[n].t),128);
774 else if(mn[n].t!=MN_BSP || g_map!=9) Z_sound(dthsnd(mn[n].t),128);
775 mn[n].life=0;
776 }else if(mn[n].st==SLEEP) {setst(n,GO);mn[n].pain=mnsz[mn[n].t].mp;}
777 return 1;
780 #define hit(o,x,y) (y<=o.y && y>o.y-o.h && x>=o.x-o.r && x<=o.x+o.r)
782 int Z_gunhit (int x, int y, int o, int xv, int yv) {
783 int i;
785 if(o!=-1) if(hit(pl1.o,x,y)) if(PL_hit(&pl1,3,o,HIT_SOME))
786 {pl1.o.vx+=xv;pl1.o.vy+=yv;return -1;}
787 if(_2pl && o!=-2) if(hit(pl2.o,x,y)) if(PL_hit(&pl2,3,o,HIT_SOME))
788 {pl2.o.vx+=xv;pl2.o.vy+=yv;return -2;}
790 for(i=0;i<MAXMN;++i) if(mn[i].t && o!=i)
791 if(hit(mn[i].o,x,y)) if(MN_hit(i,3,o,HIT_SOME))
792 {mn[i].o.vx+=xv;mn[i].o.vy+=yv;return 1;}
793 return 0;
796 static void goodsnd(void) {
797 if(!g_dm) return;
798 gsndt=18;
801 int Z_hit (obj_t *o, int d, int own, int t) {
802 int i;
804 hit_xv=o->xv+o->vx;
805 hit_yv=o->yv+o->vy;
806 if(Z_overlap(o,&pl1.o)) if(PL_hit(&pl1,d,own,t)) {
807 pl1.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
808 pl1.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
809 if(t==HIT_BFG) goodsnd();
810 return -1;
812 if(_2pl) if(Z_overlap(o,&pl2.o)) if(PL_hit(&pl2,d,own,t)) {
813 pl2.o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
814 pl2.o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
815 if(t==HIT_BFG) goodsnd();
816 return -2;
819 for(i=0;i<MAXMN;++i) if(mn[i].t)
820 if(Z_overlap(o,&mn[i].o)) if(MN_hit(i,d,own,t)) {
821 mn[i].o.vx+=(o->xv+o->vx)*((t==HIT_BFG)?8:1)/4;
822 mn[i].o.vy+=(o->yv+o->vy)*((t==HIT_BFG)?8:1)/4;
823 return 1;
825 return 0;
828 void MN_killedp (void) {
829 int i;
830 for(i=0;i<MAXMN;++i) if(mn[i].t==MN_MAN)
831 if(mn[i].st!=DEAD && mn[i].st!=DIE && mn[i].st!=SLEEP)
832 Z_sound(trupsnd,128);
835 void Z_explode (int x,int y,int rad,int own) {
836 long r;
837 int dx,dy,m,i;
839 if(x<-100 || x>FLDW*CELW+100) return;
840 if(y<-100 || y>FLDH*CELH+100) return;
841 r=(long)rad*rad;
842 dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
843 if((long)dx*dx+(long)dy*dy<r) {
844 if(!(m=max(abs(dx),abs(dy)))) m=1;
845 pl1.o.vx+=hit_xv=dx*10/m;
846 pl1.o.vy+=hit_yv=dy*10/m;
847 PL_hit(&pl1,100*(rad-m)/rad,own,HIT_ROCKET);
849 if(_2pl) {
850 dx=pl2.o.x-x;dy=pl2.o.y-pl2.o.h/2-y;
851 if((long)dx*dx+(long)dy*dy<r) {
852 if(!(m=max(abs(dx),abs(dy)))) m=1;
853 pl2.o.vx+=hit_xv=dx*10/m;
854 pl2.o.vy+=hit_yv=dy*10/m;
855 PL_hit(&pl2,100*(rad-m)/rad,own,HIT_ROCKET);
858 for(i=0;i<MAXMN;++i) if(mn[i].t) {
859 dx=mn[i].o.x-x;dy=mn[i].o.y-mn[i].o.h/2-y;
860 if((long)dx*dx+(long)dy*dy<r) {
861 if(!(m=max(abs(dx),abs(dy)))) m=1;
862 mn[i].o.vx+=hit_xv=dx*10/m;
863 mn[i].o.vy+=hit_yv=dy*10/m;
864 MN_hit(i,mn[i].o.r*10*(rad-m)/rad,own,HIT_ROCKET);
869 void Z_bfg9000 (int x,int y,int own) {
870 int dx,dy,i;
872 hit_xv=hit_yv=0;
873 if(x<-100 || x>FLDW*CELW+100) return;
874 if(y<-100 || y>FLDH*CELH+100) return;
875 dx=pl1.o.x-x;dy=pl1.o.y-pl1.o.h/2-y;
876 if(own!=-1) if((long)dx*dx+(long)dy*dy<16000)
877 if(Z_cansee(x,y,pl1.o.x,pl1.o.y-pl1.o.h/2)) {
878 if(PL_hit(&pl1,50,own,HIT_SOME))
879 WP_bfghit(pl1.o.x,pl1.o.y-pl1.o.h/2,own);
881 if(_2pl) {
882 dx=pl2.o.x-x;dy=pl2.o.y-pl2.o.h/2-y;
883 if(own!=-2) if((long)dx*dx+(long)dy*dy<16000)
884 if(Z_cansee(x,y,pl2.o.x,pl2.o.y-pl2.o.h/2)) {
885 if(PL_hit(&pl2,50,own,HIT_SOME))
886 WP_bfghit(pl2.o.x,pl2.o.y-pl2.o.h/2,own);
889 for(i=0;i<MAXMN;++i) if(mn[i].t && own!=i) {
890 dx=mn[i].o.x-x;dy=mn[i].o.y-mn[i].o.h/2-y;
891 if((long)dx*dx+(long)dy*dy<16000)
892 if(Z_cansee(x,y,mn[i].o.x,mn[i].o.y-mn[i].o.h/2)) {
893 if(MN_hit(i,50,own,HIT_SOME))
894 WP_bfghit(mn[i].o.x,mn[i].o.y-mn[i].o.h/2,own);
899 int Z_chktrap (int t, int d, int o, int ht) {
900 int i,s;
902 hit_xv=hit_yv=0;
903 s=0;
904 if(Z_istrapped(pl1.o.x,pl1.o.y,pl1.o.r,pl1.o.h)) {
905 s=1;
906 if(t) PL_hit(&pl1,d,o,ht);
908 if(_2pl) if(Z_istrapped(pl2.o.x,pl2.o.y,pl2.o.r,pl2.o.h)) {
909 s=1;
910 if(t) PL_hit(&pl2,d,o,ht);
912 for(i=0;i<MAXMN;++i) if(mn[i].t && mn[i].st!=DEAD)
913 if(Z_istrapped(mn[i].o.x,mn[i].o.y,mn[i].o.r,mn[i].o.h)) {
914 s=1;
915 if(t) MN_hit(i,d,o,ht);
917 return s;
920 void Z_teleobj (int o, int x, int y) {
921 obj_t *p;
923 if(o==-1) p=&pl1.o;
924 else if(o==-2) p=&pl2.o;
925 else if(o>=0 && o<MAXMN) p=&mn[o].o;
926 else return;
927 FX_tfog(p->x,p->y);FX_tfog(p->x=x,p->y=y);
928 Z_sound(telesnd,128);
931 void MN_warning (int l,int t,int r,int b) {
932 int i;
934 for(i=0;i<MAXMN;++i) if(mn[i].t && mn[i].t!=MN_CACO && mn[i].t!=MN_SOUL
935 && mn[i].t!=MN_PAIN && mn[i].t!=MN_FISH)
936 if(mn[i].st!=DIE && mn[i].st!=DEAD && mn[i].st!=SLEEP)
937 if(mn[i].o.x+mn[i].o.r>=l && mn[i].o.x-mn[i].o.r<=r
938 && mn[i].o.y>=t && mn[i].o.y-mn[i].o.h<=b)
939 if(Z_canstand(mn[i].o.x,mn[i].o.y,mn[i].o.r))
940 mn[i].o.yv=-mnsz[mn[i].t].jv;