void PlayerTrackBomb::SelectTarget() { POSITION pos = list_->GetHeadPosition(); while (pos != NULL) { EnemyPlane *p = (EnemyPlane *)list_->GetNext(pos); if (!p->GetLock()) { p->Lock(); plane_ = p; return; } } Killed(); }
// DeadTakeDamage - takedamage function called when a monster's corpse is damaged. int CBaseMonster::DeadTakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). Vector vecDir(0, 0, 0); if (!FNullEnt(pevInflictor)) { CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor); if (pInflictor) { vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // turn this back on when the bounding box issues are resolved. #if 0 pev->flags &= ~FL_ONGROUND; pev->origin.z += 1; // let the damage scoot the corpse around a bit. if (!FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER)) { pev->velocity = pev->velocity + vecDir * -DamageForce(flDamage); } #endif // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. if (bitsDamageType & DMG_GIB_CORPSE) { if (pev->health <= flDamage) { pev->health = -50; Killed(pevAttacker, GIB_ALWAYS); return 0; } // Accumulate corpse gibbing damage, so you can gib with multiple hits pev->health -= flDamage * 0.1; } return 1; }
//延时器函数 放慢动画的模仿速度 void GameObject::DelayerCount() { AddCounter(); if (Counter() >= Delayer()) { AddIndexColumn(); if (IndexColumn() == Ima()->Column()) { IndexColumn(0); AddIndexRow(); } if (IndexRow() == Ima()->Row()) { if (Loop()) { IndexRow(0); IndexColumn(0); } else Killed(); } ClearCounter(); } }
void CSqueakGrenade::HuntThink( void ) { // ALERT( at_console, "think\n" ); if (!IsInWorld()) { SetTouch( NULL ); UTIL_Remove( this ); return; } StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; // explode when ready if (gpGlobals->time >= m_flDie) { g_vecAttackDir = pev->velocity.Normalize( ); pev->health = -1; Killed( pev, 0 ); return; } // float if (pev->waterlevel != 0) { if (pev->movetype == MOVETYPE_BOUNCE) { pev->movetype = MOVETYPE_FLY; } pev->velocity = pev->velocity * 0.9; pev->velocity.z += 8.0; } else if (pev->movetype = MOVETYPE_FLY) { pev->movetype = MOVETYPE_BOUNCE; } // return if not time to hunt if (m_flNextHunt > gpGlobals->time) return; m_flNextHunt = gpGlobals->time + 2.0; CBaseEntity *pOther = NULL; Vector vecDir; TraceResult tr; Vector vecFlat = pev->velocity; vecFlat.z = 0; vecFlat = vecFlat.Normalize( ); UTIL_MakeVectors( pev->angles ); if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) { // find target, bounce a bit towards it. Look( 512 ); m_hEnemy = BestVisibleEnemy( ); } // squeek if it's about time blow up if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) { EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); } // higher pitch as squeeker gets closer to detonation time float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); if (flpitch < 80) flpitch = 80; if (m_hEnemy != NULL) { if (FVisible( m_hEnemy )) { vecDir = m_hEnemy->EyePosition() - pev->origin; m_vecTarget = vecDir.Normalize( ); } float flVel = pev->velocity.Length(); float flAdj = 50.0 / (flVel + 10.0); if (flAdj > 1.2) flAdj = 1.2; // ALERT( at_console, "think : enemy\n"); // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; } if (pev->flags & FL_ONGROUND) { pev->avelocity = Vector( 0, 0, 0 ); } else { if (pev->avelocity == Vector( 0, 0, 0)) { pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); } } if ((pev->origin - m_posPrev).Length() < 1.0) { pev->velocity.x = RANDOM_FLOAT( -100, 100 ); pev->velocity.y = RANDOM_FLOAT( -100, 100 ); } m_posPrev = pev->origin; pev->angles = UTIL_VecToAngles( pev->velocity ); pev->angles.z = 0; pev->angles.x = 0; }
void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) { SetTouch( NULL ); SetThink( NULL ); if (pOther->pev->takedamage) { TraceResult tr = UTIL_GetGlobalTrace( ); entvars_t *pevOwner; pevOwner = VARS( pev->owner ); // UNDONE: this needs to call TraceAttack instead ClearMultiDamage( ); if ( pOther->IsPlayer() ) { pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); } else { pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); } ApplyMultiDamage( pev, pevOwner ); pev->velocity = Vector( 0, 0, 0 ); // play body "thwack" sound switch( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; } if ( !g_pGameRules->IsMultiplayer() ) { Killed( pev, GIB_NEVER ); } } else { EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7)); SetThink( &CCrossbowBolt::SUB_Remove ); pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit. if ( FClassnameIs( pOther->pev, "worldspawn" ) ) { // if what we hit is static architecture, can stay around for a while. Vector vecDir = pev->velocity.Normalize( ); UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); pev->angles = UTIL_VecToAngles( vecDir ); pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_FLY; pev->velocity = Vector( 0, 0, 0 ); pev->avelocity.z = 0; pev->angles.z = RANDOM_LONG(0,360); pev->nextthink = gpGlobals->time + 10.0; } if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) { UTIL_Sparks( pev->origin ); } } if ( g_pGameRules->IsMultiplayer() ) { SetThink( &CCrossbowBolt::ExplodeThink ); pev->nextthink = gpGlobals->time + 0.1; } }
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage ) { vec3_t dir; gedict_t *oldself; float save; float take; int i, c1 = 8, c2 = 4, hdp; float dmg_dealt = 0, virtual_take = 0; float non_hdp_damage; // save damage before handicap apply for kickback calculation float native_damage = damage; // save damage before apply any modificator char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; //midair and instagib float playerheight = 0, midheight = 0; qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false; // can't apply damage to dead if ( !targ->s.v.takedamage || ISDEAD( targ ) ) return; // can't damage other players in race if ( isRACE() && ( attacker != targ ) ) { if ( targ->ct == ctPlayer || attacker->ct == ctPlayer ) return; } // ignore almost all damage in CA while coutdown if ( isCA() && match_in_progress && ra_match_fight != 2 ) { if ( !( dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype // do suicide damage anyway ) ) return; } // used by buttons and triggers to set activator for target firing damage_attacker = attacker; damage_inflictor = inflictor; attackerteam = getteam( attacker ); targteam = getteam( targ ); if ( (int)cvar("k_midair") ) midair = true; // in bloodfest boss damage factor. if ( k_bloodfest && attacker->bloodfest_boss ) { damage *= 4; } // check for quad damage powerup on the attacker // midair quad makes rockets fast, but no change to damage if ( attacker->super_damage_finished > g_globalvars.time && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype && !midair ) damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually // ctf strength rune if ( attacker->ctf_flag & CTF_RUNE_STR ) damage *= 2; // ctf resistance rune if ( targ->ctf_flag & CTF_RUNE_RES ) { damage /= 2; ResistanceSound( targ ); } // did we hurt enemy flag carrier? if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) ) { attacker->carrier_hurt_time = g_globalvars.time; } // in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) ) { tp4teamdmg = true; } if ( midair || cvar("k_instagib") ) { traceline( PASSVEC3(targ->s.v.origin), targ->s.v.origin[0], targ->s.v.origin[1], targ->s.v.origin[2] - 2048, true, targ ); playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 ); } // get some data before apply damage in mid air mode if ( midair ) { inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 ); if ( streq( inflictor->s.v.classname, "rocket" )) midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2]; rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype ); stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype ); if ( !rl_dmg ) { // damage types which ignore "lowheight" do_dmg = targ->ct != ctPlayer // always do damage to non player, secret doors etc... || dtWATER_DMG == targ->deathtype // always do water damage || dtLAVA_DMG == targ->deathtype // always do lava damage || dtSLIME_DMG == targ->deathtype // always do slime damage || dtSTOMP == targ->deathtype // always do stomp damage || dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype; // do suicide damage anyway } } non_hdp_damage = damage; // save damage before handicap apply for kickback calculation // #handicap# if ( attacker != targ ) // attack no self if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100 if ( dtAXE == targ->deathtype || dtSG == targ->deathtype || dtSSG == targ->deathtype || dtNG == targ->deathtype || dtSNG == targ->deathtype || dtGL == targ->deathtype || dtRL == targ->deathtype || dtLG_BEAM == targ->deathtype || dtLG_DIS == targ->deathtype || dtLG_DIS_SELF == targ->deathtype // even that impossible ) { damage *= 0.01f * hdp; } // save damage based on the target's armor level save = newceil( targ->s.v.armortype * damage ); if ( tp4teamdmg ) save = 0; // we do not touch armor if ( save >= targ->s.v.armorvalue ) { save = targ->s.v.armorvalue; targ->s.v.armortype = 0; // lost all armor targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) ); } dmg_dealt += save; if ( match_in_progress == 2 ) targ->s.v.armorvalue = targ->s.v.armorvalue - save; take = newceil( damage - save ); // mid air damage modificators if ( midair ) { int k_midair_minheight, midair_minheight; k_midair_minheight = (int)cvar("k_midair_minheight"); if ( k_midair_minheight == 1 ) midair_minheight = 128; else if ( k_midair_minheight == 2 ) midair_minheight = 256; else if ( k_midair_minheight == 3 ) midair_minheight = 512; else if ( k_midair_minheight == 4 ) midair_minheight = 1024; else midair_minheight = 64; if ( rl_dmg || stomp_dmg ) take = 9999; if ( playerheight < midair_minheight && rl_dmg ) take = 0; // no dmg done if target is not high enough if ( playerheight < 45 && !inwater && rl_dmg ) take = 0; // no rl dmg in such case if ( !rl_dmg && !do_dmg ) take = 0; // unknown damage for midair, so do not damage if ( rl_dmg && targ == attacker ) take = 0; // no self rl damage } // instagib damage modificators if ( cvar("k_instagib") ) { if ( inflictor->ct == ctPlayer ) take = 5000; if ( attacker == targ ) take = 0; } // helps kill player in prewar at "wrong" places if ( match_in_progress != 2 && native_damage > 450 ) take = 99999; // team play damage avoidance and godmode or invincibility check virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags // ignore this checks for suicide damage if ( dtSUICIDE != targ->deathtype ) { if ( ( int ) targ->s.v.flags & FL_GODMODE ) { take = 0; // what if god was one of us } else if ( targ->invincible_finished >= g_globalvars.time ) { if ( targ->invincible_sound < g_globalvars.time ) { sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM ); targ->invincible_sound = g_globalvars.time + 2; } take = 0; } else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) ) && !strnull( attackerteam ) && streq( targteam, attackerteam ) && attacker->ct == ctPlayer && strneq( inflictor->s.v.classname, "door" ) && !TELEDEATH( targ ) // do telefrag damage in tp ) { // teamplay == 1 don't damage self and mates (armor affected anyway) // teamplay == 3 don't damage mates, do damage to self (armor affected anyway) take = 0; } else if ( tp4teamdmg ) { take = 0; // we do not touch health } } take = max(0, take); // avoid negative take, if any if ( cvar("k_dmgfrags") ) { if ( TELEDEATH( targ ) ) { // tele doesn't count for any dmgfrags damage dmg_dealt = 0; } else if ( targ->invincible_finished >= g_globalvars.time ) { // damage dealt _not_ capped by victim's health if victim has pent dmg_dealt += virtual_take; } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, virtual_take, targ->s.v.health ); } } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, take, targ->s.v.health ); } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // FIXME: remove after combining shotgun blasts? if ( targ->ct == ctPlayer ) { targ->s.v.dmg_take += take; targ->s.v.dmg_save += save; targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor ); } if ( save ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>1</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)save ); } // figure momentum add if ( inflictor != world && ( targ->s.v.movetype == MOVETYPE_WALK || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) ) ) { float nailkick; for ( i = 0; i < 3; i++ ) dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5; VectorNormalize( dir ); dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2]; if ( midair && non_hdp_damage < 60 && attacker != targ ) { c1 = 11; c2 = 6; } // Yawnmode: nails increases kickback // - Molgrum if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) ) nailkick = 1.2; else nailkick = 1.0; for ( i = 0; i < 3; i++ ) targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 ); if ( midair && playerheight < 45 ) targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) { targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND; } } if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") ) { if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ ) { if ( isDuel() || isFFA() || strneq(attackerteam, targteam) ) { int dmg_frags; attacker->ps.dmg_frags += dmg_dealt; // add dealt dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags); attacker->ps.dmg_frags -= dmg_frags * 100; } } } // do the damage if ( match_in_progress == 2 || dtSUICIDE == targ->deathtype // do suicide damage anyway || TELEDEATH( targ ) || ( k_practice && targ->ct != ctPlayer ) // #practice mode# || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2 ) { targ->s.v.health -= take; // G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health ); if ( take ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>0</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)take ); } if ( !targ->s.v.health || dtSUICIDE == targ->deathtype ) targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this } // show damage in sbar if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess ) { if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) ) { if ( targ->ct == ctPlayer ) targ->s.v.currentammo = 1000 + Q_rint(damage); if ( attacker != targ && attacker->ct == ctPlayer) attacker->s.v.health = 1000 + Q_rint(damage); } } // update damage stats like: give/taked/team damage if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) { if ( attacker == targ ) { // self damage attacker->ps.dmg_self += dmg_dealt; } else { int items = targ->s.v.items; // damage to enemy weapon if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) ) { attacker->ps.dmg_eweapon += dmg_dealt; } if ( tp_num() && streq(attackerteam, targteam) ) { attacker->ps.dmg_team += dmg_dealt; } else { attacker->ps.dmg_g += dmg_dealt; targ->ps.dmg_t += dmg_dealt; } // real hits if ( take || save ) { if ( dtRL == targ->deathtype ) attacker->ps.wpn[wpRL].rhits++; if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].rhits++; } // virtual hits if ( virtual_take || save ) { if ( dtRL == targ->deathtype ) { attacker->ps.wpn[wpRL].vhits++; // virtual given rl damage attacker->ps.dmg_g_rl += ( virtual_take + save ); } if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].vhits++; } } } // mid air bonuses if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg) MidairDamageBonus(attacker, midheight); if ( midair && match_in_progress == 2 && stomp_dmg ) { attacker->ps.mid_stomps++; targ->s.v.frags -= 3; } // if targed killed, do appropriate action and return if ( ISDEAD( targ ) ) { Killed( targ, attacker, inflictor ); return; } // react to the damage - call pain function oldself = self; self = targ; if ( (int)self->s.v.flags & FL_MONSTER ) { GetMadAtAttacker( attacker ); } if ( self->th_pain ) { self->th_pain( attacker, take ); } self = oldself; }
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) { gclient_t *client; int take; int save; int asave; int psave; int te_sparks; if (!targ->takedamage) return; if(mod == MOD_CRUSH) { //bot's state change if((targ->svflags & SVF_MONSTER) && targ->client) { if((targ->client->zc.waitin_obj == inflictor && targ->client->zc.zcstate) || targ->groundentity == inflictor) { // gi.bprintf(PRINT_HIGH,"MOOOOOOOOOOOOOOOOOOOO\n"); targ->client->zc.zcstate |= STS_W_DONT; } } } // friendly fire avoidance // if enabled you can't hurt teammates (but you can hurt yourself) // knockback still occurs if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) { if (OnSameTeam (targ, attacker)) { if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) damage = 0; else mod |= MOD_FRIENDLY_FIRE; } else if(targ->client && !(targ->svflags & SVF_MONSTER)) { if(attacker->client) targ->client->zc.first_target = attacker; } } meansOfDeath = mod; // easy mode takes half damage if (skill->value == 0 && deathmatch->value == 0 && targ->client) { damage *= 0.5; if (!damage) damage = 1; } client = targ->client; if (dflags & DAMAGE_BULLET) te_sparks = TE_BULLET_SPARKS; else te_sparks = TE_SPARKS; VectorNormalize(dir); // bonus damage for suprising a monster if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0)) damage *= 2; //ZOID //strength tech damage = CTFApplyStrength(attacker, damage); //ZOID if (targ->flags & FL_NO_KNOCKBACK) knockback = 0; // figure momentum add if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) { vec3_t kvel; float mass; if (targ->mass < 50) mass = 50; else mass = targ->mass; if (targ->client && attacker == targ) VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack... else VectorScale (dir, 500.0 * (float)knockback / mass, kvel); VectorAdd (targ->velocity, kvel, targ->velocity); } } take = damage; save = 0; // check for godmode if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) ) { take = 0; save = damage; SpawnDamage (te_sparks, point, normal, save); } // check for invincibility if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION)) { if (targ->pain_debounce_time < level.time) { gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect3.wav"), 1, ATTN_NORM, 0); // gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } //ZOID //team armor protect if (ctf->value && targ->client && attacker->client && targ->client->resp.ctf_team == attacker->client->resp.ctf_team && targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT)) { psave = asave = 0; } else { //ZOID psave = CheckPowerArmor (targ, point, normal, take, dflags); take -= psave; asave = CheckArmor (targ, point, normal, take, te_sparks, dflags); take -= asave; } //treat cheat/powerup savings the same as armor asave += save; //ZOID //resistance tech take = CTFApplyResistance(targ, take); //ZOID // team damage avoidance if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker)) return; //ZOID CTFCheckHurtCarrier(targ, attacker); //ZOID // do the damage if (take) { if ((targ->svflags & SVF_MONSTER) || (client)) { SpawnDamage (TE_BLOOD, point, normal, take); if(client && (targ->svflags & SVF_MONSTER) && attacker) { if(client->zc.battlemode & FIRE_CHIKEN) client->zc.battlemode &= ~FIRE_CHIKEN; if(mod == MOD_RAILGUN || mod == MOD_BFG_LASER || mod == MOD_ROCKET || mod == MOD_BLASTER || mod == MOD_RIPPER || mod == MOD_HYPERBLASTER || mod == MOD_PHALANX) { if(attacker->client && (9 * random() < Bot[client->zc.botindex].param[BOP_REACTION]) && !client->zc.first_target) { if(!OnSameTeam (targ, attacker)) client->zc.first_target = attacker; } } } } else SpawnDamage (te_sparks, point, normal, take); targ->health = targ->health - take; if (targ->health <= 0) { if ((targ->svflags & SVF_MONSTER) || (client)) targ->flags |= FL_NO_KNOCKBACK; Killed (targ, inflictor, attacker, take, point); return; } } if (client) { if (!(targ->flags & FL_GODMODE) && (take)) targ->pain (targ, attacker, knockback, take); } else if (take) { if (targ->pain) targ->pain (targ, attacker, knockback, take); } // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame if (client) { client->damage_parmor += psave; client->damage_armor += asave; client->damage_blood += take; client->damage_knockback += knockback; VectorCopy (point, client->damage_from); } }
/* ================ idExplodingBarrel::Event_Explode ================ */ void idExplodingBarrel::Event_Explode() { if ( state == NORMAL || state == BURNING ) { state = BURNEXPIRED; Killed( NULL, NULL, 0, vec3_zero, 0 ); } }
//----------------------------------------------------------------------------- // Purpose: Player has taken some damage. This is now using the Quake functionality. //----------------------------------------------------------------------------- int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { if ( (pev->takedamage == DAMAGE_NO) || (IsAlive() == FALSE) ) return 0; //We are wearing the suit and we want to be hurt by lava or slime if ( m_iQuakeItems & IT_SUIT ) { if ( bitsDamageType & DMG_BURN || bitsDamageType & DMG_ACID ) return 0; } CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); // keep track of amount of damage last sustained m_lastDamageAmount = flDamage; // check for quad damage powerup on the attacker if (pAttacker->IsPlayer()) { if ( ((CBasePlayer*)pAttacker)->m_flSuperDamageFinished > gpGlobals->time ) { if (gpGlobals->deathmatch == 4) flDamage *= 8; else flDamage *= 4; } } // team play damage avoidance if ( g_pGameRules->PlayerRelationship( this, pAttacker ) == GR_TEAMMATE ) { // Teamplay 3 you can still hurt yourself if ( CVAR_GET_FLOAT( "mp_teamplay" ) == 3 && pAttacker != this ) return 0; // Teamplay 1 can't hurt any teammates, including yourself if ( CVAR_GET_FLOAT( "mp_teamplay" ) == 1 ) return 0; // Teamplay 2 you can still hurt teammates } // save damage based on the target's armor level float flSave = ceil(pev->armortype * flDamage); if (flSave >= pev->armorvalue) { flSave = pev->armorvalue; pev->armortype = 0; // lost all armor m_iQuakeItems &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } pev->armorvalue -= flSave; float flTake = ceil(flDamage - flSave); // add to the damage total for clients, which will be sent as a single message at the end of the frame pev->dmg_take = pev->dmg_take + flTake; pev->dmg_inflictor = ENT(pevInflictor); Vector vecTemp; if ( pevAttacker == pevInflictor ) { vecTemp = pevAttacker->origin - ( VecBModelOrigin(pev) ); } else // an actual missile was involved. { vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); } // this global is still used for glass and other non-monster killables, along with decals. g_vecAttackDir = vecTemp.Normalize(); // figure momentum add if ( (pevInflictor) && (pev->movetype == MOVETYPE_WALK) && !( FBitSet (bitsDamageType, DMG_BURN) ) && !( FBitSet (bitsDamageType, DMG_ACID) ) ) { Vector vecPush = (pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5).Normalize(); // Set kickback for smaller weapons // Read: only if it's not yourself doing the damage if ( (flDamage < 60) && pAttacker->IsPlayer() && (pAttacker != this) ) pev->velocity = pev->velocity + vecPush * flDamage * 11; else { // Otherwise, these rules apply to rockets and grenades // for blast velocity if ( pAttacker == this ) { if ( m_iQuakeWeapon != IT_LIGHTNING ) pev->velocity = pev->velocity + vecPush * flDamage * 8; } else pev->velocity = pev->velocity + vecPush * flDamage * 8; } // Rocket Jump modifiers int iRocketJumpModifier = (int)CVAR_GET_FLOAT("rj"); if ( (iRocketJumpModifier > 1) && (pAttacker == this) && m_iQuakeWeapon == ( IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER ) ) pev->velocity = pev->velocity + vecPush * flDamage * iRocketJumpModifier; } // check for godmode or invincibility if (pev->flags & FL_GODMODE) return 0; if (m_flInvincibleFinished > gpGlobals->time) { if (m_fInvincSound < gpGlobals->time) { EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); m_fInvincSound = gpGlobals->time + 2; } return 0; } // do the damage pev->health -= (int)flTake; // tell director about it MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); WRITE_BYTE ( 9 ); // command length in bytes WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity WRITE_LONG( 5 ); // eventflags (priority and flags) MESSAGE_END(); // react to the damage m_bitsDamageType |= bitsDamageType; // Save this so we can report it to the client m_bitsHUDDamage = -1; // make sure the damage bits get resent if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; Killed( pevAttacker, GIB_NORMAL ); g_pevLastInflictor = NULL; return 0; } // play pain sound Pain( pAttacker ); return flTake; }
// The damage is coming from inflictor, but get mad at attacker // This should be the only function that ever reduces health. // bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK // // Time-based damage: only occurs while the monster is within the trigger_hurt. // When a monster is poisoned via an arrow etc it takes all the poison damage at once. int CBaseMonster::__MAKE_VHOOK(TakeDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { if (pev->takedamage == DAMAGE_NO) return 0; if (!IsAlive()) { return DeadTakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); } if (pev->deadflag == DEAD_NO) { // no pain sound during death animation. PainSound(); } // LATER: make armor consideration here! float flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). Vector vecDir(0, 0, 0); if (!FNullEnt(pevInflictor)) { CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor); if (pInflictor) { #ifndef PLAY_GAMEDLL vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize(); #else // TODO: fix test demo vecDir = NormalizeSubtract< float_precision, float, float_precision, float_precision >(Center(), pInflictor->Center() - Vector(0, 0, 10)); #endif vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // TODO: remove after combining shotgun blasts? if (IsPlayer()) { if (pevInflictor) { pev->dmg_inflictor = ENT(pevInflictor); } pev->dmg_take += flTake; } pev->health -= flTake; if (m_MonsterState == MONSTERSTATE_SCRIPT) { SetConditions(bits_COND_LIGHT_DAMAGE); return 0; } if (pev->health <= 0.0f) { g_pevLastInflictor = pevInflictor; if (bitsDamageType & DMG_ALWAYSGIB) Killed(pevAttacker, GIB_ALWAYS); else if (bitsDamageType & DMG_NEVERGIB) Killed(pevAttacker, GIB_NEVER); else Killed(pevAttacker, GIB_NORMAL); g_pevLastInflictor = NULL; return 0; } if ((pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker)) { if (pevAttacker->flags & (FL_MONSTER | FL_CLIENT)) { if (pevInflictor) { if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) m_vecEnemyLKP = pevInflictor->origin; } else { m_vecEnemyLKP = pev->origin + (g_vecAttackDir * 64); } MakeIdealYaw(m_vecEnemyLKP); if (flDamage > 20.0f) { SetConditions(bits_COND_LIGHT_DAMAGE); } if (flDamage >= 20.0f) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }
void CGrappleHook::Move( void ) { // Fograin92: If owner (player) is dead if( !myowner->IsAlive() ) { Killed(pev, 0); // Remove tongue instantly return; } // Fograin92: Player isn't holding attack buttons if( !(myowner->pev->button & (IN_ATTACK|IN_ATTACK2)) ) { bPullBack = true; // Fograin92: We should pull the tongue back } // Fograin92: Animate pull-back tongue animation ONLY if we didn't hit a monster if(bPullBack) { UTIL_MakeVectors( myowner->pev->v_angle + myowner->pev->punchangle ); Vector GunPosition = myowner->GetGunPosition(); GunPosition = GunPosition + gpGlobals->v_up * -4 + gpGlobals->v_right * 3 + gpGlobals->v_forward * 6; pev->velocity = (GunPosition - pev->origin) * 10; // Pull back the tongue tip float fDistance = (GunPosition - pev->origin).Length2D(); // Calculate distance between tongue tip and player //ALERT( at_console, "^2HLU -> ^3weapon_grapple ^2-> %f\n", fDistance ); if (fDistance < 40) { Killed(pev, 0); return; } } else { // Fograin92: We did hit a monster if(m_iHitMonster > 0) { // Fograin92: Let's "stick" grapple tongue XYZ to target's center XYZ pev->origin = myHitMonster->Center(); // Fograin92: We did hit tiny monster, let's pull it if(m_iHitMonster == 2) { myHitMonster->pev->movetype = MOVETYPE_FLY; // Remove gravity effect on our pulled monster myHitMonster->pev->velocity = (myowner->pev->origin - myHitMonster->pev->origin) * 4; // Pull our monster } // Fograin92: Check distance (player <-> monster) float fDistance = (myowner->pev->origin - myHitMonster->pev->origin).Length2D(); // Fograin92: The monster is very close to player, let's OWN IT! if (fDistance < 40) { ALERT( at_console, "^2HLU -> ^3weapon_grapple ^2-> OWNED -> ^3%s\n", STRING(myHitMonster->pev->classname) ); // Fograin92: Did we pull the gib? if( myHitMonster->Classify() == CLASS_GIBS ) myHitMonster->SUB_Remove(); else myHitMonster->TakeDamage(myHitMonster->pev, myowner->pev, 10000, DMG_GENERIC); Killed(pev, 0); // Fograin92: Target died, kill tongue } } } // Fograin92: If tongue (beam) exists if( m_pTongue ) { UTIL_MakeVectors( myowner->pev->v_angle + myowner->pev->punchangle ); Vector GunPosition = myowner->GetGunPosition(); GunPosition = GunPosition + gpGlobals->v_up * -4 + gpGlobals->v_right * 3 + gpGlobals->v_forward * 6; m_pTongue->PointEntInit( GunPosition, this->entindex() ); } else { // Fograin92: Create tongue (beam) m_pTongue = CBeam::BeamCreate( "sprites/_tongue.spr", 8 ); m_pTongue->SetFlags( 0x20 ); // Solid beam m_pTongue->SetColor( 100, 100, 100 ); m_pTongue->SetScrollRate( 20 ); } pev->nextthink = gpGlobals->time + 0.01; }
int T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) { qboolean mod_magic = false; gclient_t *client; int take = 0; int save = 0; int asave = 0; int psave = 0; int rsave = 0; int sasave = 0; int te_sparks; if (!targ->takedamage) return 0; // Can't heal monsters if ((damage < 0) && (targ->svflags & SVF_MONSTER)) { return 0; } if (mod & MOD_MAGIC) { //damage dealt by magic mod_magic = true; mod &= ~MOD_MAGIC; } // friendly fire avoidance // if enabled you can't hurt teammates (but you can hurt yourself) // knockback still occurs // team damage avoidance, if not telefrag if (mod != MOD_TELEFRAG) { if (deathmatch->value && attacker->client && targ->client && (targ != attacker) && (((targ->count == attacker->count) && teams->value) || (game.monsterhunt == 10)) && (damage > 0)) { // Two players on same team damage *= teamdamage->value; } if (coop->value && attacker->client && targ->client && (targ != attacker)) { damage *= teamdamage->value; } } meansOfDeath = mod; client = targ->client; if (dflags & DAMAGE_BULLET) te_sparks = TE_BULLET_SPARKS; else te_sparks = TE_SPARKS; VectorNormalize(dir); if (targ->flags & FL_NO_KNOCKBACK) knockback = 0; // Simulate armor pierce and armor breaker on monsters // This has been disabled, since it applies bonus AFTER all other bonuses, resulting in crazy total bonuses /* if ((targ->svflags & SVF_MONSTER) && (attacker->client) && (!mod_magic)) { if (attacker->client->pers.skill[2] > 0) { if (mod == MOD_BLASTER) { iteminfo_t *winfo = getWornItemInfo(attacker, 0); damage *= 1 + 0.75 * (winfo->arg4 + winfo->arg5 * attacker->client->pers.skill[2]); } else { damage *= 1 + 0.02 * attacker->client->pers.skill[2]; } } if (attacker->client->pers.skill[72] > 0) { damage *= 1 + 0.02 * attacker->client->pers.skill[72]; } }*/ if ((targ->svflags & SVF_MONSTER) && (targ->health > 0)) { float manaburn_mult = 0.0f; float manaleech_mult = 0.0f; if ((targ->radius_dmg) && (targ->monsterinfo.ability) && (damage > 0)) { rsave = 0; if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_EXPL) && ((mod == MOD_GRENADE) || (mod == MOD_G_SPLASH) || (mod == MOD_ROCKET) || (mod == MOD_R_SPLASH) || (mod == MOD_HANDGRENADE) || (mod == MOD_HG_SPLASH))) { rsave += 0.33 * damage; } if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_IMPACT) && ((mod == MOD_MACHINEGUN) || (mod == MOD_CHAINGUN) || (mod == MOD_SHOTGUN) || (mod == MOD_SSHOTGUN))) { rsave += 0.33 * damage; } if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_ENERGY) && ((mod == MOD_BLASTER) || (mod == MOD_HYPERBLASTER) || (mod == MOD_LASERMINE) || (mod == MOD_RAILGUN) || (mod == MOD_BFG_LASER) || (mod == MOD_BFG_BLAST) || (mod == MOD_BFG_EFFECT))) { rsave += 0.33 * damage; } if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_BMAGIC) && ((mod == MOD_PLAGUEBOMB) || (mod == MOD_DRAIN) || (mod == MOD_SPORE))) { rsave += 0.33 * damage; } if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_FMAGIC) && ((mod == MOD_INFERNO) || (mod == MOD_FIREBOLT) || (mod == MOD_FIREBALL) || (mod == MOD_CORPSEEXPLOSION))) { rsave += 0.33 * damage; } if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_LMAGIC) && ((mod == MOD_LIGHTNING) || (mod == MOD_SPARK) || (mod == MOD_BOLT) || (mod == MOD_STORM))) { rsave += 0.33 * damage; } if (rsave > 0) { //Anti-resist int arlvl = getAuraLevel(attacker, 84); if (arlvl > 0) { int slot = getAuraSlot(attacker, 84); if (attacker->client->aura_caster[slot]->client->magic > 0) { attacker->client->aura_caster[slot]->client->magic -= 0.1 * rsave; attacker->client->aura_caster[slot]->client->magregentime = level.time + 1.0; rsave *= 1 - (arlvl * 0.02); } } damage -= rsave; } } if (attacker->client) { if (dflags & DAMAGE_10_MANABURN) // 10% manaburn_mult += 0.1; if (dflags & DAMAGE_25_MANABURN) // 25% manaburn_mult += 0.25; if (dflags & DAMAGE_50_MANABURN) // 50% manaburn_mult += 0.5; if (dflags & DAMAGE_100_MANABURN) // 100% manaburn_mult += 1.0; if (dflags & DAMAGE_200_MANABURN) // 200% manaburn_mult += 2.0; if (dflags & DAMAGE_400_MANABURN) // 400% manaburn_mult += 4.0; if (dflags & DAMAGE_50_MANALEECH) // 50% manaleech_mult += 0.5; if (dflags & DAMAGE_100_MANALEECH) // 100% manaleech_mult += 1.0; if (dflags & DAMAGE_200_MANALEECH) // 200% manaleech_mult += 2.0; if ((manaburn_mult > 0.0) && (attacker->client->magic < attacker->client->max_magic * 4)) { attacker->client->magic += (int) ceil(damage * manaburn_mult); if (attacker->client->magic > attacker->client->max_magic * 4) { attacker->client->magic = attacker->client->max_magic * 4; } gi.WriteByte (svc_muzzleflash); gi.WriteShort (targ-g_edicts); gi.WriteByte (MZ_NUKE4); gi.multicast (targ->s.origin, MULTICAST_PVS); } if (manaleech_mult > 0.0) { if (attacker->client->magic < attacker->client->max_magic * 4) { attacker->client->magic += (int) ceil(damage * manaleech_mult); if (attacker->client->magic > attacker->client->max_magic * 4) { attacker->client->magic = attacker->client->max_magic * 4; } } if (manaburn_mult == 0.0) { gi.WriteByte (svc_muzzleflash); gi.WriteShort (targ-g_edicts); gi.WriteByte (MZ_NUKE4); gi.multicast (targ->s.origin, MULTICAST_PVS); } } } } if (client && (damage > 0) && (targ->health > 0)) { int pre_damage = damage; int nosanc_damage = damage; int pre_magic = targ->client->magic; float res_boost = 0.15 * targ->client->pers.skill[45]; //Resistance boost float manaburn_mult = 0.0f; float manaleech_mult = 0.0f; if (targ->client->magic <= 0) res_boost = 0; //Sanctuary aura if ((getAuraLevel(targ, 65) > 0) && (damage > 0)) { int slot = getAuraSlot(targ, 65); if (targ->client->aura_caster[slot]->client->magic > 0) { float bonus = getMagicBonuses(targ->client->aura_caster[slot], 65); float dmg_mult = 1.0; float cost_mult = 0.0; dmg_mult = (0.004 * targ->client->aura_level[slot] * (0.2 + bonus * 0.8)); if (dmg_mult > 1) dmg_mult = 1.0; cost_mult = 0.002 * targ->client->aura_level[slot]; if (targ->client->aura_level[slot] > 40) { cost_mult += 0.002 * (targ->client->aura_level[slot] - 40); } cost_mult *= ((float) (targ->client->aura_caster[slot]->client->max_magic + 800.0)) / 800.0; if (cost_mult * damage > targ->client->aura_caster[slot]->client->magic) { int dmgsave = (int) targ->client->aura_caster[slot]->client->magic / cost_mult; //gi.dprintf("%d %d %f %d %d\n", damage, dmgsave, cost_mult, targ->client->aura_caster[slot]->client->magic, (int) dmgsave * cost_mult); sasave += dmgsave * dmg_mult; damage -= dmgsave * dmg_mult; targ->client->aura_caster[slot]->client->magic -= dmgsave * cost_mult; } else { targ->client->aura_caster[slot]->client->magic -= cost_mult * damage; sasave += dmg_mult * damage; damage *= 1.0 - dmg_mult; } targ->client->aura_caster[slot]->client->magregentime = level.time + 1.0; gi.sound(targ, CHAN_ITEM, gi.soundindex("giex/magarm1.wav"), 0.5, ATTN_NORM, 0); } } rsave = 0; // Global (Damage resist) if (targ->client->pers.skill[46] > 0) { rsave += damage * 0.01 * targ->client->pers.skill[46]; } // Bullet if ((targ->client->pers.skill[36] > 0) && ((mod == MOD_MACHINEGUN) || (mod == MOD_CHAINGUN))) { rsave += damage * 0.015 * targ->client->pers.skill[36] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // Pellet else if ((targ->client->pers.skill[37] > 0) && ((mod == MOD_SHOTGUN) || (mod == MOD_SSHOTGUN))) { rsave += damage * 0.015 * targ->client->pers.skill[37] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // Explosion else if ((targ->client->pers.skill[38] > 0) && ((mod == MOD_GRENADE) || (mod == MOD_G_SPLASH) || (mod == MOD_ROCKET) || (mod == MOD_R_SPLASH) || (mod == MOD_HANDGRENADE) || (mod == MOD_HG_SPLASH))) { rsave += damage * 0.015 * targ->client->pers.skill[38] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // Energy else if ((targ->client->pers.skill[39] > 0) && ((mod == MOD_BLASTER) || (mod == MOD_HYPERBLASTER) || (mod == MOD_LASERMINE))) { rsave += damage * 0.015 * targ->client->pers.skill[39] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // High energy else if ((targ->client->pers.skill[40] > 0) && ((mod == MOD_RAILGUN) || (mod == MOD_BFG_LASER) || (mod == MOD_BFG_BLAST) || (mod == MOD_BFG_EFFECT))) { rsave += damage * 0.015 * targ->client->pers.skill[40] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // World and hit damage else if (targ->client->pers.skill[41] > 0) { if ((mod == MOD_WATER) || (mod == MOD_SLIME) || (mod == MOD_FALLING) || (mod == MOD_LAVA) || (mod == MOD_CRUSH)) { rsave += damage * 0.1 * targ->client->pers.skill[41]; } else if (mod == MOD_HIT) { rsave += damage * 0.015 * targ->client->pers.skill[41] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } } // Blood magic else if ((targ->client->pers.skill[42] > 0) && ((mod == MOD_PLAGUEBOMB) || (mod == MOD_DRAIN) || (mod == MOD_SPORE))) { rsave += damage * 0.015 * targ->client->pers.skill[42] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // Fire magic else if ((targ->client->pers.skill[43] > 0) && ((mod == MOD_INFERNO) || (mod == MOD_FIREBOLT) || (mod == MOD_FIREBALL) || (mod == MOD_CORPSEEXPLOSION))) { rsave += damage * 0.015 * targ->client->pers.skill[43] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } // Lightning magic else if ((targ->client->pers.skill[69] > 0) && ((mod == MOD_LIGHTNING) || (mod == MOD_SPARK) || (mod == MOD_BOLT))) { rsave += damage * 0.015 * targ->client->pers.skill[69] * res_boost; targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost); } if (rsave > 0) { //Anti-resist int arlvl = getAuraLevel(attacker, 84); if (arlvl > 0) { int slot = getAuraSlot(attacker, 84); if (attacker->client->aura_caster[slot]->client->magic > 0) { attacker->client->aura_caster[slot]->client->magic -= 0.1 * rsave; attacker->client->aura_caster[slot]->client->magregentime = level.time + 1.0; rsave *= 1 - (arlvl * 0.02); } } damage -= rsave; nosanc_damage -= rsave; } if (dflags & DAMAGE_10_MANABURN) // 10% manaburn_mult += 0.1; if (dflags & DAMAGE_25_MANABURN) // 25% manaburn_mult += 0.25; if (dflags & DAMAGE_50_MANABURN) // 50% manaburn_mult += 0.5; if (dflags & DAMAGE_100_MANABURN) // 100% manaburn_mult += 1.0; if (dflags & DAMAGE_200_MANABURN) // 200% manaburn_mult += 2.0; if (dflags & DAMAGE_400_MANABURN) // 400% manaburn_mult += 4.0; if (dflags & DAMAGE_50_MANALEECH) // 50% manaleech_mult += 0.5; if (dflags & DAMAGE_100_MANALEECH) // 100% manaleech_mult += 1.0; if (dflags & DAMAGE_200_MANALEECH) // 200% manaleech_mult += 2.0; if ((attacker->svflags & SVF_MONSTER) && (attacker->monsterinfo.ability & GIEX_MABILITY_MANABURN)) { manaburn_mult += 1.0; } if (manaburn_mult > 0.0) { targ->client->magic -= nosanc_damage * manaburn_mult; if (targ->client->magic < 0) targ->client->magic = 0; if ((attacker->client) && (attacker->client->magic < attacker->client->max_magic * 4)) { attacker->client->magic += nosanc_damage * manaburn_mult; if (attacker->client->magic > attacker->client->max_magic * 4) { attacker->client->magic = attacker->client->max_magic * 4; } } gi.WriteByte (svc_muzzleflash); gi.WriteShort (targ-g_edicts); gi.WriteByte (MZ_NUKE4); gi.multicast (targ->s.origin, MULTICAST_PVS); } if (manaleech_mult > 0.0) { if (attacker->client->magic < attacker->client->max_magic * 4) { attacker->client->magic += (int) ceil(nosanc_damage * manaleech_mult); if (attacker->client->magic > attacker->client->max_magic * 4) { attacker->client->magic = attacker->client->max_magic * 4; } } if (manaburn_mult == 0.0) { gi.WriteByte (svc_muzzleflash); gi.WriteShort (targ-g_edicts); gi.WriteByte (MZ_NUKE4); gi.multicast (targ->s.origin, MULTICAST_PVS); } } if ((pre_magic != targ->client->magic) && (targ->client->magregentime < level.time + 1.0)) { targ->client->magregentime = level.time + 1.0; } if (damage < 0) { damage = 0; } } // figure momentum add if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) { vec3_t kvel; float mass; if (targ->mass < 50) mass = 50; else mass = targ->mass; if (targ->client && attacker == targ) VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack... else VectorScale (dir, 500.0 * (float)knockback / mass, kvel); VectorAdd (targ->velocity, kvel, targ->velocity); } } take = damage; save = 0; // check for godmode if ((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) && (damage > 0)) { take = 0; save = damage; SpawnDamage (te_sparks, point, normal, save); } // check for invincibility if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION) && (damage > 0)) { if (targ->pain_debounce_time < level.time) { gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } if (take > 0) { if ((targ->client) && (targ->client->damage_time < level.time + 0.5 + take * 0.001)) { targ->client->damage_time = level.time + 0.5 + take * 0.001; } psave = CheckPowerArmor (targ, point, normal, take, dflags); take -= psave; asave = CheckArmor (targ, attacker, point, normal, take, te_sparks, dflags, mod, mod_magic); take -= asave; } // do the damage /* if ((attacker->client) && (targ->svflags & SVF_MONSTER)) { if (take <= 0) { gi.dprintf("NO DAMAGE\n", take); _asm int 3; } }*/ if (rsave > 0) { SpawnDamage (TE_SCREEN_SPARKS, point, normal, rsave); } if (sasave > 0) { SpawnDamage (TE_SHIELD_SPARKS, point, normal, sasave); } if ((take > 0) || ( (take < 0) && (targ->health < 2 * targ->max_health)) ) { targ->health -= take; } if ( (targ->health > 0) && ((take != 0) || (take + asave > 0)) ) { addExp(attacker, targ, take + asave); //Also give exp for killing armor } if (take != 0) { if ((targ->svflags & SVF_MONSTER) || (client)) SpawnDamage (TE_BLOOD, point, normal, take); else SpawnDamage (te_sparks, point, normal, take); if ((attacker->client) && (mod != MOD_TELEFRAG)) /* && (targ->health > 0))*/ { if ((damage > 0) && (attacker->client->pers.skill[34] /*|| (attacker->client->pers.skills.classLevel[4] > 0)*/) && ((targ->health + take) > 0)) { int maxhealth = attacker->max_health * 0.75; maxhealth += 13.5 * pow(attacker->client->pers.skills.classLevel[4], 1.05); if (attacker->health < maxhealth) { float amount = 0; float mult = 0; //mult += 0.001 * pow(attacker->client->pers.skills.classLevel[4], 1.1); // Vampire class level bonus //mult *= 0.4 + 0.6 * ((float) attacker->client->pers.skills.classLevel[4] / (float) attacker->radius_dmg); // Penalty if not pure Vampire mult += 0.01 * attacker->client->pers.skill[34]; //From item powerups if (attacker->client->damage_time > level.time) { mult *= 0.25; } amount = take * mult; if ((mod == MOD_TELEFRAG) || (attacker == targ)) amount = 0; attacker->client->pers.add_health += amount; if (attacker->health > maxhealth) attacker->health = maxhealth; } } } if (targ->health <= 0) { if ((targ->svflags & SVF_MONSTER) || (client)) targ->flags |= FL_NO_KNOCKBACK; Killed (targ, inflictor, attacker, take, point); return take; } } if (take > 0) { if (targ->svflags & SVF_MONSTER) { edict_t *oldenemy = targ->enemy; if (targ->radius_dmg && (targ != attacker) && (attacker->takedamage) && (targ->monsterinfo.ability & GIEX_MABILITY_SHARDARMOR) && targ->monsterinfo.shardtime < (level.time - 0.1)) { vec3_t aim, end; float mult = level.time - targ->monsterinfo.shardtime; if (mult > 1.7) mult = 1.7; mult += 0.2; targ->monsterinfo.shardtime = level.time + 0.2; VectorMA(attacker->s.origin, 0.3, attacker->velocity, end); end[2] += attacker->viewheight; VectorSubtract (end, point, aim); if (targ->monsterinfo.ability & GIEX_MABILITY_DAMAGE) // Damage ability shouldn't affect Shard armor, halve mult mult *= 0.5; monster_fire_blaster (targ, point, aim, (int) ceil((16 + 10 * targ->monsterinfo.skill) * mult), 2200, MZ2_SOLDIER_BLASTER_1, EF_BLASTER); gi.sound(targ, CHAN_AUTO, gi.soundindex("giex/magarm2.wav"), 0.8, ATTN_NORM, 0); } M_ReactToDamage (targ, attacker); if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) { targ->pain_debounce_time = level.time + 2 + 0.1 * targ->monsterinfo.skill; if (oldenemy != NULL) targ->pain (targ, attacker, knockback, take); } } else if (client) { if (!(targ->flags & FL_GODMODE) && (take)) targ->pain (targ, attacker, knockback, take); } else if (take) { if (targ->pain) targ->pain (targ, attacker, knockback, take); } } // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame if (client) { client->damage_parmor += psave; client->damage_armor += (asave + save); client->damage_blood += take; client->damage_knockback += knockback; VectorCopy (point, client->damage_from); } return take; }
// This is a NPC implementation of damage system (incomplete) bool NPC::ApplyDamage(Damage &d) { _log(ITEM__TRACE, "%u: Applying %.1f total damage from %u", GetID(), d.GetTotal(), d.source->GetID()); double total_damage = 0; bool killed = false; int random_damage = 0; double random_damage_mult = 1.0; //apply resistances... //damageResistance? //Shield: double available_shield = m_shieldCharge; Damage shield_damage = d.MultiplyDup( m_self->GetAttribute(AttrShieldKineticDamageResonance).get_float(), m_self->GetAttribute(AttrShieldThermalDamageResonance).get_float(), m_self->GetAttribute(AttrShieldEmDamageResonance).get_float(), m_self->GetAttribute(AttrShieldExplosiveDamageResonance).get_float() ); //other: //emDamageResistanceBonus //explosiveDamageResistanceBonus //kineticDamageResistanceBonus //thermalDamageResistanceBonus // //TODO: deal with seepage from shield into armor. //shieldUniformity //uniformity (chance of seeping through to armor) /* * Here we calculates the uniformity thing. * I think this must be calculated based on * the type of damage -> resistance basis. * double shield_uniformity = available_shield / m_self->shieldCapacity(); if( shield_uniformity < ( 1.0 - m_self->shieldUniformity() ) ) { /* * As far i can see mostly npc/entities have a * chance of transpassing when the shield is below 25% / } */ // Make a random value to use in msg's and attack multiplier random_damage = static_cast<int32>(MakeRandomInt(0, 5)); random_damage_mult = (double)(random_damage / 10.0); // Not sure about this, but with this we get some random hits... :) //total_shield_damage += total_shield_damage * random_damage_mult; shield_damage.SumWithMultFactor( random_damage_mult ); double total_shield_damage = shield_damage.GetTotal(); if(total_shield_damage <= available_shield) { //we can take all this damage with our shield... double new_charge = m_shieldCharge - total_shield_damage; m_shieldCharge = new_charge; total_damage += total_shield_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to shields. New charge: %.1f", GetName(), GetID(), total_shield_damage, new_charge); } else { //first determine how much we can actually apply to //the shield, the rest goes further down. double consumed_shield_ratio = available_shield / shield_damage.GetTotal(); d *= 1.0 - consumed_shield_ratio; if(available_shield > 0) { total_damage += available_shield; _log(ITEM__TRACE, "%s(%us): Shield depleated with %.1f damage. %.1f damage remains.", GetName(), GetID(), available_shield, d.GetTotal()); //set shield to 0, it is fully depleated. m_shieldCharge = 0; } //Armor: double available_armor = m_self->GetAttribute(AttrArmorHP).get_float() - m_armorDamage; Damage armor_damage = d.MultiplyDup( m_self->GetAttribute(AttrArmorKineticDamageResonance).get_float(), m_self->GetAttribute(AttrArmorThermalDamageResonance).get_float(), m_self->GetAttribute(AttrArmorEmDamageResonance).get_float(), m_self->GetAttribute(AttrArmorExplosiveDamageResonance).get_float() ); //other: //activeEmResistanceBonus //activeExplosiveResistanceBonus //activeThermicResistanceBonus //activeKineticResistanceBonus //passiveEmDamageResistanceBonus //passiveExplosiveDamageResistanceBonus //passiveKineticDamageResistanceBonus //passiveThermicDamageResistanceBonus //TODO: figure out how much passes through to structure/modules. //armorUniformity // Not sure about this, but with this we get some random hits... :) //total_armor_damage += total_armor_damage * random_damage_mult; armor_damage.SumWithMultFactor( random_damage_mult ); double total_armor_damage = armor_damage.GetTotal(); if(total_armor_damage <= available_armor) { //we can take all this damage with our armor... double new_damage = m_armorDamage + total_armor_damage; m_armorDamage = new_damage; total_damage += total_armor_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to armor. New armor damage: %.1f", GetName(), GetID(), total_armor_damage, new_damage); } else { //first determine how much we can actually apply to //the armor, the rest goes further down. double consumed_armor_ratio = available_armor / armor_damage.GetTotal(); d *= 1.0 - consumed_armor_ratio; if(available_armor > 0) { total_damage += available_armor; _log(ITEM__TRACE, "%s(%u): Armor depleated with %.1f damage. %.1f damage remains.", GetName(), GetID(), available_armor, d.GetTotal()); //all armor has been penetrated. m_armorDamage = m_self->GetAttribute(AttrArmorHP).get_float(); } //Hull/Structure: //The base hp and damage attributes represent structure. double available_hull = m_self->GetAttribute(AttrHp).get_float() - m_hullDamage; Damage hull_damage = d.MultiplyDup( m_self->GetAttribute(AttrHullKineticDamageResonance).get_float(), m_self->GetAttribute(AttrHullThermalDamageResonance).get_float(), m_self->GetAttribute(AttrHullEmDamageResonance).get_float(), m_self->GetAttribute(AttrHullExplosiveDamageResonance).get_float() ); //other: //passiveEmDamageResonanceMultiplier //passiveThermalDamageResonanceMultiplier //passiveKineticDamageResonanceMultiplier //passiveExplosiveDamageResonanceMultiplier //activeEmDamageResonance //activeThermalDamageResonance //activeKineticDamageResonance //activeExplosiveDamageResonance //structureUniformity // Not sure about this, but with this we get some random hits... :) //total_hull_damage += total_hull_damage * random_damage_mult; hull_damage.SumWithMultFactor( random_damage_mult ); double total_hull_damage = hull_damage.GetTotal(); total_damage += total_hull_damage; if(total_hull_damage < available_hull) { //we can take all this damage with our hull... double new_damage = m_hullDamage + total_hull_damage; m_hullDamage = new_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to structure. New structure damage: %.1f", GetName(), GetID(), total_hull_damage, new_damage); } else { //dead.... _log(ITEM__TRACE, "%s(%u): %.1f damage has depleated our structure. Time to explode.", GetName(), GetID(), total_hull_damage); killed = true; //m_hullDamage = m_self->hp(); m_hullDamage = m_self->GetAttribute(AttrHp).get_float(); } //TODO: deal with damaging modules. no idea the mechanics on this. } } //if( total_damage <= 0.0 ) // return(killed); PyTuple *up; //Notifications to ourself: Notify_OnEffectHit noeh; noeh.itemID = d.source->GetID(); noeh.effectID = d.effect; noeh.targetID = GetID(); noeh.damage = total_damage; up = noeh.Encode(); QueueDestinyEvent(&up); PySafeDecRef( up ); //NOTE: could send out the RD version of this message instead of the R version, which //includes "weapon" and "owner" instead of "source". Notify_OnDamageMessage_Self ondam; //ondam.messageID = "AttackHit2R"; //TODO: randomize/select this somehow. ondam.messageID = DamageMessageIDs_Self[random_damage]; ondam.damage = total_damage; ondam.source = d.source->GetID(); ondam.splash = ""; up = ondam.Encode(); QueueDestinyEvent(&up); PySafeDecRef( up ); //Notifications to others: //I am not sure what the correct scope of this broadcast //should be. For now, it goes to anybody targeting us. if(targets.IsTargetedBySomething()) { up = noeh.Encode(); targets.QueueTBDestinyEvent(&up); PySafeDecRef( up ); Notify_OnDamageMessage_Other ondamo; //ondamo.messageID = "AttackHit3"; //TODO: select this based on the severity of the hit... ondamo.messageID = DamageMessageIDs_Other[random_damage]; ondamo.format_type = fmtMapping_itemTypeName; ondamo.weaponType = d.weapon->typeID(); ondamo.damage = total_damage; ondamo.target = GetID(); ondamo.splash = ""; up = ondamo.Encode(); targets.QueueTBDestinyEvent(&up); PySafeDecRef( up ); } if(killed == true) { Killed(d); } else { _SendDamageStateChanged(); } return(killed); }
/* ============ idActor::Damage this entity that is being damaged inflictor entity that is causing the damage attacker entity that caused the inflictor to damage targ example: this=monster, inflictor=rocket, attacker=player dir direction of the attack for knockback in global space point point at which the damage is being inflicted, used for headshots damage amount of damage being inflicted inflictor, attacker, dir, and point can be NULL for environmental effects Bleeding wounds and surface overlays are applied in the collision code that calls Damage() ============ */ void idActor::Damage( idEntity *inflictor, idEntity *attacker, const noVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { if ( !fl.takedamage ) { return; } if ( !inflictor ) { inflictor = gameLocal.world; } if ( !attacker ) { attacker = gameLocal.world; } #if 0 #ifdef _D3XP SetTimeState ts( timeGroup ); // Helltime boss is immune to all projectiles except the helltime killer if ( finalBoss && idStr::Icmp(inflictor->GetEntityDefName(), "projectile_helltime_killer") ) { return; } // Maledict is immume to the falling asteroids if ( !idStr::Icmp( GetEntityDefName(), "monster_boss_d3xp_maledict" ) && (!idStr::Icmp( damageDefName, "damage_maledict_asteroid" ) || !idStr::Icmp( damageDefName, "damage_maledict_asteroid_splash" ) ) ) { return; } #else if ( finalBoss && !inflictor->IsType( idSoulCubeMissile::Type ) ) { return; } #endif #endif const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); if ( !damageDef ) { gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); } int damage = damageDef->GetInt( "damage" ) * damageScale; damage = GetDamageForLocation( damage, location ); // inform the attacker that they hit someone attacker->DamageFeedback( this, inflictor, damage ); if ( damage > 0 ) { health -= damage; #ifdef _D3XP //Check the health against any damage cap that is currently set if(damageCap >= 0 && health < damageCap) { health = damageCap; } #endif if ( health <= 0 ) { if ( health < -999 ) { health = -999; } Killed( inflictor, attacker, damage, dir, location ); if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) { Gib( dir, damageDefName ); } } else { Pain( inflictor, attacker, damage, dir, location ); } } else { // don't accumulate knockback if ( af.IsLoaded() ) { // clear impacts af.Rest(); // physics is turned off by calling af.Rest() BecomeActive( TH_PHYSICS ); } } }
void T_Damage (edict_t * targ, edict_t * inflictor, edict_t * attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) { gclient_t *client; char buf[256]; int take, save; int asave, psave; int te_sparks, do_sparks = 0; int damage_type = 0; // used for MOD later int bleeding = 0; // damage causes bleeding int head_success = 0; int instant_dam = 1; float z_rel; int height; float from_top; vec_t dist; float targ_maxs2; //FB 6/1/99 // do this before teamplay check if (!targ->takedamage) return; //FIREBLADE if (teamplay->value && mod != MOD_TELEFRAG) { if (lights_camera_action) return; // AQ2:TNG - JBravo adding UVtime if (ctf->value && targ->client) { if(targ->client->ctf_uvtime > 0) return; if (attacker->client && attacker->client->ctf_uvtime > 0) return; } // AQ2:TNG - JBravo adding FF after rounds if (targ != attacker && targ->client && attacker->client && targ->client->resp.team == attacker->client->resp.team && ((int)(dmflags->value) & (DF_NO_FRIENDLY_FIRE))) { if (team_round_going) return; else if (!ff_afterround->value) return; } // AQ:TNG } //FIREBLADE if (dm_shield->value && targ->client) { if (targ->client->ctf_uvtime > 0) return; if (attacker->client && attacker->client->ctf_uvtime > 0) return; } // damage reduction for shotgun // if far away, reduce it to original action levels if (mod == MOD_M3) { dist = Distance(targ->s.origin, inflictor->s.origin); if (dist > 450.0) damage = damage - 2; } targ_maxs2 = targ->maxs[2]; if (targ_maxs2 == 4) targ_maxs2 = CROUCHING_MAXS2; //FB 6/1/99 height = abs (targ->mins[2]) + targ_maxs2; // locational damage code // base damage is head shot damage, so all the scaling is downwards if (targ->client) { if (!((targ != attacker) && ((deathmatch->value && ((int)dmflags->value & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value) && (attacker && attacker->client && OnSameTeam (targ, attacker) && ((int)dmflags->value & DF_NO_FRIENDLY_FIRE) && (team_round_going && ff_afterround->value)))) { // TNG Stats - Add +1 to hit, make sure that hc and m3 are handles differently if ((attacker->client) && (mod != MOD_M3) && (mod != MOD_HC)) { strcpy(attacker->client->resp.last_damaged_players, targ->client->pers.netname); if (!teamplay->value || team_round_going || stats_afterround->value) { attacker->client->resp.stats_hits[mod]++; attacker->client->resp.stats_shots_h++; } } // TNG Stats END if (mod == MOD_MK23 || mod == MOD_MP5 || mod == MOD_M4 || mod == MOD_SNIPER || mod == MOD_DUAL || mod == MOD_KNIFE || mod == MOD_KNIFE_THROWN) { z_rel = point[2] - targ->s.origin[2]; from_top = targ_maxs2 - z_rel; if (from_top < 0.0) //FB 6/1/99 from_top = 0.0; //Slightly negative values were being handled wrong bleeding = 1; instant_dam = 0; // damage reduction for longer range pistol shots if (mod == MOD_MK23 || mod == MOD_DUAL) { dist = Distance(targ->s.origin, inflictor->s.origin); if (dist > 600.0 && dist < 1400.0) damage = (int) (damage * 2 / 3); else if (dist > 1400.0) damage = (int) (damage * 1 / 2); } //gi.cprintf(targ, PRINT_HIGH, "z_rel is %f\n leg: %f stomach: %f chest: %f\n", z_rel, LEG_DAMAGE, STOMACH_DAMAGE, CHEST_DAMAGE ); //gi.cprintf(targ, PRINT_HIGH, "point[2]: %f targ->s.origin[2]: %f height: %d\n", point[2], targ->s.origin[2], height ); //gi.cprintf(targ, PRINT_HIGH, "abs(trag->min[2]): %d targ_max[2] %d\n", (int)abs(targ->mins[2]), (int)targ_maxs2); //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[2]): %d targ_max[2] %d\n", (int)abs(targ->mins[2]), (int)targ_maxs2); //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[0]): %d targ_max[0] %d\n", (int)abs(targ->mins[0]), (int)targ->maxs[0]); //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[1]): %d targ_max[1] %d\n", (int)abs(targ->mins[1]), (int)targ->maxs[1]); if (from_top < 2 * HEAD_HEIGHT) { vec3_t new_point; VerifyHeadShot (point, dir, HEAD_HEIGHT, new_point); VectorSubtract (new_point, targ->s.origin, new_point); //gi.cprintf(attacker, PRINT_HIGH, "z: %d y: %d x: %d\n", (int)(targ_maxs2 - new_point[2]),(int)(new_point[1]) , (int)(new_point[0]) ); if ((targ_maxs2 - new_point[2]) < HEAD_HEIGHT && (abs (new_point[1])) < HEAD_HEIGHT * .8 && (abs (new_point[0])) < HEAD_HEIGHT * .8) { head_success = 1; } } if (head_success) { if (attacker->client) { if (!teamplay->value || team_round_going || stats_afterround->value) { attacker->client->resp.stats_headshot[mod]++; } //AQ2:TNG Slicer Last Damage Location if (INV_AMMO(targ, HELM_NUM)) { attacker->client->resp.last_damaged_part = LOC_KVLR_HELMET; if ((!teamplay->value || team_round_going || stats_afterround->value)) attacker->client->resp.stats_locations[LOC_KVLR_HELMET]++; } else { attacker->client->resp.last_damaged_part = LOC_HDAM; if ((!teamplay->value || team_round_going || stats_afterround->value)) attacker->client->resp.stats_locations[LOC_HDAM]++; } //AQ2:TNG END if (!OnSameTeam (targ, attacker)) attacker->client->resp.hs_streak++; // AQ:TNG Igor[Rock] changing sound dir if (attacker->client->resp.hs_streak == 3) { if (use_rewards->value) { sprintf (buf, "ACCURACY %s!", attacker->client->pers.netname); CenterPrintAll (buf); gi.sound (&g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD, gi.soundindex ("tng/accuracy.wav"), 1.0, ATTN_NONE, 0.0); } attacker->client->resp.hs_streak = 0; } // end of changing sound dir } if (INV_AMMO(targ, HELM_NUM) && mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN && mod != MOD_SNIPER) { if (attacker->client) { gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Helmet - AIM FOR THE BODY!\n", targ->client->pers.netname); gi.cprintf (targ, PRINT_HIGH, "Kevlar Helmet absorbed a part of %s's shot\n", attacker->client->pers.netname); } gi.sound (targ, CHAN_ITEM, gi.soundindex("misc/vest.wav"), 1, ATTN_NORM, 0); damage = (int) (damage / 2); damage_type = LOC_HDAM; bleeding = 0; instant_dam = 1; stopAP = 1; do_sparks = 1; } else if (INV_AMMO(targ, HELM_NUM) && mod == MOD_SNIPER) { if (attacker->client) { gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Helmet, too bad you have AP rounds...\n", targ->client->pers.netname); gi.cprintf (targ, PRINT_HIGH, "Kevlar Helmet absorbed some of %s's AP sniper round\n", attacker->client->pers.netname); } damage = (int) (damage * 0.325); gi.sound (targ, CHAN_VOICE, gi.soundindex("misc/headshot.wav"), 1, ATTN_NORM, 0); damage_type = LOC_HDAM; } else { damage = damage * 1.8 + 1; gi.cprintf (targ, PRINT_HIGH, "Head damage\n"); if (attacker->client) gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the head\n", targ->client->pers.netname); damage_type = LOC_HDAM; if (mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN) gi.sound (targ, CHAN_VOICE, gi.soundindex ("misc/headshot.wav"), 1, ATTN_NORM, 0); //else // gi.sound(targ, CHAN_VOICE, gi.soundindex("misc/glurp.wav"), 1, ATTN_NORM, 0); } } else if (z_rel < LEG_DAMAGE) { damage = damage * .25; gi.cprintf (targ, PRINT_HIGH, "Leg damage\n"); if (attacker->client) { attacker->client->resp.hs_streak = 0; gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the legs\n", targ->client->pers.netname); } damage_type = LOC_LDAM; if (!heroes->value || targ->client->resp.team == 2) { // ESJ Heroes don't run out targ->client->leg_damage = 1; targ->client->leghits++; } //AQ2:TNG Slicer Last Damage Location attacker->client->resp.last_damaged_part = LOC_LDAM; //AQ2:TNG END if (!teamplay->value || team_round_going || stats_afterround->value) attacker->client->resp.stats_locations[LOC_LDAM]++; // TNG Stats } else if (z_rel < STOMACH_DAMAGE) { damage = damage * .4; gi.cprintf (targ, PRINT_HIGH, "Stomach damage\n"); if (attacker->client) { attacker->client->resp.hs_streak = 0; gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the stomach\n", targ->client->pers.netname); } damage_type = LOC_SDAM; //TempFile bloody gibbing if (mod == MOD_SNIPER && sv_gib->value) ThrowGib (targ, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); //AQ2:TNG Slicer Last Damage Location attacker->client->resp.last_damaged_part = LOC_SDAM; //AQ2:TNG END if (!teamplay->value || team_round_going || stats_afterround->value) attacker->client->resp.stats_locations[LOC_SDAM]++; // TNG Stats } else //(z_rel < CHEST_DAMAGE) { if (attacker->client) { attacker->client->resp.hs_streak = 0; } if (INV_AMMO(targ, KEV_NUM) && mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN && mod != MOD_SNIPER) { if (attacker->client) { gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Vest - AIM FOR THE HEAD!\n", targ->client->pers.netname); gi.cprintf (targ, PRINT_HIGH, "Kevlar Vest absorbed most of %s's shot\n", attacker->client->pers.netname); /* if (IsFemale(targ)) gi.cprintf(attacker, PRINT_HIGH, "You bruised %s through her Kevlar Vest\n", targ->client->pers.netname); else gi.cprintf(attacker, PRINT_HIGH, "You bruised %s through his Kevlar Vest\n", targ->client->pers.netname); */ } gi.sound (targ, CHAN_ITEM, gi.soundindex ("misc/vest.wav"), 1, ATTN_NORM, 0); damage = (int) (damage / 10); damage_type = LOC_CDAM; bleeding = 0; instant_dam = 1; stopAP = 1; do_sparks = 1; } else if (INV_AMMO(targ, KEV_NUM) && mod == MOD_SNIPER) { if (attacker->client) { gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Vest, too bad you have AP rounds...\n", targ->client->pers.netname); gi.cprintf (targ, PRINT_HIGH, "Kevlar Vest absorbed some of %s's AP sniper round\n", attacker->client->pers.netname); } damage = damage * .325; damage_type = LOC_CDAM; } else { damage = damage * .65; gi.cprintf (targ, PRINT_HIGH, "Chest damage\n"); if (attacker->client) gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the chest\n", targ->client->pers.netname); damage_type = LOC_CDAM; //TempFile bloody gibbing if (mod == MOD_SNIPER && sv_gib->value) ThrowGib (targ, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); } //AQ2:TNG Slicer Last Damage Location if (INV_AMMO(targ, KEV_NUM) && mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN) { attacker->client->resp.last_damaged_part = LOC_KVLR_VEST; if (!teamplay->value || team_round_going || stats_afterround->value) attacker->client->resp.stats_locations[LOC_KVLR_VEST]++; // TNG Stats } else { attacker->client->resp.last_damaged_part = LOC_CDAM; if (!teamplay->value || team_round_going || stats_afterround->value) attacker->client->resp.stats_locations[LOC_CDAM]++; // TNG Stats } //AQ2:TNG END } /*else { // no mod to damage gi.cprintf(targ, PRINT_HIGH, "Head damage\n"); if (attacker->client) gi.cprintf(attacker, PRINT_HIGH, "You hit %s in the head\n", targ->client->pers.netname); damage_type = LOC_HDAM; gi.sound(targ, CHAN_VOICE, gi.soundindex("misc/headshot.wav"), 1, ATTN_NORM, 0); } */ } if (team_round_going && attacker->client && targ != attacker && OnSameTeam (targ, attacker)) { Add_TeamWound (attacker, targ, mod); } } } if (damage_type && !instant_dam) // bullets but not vest hits { vec3_t temp; vec3_t temporig; //vec3_t forward; VectorMA (targ->s.origin, 50, dir, temp); //AngleVectors (attacker->client->v_angle, forward, NULL, NULL); VectorScale (dir, 20, temp); VectorAdd (point, temp, temporig); if (mod != MOD_SNIPER) spray_blood (targ, temporig, dir, damage, mod); else spray_sniper_blood (targ, temporig, dir); } if (mod == MOD_FALLING && !(targ->flags & FL_GODMODE) ) { if (!heroes->value || targ->client->resp.team == 2) { // ESJ no limp for heroes if (targ->client && targ->health > 0) { gi.cprintf (targ, PRINT_HIGH, "Leg damage\n"); targ->client->leg_damage = 1; targ->client->leghits++; // bleeding = 1; for testing } } } if (heroes->value && targ->client && targ->client->resp.team == 1) //ESJ take damage or give points, depending { if (attacker->client) //not fall damage or the like { attacker->client->points += damage; while (attacker->client->points >= 100) { attacker->client->resp.score++; attacker->client->points -= 100; } } damage = 0; } // friendly fire avoidance // if enabled you can't hurt teammates (but you can hurt yourself) // knockback still occurs if (targ != attacker && ((deathmatch->value && ((int)dmflags->value & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) { if (OnSameTeam (targ, attacker)) { if ((int)dmflags->value & DF_NO_FRIENDLY_FIRE && (team_round_going || !ff_afterround->value)) damage = 0; else mod |= MOD_FRIENDLY_FIRE; } } meansOfDeath = mod; locOfDeath = damage_type; // location client = targ->client; if (dflags & DAMAGE_BULLET) te_sparks = TE_BULLET_SPARKS; else te_sparks = TE_SPARKS; VectorNormalize (dir); // bonus damage for suprising a monster // if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0)) // damage *= 2; if (targ->flags & FL_NO_KNOCKBACK) knockback = 0; // figure momentum add if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) { vec3_t kvel, flydir; float mass; if (mod != MOD_FALLING) { VectorCopy (dir, flydir); flydir[2] += 0.4f; } if (targ->mass < 50) mass = 50; else mass = targ->mass; if (targ->client && attacker == targ) VectorScale (flydir, 1600.0 * (float) knockback / mass, kvel); // the rocket jump hack... else VectorScale (flydir, 500.0 * (float) knockback / mass, kvel); // FB //if (mod == MOD_KICK ) //{ // kvel[2] = 0; //} VectorAdd (targ->velocity, kvel, targ->velocity); } } take = damage; save = 0; // check for godmode if ((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION)) { take = 0; save = damage; SpawnDamage (te_sparks, point, normal, save); } // zucc don't need this stuff, but to remove it need to change how damagefeedback works with colors // check for invincibility if ((client && client->invincible_framenum > level.framenum) && !(dflags & DAMAGE_NO_PROTECTION)) { if (targ->pain_debounce_time < level.time) { gi.sound (targ, CHAN_ITEM, gi.soundindex ("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } psave = CheckPowerArmor (targ, point, normal, take, dflags); take -= psave; asave = CheckArmor (targ, point, normal, take, te_sparks, dflags); take -= asave; //treat cheat/powerup savings the same as armor asave += save; // team damage avoidance if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker)) return; if ((mod == MOD_M3) || (mod == MOD_HC) || (mod == MOD_HELD_GRENADE) || (mod == MOD_HG_SPLASH) || (mod == MOD_G_SPLASH) || (mod == MOD_BREAKINGGLASS)) { //FB 6/3/99 - shotgun damage report stuff int playernum = targ - g_edicts; playernum--; if (playernum >= 0 && playernum <= game.maxclients - 1) *(took_damage + playernum) = 1; //FB 6/3/99 bleeding = 1; instant_dam = 0; } /* if ( (mod == MOD_M3) || (mod == MOD_HC) ) { instant_dam = 1; remain = take % 2; take = (int)(take/2); // balances out difference in how action and axshun handle damage/bleeding } */ if (ctf->value) CTFCheckHurtCarrier (targ, attacker); // do the damage if (take) { // zucc added check for stopAP, if it hit a vest we want sparks if (((targ->svflags & SVF_MONSTER) || (client)) && !do_sparks) SpawnDamage (TE_BLOOD, point, normal, take); else SpawnDamage (te_sparks, point, normal, take); // all things that have at least some instantaneous damage, i.e. bruising/falling if (instant_dam) targ->health = targ->health - take; if (targ->health <= 0) { if (client && attacker->client) { //Added these here also, if this is the last shot and before shots is from //different attacker, msg's would go to wrong client -M if (!OnSameTeam (attacker, targ)) attacker->client->resp.damage_dealt += damage; client->attacker = attacker; client->attacker_mod = mod; client->attacker_loc = damage_type; } if ((targ->svflags & SVF_MONSTER) || (client)) targ->flags |= FL_NO_KNOCKBACK; Killed (targ, inflictor, attacker, take, point); return; } } if (targ->svflags & SVF_MONSTER) { M_ReactToDamage (targ, attacker); if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) { targ->pain (targ, attacker, knockback, take); // nightmare mode monsters don't go into pain frames often if (skill->value == 3) targ->pain_debounce_time = level.time + 5; } } else if (client) { if (!(targ->flags & FL_GODMODE) && (take)) targ->pain (targ, attacker, knockback, take); } else if (take) { if (targ->pain) targ->pain (targ, attacker, knockback, take); } // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame if (client) { client->damage_parmor += psave; client->damage_armor += asave; client->damage_blood += take; client->damage_knockback += knockback; //zucc handle adding bleeding here if (damage_type && bleeding) // one of the hit location weapons { /* zucc add in partial bleeding, changed if ( client->bleeding < 4*damage*BLEED_TIME ) { client->bleeding = 4*damage*BLEED_TIME + client->bleeding/2; } else { client->bleeding += damage*BLEED_TIME*2; } */ client->bleeding += damage * BLEED_TIME; VectorSubtract (point, targ->absmax, targ->client->bleedloc_offset); //VectorSubtract(point, targ->s.origin, client->bleedloc_offset); } else if (bleeding) { /* if ( client->bleeding < damage*BLEED_TIME ) { client->bleeding = damage*BLEED_TIME; //client->bleedcount = 0; } */ client->bleeding += damage * BLEED_TIME; VectorSubtract (point, targ->absmax, targ->client->bleedloc_offset); //VectorSubtract(point, targ->s.origin, client->bleedloc_offset); } if (attacker->client) { if (!OnSameTeam (attacker, targ)) attacker->client->resp.damage_dealt += damage; client->attacker = attacker; client->attacker_mod = mod; client->attacker_loc = damage_type; client->push_timeout = 50; //VectorCopy(dir, client->bleeddir ); //VectorCopy(point, client->bleedpoint ); //VectorCopy(normal, client->bleednormal); } VectorCopy (point, client->damage_from); } }
bool ETHParticleManager::UpdateParticleSystem( const Vector2& v2Pos, const Vector3& v3Pos, const float angle, const unsigned long lastFrameElapsedTime) { bool anythingDrawn = false; const unsigned long cappedLastFrameElapsedTime = Min(lastFrameElapsedTime, static_cast<unsigned long>(250)); const float frameSpeed = static_cast<float>((static_cast<double>(cappedLastFrameElapsedTime) / 1000.0) * 60.0); Matrix4x4 rot = RotateZ(DegreeToRadian(angle)); m_nActiveParticles = 0; for (int t = 0; t < m_system.nParticles; t++) { PARTICLE& particle = m_particles[t]; if (m_system.repeat > 0) if (particle.repeat >= m_system.repeat) continue; // check how many particles are active if (particle.size > 0.0f && particle.released) { if (!Killed() || (Killed() && particle.elapsed < particle.lifeTime)) m_nActiveParticles++; } anythingDrawn = true; particle.elapsed += lastFrameElapsedTime; if (!particle.released) { // if we shouldn't release all particles at the same time, check if it's time to release this particle const float releaseTime = ((m_system.lifeTime + m_system.randomizeLifeTime) * (static_cast<float>(particle.id) / static_cast<float>(m_system.nParticles))); if (particle.elapsed > releaseTime || m_system.allAtOnce) { particle.elapsed = 0.0f; particle.released = true; PositionParticle(t, v2Pos, angle, rot, v3Pos); } } if (particle.released) { particle.dir += (m_system.gravityVector * frameSpeed); particle.pos += (particle.dir * frameSpeed); particle.angle += (particle.angleDir * frameSpeed); particle.size += (m_system.growth * frameSpeed); const float w = particle.elapsed / particle.lifeTime; particle.color = m_system.color0 + (m_system.color1 - m_system.color0) * w; // update particle animation if there is any if (m_system.spriteCut.x > 1 || m_system.spriteCut.y > 1) { if (m_system.animationMode == ETHParticleSystem::PLAY_ANIMATION) { particle.currentFrame = static_cast<unsigned int>( Min(static_cast<int>(static_cast<float>(m_system.GetNumFrames()) * w), m_system.GetNumFrames() - 1)); } } particle.size = Min(particle.size, m_system.maxSize); particle.size = Max(particle.size, m_system.minSize); if (particle.elapsed > particle.lifeTime) { particle.repeat++; if (!Killed()) ResetParticle(t, v2Pos, v3Pos, angle, rot); } } } m_finished = !anythingDrawn; // manages the sound HandleSoundPlayback(v2Pos, frameSpeed); return true; }
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) { gclient_t *client; int take; int save; int asave; int psave; int te_sparks; if (!targ->takedamage) return; // friendly fire avoidance // if enabled you can't hurt teammates (but you can hurt yourself) // knockback still occurs if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) { if (OnSameTeam (targ, attacker)) { if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) damage = 0; else mod |= MOD_FRIENDLY_FIRE; } } meansOfDeath = mod; // easy mode takes half damage if (skill->value == 0 && deathmatch->value == 0 && targ->client) { damage *= 0.5; if (!damage) damage = 1; } client = targ->client; if (dflags & DAMAGE_BULLET) te_sparks = TE_BULLET_SPARKS; else te_sparks = TE_SPARKS; VectorNormalize(dir); // bonus damage for suprising a monster if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0)) damage *= 2; if (targ->flags & FL_NO_KNOCKBACK) knockback = 0; // figure momentum add if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) { vec3_t kvel; float mass; if (targ->mass < 50) mass = 50; else mass = targ->mass; if (targ->client && attacker == targ) VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack... else VectorScale (dir, 500.0 * (float)knockback / mass, kvel); VectorAdd (targ->velocity, kvel, targ->velocity); } } take = damage; save = 0; // check for godmode if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) ) { take = 0; save = damage; SpawnDamage (te_sparks, point, normal, save); } // check for invincibility if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION)) { if (targ->pain_debounce_time < level.time) { gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } psave = CheckPowerArmor (targ, point, normal, take, dflags); take -= psave; asave = CheckArmor (targ, point, normal, take, te_sparks, dflags); take -= asave; //treat cheat/powerup savings the same as armor asave += save; // team damage avoidance if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker)) return; // do the damage if (take) { if ((targ->svflags & SVF_MONSTER) || (client)) SpawnDamage (TE_BLOOD, point, normal, take); else SpawnDamage (te_sparks, point, normal, take); targ->health = targ->health - take; if (targ->health <= 0) { if ((targ->svflags & SVF_MONSTER) || (client)) targ->flags |= FL_NO_KNOCKBACK; Killed (targ, inflictor, attacker, take, point); return; } } if (targ->svflags & SVF_MONSTER) { M_ReactToDamage (targ, attacker); if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) { targ->pain (targ, attacker, knockback, take); // nightmare mode monsters don't go into pain frames often if (skill->value == 3) targ->pain_debounce_time = level.time + 5; } } else if (client) { if (!(targ->flags & FL_GODMODE) && (take)) targ->pain (targ, attacker, knockback, take); } else if (take) { if (targ->pain) targ->pain (targ, attacker, knockback, take); } // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame if (client) { client->damage_parmor += psave; client->damage_armor += asave; client->damage_blood += take; client->damage_knockback += knockback; VectorCopy (point, client->damage_from); } }
bool ETHParticleManager::DrawParticleSystem( Vector3 v3Ambient, const float maxHeight, const float minHeight, const DEPTH_SORTING_MODE ownerType, const Vector2& zAxisDirection, const Vector2& parallaxOffset, const float ownerDepth) { if (!m_pBMP) { ETH_STREAM_DECL(ss) << GS_L("ETHParticleManager::DrawParticleSystem: Invalid particle system bitmap"); m_provider->Log(ss.str(), Platform::FileLogger::WARNING); return false; } const VideoPtr& video = m_provider->GetVideo(); Video::ALPHA_MODE alpha = video->GetAlphaMode(); video->SetAlphaMode(m_system.alphaMode); // if the alpha blending is not additive, we'll have to sort it if (alpha == Video::AM_PIXEL) { BubbleSort(m_particles); } m_pBMP->SetOrigin(Sprite::EO_CENTER); for (int t = 0; t < m_system.nParticles; t++) { const PARTICLE& particle = m_particles[t]; if (m_system.repeat > 0) if (particle.repeat >= m_system.repeat) continue; if (particle.size <= 0.0f || !particle.released) continue; if (Killed() && particle.elapsed > particle.lifeTime) continue; Vector3 v3FinalAmbient(1, 1, 1); if (m_system.alphaMode == Video::AM_PIXEL || m_system.alphaMode == Video::AM_ALPHA_TEST) { v3FinalAmbient.x = Min(m_system.emissive.x + v3Ambient.x, 1.0f); v3FinalAmbient.y = Min(m_system.emissive.y + v3Ambient.y, 1.0f); v3FinalAmbient.z = Min(m_system.emissive.z + v3Ambient.z, 1.0f); } Color dwColor; const Vector4& color(particle.color); dwColor.a = (GS_BYTE)(color.w * 255.0f); dwColor.r = (GS_BYTE)(color.x * v3FinalAmbient.x * 255.0f); dwColor.g = (GS_BYTE)(color.y * v3FinalAmbient.y * 255.0f); dwColor.b = (GS_BYTE)(color.z * v3FinalAmbient.z * 255.0f); // compute the right in-screen position const Vector2 v2Pos = ETHGlobal::ToScreenPos(Vector3(particle.pos, m_system.startPoint.z), zAxisDirection); SetParticleDepth(ComputeParticleDepth(ownerType, ownerDepth, particle, maxHeight, minHeight)); // draw if (m_system.spriteCut.x > 1 || m_system.spriteCut.y > 1) { if ((int)m_pBMP->GetNumColumns() != m_system.spriteCut.x || (int)m_pBMP->GetNumRows() != m_system.spriteCut.y) m_pBMP->SetupSpriteRects(m_system.spriteCut.x, m_system.spriteCut.y); m_pBMP->SetRect(particle.currentFrame); } else { m_pBMP->UnsetRect(); } m_pBMP->DrawOptimal((v2Pos + parallaxOffset), dwColor, particle.angle, Vector2(particle.size, particle.size)); } video->SetAlphaMode(alpha); return true; }
/* ============ TakeDamage The damage is coming from inflictor, but get mad at attacker This should be the only function that ever reduces health. bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK Time-based damage: only occurs while the monster is within the trigger_hurt. When a monster is poisoned via an arrow etc it takes all the poison damage at once. GLOBALS ASSUMED SET: g_iSkillLevel ============ */ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { float flTake; Vector vecDir; if (!pev->takedamage) return 0; if ( !IsAlive() ) { return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } if ( pev->deadflag == DEAD_NO ) { // no pain sound during death animation. PainSound();// "Ouch!" } //!!!LATER - make armor consideration here! flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). vecDir = Vector( 0, 0, 0 ); if (!FNullEnt( pevInflictor )) { CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); if (pInflictor) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // todo: remove after combining shotgun blasts? if ( IsPlayer() ) { if ( pevInflictor ) pev->dmg_inflictor = ENT(pevInflictor); pev->dmg_take += flTake; // check for godmode or invincibility if ( pev->flags & FL_GODMODE ) { return 0; } } // if this is a player, move him around! if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) { pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); } // do the damage pev->health -= flTake; // HACKHACK Don't kill monsters in a script. Let them break their scripts first if ( m_MonsterState == MONSTERSTATE_SCRIPT ) { SetConditions( bits_COND_LIGHT_DAMAGE ); return 0; } if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; if ( bitsDamageType & DMG_ALWAYSGIB ) { Killed( pevAttacker, GIB_ALWAYS ); } else if ( bitsDamageType & DMG_NEVERGIB ) { Killed( pevAttacker, GIB_NEVER ); } else { Killed( pevAttacker, GIB_NORMAL ); } g_pevLastInflictor = NULL; return 0; } // react to the damage (get mad) if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) { if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) {// only if the attack was a monster or client! // enemy's last known position is somewhere down the vector that the attack came from. if (pevInflictor) { if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) { m_vecEnemyLKP = pevInflictor->origin; } } else { m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); } MakeIdealYaw( m_vecEnemyLKP ); // add pain to the conditions // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and // heavy damage per monster class? if ( flDamage > 0 ) { SetConditions(bits_COND_LIGHT_DAMAGE); } if ( flDamage >= 20 ) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) { gclient_t *client; int take; int save; int asave; int psave; int te_sparks; int sphere_notified; // PGM if (!targ->takedamage) return; sphere_notified = false; // PGM // friendly fire avoidance // if enabled you can't hurt teammates (but you can hurt yourself) // knockback still occurs if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) { if (OnSameTeam (targ, attacker)) { // PMM - nukes kill everyone if (((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) && (mod != MOD_NUKE)) damage = 0; else mod |= MOD_FRIENDLY_FIRE; } } meansOfDeath = mod; //ROGUE // allow the deathmatch game to change values if (deathmatch->value && gamerules && gamerules->value) { if(DMGame.ChangeDamage) damage = DMGame.ChangeDamage(targ, attacker, damage, mod); if(DMGame.ChangeKnockback) knockback = DMGame.ChangeKnockback(targ, attacker, knockback, mod); if(!damage) return; } //ROGUE // easy mode takes half damage if (skill->value == 0 && deathmatch->value == 0 && targ->client) { damage *= 0.5; if (!damage) damage = 1; } client = targ->client; // PMM - defender sphere takes half damage if ((client) && (client->owned_sphere) && (client->owned_sphere->spawnflags == 1)) { damage *= 0.5; if (!damage) damage = 1; } if (dflags & DAMAGE_BULLET) te_sparks = TE_BULLET_SPARKS; else te_sparks = TE_SPARKS; VectorNormalize(dir); // bonus damage for suprising a monster if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0)) damage *= 2; if (targ->flags & FL_NO_KNOCKBACK) knockback = 0; // figure momentum add if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) { vec3_t kvel; float mass; if (targ->mass < 50) mass = 50; else mass = targ->mass; if (targ->client && attacker == targ) VectorScale (dir, 1600.0 * (float)knockback / mass, kvel); // the rocket jump hack... else VectorScale (dir, 500.0 * (float)knockback / mass, kvel); VectorAdd (targ->velocity, kvel, targ->velocity); } } take = damage; save = 0; // check for godmode if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) ) { take = 0; save = damage; SpawnDamage (te_sparks, point, normal, save); } // check for invincibility if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION)) { if (targ->pain_debounce_time < level.time) { gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } // ROGUE // check for monster invincibility if (((targ->svflags & SVF_MONSTER) && targ->monsterinfo.invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION)) { if (targ->pain_debounce_time < level.time) { gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0); targ->pain_debounce_time = level.time + 2; } take = 0; save = damage; } // ROGUE psave = CheckPowerArmor (targ, point, normal, take, dflags); take -= psave; asave = CheckArmor (targ, point, normal, take, te_sparks, dflags); take -= asave; //treat cheat/powerup savings the same as armor asave += save; // team damage avoidance if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker)) return; // ROGUE - this option will do damage both to the armor and person. originally for DPU rounds if (dflags & DAMAGE_DESTROY_ARMOR) { if(!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) && !(client && client->invincible_framenum > level.framenum)) { take = damage; } } // ROGUE // do the damage if (take) { //PGM need more blood for chainfist. if(targ->flags & FL_MECHANICAL) { SpawnDamage ( TE_ELECTRIC_SPARKS, point, normal, take); } else if ((targ->svflags & SVF_MONSTER) || (client)) { if(mod == MOD_CHAINFIST) SpawnDamage (TE_MOREBLOOD, point, normal, 255); else SpawnDamage (TE_BLOOD, point, normal, take); } else SpawnDamage (te_sparks, point, normal, take); //PGM targ->health = targ->health - take; //PGM - spheres need to know who to shoot at if(client && client->owned_sphere) { sphere_notified = true; if(client->owned_sphere->pain) client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0); } //PGM if (targ->health <= 0) { if ((targ->svflags & SVF_MONSTER) || (client)) targ->flags |= FL_NO_KNOCKBACK; Killed (targ, inflictor, attacker, take, point); return; } } //PGM - spheres need to know who to shoot at if (!sphere_notified) { if(client && client->owned_sphere) { if(client->owned_sphere->pain) client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0); } } //PGM if (targ->svflags & SVF_MONSTER) { M_ReactToDamage (targ, attacker, inflictor); // PMM - fixme - if anyone else but the medic ever uses AI_MEDIC, check for it here instead // of in the medic's pain function if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) { targ->pain (targ, attacker, knockback, take); // nightmare mode monsters don't go into pain frames often if (skill->value == 3) targ->pain_debounce_time = level.time + 5; } } else if (client) { if (!(targ->flags & FL_GODMODE) && (take)) targ->pain (targ, attacker, knockback, take); } else if (take) { if (targ->pain) targ->pain (targ, attacker, knockback, take); } // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame if (client) { client->damage_parmor += psave; client->damage_armor += asave; client->damage_blood += take; client->damage_knockback += knockback; VectorCopy (point, client->damage_from); } }
/* ================ idMoveable::Event_Activate ================ */ void idExplodingBarrel::Event_Activate( idEntity *activator ) { Killed( activator, activator, 0, vec3_origin, 0 ); }
/* ================ idExplodingBarrel::Killed ================ */ void idExplodingBarrel::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { // This simple condition causes a barrel to explode when shot while burning #ifdef _DENTONMOD if ( IsHidden() || state == EXPLODING ) { #else if ( IsHidden() || state == EXPLODING || state == BURNING ) { #endif return; } float f = spawnArgs.GetFloat( "burn" ); #ifdef _DENTONMOD int explodeHealth = spawnArgs.GetInt( "explode_health" ); if ( f > 0.0f && state == NORMAL && health > explodeHealth ) { #else if ( f > 0.0f && state == NORMAL ) { #endif state = BURNING; PostEventSec( &EV_Explode, f ); StartSound( "snd_burn", SND_CHANNEL_ANY, 0, false, NULL ); AddParticles( spawnArgs.GetString ( "model_burn", "" ), true ); return; } else { #ifdef _DENTONMOD if( state == BURNING && health > explodeHealth ) { return; } #endif state = EXPLODING; if ( gameLocal.isServer ) { idBitMsg msg; byte msgBuf[MAX_EVENT_PARAM_SIZE]; msg.Init( msgBuf, sizeof( msgBuf ) ); msg.WriteLong( gameLocal.time ); ServerSendEvent( EVENT_EXPLODE, &msg, false, -1 ); } } // do this before applying radius damage so the ent can trace to any damagable ents nearby Hide(); #ifdef _DENTONMOD BecomeInactive(TH_PHYSICS); // This causes the physics not to update after explosion #else physicsObj.SetContents( 0 ); // Set physics content 0 after spawining debris. #endif const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" ); if ( splash && *splash ) { gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, attacker, this, this, splash ); } ExplodingEffects( ); //FIXME: need to precache all the debris stuff here and in the projectiles const idKeyValue *kv = spawnArgs.MatchPrefix( "def_debris" ); // bool first = true; while ( kv ) { const idDict *debris_args = gameLocal.FindEntityDefDict( kv->GetValue(), false ); if ( debris_args ) { idEntity *ent; idVec3 dir; idDebris *debris; //if ( first ) { dir = physicsObj.GetAxis()[1]; // first = false; //} else { dir.x += gameLocal.random.CRandomFloat() * 4.0f; dir.y += gameLocal.random.CRandomFloat() * 4.0f; //dir.z = gameLocal.random.RandomFloat() * 8.0f; //} dir.Normalize(); gameLocal.SpawnEntityDef( *debris_args, &ent, false ); if ( !ent || !ent->IsType( idDebris::Type ) ) { gameLocal.Error( "'projectile_debris' is not an idDebris" ); } debris = static_cast<idDebris *>(ent); debris->Create( this, physicsObj.GetOrigin(), dir.ToMat3() ); debris->Launch(); debris->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = ( gameLocal.time + 1500 ) * 0.001f; debris->UpdateVisuals(); } kv = spawnArgs.MatchPrefix( "def_debris", kv ); } SpawnDrops(); //ivan #ifdef _DENTONMOD physicsObj.SetContents( 0 ); #endif physicsObj.PutToRest(); CancelEvents( &EV_Explode ); CancelEvents( &EV_Activate ); f = spawnArgs.GetFloat( "respawn" ); if ( f > 0.0f ) { PostEventSec( &EV_Respawn, f ); } else { PostEventMS( &EV_Remove, 5000 ); } if ( spawnArgs.GetBool( "triggerTargets" ) ) { ActivateTargets( this ); } //ivan start - add score only if player is the killer if ( attacker && attacker->IsType( idPlayer::Type ) ) { static_cast< idPlayer* >( attacker )->AddScore( spawnArgs.GetInt( "score", "100" ) ); } //ivan end } /* ================ idExplodingBarrel::Damage ================ */ void idExplodingBarrel::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); if ( !damageDef ) { gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName ); } #ifdef _DENTONMOD // Following condition means, if inflictor's got a radius damage then explode immediately, // which could cause explosions when barrel's health is greater than 0 so I am disabling it. #else if ( damageDef->FindKey( "radius" ) && GetPhysics()->GetContents() != 0 && GetBindMaster() == NULL ) { PostEventMS( &EV_Explode, 400 ); } else { #endif idEntity::Damage( inflictor, attacker, dir, damageDefName, damageScale, location ); #ifdef _DENTONMOD #else } #endif } /* ================ idExplodingBarrel::Event_TriggerTargets ================ */ void idExplodingBarrel::Event_TriggerTargets() { ActivateTargets( this ); } /* ================ idExplodingBarrel::Event_Explode ================ */ void idExplodingBarrel::Event_Explode() { if ( state == NORMAL || state == BURNING ) { state = BURNEXPIRED; Killed( NULL, NULL, 0, vec3_zero, 0 ); } } /* ================ idExplodingBarrel::Event_Respawn ================ */ void idExplodingBarrel::Event_Respawn() { int i; int minRespawnDist = spawnArgs.GetInt( "respawn_range", "256" ); if ( minRespawnDist ) { float minDist = -1; for ( i = 0; i < gameLocal.numClients; i++ ) { if ( !gameLocal.entities[ i ] || !gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { continue; } idVec3 v = gameLocal.entities[ i ]->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); float dist = v.Length(); if ( minDist < 0 || dist < minDist ) { minDist = dist; } } if ( minDist < minRespawnDist ) { PostEventSec( &EV_Respawn, spawnArgs.GetInt( "respawn_again", "10" ) ); return; } } const char *temp = spawnArgs.GetString( "model" ); if ( temp && *temp ) { SetModel( temp ); } health = spawnArgs.GetInt( "health", "5" ); fl.takedamage = true; physicsObj.SetOrigin( spawnOrigin ); physicsObj.SetAxis( spawnAxis ); physicsObj.SetContents( CONTENTS_SOLID ); physicsObj.DropToFloor(); state = NORMAL; Show(); UpdateVisuals(); }