#include "b_local.h"#include "bg_saga.h"#include "../namespace_begin.h"#include "../namespace_end.h"Go to the source code of this file.
Defines | |
| #define | DEATH_ALERT_RADIUS 512 |
| #define | DEATH_ALERT_SOUND_RADIUS 512 |
Functions | |
| int | G_ShipSurfaceForSurfName (const char *surfaceName) |
| qboolean | G_FlyVehicleDestroySurface (gentity_t *veh, int surface) |
| void | G_VehicleSetDamageLocFlags (gentity_t *veh, int impactDir, int deathPoint) |
| void | G_VehUpdateShields (gentity_t *targ) |
| void | G_LetGoOfWall (gentity_t *ent) |
| void | BG_ClearRocketLock (playerState_t *ps) |
| void | BotDamageNotification (gclient_t *bot, gentity_t *attacker) |
| void | ThrowSaberToAttacker (gentity_t *self, gentity_t *attacker) |
| void | ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath) |
| qboolean | G_HeavyMelee (gentity_t *attacker) |
| int | G_GetHitLocation (gentity_t *target, vec3_t ppoint) |
| void | ExplodeDeath (gentity_t *self) |
| void | ScorePlum (gentity_t *ent, vec3_t origin, int score) |
| void | AddScore (gentity_t *ent, vec3_t origin, int score) |
| void | TossClientWeapon (gentity_t *self, vec3_t direction, float speed) |
| void | TossClientItems (gentity_t *self) |
| void | LookAtKiller (gentity_t *self, gentity_t *inflictor, gentity_t *attacker) |
| void | GibEntity (gentity_t *self, int killer) |
| void | BodyRid (gentity_t *ent) |
| void | body_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath) |
| void | CheckAlmostCapture (gentity_t *self, gentity_t *attacker) |
| qboolean | G_InKnockDown (playerState_t *ps) |
| int | G_PickDeathAnim (gentity_t *self, vec3_t point, int damage, int mod, int hitLoc) |
| gentity_t * | G_GetJediMaster (void) |
| void | G_AlertTeam (gentity_t *victim, gentity_t *attacker, float radius, float soundDist) |
| void | G_DeathAlert (gentity_t *victim, gentity_t *attacker) |
| void | DeathFX (gentity_t *ent) |
| void | G_CheckVictoryScript (gentity_t *self) |
| void | G_AddPowerDuelScore (int team, int score) |
| void | G_AddPowerDuelLoserScore (int team, int score) |
| void | AI_DeleteSelfFromGroup (gentity_t *self) |
| void | AI_GroupMemberKilled (gentity_t *self) |
| void | Boba_FlyStop (gentity_t *self) |
| qboolean | Jedi_WaitingAmbush (gentity_t *self) |
| void | CheckExitRules (void) |
| void | Rancor_DropVictim (gentity_t *self) |
| void | player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath) |
| int | CheckArmor (gentity_t *ent, int damage, int dflags) |
| void | G_ApplyKnockback (gentity_t *targ, vec3_t newDir, float knockback) |
| int | RaySphereIntersections (vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2]) |
| void | G_GetDismemberLoc (gentity_t *self, vec3_t boltPoint, int limbType) |
| void | G_GetDismemberBolt (gentity_t *self, vec3_t boltPoint, int limbType) |
| void | LimbTouch (gentity_t *self, gentity_t *other, trace_t *trace) |
| void | LimbThink (gentity_t *ent) |
| qboolean | BG_GetRootSurfNameWithVariant (void *ghoul2, const char *rootSurfName, char *returnSurfName, int returnSize) |
| void | G_Dismember (gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath) |
| void | DismembermentTest (gentity_t *self) |
| void | DismembermentByNum (gentity_t *self, int num) |
| int | G_GetHitQuad (gentity_t *self, vec3_t hitloc) |
| void | UpdateClientRenderBolts (gentity_t *self, vec3_t renderOrigin, vec3_t renderAngles) |
| qboolean | G_GetHitLocFromSurfName (gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod) |
| void | G_CheckForDismemberment (gentity_t *ent, gentity_t *enemy, vec3_t point, int damage, int deathAnim, qboolean postDeath) |
| void | G_LocationBasedDamageModifier (gentity_t *ent, vec3_t point, int mod, int dflags, int *damage) |
| qboolean | G_ThereIsAMaster (void) |
| void | G_Knockdown (gentity_t *victim) |
| void | G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod) |
| qboolean | CanDamage (gentity_t *targ, vec3_t origin) |
| qboolean | G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, gentity_t *missile, int mod) |
Variables | |
| qboolean | g_dontPenalizeTeam |
| char * | modNames [MOD_MAX] |
| stringID_table_t | animTable [MAX_ANIMATIONS+1] |
| qboolean | g_dontFrickinCheck |
| qboolean | g_endPDuel |
| qboolean | g_noPDuelCheck |
| char * | hitLocName [HL_MAX] |
| int | gGAvoidDismember = 0 |
| qboolean | gSiegeRoundBegun |
| int | gPainMOD = 0 |
| int | gPainHitLoc = -1 |
| vec3_t | gPainPoint |
|
|
Definition at line 1865 of file g_combat.c. Referenced by G_DeathAlert(). |
|
|
Definition at line 1866 of file g_combat.c. Referenced by G_DeathAlert(). |
|
||||||||||||||||
|
Definition at line 436 of file g_combat.c. References CalculateRanks(), gentity_s::client, g_dontPenalizeTeam, g_gametype, gentity_t, GT_TEAM, vmCvar_t::integer, level, PERS_SCORE, PERS_TEAM, playerState_s::persistant, gclient_s::ps, level_locals_t::teamScores, vec3_t, and level_locals_t::warmupTime. Referenced by AddSiegeWinningTeamPoints(), BroadcastObjectiveCompletion(), player_die(), Team_FragBonuses(), Team_TouchEnemyFlag(), Team_TouchOurFlag(), Use_Target_Escapetrig(), and Use_Target_Score().
00437 {
00438 /*
00439 if (g_gametype.integer == GT_SIEGE)
00440 { //no scoring in this gametype at all.
00441 return;
00442 }
00443 */
00444
00445 if ( !ent->client ) {
00446 return;
00447 }
00448 // no scoring during pre-match warmup
00449 if ( level.warmupTime ) {
00450 return;
00451 }
00452 // show score plum
00453 //ScorePlum(ent, origin, score);
00454 //
00455 ent->client->ps.persistant[PERS_SCORE] += score;
00456 if ( g_gametype.integer == GT_TEAM && !g_dontPenalizeTeam )
00457 level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
00458 CalculateRanks();
00459 }
|
|
|
Definition at line 602 of file NPC_AI_Utils.c. References AI_DeleteGroupMember(), gentity_t, gNPC_t::group, AIGroupInfo_s::member, gentity_s::NPC, AIGroupMember_s::number, entityState_s::number, AIGroupInfo_s::numGroup, and gentity_s::s. Referenced by player_die().
00603 {
00604 int i;
00605
00606 //FIXME: if killed, keep track of how many in group killed? To affect morale?
00607 for ( i = 0; i < self->NPC->group->numGroup; i++ )
00608 {
00609 if ( self->NPC->group->member[i].number == self->s.number )
00610 {
00611 AI_DeleteGroupMember( self->NPC->group, i );
00612 return;
00613 }
00614 }
00615 }
|
|
|
Definition at line 620 of file NPC_AI_Utils.c. References AEL_DANGER_GREAT, AIGroupInfo_t, AIGroupInfo_s::commander, gNPC_t::currentAim, entityShared_t::currentOrigin, AIGroupInfo_s::enemy, g_entities, gentity_t, gNPC_t::group, AIGroupInfo_s::member, AIGroupInfo_s::moraleAdjust, gentity_s::NPC, AIGroupMember_s::number, AIGroupInfo_s::numGroup, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_ENSIGN, AIGroupInfo_s::speechDebounceTime, ST_AggressionAdjust(), ST_MarkToCover(), and ST_StartFlee(). Referenced by player_die().
00621 {
00622 AIGroupInfo_t *group = self->NPC->group;
00623 gentity_t *member;
00624 qboolean noflee = qfalse;
00625 int i;
00626
00627 if ( !group )
00628 {//what group?
00629 return;
00630 }
00631 if ( !self || !self->NPC || self->NPC->rank < RANK_ENSIGN )
00632 {//I'm not an officer, let's not really care for now
00633 return;
00634 }
00635 //temporarily drop group morale for a few seconds
00636 group->moraleAdjust -= self->NPC->rank;
00637 //go through and drop aggression on my teammates (more cover, worse aim)
00638 for ( i = 0; i < group->numGroup; i++ )
00639 {
00640 member = &g_entities[group->member[i].number];
00641 if ( member == self )
00642 {
00643 continue;
00644 }
00645 if ( member->NPC->rank > RANK_ENSIGN )
00646 {//officers do not panic
00647 noflee = qtrue;
00648 }
00649 else
00650 {
00651 ST_AggressionAdjust( member, -1 );
00652 member->NPC->currentAim -= Q_irand( 0, 10 );//Q_irand( 0, 2);//drop their aim accuracy
00653 }
00654 }
00655 //okay, if I'm the group commander, make everyone else flee
00656 if ( group->commander != self )
00657 {//I'm not the commander... hmm, should maybe a couple flee... maybe those near me?
00658 return;
00659 }
00660 //now see if there is another of sufficient rank to keep them from fleeing
00661 if ( !noflee )
00662 {
00663 self->NPC->group->speechDebounceTime = 0;
00664 for ( i = 0; i < group->numGroup; i++ )
00665 {
00666 member = &g_entities[group->member[i].number];
00667 if ( member == self )
00668 {
00669 continue;
00670 }
00671 if ( member->NPC->rank < RANK_ENSIGN )
00672 {//grunt
00673 if ( group->enemy && DistanceSquared( member->r.currentOrigin, group->enemy->r.currentOrigin ) < 65536/*256*256*/ )
00674 {//those close to enemy run away!
00675 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00676 }
00677 else if ( DistanceSquared( member->r.currentOrigin, self->r.currentOrigin ) < 65536/*256*256*/ )
00678 {//those close to me run away!
00679 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00680 }
00681 else
00682 {//else, maybe just a random chance
00683 if ( Q_irand( 0, self->NPC->rank ) > member->NPC->rank )
00684 {//lower rank they are, higher rank I am, more likely they are to flee
00685 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00686 }
00687 else
00688 {
00689 ST_MarkToCover( member );
00690 }
00691 }
00692 member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00693 }
00694 member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00695 }
00696 }
00697 }
|
|
|
Definition at line 5751 of file bg_pmove.c. References ENTITYNUM_NONE, playerState_t, playerState_s::rocketLastValidTime, playerState_s::rocketLockIndex, playerState_s::rocketLockTime, and playerState_s::rocketTargetTime. Referenced by player_die(), and PM_BeginWeaponChange().
05752 {
05753 if ( ps )
05754 {
05755 ps->rocketLockIndex = ENTITYNUM_NONE;
05756 ps->rocketLastValidTime = 0;
05757 ps->rocketLockTime = -1;
05758 ps->rocketTargetTime = 0;
05759 }
05760 }
|
|
||||||||||||||||||||
|
Definition at line 101 of file bg_g2_utils.c. References Com_sprintf(), MAX_VARIANTS, Q_strncpyz(), qboolean, qfalse, qtrue, and trap_G2API_GetSurfaceRenderStatus(). Referenced by G_Dismember().
00102 {
00103 if ( !ghoul2 || !trap_G2API_GetSurfaceRenderStatus( ghoul2, 0, rootSurfName ) )
00104 {//see if the basic name without variants is on
00105 Q_strncpyz( returnSurfName, rootSurfName, returnSize );
00106 return qtrue;
00107 }
00108 else
00109 {//check variants
00110 int i;
00111 for ( i = 0; i < MAX_VARIANTS; i++ )
00112 {
00113 Com_sprintf( returnSurfName, returnSize, "%s%c", rootSurfName, 'a'+i );
00114 if ( !trap_G2API_GetSurfaceRenderStatus( ghoul2, 0, returnSurfName ) )
00115 {
00116 return qtrue;
00117 }
00118 }
00119 }
00120 Q_strncpyz( returnSurfName, rootSurfName, returnSize );
00121 return qfalse;
00122 }
|
|
|
Definition at line 367 of file NPC_AI_Jedi.c.
00368 {
00369 self->client->ps.gravity = g_gravity.value;
00370 if ( self->NPC )
00371 {
00372 self->NPC->aiFlags &= ~NPCAI_CUSTOM_GRAVITY;
00373 }
00374 self->client->ps.eFlags2 &= ~EF2_FLYING;
00375 self->client->jetPackTime = 0;
00376 //stop jet loop sound
00377 self->s.loopSound = 0;
00378 if ( self->NPC )
00379 {
00380 self->count = 0; // SEEKER shot ammo count
00381 TIMER_Set( self, "jetRecharge", Q_irand( 1000, 5000 ) );
00382 TIMER_Set( self, "jumpChaseDebounce", Q_irand( 500, 2000 ) );
00383 }
00384 }
|
|
||||||||||||||||||||||||
|
Definition at line 685 of file g_combat.c. References BodyRid(), gentity_s::client, entityShared_t::currentOrigin, EF_DISINTEGRATION, playerState_s::eFlags, entityState_s::eFlags, ET_NPC, entityState_s::eType, G_FreeEntity(), gentity_t, GIB_HEALTH, gentity_s::health, playerState_s::lastHitLoc, level, MOD_CRUSH, MOD_FALLING, MOD_LAVA, MOD_SLIME, MOD_SUICIDE, MOD_TARGET_LASER, MOD_TELEFRAG, MOD_TRIGGER_HURT, MOD_UNKNOWN, MOD_WATER, gentity_s::nextthink, playerState_s::origin, entityState_s::origin2, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gclient_s::respawnTime, gentity_s::s, gentity_s::think, level_locals_t::time, playerState_s::torsoTimer, and VectorCopy. Referenced by player_die().
00685 {
00686 // NOTENOTE No gibbing right now, this is star wars.
00687 qboolean doDisint = qfalse;
00688
00689 if (self->s.eType == ET_NPC)
00690 { //well, just rem it then, so long as it's done with its death anim and it's not a standard weapon.
00691 if ( self->client && self->client->ps.torsoTimer <= 0 &&
00692 (meansOfDeath == MOD_UNKNOWN ||
00693 meansOfDeath == MOD_WATER ||
00694 meansOfDeath == MOD_SLIME ||
00695 meansOfDeath == MOD_LAVA ||
00696 meansOfDeath == MOD_CRUSH ||
00697 meansOfDeath == MOD_TELEFRAG ||
00698 meansOfDeath == MOD_FALLING ||
00699 meansOfDeath == MOD_SUICIDE ||
00700 meansOfDeath == MOD_TARGET_LASER ||
00701 meansOfDeath == MOD_TRIGGER_HURT) )
00702 {
00703 self->think = G_FreeEntity;
00704 self->nextthink = level.time;
00705 }
00706 return;
00707 }
00708
00709 if (self->health < (GIB_HEALTH+1))
00710 {
00711 self->health = GIB_HEALTH+1;
00712
00713 if (self->client && (level.time - self->client->respawnTime) < 2000)
00714 {
00715 doDisint = qfalse;
00716 }
00717 else
00718 {
00719 doDisint = qtrue;
00720 }
00721 }
00722
00723 if (self->client && (self->client->ps.eFlags & EF_DISINTEGRATION))
00724 {
00725 return;
00726 }
00727 else if (self->s.eFlags & EF_DISINTEGRATION)
00728 {
00729 return;
00730 }
00731
00732 if (doDisint)
00733 {
00734 if (self->client)
00735 {
00736 self->client->ps.eFlags |= EF_DISINTEGRATION;
00737 VectorCopy(self->client->ps.origin, self->client->ps.lastHitLoc);
00738 }
00739 else
00740 {
00741 self->s.eFlags |= EF_DISINTEGRATION;
00742 VectorCopy(self->r.currentOrigin, self->s.origin2);
00743
00744 //since it's the corpse entity, tell it to "remove" itself
00745 self->think = BodyRid;
00746 self->nextthink = level.time + 1000;
00747 }
00748 return;
00749 }
00750 }
|
|
|
Definition at line 674 of file g_combat.c. References gentity_t, gentity_s::physicsObject, qfalse, and trap_UnlinkEntity(). Referenced by body_die().
00675 {
00676 trap_UnlinkEntity( ent );
00677 ent->physicsObject = qfalse;
00678 }
|
|
||||||||||||
|
Definition at line 1861 of file ai_main.c. References bot_state_t, botstates, bot_state_s::client, gentity_s::client, playerState_s::clientNum, bot_state_s::currentEnemy, ENEMY_FORGET_MS, bot_state_s::enemySeenTime, g_entities, gclient_t, gentity_t, bot_state_s::lastAttacked, bot_state_s::lastHurt, level, MAX_CLIENTS, NULL, entityState_s::number, PassLovedOneCheck(), PassStandardEnemyChecks(), gclient_s::ps, gentity_s::s, and level_locals_t::time. Referenced by G_Damage().
01862 {
01863 bot_state_t *bs;
01864 bot_state_t *bs_a;
01865 int i;
01866
01867 if (!bot || !attacker || !attacker->client)
01868 {
01869 return;
01870 }
01871
01872 if (bot->ps.clientNum >= MAX_CLIENTS)
01873 { //an NPC.. do nothing for them.
01874 return;
01875 }
01876
01877 if (attacker->s.number >= MAX_CLIENTS)
01878 { //if attacker is an npc also don't care I suppose.
01879 return;
01880 }
01881
01882 bs_a = botstates[attacker->s.number];
01883
01884 if (bs_a)
01885 { //if the client attacking us is a bot as well
01886 bs_a->lastAttacked = &g_entities[bot->ps.clientNum];
01887 i = 0;
01888
01889 while (i < MAX_CLIENTS)
01890 {
01891 if (botstates[i] &&
01892 i != bs_a->client &&
01893 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01894 {
01895 botstates[i]->lastAttacked = NULL;
01896 }
01897
01898 i++;
01899 }
01900 }
01901 else //got attacked by a real client, so no one gets rights to lastAttacked
01902 {
01903 i = 0;
01904
01905 while (i < MAX_CLIENTS)
01906 {
01907 if (botstates[i] &&
01908 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01909 {
01910 botstates[i]->lastAttacked = NULL;
01911 }
01912
01913 i++;
01914 }
01915 }
01916
01917 bs = botstates[bot->ps.clientNum];
01918
01919 if (!bs)
01920 {
01921 return;
01922 }
01923
01924 bs->lastHurt = attacker;
01925
01926 if (bs->currentEnemy)
01927 { //we don't care about the guy attacking us if we have an enemy already
01928 return;
01929 }
01930
01931 if (!PassStandardEnemyChecks(bs, attacker))
01932 { //the person that hurt us is not a valid enemy
01933 return;
01934 }
01935
01936 if (PassLovedOneCheck(bs, attacker))
01937 { //the person that hurt us is the one we love!
01938 bs->currentEnemy = attacker;
01939 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
01940 }
01941 }
|
|
||||||||||||
|
Definition at line 5510 of file g_combat.c. References entityShared_t::absmax, entityShared_t::absmin, trace_t::entityNum, ENTITYNUM_NONE, trace_t::fraction, gentity_t, MASK_SOLID, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, trap_Trace(), vec3_origin, vec3_t, VectorAdd, VectorCopy, and VectorScale. Referenced by G_RadiusDamage().
05510 {
05511 vec3_t dest;
05512 trace_t tr;
05513 vec3_t midpoint;
05514
05515 // use the midpoint of the bounds instead of the origin, because
05516 // bmodels may have their origin is 0,0,0
05517 VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
05518 VectorScale (midpoint, 0.5, midpoint);
05519
05520 VectorCopy (midpoint, dest);
05521 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05522 if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
05523 return qtrue;
05524
05525 // this should probably check in the plane of projection,
05526 // rather than in world coordinate, and also include Z
05527 VectorCopy (midpoint, dest);
05528 dest[0] += 15.0;
05529 dest[1] += 15.0;
05530 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05531 if (tr.fraction == 1.0)
05532 return qtrue;
05533
05534 VectorCopy (midpoint, dest);
05535 dest[0] += 15.0;
05536 dest[1] -= 15.0;
05537 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05538 if (tr.fraction == 1.0)
05539 return qtrue;
05540
05541 VectorCopy (midpoint, dest);
05542 dest[0] -= 15.0;
05543 dest[1] += 15.0;
05544 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05545 if (tr.fraction == 1.0)
05546 return qtrue;
05547
05548 VectorCopy (midpoint, dest);
05549 dest[0] -= 15.0;
05550 dest[1] -= 15.0;
05551 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05552 if (tr.fraction == 1.0)
05553 return qtrue;
05554
05555
05556 return qfalse;
05557 }
|
|
||||||||||||
|
Definition at line 805 of file g_combat.c. References gentity_s::client, FL_DROPPED_ITEM, gentity_s::flags, FOFS, G_Find(), g_gametype, gentity_t, GT_CTF, GT_CTY, vmCvar_t::integer, NULL, entityState_s::origin, playerState_s::origin, PERS_PLAYEREVENTS, playerState_s::persistant, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_NEUTRALFLAG, PW_REDFLAG, gentity_s::r, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, SVF_NOCLIENT, entityShared_t::svFlags, TEAM_BLUE, vec3_t, and VectorSubtract. Referenced by player_die().
00805 {
00806 #if 0
00807 gentity_t *ent;
00808 vec3_t dir;
00809 char *classname;
00810
00811 // if this player was carrying a flag
00812 if ( self->client->ps.powerups[PW_REDFLAG] ||
00813 self->client->ps.powerups[PW_BLUEFLAG] ||
00814 self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00815 // get the goal flag this player should have been going for
00816 if ( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY ) {
00817 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00818 classname = "team_CTF_blueflag";
00819 }
00820 else {
00821 classname = "team_CTF_redflag";
00822 }
00823 }
00824 else {
00825 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00826 classname = "team_CTF_redflag";
00827 }
00828 else {
00829 classname = "team_CTF_blueflag";
00830 }
00831 }
00832 ent = NULL;
00833 do
00834 {
00835 ent = G_Find(ent, FOFS(classname), classname);
00836 } while (ent && (ent->flags & FL_DROPPED_ITEM));
00837 // if we found the destination flag and it's not picked up
00838 if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
00839 // if the player was *very* close
00840 VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00841 if ( VectorLength(dir) < 200 ) {
00842 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00843 if ( attacker->client ) {
00844 attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00845 }
00846 }
00847 }
00848 }
00849 #endif
00850 }
|
|
||||||||||||||||
|
Definition at line 2894 of file g_combat.c. References ARMOR_PROTECTION, ARMOR_REDUCTION_FACTOR, ceil(), CLASS_VEHICLE, gentity_s::client, client, DAMAGE_HALF_ABSORB, DAMAGE_HALF_ARMOR_REDUCTION, DAMAGE_NO_ARMOR, playerState_s::electrifyTime, gclient_t, gentity_t, level, gentity_s::m_pVehicle, gclient_s::NPC_class, gclient_s::ps, STAT_ARMOR, playerState_s::stats, and level_locals_t::time. Referenced by G_Damage().
02895 {
02896 gclient_t *client;
02897 int save;
02898 int count;
02899
02900 if (!damage)
02901 return 0;
02902
02903 client = ent->client;
02904
02905 if (!client)
02906 return 0;
02907
02908 if (dflags & DAMAGE_NO_ARMOR)
02909 return 0;
02910
02911 if ( client->NPC_class == CLASS_VEHICLE
02912 && ent->m_pVehicle
02913 && ent->client->ps.electrifyTime > level.time )
02914 {//ion-cannon has disabled this ship's shields, take damage on hull!
02915 return 0;
02916 }
02917 // armor
02918 count = client->ps.stats[STAT_ARMOR];
02919
02920 if (dflags & DAMAGE_HALF_ABSORB)
02921 { // Half the damage gets absorbed by the shields, rather than 100%
02922 save = ceil( damage * ARMOR_PROTECTION );
02923 }
02924 else
02925 { // All the damage gets absorbed by the shields.
02926 save = damage;
02927 }
02928
02929 // save is the most damage that the armor is elibigle to protect, of course, but it's limited by the total armor.
02930 if (save >= count)
02931 save = count;
02932
02933 if (!save)
02934 return 0;
02935
02936 if (dflags & DAMAGE_HALF_ARMOR_REDUCTION) // Armor isn't whittled so easily by sniper shots.
02937 {
02938 client->ps.stats[STAT_ARMOR] -= (int)(save*ARMOR_REDUCTION_FACTOR);
02939 }
02940 else
02941 {
02942 client->ps.stats[STAT_ARMOR] -= save;
02943 }
02944
02945 return save;
02946 }
|
|
|
Definition at line 2572 of file g_main.c. References BeginIntermission(), CheckIntermissionExit(), gentity_s::client, level_locals_t::clients, Com_Printf(), CON_CONNECTED, clientPersistant_t::connected, d_powerDuelPrint, g_capturelimit, g_duel_fraglimit, g_endPDuel, g_entities, g_fraglimit, g_gametype, G_GetStringEdString(), g_maxclients, g_timelimit, gclient_t, gDoSlowMoDuel, gDuelExit, gEscapeTime, gEscaping, GT_CTF, GT_DUEL, GT_POWERDUEL, GT_SIEGE, gentity_s::health, vmCvar_t::integer, INTERMISSION_DELAY_TIME, level_locals_t::intermissionQueued, level_locals_t::intermissiontime, gentity_s::inuse, level, LogExit(), MAX_CLIENTS, clientPersistant_t::netname, level_locals_t::numPlayingClients, gclient_s::pers, PERS_SCORE, playerState_s::persistant, playerState_s::pm_flags, PMF_FOLLOW, gclient_s::ps, qboolean, qfalse, qtrue, S_COLOR_WHITE, ScoreIsTied(), gclient_s::sess, clientSession_t::sessionTeam, level_locals_t::startTime, TEAM_BLUE, TEAM_FREE, TEAM_RED, TEAM_SPECTATOR, level_locals_t::teamScores, level_locals_t::time, trap_SendServerCommand(), va(), level_locals_t::warmupTime, and clientSession_t::wins. Referenced by CalculateRanks(), G_RunFrame(), and player_die().
02572 {
02573 int i;
02574 gclient_t *cl;
02575 char *sKillLimit;
02576 qboolean printLimit = qtrue;
02577 // if at the intermission, wait for all non-bots to
02578 // signal ready, then go to next level
02579 if ( level.intermissiontime ) {
02580 CheckIntermissionExit ();
02581 return;
02582 }
02583
02584 if (gDoSlowMoDuel)
02585 { //don't go to intermission while in slow motion
02586 return;
02587 }
02588
02589 if (gEscaping)
02590 {
02591 int i = 0;
02592 int numLiveClients = 0;
02593
02594 while (i < MAX_CLIENTS)
02595 {
02596 if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0)
02597 {
02598 if (g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR &&
02599 !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW))
02600 {
02601 numLiveClients++;
02602 }
02603 }
02604
02605 i++;
02606 }
02607 if (gEscapeTime < level.time)
02608 {
02609 gEscaping = qfalse;
02610 LogExit( "Escape time ended." );
02611 return;
02612 }
02613 if (!numLiveClients)
02614 {
02615 gEscaping = qfalse;
02616 LogExit( "Everyone failed to escape." );
02617 return;
02618 }
02619 }
02620
02621 if ( level.intermissionQueued ) {
02622 //int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
02623 int time = INTERMISSION_DELAY_TIME;
02624 if ( level.time - level.intermissionQueued >= time ) {
02625 level.intermissionQueued = 0;
02626 BeginIntermission();
02627 }
02628 return;
02629 }
02630
02631 /*
02632 if (g_gametype.integer == GT_POWERDUEL)
02633 {
02634 if (level.numPlayingClients < 3)
02635 {
02636 if (!level.intermissiontime)
02637 {
02638 if (d_powerDuelPrint.integer)
02639 {
02640 Com_Printf("POWERDUEL WIN CONDITION: Duel forfeit (1)\n");
02641 }
02642 LogExit("Duel forfeit.");
02643 return;
02644 }
02645 }
02646 }
02647 */
02648
02649 // check for sudden death
02650 if (g_gametype.integer != GT_SIEGE)
02651 {
02652 if ( ScoreIsTied() ) {
02653 // always wait for sudden death
02654 if ((g_gametype.integer != GT_DUEL) || !g_timelimit.integer)
02655 {
02656 if (g_gametype.integer != GT_POWERDUEL)
02657 {
02658 return;
02659 }
02660 }
02661 }
02662 }
02663
02664 if (g_gametype.integer != GT_SIEGE)
02665 {
02666 if ( g_timelimit.integer && !level.warmupTime ) {
02667 if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
02668 // trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
02669 trap_SendServerCommand( -1, va("print \"%s.\n\"",G_GetStringEdString("MP_SVGAME", "TIMELIMIT_HIT")));
02670 if (d_powerDuelPrint.integer)
02671 {
02672 Com_Printf("POWERDUEL WIN CONDITION: Timelimit hit (1)\n");
02673 }
02674 LogExit( "Timelimit hit." );
02675 return;
02676 }
02677 }
02678 }
02679
02680 if (g_gametype.integer == GT_POWERDUEL && level.numPlayingClients >= 3)
02681 {
02682 if (g_endPDuel)
02683 {
02684 g_endPDuel = qfalse;
02685 LogExit("Powerduel ended.");
02686 }
02687
02688 //yeah, this stuff was completely insane.
02689 /*
02690 int duelists[3];
02691 duelists[0] = level.sortedClients[0];
02692 duelists[1] = level.sortedClients[1];
02693 duelists[2] = level.sortedClients[2];
02694
02695 if (duelists[0] != -1 &&
02696 duelists[1] != -1 &&
02697 duelists[2] != -1)
02698 {
02699 if (!g_entities[duelists[0]].inuse ||
02700 !g_entities[duelists[0]].client ||
02701 g_entities[duelists[0]].client->ps.stats[STAT_HEALTH] <= 0 ||
02702 g_entities[duelists[0]].client->sess.sessionTeam != TEAM_FREE)
02703 { //The lone duelist lost, give the other two wins (if applicable) and him a loss
02704 if (g_entities[duelists[0]].inuse &&
02705 g_entities[duelists[0]].client)
02706 {
02707 g_entities[duelists[0]].client->sess.losses++;
02708 ClientUserinfoChanged(duelists[0]);
02709 }
02710 if (g_entities[duelists[1]].inuse &&
02711 g_entities[duelists[1]].client)
02712 {
02713 if (g_entities[duelists[1]].client->ps.stats[STAT_HEALTH] > 0 &&
02714 g_entities[duelists[1]].client->sess.sessionTeam == TEAM_FREE)
02715 {
02716 g_entities[duelists[1]].client->sess.wins++;
02717 }
02718 else
02719 {
02720 g_entities[duelists[1]].client->sess.losses++;
02721 }
02722 ClientUserinfoChanged(duelists[1]);
02723 }
02724 if (g_entities[duelists[2]].inuse &&
02725 g_entities[duelists[2]].client)
02726 {
02727 if (g_entities[duelists[2]].client->ps.stats[STAT_HEALTH] > 0 &&
02728 g_entities[duelists[2]].client->sess.sessionTeam == TEAM_FREE)
02729 {
02730 g_entities[duelists[2]].client->sess.wins++;
02731 }
02732 else
02733 {
02734 g_entities[duelists[2]].client->sess.losses++;
02735 }
02736 ClientUserinfoChanged(duelists[2]);
02737 }
02738
02739 //Will want to parse indecies for two out at some point probably
02740 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", duelists[1] ) );
02741
02742 if (d_powerDuelPrint.integer)
02743 {
02744 Com_Printf("POWERDUEL WIN CONDITION: Coupled duelists won (1)\n");
02745 }
02746 LogExit( "Coupled duelists won." );
02747 gDuelExit = qfalse;
02748 }
02749 else if ((!g_entities[duelists[1]].inuse ||
02750 !g_entities[duelists[1]].client ||
02751 g_entities[duelists[1]].client->sess.sessionTeam != TEAM_FREE ||
02752 g_entities[duelists[1]].client->ps.stats[STAT_HEALTH] <= 0) &&
02753 (!g_entities[duelists[2]].inuse ||
02754 !g_entities[duelists[2]].client ||
02755 g_entities[duelists[2]].client->sess.sessionTeam != TEAM_FREE ||
02756 g_entities[duelists[2]].client->ps.stats[STAT_HEALTH] <= 0))
02757 { //the coupled duelists lost, give the lone duelist a win (if applicable) and the couple both losses
02758 if (g_entities[duelists[1]].inuse &&
02759 g_entities[duelists[1]].client)
02760 {
02761 g_entities[duelists[1]].client->sess.losses++;
02762 ClientUserinfoChanged(duelists[1]);
02763 }
02764 if (g_entities[duelists[2]].inuse &&
02765 g_entities[duelists[2]].client)
02766 {
02767 g_entities[duelists[2]].client->sess.losses++;
02768 ClientUserinfoChanged(duelists[2]);
02769 }
02770
02771 if (g_entities[duelists[0]].inuse &&
02772 g_entities[duelists[0]].client &&
02773 g_entities[duelists[0]].client->ps.stats[STAT_HEALTH] > 0 &&
02774 g_entities[duelists[0]].client->sess.sessionTeam == TEAM_FREE)
02775 {
02776 g_entities[duelists[0]].client->sess.wins++;
02777 ClientUserinfoChanged(duelists[0]);
02778 }
02779
02780 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", duelists[0] ) );
02781
02782 if (d_powerDuelPrint.integer)
02783 {
02784 Com_Printf("POWERDUEL WIN CONDITION: Lone duelist won (1)\n");
02785 }
02786 LogExit( "Lone duelist won." );
02787 gDuelExit = qfalse;
02788 }
02789 }
02790 */
02791 return;
02792 }
02793
02794 if ( level.numPlayingClients < 2 ) {
02795 return;
02796 }
02797
02798 if (g_gametype.integer == GT_DUEL ||
02799 g_gametype.integer == GT_POWERDUEL)
02800 {
02801 if (g_fraglimit.integer > 1)
02802 {
02803 sKillLimit = "Kill limit hit.";
02804 }
02805 else
02806 {
02807 sKillLimit = "";
02808 printLimit = qfalse;
02809 }
02810 }
02811 else
02812 {
02813 sKillLimit = "Kill limit hit.";
02814 }
02815 if ( g_gametype.integer < GT_SIEGE && g_fraglimit.integer ) {
02816 if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
02817 trap_SendServerCommand( -1, va("print \"Red %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02818 if (d_powerDuelPrint.integer)
02819 {
02820 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (1)\n");
02821 }
02822 LogExit( sKillLimit );
02823 return;
02824 }
02825
02826 if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
02827 trap_SendServerCommand( -1, va("print \"Blue %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02828 if (d_powerDuelPrint.integer)
02829 {
02830 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (2)\n");
02831 }
02832 LogExit( sKillLimit );
02833 return;
02834 }
02835
02836 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02837 cl = level.clients + i;
02838 if ( cl->pers.connected != CON_CONNECTED ) {
02839 continue;
02840 }
02841 if ( cl->sess.sessionTeam != TEAM_FREE ) {
02842 continue;
02843 }
02844
02845 if ( (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && g_duel_fraglimit.integer && cl->sess.wins >= g_duel_fraglimit.integer )
02846 {
02847 if (d_powerDuelPrint.integer)
02848 {
02849 Com_Printf("POWERDUEL WIN CONDITION: Duel limit hit (1)\n");
02850 }
02851 LogExit( "Duel limit hit." );
02852 gDuelExit = qtrue;
02853 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the win limit.\n\"",
02854 cl->pers.netname ) );
02855 return;
02856 }
02857
02858 if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
02859 if (d_powerDuelPrint.integer)
02860 {
02861 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (3)\n");
02862 }
02863 LogExit( sKillLimit );
02864 gDuelExit = qfalse;
02865 if (printLimit)
02866 {
02867 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s.\n\"",
02868 cl->pers.netname,
02869 G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")
02870 )
02871 );
02872 }
02873 return;
02874 }
02875 }
02876 }
02877
02878 if ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {
02879
02880 if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer )
02881 {
02882 trap_SendServerCommand( -1, va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTREDTEAM")));
02883 trap_SendServerCommand( -1, va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02884 LogExit( "Capturelimit hit." );
02885 return;
02886 }
02887
02888 if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
02889 trap_SendServerCommand( -1, va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTBLUETEAM")));
02890 trap_SendServerCommand( -1, va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02891 LogExit( "Capturelimit hit." );
02892 return;
02893 }
02894 }
02895 }
|
|
|
Definition at line 1882 of file g_combat.c. References AngleVectors(), CHAN_AUTO, CLASS_ATST, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_R5D2, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, G_EffectIndex(), G_PlayEffectID(), G_Sound(), G_SoundIndex(), gentity_t, gclient_s::NPC_class, NULL, Q_irand(), gentity_s::r, va(), vec3_t, VectorCopy, VectorMA, and VectorSet. Referenced by player_die().
01883 {
01884 vec3_t effectPos, right;
01885 vec3_t defaultDir;
01886
01887 if ( !ent || !ent->client )
01888 return;
01889
01890 VectorSet(defaultDir, 0, 0, 1);
01891
01892 // team no longer indicates species/race. NPC_class should be used to identify certain npc types
01893 switch(ent->client->NPC_class)
01894 {
01895 case CLASS_MOUSE:
01896 VectorCopy( ent->r.currentOrigin, effectPos );
01897 effectPos[2] -= 20;
01898 G_PlayEffectID( G_EffectIndex("env/small_explode"), effectPos, defaultDir );
01899 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mouse/misc/death1") );
01900 break;
01901
01902 case CLASS_PROBE:
01903 VectorCopy( ent->r.currentOrigin, effectPos );
01904 effectPos[2] += 50;
01905 G_PlayEffectID( G_EffectIndex("explosions/probeexplosion1"), effectPos, defaultDir );
01906 break;
01907
01908 case CLASS_ATST:
01909 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01910 VectorMA( ent->r.currentOrigin, 20, right, effectPos );
01911 effectPos[2] += 180;
01912 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01913 VectorMA( effectPos, -40, right, effectPos );
01914 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01915 break;
01916
01917 case CLASS_SEEKER:
01918 case CLASS_REMOTE:
01919 G_PlayEffectID( G_EffectIndex("env/small_explode"), ent->r.currentOrigin, defaultDir );
01920 break;
01921
01922 case CLASS_GONK:
01923 VectorCopy( ent->r.currentOrigin, effectPos );
01924 effectPos[2] -= 5;
01925 // statusTextIndex = Q_irand( IGT_RESISTANCEISFUTILE, IGT_NAMEIS8OF12 );
01926 G_Sound( ent, CHAN_AUTO, G_SoundIndex(va("sound/chars/gonk/misc/death%d.wav",Q_irand( 1, 3 ))) );
01927 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01928 break;
01929
01930 // should list all remaining droids here, hope I didn't miss any
01931 case CLASS_R2D2:
01932 VectorCopy( ent->r.currentOrigin, effectPos );
01933 effectPos[2] -= 10;
01934 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01935 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01936 break;
01937
01938 case CLASS_PROTOCOL: //c3p0
01939 case CLASS_R5D2:
01940 VectorCopy( ent->r.currentOrigin, effectPos );
01941 effectPos[2] -= 10;
01942 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01943 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01944 break;
01945
01946 case CLASS_MARK2:
01947 VectorCopy( ent->r.currentOrigin, effectPos );
01948 effectPos[2] -= 15;
01949 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01950 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01951 break;
01952
01953 case CLASS_INTERROGATOR:
01954 VectorCopy( ent->r.currentOrigin, effectPos );
01955 effectPos[2] -= 15;
01956 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01957 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/interrogator/misc/int_droid_explo") );
01958 break;
01959
01960 case CLASS_MARK1:
01961 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01962 VectorMA( ent->r.currentOrigin, 10, right, effectPos );
01963 effectPos[2] -= 15;
01964 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01965 VectorMA( effectPos, -20, right, effectPos );
01966 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01967 VectorMA( effectPos, -20, right, effectPos );
01968 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01969 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark1/misc/mark1_explo") );
01970 break;
01971
01972 case CLASS_SENTRY:
01973 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/sentry/misc/sentry_explo") );
01974 VectorCopy( ent->r.currentOrigin, effectPos );
01975 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01976 break;
01977
01978 default:
01979 break;
01980
01981 }
01982
01983 }
|
|
||||||||||||
|
Definition at line 3510 of file g_combat.c. References BOTH_DEATH1, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_Dismember(), G_GetDismemberBolt(), gentity_t, qfalse, and vec3_t. Referenced by ClientCommand().
03511 {
03512 int sect = G2_MODELPART_HEAD;
03513 vec3_t boltPoint;
03514
03515 switch (num)
03516 {
03517 case 0:
03518 sect = G2_MODELPART_HEAD;
03519 break;
03520 case 1:
03521 sect = G2_MODELPART_WAIST;
03522 break;
03523 case 2:
03524 sect = G2_MODELPART_LARM;
03525 break;
03526 case 3:
03527 sect = G2_MODELPART_RARM;
03528 break;
03529 case 4:
03530 sect = G2_MODELPART_RHAND;
03531 break;
03532 case 5:
03533 sect = G2_MODELPART_LLEG;
03534 break;
03535 case 6:
03536 sect = G2_MODELPART_RLEG;
03537 break;
03538 default:
03539 break;
03540 }
03541
03542 G_GetDismemberBolt(self, boltPoint, sect);
03543 G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03544 }
|
|
|
Definition at line 3497 of file g_combat.c. References BOTH_DEATH1, G2_MODELPART_HEAD, G2_MODELPART_RLEG, G_Dismember(), G_GetDismemberBolt(), gentity_t, qfalse, and vec3_t. Referenced by ClientCommand().
03498 {
03499 int sect = G2_MODELPART_HEAD;
03500 vec3_t boltPoint;
03501
03502 while (sect <= G2_MODELPART_RLEG)
03503 {
03504 G_GetDismemberBolt(self, boltPoint, sect);
03505 G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03506 sect++;
03507 }
03508 }
|
|
|
Definition at line 368 of file g_combat.c. References entityState_s::angles, AngleVectors(), entityShared_t::currentOrigin, G_RadiusDamage(), gentity_t, entityState_s::loopIsSoundset, entityState_s::loopSound, MOD_UNKNOWN, NULL, ObjectDie(), gentity_s::parent, entityState_s::pos, qfalse, gentity_s::r, gentity_s::s, gentity_s::splashDamage, gentity_s::splashRadius, gentity_s::takedamage, trajectory_t::trBase, vec3_t, and VectorCopy.
00369 {
00370 // gentity_t *tent;
00371 vec3_t forward;
00372
00373 self->takedamage = qfalse;//stop chain reaction runaway loops
00374
00375 self->s.loopSound = 0;
00376 self->s.loopIsSoundset = qfalse;
00377
00378 VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
00379
00380 // tent = G_TempEntity( self->s.origin, EV_FX_EXPLOSION );
00381 AngleVectors(self->s.angles, forward, NULL, NULL);
00382
00383 /*
00384 if ( self->fxID > 0 )
00385 {
00386 G_PlayEffect( self->fxID, self->r.currentOrigin, forward );
00387 }
00388 else
00389 */
00390
00391 {
00392 // CG_SurfaceExplosion( self->r.currentOrigin, forward, 20.0f, 12.0f, ((self->spawnflags&4)==qfalse) ); //FIXME: This needs to be consistent to all exploders!
00393 // G_Sound(self, self->sounds );
00394 }
00395
00396 if(self->splashDamage > 0 && self->splashRadius > 0)
00397 {
00398 gentity_t *attacker = self;
00399 if ( self->parent )
00400 {
00401 attacker = self->parent;
00402 }
00403 G_RadiusDamage( self->r.currentOrigin, attacker, self->splashDamage, self->splashRadius,
00404 attacker, NULL, MOD_UNKNOWN );
00405 }
00406
00407 ObjectDie( self, self, self, 20, 0 );
00408 }
|
|
||||||||||||
|
||||||||||||
|
||||||||||||||||||||
|
Definition at line 1769 of file g_combat.c. References gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, g_entities, G_SetEnemy(), gentity_t, gentity_s::health, gNPCstats_e::hfov, InFOV(), gentity_s::NPC, NPC_ClearLOS2(), NULL, gclient_s::playerTeam, gentity_s::r, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_NO_GROUPS, gNPC_t::scriptFlags, gNPC_t::stats, trap_EntitiesInBox(), trap_InPVS(), vec3_t, and gNPCstats_e::vfov. Referenced by G_AngerAlert(), and G_DeathAlert().
01770 {
01771 int radiusEnts[ 128 ];
01772 gentity_t *check;
01773 vec3_t mins, maxs;
01774 int numEnts;
01775 int i;
01776 float distSq, sndDistSq = (soundDist*soundDist);
01777
01778 if ( attacker == NULL || attacker->client == NULL )
01779 return;
01780
01781 //Setup the bbox to search in
01782 for ( i = 0; i < 3; i++ )
01783 {
01784 mins[i] = victim->r.currentOrigin[i] - radius;
01785 maxs[i] = victim->r.currentOrigin[i] + radius;
01786 }
01787
01788 //Get the number of entities in a given space
01789 numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 );
01790
01791 //Cull this list
01792 for ( i = 0; i < numEnts; i++ )
01793 {
01794 check = &g_entities[radiusEnts[i]];
01795
01796 //Validate clients
01797 if ( check->client == NULL )
01798 continue;
01799
01800 //only want NPCs
01801 if ( check->NPC == NULL )
01802 continue;
01803
01804 //Don't bother if they're ignoring enemies
01805 // if ( check->svFlags & SVF_IGNORE_ENEMIES )
01806 // continue;
01807
01808 //This NPC specifically flagged to ignore alerts
01809 if ( check->NPC->scriptFlags & SCF_IGNORE_ALERTS )
01810 continue;
01811
01812 //This NPC specifically flagged to ignore alerts
01813 if ( !(check->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
01814 continue;
01815
01816 //this ent does not participate in group AI
01817 if ( (check->NPC->scriptFlags&SCF_NO_GROUPS) )
01818 continue;
01819
01820 //Skip the requested avoid check if present
01821 if ( check == victim )
01822 continue;
01823
01824 //Skip the attacker
01825 if ( check == attacker )
01826 continue;
01827
01828 //Must be on the same team
01829 if ( check->client->playerTeam != victim->client->playerTeam )
01830 continue;
01831
01832 //Must be alive
01833 if ( check->health <= 0 )
01834 continue;
01835
01836 if ( check->enemy == NULL )
01837 {//only do this if they're not already mad at someone
01838 distSq = DistanceSquared( check->r.currentOrigin, victim->r.currentOrigin );
01839 if ( distSq > 16384 /*128 squared*/ && !trap_InPVS( victim->r.currentOrigin, check->r.currentOrigin ) )
01840 {//not even potentially visible/hearable
01841 continue;
01842 }
01843 //NOTE: this allows sound alerts to still go through doors/PVS if the teammate is within 128 of the victim...
01844 if ( soundDist <= 0 || distSq > sndDistSq )
01845 {//out of sound range
01846 if ( !InFOV( victim, check, check->NPC->stats.hfov, check->NPC->stats.vfov )
01847 || !NPC_ClearLOS2( check, victim->r.currentOrigin ) )
01848 {//out of FOV or no LOS
01849 continue;
01850 }
01851 }
01852
01853 //FIXME: This can have a nasty cascading effect if setup wrong...
01854 G_SetEnemy( check, attacker );
01855 }
01856 }
01857 }
|
|
||||||||||||||||
|
Definition at line 2949 of file g_combat.c. References gentity_s::client, entityShared_t::currentOrigin, g_gravity, g_knockback, gentity_t, level, gentity_s::physicsBounce, playerState_s::pm_flags, playerState_s::pm_time, PMF_TIME_KNOCKBACK, entityState_s::pos, gclient_s::ps, gentity_s::r, gentity_s::s, level_locals_t::time, TR_LINEAR_STOP, TR_NONLINEAR_STOP, TR_STATIONARY, trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, vmCvar_t::value, vec3_t, VectorAdd, VectorCopy, VectorScale, and playerState_s::velocity. Referenced by DoImpact().
02950 {
02951 vec3_t kvel;
02952 float mass;
02953
02954 if ( targ->physicsBounce > 0 ) //overide the mass
02955 mass = targ->physicsBounce;
02956 else
02957 mass = 200;
02958
02959 if ( g_gravity.value > 0 )
02960 {
02961 VectorScale( newDir, g_knockback.value * (float)knockback / mass * 0.8, kvel );
02962 kvel[2] = newDir[2] * g_knockback.value * (float)knockback / mass * 1.5;
02963 }
02964 else
02965 {
02966 VectorScale( newDir, g_knockback.value * (float)knockback / mass, kvel );
02967 }
02968
02969 if ( targ->client )
02970 {
02971 VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
02972 }
02973 else if ( targ->s.pos.trType != TR_STATIONARY && targ->s.pos.trType != TR_LINEAR_STOP && targ->s.pos.trType != TR_NONLINEAR_STOP )
02974 {
02975 VectorAdd( targ->s.pos.trDelta, kvel, targ->s.pos.trDelta );
02976 VectorCopy( targ->r.currentOrigin, targ->s.pos.trBase );
02977 targ->s.pos.trTime = level.time;
02978 }
02979
02980 // set the timer so that the other client can't cancel
02981 // out the movement immediately
02982 if ( targ->client && !targ->client->ps.pm_time )
02983 {
02984 int t;
02985
02986 t = knockback * 2;
02987 if ( t < 50 ) {
02988 t = 50;
02989 }
02990 if ( t > 200 ) {
02991 t = 200;
02992 }
02993 targ->client->ps.pm_time = t;
02994 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
02995 }
02996 }
|
|
||||||||||||||||||||||||||||
|
Definition at line 4093 of file g_combat.c. References CLASS_PROTOCOL, gentity_s::client, d_saberGhoul2Collision, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, gclient_s::g2LastSurfaceHit, gclient_s::g2LastSurfaceTime, g_austrian, g_dismember, G_Dismember(), g_gametype, G_GetDismemberBolt(), G_GetDismemberLoc(), G_GetHitLocation(), G_GetHitLocFromSurfName(), G_GetHitQuad(), G_LogPrintf(), gentity_t, gGAvoidDismember, gentity_s::ghoul2, GT_DUEL, GT_POWERDUEL, hitLocName, HL_ARM_LT, HL_ARM_RT, HL_FOOT_LT, HL_FOOT_RT, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MAX_QPATH, MOD_UNKNOWN, clientPersistant_t::netname, gentity_s::NPC, gclient_s::NPC_class, gclient_s::pers, Q_irand(), level_locals_t::time, trap_G2API_GetSurfaceName(), vec3_origin, and vec3_t. Referenced by ClientCommand(), ClientThink_real(), G_Damage(), and player_die().
04094 {
04095 int hitLoc = -1, hitLocUse = -1;
04096 vec3_t boltPoint;
04097 int dismember = g_dismember.integer;
04098
04099 if (ent->localAnimIndex > 1)
04100 {
04101 if (!ent->NPC)
04102 {
04103 return;
04104 }
04105
04106 if (ent->client->NPC_class != CLASS_PROTOCOL)
04107 { //this is the only non-humanoid allowed to do dismemberment.
04108 return;
04109 }
04110 }
04111
04112 if (!dismember)
04113 {
04114 return;
04115 }
04116
04117 if (gGAvoidDismember == 1)
04118 {
04119 return;
04120 }
04121
04122 if (gGAvoidDismember != 2)
04123 { //this means do the dismemberment regardless of randomness and damage
04124 if (Q_irand(0, 100) > dismember)
04125 {
04126 return;
04127 }
04128
04129 if (damage < 5)
04130 {
04131 return;
04132 }
04133 }
04134
04135 if (gGAvoidDismember == 2)
04136 {
04137 hitLoc = HL_HAND_RT;
04138 }
04139 else
04140 {
04141 if (d_saberGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time)
04142 {
04143 char hitSurface[MAX_QPATH];
04144
04145 trap_G2API_GetSurfaceName(ent->ghoul2, ent->client->g2LastSurfaceHit, 0, hitSurface);
04146
04147 if (hitSurface[0])
04148 {
04149 G_GetHitLocFromSurfName(ent, hitSurface, &hitLoc, point, vec3_origin, vec3_origin, MOD_UNKNOWN);
04150 }
04151 }
04152
04153 if (hitLoc == -1)
04154 {
04155 hitLoc = G_GetHitLocation( ent, point );
04156 }
04157 }
04158
04159 switch(hitLoc)
04160 {
04161 case HL_FOOT_RT:
04162 case HL_LEG_RT:
04163 hitLocUse = G2_MODELPART_RLEG;
04164 break;
04165 case HL_FOOT_LT:
04166 case HL_LEG_LT:
04167 hitLocUse = G2_MODELPART_LLEG;
04168 break;
04169
04170 case HL_WAIST:
04171 hitLocUse = G2_MODELPART_WAIST;
04172 break;
04173 /*
04174 case HL_BACK_RT:
04175 case HL_BACK_LT:
04176 case HL_BACK:
04177 case HL_CHEST_RT:
04178 case HL_CHEST_LT:
04179 case HL_CHEST:
04180 break;
04181 */
04182 case HL_ARM_RT:
04183 hitLocUse = G2_MODELPART_RARM;
04184 break;
04185 case HL_HAND_RT:
04186 hitLocUse = G2_MODELPART_RHAND;
04187 break;
04188 case HL_ARM_LT:
04189 case HL_HAND_LT:
04190 hitLocUse = G2_MODELPART_LARM;
04191 break;
04192 case HL_HEAD:
04193 hitLocUse = G2_MODELPART_HEAD;
04194 break;
04195 default:
04196 hitLocUse = G_GetHitQuad(ent, point);
04197 break;
04198 }
04199
04200 if (hitLocUse == -1)
04201 {
04202 return;
04203 }
04204
04205 if (ent->client)
04206 {
04207 G_GetDismemberBolt(ent, boltPoint, hitLocUse);
04208 if ( g_austrian.integer
04209 && (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) )
04210 {
04211 G_LogPrintf( "Duel Dismemberment: %s dismembered at %s\n", ent->client->pers.netname, hitLocName[hitLoc] );
04212 }
04213 }
04214 else
04215 {
04216 G_GetDismemberLoc(ent, boltPoint, hitLocUse);
04217 }
04218 G_Dismember(ent, enemy, boltPoint, hitLocUse, 90, 0, deathAnim, postDeath);
04219 }
|
|
|
Definition at line 1985 of file g_combat.c. References gNPC_t::blockedSpeechDebounceTime, BSET_VICTORY, CLASS_GALAKMECH, gentity_s::client, AIGroupInfo_s::commander, G_ActivateBehavior(), gentity_t, gNPC_t::greetingDebounceTime, gNPC_t::group, level, gentity_s::NPC, gclient_s::NPC_class, Q_irand(), gNPC_t::rank, gentity_s::s, level_locals_t::time, TIMER_Set(), gentity_s::wait, entityState_s::weapon, and WP_SABER. Referenced by player_die().
01986 {
01987 if ( !G_ActivateBehavior( self, BSET_VICTORY ) )
01988 {
01989 if ( self->NPC && self->s.weapon == WP_SABER )
01990 {//Jedi taunt from within their AI
01991 self->NPC->blockedSpeechDebounceTime = 0;//get them ready to taunt
01992 return;
01993 }
01994 if ( self->client && self->client->NPC_class == CLASS_GALAKMECH )
01995 {
01996 self->wait = 1;
01997 TIMER_Set( self, "gloatTime", Q_irand( 5000, 8000 ) );
01998 self->NPC->blockedSpeechDebounceTime = 0;//get him ready to taunt
01999 return;
02000 }
02001 //FIXME: any way to not say this *right away*? Wait for victim's death anim/scream to finish?
02002 if ( self->NPC && self->NPC->group && self->NPC->group->commander && self->NPC->group->commander->NPC && self->NPC->group->commander->NPC->rank > self->NPC->rank && !Q_irand( 0, 2 ) )
02003 {//sometimes have the group commander speak instead
02004 self->NPC->group->commander->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02005 //G_AddVoiceEvent( self->NPC->group->commander, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 );
02006 }
02007 else if ( self->NPC )
02008 {
02009 self->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02010 //G_AddVoiceEvent( self, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 );
02011 }
02012 }
02013 }
|
|
||||||||||||||||||||||||||||||||||||
|
Definition at line 4369 of file g_combat.c. References gentity_s::activator, gentity_s::alliedTeam, AngleVectors(), bgSiegeClasses, BotDamageNotification(), BROKENLIMB_LARM, BROKENLIMB_RARM, playerState_s::brokenLimbs, BSET_DEATH, CFL_STRONGAGAINSTPHYSICAL, CheckArmor(), CLASS_ATST, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_R5D2, CLASS_RANCOR, CLASS_SEEKER, CLASS_SENTRY, CLASS_VEHICLE, client, gentity_s::client, playerState_s::clientNum, entityShared_t::currentOrigin, gclient_s::damage_armor, gclient_s::damage_blood, gclient_s::damage_from, gclient_s::damage_fromWorld, gclient_s::damage_knockback, DAMAGE_NO_DISMEMBER, DAMAGE_NO_HIT_LOC, DAMAGE_NO_KNOCKBACK, DAMAGE_NO_PROTECTION, DAMAGE_NO_SELF_PROTECTION, DAMAGE_RADIUS, DAMAGE_SABER_KNOCKBACK1, DAMAGE_SABER_KNOCKBACK1_B2, DAMAGE_SABER_KNOCKBACK2, DAMAGE_SABER_KNOCKBACK2_B2, gentity_s::damageRedirect, gentity_s::damageRedirectTo, gentity_s::die, DirToByte(), DotProduct, playerState_s::duelIndex, playerState_s::duelInProgress, EF_DEAD, EF_INVULNERABLE, playerState_s::eFlags, entityState_s::eFlags, playerState_s::electrifyTime, gentity_s::enemy, ENTITYNUM_WORLD, ET_GENERAL, ET_MISSILE, ET_MOVER, ET_NPC, ET_PLAYER, entityState_s::eType, EV_POWERUP_BATTLESUIT, EV_SHIELD_HIT, entityState_s::eventParm, playerState_s::fd, FL_BBRUSH, FL_DMG_BY_HEAVY_WEAP_ONLY, FL_DMG_BY_SABER_ONLY, FL_GODMODE, FL_NO_KNOCKBACK, FL_SHIELDED, FL_UNDYING, gentity_s::flags, FORCE_LEVEL_1, FORCE_LEVEL_2, FORCE_LEVEL_3, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcedata_s::forcePowersActive, gclient_s::forcePowerSoundDebounce, FP_PROTECT, FP_RAGE, trace_t::fraction, gclient_s::g2LastSurfaceHit, gclient_s::g2LastSurfaceTime, G_ActivateBehavior(), G_AddEvent(), g_armBreakage, G_BreakArm(), G_CheckForDismemberment(), g_debugDamage, g_debugMelee, g_entities, g_ff_objectives, G_FlyVehicleDestroySurface(), g_friendlyFire, g_gametype, G_GetHitLocFromSurfName(), G_HeavyMelee(), g_knockback, G_LetGoOfWall(), G_LocationBasedDamageModifier(), G_LogWeaponDamage(), G_PreDefSound(), G_Printf(), g_saberDmgVelocityScale, G_ScaleNetHealth(), G_ShipSurfaceForSurfName(), G_TempEntity(), G_ThereIsAMaster(), g_trueJedi, G_VehicleSetDamageLocFlags(), G_VehUpdateShields(), gclient_t, gentity_s::genericValue4, gentity_t, gentity_s::ghoul2, GlobalUse(), gPainHitLoc, gPainMOD, gPainPoint, gSiegeRoundBegun, GT_CTF, GT_CTY, GT_JEDIMASTER, GT_SIEGE, GT_TEAM, gentity_s::health, vehicleInfo_t::health_back, vehicleInfo_t::health_front, vehicleInfo_t::health_left, vehicleInfo_t::health_right, HL_ARM_LT, HL_ARM_RT, HL_HAND_LT, HL_HAND_RT, vmCvar_t::integer, level_locals_t::intermissionQueued, gentity_s::inuse, gclient_s::invulnerableTimer, playerState_s::isJediMaster, Jetpack_Off(), gclient_s::jetPackOn, gclient_s::jetPackToggleTime, saberInfo_t::knockbackScale, saberInfo_t::knockbackScale2, gclient_s::lasthurt_client, gclient_s::lasthurt_mod, level, gentity_s::locationDamage, Vehicle_s::m_iArmor, Vehicle_s::m_iShields, playerState_s::m_iVehicleNum, Vehicle_s::m_LandTrace, gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vOrientation, MAX_CLIENTS, MAX_QPATH, gentity_s::maxHealth, MOD_BRYAR_PISTOL, MOD_BRYAR_PISTOL_ALT, MOD_CONC, MOD_CONC_ALT, MOD_CRUSH, MOD_DEMP2, MOD_DEMP2_ALT, MOD_DET_PACK_SPLASH, MOD_FALLING, MOD_FLECHETTE_ALT_SPLASH, MOD_MELEE, MOD_REPEATER_ALT, MOD_REPEATER_ALT_SPLASH, MOD_ROCKET, MOD_ROCKET_HOMING, MOD_ROCKET_HOMING_SPLASH, MOD_ROCKET_SPLASH, MOD_SABER, MOD_SUICIDE, MOD_TELEFRAG, MOD_THERMAL, MOD_THERMAL_SPLASH, MOD_TIMED_MINE_SPLASH, MOD_TRIGGER_HURT, MOD_TRIP_MINE_SPLASH, MOD_TURBLAST, MOD_VEHICLE, MOVER_POS1, gentity_s::moverState, gclient_s::noclip, entityState_s::NPC_class, gclient_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), playerState_s::origin, entityState_s::otherEntityNum, playerState_s::otherKiller, playerState_s::otherKillerDebounceTime, playerState_s::otherKillerTime, entityState_s::owner, gentity_s::pain, PDSOUND_PROTECTHIT, PERS_ATTACKEE_ARMOR, PERS_ATTACKER, PERS_HITS, playerState_s::persistant, PITCH, playerState_s::pm_flags, playerState_s::pm_time, PMF_STUCK_TO_WALL, PMF_TIME_KNOCKBACK, gentity_s::pos1, gentity_s::pos2, playerState_s::powerups, gclient_s::ps, PW_BATTLESUIT, PW_FORCE_BOON, Q3_INFINITE, Q_irand(), qfalse, qtrue, gentity_s::r, ROLL, gentity_s::s, gclient_s::saber, gclient_s::sess, clientSession_t::sessionTeam, SHIPSURF_BACK, SHIPSURF_FRONT, SHIPSURF_LEFT, SHIPSURF_RIGHT, entityState_s::shouldtarget, gclient_s::siegeClass, STAT_ARMOR, STAT_HEALTH, STAT_MAX_HEALTH, playerState_s::stats, SVF_GLASS_BRUSH, entityShared_t::svFlags, gentity_s::takedamage, Team_CheckHurtCarrier(), gentity_s::teamnodmg, entityState_s::teamowner, level_locals_t::time, entityState_s::time2, playerState_s::torsoAnim, trap_G2API_GetSurfaceName(), playerState_s::trueJedi, playerState_s::trueNonJedi, vehicleInfo_t::type, gentity_s::use, vmCvar_t::value, vec3_origin, vec3_t, VectorAdd, VectorClear, VectorCopy, VectorNormalize(), VectorScale, VectorSubtract, playerState_s::velocity, VH_ANIMAL, VH_FIGHTER, VH_SPEEDER, VH_WALKER, playerState_s::weapon, WEAPON_CHARGING, WEAPON_CHARGING_ALT, WEAPON_READY, playerState_s::weaponstate, playerState_s::weaponTime, and WP_SABER. Referenced by AnimateRiders(), Blocked_Door(), Blocked_Mover(), Boba_FireFlameThrower(), ClientEvents(), ClientThink_real(), Cmd_DuelTeam_f(), DEMP2_AltRadiusDamage(), DetPackBlow(), Do_Strike(), DoGripAction(), DoImpact(), EjectAll(), ForceLightningDamage(), funcBBrushDieGo(), G_EjectDroidUnit(), G_KillBox(), G_MissileImpact(), G_MoverPush(), G_RadiusDamage(), G_RunFrame(), G_RunStuckMissile(), G_TryPushingEntity(), Howler_TryDamage(), hurt_touch(), hyperspace_touch(), ImperialProbe_Wait(), Interrogator_Melee(), MineMonster_TryDamage(), NPC_BSGM_Attack(), NPC_BSSeeker_Default(), NPC_Mark1_Pain(), NPC_Mark2_Pain(), NPC_Seeker_Pain(), P_WorldEffects(), player_die(), PM_VehicleImpact(), Rancor_Attack(), Rancor_Bite(), Rancor_Crush(), Rancor_Smash(), Rancor_Swing(), Seeker_Ranged(), shipboundary_touch(), target_kill_use(), target_laser_think(), Wampa_Slash(), WP_DisruptorAltFire(), WP_FireMelee(), WP_FireStunBaton(), WP_SaberApplyDamage(), WP_SaberPositionUpdate(), and WP_SaberRadiusDamage().
04370 {
04371 gclient_t *client;
04372 int take;
04373 int save;
04374 int asave;
04375 int knockback;
04376 int max;
04377 int subamt = 0;
04378 float famt = 0;
04379 float hamt = 0;
04380 float shieldAbsorbed = 0;
04381
04382 if (targ && targ->damageRedirect)
04383 {
04384 G_Damage(&g_entities[targ->damageRedirectTo], inflictor, attacker, dir, point, damage, dflags, mod);
04385 return;
04386 }
04387
04388 if (mod == MOD_DEMP2 && targ && targ->inuse && targ->client)
04389 {
04390 if ( targ->client->ps.electrifyTime < level.time )
04391 {//electrocution effect
04392 if (targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE &&
04393 targ->m_pVehicle && (targ->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER || targ->m_pVehicle->m_pVehicleInfo->type == VH_WALKER))
04394 { //do some extra stuff to speeders/walkers
04395 targ->client->ps.electrifyTime = level.time + Q_irand( 3000, 4000 );
04396 }
04397 else if ( targ->s.NPC_class != CLASS_VEHICLE
04398 || (targ->m_pVehicle && targ->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER) )
04399 {//don't do this to fighters
04400 targ->client->ps.electrifyTime = level.time + Q_irand( 300, 800 );
04401 }
04402 }
04403 }
04404
04405 if (g_gametype.integer == GT_SIEGE &&
04406 !gSiegeRoundBegun)
04407 { //nothing can be damaged til the round starts.
04408 return;
04409 }
04410
04411 if (!targ->takedamage) {
04412 return;
04413 }
04414
04415 if ( (targ->flags&FL_SHIELDED) && mod != MOD_SABER && !targ->client)
04416 {//magnetically protected, this thing can only be damaged by lightsabers
04417 return;
04418 }
04419
04420 if ((targ->flags & FL_DMG_BY_SABER_ONLY) && mod != MOD_SABER)
04421 { //saber-only damage
04422 return;
04423 }
04424
04425 if ( targ->client )
04426 {//don't take damage when in a walker, or fighter
04427 //unless the walker/fighter is dead!!! -rww
04428 if ( targ->client->ps.clientNum < MAX_CLIENTS && targ->client->ps.m_iVehicleNum )
04429 {
04430 gentity_t *veh = &g_entities[targ->client->ps.m_iVehicleNum];
04431 if ( veh->m_pVehicle && veh->health > 0 )
04432 {
04433 if ( veh->m_pVehicle->m_pVehicleInfo->type == VH_WALKER ||
04434 veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER)
04435 {
04436 if (!(dflags & DAMAGE_NO_PROTECTION))
04437 {
04438 return;
04439 }
04440 }
04441 }
04442 }
04443 }
04444
04445 if ((targ->flags & FL_DMG_BY_HEAVY_WEAP_ONLY))
04446 { //only take damage from explosives and such
04447 if (mod != MOD_REPEATER_ALT &&
04448 mod != MOD_ROCKET &&
04449 mod != MOD_FLECHETTE_ALT_SPLASH &&
04450 mod != MOD_ROCKET_HOMING &&
04451 mod != MOD_THERMAL &&
04452 mod != MOD_THERMAL_SPLASH &&
04453 mod != MOD_TRIP_MINE_SPLASH &&
04454 mod != MOD_TIMED_MINE_SPLASH &&
04455 mod != MOD_DET_PACK_SPLASH &&
04456 mod != MOD_VEHICLE &&
04457 mod != MOD_CONC &&
04458 mod != MOD_CONC_ALT &&
04459 mod != MOD_SABER &&
04460 mod != MOD_TURBLAST &&
04461 mod != MOD_SUICIDE &&
04462 mod != MOD_FALLING &&
04463 mod != MOD_CRUSH &&
04464 mod != MOD_TELEFRAG &&
04465 mod != MOD_TRIGGER_HURT)
04466 {
04467 if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04468 { //let classes with heavy melee ability damage heavy wpn dmg doors with fists
04469 return;
04470 }
04471 }
04472 }
04473
04474 if (targ->flags & FL_BBRUSH)
04475 {
04476 if (mod == MOD_DEMP2 ||
04477 mod == MOD_DEMP2_ALT ||
04478 mod == MOD_BRYAR_PISTOL ||
04479 mod == MOD_BRYAR_PISTOL_ALT ||
04480 mod == MOD_MELEE)
04481 { //these don't damage bbrushes.. ever
04482 if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04483 { //let classes with heavy melee ability damage breakable brushes with fists
04484 return;
04485 }
04486 }
04487 }
04488
04489 if (targ && targ->client && targ->client->ps.duelInProgress)
04490 {
04491 if (attacker && attacker->client && attacker->s.number != targ->client->ps.duelIndex)
04492 {
04493 return;
04494 }
04495 else if (attacker && attacker->client && mod != MOD_SABER)
04496 {
04497 return;
04498 }
04499 }
04500 if (attacker && attacker->client && attacker->client->ps.duelInProgress)
04501 {
04502 if (targ && targ->client && targ->s.number != attacker->client->ps.duelIndex)
04503 {
04504 return;
04505 }
04506 else if (targ && targ->client && mod != MOD_SABER)
04507 {
04508 return;
04509 }
04510 }
04511
04512 if ( !(dflags & DAMAGE_NO_PROTECTION) )
04513 {//rage overridden by no_protection
04514 if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)))
04515 {
04516 damage *= 0.5;
04517 }
04518 }
04519
04520 // the intermission has allready been qualified for, so don't
04521 // allow any extra scoring
04522 if ( level.intermissionQueued ) {
04523 return;
04524 }
04525 if ( !inflictor ) {
04526 inflictor = &g_entities[ENTITYNUM_WORLD];
04527 }
04528 if ( !attacker ) {
04529 attacker = &g_entities[ENTITYNUM_WORLD];
04530 }
04531
04532 // shootable doors / buttons don't actually have any health
04533
04534 //if genericValue4 == 1 then it's glass or a breakable and those do have health
04535 if ( targ->s.eType == ET_MOVER && targ->genericValue4 != 1 ) {
04536 if ( targ->use && targ->moverState == MOVER_POS1 ) {
04537 GlobalUse( targ, inflictor, attacker );
04538 }
04539 return;
04540 }
04541 // reduce damage by the attacker's handicap value
04542 // unless they are rocket jumping
04543 if ( attacker->client
04544 && attacker != targ
04545 && attacker->s.eType == ET_PLAYER
04546 && g_gametype.integer != GT_SIEGE )
04547 {
04548 max = attacker->client->ps.stats[STAT_MAX_HEALTH];
04549 damage = damage * max / 100;
04550 }
04551
04552 if ( !(dflags&DAMAGE_NO_HIT_LOC) )
04553 {//see if we should modify it by damage location
04554 if (targ->inuse && (targ->client || targ->s.eType == ET_NPC) &&
04555 attacker->inuse && (attacker->client || attacker->s.eType == ET_NPC))
04556 { //check for location based damage stuff.
04557 G_LocationBasedDamageModifier(targ, point, mod, dflags, &damage);
04558 }
04559 }
04560
04561 if ( targ->client
04562 && targ->client->NPC_class == CLASS_RANCOR
04563 && (!attacker||!attacker->client||attacker->client->NPC_class!=CLASS_RANCOR) )
04564 {
04565 // I guess always do 10 points of damage...feel free to tweak as needed
04566 if ( damage < 10 )
04567 {//ignore piddly little damage
04568 damage = 0;
04569 }
04570 else if ( damage >= 10 )
04571 {
04572 damage = 10;
04573 }
04574 }
04575
04576 client = targ->client;
04577
04578 if ( client ) {
04579 if ( client->noclip ) {
04580 return;
04581 }
04582 }
04583
04584 if ( !dir ) {
04585 dflags |= DAMAGE_NO_KNOCKBACK;
04586 } else {
04587 VectorNormalize(dir);
04588 }
04589
04590 knockback = damage;
04591 if ( knockback > 200 ) {
04592 knockback = 200;
04593 }
04594 if ( targ->flags & FL_NO_KNOCKBACK ) {
04595 knockback = 0;
04596 }
04597 if ( dflags & DAMAGE_NO_KNOCKBACK ) {
04598 knockback = 0;
04599 }
04600
04601 // figure momentum add, even if the damage won't be taken
04602 if ( knockback && targ->client ) {
04603 vec3_t kvel;
04604 float mass;
04605
04606 mass = 200;
04607
04608 if (mod == MOD_SABER)
04609 {
04610 float saberKnockbackScale = g_saberDmgVelocityScale.value;
04611 if ( (dflags&DAMAGE_SABER_KNOCKBACK1)
04612 || (dflags&DAMAGE_SABER_KNOCKBACK2) )
04613 {//saber does knockback, scale it by the right number
04614 if ( !saberKnockbackScale )
04615 {
04616 saberKnockbackScale = 1.0f;
04617 }
04618 if ( attacker
04619 && attacker->client )
04620 {
04621 if ( (dflags&DAMAGE_SABER_KNOCKBACK1) )
04622 {
04623 if ( attacker && attacker->client )
04624 {
04625 saberKnockbackScale *= attacker->client->saber[0].knockbackScale;
04626 }
04627 }
04628 if ( (dflags&DAMAGE_SABER_KNOCKBACK1_B2) )
04629 {
04630 if ( attacker && attacker->client )
04631 {
04632 saberKnockbackScale *= attacker->client->saber[0].knockbackScale2;
04633 }
04634 }
04635 if ( (dflags&DAMAGE_SABER_KNOCKBACK2) )
04636 {
04637 if ( attacker && attacker->client )
04638 {
04639 saberKnockbackScale *= attacker->client->saber[1].knockbackScale;
04640 }
04641 }
04642 if ( (dflags&DAMAGE_SABER_KNOCKBACK2_B2) )
04643 {
04644 if ( attacker && attacker->client )
04645 {
04646 saberKnockbackScale *= attacker->client->saber[1].knockbackScale2;
04647 }
04648 }
04649 }
04650 }
04651 VectorScale (dir, (g_knockback.value * (float)knockback / mass)*saberKnockbackScale, kvel);
04652 }
04653 else
04654 {
04655 VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
04656 }
04657 VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
04658
04659 if (attacker && attacker->client && attacker != targ)
04660 {
04661 float dur = 5000;
04662 float dur2 = 100;
04663 if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE)
04664 {
04665 dur = 25000;
04666 dur2 = 25000;
04667 }
04668 targ->client->ps.otherKiller = attacker->s.number;
04669 targ->client->ps.otherKillerTime = level.time + dur;
04670 targ->client->ps.otherKillerDebounceTime = level.time + dur2;
04671 }
04672 // set the timer so that the other client can't cancel
04673 // out the movement immediately
04674 if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER || (dflags&DAMAGE_SABER_KNOCKBACK1) || (dflags&DAMAGE_SABER_KNOCKBACK2) || (dflags&DAMAGE_SABER_KNOCKBACK1_B2) || (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) ) {
04675 int t;
04676
04677 t = knockback * 2;
04678 if ( t < 50 ) {
04679 t = 50;
04680 }
04681 if ( t > 200 ) {
04682 t = 200;
04683 }
04684 targ->client->ps.pm_time = t;
04685 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
04686 }
04687 }
04688 else if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE && attacker != targ)
04689 {
04690 targ->client->ps.otherKiller = attacker->s.number;
04691 targ->client->ps.otherKillerTime = level.time + 25000;
04692 targ->client->ps.otherKillerDebounceTime = level.time + 25000;
04693 }
04694
04695
04696 if ( (g_trueJedi.integer || g_gametype.integer == GT_SIEGE)
04697 && client )
04698 {//less explosive damage for jedi, more saber damage for non-jedi
04699 if ( client->ps.trueJedi
04700 || (g_gametype.integer == GT_SIEGE&&client->ps.weapon == WP_SABER))
04701 {//if the target is a trueJedi, reduce splash and explosive damage to 1/2
04702 switch ( mod )
04703 {
04704 case MOD_REPEATER_ALT:
04705 case MOD_REPEATER_ALT_SPLASH:
04706 case MOD_DEMP2_ALT:
04707 case MOD_FLECHETTE_ALT_SPLASH:
04708 case MOD_ROCKET:
04709 case MOD_ROCKET_SPLASH:
04710 case MOD_ROCKET_HOMING:
04711 case MOD_ROCKET_HOMING_SPLASH:
04712 case MOD_THERMAL:
04713 case MOD_THERMAL_SPLASH:
04714 case MOD_TRIP_MINE_SPLASH:
04715 case MOD_TIMED_MINE_SPLASH:
04716 case MOD_DET_PACK_SPLASH:
04717 damage *= 0.75;
04718 break;
04719 }
04720 }
04721 else if ( (client->ps.trueNonJedi || (g_gametype.integer == GT_SIEGE&&client->ps.weapon != WP_SABER))
04722 && mod == MOD_SABER )
04723 {//if the target is a trueNonJedi, take more saber damage... combined with the 1.5 in the w_saber stuff, this is 6 times damage!
04724 if ( damage < 100 )
04725 {
04726 damage *= 4;
04727 if ( damage > 100 )
04728 {
04729 damage = 100;
04730 }
04731 }
04732 }
04733 }
04734
04735 if (attacker->client && targ->client && g_gametype.integer == GT_SIEGE &&
04736 targ->client->siegeClass != -1 && (bgSiegeClasses[targ->client->siegeClass].classflags & (1<<CFL_STRONGAGAINSTPHYSICAL)))
04737 { //this class is flagged to take less damage from physical attacks.
04738 //For now I'm just decreasing against any client-based attack, this can be changed later I guess.
04739 damage *= 0.5;
04740 }
04741
04742 // check for completely getting out of the damage
04743 if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
04744
04745 // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
04746 // if the attacker was on the same team
04747 if ( targ != attacker)
04748 {
04749 if (OnSameTeam (targ, attacker))
04750 {
04751 if ( !g_friendlyFire.integer )
04752 {
04753 return;
04754 }
04755 }
04756 else if (attacker && attacker->inuse &&
04757 !attacker->client && attacker->activator &&
04758 targ != attacker->activator &&
04759 attacker->activator->inuse && attacker->activator->client)
04760 { //emplaced guns don't hurt teammates of user
04761 if (OnSameTeam (targ, attacker->activator))
04762 {
04763 if ( !g_friendlyFire.integer )
04764 {
04765 return;
04766 }
04767 }
04768 }
04769 else if (targ->inuse && targ->client &&
04770 g_gametype.integer >= GT_TEAM &&
04771 attacker->s.number >= MAX_CLIENTS &&
04772 attacker->alliedTeam &&
04773 targ->client->sess.sessionTeam == attacker->alliedTeam &&
04774 !g_friendlyFire.integer)
04775 { //things allied with my team should't hurt me.. I guess
04776 return;
04777 }
04778 }
04779
04780 if (g_gametype.integer == GT_JEDIMASTER && !g_friendlyFire.integer &&
04781 targ && targ->client && attacker && attacker->client &&
04782 targ != attacker && !targ->client->ps.isJediMaster && !attacker->client->ps.isJediMaster &&
04783 G_ThereIsAMaster())
04784 {
04785 return;
04786 }
04787
04788 if (targ->s.number >= MAX_CLIENTS && targ->client
04789 && targ->s.shouldtarget && targ->s.teamowner &&
04790 attacker && attacker->inuse && attacker->client && targ->s.owner >= 0 && targ->s.owner < MAX_CLIENTS)
04791 {
04792 gentity_t *targown = &g_entities[targ->s.owner];
04793
04794 if (targown && targown->inuse && targown->client && OnSameTeam(targown, attacker))
04795 {
04796 if (!g_friendlyFire.integer)
04797 {
04798 return;
04799 }
04800 }
04801 }
04802
04803 // check for godmode
04804 if ( (targ->flags & FL_GODMODE) && targ->s.eType != ET_NPC ) {
04805 return;
04806 }
04807
04808 if (targ && targ->client && (targ->client->ps.eFlags & EF_INVULNERABLE) &&
04809 attacker && attacker->client && targ != attacker)
04810 {
04811 if (targ->client->invulnerableTimer <= level.time)
04812 {
04813 targ->client->ps.eFlags &= ~EF_INVULNERABLE;
04814 }
04815 else
04816 {
04817 return;
04818 }
04819 }
04820 }
04821
04822 //check for teamnodmg
04823 //NOTE: non-client objects hitting clients (and clients hitting clients) purposely doesn't obey this teamnodmg (for emplaced guns)
04824 if ( attacker && !targ->client )
04825 {//attacker hit a non-client
04826 if ( g_gametype.integer == GT_SIEGE &&
04827 !g_ff_objectives.integer )
04828 {//in siege mode (and...?)
04829 if ( targ->teamnodmg )
04830 {//targ shouldn't take damage from a certain team
04831 if ( attacker->client )
04832 {//a client hit a non-client object
04833 if ( targ->teamnodmg == attacker->client->sess.sessionTeam )
04834 {
04835 return;
04836 }
04837 }
04838 else if ( attacker->teamnodmg )
04839 {//a non-client hit a non-client object
04840 //FIXME: maybe check alliedTeam instead?
04841 if ( targ->teamnodmg == attacker->teamnodmg )
04842 {
04843 if (attacker->activator &&
04844 attacker->activator->inuse &&
04845 attacker->activator->s.number < MAX_CLIENTS &&
04846 attacker->activator->client &&
04847 attacker->activator->client->sess.sessionTeam != targ->teamnodmg)
04848 { //uh, let them damage it I guess.
04849 }
04850 else
04851 {
04852 return;
04853 }
04854 }
04855 }
04856 }
04857 }
04858 }
04859
04860 // battlesuit protects from all radius damage (but takes knockback)
04861 // and protects 50% against all damage
04862 if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
04863 G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
04864 if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
04865 return;
04866 }
04867 damage *= 0.5;
04868 }
04869
04870 // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
04871 if ( attacker->client && targ != attacker && targ->health > 0
04872 && targ->s.eType != ET_MISSILE
04873 && targ->s.eType != ET_GENERAL
04874 && client) {
04875 if ( OnSameTeam( targ, attacker ) ) {
04876 attacker->client->ps.persistant[PERS_HITS]--;
04877 } else {
04878 attacker->client->ps.persistant[PERS_HITS]++;
04879 }
04880 attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
04881 }
04882
04883 // always give half damage if hurting self... but not in siege. Heavy weapons need a counter.
04884 // calculated after knockback, so rocket jumping works
04885 if ( targ == attacker && !(dflags & DAMAGE_NO_SELF_PROTECTION)) {
04886 if ( g_gametype.integer == GT_SIEGE )
04887 {
04888 damage *= 1.5;
04889 }
04890 else
04891 {
04892 damage *= 0.5;
04893 }
04894 }
04895
04896 if ( damage < 1 ) {
04897 damage = 1;
04898 }
04899 take = damage;
04900 save = 0;
04901
04902 // save some from armor
04903 asave = CheckArmor (targ, take, dflags);
04904
04905 if (asave)
04906 {
04907 shieldAbsorbed = asave;
04908 }
04909
04910 take -= asave;
04911 if ( targ->client )
04912 {//update vehicle shields and armor, check for explode
04913 if ( targ->client->NPC_class == CLASS_VEHICLE &&
04914 targ->m_pVehicle )
04915 {//FIXME: should be in its own function in g_vehicles.c now, too big to be here
04916 int surface = -1;
04917 if ( attacker )
04918 {//so we know the last guy who shot at us
04919 targ->enemy = attacker;
04920 }
04921
04922 if ( ( targ->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL ) )
04923 {
04924 //((CVehicleNPC *)targ->NPC)->m_ulFlags |= CVehicleNPC::VEH_BUCKING;
04925 }
04926
04927 targ->m_pVehicle->m_iShields = targ->client->ps.stats[STAT_ARMOR];
04928 G_VehUpdateShields( targ );
04929 targ->m_pVehicle->m_iArmor -= take;
04930 if ( targ->m_pVehicle->m_iArmor <= 0 )
04931 {
04932 targ->s.eFlags |= EF_DEAD;
04933 targ->client->ps.eFlags |= EF_DEAD;
04934 targ->m_pVehicle->m_iArmor = 0;
04935 }
04936 if ( targ->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
04937 {//get the last surf that was hit
04938 if ( targ->client && targ->client->g2LastSurfaceTime == level.time)
04939 {
04940 char hitSurface[MAX_QPATH];
04941
04942 trap_G2API_GetSurfaceName(targ->ghoul2, targ->client->g2LastSurfaceHit, 0, hitSurface);
04943
04944 if (hitSurface[0])
04945 {
04946 surface = G_ShipSurfaceForSurfName( &hitSurface[0] );
04947
04948 if ( take && surface > 0 )
04949 {//hit a certain part of the ship
04950 int deathPoint = 0;
04951
04952 targ->locationDamage[surface] += take;
04953
04954 switch(surface)
04955 {
04956 case SHIPSURF_FRONT:
04957 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_front;
04958 break;
04959 case SHIPSURF_BACK:
04960 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_back;
04961 break;
04962 case SHIPSURF_RIGHT:
04963 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_right;
04964 break;
04965 case SHIPSURF_LEFT:
04966 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_left;
04967 break;
04968 default:
04969 break;
04970 }
04971
04972 //presume 0 means it wasn't set and so it should never die.
04973 if ( deathPoint )
04974 {
04975 if ( targ->locationDamage[surface] >= deathPoint)
04976 { //this area of the ship is now dead
04977 if ( G_FlyVehicleDestroySurface( targ, surface ) )
04978 {//actually took off a surface
04979 G_VehicleSetDamageLocFlags( targ, surface, deathPoint );
04980 }
04981 }
04982 else
04983 {
04984 G_VehicleSetDamageLocFlags( targ, surface, deathPoint );
04985 }
04986 }
04987 }
04988 }
04989 }
04990 }
04991 if ( targ->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL )
04992 {
04993 /*
04994 if ( targ->m_pVehicle->m_iArmor <= 0 )
04995 {//vehicle all out of armor
04996 Vehicle_t *pVeh = targ->m_pVehicle;
04997 if ( pVeh->m_iDieTime == 0 )
04998 {//just start the flaming effect and explosion delay, if it's not going already...
04999 pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, 0 );
05000 }
05001 }
05002 else*/
05003 if ( attacker
05004 //&& attacker->client
05005 && targ != attacker
05006 && point
05007 && !VectorCompare( targ->client->ps.origin, point )
05008 && targ->m_pVehicle->m_LandTrace.fraction >= 1.0f)
05009 {//just took a hit, knock us around
05010 vec3_t vUp, impactDir;
05011 float impactStrength = (damage/200.0f)*10.0f;
05012 float dot = 0.0f;
05013 if ( impactStrength > 10.0f )
05014 {
05015 impactStrength = 10.0f;
05016 }
05017 //pitch or roll us based on where we were hit
05018 AngleVectors( targ->m_pVehicle->m_vOrientation, NULL, NULL, vUp );
05019 VectorSubtract( point, targ->r.currentOrigin, impactDir );
05020 VectorNormalize( impactDir );
05021 if ( surface <= 0 )
05022 {//no surf guess where we were hit, then
05023 vec3_t vFwd, vRight;
05024 AngleVectors( targ->m_pVehicle->m_vOrientation, vFwd, vRight, vUp );
05025 dot = DotProduct( vRight, impactDir );
05026 if ( dot > 0.4f )
05027 {
05028 surface = SHIPSURF_RIGHT;
05029 }
05030 else if ( dot < -0.4f )
05031 {
05032 surface = SHIPSURF_LEFT;
05033 }
05034 else
05035 {
05036 dot = DotProduct( vFwd, impactDir );
05037 if ( dot > 0.0f )
05038 {
05039 surface = SHIPSURF_FRONT;
05040 }
05041 else
05042 {
05043 surface = SHIPSURF_BACK;
05044 }
05045 }
05046 }
05047 switch ( surface )
05048 {
05049 case SHIPSURF_FRONT:
05050 dot = DotProduct( vUp, impactDir );
05051 if ( dot > 0 )
05052 {
05053 targ->m_pVehicle->m_vOrientation[PITCH] += impactStrength;
05054 }
05055 else
05056 {
05057 targ->m_pVehicle->m_vOrientation[PITCH] -= impactStrength;
05058 }
05059 break;
05060 case SHIPSURF_BACK:
05061 dot = DotProduct( vUp, impactDir );
05062 if ( dot > 0 )
05063 {
05064 targ->m_pVehicle->m_vOrientation[PITCH] -= impactStrength;
05065 }
05066 else
05067 {
05068 targ->m_pVehicle->m_vOrientation[PITCH] += impactStrength;
05069 }
05070 break;
05071 case SHIPSURF_RIGHT:
05072 dot = DotProduct( vUp, impactDir );
05073 if ( dot > 0 )
05074 {
05075 targ->m_pVehicle->m_vOrientation[ROLL] -= impactStrength;
05076 }
05077 else
05078 {
05079 targ->m_pVehicle->m_vOrientation[ROLL] += impactStrength;
05080 }
05081 break;
05082 case SHIPSURF_LEFT:
05083 dot = DotProduct( vUp, impactDir );
05084 if ( dot > 0 )
05085 {
05086 targ->m_pVehicle->m_vOrientation[ROLL] += impactStrength;
05087 }
05088 else
05089 {
05090 targ->m_pVehicle->m_vOrientation[ROLL] -= impactStrength;
05091 }
05092 break;
05093 }
05094
05095 }
05096 }
05097 }
05098 }
05099
05100 if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT )
05101 {//FIXME: screw with non-animal vehicles, too?
05102 if ( client )
05103 {
05104 if ( client->NPC_class == CLASS_VEHICLE
05105 && targ->m_pVehicle
05106 && targ->m_pVehicle->m_pVehicleInfo
05107 && targ->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
05108 {//all damage goes into the disruption of shields and systems
05109 take = 0;
05110 }
05111 else
05112 {
05113
05114 if (client->jetPackOn)
05115 { //disable jetpack temporarily
05116 Jetpack_Off(targ);
05117 client->jetPackToggleTime = level.time + Q_irand(3000, 10000);
05118 }
05119
05120 if ( client->NPC_class == CLASS_PROTOCOL || client->NPC_class == CLASS_SEEKER ||
05121 client->NPC_class == CLASS_R2D2 || client->NPC_class == CLASS_R5D2 ||
05122 client->NPC_class == CLASS_MOUSE || client->NPC_class == CLASS_GONK )
05123 {
05124 // DEMP2 does more damage to these guys.
05125 take *= 2;
05126 }
05127 else if ( client->NPC_class == CLASS_PROBE || client->NPC_class == CLASS_INTERROGATOR ||
05128 client->NPC_class == CLASS_MARK1 || client->NPC_class == CLASS_MARK2 || client->NPC_class == CLASS_SENTRY ||
05129 client->NPC_class == CLASS_ATST )
05130 {
05131 // DEMP2 does way more damage to these guys.
05132 take *= 5;
05133 }
05134 else
05135 {
05136 if (take > 0)
05137 {
05138 take /= 3;
05139 if (take < 1)
05140 {
05141 take = 1;
05142 }
05143 }
05144 }
05145 }
05146 }
05147 }
05148
05149 #ifndef FINAL_BUILD
05150 if ( g_debugDamage.integer ) {
05151 G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
05152 targ->health, take, asave );
05153 }
05154 #endif
05155
05156 // add to the damage inflicted on a player this frame
05157 // the total will be turned into screen blends and view angle kicks
05158 // at the end of the frame
05159 if ( client ) {
05160 if ( attacker ) {
05161 client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
05162 } else {
05163 client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
05164 }
05165 client->damage_armor += asave;
05166 client->damage_blood += take;
05167 client->damage_knockback += knockback;
05168 if ( dir ) {
05169 VectorCopy ( dir, client->damage_from );
05170 client->damage_fromWorld = qfalse;
05171 } else {
05172 VectorCopy ( targ->r.currentOrigin, client->damage_from );
05173 client->damage_fromWorld = qtrue;
05174 }
05175
05176 if (attacker && attacker->client)
05177 {
05178 BotDamageNotification(client, attacker);
05179 }
05180 else if (inflictor && inflictor->client)
05181 {
05182 BotDamageNotification(client, inflictor);
05183 }
05184 }
05185
05186 // See if it's the player hurting the emeny flag carrier
05187 if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY) {
05188 Team_CheckHurtCarrier(targ, attacker);
05189 }
05190
05191 if (targ->client) {
05192 // set the last client who damaged the target
05193 targ->client->lasthurt_client = attacker->s.number;
05194 targ->client->lasthurt_mod = mod;
05195 }
05196
05197 if ( !(dflags & DAMAGE_NO_PROTECTION) )
05198 {//protect overridden by no_protection
05199 if (take && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_PROTECT)))
05200 {
05201 if (targ->client->ps.fd.forcePower)
05202 {
05203 int maxtake = take;
05204
05205 //G_Sound(targ, CHAN_AUTO, protectHitSound);
05206 if (targ->client->forcePowerSoundDebounce < level.time)
05207 {
05208 G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT);
05209 targ->client->forcePowerSoundDebounce = level.time + 400;
05210 }
05211
05212 if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1)
05213 {
05214 famt = 1;
05215 hamt = 0.40;
05216
05217 if (maxtake > 100)
05218 {
05219 maxtake = 100;
05220 }
05221 }
05222 else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_2)
05223 {
05224 famt = 0.5;
05225 hamt = 0.60;
05226
05227 if (maxtake > 200)
05228 {
05229 maxtake = 200;
05230 }
05231 }
05232 else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_3)
05233 {
05234 famt = 0.25;
05235 hamt = 0.80;
05236
05237 if (maxtake > 400)
05238 {
05239 maxtake = 400;
05240 }
05241 }
05242
05243 if (!targ->client->ps.powerups[PW_FORCE_BOON])
05244 {
05245 targ->client->ps.fd.forcePower -= maxtake*famt;
05246 }
05247 else
05248 {
05249 targ->client->ps.fd.forcePower -= (maxtake*famt)/2;
05250 }
05251 subamt = (maxtake*hamt)+(take-maxtake);
05252 if (targ->client->ps.fd.forcePower < 0)
05253 {
05254 subamt += targ->client->ps.fd.forcePower;
05255 targ->client->ps.fd.forcePower = 0;
05256 }
05257 if (subamt)
05258 {
05259 take -= subamt;
05260
05261 if (take < 0)
05262 {
05263 take = 0;
05264 }
05265 }
05266 }
05267 }
05268 }
05269
05270 if (shieldAbsorbed)
05271 {
05272 /*
05273 if ( targ->client->NPC_class == CLASS_VEHICLE )
05274 {
05275 targ->client->ps.electrifyTime = level.time + Q_irand( 500, 1000 );
05276 }
05277 else
05278 */
05279 {
05280 gentity_t *evEnt;
05281
05282 // Send off an event to show a shield shell on the player, pointing in the right direction.
05283 //evEnt = G_TempEntity(vec3_origin, EV_SHIELD_HIT);
05284 //rww - er.. what the? This isn't broadcast, why is it being set on vec3_origin?!
05285 evEnt = G_TempEntity(targ->r.currentOrigin, EV_SHIELD_HIT);
05286 evEnt->s.otherEntityNum = targ->s.number;
05287 evEnt->s.eventParm = DirToByte(dir);
05288 evEnt->s.time2=shieldAbsorbed;
05289 /*
05290 shieldAbsorbed *= 20;
05291
05292 if (shieldAbsorbed > 1500)
05293 {
05294 shieldAbsorbed = 1500;
05295 }
05296 if (shieldAbsorbed < 200)
05297 {
05298 shieldAbsorbed = 200;
05299 }
05300
05301 if (targ->client->ps.powerups[PW_SHIELDHIT] < (level.time + shieldAbsorbed))
05302 {
05303 targ->client->ps.powerups[PW_SHIELDHIT] = level.time + shieldAbsorbed;
05304 }
05305 //flicker for as many ms as damage was absorbed (*20)
05306 //therefore 10 damage causes 1/5 of a seond of flickering, whereas
05307 //a full 100 causes 2 seconds (but is reduced to 1.5 seconds due to the max)
05308
05309 */
05310 }
05311 }
05312
05313 // do the damage
05314 if (take)
05315 {
05316 if (targ->client && targ->s.number < MAX_CLIENTS &&
05317 (mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT))
05318 { //uh.. shock them or something. what the hell, I don't know.
05319 if (targ->client->ps.weaponTime <= 0)
05320 { //yeah, we were supposed to be beta a week ago, I don't feel like
05321 //breaking the game so I'm gonna be safe and only do this only
05322 //if your weapon is not busy
05323 targ->client->ps.weaponTime = 2000;
05324 targ->client->ps.electrifyTime = level.time + 2000;
05325 if (targ->client->ps.weaponstate == WEAPON_CHARGING ||
05326 targ->client->ps.weaponstate == WEAPON_CHARGING_ALT)
05327 {
05328 targ->client->ps.weaponstate = WEAPON_READY;
05329 }
05330 }
05331 }
05332
05333 if ( !(dflags & DAMAGE_NO_PROTECTION) )
05334 {//rage overridden by no_protection
05335 if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client))
05336 {
05337 take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]+1);
05338 }
05339 }
05340 targ->health = targ->health - take;
05341
05342 if ( (targ->flags&FL_UNDYING) )
05343 {//take damage down to 1, but never die
05344 if ( targ->health < 1 )
05345 {
05346 targ->health = 1;
05347 }
05348 }
05349
05350 if ( targ->client ) {
05351 targ->client->ps.stats[STAT_HEALTH] = targ->health;
05352 }
05353
05354 if ( !(dflags & DAMAGE_NO_PROTECTION) )
05355 {//rage overridden by no_protection
05356 if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client))
05357 {
05358 if (targ->health <= 0)
05359 {
05360 targ->health = 1;
05361 }
05362 if (targ->client->ps.stats[STAT_HEALTH] <= 0)
05363 {
05364 targ->client->ps.stats[STAT_HEALTH] = 1;
05365 }
05366 }
05367 }
05368
05369 //We want to go ahead and set gPainHitLoc regardless of if we have a pain func,
05370 //so we can adjust the location damage too.
05371 if (targ->client && targ->ghoul2 && targ->client->g2LastSurfaceTime == level.time)
05372 { //We updated the hit surface this frame, so it's valid.
05373 char hitSurface[MAX_QPATH];
05374
05375 trap_G2API_GetSurfaceName(targ->ghoul2, targ->client->g2LastSurfaceHit, 0, hitSurface);
05376
05377 if (hitSurface[0])
05378 {
05379 G_GetHitLocFromSurfName(targ, hitSurface, &gPainHitLoc, point, dir, vec3_origin, mod);
05380 }
05381 else
05382 {
05383 gPainHitLoc = -1;
05384 }
05385
05386 if (gPainHitLoc < HL_MAX && gPainHitLoc >= 0 && targ->locationDamage[gPainHitLoc] < Q3_INFINITE &&
05387 (targ->s.eType == ET_PLAYER || targ->s.NPC_class != CLASS_VEHICLE))
05388 {
05389 targ->locationDamage[gPainHitLoc] += take;
05390
05391 if (g_armBreakage.integer && !targ->client->ps.brokenLimbs &&
05392 targ->client->ps.stats[STAT_HEALTH] > 0 && targ->health > 0 &&
05393 !(targ->s.eFlags & EF_DEAD))
05394 { //check for breakage
05395 if (targ->locationDamage[HL_ARM_RT]+targ->locationDamage[HL_HAND_RT] >= 80)
05396 {
05397 G_BreakArm(targ, BROKENLIMB_RARM);
05398 }
05399 else if (targ->locationDamage[HL_ARM_LT]+targ->locationDamage[HL_HAND_LT] >= 80)
05400 {
05401 G_BreakArm(targ, BROKENLIMB_LARM);
05402 }
05403 }
05404 }
05405 }
05406 else
05407 {
05408 gPainHitLoc = -1;
05409 }
05410
05411 if (targ->maxHealth)
05412 { //if this is non-zero this guy should be updated his s.health to send to the client
05413 G_ScaleNetHealth(targ);
05414 }
05415
05416 if ( targ->health <= 0 ) {
05417 if ( client )
05418 {
05419 targ->flags |= FL_NO_KNOCKBACK;
05420
05421 if (point)
05422 {
05423 VectorCopy( point, targ->pos1 );
05424 }
05425 else
05426 {
05427 VectorCopy(targ->client->ps.origin, targ->pos1);
05428 }
05429 }
05430 else if (targ->s.eType == ET_NPC)
05431 { //g2animent
05432 VectorCopy(point, targ->pos1);
05433 }
05434
05435 if (targ->health < -999)
05436 targ->health = -999;
05437
05438 // If we are a breaking glass brush, store the damage point so we can do cool things with it.
05439 if ( targ->r.svFlags & SVF_GLASS_BRUSH )
05440 {
05441 VectorCopy( point, targ->pos1 );
05442 if (dir)
05443 {
05444 VectorCopy( dir, targ->pos2 );
05445 }
05446 else
05447 {
05448 VectorClear(targ->pos2);
05449 }
05450 }
05451
05452 if (targ->s.eType == ET_NPC &&
05453 targ->client &&
05454 (targ->s.eFlags & EF_DEAD))
05455 { //an NPC that's already dead. Maybe we can cut some more limbs off!
05456 if ( (mod == MOD_SABER || (mod == MOD_MELEE && G_HeavyMelee( attacker )) )//saber or heavy melee (claws)
05457 && take > 2
05458 && !(dflags&DAMAGE_NO_DISMEMBER) )
05459 {
05460 G_CheckForDismemberment(targ, attacker, targ->pos1, take, targ->client->ps.torsoAnim, qtrue);
05461 }
05462 }
05463
05464 targ->enemy = attacker;
05465 targ->die (targ, inflictor, attacker, take, mod);
05466 G_ActivateBehavior( targ, BSET_DEATH );
05467 return;
05468 }
05469 else
05470 {
05471 if ( g_debugMelee.integer )
05472 {//getting hurt makes you let go of the wall
05473 if ( targ->client && (targ->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
05474 {
05475 G_LetGoOfWall( targ );
05476 }
05477 }
05478 if ( targ->pain )
05479 {
05480 if (targ->s.eType != ET_NPC || mod != MOD_SABER || take > 1)
05481 { //don't even notify NPCs of pain if it's just idle saber damage
05482 gPainMOD = mod;
05483 if (point)
05484 {
05485 VectorCopy(point, gPainPoint);
05486 }
05487 else
05488 {
05489 VectorCopy(targ->r.currentOrigin, gPainPoint);
05490 }
05491 targ->pain (targ, attacker, take);
05492 }
05493 }
05494 }
05495
05496 G_LogWeaponDamage(attacker->s.number, mod, take);
05497 }
05498
05499 }
|
|
||||||||||||
|
Definition at line 1868 of file g_combat.c. References DEATH_ALERT_RADIUS, DEATH_ALERT_SOUND_RADIUS, G_AlertTeam(), and gentity_t. Referenced by player_die().
01869 {//FIXME: with all the other alert stuff, do we really need this?
01870 G_AlertTeam( victim, attacker, DEATH_ALERT_RADIUS, DEATH_ALERT_SOUND_RADIUS );
01871 }
|
|
||||||||||||||||||||||||||||||||||||
|
Definition at line 3311 of file g_combat.c. References entityState_s::apos, BG_GetRootSurfNameWithVariant(), BG_InDeathAnim(), gentity_s::classname, gentity_s::client, gentity_s::clipmask, Com_sprintf(), entityShared_t::contents, CONTENTS_TRIGGER, entityShared_t::currentAngles, entityShared_t::currentOrigin, entityState_s::customRGBA, gentity_s::epGravFactor, gentity_s::epVelocity, ET_GENERAL, ET_NPC, entityState_s::eType, FRAMETIME, G2_MODEL_PART, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, entityState_s::g2radius, G_SetOrigin(), G_Spawn(), gentity_t, gentity_s::ghoul2, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, LimbThink(), LimbTouch(), MASK_SOLID, MAX_QPATH, entityShared_t::maxs, entityShared_t::mins, entityState_s::modelGhoul2, entityState_s::modelindex, gentity_s::nextthink, entityState_s::number, gclient_s::olderIsValid, gclient_s::olderSaberBase, entityState_s::otherEntityNum2, gentity_s::physicsObject, entityState_s::pos, gclient_s::ps, Q_irand(), Q_strncpyz(), qtrue, gentity_s::r, gentity_s::s, gentity_s::speed, SVF_USE_CURRENT_ORIGIN, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, playerState_s::torsoAnim, playerState_s::torsoTimer, gentity_s::touch, trap_G2API_GetSurfaceRenderStatus(), trap_G2API_SetSurfaceOnOff(), trap_LinkEntity(), trajectory_t::trBase, trajectory_t::trDelta, vec3_t, VectorAdd, VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, playerState_s::weapon, and WP_SABER. Referenced by DismembermentByNum(), DismembermentTest(), G_CheckForDismemberment(), Rancor_Attack(), Rancor_Bite(), and Wampa_Slash().
03312 {
03313 vec3_t newPoint, dir, vel;
03314 gentity_t *limb;
03315 char limbName[MAX_QPATH];
03316 char stubName[MAX_QPATH];
03317 char stubCapName[MAX_QPATH];
03318
03319 if (limbType == G2_MODELPART_HEAD)
03320 {
03321 Q_strncpyz( limbName , "head", sizeof( limbName ) );
03322 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
03323 }
03324 else if (limbType == G2_MODELPART_WAIST)
03325 {
03326 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
03327 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
03328 }
03329 else if (limbType == G2_MODELPART_LARM)
03330 {
03331 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_arm", limbName, sizeof(limbName) );
03332 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03333 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
03334 }
03335 else if (limbType == G2_MODELPART_RARM)
03336 {
03337 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", limbName, sizeof(limbName) );
03338 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03339 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
03340 }
03341 else if (limbType == G2_MODELPART_RHAND)
03342 {
03343 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_hand", limbName, sizeof(limbName) );
03344 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", stubName, sizeof(stubName) );
03345 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
03346 }
03347 else if (limbType == G2_MODELPART_LLEG)
03348 {
03349 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_leg", limbName, sizeof(limbName) );
03350 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03351 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
03352 }
03353 else if (limbType == G2_MODELPART_RLEG)
03354 {
03355 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03356 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03357 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03358 }
03359 else
03360 {//umm... just default to the right leg, I guess (same as on client)
03361 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03362 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03363 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03364 }
03365
03366 if (ent->ghoul2 && limbName && trap_G2API_GetSurfaceRenderStatus(ent->ghoul2, 0, limbName))
03367 { //is it already off? If so there's no reason to be doing it again, so get out of here.
03368 return;
03369 }
03370
03371 VectorCopy( point, newPoint );
03372 limb = G_Spawn();
03373 limb->classname = "playerlimb";
03374
03375 /*
03376 if (limbType == G2_MODELPART_WAIST)
03377 { //slight hack
03378 newPoint[2] += 1;
03379 }
03380 */
03381
03382 G_SetOrigin( limb, newPoint );
03383 VectorCopy( newPoint, limb->s.pos.trBase );
03384 limb->think = LimbThink;
03385 limb->touch = LimbTouch;
03386 limb->speed = level.time + Q_irand(8000, 16000);
03387 limb->nextthink = level.time + FRAMETIME;
03388
03389 limb->r.svFlags = SVF_USE_CURRENT_ORIGIN;
03390 limb->clipmask = MASK_SOLID;
03391 limb->r.contents = CONTENTS_TRIGGER;
03392 limb->physicsObject = qtrue;
03393 VectorSet( limb->r.mins, -6.0f, -6.0f, -3.0f );
03394 VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f );
03395
03396 limb->s.g2radius = 200;
03397
03398 limb->s.eType = ET_GENERAL;
03399 limb->s.weapon = G2_MODEL_PART;
03400 limb->s.modelGhoul2 = limbType;
03401 limb->s.modelindex = ent->s.number;
03402 if (!ent->client)
03403 {
03404 limb->s.modelindex = -1;
03405 limb->s.otherEntityNum2 = ent->s.number;
03406 }
03407
03408 VectorClear(limb->s.apos.trDelta);
03409
03410 if (ent->client)
03411 {
03412 VectorCopy(ent->client->ps.viewangles, limb->r.currentAngles);
03413 VectorCopy(ent->client->ps.viewangles, limb->s.apos.trBase);
03414 }
03415 else
03416 {
03417 VectorCopy(ent->r.currentAngles, limb->r.currentAngles);
03418 VectorCopy(ent->r.currentAngles, limb->s.apos.trBase);
03419 }
03420
03421 //Set up the ExPhys values for the entity.
03422 limb->epGravFactor = 0;
03423 VectorClear(limb->epVelocity);
03424 VectorSubtract( point, ent->r.currentOrigin, dir );
03425 VectorNormalize( dir );
03426 if (ent->client)
03427 {
03428 VectorCopy(ent->client->ps.velocity, vel);
03429 }
03430 else
03431 {
03432 VectorCopy(ent->s.pos.trDelta, vel);
03433 }
03434 VectorMA( vel, 80, dir, limb->epVelocity );
03435
03436 //add some vertical velocity
03437 if (limbType == G2_MODELPART_HEAD ||
03438 limbType == G2_MODELPART_WAIST)
03439 {
03440 limb->epVelocity[2] += 10;
03441 }
03442
03443 if (enemy && enemy->client && ent && ent != enemy && ent->s.number != enemy->s.number &&
03444 enemy->client->ps.weapon == WP_SABER && enemy->client->olderIsValid &&
03445 (level.time - enemy->client->lastSaberStorageTime) < 200)
03446 { //The enemy has valid saber positions between this and last frame. Use them to factor in direction of the limb.
03447 vec3_t dif;
03448 float totalDistance;
03449 const float distScale = 1.2f;
03450
03451 //scale down the initial velocity first, which is based on the speed of the limb owner.
03452 //ExPhys object velocity operates on a slightly different scale than Q3-based physics velocity.
03453 VectorScale(limb->epVelocity, 0.4f, limb->epVelocity);
03454
03455 VectorSubtract(enemy->client->lastSaberBase_Always, enemy->client->olderSaberBase, dif);
03456 totalDistance = VectorNormalize(dif);
03457
03458 VectorScale(dif, totalDistance*distScale, dif);
03459 VectorAdd(limb->epVelocity, dif, limb->epVelocity);
03460
03461 if (ent->client && (ent->client->ps.torsoTimer > 0 || !BG_InDeathAnim(ent->client->ps.torsoAnim)))
03462 { //if he's done with his death anim we don't actually want the limbs going far
03463 vec3_t preVel;
03464
03465 VectorCopy(limb->epVelocity, preVel);
03466 preVel[2] = 0;
03467 totalDistance = VectorNormalize(preVel);
03468
03469 if (totalDistance < 40.0f)
03470 {
03471 float mAmt = 40.0f;//60.0f/totalDistance;
03472
03473 limb->epVelocity[0] = preVel[0]*mAmt;
03474 limb->epVelocity[1] = preVel[1]*mAmt;
03475 }
03476 }
03477 else if (ent->client)
03478 {
03479 VectorScale(limb->epVelocity, 0.3f, limb->epVelocity);
03480 }
03481 }
03482
03483 if (ent->s.eType == ET_NPC && ent->ghoul2 && limbName && stubCapName)
03484 { //if it's an npc remove these surfs on the server too. For players we don't even care cause there's no further dismemberment after death.
03485 trap_G2API_SetSurfaceOnOff(ent->ghoul2, limbName, 0x00000100);
03486 trap_G2API_SetSurfaceOnOff(ent->ghoul2, stubCapName, 0);
03487 }
03488
03489 limb->s.customRGBA[0] = ent->s.customRGBA[0];
03490 limb->s.customRGBA[1] = ent->s.customRGBA[1];
03491 limb->s.customRGBA[2] = ent->s.customRGBA[2];
03492 limb->s.customRGBA[3] = ent->s.customRGBA[3];
03493
03494 trap_LinkEntity( limb );
03495 }
|
|
||||||||||||
|
Referenced by G_Damage(). |
|
||||||||||||||||
|
Definition at line 3139 of file g_combat.c. References entityState_s::angles, gentity_s::client, ENTITYNUM_NONE, EV_SABER_HIT, entityState_s::eventParm, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_TempEntity(), gentity_s::genericValue5, gentity_t, gentity_s::ghoul2, entityState_s::legsAnim, level, gentity_s::localAnimIndex, mdxaBone_t::matrix, gentity_s::modelScale, NULL, entityState_s::number, entityState_s::origin, playerState_s::origin, entityState_s::otherEntityNum, entityState_s::otherEntityNum2, gclient_s::ps, gentity_s::s, level_locals_t::time, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), vec3_t, VectorCopy, VectorNormalize(), playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, and YAW. Referenced by DismembermentByNum(), DismembermentTest(), and G_CheckForDismemberment().
03140 {
03141 int useBolt = self->genericValue5;
03142 vec3_t properOrigin, properAngles, addVel;
03143 //vec3_t legAxis[3];
03144 mdxaBone_t boltMatrix;
03145 float fVSpeed = 0;
03146 char *rotateBone = NULL;
03147
03148 switch (limbType)
03149 {
03150 case G2_MODELPART_HEAD:
03151 rotateBone = "cranium";
03152 break;
03153 case G2_MODELPART_WAIST:
03154 if (self->localAnimIndex <= 1)
03155 { //humanoid
03156 rotateBone = "thoracic";
03157 }
03158 else
03159 {
03160 rotateBone = "pelvis";
03161 }
03162 break;
03163 case G2_MODELPART_LARM:
03164 rotateBone = "lradius";
03165 break;
03166 case G2_MODELPART_RARM:
03167 rotateBone = "rradius";
03168 break;
03169 case G2_MODELPART_RHAND:
03170 rotateBone = "rhand";
03171 break;
03172 case G2_MODELPART_LLEG:
03173 rotateBone = "ltibia";
03174 break;
03175 case G2_MODELPART_RLEG:
03176 rotateBone = "rtibia";
03177 break;
03178 default:
03179 rotateBone = "rtibia";
03180 break;
03181 }
03182
03183 useBolt = trap_G2API_AddBolt(self->ghoul2, 0, rotateBone);
03184
03185 VectorCopy(self->client->ps.origin, properOrigin);
03186 VectorCopy(self->client->ps.viewangles, properAngles);
03187
03188 //try to predict the origin based on velocity so it's more like what the client is seeing
03189 VectorCopy(self->client->ps.velocity, addVel);
03190 VectorNormalize(addVel);
03191
03192 if (self->client->ps.velocity[0] < 0)
03193 {
03194 fVSpeed += (-self->client->ps.velocity[0]);
03195 }
03196 else
03197 {
03198 fVSpeed += self->client->ps.velocity[0];
03199 }
03200 if (self->client->ps.velocity[1] < 0)
03201 {
03202 fVSpeed += (-self->client->ps.velocity[1]);
03203 }
03204 else
03205 {
03206 fVSpeed += self->client->ps.velocity[1];
03207 }
03208 if (self->client->ps.velocity[2] < 0)
03209 {
03210 fVSpeed += (-self->client->ps.velocity[2]);
03211 }
03212 else
03213 {
03214 fVSpeed += self->client->ps.velocity[2];
03215 }
03216
03217 fVSpeed *= 0.08;
03218
03219 properOrigin[0] += addVel[0]*fVSpeed;
03220 properOrigin[1] += addVel[1]*fVSpeed;
03221 properOrigin[2] += addVel[2]*fVSpeed;
03222
03223 properAngles[0] = 0;
03224 properAngles[1] = self->client->ps.viewangles[YAW];
03225 properAngles[2] = 0;
03226
03227 trap_G2API_GetBoltMatrix(self->ghoul2, 0, useBolt, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03228
03229 boltPoint[0] = boltMatrix.matrix[0][3];
03230 boltPoint[1] = boltMatrix.matrix[1][3];
03231 boltPoint[2] = boltMatrix.matrix[2][3];
03232
03233 trap_G2API_GetBoltMatrix(self->ghoul2, 1, 0, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03234
03235 if (self->client && limbType == G2_MODELPART_RHAND)
03236 { //Make some saber hit sparks over the severed wrist area
03237 vec3_t boltAngles;
03238 gentity_t *te;
03239
03240 boltAngles[0] = -boltMatrix.matrix[0][1];
03241 boltAngles[1] = -boltMatrix.matrix[1][1];
03242 boltAngles[2] = -boltMatrix.matrix[2][1];
03243
03244 te = G_TempEntity( boltPoint, EV_SABER_HIT );
03245 te->s.otherEntityNum = self->s.number;
03246 te->s.otherEntityNum2 = ENTITYNUM_NONE;
03247 te->s.weapon = 0;//saberNum
03248 te->s.legsAnim = 0;//bladeNum
03249
03250 VectorCopy(boltPoint, te->s.origin);
03251 VectorCopy(boltAngles, te->s.angles);
03252
03253 if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
03254 { //don't let it play with no direction
03255 te->s.angles[1] = 1;
03256 }
03257
03258 te->s.eventParm = 16; //lots of sparks
03259 }
03260 }
|
|
||||||||||||||||
|
Definition at line 3067 of file g_combat.c. References AngleVectors(), entityShared_t::currentAngles, entityShared_t::currentOrigin, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, gentity_t, gentity_s::r, vec3_t, and VectorCopy. Referenced by G_CheckForDismemberment().
03068 { //Just get the general area without using server-side ghoul2
03069 vec3_t fwd, right, up;
03070
03071 AngleVectors(self->r.currentAngles, fwd, right, up);
03072
03073 VectorCopy(self->r.currentOrigin, boltPoint);
03074
03075 switch (limbType)
03076 {
03077 case G2_MODELPART_HEAD:
03078 boltPoint[0] += up[0]*24;
03079 boltPoint[1] += up[1]*24;
03080 boltPoint[2] += up[2]*24;
03081 break;
03082 case G2_MODELPART_WAIST:
03083 boltPoint[0] += up[0]*4;
03084 boltPoint[1] += up[1]*4;
03085 boltPoint[2] += up[2]*4;
03086 break;
03087 case G2_MODELPART_LARM:
03088 boltPoint[0] += up[0]*18;
03089 boltPoint[1] += up[1]*18;
03090 boltPoint[2] += up[2]*18;
03091
03092 boltPoint[0] -= right[0]*10;
03093 boltPoint[1] -= right[1]*10;
03094 boltPoint[2] -= right[2]*10;
03095 break;
03096 case G2_MODELPART_RARM:
03097 boltPoint[0] += up[0]*18;
03098 boltPoint[1] += up[1]*18;
03099 boltPoint[2] += up[2]*18;
03100
03101 boltPoint[0] += right[0]*10;
03102 boltPoint[1] += right[1]*10;
03103 boltPoint[2] += right[2]*10;
03104 break;
03105 case G2_MODELPART_RHAND:
03106 boltPoint[0] += up[0]*8;
03107 boltPoint[1] += up[1]*8;
03108 boltPoint[2] += up[2]*8;
03109
03110 boltPoint[0] += right[0]*10;
03111 boltPoint[1] += right[1]*10;
03112 boltPoint[2] += right[2]*10;
03113 break;
03114 case G2_MODELPART_LLEG:
03115 boltPoint[0] -= up[0]*4;
03116 boltPoint[1] -= up[1]*4;
03117 boltPoint[2] -= up[2]*4;
03118
03119 boltPoint[0] -= right[0]*10;
03120 boltPoint[1] -= right[1]*10;
03121 boltPoint[2] -= right[2]*10;
03122 break;
03123 case G2_MODELPART_RLEG:
03124 boltPoint[0] -= up[0]*4;
03125 boltPoint[1] -= up[1]*4;
03126 boltPoint[2] -= up[2]*4;
03127
03128 boltPoint[0] += right[0]*10;
03129 boltPoint[1] += right[1]*10;
03130 boltPoint[2] += right[2]*10;
03131 break;
03132 default:
03133 break;
03134 }
03135
03136 return;
03137 }
|
|
||||||||||||
|
Definition at line 45 of file g_combat.c. References entityShared_t::absmax, entityShared_t::absmin, AngleVectors(), gentity_s::client, entityShared_t::currentAngles, DotProduct, fabs(), gentity_t, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, entityShared_t::maxs, entityShared_t::mins, gentity_s::r, vec3_origin, vec3_t, VectorAdd, VectorCopy, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, and YAW. Referenced by G_CheckForDismemberment(), G_LocationBasedDamageModifier(), G_PickDeathAnim(), and WP_DisruptorAltFire().
00046 {
00047 vec3_t point, point_dir;
00048 vec3_t forward, right, up;
00049 vec3_t tangles, tcenter;
00050 float tradius;
00051 float udot, fdot, rdot;
00052 int Vertical, Forward, Lateral;
00053 int HitLoc;
00054
00055 // Get target forward, right and up.
00056 if(target->client)
00057 {
00058 // Ignore player's pitch and roll.
00059 VectorSet(tangles, 0, target->r.currentAngles[YAW], 0);
00060 }
00061
00062 AngleVectors(tangles, forward, right, up);
00063
00064 // Get center of target.
00065 VectorAdd(target->r.absmin, target->r.absmax, tcenter);
00066 VectorScale(tcenter, 0.5, tcenter);
00067
00068 // Get radius width of target.
00069 tradius = (fabs(target->r.maxs[0]) + fabs(target->r.maxs[1]) + fabs(target->r.mins[0]) + fabs(target->r.mins[1]))/4;
00070
00071 // Get impact point.
00072 if(ppoint && !VectorCompare(ppoint, vec3_origin))
00073 {
00074 VectorCopy(ppoint, point);
00075 }
00076 else
00077 {
00078 return HL_NONE;
00079 }
00080
00081 /*
00082 //get impact dir
00083 if(pdir && !VectorCompare(pdir, vec3_origin))
00084 {
00085 VectorCopy(pdir, dir);
00086 }
00087 else
00088 {
00089 return;
00090 }
00091
00092 //put point at controlled distance from center
00093 VectorSubtract(point, tcenter, tempvec);
00094 tempvec[2] = 0;
00095 hdist = VectorLength(tempvec);
00096
00097 VectorMA(point, hdist - tradius, dir, point);
00098 //now a point on the surface of a cylinder with a radius of tradius
00099 */
00100 VectorSubtract(point, tcenter, point_dir);
00101 VectorNormalize(point_dir);
00102
00103 // Get bottom to top (vertical) position index
00104 udot = DotProduct(up, point_dir);
00105 if(udot>.800)
00106 {
00107 Vertical = 4;
00108 }
00109 else if(udot>.400)
00110 {
00111 Vertical = 3;
00112 }
00113 else if(udot>-.333)
00114 {
00115 Vertical = 2;
00116 }
00117 else if(udot>-.666)
00118 {
00119 Vertical = 1;
00120 }
00121 else
00122 {
00123 Vertical = 0;
00124 }
00125
00126 // Get back to front (forward) position index.
00127 fdot = DotProduct(forward, point_dir);
00128 if(fdot>.666)
00129 {
00130 Forward = 4;
00131 }
00132 else if(fdot>.333)
00133 {
00134 Forward = 3;
00135 }
00136 else if(fdot>-.333)
00137 {
00138 Forward = 2;
00139 }
00140 else if(fdot>-.666)
00141 {
00142 Forward = 1;
00143 }
00144 else
00145 {
00146 Forward = 0;
00147 }
00148
00149 // Get left to right (lateral) position index.
00150 rdot = DotProduct(right, point_dir);
00151 if(rdot>.666)
00152 {
00153 Lateral = 4;
00154 }
00155 else if(rdot>.333)
00156 {
00157 Lateral = 3;
00158 }
00159 else if(rdot>-.333)
00160 {
00161 Lateral = 2;
00162 }
00163 else if(rdot>-.666)
00164 {
00165 Lateral = 1;
00166 }
00167 else
00168 {
00169 Lateral = 0;
00170 }
00171
00172 HitLoc = Vertical * 25 + Forward * 5 + Lateral;
00173
00174 if(HitLoc <= 10)
00175 {
00176 // Feet.
00177 if ( rdot > 0 )
00178 {
00179 return HL_FOOT_RT;
00180 }
00181 else
00182 {
00183 return HL_FOOT_LT;
00184 }
00185 }
00186 else if(HitLoc <= 50)
00187 {
00188 // Legs.
00189 if ( rdot > 0 )
00190 {
00191 return HL_LEG_RT;
00192 }
00193 else
00194 {
00195 return HL_LEG_LT;
00196 }
00197 }
00198 else if(HitLoc == 56||HitLoc == 60||HitLoc == 61||HitLoc == 65||HitLoc == 66||HitLoc == 70)
00199 {
00200 // Hands.
00201 if ( rdot > 0 )
00202 {
00203 return HL_HAND_RT;
00204 }
00205 else
00206 {
00207 return HL_HAND_LT;
00208 }
00209 }
00210 else if(HitLoc == 83||HitLoc == 87||HitLoc == 88||HitLoc == 92||HitLoc == 93||HitLoc == 97)
00211 {
00212 // Arms.
00213 if ( rdot > 0 )
00214 {
00215 return HL_ARM_RT;
00216 }
00217 else
00218 {
00219 return HL_ARM_LT;
00220 }
00221 }
00222 else if((HitLoc >= 107 && HitLoc <= 109)||(HitLoc >= 112 && HitLoc <= 114)||(HitLoc >= 117 && HitLoc <= 119))
00223 {
00224 // Head.
00225 return HL_HEAD;
00226 }
00227 else
00228 {
00229 if(udot < 0.3)
00230 {
00231 return HL_WAIST;
00232 }
00233 else if(fdot < 0)
00234 {
00235 if(rdot > 0.4)
00236 {
00237 return HL_BACK_RT;
00238 }
00239 else if(rdot < -0.4)
00240 {
00241 return HL_BACK_LT;
00242 }
00243 else if(fdot < 0)
00244 {
00245 return HL_BACK;
00246 }
00247 }
00248 else
00249 {
00250 if(rdot > 0.3)
00251 {
00252 return HL_CHEST_RT;
00253 }
00254 else if(rdot < -0.3)
00255 {
00256 return HL_CHEST_LT;
00257 }
00258 else if(fdot < 0)
00259 {
00260 return HL_CHEST;
00261 }
00262 }
00263 }
00264 return HL_NONE;
00265 }
|
|
||||||||||||||||||||||||||||||||
|
Definition at line 3632 of file g_combat.c. References AngleVectors(), renderInfo_s::boltValidityTime, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DotProduct, g_dismember, gentity_t, gentity_s::ghoul2, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_GENERIC1, HL_GENERIC2, HL_GENERIC3, HL_GENERIC4, HL_GENERIC5, HL_GENERIC6, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MOD_SABER, gentity_s::modelScale, NEGATIVE_Y, gclient_s::NPC_class, NULL, ORIGIN, playerState_s::origin, gclient_s::ps, Q_stricmp(), Q_strncmp(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, renderInfo_s::torsoAngles, renderInfo_s::torsoPoint, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), UpdateClientRenderBolts(), vec3_t, VectorSet, VectorSubtract, playerState_s::viewangles, and YAW. Referenced by G_CheckForDismemberment(), G_Damage(), and G_LocationBasedDamageModifier().
03633 {
03634 qboolean dismember = qfalse;
03635 int actualTime;
03636 int kneeLBolt = -1;
03637 int kneeRBolt = -1;
03638 int handRBolt = -1;
03639 int handLBolt = -1;
03640 int footRBolt = -1;
03641 int footLBolt = -1;
03642
03643 *hitLoc = HL_NONE;
03644
03645 if ( !surfName || !surfName[0] )
03646 {
03647 return qfalse;
03648 }
03649
03650 if( !ent->client )
03651 {
03652 return qfalse;
03653 }
03654
03655 if (!point)
03656 {
03657 return qfalse;
03658 }
03659
03660 if ( ent->client
03661 && ( ent->client->NPC_class == CLASS_R2D2
03662 || ent->client->NPC_class == CLASS_R2D2
03663 || ent->client->NPC_class == CLASS_GONK
03664 || ent->client->NPC_class == CLASS_MOUSE
03665 || ent->client->NPC_class == CLASS_SENTRY
03666 || ent->client->NPC_class == CLASS_INTERROGATOR
03667 || ent->client->NPC_class == CLASS_SENTRY
03668 || ent->client->NPC_class == CLASS_PROBE ) )
03669 {//we don't care about per-surface hit-locations or dismemberment for these guys
03670 return qfalse;
03671 }
03672
03673 if (ent->localAnimIndex <= 1)
03674 { //humanoid
03675 handLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
03676 handRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
03677 kneeLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_l_knee");
03678 kneeRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_r_knee");
03679 footLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
03680 footRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
03681 }
03682
03683 if ( ent->client && (ent->client->NPC_class == CLASS_ATST) )
03684 {
03685 //FIXME: almost impossible to hit these... perhaps we should
03686 // check for splashDamage and do radius damage to these parts?
03687 // Or, if we ever get bbox G2 traces, that may fix it, too
03688 if (!Q_stricmp("head_light_blaster_cann",surfName))
03689 {
03690 *hitLoc = HL_ARM_LT;
03691 }
03692 else if (!Q_stricmp("head_concussion_charger",surfName))
03693 {
03694 *hitLoc = HL_ARM_RT;
03695 }
03696 return(qfalse);
03697 }
03698 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK1) )
03699 {
03700 if (!Q_stricmp("l_arm",surfName))
03701 {
03702 *hitLoc = HL_ARM_LT;
03703 }
03704 else if (!Q_stricmp("r_arm",surfName))
03705 {
03706 *hitLoc = HL_ARM_RT;
03707 }
03708 else if (!Q_stricmp("torso_front",surfName))
03709 {
03710 *hitLoc = HL_CHEST;
03711 }
03712 else if (!Q_stricmp("torso_tube1",surfName))
03713 {
03714 *hitLoc = HL_GENERIC1;
03715 }
03716 else if (!Q_stricmp("torso_tube2",surfName))
03717 {
03718 *hitLoc = HL_GENERIC2;
03719 }
03720 else if (!Q_stricmp("torso_tube3",surfName))
03721 {
03722 *hitLoc = HL_GENERIC3;
03723 }
03724 else if (!Q_stricmp("torso_tube4",surfName))
03725 {
03726 *hitLoc = HL_GENERIC4;
03727 }
03728 else if (!Q_stricmp("torso_tube5",surfName))
03729 {
03730 *hitLoc = HL_GENERIC5;
03731 }
03732 else if (!Q_stricmp("torso_tube6",surfName))
03733 {
03734 *hitLoc = HL_GENERIC6;
03735 }
03736 return(qfalse);
03737 }
03738 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK2) )
03739 {
03740 if (!Q_stricmp("torso_canister1",surfName))
03741 {
03742 *hitLoc = HL_GENERIC1;
03743 }
03744 else if (!Q_stricmp("torso_canister2",surfName))
03745 {
03746 *hitLoc = HL_GENERIC2;
03747 }
03748 else if (!Q_stricmp("torso_canister3",surfName))
03749 {
03750 *hitLoc = HL_GENERIC3;
03751 }
03752 return(qfalse);
03753 }
03754 else if ( ent->client && (ent->client->NPC_class == CLASS_GALAKMECH) )
03755 {
03756 if (!Q_stricmp("torso_antenna",surfName)||!Q_stricmp("torso_antenna_base",surfName))
03757 {
03758 *hitLoc = HL_GENERIC1;
03759 }
03760 else if (!Q_stricmp("torso_shield",surfName))
03761 {
03762 *hitLoc = HL_GENERIC2;
03763 }
03764 else
03765 {
03766 *hitLoc = HL_CHEST;
03767 }
03768 return(qfalse);
03769 }
03770
03771 //FIXME: check the hitLoc and hitDir against the cap tag for the place
03772 //where the split will be- if the hit dir is roughly perpendicular to
03773 //the direction of the cap, then the split is allowed, otherwise we
03774 //hit it at the wrong angle and should not dismember...
03775 actualTime = level.time;
03776 if ( !Q_strncmp( "hips", surfName, 4 ) )
03777 {//FIXME: test properly for legs
03778 *hitLoc = HL_WAIST;
03779 if ( ent->client != NULL && ent->ghoul2 )
03780 {
03781 mdxaBone_t boltMatrix;
03782 vec3_t tagOrg, angles;
03783
03784 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03785 if (kneeLBolt>=0)
03786 {
03787 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeLBolt,
03788 &boltMatrix, angles, ent->r.currentOrigin,
03789 actualTime, NULL, ent->modelScale );
03790 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03791 if ( DistanceSquared( point, tagOrg ) < 100 )
03792 {//actually hit the knee
03793 *hitLoc = HL_LEG_LT;
03794 }
03795 }
03796 if (*hitLoc == HL_WAIST)
03797 {
03798 if (kneeRBolt>=0)
03799 {
03800 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeRBolt,
03801 &boltMatrix, angles, ent->r.currentOrigin,
03802 actualTime, NULL, ent->modelScale );
03803 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03804 if ( DistanceSquared( point, tagOrg ) < 100 )
03805 {//actually hit the knee
03806 *hitLoc = HL_LEG_RT;
03807 }
03808 }
03809 }
03810 }
03811 }
03812 else if ( !Q_strncmp( "torso", surfName, 5 ) )
03813 {
03814 if ( !ent->client )
03815 {
03816 *hitLoc = HL_CHEST;
03817 }
03818 else
03819 {
03820 vec3_t t_fwd, t_rt, t_up, dirToImpact;
03821 float frontSide, rightSide, upSide;
03822 AngleVectors( ent->client->renderInfo.torsoAngles, t_fwd, t_rt, t_up );
03823
03824 if (ent->client->renderInfo.boltValidityTime != level.time)
03825 {
03826 vec3_t renderAng;
03827
03828 renderAng[0] = 0;
03829 renderAng[1] = ent->client->ps.viewangles[YAW];
03830 renderAng[2] = 0;
03831
03832 UpdateClientRenderBolts(ent, ent->client->ps.origin, renderAng);
03833 }
03834
03835 VectorSubtract( point, ent->client->renderInfo.torsoPoint, dirToImpact );
03836 frontSide = DotProduct( t_fwd, dirToImpact );
03837 rightSide = DotProduct( t_rt, dirToImpact );
03838 upSide = DotProduct( t_up, dirToImpact );
03839 if ( upSide < -10 )
03840 {//hit at waist
03841 *hitLoc = HL_WAIST;
03842 }
03843 else
03844 {//hit on upper torso
03845 if ( rightSide > 4 )
03846 {
03847 *hitLoc = HL_ARM_RT;
03848 }
03849 else if ( rightSide < -4 )
03850 {
03851 *hitLoc = HL_ARM_LT;
03852 }
03853 else if ( rightSide > 2 )
03854 {
03855 if ( frontSide > 0 )
03856 {
03857 *hitLoc = HL_CHEST_RT;
03858 }
03859 else
03860 {
03861 *hitLoc = HL_BACK_RT;
03862 }
03863 }
03864 else if ( rightSide < -2 )
03865 {
03866 if ( frontSide > 0 )
03867 {
03868 *hitLoc = HL_CHEST_LT;
03869 }
03870 else
03871 {
03872 *hitLoc = HL_BACK_LT;
03873 }
03874 }
03875 else if ( upSide > -3 && mod == MOD_SABER )
03876 {
03877 *hitLoc = HL_HEAD;
03878 }
03879 else if ( frontSide > 0 )
03880 {
03881 *hitLoc = HL_CHEST;
03882 }
03883 else
03884 {
03885 *hitLoc = HL_BACK;
03886 }
03887 }
03888 }
03889 }
03890 else if ( !Q_strncmp( "head", surfName, 4 ) )
03891 {
03892 *hitLoc = HL_HEAD;
03893 }
03894 else if ( !Q_strncmp( "r_arm", surfName, 5 ) )
03895 {
03896 *hitLoc = HL_ARM_RT;
03897 if ( ent->client != NULL && ent->ghoul2 )
03898 {
03899 mdxaBone_t boltMatrix;
03900 vec3_t tagOrg, angles;
03901
03902 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03903 if (handRBolt>=0)
03904 {
03905 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handRBolt,
03906 &boltMatrix, angles, ent->r.currentOrigin,
03907 actualTime, NULL, ent->modelScale );
03908 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03909 if ( DistanceSquared( point, tagOrg ) < 256 )
03910 {//actually hit the hand
03911 *hitLoc = HL_HAND_RT;
03912 }
03913 }
03914 }
03915 }
03916 else if ( !Q_strncmp( "l_arm", surfName, 5 ) )
03917 {
03918 *hitLoc = HL_ARM_LT;
03919 if ( ent->client != NULL && ent->ghoul2 )
03920 {
03921 mdxaBone_t boltMatrix;
03922 vec3_t tagOrg, angles;
03923
03924 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03925 if (handLBolt>=0)
03926 {
03927 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handLBolt,
03928 &boltMatrix, angles, ent->r.currentOrigin,
03929 actualTime, NULL, ent->modelScale );
03930 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03931 if ( DistanceSquared( point, tagOrg ) < 256 )
03932 {//actually hit the hand
03933 *hitLoc = HL_HAND_LT;
03934 }
03935 }
03936 }
03937 }
03938 else if ( !Q_strncmp( "r_leg", surfName, 5 ) )
03939 {
03940 *hitLoc = HL_LEG_RT;
03941 if ( ent->client != NULL && ent->ghoul2 )
03942 {
03943 mdxaBone_t boltMatrix;
03944 vec3_t tagOrg, angles;
03945
03946 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03947 if (footRBolt>=0)
03948 {
03949 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footRBolt,
03950 &boltMatrix, angles, ent->r.currentOrigin,
03951 actualTime, NULL, ent->modelScale );
03952 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03953 if ( DistanceSquared( point, tagOrg ) < 100 )
03954 {//actually hit the foot
03955 *hitLoc = HL_FOOT_RT;
03956 }
03957 }
03958 }
03959 }
03960 else if ( !Q_strncmp( "l_leg", surfName, 5 ) )
03961 {
03962 *hitLoc = HL_LEG_LT;
03963 if ( ent->client != NULL && ent->ghoul2 )
03964 {
03965 mdxaBone_t boltMatrix;
03966 vec3_t tagOrg, angles;
03967
03968 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03969 if (footLBolt>=0)
03970 {
03971 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footLBolt,
03972 &boltMatrix, angles, ent->r.currentOrigin,
03973 actualTime, NULL, ent->modelScale );
03974 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03975 if ( DistanceSquared( point, tagOrg ) < 100 )
03976 {//actually hit the foot
03977 *hitLoc = HL_FOOT_LT;
03978 }
03979 }
03980 }
03981 }
03982 else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) )
03983 {//right hand or weapon
03984 *hitLoc = HL_HAND_RT;
03985 }
03986 else if ( !Q_strncmp( "l_hand", surfName, 6 ) )
03987 {
03988 *hitLoc = HL_HAND_LT;
03989 }
03990 /*
03991 #ifdef _DEBUG
03992 else
03993 {
03994 Com_Printf( "ERROR: surface %s does not belong to any hitLocation!!!\n", surfName );
03995 }
03996 #endif //_DEBUG
03997 */
03998
03999 //if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered )
04000 if (g_dismember.integer == 100)
04001 { //full probability...
04002 if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL )
04003 {
04004 dismember = qtrue;
04005 }
04006 else if ( dir && (dir[0] || dir[1] || dir[2]) &&
04007 bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) )
04008 {//we care about direction (presumably for dismemberment)
04009 //if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) )
04010 if (1) //Fix me?
04011 {//either we don't care about probabilties or the probability let us continue
04012 char *tagName = NULL;
04013 float aoa = 0.5f;
04014 //dir must be roughly perpendicular to the hitLoc's cap bolt
04015 switch ( *hitLoc )
04016 {
04017 case HL_LEG_RT:
04018 tagName = "*hips_cap_r_leg";
04019 break;
04020 case HL_LEG_LT:
04021 tagName = "*hips_cap_l_leg";
04022 break;
04023 case HL_WAIST:
04024 tagName = "*hips_cap_torso";
04025 aoa = 0.25f;
04026 break;
04027 case HL_CHEST_RT:
04028 case HL_ARM_RT:
04029 case HL_BACK_LT:
04030 tagName = "*torso_cap_r_arm";
04031 break;
04032 case HL_CHEST_LT:
04033 case HL_ARM_LT:
04034 case HL_BACK_RT:
04035 tagName = "*torso_cap_l_arm";
04036 break;
04037 case HL_HAND_RT:
04038 tagName = "*r_arm_cap_r_hand";
04039 break;
04040 case HL_HAND_LT:
04041 tagName = "*l_arm_cap_l_hand";
04042 break;
04043 case HL_HEAD:
04044 tagName = "*torso_cap_head";
04045 aoa = 0.25f;
04046 break;
04047 case HL_CHEST:
04048 case HL_BACK:
04049 case HL_FOOT_RT:
04050 case HL_FOOT_LT:
04051 default:
04052 //no dismemberment possible with these, so no checks needed
04053 break;
04054 }
04055 if ( tagName )
04056 {
04057 int tagBolt = trap_G2API_AddBolt( ent->ghoul2, 0, tagName );
04058 if ( tagBolt != -1 )
04059 {
04060 mdxaBone_t boltMatrix;
04061 vec3_t tagOrg, tagDir, angles;
04062
04063 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
04064 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, tagBolt,
04065 &boltMatrix, angles, ent->r.currentOrigin,
04066 actualTime, NULL, ent->modelScale );
04067 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
04068 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, tagDir );
04069 if ( DistanceSquared( point, tagOrg ) < 256 )
04070 {//hit close
04071 float dot = DotProduct( dir, tagDir );
04072 if ( dot < aoa && dot > -aoa )
04073 {//hit roughly perpendicular
04074 dot = DotProduct( bladeDir, tagDir );
04075 if ( dot < aoa && dot > -aoa )
04076 {//blade was roughly perpendicular
04077 dismember = qtrue;
04078 }
04079 }
04080 }
04081 }
04082 }
04083 }
04084 }
04085 else
04086 { //hmm, no direction supplied.
04087 dismember = qtrue;
04088 }
04089 }
04090 return dismember;
04091 }
|
|
||||||||||||
|
Definition at line 3546 of file g_combat.c. References AngleVectors(), entityState_s::apos, gentity_s::client, DotProduct, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RLEG, gentity_t, gPainHitLoc, NULL, playerState_s::origin, entityState_s::pos, gclient_s::ps, gentity_s::s, trajectory_t::trBase, vec3_t, VectorCopy, VectorNormalize(), VectorSubtract, playerState_s::viewangles, and playerState_s::viewheight. Referenced by G_CheckForDismemberment().
03547 {
03548 vec3_t diff, fwdangles={0,0,0}, right;
03549 vec3_t clEye;
03550 float rightdot;
03551 float zdiff;
03552 int hitLoc = gPainHitLoc;
03553
03554 if (self->client)
03555 {
03556 VectorCopy(self->client->ps.origin, clEye);
03557 clEye[2] += self->client->ps.viewheight;
03558 }
03559 else
03560 {
03561 VectorCopy(self->s.pos.trBase, clEye);
03562 clEye[2] += 16;
03563 }
03564
03565 |