static int numAmmoClipsToGiveWithWeapon(dd_bool dropped) { // Dropped weapons only ever give one clip. if(dropped) return 1; // Give extra clips in deathmatch. return (IS_NETGAME && G_Ruleset_Deathmatch() == 1)? 5 : 2; }
static dd_bool giveOneWeapon(player_t *plr, weapontype_t weaponType, dd_bool dropped) { int numClips = numAmmoClipsToGiveWithWeapon(dropped); dd_bool gaveAmmo = false, gaveWeapon = false; weaponinfo_t const *wpnInfo; ammotype_t i; DENG_ASSERT(plr != 0); DENG_ASSERT(weaponType >= WT_FIRST && weaponType < NUM_WEAPON_TYPES); wpnInfo = &weaponInfo[weaponType][plr->class_]; // Do not give weapons unavailable for the current mode. if(!(wpnInfo->mode[0].gameModeBits & gameModeBits)) return false; // Give some of each of the ammo types used by this weapon. for(i = 0; i < NUM_AMMO_TYPES; ++i) { // Is this ammo type usable?. if(!wpnInfo->mode[0].ammoType[i]) continue; if(P_GiveAmmo(plr, i, numClips)) { gaveAmmo = true; } } if(!plr->weapons[weaponType].owned) { gaveWeapon = true; plr->weapons[weaponType].owned = true; plr->update |= PSF_OWNED_WEAPONS; // Animate a pickup bonus flash? if(IS_NETGAME && G_Ruleset_Deathmatch() != 2 && !dropped) { plr->bonusCount += BONUSADD; } // Given the new weapon the player may want to change automatically. P_MaybeChangeWeapon(plr, weaponType, AT_NOAMMO, shouldForceWeaponChange(dropped)); // Maybe unhide the HUD? ST_HUDUnHide(plr - players, HUE_ON_PICKUP_WEAPON); } return (gaveWeapon || gaveAmmo); }
/** * Attempt to pickup the found weapon type. * * @param plr Player to attempt the pickup. * @param weaponType Weapon type to pickup. * @param dropped @c true= the weapon was dropped by someone. * @param pickupMessage Message to display if picked up. * * @return @c true if the player picked up the weapon. */ static dd_bool pickupWeapon(player_t *plr, weapontype_t weaponType, dd_bool dropped, char const *pickupMessage) { dd_bool pickedWeapon; DENG_ASSERT(plr != 0); DENG_ASSERT(weaponType >= WT_FIRST && weaponType < NUM_WEAPON_TYPES); // Depending on the game rules the player should ignore the weapon. if(plr->weapons[weaponType].owned) { // Leave placed weapons forever on net games. if(IS_NETGAME && G_Ruleset_Deathmatch() != 2 && !dropped) return false; } // Attempt the pickup. pickedWeapon = P_GiveWeapon(plr, weaponType, dropped); if(pickedWeapon) { // Notify the user. P_SetMessage(plr, 0, pickupMessage); if(!mapSetup) // Pickup sounds are not played during map setup. { S_ConsoleSound(SFX_WPNUP, NULL, plr - players); } } if(IS_NETGAME && G_Ruleset_Deathmatch() != 2 && !dropped) { // Leave placed weapons forever on net games. return false; } return pickedWeapon; }
static dd_bool shouldForceWeaponChange(dd_bool dropped) { return IS_NETGAME && G_Ruleset_Deathmatch() == 1 && !dropped; }
/** * Damages both enemies and players. * * @param inflictor Mobj that caused the damage creature or missile, * can be NULL (slime, etc) * @param source Mobj to target after taking damage. Can be @c NULL * for barrel explosions and other environmental stuff. * Source and inflictor are the same for melee attacks. * @param skipNetworkCheck Allow the damage to be done regardless of netgame status. * * @return Actual amount of damage done. */ int P_DamageMobj2(mobj_t *target, mobj_t *inflictor, mobj_t *source, int damageP, dd_bool stomping, dd_bool skipNetworkCheck) { angle_t angle; int saved, originalHealth; player_t *player; int /*temp,*/ damage; if(!target) return 0; // Wha? originalHealth = target->health; // The actual damage (== damageP * netMobDamageModifier for any // non-player mobj). damage = damageP; if(!skipNetworkCheck) { if(IS_NETGAME && !stomping && D_NetDamageMobj(target, inflictor, source, damage)) { // We're done here. return 0; } // Clients can't harm anybody. if(IS_CLIENT) return 0; } if(!(target->flags & MF_SHOOTABLE)) return 0; // Shouldn't happen... if(target->health <= 0) return 0; if(target->player) { // Player specific. // Check if player-player damage is disabled. if(source && source->player && source->player != target->player) { // Co-op damage disabled? if(IS_NETGAME && !G_Ruleset_Deathmatch() && cfg.noCoopDamage) return 0; // Same color, no damage? if(cfg.noTeamDamage && cfg.playerColor[target->player - players] == cfg.playerColor[source->player - players]) return 0; } } if(target->flags & MF_SKULLFLY) { target->mom[MX] = target->mom[MY] = target->mom[MZ] = 0; } player = target->player; if(player && G_Ruleset_Skill() == SM_BABY) damage /= 2; // Take half damage in trainer mode. // Use the cvar damage multiplier netMobDamageModifier only if the // inflictor is not a player. if(inflictor && !inflictor->player && (!source || (source && !source->player))) { // damage = (int) ((float) damage * netMobDamageModifier); if(IS_NETGAME) damage *= cfg.netMobDamageModifier; } // Some close combat weapons should not inflict thrust and push the // victim out of reach, thus kick away unless using a melee weapon. if(inflictor && !(target->flags & MF_NOCLIP) && (!source || !source->player || source->player->readyWeapon != WT_EIGHTH) && !(inflictor->flags2 & MF2_NODMGTHRUST)) { uint an; coord_t thrust; angle = M_PointToAngle2(inflictor->origin, target->origin); thrust = FIX2FLT(damage * (FRACUNIT>>3) * 100 / target->info->mass); // Make fall forwards sometimes. if(damage < 40 && damage > target->health && target->origin[VZ] - inflictor->origin[VZ] > 64 && (P_Random() & 1)) { angle += ANG180; thrust *= 4; } an = angle >> ANGLETOFINESHIFT; target->mom[MX] += thrust * FIX2FLT(finecosine[an]); target->mom[MY] += thrust * FIX2FLT(finesine[an]); NetSv_PlayerMobjImpulse(target, thrust * FIX2FLT(finecosine[an]), thrust * FIX2FLT(finesine[an]), 0); // $dropoff_fix: thrust objects hanging off ledges. if((target->intFlags & MIF_FALLING) && target->gear >= MAXGEAR) target->gear = 0; }
/** * The weapon name may have a MF_DROPPED flag ored in. */ dd_bool P_GiveWeapon(player_t *player, weapontype_t weapon, dd_bool dropped) { ammotype_t i; dd_bool gaveAmmo = false; dd_bool gaveWeapon; int numClips; if(IS_NETGAME && (G_Ruleset_Deathmatch() != 2) && !dropped) { // leave placed weapons forever on net games if(player->weapons[weapon].owned) return false; player->bonusCount += BONUSADD; player->weapons[weapon].owned = true; player->update |= PSF_OWNED_WEAPONS; // Give some of each of the ammo types used by this weapon. for(i = 0; i < NUM_AMMO_TYPES; ++i) { if(!weaponInfo[weapon][player->class_].mode[0].ammoType[i]) continue; // Weapon does not take this type of ammo. if(G_Ruleset_Deathmatch()) numClips = 5; else numClips = 2; if(P_GiveAmmo(player, i, numClips)) gaveAmmo = true; // At least ONE type of ammo was given. } // Should we change weapon automatically? P_MaybeChangeWeapon(player, weapon, AT_NOAMMO, G_Ruleset_Deathmatch() == 1); // Maybe unhide the HUD? ST_HUDUnHide(player - players, HUE_ON_PICKUP_WEAPON); S_ConsoleSound(SFX_WPNUP, NULL, player - players); return false; } else { // Give some of each of the ammo types used by this weapon. for(i = 0; i < NUM_AMMO_TYPES; ++i) { if(!weaponInfo[weapon][player->class_].mode[0].ammoType[i]) continue; // Weapon does not take this type of ammo. // Give one clip with a dropped weapon, two clips with a found // weapon. if(dropped) numClips = 1; else numClips = 2; if(P_GiveAmmo(player, i, numClips)) gaveAmmo = true; // At least ONE type of ammo was given. } if(player->weapons[weapon].owned) gaveWeapon = false; else { gaveWeapon = true; player->weapons[weapon].owned = true; player->update |= PSF_OWNED_WEAPONS; // Should we change weapon automatically? P_MaybeChangeWeapon(player, weapon, AT_NOAMMO, false); } // Maybe unhide the HUD? if(gaveWeapon) ST_HUDUnHide(player - players, HUE_ON_PICKUP_WEAPON); return (gaveWeapon || gaveAmmo); } }
/** * Damages both enemies and players * Source and inflictor are the same for melee attacks. * Source can be NULL for slime, barrel explosions * and other environmental stuff. * * @param inflictor Mobj that caused the damage creature or missile, * can be NULL (slime, etc). * @param source Mobj to target after taking damage, creature or NULL. * * @return Actual amount of damage done. */ int P_DamageMobj2(mobj_t *target, mobj_t *inflictor, mobj_t *source, int damageP, dd_bool stomping, dd_bool skipNetworkCheck) { // Follow a player exlusively for 3 seconds. #define BASETHRESHOLD (100) uint an; angle_t angle; int saved; player_t *player; float thrust; //int temp; int originalHealth; // The actual damage (== damageP * netMobDamageModifier for any non-player mobj). int damage = damageP; if(!target) return 0; // Wha? originalHealth = target->health; if(!skipNetworkCheck) { // Clients can't harm anybody. if(IS_CLIENT) return 0; } if(!(target->flags & MF_SHOOTABLE)) return 0; // Shouldn't happen... if(target->health <= 0) return 0; // Player specific. if(target->player) { // Check if player-player damage is disabled. if(source && source->player && source->player != target->player) { // Co-op damage disabled? if(IS_NETGAME && !G_Ruleset_Deathmatch() && cfg.noCoopDamage) return 0; // Same color, no damage? if(cfg.noTeamDamage && cfg.playerColor[target->player - players] == cfg.playerColor[source->player - players]) return 0; } } if(target->flags & MF_SKULLFLY) { target->mom[MX] = target->mom[MY] = target->mom[MZ] = 0; } player = target->player; if(player && G_Ruleset_Skill() == SM_BABY) damage >>= 1; // take half damage in trainer mode // jd64 > #if 0 if(inflictor && inflictor->type == MT_FIREEND) { // Special for Motherdemon attack #if 0 /** DJS - This was originally in a sub routine called P_TouchMotherFire * but due to the fact that @c player, was not initialized * this likely does not work the way kaiser expected it to. * What would actually happen is not certain but I would guess it * would most likely simply return without doing anything at all. * \todo SHOULD this be fixed? Or is something implemented elsewhere * which does what this was attempting to do? */ int damage; player_t *player; if(player = target->player) { damage = ((P_Random() % 10) + 1) * 8; P_DamageMobj(target, NULL, NULL, damage); player->plr->mo->momz = 16; player->jumpTics = 24; } #endif return; } #endif // < d64tc // Use the cvar damage multiplier netMobDamageModifier only if the // inflictor is not a player. if(inflictor && !inflictor->player && (!source || (source && !source->player))) { // damage = (int) ((float) damage * netMobDamageModifier); if(IS_NETGAME) damage *= cfg.common.netMobDamageModifier; } // Some close combat weapons should not inflict thrust and push the // victim out of reach, thus kick away unless using the chainsaw. if(inflictor && !(target->flags & MF_NOCLIP) && (!source || !source->player || source->player->readyWeapon != WT_EIGHTH) && !(inflictor->flags2 & MF2_NODMGTHRUST)) { angle = M_PointToAngle2(inflictor->origin, target->origin); thrust = FIX2FLT(damage * (FRACUNIT>>3) * 100 / target->info->mass); // Make fall forwards sometimes. if(damage < 40 && damage > target->health && target->origin[VZ] - inflictor->origin[VZ] > 64 && (P_Random() & 1)) { angle += ANG180; thrust *= 4; } an = angle >> ANGLETOFINESHIFT; target->mom[MX] += thrust * FIX2FLT(finecosine[an]); target->mom[MY] += thrust * FIX2FLT(finesine[an]); NetSv_PlayerMobjImpulse(target, thrust * FIX2FLT(finecosine[an]), thrust * FIX2FLT(finesine[an]), 0); // $dropoff_fix: thrust objects hanging off ledges. if(target->intFlags & MIF_FALLING && target->gear >= MAXGEAR) target->gear = 0; }