6a803a151b1588e206a404e9e5fcb57b66608c83
1 /* Copyright (C) 1996-1997 Aleksey Volynskov
2 * Copyright (C) 2011 Rambo
3 * Copyright (C) 2020 SovietPony
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.
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.
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/>.
41 #define PL_AQUA_AIR 1091
49 static int wp_it
[11]={0,I_CSAW
,0,I_SGUN
,I_SGUN2
,I_MGUN
,I_LAUN
,I_PLAS
,I_BFG
,I_GUN2
,0};
51 enum{STAND
,GO
,DIE
,SLOP
,DEAD
,MESS
,OUT
,FALL
};
53 typedef void fire_f(int,int,int,int,int);
58 static void *aisnd
[3];
59 static void *pdsnd
[5];
62 byte plr_goanim
[]="BDACDA";
63 byte plr_dieanim
[]="HHHHIIIIJJJJKKKKLLLLMMMM";
64 byte plr_slopanim
[]="OOPPQQRRSSTTUUVVWW";
66 static int nonz (int a
) {
70 static int firediry(player_t
*p
) {
71 if(p
->f
&PLF_UP
) return -42;
72 if(p
->f
&PLF_DOWN
) return 19;
76 static void fire(player_t
*p
) {
77 static fire_f
*ff
[11]={
78 WP_pistol
,WP_pistol
,WP_pistol
,WP_shotgun
,WP_dshotgun
,
79 WP_mgun
,WP_rocket
,WP_plasma
,WP_bfgshot
,WP_shotgun
,WP_pistol
};
80 static int ft
[11]={5,2,6,18,36,2,12,2,0,2,1};
85 if(I_pressed(p
->kf
) && p
->cell
>=40)
86 {Z_sound(snd
[5],128);p
->fire
=21;p
->cell
-=40;p
->drawst
|=PL_DRAWWPN
;return;}
88 if(p
->fire
==1) p
->cwpn
=12;
92 if(!I_pressed(p
->kf
)) {Z_sound(snd
[7],128);p
->csnd
=13;return;}
94 if(I_pressed(p
->kf
) && !p
->fire
) {
96 WP_chainsaw(p
->o
.x
+((p
->d
)?4:-4),p
->o
.y
,(g_dm
)?9:3,p
->id
);
97 if(!p
->csnd
) {Z_sound(snd
[8],128);p
->csnd
=29;}
99 }else if(p
->fire
) return;
100 if(I_pressed(p
->kf
) || p
->wpn
==8) {
104 --p
->ammo
;p
->drawst
|=PL_DRAWWPN
;break;
107 --p
->shel
;p
->drawst
|=PL_DRAWWPN
;break;
109 if(p
->shel
<2) return;
110 p
->shel
-=2;p
->drawst
|=PL_DRAWWPN
;break;
113 --p
->rock
;p
->drawst
|=PL_DRAWWPN
;break;
116 --p
->cell
;p
->drawst
|=PL_DRAWWPN
;break;
119 --p
->fuel
;p
->drawst
|=PL_DRAWWPN
;break;
122 WP_ognemet(p
->o
.x
,p
->o
.y
-15,p
->o
.x
+((p
->d
)?30:-30),p
->o
.y
-15+firediry(p
),
123 p
->o
.xv
+p
->o
.vx
,p
->o
.yv
+p
->o
.vy
,p
->id
);
124 else if(p
->wpn
>=1) ff
[p
->wpn
] (p
->o
.x
,p
->o
.y
-15,p
->o
.x
+((p
->d
)?30:-30),
125 p
->o
.y
-15+firediry(p
),p
->id
);
126 else WP_punch(p
->o
.x
+((p
->d
)?4:-4),p
->o
.y
,3,p
->id
);
128 if(p
->wpn
>=2) p
->f
|=PLF_FIRE
;
132 static void chgwpn(player_t
*p
) {
134 if(p
->fire
&& p
->wpn
!=1) return;
135 if(I_pressed(p
->kwl
)) {
136 do{ if(--p
->wpn
<0) p
->wpn
=10; }while(!(p
->wpns
&(1<<p
->wpn
)));
138 }else if(I_pressed(p
->kwr
)) {
139 do{ if(++p
->wpn
>10) p
->wpn
=0; }while(!(p
->wpns
&(1<<p
->wpn
)));
143 p
->drawst
|=PL_DRAWWPN
;p
->fire
=0;
144 if(p
->wpn
==1) Z_sound(snd
[6],128);
148 static void jump(player_t
*p
,int st
) {
149 if(Z_canbreathe(p
->o
.x
,p
->o
.y
,p
->o
.r
,p
->o
.h
)) {
150 if(p
->air
<PL_AIR
) {p
->air
=PL_AIR
;p
->drawst
|=PL_DRAWAIR
;}
154 PL_hit(p
,10,-3,HIT_WATER
);
155 }else if((p
->air
&31)==0) {
156 FX_bubble(p
->o
.x
,p
->o
.y
-20,0,0,5);
158 p
->drawst
|=PL_DRAWAIR
;
160 if(I_pressed(p
->kj
)) {
164 if(Z_canstand(p
->o
.x
,p
->o
.y
,p
->o
.r
)) p
->o
.yv
=-PL_JUMP
;
165 else if(st
&Z_INWATER
) p
->o
.yv
=-PL_SWUP
;
170 int PL_isdead (player_t
*p
) {
172 case DEAD
: case MESS
:
179 void PL_init (void) {
188 void PL_alloc(void) {
190 static char nm
[][6]={
204 for(i
=0;i
<11;++i
) snd
[i
]=Z_getsnd(nm
[i
]);
208 aisnd
[i
]=Z_getsnd(s
);
210 memcpy(s
,"PLDTHx",6);
213 pdsnd
[i
]=Z_getsnd(s
);
217 static void PL_restore(player_t
*p
) {
218 p
->o
.xv
=p
->o
.yv
=p
->o
.vx
=p
->o
.vy
=0;
219 p
->o
.r
=PL_RAD
;p
->o
.h
=PL_HT
;
223 case DEAD
: case MESS
: case OUT
:
224 case DIE
: case SLOP
: case FALL
:
225 p
->life
=100;p
->armor
=0;p
->air
=PL_AIR
;
228 p
->ammo
=50;p
->fuel
=p
->shel
=p
->rock
=p
->cell
=0;
232 p
->fire
=p
->cwpn
=p
->csnd
=0;
236 p
->keys
=(g_dm
)?0x70:0;
239 void PL_reset (void) {
244 void PL_spawn (player_t
*p
,int x
,int y
,char d
) {
246 p
->o
.x
=x
;p
->o
.y
=y
;p
->d
=d
;
247 p
->kills
=p
->secrets
=0;
250 int PL_hit (player_t
*p
,int d
,int o
,int t
) {
254 case DEAD
: case MESS
:
258 if(t
==HIT_TRAP
) {if(!p_immortal
) {p
->armor
=0;p
->life
=-100;}}
259 else if(t
!=HIT_ROCKET
&& t
!=HIT_ELECTRO
) {
260 if(p
->id
==-1) {if(o
==-1) return 0;}
261 else if(o
==-2) return 0;
263 if(t
!=HIT_WATER
&& t
!=HIT_ELECTRO
)
264 DOT_blood(p
->o
.x
,p
->o
.y
-15,hit_xv
,hit_yv
,d
*2);
265 else if(t
==HIT_WATER
) FX_bubble(p
->o
.x
,p
->o
.y
-20,0,0,d
/2);
266 if(p_immortal
|| p
->invl
) return 1;
272 void PL_damage (player_t
*p
) {
275 if(!p
->hit
&& p
->life
>0) return;
278 case DEAD
: case MESS
:
282 i
=p
->hit
*p
->life
/nonz(p
->armor
*3/4+p
->life
);
284 p
->drawst
|=PL_DRAWLIFE
|PL_DRAWARMOR
;
285 if((p
->armor
-=p
->hit
-i
)<0) {p
->life
+=p
->armor
;p
->armor
=0;}
286 if((p
->life
-=i
)<=0) {
287 if(p
->life
>-30) {p
->st
=DIE
;p
->s
=0;Z_sound(pdsnd
[rand()%5
],128);}
288 else {p
->st
=SLOP
;p
->s
=0;Z_sound(snd
[3],128);}
289 if(p
->amul
>1) IT_spawn(p
->o
.x
,p
->o
.y
,I_BPACK
);
291 if(p
->keys
&16) IT_spawn(p
->o
.x
,p
->o
.y
,I_KEYR
);
292 if(p
->keys
&32) IT_spawn(p
->o
.x
,p
->o
.y
,I_KEYG
);
293 if(p
->keys
&64) IT_spawn(p
->o
.x
,p
->o
.y
,I_KEYB
);
295 for(i
=1,p
->wpns
>>=1;i
<11;++i
,p
->wpns
>>=1)
296 if(i
!=2) if(p
->wpns
&1) IT_spawn(p
->o
.x
,p
->o
.y
,wp_it
[i
]);
299 p
->drawst
|=PL_DRAWWPN
;
302 if(p
->hito
==-2) {++pl2
.kills
;++pl2
.frag
;}
303 else if(p
->hito
==-1) --pl1
.frag
;
305 if(p
->hito
==-1) {++pl1
.kills
;++pl1
.frag
;}
306 else if(p
->hito
==-2) --pl2
.frag
;
308 pl1
.drawst
|=PL_DRAWFRAG
;
309 if(_2pl
) pl2
.drawst
|=PL_DRAWFRAG
;
316 void PL_cry (player_t
*p
) {
317 Z_sound(snd
[(p
->pain
>20)?1:0],128);
321 int PL_give (player_t
*p
, int t
) {
326 case DEAD
: case MESS
: case OUT
:
330 case I_STIM
: case I_MEDI
:
331 if(p
->life
>=100) return 0;
332 if((p
->life
+=((t
==I_MEDI
)?25:10))>100) p
->life
=100;
333 p
->drawst
|=PL_DRAWLIFE
;return 1;
335 if(p
->ammo
>=200*p
->amul
) return 0;
336 if((p
->ammo
+=10)>200*p
->amul
) p
->ammo
=200*p
->amul
;
337 p
->drawst
|=PL_DRAWWPN
;return 1;
339 if(p
->ammo
>=200*p
->amul
) return 0;
340 if((p
->ammo
+=50)>200*p
->amul
) p
->ammo
=200*p
->amul
;
341 p
->drawst
|=PL_DRAWWPN
;return 1;
343 if(p
->shel
>=50*p
->amul
) return 0;
344 if((p
->shel
+=4)>50*p
->amul
) p
->shel
=50*p
->amul
;
345 p
->drawst
|=PL_DRAWWPN
;return 1;
347 if(p
->shel
>=50*p
->amul
) return 0;
348 if((p
->shel
+=25)>50*p
->amul
) p
->shel
=50*p
->amul
;
349 p
->drawst
|=PL_DRAWWPN
;return 1;
351 if(p
->rock
>=50*p
->amul
) return 0;
352 if((++p
->rock
)>50*p
->amul
) p
->rock
=50*p
->amul
;
353 p
->drawst
|=PL_DRAWWPN
;return 1;
355 if(p
->rock
>=50*p
->amul
) return 0;
356 if((p
->rock
+=5)>50*p
->amul
) p
->rock
=50*p
->amul
;
357 p
->drawst
|=PL_DRAWWPN
;return 1;
359 if(p
->cell
>=300*p
->amul
) return 0;
360 if((p
->cell
+=40)>300*p
->amul
) p
->cell
=300*p
->amul
;
361 p
->drawst
|=PL_DRAWWPN
;return 1;
363 if(p
->cell
>=300*p
->amul
) return 0;
364 if((p
->cell
+=100)>300*p
->amul
) p
->cell
=300*p
->amul
;
365 p
->drawst
|=PL_DRAWWPN
;return 1;
367 if(p
->amul
==1) {p
->amul
=2;i
=1;} else i
=0;
368 i
|=PL_give(p
,I_CLIP
);
369 i
|=PL_give(p
,I_SHEL
);
370 i
|=PL_give(p
,I_ROCKET
);
371 i
|=PL_give(p
,I_CELL
);
374 if(!(p
->wpns
&2)) {p
->wpns
|=2;p
->drawst
|=PL_DRAWWPN
;return 1;}
378 if(!(p
->wpns
&512)) {p
->wpns
|=512;i
=1;}
379 p
->drawst
|=PL_DRAWWPN
;return i
;
382 if(!(p
->wpns
&8)) {p
->wpns
|=8;i
=1;}
383 p
->drawst
|=PL_DRAWWPN
;return i
;
386 if(!(p
->wpns
&16)) {p
->wpns
|=16;i
=1;}
387 p
->drawst
|=PL_DRAWWPN
;return i
;
390 if(!(p
->wpns
&32)) {p
->wpns
|=32;i
=1;}
391 p
->drawst
|=PL_DRAWWPN
;return i
;
393 i
=PL_give(p
,I_ROCKET
);
394 i
|=PL_give(p
,I_ROCKET
);
395 if(!(p
->wpns
&64)) {p
->wpns
|=64;i
=1;}
396 p
->drawst
|=PL_DRAWWPN
;return i
;
399 if(!(p
->wpns
&128)) {p
->wpns
|=128;i
=1;}
400 p
->drawst
|=PL_DRAWWPN
;return i
;
403 if(!(p
->wpns
&256)) {p
->wpns
|=256;i
=1;}
404 p
->drawst
|=PL_DRAWWPN
;return i
;
406 if(p
->armor
>=100) return 0;
407 p
->armor
=100;p
->drawst
|=PL_DRAWARMOR
;return 1;
409 if(p
->armor
>=200) return 0;
410 p
->armor
=200;p
->drawst
|=PL_DRAWARMOR
;return 1;
413 if(p
->life
<200) {p
->life
=200;p
->drawst
|=PL_DRAWLIFE
;i
=1;}
414 if(p
->armor
<200) {p
->armor
=200;p
->drawst
|=PL_DRAWARMOR
;i
=1;}
417 if(p
->life
<200) {p
->life
=min(p
->life
+100,200);p
->drawst
|=PL_DRAWLIFE
;return 1;}
420 p
->invl
=PL_POWERUP_TIME
;
423 p
->suit
=PL_POWERUP_TIME
;
426 if(p
->air
>= PL_AQUA_AIR
) return 0;
427 p
->air
=PL_AQUA_AIR
;p
->drawst
|=PL_DRAWAIR
;
430 if(p
->keys
&16) return 0;
431 p
->keys
|=16;p
->drawst
|=PL_DRAWKEYS
;return 1;
433 if(p
->keys
&32) return 0;
434 p
->keys
|=32;p
->drawst
|=PL_DRAWKEYS
;return 1;
436 if(p
->keys
&64) return 0;
437 p
->keys
|=64;p
->drawst
|=PL_DRAWKEYS
;return 1;
443 void PL_act (player_t
*p
) {
446 if(--aitime
<0) aitime
=0;
447 SW_press(p
->o
.x
,p
->o
.y
,p
->o
.r
,p
->o
.h
,4|p
->keys
,p
->id
);
448 if(!p
->suit
) if((g_time
&15)==0)
449 PL_hit(p
,Z_getacid(p
->o
.x
,p
->o
.y
,p
->o
.r
,p
->o
.h
),-3,HIT_SOME
);
450 if(p
->st
!=FALL
&& p
->st
!=OUT
) {
451 if(((st
=Z_moveobj(&p
->o
))&Z_FALLOUT
) && p
->o
.y
>=FLDH
*CELH
+50) {
453 case DEAD
: case MESS
: case DIE
: case SLOP
:
456 p
->s
=Z_sound(snd
[10],128);
461 if(st
&Z_HITWATER
) Z_splash(&p
->o
,PL_RAD
+PL_HT
);
462 if(p
->f
&PLF_FIRE
) if(p
->fire
!=2) p
->f
-=PLF_FIRE
;
463 if(I_pressed(p
->ku
)) {p
->f
|=PLF_UP
;p
->looky
-=5;}
467 {p
->f
|=PLF_DOWN
;p
->looky
+=5;}
468 else {p
->f
&=0xFFFF-PLF_DOWN
;p
->looky
=Z_dec(p
->looky
,5);}
470 if(I_pressed(p
->kp
)) SW_press(p
->o
.x
,p
->o
.y
,p
->o
.r
,p
->o
.h
,1|p
->keys
,p
->id
);
471 if(p
->fire
) --p
->fire
;
472 if(p
->cwpn
) --p
->cwpn
;
473 if(p
->csnd
) --p
->csnd
;
474 if(p
->invl
) --p
->invl
;
475 if(p
->suit
) --p
->suit
;
479 if(!plr_dieanim
[++p
->s
]) {p
->st
=DEAD
;MN_killedp();}
480 p
->o
.xv
=Z_dec(p
->o
.xv
,1);
484 if(!plr_slopanim
[++p
->s
]) {p
->st
=MESS
;MN_killedp();}
485 p
->o
.xv
=Z_dec(p
->o
.xv
,1);
488 chgwpn(p
);fire(p
);jump(p
,st
);
490 SMK_gas(p
->o
.x
,p
->o
.y
-2,2,3,p
->o
.xv
+p
->o
.vx
,p
->o
.yv
+p
->o
.vy
,128);
491 if((p
->s
+=abs(p
->o
.xv
)/2) >= 24) p
->s
%=24;
492 if(!I_pressed(p
->kl
) && !I_pressed(p
->kr
)) {
493 if(p
->o
.xv
) p
->o
.xv
=Z_dec(p
->o
.xv
,1);
497 if(p
->o
.xv
<PL_RUN
&& I_pressed(p
->kr
)) {p
->o
.xv
+=PL_RUN
>>3;p
->d
=1;}
499 SMK_gas(p
->o
.x
,p
->o
.y
-2,2,3,p
->o
.xv
+p
->o
.vx
,p
->o
.yv
+p
->o
.vy
,32);
500 if(p
->o
.xv
>-PL_RUN
&& I_pressed(p
->kl
)) {p
->o
.xv
-=PL_RUN
>>3;p
->d
=0;}
502 SMK_gas(p
->o
.x
,p
->o
.y
-2,2,3,p
->o
.xv
+p
->o
.vx
,p
->o
.yv
+p
->o
.vy
,32);
505 chgwpn(p
);fire(p
);jump(p
,st
);
507 SMK_gas(p
->o
.x
,p
->o
.y
-2,2,3,p
->o
.xv
+p
->o
.vx
,p
->o
.yv
+p
->o
.vy
,128);
508 if(I_pressed(p
->kl
)) {p
->st
=GO
;p
->s
=0;p
->d
=0;}
509 else if(I_pressed(p
->kr
)) {p
->st
=GO
;p
->s
=0;p
->d
=1;}
514 p
->o
.xv
=Z_dec(p
->o
.xv
,1);
515 if(I_pressed(p
->ku
) || I_pressed(p
->kd
) || I_pressed(p
->kl
) || I_pressed(p
->kr
) ||
516 I_pressed(p
->kf
) || I_pressed(p
->kj
) || I_pressed(p
->kp
) || I_pressed(p
->kwl
) || I_pressed(p
->kwr
)) {
517 if(p
->st
!=OUT
) MN_spawn_deadpl(&p
->o
,p
->color
,(p
->st
==MESS
)?1:0);
519 if(g_dm
) {G_respawn_player(p
);break;}
521 if(--p
->lives
==0) {G_start();break;}
522 else{p
->o
.x
=dm_pos
[0].x
;p
->o
.y
=dm_pos
[0].y
;p
->d
=dm_pos
[0].d
;}
523 p
->drawst
|=PL_DRAWLIVES
;
526 {p
->o
.x
=dm_pos
[0].x
;p
->o
.y
=dm_pos
[0].y
;p
->d
=dm_pos
[0].d
;}
527 else {p
->o
.x
=dm_pos
[1].x
;p
->o
.y
=dm_pos
[1].y
;p
->d
=dm_pos
[1].d
;}
530 if(--p
->s
<=0) p
->st
=OUT
;
535 static void chk_bfg(player_t
*p
,int x
,int y
) {
540 case DIE
: case SLOP
: case FALL
:
541 case DEAD
: case MESS
: case OUT
:
544 dx
=p
->o
.x
-x
;dy
=p
->o
.y
-p
->o
.h
/2-y
;
545 if(dx
*dx
+dy
*dy
<=1600) {
546 aitime
=Z_sound(aisnd
[rand()%3
],128)*4;
550 void bfg_fly (int x
,int y
,int o
) {
552 if(o
!=-1) chk_bfg(&pl1
,x
,y
);
553 if(_2pl
) if(o
!=-2) chk_bfg(&pl2
,x
,y
);
554 if(o
==-1 || o
==-2) MN_warning(x
-50,y
-50,x
+50,y
+50);