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 }