00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "g_local.h"
00026
00027
00028
00029
00030
00031
00032
00033 void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
00034 gentity_t *plum;
00035
00036 plum = G_TempEntity( origin, EV_SCOREPLUM );
00037
00038 plum->r.svFlags |= SVF_SINGLECLIENT;
00039 plum->r.singleClient = ent->s.number;
00040
00041 plum->s.otherEntityNum = ent->s.number;
00042 plum->s.time = score;
00043 }
00044
00045
00046
00047
00048
00049
00050
00051
00052 void AddScore( gentity_t *ent, vec3_t origin, int score ) {
00053 if ( !ent->client ) {
00054 return;
00055 }
00056
00057 if ( level.warmupTime ) {
00058 return;
00059 }
00060
00061 ScorePlum(ent, origin, score);
00062
00063 ent->client->ps.persistant[PERS_SCORE] += score;
00064 if ( g_gametype.integer == GT_TEAM )
00065 level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
00066 CalculateRanks();
00067 }
00068
00069
00070
00071
00072
00073
00074
00075
00076 void TossClientItems( gentity_t *self ) {
00077 gitem_t *item;
00078 int weapon;
00079 float angle;
00080 int i;
00081 gentity_t *drop;
00082
00083
00084 weapon = self->s.weapon;
00085
00086
00087
00088
00089
00090 if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {
00091 if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
00092 weapon = self->client->pers.cmd.weapon;
00093 }
00094 if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
00095 weapon = WP_NONE;
00096 }
00097 }
00098
00099 if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK &&
00100 self->client->ps.ammo[ weapon ] ) {
00101
00102 item = BG_FindItemForWeapon( weapon );
00103
00104
00105 Drop_Item( self, item, 0 );
00106 }
00107
00108
00109 if ( g_gametype.integer != GT_TEAM ) {
00110 angle = 45;
00111 for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
00112 if ( self->client->ps.powerups[ i ] > level.time ) {
00113 item = BG_FindItemForPowerup( i );
00114 if ( !item ) {
00115 continue;
00116 }
00117 drop = Drop_Item( self, item, angle );
00118
00119 drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
00120 if ( drop->count < 1 ) {
00121 drop->count = 1;
00122 }
00123 angle += 45;
00124 }
00125 }
00126 }
00127 }
00128
00129 #ifdef MISSIONPACK
00130
00131
00132
00133
00134
00135
00136 extern gentity_t *neutralObelisk;
00137
00138 void TossClientCubes( gentity_t *self ) {
00139 gitem_t *item;
00140 gentity_t *drop;
00141 vec3_t velocity;
00142 vec3_t angles;
00143 vec3_t origin;
00144
00145 self->client->ps.generic1 = 0;
00146
00147
00148
00149 if (!G_EntitiesFree()) {
00150 return;
00151 }
00152
00153 if( self->client->sess.sessionTeam == TEAM_RED ) {
00154 item = BG_FindItem( "Red Cube" );
00155 }
00156 else {
00157 item = BG_FindItem( "Blue Cube" );
00158 }
00159
00160 angles[YAW] = (float)(level.time % 360);
00161 angles[PITCH] = 0;
00162 angles[ROLL] = 0;
00163
00164 AngleVectors( angles, velocity, NULL, NULL );
00165 VectorScale( velocity, 150, velocity );
00166 velocity[2] += 200 + crandom() * 50;
00167
00168 if( neutralObelisk ) {
00169 VectorCopy( neutralObelisk->s.pos.trBase, origin );
00170 origin[2] += 44;
00171 } else {
00172 VectorClear( origin ) ;
00173 }
00174
00175 drop = LaunchItem( item, origin, velocity );
00176
00177 drop->nextthink = level.time + g_cubeTimeout.integer * 1000;
00178 drop->think = G_FreeEntity;
00179 drop->spawnflags = self->client->sess.sessionTeam;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 void TossClientPersistantPowerups( gentity_t *ent ) {
00189 gentity_t *powerup;
00190
00191 if( !ent->client ) {
00192 return;
00193 }
00194
00195 if( !ent->client->persistantPowerup ) {
00196 return;
00197 }
00198
00199 powerup = ent->client->persistantPowerup;
00200
00201 powerup->r.svFlags &= ~SVF_NOCLIENT;
00202 powerup->s.eFlags &= ~EF_NODRAW;
00203 powerup->r.contents = CONTENTS_TRIGGER;
00204 trap_LinkEntity( powerup );
00205
00206 ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
00207 ent->client->persistantPowerup = NULL;
00208 }
00209 #endif
00210
00211
00212
00213
00214
00215
00216
00217 void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
00218 vec3_t dir;
00219 vec3_t angles;
00220
00221 if ( attacker && attacker != self ) {
00222 VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
00223 } else if ( inflictor && inflictor != self ) {
00224 VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
00225 } else {
00226 self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
00227 return;
00228 }
00229
00230 self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
00231
00232 angles[YAW] = vectoyaw ( dir );
00233 angles[PITCH] = 0;
00234 angles[ROLL] = 0;
00235 }
00236
00237
00238
00239
00240
00241
00242 void GibEntity( gentity_t *self, int killer ) {
00243 gentity_t *ent;
00244 int i;
00245
00246
00247 if (self->s.eFlags & EF_KAMIKAZE) {
00248
00249 for (i = 0; i < MAX_GENTITIES; i++) {
00250 ent = &g_entities[i];
00251 if (!ent->inuse)
00252 continue;
00253 if (ent->activator != self)
00254 continue;
00255 if (strcmp(ent->classname, "kamikaze timer"))
00256 continue;
00257 G_FreeEntity(ent);
00258 break;
00259 }
00260 }
00261 G_AddEvent( self, EV_GIB_PLAYER, killer );
00262 self->takedamage = qfalse;
00263 self->s.eType = ET_INVISIBLE;
00264 self->r.contents = 0;
00265 }
00266
00267
00268
00269
00270
00271
00272 void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
00273 if ( self->health > GIB_HEALTH ) {
00274 return;
00275 }
00276 if ( !g_blood.integer ) {
00277 self->health = GIB_HEALTH+1;
00278 return;
00279 }
00280
00281 GibEntity( self, 0 );
00282 }
00283
00284
00285
00286 char *modNames[] = {
00287 "MOD_UNKNOWN",
00288 "MOD_SHOTGUN",
00289 "MOD_GAUNTLET",
00290 "MOD_MACHINEGUN",
00291 "MOD_GRENADE",
00292 "MOD_GRENADE_SPLASH",
00293 "MOD_ROCKET",
00294 "MOD_ROCKET_SPLASH",
00295 "MOD_PLASMA",
00296 "MOD_PLASMA_SPLASH",
00297 "MOD_RAILGUN",
00298 "MOD_LIGHTNING",
00299 "MOD_BFG",
00300 "MOD_BFG_SPLASH",
00301 "MOD_WATER",
00302 "MOD_SLIME",
00303 "MOD_LAVA",
00304 "MOD_CRUSH",
00305 "MOD_TELEFRAG",
00306 "MOD_FALLING",
00307 "MOD_SUICIDE",
00308 "MOD_TARGET_LASER",
00309 "MOD_TRIGGER_HURT",
00310 #ifdef MISSIONPACK
00311 "MOD_NAIL",
00312 "MOD_CHAINGUN",
00313 "MOD_PROXIMITY_MINE",
00314 "MOD_KAMIKAZE",
00315 "MOD_JUICED",
00316 #endif
00317 "MOD_GRAPPLE"
00318 };
00319
00320 #ifdef MISSIONPACK
00321
00322
00323
00324
00325
00326 void Kamikaze_DeathActivate( gentity_t *ent ) {
00327 G_StartKamikaze(ent);
00328 G_FreeEntity(ent);
00329 }
00330
00331
00332
00333
00334
00335
00336 void Kamikaze_DeathTimer( gentity_t *self ) {
00337 gentity_t *ent;
00338
00339 ent = G_Spawn();
00340 ent->classname = "kamikaze timer";
00341 VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
00342 ent->r.svFlags |= SVF_NOCLIENT;
00343 ent->think = Kamikaze_DeathActivate;
00344 ent->nextthink = level.time + 5 * 1000;
00345
00346 ent->activator = self;
00347 }
00348
00349 #endif
00350
00351
00352
00353
00354
00355
00356 void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
00357 gentity_t *ent;
00358 vec3_t dir;
00359 char *classname;
00360
00361
00362 if ( self->client->ps.powerups[PW_REDFLAG] ||
00363 self->client->ps.powerups[PW_BLUEFLAG] ||
00364 self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00365
00366 if ( g_gametype.integer == GT_CTF ) {
00367 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00368 classname = "team_CTF_blueflag";
00369 }
00370 else {
00371 classname = "team_CTF_redflag";
00372 }
00373 }
00374 else {
00375 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00376 classname = "team_CTF_redflag";
00377 }
00378 else {
00379 classname = "team_CTF_blueflag";
00380 }
00381 }
00382 ent = NULL;
00383 do
00384 {
00385 ent = G_Find(ent, FOFS(classname), classname);
00386 } while (ent && (ent->flags & FL_DROPPED_ITEM));
00387
00388 if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
00389
00390 VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00391 if ( VectorLength(dir) < 200 ) {
00392 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00393 if ( attacker->client ) {
00394 attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00395 }
00396 }
00397 }
00398 }
00399 }
00400
00401
00402
00403
00404
00405
00406 void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) {
00407 gentity_t *ent;
00408 vec3_t dir;
00409 char *classname;
00410
00411
00412 if ( self->client->ps.generic1 ) {
00413 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00414 classname = "team_redobelisk";
00415 }
00416 else {
00417 classname = "team_blueobelisk";
00418 }
00419 ent = G_Find(NULL, FOFS(classname), classname);
00420
00421 if ( ent ) {
00422
00423 VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00424 if ( VectorLength(dir) < 200 ) {
00425 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00426 if ( attacker->client ) {
00427 attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00428 }
00429 }
00430 }
00431 }
00432 }
00433
00434
00435
00436
00437
00438
00439 void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
00440 gentity_t *ent;
00441 int anim;
00442 int contents;
00443 int killer;
00444 int i;
00445 char *killerName, *obit;
00446
00447 if ( self->client->ps.pm_type == PM_DEAD ) {
00448 return;
00449 }
00450
00451 if ( level.intermissiontime ) {
00452 return;
00453 }
00454
00455
00456 CheckAlmostCapture( self, attacker );
00457
00458 CheckAlmostScored( self, attacker );
00459
00460 if (self->client && self->client->hook) {
00461 Weapon_HookFree(self->client->hook);
00462 }
00463 #ifdef MISSIONPACK
00464 if ((self->client->ps.eFlags & EF_TICKING) && self->activator) {
00465 self->client->ps.eFlags &= ~EF_TICKING;
00466 self->activator->think = G_FreeEntity;
00467 self->activator->nextthink = level.time;
00468 }
00469 #endif
00470 self->client->ps.pm_type = PM_DEAD;
00471
00472 if ( attacker ) {
00473 killer = attacker->s.number;
00474 if ( attacker->client ) {
00475 killerName = attacker->client->pers.netname;
00476 } else {
00477 killerName = "<non-client>";
00478 }
00479 } else {
00480 killer = ENTITYNUM_WORLD;
00481 killerName = "<world>";
00482 }
00483
00484 if ( killer < 0 || killer >= MAX_CLIENTS ) {
00485 killer = ENTITYNUM_WORLD;
00486 killerName = "<world>";
00487 }
00488
00489 if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
00490 obit = "<bad obituary>";
00491 } else {
00492 obit = modNames[ meansOfDeath ];
00493 }
00494
00495 G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n",
00496 killer, self->s.number, meansOfDeath, killerName,
00497 self->client->pers.netname, obit );
00498
00499
00500 ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
00501 ent->s.eventParm = meansOfDeath;
00502 ent->s.otherEntityNum = self->s.number;
00503 ent->s.otherEntityNum2 = killer;
00504 ent->r.svFlags = SVF_BROADCAST;
00505
00506 self->enemy = attacker;
00507
00508 self->client->ps.persistant[PERS_KILLED]++;
00509
00510 if (attacker && attacker->client) {
00511 attacker->client->lastkilled_client = self->s.number;
00512
00513 if ( attacker == self || OnSameTeam (self, attacker ) ) {
00514 AddScore( attacker, self->r.currentOrigin, -1 );
00515 } else {
00516 AddScore( attacker, self->r.currentOrigin, 1 );
00517
00518 if( meansOfDeath == MOD_GAUNTLET ) {
00519
00520
00521 attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
00522
00523
00524 attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00525 attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
00526 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00527
00528
00529 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
00530 }
00531
00532
00533
00534 if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
00535
00536 attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
00537
00538
00539 attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00540 attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
00541 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00542 }
00543 attacker->client->lastKillTime = level.time;
00544
00545 }
00546 } else {
00547 AddScore( self, self->r.currentOrigin, -1 );
00548 }
00549
00550
00551 Team_FragBonuses(self, inflictor, attacker);
00552
00553
00554 if (meansOfDeath == MOD_SUICIDE) {
00555 if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00556 Team_ReturnFlag( TEAM_FREE );
00557 self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
00558 }
00559 else if ( self->client->ps.powerups[PW_REDFLAG] ) {
00560 Team_ReturnFlag( TEAM_RED );
00561 self->client->ps.powerups[PW_REDFLAG] = 0;
00562 }
00563 else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {
00564 Team_ReturnFlag( TEAM_BLUE );
00565 self->client->ps.powerups[PW_BLUEFLAG] = 0;
00566 }
00567 }
00568
00569
00570 contents = trap_PointContents( self->r.currentOrigin, -1 );
00571 if ( !( contents & CONTENTS_NODROP )) {
00572 TossClientItems( self );
00573 }
00574 else {
00575 if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00576 Team_ReturnFlag( TEAM_FREE );
00577 }
00578 else if ( self->client->ps.powerups[PW_REDFLAG] ) {
00579 Team_ReturnFlag( TEAM_RED );
00580 }
00581 else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {
00582 Team_ReturnFlag( TEAM_BLUE );
00583 }
00584 }
00585 #ifdef MISSIONPACK
00586 TossClientPersistantPowerups( self );
00587 if( g_gametype.integer == GT_HARVESTER ) {
00588 TossClientCubes( self );
00589 }
00590 #endif
00591
00592 Cmd_Score_f( self );
00593
00594
00595 for ( i = 0 ; i < level.maxclients ; i++ ) {
00596 gclient_t *client;
00597
00598 client = &level.clients[i];
00599 if ( client->pers.connected != CON_CONNECTED ) {
00600 continue;
00601 }
00602 if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
00603 continue;
00604 }
00605 if ( client->sess.spectatorClient == self->s.number ) {
00606 Cmd_Score_f( g_entities + i );
00607 }
00608 }
00609
00610 self->takedamage = qtrue;
00611
00612 self->s.weapon = WP_NONE;
00613 self->s.powerups = 0;
00614 self->r.contents = CONTENTS_CORPSE;
00615
00616 self->s.angles[0] = 0;
00617 self->s.angles[2] = 0;
00618 LookAtKiller (self, inflictor, attacker);
00619
00620 VectorCopy( self->s.angles, self->client->ps.viewangles );
00621
00622 self->s.loopSound = 0;
00623
00624 self->r.maxs[2] = -8;
00625
00626
00627
00628 self->client->respawnTime = level.time + 1700;
00629
00630
00631 memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
00632
00633
00634 if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {
00635
00636 GibEntity( self, killer );
00637 } else {
00638
00639 static int i;
00640
00641 switch ( i ) {
00642 case 0:
00643 anim = BOTH_DEATH1;
00644 break;
00645 case 1:
00646 anim = BOTH_DEATH2;
00647 break;
00648 case 2:
00649 default:
00650 anim = BOTH_DEATH3;
00651 break;
00652 }
00653
00654
00655
00656 if ( self->health <= GIB_HEALTH ) {
00657 self->health = GIB_HEALTH+1;
00658 }
00659
00660 self->client->ps.legsAnim =
00661 ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
00662 self->client->ps.torsoAnim =
00663 ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
00664
00665 G_AddEvent( self, EV_DEATH1 + i, killer );
00666
00667
00668 self->die = body_die;
00669
00670
00671 i = ( i + 1 ) % 3;
00672
00673 #ifdef MISSIONPACK
00674 if (self->s.eFlags & EF_KAMIKAZE) {
00675 Kamikaze_DeathTimer( self );
00676 }
00677 #endif
00678 }
00679
00680 trap_LinkEntity (self);
00681
00682 }
00683
00684
00685
00686
00687
00688
00689
00690 int CheckArmor (gentity_t *ent, int damage, int dflags)
00691 {
00692 gclient_t *client;
00693 int save;
00694 int count;
00695
00696 if (!damage)
00697 return 0;
00698
00699 client = ent->client;
00700
00701 if (!client)
00702 return 0;
00703
00704 if (dflags & DAMAGE_NO_ARMOR)
00705 return 0;
00706
00707
00708 count = client->ps.stats[STAT_ARMOR];
00709 save = ceil( damage * ARMOR_PROTECTION );
00710 if (save >= count)
00711 save = count;
00712
00713 if (!save)
00714 return 0;
00715
00716 client->ps.stats[STAT_ARMOR] -= save;
00717
00718 return save;
00719 }
00720
00721
00722
00723
00724
00725
00726 int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
00727 float b, c, d, t;
00728
00729
00730
00731
00732
00733
00734
00735 VectorNormalize(dir);
00736 b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
00737 c = (point[0] - origin[0]) * (point[0] - origin[0]) +
00738 (point[1] - origin[1]) * (point[1] - origin[1]) +
00739 (point[2] - origin[2]) * (point[2] - origin[2]) -
00740 radius * radius;
00741
00742 d = b * b - 4 * c;
00743 if (d > 0) {
00744 t = (- b + sqrt(d)) / 2;
00745 VectorMA(point, t, dir, intersections[0]);
00746 t = (- b - sqrt(d)) / 2;
00747 VectorMA(point, t, dir, intersections[1]);
00748 return 2;
00749 }
00750 else if (d == 0) {
00751 t = (- b ) / 2;
00752 VectorMA(point, t, dir, intersections[0]);
00753 return 1;
00754 }
00755 return 0;
00756 }
00757
00758 #ifdef MISSIONPACK
00759
00760
00761
00762
00763
00764 int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir ) {
00765 gentity_t *impact;
00766 vec3_t intersections[2], vec;
00767 int n;
00768
00769 if ( !targ->client ) {
00770 return qfalse;
00771 }
00772 VectorCopy(dir, vec);
00773 VectorInverse(vec);
00774
00775 n = RaySphereIntersections( targ->client->ps.origin, 42, point, vec, intersections);
00776 if (n > 0) {
00777 impact = G_TempEntity( targ->client->ps.origin, EV_INVUL_IMPACT );
00778 VectorSubtract(intersections[0], targ->client->ps.origin, vec);
00779 vectoangles(vec, impact->s.angles);
00780 impact->s.angles[0] += 90;
00781 if (impact->s.angles[0] > 360)
00782 impact->s.angles[0] -= 360;
00783 if ( impactpoint ) {
00784 VectorCopy( intersections[0], impactpoint );
00785 }
00786 if ( bouncedir ) {
00787 VectorCopy( vec, bouncedir );
00788 VectorNormalize( bouncedir );
00789 }
00790 return qtrue;
00791 }
00792 else {
00793 return qfalse;
00794 }
00795 }
00796 #endif
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
00822 vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
00823 gclient_t *client;
00824 int take;
00825 int save;
00826 int asave;
00827 int knockback;
00828 int max;
00829 #ifdef MISSIONPACK
00830 vec3_t bouncedir, impactpoint;
00831 #endif
00832
00833 if (!targ->takedamage) {
00834 return;
00835 }
00836
00837
00838
00839 if ( level.intermissionQueued ) {
00840 return;
00841 }
00842 #ifdef MISSIONPACK
00843 if ( targ->client && mod != MOD_JUICED) {
00844 if ( targ->client->invulnerabilityTime > level.time) {
00845 if ( dir && point ) {
00846 G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
00847 }
00848 return;
00849 }
00850 }
00851 #endif
00852 if ( !inflictor ) {
00853 inflictor = &g_entities[ENTITYNUM_WORLD];
00854 }
00855 if ( !attacker ) {
00856 attacker = &g_entities[ENTITYNUM_WORLD];
00857 }
00858
00859
00860 if ( targ->s.eType == ET_MOVER ) {
00861 if ( targ->use && targ->moverState == MOVER_POS1 ) {
00862 targ->use( targ, inflictor, attacker );
00863 }
00864 return;
00865 }
00866 #ifdef MISSIONPACK
00867 if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
00868 return;
00869 }
00870 #endif
00871
00872
00873 if ( attacker->client && attacker != targ ) {
00874 max = attacker->client->ps.stats[STAT_MAX_HEALTH];
00875 #ifdef MISSIONPACK
00876 if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
00877 max /= 2;
00878 }
00879 #endif
00880 damage = damage * max / 100;
00881 }
00882
00883 client = targ->client;
00884
00885 if ( client ) {
00886 if ( client->noclip ) {
00887 return;
00888 }
00889 }
00890
00891 if ( !dir ) {
00892 dflags |= DAMAGE_NO_KNOCKBACK;
00893 } else {
00894 VectorNormalize(dir);
00895 }
00896
00897 knockback = damage;
00898 if ( knockback > 200 ) {
00899 knockback = 200;
00900 }
00901 if ( targ->flags & FL_NO_KNOCKBACK ) {
00902 knockback = 0;
00903 }
00904 if ( dflags & DAMAGE_NO_KNOCKBACK ) {
00905 knockback = 0;
00906 }
00907
00908
00909 if ( knockback && targ->client ) {
00910 vec3_t kvel;
00911 float mass;
00912
00913 mass = 200;
00914
00915 VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
00916 VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
00917
00918
00919
00920 if ( !targ->client->ps.pm_time ) {
00921 int t;
00922
00923 t = knockback * 2;
00924 if ( t < 50 ) {
00925 t = 50;
00926 }
00927 if ( t > 200 ) {
00928 t = 200;
00929 }
00930 targ->client->ps.pm_time = t;
00931 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00932 }
00933 }
00934
00935
00936 if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
00937
00938
00939
00940 #ifdef MISSIONPACK
00941 if ( mod != MOD_JUICED && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker) ) {
00942 #else
00943 if ( targ != attacker && OnSameTeam (targ, attacker) ) {
00944 #endif
00945 if ( !g_friendlyFire.integer ) {
00946 return;
00947 }
00948 }
00949 #ifdef MISSIONPACK
00950 if (mod == MOD_PROXIMITY_MINE) {
00951 if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
00952 return;
00953 }
00954 if (targ == attacker) {
00955 return;
00956 }
00957 }
00958 #endif
00959
00960
00961 if ( targ->flags & FL_GODMODE ) {
00962 return;
00963 }
00964 }
00965
00966
00967
00968 if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
00969 G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
00970 if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
00971 return;
00972 }
00973 damage *= 0.5;
00974 }
00975
00976
00977 if ( attacker->client && targ != attacker && targ->health > 0
00978 && targ->s.eType != ET_MISSILE
00979 && targ->s.eType != ET_GENERAL) {
00980 if ( OnSameTeam( targ, attacker ) ) {
00981 attacker->client->ps.persistant[PERS_HITS]--;
00982 } else {
00983 attacker->client->ps.persistant[PERS_HITS]++;
00984 }
00985 attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
00986 }
00987
00988
00989
00990 if ( targ == attacker) {
00991 damage *= 0.5;
00992 }
00993
00994 if ( damage < 1 ) {
00995 damage = 1;
00996 }
00997 take = damage;
00998 save = 0;
00999
01000
01001 asave = CheckArmor (targ, take, dflags);
01002 take -= asave;
01003
01004 if ( g_debugDamage.integer ) {
01005 G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
01006 targ->health, take, asave );
01007 }
01008
01009
01010
01011
01012 if ( client ) {
01013 if ( attacker ) {
01014 client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
01015 } else {
01016 client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
01017 }
01018 client->damage_armor += asave;
01019 client->damage_blood += take;
01020 client->damage_knockback += knockback;
01021 if ( dir ) {
01022 VectorCopy ( dir, client->damage_from );
01023 client->damage_fromWorld = qfalse;
01024 } else {
01025 VectorCopy ( targ->r.currentOrigin, client->damage_from );
01026 client->damage_fromWorld = qtrue;
01027 }
01028 }
01029
01030
01031 #ifdef MISSIONPACK
01032 if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF ) {
01033 #else
01034 if( g_gametype.integer == GT_CTF) {
01035 #endif
01036 Team_CheckHurtCarrier(targ, attacker);
01037 }
01038
01039 if (targ->client) {
01040
01041 targ->client->lasthurt_client = attacker->s.number;
01042 targ->client->lasthurt_mod = mod;
01043 }
01044
01045
01046 if (take) {
01047 targ->health = targ->health - take;
01048 if ( targ->client ) {
01049 targ->client->ps.stats[STAT_HEALTH] = targ->health;
01050 }
01051
01052 if ( targ->health <= 0 ) {
01053 if ( client )
01054 targ->flags |= FL_NO_KNOCKBACK;
01055
01056 if (targ->health < -999)
01057 targ->health = -999;
01058
01059 targ->enemy = attacker;
01060 targ->die (targ, inflictor, attacker, take, mod);
01061 return;
01062 } else if ( targ->pain ) {
01063 targ->pain (targ, attacker, take);
01064 }
01065 }
01066
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078 qboolean CanDamage (gentity_t *targ, vec3_t origin) {
01079 vec3_t dest;
01080 trace_t tr;
01081 vec3_t midpoint;
01082
01083
01084
01085 VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
01086 VectorScale (midpoint, 0.5, midpoint);
01087
01088 VectorCopy (midpoint, dest);
01089 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01090 if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
01091 return qtrue;
01092
01093
01094
01095 VectorCopy (midpoint, dest);
01096 dest[0] += 15.0;
01097 dest[1] += 15.0;
01098 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01099 if (tr.fraction == 1.0)
01100 return qtrue;
01101
01102 VectorCopy (midpoint, dest);
01103 dest[0] += 15.0;
01104 dest[1] -= 15.0;
01105 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01106 if (tr.fraction == 1.0)
01107 return qtrue;
01108
01109 VectorCopy (midpoint, dest);
01110 dest[0] -= 15.0;
01111 dest[1] += 15.0;
01112 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01113 if (tr.fraction == 1.0)
01114 return qtrue;
01115
01116 VectorCopy (midpoint, dest);
01117 dest[0] -= 15.0;
01118 dest[1] -= 15.0;
01119 trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01120 if (tr.fraction == 1.0)
01121 return qtrue;
01122
01123
01124 return qfalse;
01125 }
01126
01127
01128
01129
01130
01131
01132
01133 qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,
01134 gentity_t *ignore, int mod) {
01135 float points, dist;
01136 gentity_t *ent;
01137 int entityList[MAX_GENTITIES];
01138 int numListedEntities;
01139 vec3_t mins, maxs;
01140 vec3_t v;
01141 vec3_t dir;
01142 int i, e;
01143 qboolean hitClient = qfalse;
01144
01145 if ( radius < 1 ) {
01146 radius = 1;
01147 }
01148
01149 for ( i = 0 ; i < 3 ; i++ ) {
01150 mins[i] = origin[i] - radius;
01151 maxs[i] = origin[i] + radius;
01152 }
01153
01154 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
01155
01156 for ( e = 0 ; e < numListedEntities ; e++ ) {
01157 ent = &g_entities[entityList[ e ]];
01158
01159 if (ent == ignore)
01160 continue;
01161 if (!ent->takedamage)
01162 continue;
01163
01164
01165 for ( i = 0 ; i < 3 ; i++ ) {
01166 if ( origin[i] < ent->r.absmin[i] ) {
01167 v[i] = ent->r.absmin[i] - origin[i];
01168 } else if ( origin[i] > ent->r.absmax[i] ) {
01169 v[i] = origin[i] - ent->r.absmax[i];
01170 } else {
01171 v[i] = 0;
01172 }
01173 }
01174
01175 dist = VectorLength( v );
01176 if ( dist >= radius ) {
01177 continue;
01178 }
01179
01180 points = damage * ( 1.0 - dist / radius );
01181
01182 if( CanDamage (ent, origin) ) {
01183 if( LogAccuracyHit( ent, attacker ) ) {
01184 hitClient = qtrue;
01185 }
01186 VectorSubtract (ent->r.currentOrigin, origin, dir);
01187
01188
01189 dir[2] += 24;
01190 G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
01191 }
01192 }
01193
01194 return hitClient;
01195 }