doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

p_inter.c (13454B)


      1 #include "doomdef.h"
      2 #include "dstrings.h"
      3 #include "sounds.h"
      4 #include "doomstat.h"
      5 #include "m_random.h"
      6 #include "i_system.h"
      7 #include "am_map.h"
      8 #include "p_local.h"
      9 #include "s_sound.h"
     10 #include "p_inter.h"
     11 
     12 #define BONUSADD	6
     13 
     14 int	maxammo[NUMAMMO] = {200, 50, 300, 50};
     15 int	clipammo[NUMAMMO] = {10, 4, 20, 1};
     16 
     17 boolean
     18 P_GiveAmmo(player_t* player, ammotype_t ammo, int num)
     19 {
     20 	int oldammo;
     21 	if (ammo == am_noammo) return false;
     22 	if (ammo < 0 || ammo > NUMAMMO) I_Error("P_GiveAmmo: bad type %i", ammo);
     23 	if (player->ammo[ammo] == player->maxammo[ammo]) return false;
     24 	if (num) num *= clipammo[ammo];
     25 	else num = clipammo[ammo]/2;
     26 	if (gameskill == sk_baby || gameskill == sk_nightmare) num <<= 1;
     27 	oldammo = player->ammo[ammo];
     28 	player->ammo[ammo] += num;
     29 	if (player->ammo[ammo] > player->maxammo[ammo]) player->ammo[ammo] = player->maxammo[ammo];
     30 	if (oldammo) return true;
     31 	switch(ammo) {
     32 		case am_clip:
     33 			if (player->readyweapon == wp_fist) {
     34 				if (player->weaponowned[wp_chaingun]) player->pendingweapon = wp_chaingun;
     35 				else player->pendingweapon = wp_pistol;
     36 			}
     37 			break;
     38 		case am_shell:
     39 			if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
     40 				if (player->weaponowned[wp_shotgun]) player->pendingweapon = wp_shotgun;
     41 			break;
     42 		case am_cell:
     43 			if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
     44 				if (player->weaponowned[wp_plasma])
     45 					player->pendingweapon = wp_plasma;
     46 			break;
     47 		case am_misl:
     48 			if (player->readyweapon == wp_fist)
     49 				if (player->weaponowned[wp_missile])
     50 					player->pendingweapon = wp_missile;
     51 		default:
     52 			break;
     53 	}
     54 	return true;
     55 }
     56 
     57 boolean
     58 P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped)
     59 {
     60 	boolean	gaveammo;
     61 	boolean	gaveweapon;
     62 
     63 	if (netgame && (deathmatch!=2) && !dropped) {
     64 		if (player->weaponowned[weapon]) return false;
     65 		player->bonuscount += BONUSADD;
     66 		player->weaponowned[weapon] = true;
     67 		if (deathmatch) P_GiveAmmo(player, weaponinfo[weapon].ammo, 5);
     68 		else P_GiveAmmo(player, weaponinfo[weapon].ammo, 2);
     69 		player->pendingweapon = weapon;
     70 		if (player == &players[consoleplayer]) S_StartSound(NULL, sfx_wpnup);
     71 		return false;
     72 	}
     73 	if (weaponinfo[weapon].ammo != am_noammo) {
     74 		if (dropped) gaveammo = P_GiveAmmo(player, weaponinfo[weapon].ammo, 1);
     75 		else gaveammo = P_GiveAmmo(player, weaponinfo[weapon].ammo, 2);
     76 	} else gaveammo = false;
     77 	if (player->weaponowned[weapon]) gaveweapon = false;
     78 	else {
     79 		gaveweapon = true;
     80 		player->weaponowned[weapon] = true;
     81 		player->pendingweapon = weapon;
     82 	}
     83 	return(gaveweapon || gaveammo);
     84 }
     85 
     86 boolean
     87 P_GiveBody(player_t* player, int num)
     88 {
     89 	if (player->health >= MAXHEALTH) return false;
     90 	player->health += num;
     91 	if (player->health > MAXHEALTH) player->health = MAXHEALTH;
     92 	player->mo->health = player->health;
     93 	return true;
     94 }
     95 
     96 boolean
     97 P_GiveArmor(player_t* player, int armortype)
     98 {
     99 	int hits;
    100 
    101 	hits = armortype * 100;
    102 	if (player->armorpoints >= hits) return false;
    103 	player->armortype = armortype;
    104 	player->armorpoints = hits;
    105 	return true;
    106 }
    107 
    108 void
    109 P_GiveCard(player_t* player, card_t card)
    110 {
    111 	if (player->cards[card]) return;
    112 	player->bonuscount = BONUSADD;
    113 	player->cards[card] = 1;
    114 }
    115 
    116 boolean
    117 P_GivePower(player_t* player, int power)
    118 {
    119 	if (power == pw_invulnerability) {
    120 		player->powers[power] = INVULNTICS;
    121 		return true;
    122 	}
    123 	if (power == pw_invisibility) {
    124 		player->powers[power] = INVISTICS;
    125 		player->mo->flags |= MF_SHADOW;
    126 		return true;
    127 	}
    128 	if (power == pw_infrared) {
    129 		player->powers[power] = INFRATICS;
    130 		return true;
    131 	}
    132 	if (power == pw_ironfeet) {
    133 		player->powers[power] = IRONTICS;
    134 		return true;
    135 	}
    136 	if (power == pw_strength) {
    137 		P_GiveBody(player, 100);
    138 		player->powers[power] = 1;
    139 		return true;
    140 	}
    141 	if (player->powers[power]) return false;
    142 	player->powers[power] = 1;
    143 	return true;
    144 }
    145 
    146 void
    147 P_TouchSpecialThing(mobj_t* special, mobj_t* toucher)
    148 {
    149 	player_t* player;
    150 	int       i, sound;
    151 	fixed_t   delta;
    152 
    153 	delta = special->z - toucher->z;
    154 	if (delta > toucher->height || delta < -8*FRACUNIT) return;
    155 	sound = sfx_itemup;
    156 	player = toucher->player;
    157 	if (toucher->health <= 0) return;
    158 	switch(special->sprite) {
    159 		case SPR_ARM1:
    160 			if (!P_GiveArmor(player, 1)) return;
    161 			player->message = lang[GOTARMOR];
    162 			break;
    163 		case SPR_ARM2:
    164 			if (!P_GiveArmor(player, 2)) return;
    165 			player->message = lang[GOTMEGA];
    166 			break;
    167 		case SPR_BON1:
    168 			player->health++;	
    169 			if (player->health > 200) player->health = 200;
    170 			player->mo->health = player->health;
    171 			player->message = lang[GOTHTHBONUS];
    172 			break;
    173 		case SPR_BON2:
    174 			player->armorpoints++;	
    175 			if (player->armorpoints > 200) player->armorpoints = 200;
    176 			if (!player->armortype) player->armortype = 1;
    177 			player->message = lang[GOTARMBONUS];
    178 			break;
    179 		case SPR_SOUL:
    180 			player->health += 100;
    181 			if (player->health > 200) player->health = 200;
    182 			player->mo->health = player->health;
    183 			player->message = lang[GOTSUPER];
    184 			sound = sfx_getpow;
    185 			break;
    186 		case SPR_MEGA:
    187 			player->health = 200;
    188 			player->mo->health = player->health;
    189 			P_GiveArmor(player, 2);
    190 			player->message = lang[GOTMSPHERE];
    191 			sound = sfx_getpow;
    192 			break;
    193 		case SPR_BKEY:
    194 			if (!player->cards[it_bluecard]) player->message = lang[GOTBLUECARD];
    195 			P_GiveCard(player, it_bluecard);
    196 			if (!netgame) break;
    197 			return;
    198 		case SPR_YKEY:
    199 			if (!player->cards[it_yellowcard]) player->message = lang[GOTYELWCARD];
    200 			P_GiveCard(player, it_yellowcard);
    201 			if (!netgame) break;
    202 			return;
    203 		case SPR_RKEY:
    204 			if (!player->cards[it_redcard]) player->message = lang[GOTREDCARD];
    205 			P_GiveCard(player, it_redcard);
    206 			if (!netgame) break;
    207 			return;
    208 		case SPR_BSKU:
    209 			if (!player->cards[it_blueskull]) player->message = lang[GOTBLUESKUL];
    210 			P_GiveCard(player, it_blueskull);
    211 			if (!netgame) break;
    212 			return;
    213 		case SPR_YSKU:
    214 			if (!player->cards[it_yellowskull]) player->message = lang[GOTYELWSKUL];
    215 			P_GiveCard(player, it_yellowskull);
    216 			if (!netgame) break;
    217 			return;
    218 		case SPR_RSKU:
    219 			if (!player->cards[it_redskull]) player->message = lang[GOTREDSKULL];
    220 			P_GiveCard(player, it_redskull);
    221 			if (!netgame) break;
    222 			return;
    223 		case SPR_STIM:
    224 			if (!P_GiveBody(player, 10)) return;
    225 			player->message = lang[GOTSTIM];
    226 			break;
    227 		case SPR_MEDI:
    228 			if (!P_GiveBody(player, 25)) return;
    229 			if (player->health < 25) player->message = lang[GOTMEDINEED];
    230 			else player->message = lang[GOTMEDIKIT];
    231 			break;
    232 		case SPR_PINV:
    233 			if (!P_GivePower(player, pw_invulnerability)) return;
    234 			player->message = lang[GOTINVUL];
    235 			sound = sfx_getpow;
    236 			break;
    237 		case SPR_PSTR:
    238 			if (!P_GivePower(player, pw_strength)) return;
    239 			player->message = lang[GOTBERSERK];
    240 			if (player->readyweapon != wp_fist) player->pendingweapon = wp_fist;
    241 			sound = sfx_getpow;
    242 			break;
    243 		case SPR_PINS:
    244 			if (!P_GivePower(player, pw_invisibility)) return;
    245 			player->message = lang[GOTINVIS];
    246 			sound = sfx_getpow;
    247 			break;
    248 		case SPR_SUIT:
    249 			if (!P_GivePower(player, pw_ironfeet)) return;
    250 			player->message = lang[GOTSUIT];
    251 			sound = sfx_getpow;
    252 			break;
    253 		case SPR_PMAP:
    254 			if (!P_GivePower(player, pw_allmap)) return;
    255 			player->message = lang[GOTMAP];
    256 			sound = sfx_getpow;
    257 			break;
    258 		case SPR_PVIS:
    259 			if (!P_GivePower(player, pw_infrared)) return;
    260 			player->message = lang[GOTVISOR];
    261 			sound = sfx_getpow;
    262 			break;
    263 		case SPR_CLIP:
    264 			if (special->flags & MF_DROPPED) {
    265 				if (!P_GiveAmmo(player, am_clip, 0)) return;
    266 			}
    267 			else
    268 				if (!P_GiveAmmo(player, am_clip, 1))
    269 					return;
    270 			player->message = lang[GOTCLIP];
    271 			break;
    272 		case SPR_AMMO:
    273 			if (!P_GiveAmmo(player, am_clip, 5)) return;
    274 			player->message = lang[GOTCLIPBOX];
    275 			break;
    276 		case SPR_ROCK:
    277 			if (!P_GiveAmmo(player, am_misl, 1)) return;
    278 			player->message = lang[GOTROCKET];
    279 			break;
    280 		case SPR_BROK:
    281 			if (!P_GiveAmmo(player, am_misl, 5)) return;
    282 			player->message = lang[GOTROCKBOX];
    283 			break;
    284 		case SPR_CELL:
    285 			if (!P_GiveAmmo(player, am_cell, 1)) return;
    286 			player->message = lang[GOTCELL];
    287 			break;
    288 		case SPR_CELP:
    289 			if (!P_GiveAmmo(player, am_cell, 5)) return;
    290 			player->message = lang[GOTCELLBOX];
    291 			break;
    292 		case SPR_SHEL:
    293 			if (!P_GiveAmmo(player, am_shell, 1)) return;
    294 			player->message = lang[GOTSHELLS];
    295 			break;
    296 		case SPR_SBOX:
    297 			if (!P_GiveAmmo(player, am_shell, 5)) return;
    298 			player->message = lang[GOTSHELLBOX];
    299 			break;
    300 		case SPR_BPAK:
    301 			if (!player->backpack) {
    302 				for (i=0 ; i<NUMAMMO ; i++) player->maxammo[i] *= 2;
    303 				player->backpack = true;
    304 			}
    305 			for (i=0 ; i<NUMAMMO ; i++) P_GiveAmmo(player, i, 1);
    306 			player->message = lang[GOTBACKPACK];
    307 			break;
    308 		case SPR_BFUG:
    309 			if (!P_GiveWeapon(player, wp_bfg, false)) return;
    310 			player->message = lang[GOTBFG9000];
    311 			sound = sfx_wpnup;
    312 			break;
    313 		case SPR_MGUN:
    314 			if (!P_GiveWeapon(player, wp_chaingun, special->flags&MF_DROPPED)) return;
    315 			player->message = lang[GOTCHAINGUN];
    316 			sound = sfx_wpnup;
    317 			break;
    318 		case SPR_CSAW:
    319 			if (!P_GiveWeapon(player, wp_chainsaw, false)) return;
    320 			player->message = lang[GOTCHAINSAW];
    321 			sound = sfx_wpnup;
    322 			break;
    323 		case SPR_LAUN:
    324 			if (!P_GiveWeapon(player, wp_missile, false)) return;
    325 			player->message = lang[GOTLAUNCHER];
    326 			sound = sfx_wpnup;
    327 			break;
    328 		case SPR_PLAS:
    329 			if (!P_GiveWeapon(player, wp_plasma, false)) return;
    330 			player->message = lang[GOTPLASMA];
    331 			sound = sfx_wpnup;
    332 			break;
    333 		case SPR_SHOT:
    334 			if (!P_GiveWeapon(player, wp_shotgun, special->flags&MF_DROPPED)) return;
    335 			player->message = lang[GOTSHOTGUN];
    336 			sound = sfx_wpnup;
    337 			break;
    338 		case SPR_SGN2:
    339 			if (!P_GiveWeapon(player, wp_supershotgun, special->flags&MF_DROPPED)) return;
    340 			player->message = lang[GOTSHOTGUN2];
    341 			sound = sfx_wpnup;
    342 			break;
    343 		default:
    344 			I_Error("P_SpecialThing: Unknown gettable thing");
    345 	}
    346 	if (special->flags & MF_COUNTITEM) player->itemcount++;
    347 	P_RemoveMobj(special);
    348 	player->bonuscount += BONUSADD;
    349 	if (player == &players[consoleplayer]) S_StartSound(NULL, sound);
    350 }
    351 
    352 void
    353 P_KillMobj(mobj_t* source, mobj_t* target)
    354 {
    355 	mobjtype_t item;
    356 	mobj_t*    mo;
    357 
    358 	target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
    359 	if (target->type != MT_SKULL) target->flags &= ~MF_NOGRAVITY;
    360 	target->flags |= MF_CORPSE|MF_DROPOFF;
    361 	target->height >>= 2;
    362 	if (source && source->player)    {
    363 		if (target->flags & MF_COUNTKILL) source->player->killcount++;
    364 		if (target->player) source->player->frags[target->player-players]++;
    365 	}
    366 	else if (!netgame && (target->flags & MF_COUNTKILL)) players[0].killcount++;
    367 	if (target->player) {
    368 		if (!source) target->player->frags[target->player-players]++;
    369 		target->flags &= ~MF_SOLID;
    370 		target->player->playerstate = PST_DEAD;
    371 		P_DropWeapon(target->player);
    372 		if (target->player == &players[consoleplayer] && automapactive) AM_Stop();
    373 	}
    374 	if (target->health < -target->info->spawnhealth && target->info->xdeathstate) P_SetMobjState(target, target->info->xdeathstate);
    375 	else P_SetMobjState(target, target->info->deathstate);
    376 	target->tics -= P_Random()&3;
    377 	if (target->tics < 1)
    378 	target->tics = 1;
    379 	switch(target->type) {
    380 		case MT_WOLFSS:
    381 		case MT_POSSESSED:
    382 			item = MT_CLIP;
    383 			break;
    384 		case MT_SHOTGUY:
    385 			item = MT_SHOTGUN;
    386 			break;
    387 		case MT_CHAINGUY:
    388 			item = MT_CHAINGUN;
    389 			break;
    390 		default:
    391 			return;
    392 	}
    393 	mo = P_SpawnMobj(target->x, target->y, ONFLOORZ, item);
    394 	mo->flags |= MF_DROPPED;
    395 }
    396 
    397 void
    398 P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage)
    399 {
    400 	unsigned  ang;
    401 	int       saved;
    402 	player_t* player;
    403 	fixed_t   thrust;
    404 
    405 	if ( !(target->flags & MF_SHOOTABLE)) return;
    406 	if (target->health <= 0) return;
    407 	if ( target->flags & MF_SKULLFLY) target->momx = target->momy = target->momz = 0;
    408 	player = target->player;
    409 	if (player && gameskill == sk_baby) damage >>= 1; 
    410 	if (inflictor && !(target->flags & MF_NOCLIP) && (!source || !source->player || source->player->readyweapon != wp_chainsaw)) {
    411 		ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y);
    412 		thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
    413 		if (damage < 40 && damage > target->health && target->z - inflictor->z > 64*FRACUNIT && (P_Random()&1)) {
    414 			ang += ANG180;
    415 			thrust *= 4;
    416 		}
    417 		ang >>= ANGLETOFINESHIFT;
    418 		target->momx += FixedMul(thrust, finecosine[ang]);
    419 		target->momy += FixedMul(thrust, finesine[ang]);
    420 	}
    421 	if (player) {
    422 		return;
    423 		if (target->subsector->sector->special == 11 && damage >= target->health)
    424 			damage = target->health - 1;
    425 		if (damage < 1000 && ((player->cheats&CF_GODMODE) || player->powers[pw_invulnerability]))
    426 			return;
    427 		if (player->armortype) {
    428 			if (player->armortype == 1) saved = damage/3;
    429 			else saved = damage/2;
    430 			if (player->armorpoints <= saved) {
    431 				saved = player->armorpoints;
    432 				player->armortype = 0;
    433 			}
    434 			player->armorpoints -= saved;
    435 			damage -= saved;
    436 		}
    437 		player->health -= damage; 
    438 		if (player->health < 0) player->health = 0;
    439 		player->attacker = source;
    440 		player->damagecount += damage;
    441 		if (player->damagecount > 100)
    442 			player->damagecount = 100;
    443 		}
    444 		target->health -= damage;
    445 		if (target->health <= 0) {
    446 			P_KillMobj(source, target);
    447 		return;
    448 	}
    449 	if ((P_Random() < target->info->painchance) && !(target->flags&MF_SKULLFLY)) {
    450 		target->flags |= MF_JUSTHIT;
    451 		P_SetMobjState(target, target->info->painstate);
    452 	}
    453 	target->reactiontime = 0;	
    454 	if ((!target->threshold || target->type == MT_VILE) && source && source != target && source->type != MT_VILE) {
    455 		target->target = source;
    456 		target->threshold = BASETHRESHOLD;
    457 		if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_NULL)
    458 		P_SetMobjState(target, target->info->seestate);
    459 	}
    460 }