DEADSOFTWARE

79a5a98968cbd0b2009b80dab942b99362dd2403
[flatwaifu.git] / src / player.c
1 /*
2 Copyright (C) Prikol Software 1996-1997
3 Copyright (C) Aleksey Volynskov 1996-1997
4 Copyright (C) <ARembo@gmail.com> 2011
6 This file is part of the Doom2D:Rembo project.
8 Doom2D:Rembo is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as
10 published by the Free Software Foundation.
12 Doom2D:Rembo is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/> or
19 write to the Free Software Foundation, Inc.,
20 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
23 #include "glob.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include "view.h"
27 #include "dots.h"
28 #include "smoke.h"
29 #include "weapons.h"
30 #include "monster.h"
31 #include "fx.h"
32 #include "items.h"
33 #include "switch.h"
34 #include "player.h"
35 #include "misc.h"
36 #include "my.h"
37 #include "game.h"
38 #include "input.h"
40 #define PL_RAD 8
41 #define PL_HT 26
43 #define PL_SWUP 4
44 #define PL_FLYUP 4
46 #define PL_AQUA_AIR 1091
48 byte p_immortal;
49 byte p_fly;
51 int PL_JUMP=10;
52 int PL_RUN=8;
54 static int wp_it[11]={0,I_CSAW,0,I_SGUN,I_SGUN2,I_MGUN,I_LAUN,I_PLAS,I_BFG,I_GUN2,0};
56 enum{STAND,GO,DIE,SLOP,DEAD,MESS,OUT,FALL};
58 typedef void fire_f(int,int,int,int,int);
60 player_t pl1;
61 player_t pl2;
62 static int aitime;
63 static void *aisnd[3];
64 static void *pdsnd[5];
66 static void *snd[11];
67 byte plr_goanim[]="BDACDA";
68 byte plr_dieanim[]="HHHHIIIIJJJJKKKKLLLLMMMM";
69 byte plr_slopanim[]="OOPPQQRRSSTTUUVVWW";
71 static int nonz (int a) {
72 return a ? a : 1;
73 }
75 static int firediry(player_t *p) {
76 if(p->f&PLF_UP) return -42;
77 if(p->f&PLF_DOWN) return 19;
78 return 0;
79 }
81 static void fire(player_t *p) {
82 static fire_f *ff[11]={
83 WP_pistol,WP_pistol,WP_pistol,WP_shotgun,WP_dshotgun,
84 WP_mgun,WP_rocket,WP_plasma,WP_bfgshot,WP_shotgun,WP_pistol};
85 static int ft[11]={5,2,6,18,36,2,12,2,0,2,1};
87 if(p->cwpn) return;
88 if(p->wpn==8) {
89 if(!p->fire)
90 if(I_pressed(p->kf) && p->cell>=40)
91 {Z_sound(snd[5],128);p->fire=21;p->cell-=40;p->drawst|=PL_DRAWWPN;return;}
92 else return;
93 if(p->fire==1) p->cwpn=12;
94 else return;
95 }else if(p->wpn==1) {
96 if(!p->csnd) {
97 if(!I_pressed(p->kf)) {Z_sound(snd[7],128);p->csnd=13;return;}
98 }
99 if(I_pressed(p->kf) && !p->fire) {
100 p->fire=2;
101 WP_chainsaw(p->o.x+((p->d)?4:-4),p->o.y,(g_dm)?9:3,p->id);
102 if(!p->csnd) {Z_sound(snd[8],128);p->csnd=29;}
103 }return;
104 }else if(p->fire) return;
105 if(I_pressed(p->kf) || p->wpn==8) {
106 switch(p->wpn) {
107 case 2: case 5:
108 if(!p->ammo) return;
109 --p->ammo;p->drawst|=PL_DRAWWPN;break;
110 case 3: case 9:
111 if(!p->shel) return;
112 --p->shel;p->drawst|=PL_DRAWWPN;break;
113 case 4:
114 if(p->shel<2) return;
115 p->shel-=2;p->drawst|=PL_DRAWWPN;break;
116 case 6:
117 if(!p->rock) return;
118 --p->rock;p->drawst|=PL_DRAWWPN;break;
119 case 7:
120 if(!p->cell) return;
121 --p->cell;p->drawst|=PL_DRAWWPN;break;
122 case 10:
123 if(!p->fuel) return;
124 --p->fuel;p->drawst|=PL_DRAWWPN;break;
126 if(p->wpn==10)
127 WP_ognemet(p->o.x,p->o.y-15,p->o.x+((p->d)?30:-30),p->o.y-15+firediry(p),
128 p->o.xv+p->o.vx,p->o.yv+p->o.vy,p->id);
129 else if(p->wpn>=1) ff[p->wpn] (p->o.x,p->o.y-15,p->o.x+((p->d)?30:-30),
130 p->o.y-15+firediry(p),p->id);
131 else WP_punch(p->o.x+((p->d)?4:-4),p->o.y,3,p->id);
132 p->fire=ft[p->wpn];
133 if(p->wpn>=2) p->f|=PLF_FIRE;
137 static void chgwpn(player_t *p) {
138 if(p->cwpn) return;
139 if(p->fire && p->wpn!=1) return;
140 if(I_pressed(p->kwl)) {
141 do{ if(--p->wpn<0) p->wpn=10; }while(!(p->wpns&(1<<p->wpn)));
142 p->cwpn=3;
143 }else if(I_pressed(p->kwr)) {
144 do{ if(++p->wpn>10) p->wpn=0; }while(!(p->wpns&(1<<p->wpn)));
145 p->cwpn=3;
147 if(p->cwpn) {
148 p->drawst|=PL_DRAWWPN;p->fire=0;
149 if(p->wpn==1) Z_sound(snd[6],128);
153 static void jump(player_t *p,int st) {
154 if(Z_canbreathe(p->o.x,p->o.y,p->o.r,p->o.h)) {
155 if(p->air<PL_AIR) {p->air=PL_AIR;p->drawst|=PL_DRAWAIR;}
156 }else {
157 if(--p->air < -9) {
158 p->air=0;
159 PL_hit(p,10,-3,HIT_WATER);
160 }else if((p->air&31)==0) {
161 FX_bubble(p->o.x,p->o.y-20,0,0,5);
163 p->drawst|=PL_DRAWAIR;
165 if(I_pressed(p->kj)) {
166 if(p_fly) {
167 p->o.yv=-PL_FLYUP;
168 }else{
169 if(Z_canstand(p->o.x,p->o.y,p->o.r)) p->o.yv=-PL_JUMP;
170 else if(st&Z_INWATER) p->o.yv=-PL_SWUP;
175 int PL_isdead (player_t *p) {
176 switch(p->st) {
177 case DEAD: case MESS:
178 case OUT:
179 return 1;
181 return 0;
184 void PL_init (void) {
185 pl1.id = -1;
186 pl2.id = -2;
187 p_immortal = 0;
188 PL_JUMP = 10;
189 PL_RUN = 8;
190 aitime = 0;
193 void PL_alloc(void) {
194 int i,j;
195 static char nm[][6]={
196 "OOF",
197 "PLPAIN",
198 "PLDETH",
199 "SLOP",
200 "PDIEHI",
201 "BFG",
202 "SAWUP",
203 "SAWIDL",
204 "SAWFUL",
205 "SAWHIT",
206 "PLFALL"
207 };
208 char s[6];
209 for(i=0;i<11;++i) snd[i]=Z_getsnd(nm[i]);
210 memcpy(s,"AIx",4);
211 for(i=0;i<3;++i) {
212 s[2]=i+'1';
213 aisnd[i]=Z_getsnd(s);
215 memcpy(s,"PLDTHx",6);
216 for(i=0;i<5;++i) {
217 s[5]=i+'1';
218 pdsnd[i]=Z_getsnd(s);
222 static void PL_restore(player_t *p) {
223 p->o.xv=p->o.yv=p->o.vx=p->o.vy=0;
224 p->o.r=PL_RAD;p->o.h=PL_HT;
225 p->pain=0;
226 p->invl=p->suit=0;
227 switch(p->st) {
228 case DEAD: case MESS: case OUT:
229 case DIE: case SLOP: case FALL:
230 p->life=100;p->armor=0;p->air=PL_AIR;
231 p->wpns=5;
232 p->wpn=2;
233 p->ammo=50;p->fuel=p->shel=p->rock=p->cell=0;
234 p->amul=1;
236 p->st=STAND;
237 p->fire=p->cwpn=p->csnd=0;
238 p->f=0;
239 p->drawst=0xFF;
240 p->looky=0;
241 p->keys=(g_dm)?0x70:0;
244 void PL_reset (void) {
245 pl1.st=pl2.st=DEAD;
246 pl1.frag=pl2.frag=0;
249 void PL_spawn (player_t *p,int x,int y,char d) {
250 PL_restore(p);
251 p->o.x=x;p->o.y=y;p->d=d;
252 p->kills=p->secrets=0;
255 int PL_hit (player_t *p,int d,int o,int t) {
256 if(!d) return 0;
257 switch(p->st) {
258 case DIE: case SLOP:
259 case DEAD: case MESS:
260 case OUT: case FALL:
261 return 0;
263 if(t==HIT_TRAP) {if(!p_immortal) {p->armor=0;p->life=-100;}}
264 else if(t!=HIT_ROCKET && t!=HIT_ELECTRO) {
265 if(p->id==-1) {if(o==-1) return 0;}
266 else if(o==-2) return 0;
268 if(t!=HIT_WATER && t!=HIT_ELECTRO)
269 DOT_blood(p->o.x,p->o.y-15,hit_xv,hit_yv,d*2);
270 else if(t==HIT_WATER) FX_bubble(p->o.x,p->o.y-20,0,0,d/2);
271 if(p_immortal || p->invl) return 1;
272 p->hit+=d;
273 p->hito=o;
274 return 1;
277 void PL_damage (player_t *p) {
278 int i;
280 if(!p->hit && p->life>0) return;
281 switch(p->st) {
282 case DIE: case SLOP:
283 case DEAD: case MESS:
284 case OUT: case FALL:
285 return;
287 i=p->hit*p->life/nonz(p->armor*3/4+p->life);
288 p->pain+=p->hit;
289 p->drawst|=PL_DRAWLIFE|PL_DRAWARMOR;
290 if((p->armor-=p->hit-i)<0) {p->life+=p->armor;p->armor=0;}
291 if((p->life-=i)<=0) {
292 if(p->life>-30) {p->st=DIE;p->s=0;Z_sound(pdsnd[rand()%5],128);}
293 else {p->st=SLOP;p->s=0;Z_sound(snd[3],128);}
294 if(p->amul>1) IT_spawn(p->o.x,p->o.y,I_BPACK);
295 if(!g_dm) {
296 if(p->keys&16) IT_spawn(p->o.x,p->o.y,I_KEYR);
297 if(p->keys&32) IT_spawn(p->o.x,p->o.y,I_KEYG);
298 if(p->keys&64) IT_spawn(p->o.x,p->o.y,I_KEYB);
300 for(i=1,p->wpns>>=1;i<11;++i,p->wpns>>=1)
301 if(i!=2) if(p->wpns&1) IT_spawn(p->o.x,p->o.y,wp_it[i]);
302 p->wpns=5;p->wpn=2;
303 p->f|=PLF_PNSND;
304 p->drawst|=PL_DRAWWPN;
305 if(g_dm && _2pl) {
306 if(p->id==-1) {
307 if(p->hito==-2) {++pl2.kills;++pl2.frag;}
308 else if(p->hito==-1) --pl1.frag;
309 }else{
310 if(p->hito==-1) {++pl1.kills;++pl1.frag;}
311 else if(p->hito==-2) --pl2.frag;
313 pl1.drawst|=PL_DRAWFRAG;
314 if(_2pl) pl2.drawst|=PL_DRAWFRAG;
316 p->life=0;return;
318 return;
321 void PL_cry (player_t *p) {
322 Z_sound(snd[(p->pain>20)?1:0],128);
323 p->f|=PLF_PNSND;
326 int PL_give (player_t *p, int t) {
327 int i;
329 switch(p->st) {
330 case DIE: case SLOP:
331 case DEAD: case MESS: case OUT:
332 return 0;
334 switch(t) {
335 case I_STIM: case I_MEDI:
336 if(p->life>=100) return 0;
337 if((p->life+=((t==I_MEDI)?25:10))>100) p->life=100;
338 p->drawst|=PL_DRAWLIFE;return 1;
339 case I_CLIP:
340 if(p->ammo>=200*p->amul) return 0;
341 if((p->ammo+=10)>200*p->amul) p->ammo=200*p->amul;
342 p->drawst|=PL_DRAWWPN;return 1;
343 case I_AMMO:
344 if(p->ammo>=200*p->amul) return 0;
345 if((p->ammo+=50)>200*p->amul) p->ammo=200*p->amul;
346 p->drawst|=PL_DRAWWPN;return 1;
347 case I_SHEL:
348 if(p->shel>=50*p->amul) return 0;
349 if((p->shel+=4)>50*p->amul) p->shel=50*p->amul;
350 p->drawst|=PL_DRAWWPN;return 1;
351 case I_SBOX:
352 if(p->shel>=50*p->amul) return 0;
353 if((p->shel+=25)>50*p->amul) p->shel=50*p->amul;
354 p->drawst|=PL_DRAWWPN;return 1;
355 case I_ROCKET:
356 if(p->rock>=50*p->amul) return 0;
357 if((++p->rock)>50*p->amul) p->rock=50*p->amul;
358 p->drawst|=PL_DRAWWPN;return 1;
359 case I_RBOX:
360 if(p->rock>=50*p->amul) return 0;
361 if((p->rock+=5)>50*p->amul) p->rock=50*p->amul;
362 p->drawst|=PL_DRAWWPN;return 1;
363 case I_CELL:
364 if(p->cell>=300*p->amul) return 0;
365 if((p->cell+=40)>300*p->amul) p->cell=300*p->amul;
366 p->drawst|=PL_DRAWWPN;return 1;
367 case I_CELP:
368 if(p->cell>=300*p->amul) return 0;
369 if((p->cell+=100)>300*p->amul) p->cell=300*p->amul;
370 p->drawst|=PL_DRAWWPN;return 1;
371 case I_BPACK:
372 if(p->amul==1) {p->amul=2;i=1;} else i=0;
373 i|=PL_give(p,I_CLIP);
374 i|=PL_give(p,I_SHEL);
375 i|=PL_give(p,I_ROCKET);
376 i|=PL_give(p,I_CELL);
377 return i;
378 case I_CSAW:
379 if(!(p->wpns&2)) {p->wpns|=2;p->drawst|=PL_DRAWWPN;return 1;}
380 return 0;
381 case I_GUN2:
382 i=PL_give(p,I_SHEL);
383 if(!(p->wpns&512)) {p->wpns|=512;i=1;}
384 p->drawst|=PL_DRAWWPN;return i;
385 case I_SGUN:
386 i=PL_give(p,I_SHEL);
387 if(!(p->wpns&8)) {p->wpns|=8;i=1;}
388 p->drawst|=PL_DRAWWPN;return i;
389 case I_SGUN2:
390 i=PL_give(p,I_SHEL);
391 if(!(p->wpns&16)) {p->wpns|=16;i=1;}
392 p->drawst|=PL_DRAWWPN;return i;
393 case I_MGUN:
394 i=PL_give(p,I_AMMO);
395 if(!(p->wpns&32)) {p->wpns|=32;i=1;}
396 p->drawst|=PL_DRAWWPN;return i;
397 case I_LAUN:
398 i=PL_give(p,I_ROCKET);
399 i|=PL_give(p,I_ROCKET);
400 if(!(p->wpns&64)) {p->wpns|=64;i=1;}
401 p->drawst|=PL_DRAWWPN;return i;
402 case I_PLAS:
403 i=PL_give(p,I_CELL);
404 if(!(p->wpns&128)) {p->wpns|=128;i=1;}
405 p->drawst|=PL_DRAWWPN;return i;
406 case I_BFG:
407 i=PL_give(p,I_CELL);
408 if(!(p->wpns&256)) {p->wpns|=256;i=1;}
409 p->drawst|=PL_DRAWWPN;return i;
410 case I_ARM1:
411 if(p->armor>=100) return 0;
412 p->armor=100;p->drawst|=PL_DRAWARMOR;return 1;
413 case I_ARM2:
414 if(p->armor>=200) return 0;
415 p->armor=200;p->drawst|=PL_DRAWARMOR;return 1;
416 case I_MEGA:
417 i=0;
418 if(p->life<200) {p->life=200;p->drawst|=PL_DRAWLIFE;i=1;}
419 if(p->armor<200) {p->armor=200;p->drawst|=PL_DRAWARMOR;i=1;}
420 return i;
421 case I_SUPER:
422 if(p->life<200) {p->life=min(p->life+100,200);p->drawst|=PL_DRAWLIFE;return 1;}
423 return 0;
424 case I_INVL:
425 p->invl=PL_POWERUP_TIME;
426 return 1;
427 case I_SUIT:
428 p->suit=PL_POWERUP_TIME;
429 return 1;
430 case I_AQUA:
431 if(p->air >= PL_AQUA_AIR) return 0;
432 p->air=PL_AQUA_AIR;p->drawst|=PL_DRAWAIR;
433 return 1;
434 case I_KEYR:
435 if(p->keys&16) return 0;
436 p->keys|=16;p->drawst|=PL_DRAWKEYS;return 1;
437 case I_KEYG:
438 if(p->keys&32) return 0;
439 p->keys|=32;p->drawst|=PL_DRAWKEYS;return 1;
440 case I_KEYB:
441 if(p->keys&64) return 0;
442 p->keys|=64;p->drawst|=PL_DRAWKEYS;return 1;
443 default:
444 return 0;
448 void PL_act (player_t *p) {
449 int st;
451 if(--aitime<0) aitime=0;
452 SW_press(p->o.x,p->o.y,p->o.r,p->o.h,4|p->keys,p->id);
453 if(!p->suit) if((g_time&15)==0)
454 PL_hit(p,Z_getacid(p->o.x,p->o.y,p->o.r,p->o.h),-3,HIT_SOME);
455 if(p->st!=FALL && p->st!=OUT) {
456 if(((st=Z_moveobj(&p->o))&Z_FALLOUT) && p->o.y>=FLDH*CELH+50) {
457 switch(p->st) {
458 case DEAD: case MESS: case DIE: case SLOP:
459 p->s=5;break;
460 default:
461 p->s=Z_sound(snd[10],128);
462 if(g_dm) --p->frag;
463 }p->st=FALL;
465 }else st=0;
466 if(st&Z_HITWATER) Z_splash(&p->o,PL_RAD+PL_HT);
467 if(p->f&PLF_FIRE) if(p->fire!=2) p->f-=PLF_FIRE;
468 if(I_pressed(p->ku)) {p->f|=PLF_UP;p->looky-=5;}
469 else{
470 p->f&=0xFFFF-PLF_UP;
471 if(I_pressed(p->kd))
472 {p->f|=PLF_DOWN;p->looky+=5;}
473 else {p->f&=0xFFFF-PLF_DOWN;p->looky=Z_dec(p->looky,5);}
475 if(I_pressed(p->kp)) SW_press(p->o.x,p->o.y,p->o.r,p->o.h,1|p->keys,p->id);
476 if(p->fire) --p->fire;
477 if(p->cwpn) --p->cwpn;
478 if(p->csnd) --p->csnd;
479 if(p->invl) --p->invl;
480 if(p->suit) --p->suit;
481 switch(p->st) {
482 case DIE:
483 p->o.h=7;
484 if(!plr_dieanim[++p->s]) {p->st=DEAD;MN_killedp();}
485 p->o.xv=Z_dec(p->o.xv,1);
486 break;
487 case SLOP:
488 p->o.h=6;
489 if(!plr_slopanim[++p->s]) {p->st=MESS;MN_killedp();}
490 p->o.xv=Z_dec(p->o.xv,1);
491 break;
492 case GO:
493 chgwpn(p);fire(p);jump(p,st);
494 if(p_fly)
495 SMK_gas(p->o.x,p->o.y-2,2,3,p->o.xv+p->o.vx,p->o.yv+p->o.vy,128);
496 if((p->s+=abs(p->o.xv)/2) >= 24) p->s%=24;
497 if(!I_pressed(p->kl) && !I_pressed(p->kr)) {
498 if(p->o.xv) p->o.xv=Z_dec(p->o.xv,1);
499 else p->st=STAND;
500 break;
502 if(p->o.xv<PL_RUN && I_pressed(p->kr)) {p->o.xv+=PL_RUN>>3;p->d=1;}
503 else if(PL_RUN>8)
504 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 if(p->o.xv>-PL_RUN && I_pressed(p->kl)) {p->o.xv-=PL_RUN>>3;p->d=0;}
506 else if(PL_RUN>8)
507 SMK_gas(p->o.x,p->o.y-2,2,3,p->o.xv+p->o.vx,p->o.yv+p->o.vy,32);
508 break;
509 case STAND:
510 chgwpn(p);fire(p);jump(p,st);
511 if(p_fly)
512 SMK_gas(p->o.x,p->o.y-2,2,3,p->o.xv+p->o.vx,p->o.yv+p->o.vy,128);
513 if(I_pressed(p->kl)) {p->st=GO;p->s=0;p->d=0;}
514 else if(I_pressed(p->kr)) {p->st=GO;p->s=0;p->d=1;}
515 break;
516 case DEAD:
517 case MESS:
518 case OUT:
519 p->o.xv=Z_dec(p->o.xv,1);
520 if(I_pressed(p->ku) || I_pressed(p->kd) || I_pressed(p->kl) || I_pressed(p->kr) ||
521 I_pressed(p->kf) || I_pressed(p->kj) || I_pressed(p->kp) || I_pressed(p->kwl) || I_pressed(p->kwr)) {
522 if(p->st!=OUT) MN_spawn_deadpl(&p->o,p->color,(p->st==MESS)?1:0);
523 PL_restore(p);
524 if(g_dm) {G_respawn_player(p);break;}
525 if(!_2pl) {
526 if(--p->lives==0) {G_start();break;}
527 else{p->o.x=dm_pos[0].x;p->o.y=dm_pos[0].y;p->d=dm_pos[0].d;}
528 p->drawst|=PL_DRAWLIVES;
530 if(p->id==-1)
531 {p->o.x=dm_pos[0].x;p->o.y=dm_pos[0].y;p->d=dm_pos[0].d;}
532 else {p->o.x=dm_pos[1].x;p->o.y=dm_pos[1].y;p->d=dm_pos[1].d;}
533 }break;
534 case FALL:
535 if(--p->s<=0) p->st=OUT;
536 break;
540 static void chk_bfg(player_t *p,int x,int y) {
541 int dx,dy;
543 if(aitime) return;
544 switch(p->st) {
545 case DIE: case SLOP: case FALL:
546 case DEAD: case MESS: case OUT:
547 return;
549 dx=p->o.x-x;dy=p->o.y-p->o.h/2-y;
550 if(dx*dx+dy*dy<=1600) {
551 aitime=Z_sound(aisnd[rand()%3],128)*4;
555 void bfg_fly (int x,int y,int o) {
556 // if(!g_dm) return;
557 if(o!=-1) chk_bfg(&pl1,x,y);
558 if(_2pl) if(o!=-2) chk_bfg(&pl2,x,y);
559 if(o==-1 || o==-2) MN_warning(x-50,y-50,x+50,y+50);