|
|
1.1 ! root 1: ! 2: #include "g_local.h" ! 3: #include "m_player.h" ! 4: ! 5: ! 6: ! 7: static edict_t *current_player; ! 8: static gclient_t *current_client; ! 9: ! 10: static vec3_t forward, right, up; ! 11: float xyspeed; ! 12: ! 13: float bobmove; ! 14: int bobcycle; // odd cycles are right foot going forward ! 15: float bobfracsin; // sin(bobfrac*M_PI) ! 16: ! 17: /* ! 18: =============== ! 19: SV_CalcRoll ! 20: ! 21: =============== ! 22: */ ! 23: float SV_CalcRoll (vec3_t angles, vec3_t velocity) ! 24: { ! 25: float sign; ! 26: float side; ! 27: float value; ! 28: ! 29: side = DotProduct (velocity, right); ! 30: sign = side < 0 ? -1 : 1; ! 31: side = fabs(side); ! 32: ! 33: value = sv_rollangle->value; ! 34: ! 35: if (side < sv_rollspeed->value) ! 36: side = side * value / sv_rollspeed->value; ! 37: else ! 38: side = value; ! 39: ! 40: return side*sign; ! 41: ! 42: } ! 43: ! 44: ! 45: /* ! 46: =============== ! 47: P_DamageFeedback ! 48: ! 49: Handles color blends and view kicks ! 50: =============== ! 51: */ ! 52: void P_DamageFeedback (edict_t *player) ! 53: { ! 54: gclient_t *client; ! 55: float side; ! 56: float realcount, count, kick; ! 57: vec3_t v; ! 58: int r, l; ! 59: static vec3_t power_color = {0.0, 1.0, 0.0}; ! 60: static vec3_t acolor = {1.0, 1.0, 1.0}; ! 61: static vec3_t bcolor = {1.0, 0.0, 0.0}; ! 62: ! 63: client = player->client; ! 64: ! 65: // flash the backgrounds behind the status numbers ! 66: client->ps.stats[STAT_FLASHES] = 0; ! 67: if (client->damage_blood) ! 68: client->ps.stats[STAT_FLASHES] |= 1; ! 69: if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum)) ! 70: client->ps.stats[STAT_FLASHES] |= 2; ! 71: ! 72: // total points of damage shot at the player this frame ! 73: count = (client->damage_blood + client->damage_armor + client->damage_parmor); ! 74: if (count == 0) ! 75: return; // didn't take any damage ! 76: ! 77: // start a pain animation if still in the player model ! 78: if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255) ! 79: { ! 80: static int i; ! 81: ! 82: client->anim_priority = ANIM_PAIN; ! 83: if (client->ps.pmove.pm_flags & PMF_DUCKED) ! 84: { ! 85: player->s.frame = FRAME_crpain1-1; ! 86: client->anim_end = FRAME_crpain4; ! 87: } ! 88: else ! 89: { ! 90: i = (i+1)%3; ! 91: switch (i) ! 92: { ! 93: case 0: ! 94: player->s.frame = FRAME_pain101-1; ! 95: client->anim_end = FRAME_pain104; ! 96: break; ! 97: case 1: ! 98: player->s.frame = FRAME_pain201-1; ! 99: client->anim_end = FRAME_pain204; ! 100: break; ! 101: case 2: ! 102: player->s.frame = FRAME_pain301-1; ! 103: client->anim_end = FRAME_pain304; ! 104: break; ! 105: } ! 106: } ! 107: } ! 108: ! 109: realcount = count; ! 110: if (count < 10) ! 111: count = 10; // always make a visible effect ! 112: ! 113: // play an apropriate pain sound ! 114: if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum)) ! 115: { ! 116: r = 1 + (rand()&1); ! 117: player->pain_debounce_time = level.time + 0.7; ! 118: if (player->health < 25) ! 119: l = 25; ! 120: else if (player->health < 50) ! 121: l = 50; ! 122: else if (player->health < 75) ! 123: l = 75; ! 124: else ! 125: l = 100; ! 126: gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0); ! 127: } ! 128: ! 129: // the total alpha of the blend is always proportional to count ! 130: if (client->damage_alpha < 0) ! 131: client->damage_alpha = 0; ! 132: client->damage_alpha += count*0.01; ! 133: if (client->damage_alpha < 0.2) ! 134: client->damage_alpha = 0.2; ! 135: if (client->damage_alpha > 0.6) ! 136: client->damage_alpha = 0.6; // don't go too saturated ! 137: ! 138: // the color of the blend will vary based on how much was absorbed ! 139: // by different armors ! 140: VectorClear (v); ! 141: if (client->damage_parmor) ! 142: VectorMA (v, (float)client->damage_parmor/realcount, power_color, v); ! 143: if (client->damage_armor) ! 144: VectorMA (v, (float)client->damage_armor/realcount, acolor, v); ! 145: if (client->damage_blood) ! 146: VectorMA (v, (float)client->damage_blood/realcount, bcolor, v); ! 147: VectorCopy (v, client->damage_blend); ! 148: ! 149: ! 150: // ! 151: // calculate view angle kicks ! 152: // ! 153: kick = abs(client->damage_knockback); ! 154: if (kick && player->health > 0) // kick of 0 means no view adjust at all ! 155: { ! 156: kick = kick * 100 / player->health; ! 157: ! 158: if (kick < count*0.5) ! 159: kick = count*0.5; ! 160: if (kick > 50) ! 161: kick = 50; ! 162: ! 163: VectorSubtract (client->damage_from, player->s.origin, v); ! 164: VectorNormalize (v); ! 165: ! 166: side = DotProduct (v, right); ! 167: client->v_dmg_roll = kick*side*0.3; ! 168: ! 169: side = -DotProduct (v, forward); ! 170: client->v_dmg_pitch = kick*side*0.3; ! 171: ! 172: client->v_dmg_time = level.time + DAMAGE_TIME; ! 173: } ! 174: ! 175: // ! 176: // clear totals ! 177: // ! 178: client->damage_blood = 0; ! 179: client->damage_armor = 0; ! 180: client->damage_parmor = 0; ! 181: client->damage_knockback = 0; ! 182: } ! 183: ! 184: ! 185: ! 186: ! 187: /* ! 188: =============== ! 189: SV_CalcViewOffset ! 190: ! 191: Auto pitching on slopes? ! 192: ! 193: fall from 128: 400 = 160000 ! 194: fall from 256: 580 = 336400 ! 195: fall from 384: 720 = 518400 ! 196: fall from 512: 800 = 640000 ! 197: fall from 640: 960 = ! 198: ! 199: damage = deltavelocity*deltavelocity * 0.0001 ! 200: ! 201: =============== ! 202: */ ! 203: void SV_CalcViewOffset (edict_t *ent) ! 204: { ! 205: float *angles; ! 206: float bob; ! 207: float ratio; ! 208: float delta; ! 209: vec3_t v; ! 210: ! 211: ! 212: //=================================== ! 213: ! 214: // base angles ! 215: angles = ent->client->ps.kick_angles; ! 216: ! 217: // if dead, fix the angle and don't add any kick ! 218: if (ent->deadflag) ! 219: { ! 220: VectorClear (angles); ! 221: ! 222: if(ent->flags & FL_SAM_RAIMI) ! 223: { ! 224: ent->client->ps.viewangles[ROLL] = 0; ! 225: ent->client->ps.viewangles[PITCH] = 0; ! 226: } ! 227: else ! 228: { ! 229: ent->client->ps.viewangles[ROLL] = 40; ! 230: ent->client->ps.viewangles[PITCH] = -15; ! 231: } ! 232: ent->client->ps.viewangles[YAW] = ent->client->killer_yaw; ! 233: } ! 234: else ! 235: { ! 236: // add angles based on weapon kick ! 237: ! 238: VectorCopy (ent->client->kick_angles, angles); ! 239: ! 240: // add angles based on damage kick ! 241: ! 242: ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME; ! 243: if (ratio < 0) ! 244: { ! 245: ratio = 0; ! 246: ent->client->v_dmg_pitch = 0; ! 247: ent->client->v_dmg_roll = 0; ! 248: } ! 249: angles[PITCH] += ratio * ent->client->v_dmg_pitch; ! 250: angles[ROLL] += ratio * ent->client->v_dmg_roll; ! 251: ! 252: // add pitch based on fall kick ! 253: ! 254: ratio = (ent->client->fall_time - level.time) / FALL_TIME; ! 255: if (ratio < 0) ! 256: ratio = 0; ! 257: angles[PITCH] += ratio * ent->client->fall_value; ! 258: ! 259: // add angles based on velocity ! 260: ! 261: delta = DotProduct (ent->velocity, forward); ! 262: angles[PITCH] += delta*run_pitch->value; ! 263: ! 264: delta = DotProduct (ent->velocity, right); ! 265: angles[ROLL] += delta*run_roll->value; ! 266: ! 267: // add angles based on bob ! 268: ! 269: delta = bobfracsin * bob_pitch->value * xyspeed; ! 270: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) ! 271: delta *= 6; // crouching ! 272: angles[PITCH] += delta; ! 273: delta = bobfracsin * bob_roll->value * xyspeed; ! 274: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) ! 275: delta *= 6; // crouching ! 276: if (bobcycle & 1) ! 277: delta = -delta; ! 278: angles[ROLL] += delta; ! 279: } ! 280: ! 281: //=================================== ! 282: ! 283: // base origin ! 284: ! 285: VectorClear (v); ! 286: ! 287: // add view height ! 288: ! 289: v[2] += ent->viewheight; ! 290: ! 291: // add fall height ! 292: ! 293: ratio = (ent->client->fall_time - level.time) / FALL_TIME; ! 294: if (ratio < 0) ! 295: ratio = 0; ! 296: v[2] -= ratio * ent->client->fall_value * 0.4; ! 297: ! 298: // add bob height ! 299: ! 300: bob = bobfracsin * xyspeed * bob_up->value; ! 301: if (bob > 6) ! 302: bob = 6; ! 303: //gi.DebugGraph (bob *2, 255); ! 304: v[2] += bob; ! 305: ! 306: // add kick offset ! 307: ! 308: VectorAdd (v, ent->client->kick_origin, v); ! 309: ! 310: // absolutely bound offsets ! 311: // so the view can never be outside the player box ! 312: ! 313: if (v[0] < -14) ! 314: v[0] = -14; ! 315: else if (v[0] > 14) ! 316: v[0] = 14; ! 317: if (v[1] < -14) ! 318: v[1] = -14; ! 319: else if (v[1] > 14) ! 320: v[1] = 14; ! 321: if (v[2] < -22) ! 322: v[2] = -22; ! 323: else if (v[2] > 30) ! 324: v[2] = 30; ! 325: ! 326: VectorCopy (v, ent->client->ps.viewoffset); ! 327: } ! 328: ! 329: /* ! 330: ============== ! 331: SV_CalcGunOffset ! 332: ============== ! 333: */ ! 334: void SV_CalcGunOffset (edict_t *ent) ! 335: { ! 336: int i; ! 337: float delta; ! 338: //ROGUE ! 339: static gitem_t *heatbeam; ! 340: ! 341: if (!heatbeam) ! 342: heatbeam = FindItemByClassname ("weapon_heatbeam"); ! 343: ! 344: //ROGUE - heatbeam shouldn't bob so the beam looks right ! 345: if (ent->client->pers.weapon != heatbeam) ! 346: { ! 347: // ROGUE ! 348: // gun angles from bobbing ! 349: ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005; ! 350: ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01; ! 351: if (bobcycle & 1) ! 352: { ! 353: ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL]; ! 354: ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW]; ! 355: } ! 356: ! 357: ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005; ! 358: ! 359: // gun angles from delta movement ! 360: for (i=0 ; i<3 ; i++) ! 361: { ! 362: delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i]; ! 363: if (delta > 180) ! 364: delta -= 360; ! 365: if (delta < -180) ! 366: delta += 360; ! 367: if (delta > 45) ! 368: delta = 45; ! 369: if (delta < -45) ! 370: delta = -45; ! 371: if (i == YAW) ! 372: ent->client->ps.gunangles[ROLL] += 0.1*delta; ! 373: ent->client->ps.gunangles[i] += 0.2 * delta; ! 374: } ! 375: } ! 376: // ROGUE ! 377: else ! 378: { ! 379: for (i=0; i<3; i++) ! 380: ent->client->ps.gunangles[i] = 0; ! 381: } ! 382: //ROGUE ! 383: ! 384: // gun height ! 385: VectorClear (ent->client->ps.gunoffset); ! 386: // ent->ps->gunorigin[2] += bob; ! 387: ! 388: // gun_x / gun_y / gun_z are development tools ! 389: for (i=0 ; i<3 ; i++) ! 390: { ! 391: ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value); ! 392: ent->client->ps.gunoffset[i] += right[i]*gun_x->value; ! 393: ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value); ! 394: } ! 395: } ! 396: ! 397: ! 398: /* ! 399: ============= ! 400: SV_AddBlend ! 401: ============= ! 402: */ ! 403: void SV_AddBlend (float r, float g, float b, float a, float *v_blend) ! 404: { ! 405: float a2, a3; ! 406: ! 407: if (a <= 0) ! 408: return; ! 409: a2 = v_blend[3] + (1-v_blend[3])*a; // new total alpha ! 410: a3 = v_blend[3]/a2; // fraction of color from old ! 411: ! 412: v_blend[0] = v_blend[0]*a3 + r*(1-a3); ! 413: v_blend[1] = v_blend[1]*a3 + g*(1-a3); ! 414: v_blend[2] = v_blend[2]*a3 + b*(1-a3); ! 415: v_blend[3] = a2; ! 416: } ! 417: ! 418: ! 419: /* ! 420: ============= ! 421: SV_CalcBlend ! 422: ============= ! 423: */ ! 424: void SV_CalcBlend (edict_t *ent) ! 425: { ! 426: int contents; ! 427: vec3_t vieworg; ! 428: int remaining; ! 429: ! 430: ent->client->ps.blend[0] = ent->client->ps.blend[1] = ! 431: ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0; ! 432: ! 433: // add for contents ! 434: VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg); ! 435: contents = gi.pointcontents (vieworg); ! 436: if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) ) ! 437: ent->client->ps.rdflags |= RDF_UNDERWATER; ! 438: else ! 439: ent->client->ps.rdflags &= ~RDF_UNDERWATER; ! 440: ! 441: if (contents & (CONTENTS_SOLID|CONTENTS_LAVA)) ! 442: SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend); ! 443: else if (contents & CONTENTS_SLIME) ! 444: SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend); ! 445: else if (contents & CONTENTS_WATER) ! 446: SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend); ! 447: ! 448: // add for powerups ! 449: if (ent->client->quad_framenum > level.framenum) ! 450: { ! 451: remaining = ent->client->quad_framenum - level.framenum; ! 452: if (remaining == 30) // beginning to fade ! 453: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0); ! 454: if (remaining > 30 || (remaining & 4) ) ! 455: SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend); ! 456: } ! 457: // PMM - double damage ! 458: else if (ent->client->double_framenum > level.framenum) ! 459: { ! 460: remaining = ent->client->double_framenum - level.framenum; ! 461: if (remaining == 30) // beginning to fade ! 462: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0); ! 463: if (remaining > 30 || (remaining & 4) ) ! 464: SV_AddBlend (0.9, 0.7, 0, 0.08, ent->client->ps.blend); ! 465: } ! 466: // PMM ! 467: else if (ent->client->invincible_framenum > level.framenum) ! 468: { ! 469: remaining = ent->client->invincible_framenum - level.framenum; ! 470: if (remaining == 30) // beginning to fade ! 471: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0); ! 472: if (remaining > 30 || (remaining & 4) ) ! 473: SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend); ! 474: } ! 475: else if (ent->client->enviro_framenum > level.framenum) ! 476: { ! 477: remaining = ent->client->enviro_framenum - level.framenum; ! 478: if (remaining == 30) // beginning to fade ! 479: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 480: if (remaining > 30 || (remaining & 4) ) ! 481: SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend); ! 482: } ! 483: else if (ent->client->breather_framenum > level.framenum) ! 484: { ! 485: remaining = ent->client->breather_framenum - level.framenum; ! 486: if (remaining == 30) // beginning to fade ! 487: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 488: if (remaining > 30 || (remaining & 4) ) ! 489: SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend); ! 490: } ! 491: ! 492: //PGM ! 493: if(ent->client->nuke_framenum > level.framenum) ! 494: { ! 495: float brightness; ! 496: brightness = (ent->client->nuke_framenum - level.framenum) / 20.0; ! 497: SV_AddBlend (1, 1, 1, brightness, ent->client->ps.blend); ! 498: } ! 499: if (ent->client->ir_framenum > level.framenum) ! 500: { ! 501: remaining = ent->client->ir_framenum - level.framenum; ! 502: if(remaining > 30 || (remaining & 4)) ! 503: { ! 504: ent->client->ps.rdflags |= RDF_IRGOGGLES; ! 505: SV_AddBlend (1, 0, 0, 0.2, ent->client->ps.blend); ! 506: } ! 507: else ! 508: ent->client->ps.rdflags &= ~RDF_IRGOGGLES; ! 509: } ! 510: else ! 511: { ! 512: ent->client->ps.rdflags &= ~RDF_IRGOGGLES; ! 513: } ! 514: //PGM ! 515: ! 516: // add for damage ! 517: if (ent->client->damage_alpha > 0) ! 518: SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1] ! 519: ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend); ! 520: ! 521: if (ent->client->bonus_alpha > 0) ! 522: SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend); ! 523: ! 524: // drop the damage value ! 525: ent->client->damage_alpha -= 0.06; ! 526: if (ent->client->damage_alpha < 0) ! 527: ent->client->damage_alpha = 0; ! 528: ! 529: // drop the bonus value ! 530: ent->client->bonus_alpha -= 0.1; ! 531: if (ent->client->bonus_alpha < 0) ! 532: ent->client->bonus_alpha = 0; ! 533: } ! 534: ! 535: ! 536: /* ! 537: ================= ! 538: P_FallingDamage ! 539: ================= ! 540: */ ! 541: void P_FallingDamage (edict_t *ent) ! 542: { ! 543: float delta; ! 544: int damage; ! 545: vec3_t dir; ! 546: ! 547: if (ent->s.modelindex != 255) ! 548: return; // not in the player model ! 549: ! 550: if (ent->movetype == MOVETYPE_NOCLIP) ! 551: return; ! 552: ! 553: if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity)) ! 554: { ! 555: delta = ent->client->oldvelocity[2]; ! 556: } ! 557: else ! 558: { ! 559: if (!ent->groundentity) ! 560: return; ! 561: delta = ent->velocity[2] - ent->client->oldvelocity[2]; ! 562: } ! 563: delta = delta*delta * 0.0001; ! 564: ! 565: // never take falling damage if completely underwater ! 566: if (ent->waterlevel == 3) ! 567: return; ! 568: if (ent->waterlevel == 2) ! 569: delta *= 0.25; ! 570: if (ent->waterlevel == 1) ! 571: delta *= 0.5; ! 572: ! 573: if (delta < 1) ! 574: return; ! 575: ! 576: if (delta < 15) ! 577: { ! 578: ent->s.event = EV_FOOTSTEP; ! 579: return; ! 580: } ! 581: ! 582: ent->client->fall_value = delta*0.5; ! 583: if (ent->client->fall_value > 40) ! 584: ent->client->fall_value = 40; ! 585: ent->client->fall_time = level.time + FALL_TIME; ! 586: ! 587: if (delta > 30) ! 588: { ! 589: if (ent->health > 0) ! 590: { ! 591: if (delta >= 55) ! 592: ent->s.event = EV_FALLFAR; ! 593: else ! 594: ent->s.event = EV_FALL; ! 595: } ! 596: ent->pain_debounce_time = level.time; // no normal pain sound ! 597: damage = (delta-30)/2; ! 598: if (damage < 1) ! 599: damage = 1; ! 600: VectorSet (dir, 0, 0, 1); ! 601: ! 602: if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) ) ! 603: T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING); ! 604: } ! 605: else ! 606: { ! 607: ent->s.event = EV_FALLSHORT; ! 608: return; ! 609: } ! 610: } ! 611: ! 612: ! 613: ! 614: /* ! 615: ============= ! 616: P_WorldEffects ! 617: ============= ! 618: */ ! 619: void P_WorldEffects (void) ! 620: { ! 621: qboolean breather; ! 622: qboolean envirosuit; ! 623: int waterlevel, old_waterlevel; ! 624: ! 625: if (current_player->movetype == MOVETYPE_NOCLIP) ! 626: { ! 627: current_player->air_finished = level.time + 12; // don't need air ! 628: return; ! 629: } ! 630: ! 631: waterlevel = current_player->waterlevel; ! 632: old_waterlevel = current_client->old_waterlevel; ! 633: current_client->old_waterlevel = waterlevel; ! 634: ! 635: breather = current_client->breather_framenum > level.framenum; ! 636: envirosuit = current_client->enviro_framenum > level.framenum; ! 637: ! 638: // ! 639: // if just entered a water volume, play a sound ! 640: // ! 641: if (!old_waterlevel && waterlevel) ! 642: { ! 643: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 644: if (current_player->watertype & CONTENTS_LAVA) ! 645: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0); ! 646: else if (current_player->watertype & CONTENTS_SLIME) ! 647: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 648: else if (current_player->watertype & CONTENTS_WATER) ! 649: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 650: current_player->flags |= FL_INWATER; ! 651: ! 652: // clear damage_debounce, so the pain sound will play immediately ! 653: current_player->damage_debounce_time = level.time - 1; ! 654: } ! 655: ! 656: // ! 657: // if just completely exited a water volume, play a sound ! 658: // ! 659: if (old_waterlevel && ! waterlevel) ! 660: { ! 661: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 662: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0); ! 663: current_player->flags &= ~FL_INWATER; ! 664: } ! 665: ! 666: // ! 667: // check for head just going under water ! 668: // ! 669: if (old_waterlevel != 3 && waterlevel == 3) ! 670: { ! 671: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0); ! 672: } ! 673: ! 674: // ! 675: // check for head just coming out of water ! 676: // ! 677: if (old_waterlevel == 3 && waterlevel != 3) ! 678: { ! 679: if (current_player->air_finished < level.time) ! 680: { // gasp for air ! 681: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0); ! 682: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 683: } ! 684: else if (current_player->air_finished < level.time + 11) ! 685: { // just break surface ! 686: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0); ! 687: } ! 688: } ! 689: ! 690: // ! 691: // check for drowning ! 692: // ! 693: if (waterlevel == 3) ! 694: { ! 695: // breather or envirosuit give air ! 696: if (breather || envirosuit) ! 697: { ! 698: current_player->air_finished = level.time + 10; ! 699: ! 700: if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0) ! 701: { ! 702: if (!current_client->breather_sound) ! 703: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0); ! 704: else ! 705: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0); ! 706: current_client->breather_sound ^= 1; ! 707: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 708: //FIXME: release a bubble? ! 709: } ! 710: } ! 711: ! 712: // if out of air, start drowning ! 713: if (current_player->air_finished < level.time) ! 714: { // drown! ! 715: if (current_player->client->next_drown_time < level.time ! 716: && current_player->health > 0) ! 717: { ! 718: current_player->client->next_drown_time = level.time + 1; ! 719: ! 720: // take more damage the longer underwater ! 721: current_player->dmg += 2; ! 722: if (current_player->dmg > 15) ! 723: current_player->dmg = 15; ! 724: ! 725: // play a gurp sound instead of a normal pain sound ! 726: if (current_player->health <= current_player->dmg) ! 727: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0); ! 728: else if (rand()&1) ! 729: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0); ! 730: else ! 731: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0); ! 732: ! 733: current_player->pain_debounce_time = level.time; ! 734: ! 735: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER); ! 736: } ! 737: } ! 738: } ! 739: else ! 740: { ! 741: current_player->air_finished = level.time + 12; ! 742: current_player->dmg = 2; ! 743: } ! 744: ! 745: // ! 746: // check for sizzle damage ! 747: // ! 748: if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 749: { ! 750: if (current_player->watertype & CONTENTS_LAVA) ! 751: { ! 752: if (current_player->health > 0 ! 753: && current_player->pain_debounce_time <= level.time ! 754: && current_client->invincible_framenum < level.framenum) ! 755: { ! 756: if (rand()&1) ! 757: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0); ! 758: else ! 759: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0); ! 760: current_player->pain_debounce_time = level.time + 1; ! 761: } ! 762: ! 763: if (envirosuit) // take 1/3 damage with envirosuit ! 764: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA); ! 765: else ! 766: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA); ! 767: } ! 768: ! 769: if (current_player->watertype & CONTENTS_SLIME) ! 770: { ! 771: if (!envirosuit) ! 772: { // no damage from slime with envirosuit ! 773: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME); ! 774: } ! 775: } ! 776: } ! 777: } ! 778: ! 779: ! 780: /* ! 781: =============== ! 782: G_SetClientEffects ! 783: =============== ! 784: */ ! 785: void G_SetClientEffects (edict_t *ent) ! 786: { ! 787: int pa_type; ! 788: int remaining; ! 789: ! 790: ent->s.effects = 0; ! 791: // ent->s.renderfx = 0; ! 792: //PGM ! 793: ent->s.renderfx = RF_IR_VISIBLE; ! 794: //PGM ! 795: ! 796: if(ent->flags & FL_DISGUISED) ! 797: ent->s.renderfx = RF_USE_DISGUISE; ! 798: ! 799: if (ent->health <= 0 || level.intermissiontime) ! 800: return; ! 801: ! 802: //PGM ! 803: if (gamerules && gamerules->value) ! 804: { ! 805: if(DMGame.PlayerEffects) ! 806: DMGame.PlayerEffects(ent); ! 807: } ! 808: //PGM ! 809: ! 810: if (ent->powerarmor_time > level.time) ! 811: { ! 812: pa_type = PowerArmorType (ent); ! 813: if (pa_type == POWER_ARMOR_SCREEN) ! 814: { ! 815: ent->s.effects |= EF_POWERSCREEN; ! 816: } ! 817: else if (pa_type == POWER_ARMOR_SHIELD) ! 818: { ! 819: ent->s.effects |= EF_COLOR_SHELL; ! 820: ent->s.renderfx |= RF_SHELL_GREEN; ! 821: } ! 822: } ! 823: ! 824: if (ent->client->quad_framenum > level.framenum) ! 825: { ! 826: remaining = ent->client->quad_framenum - level.framenum; ! 827: if (remaining > 30 || (remaining & 4) ) ! 828: ent->s.effects |= EF_QUAD; ! 829: } ! 830: ! 831: //======= ! 832: //ROGUE ! 833: if (ent->client->double_framenum > level.framenum) ! 834: { ! 835: remaining = ent->client->double_framenum - level.framenum; ! 836: if (remaining > 30 || (remaining & 4) ) ! 837: ent->s.effects |= EF_DOUBLE; ! 838: } ! 839: if ((ent->client->owned_sphere) && (ent->client->owned_sphere->spawnflags == 1)) ! 840: { ! 841: ent->s.effects |= EF_HALF_DAMAGE; ! 842: } ! 843: if (ent->client->tracker_pain_framenum > level.framenum) ! 844: { ! 845: ent->s.effects |= EF_TRACKERTRAIL; ! 846: } ! 847: //ROGUE ! 848: //======= ! 849: ! 850: if (ent->client->invincible_framenum > level.framenum) ! 851: { ! 852: remaining = ent->client->invincible_framenum - level.framenum; ! 853: if (remaining > 30 || (remaining & 4) ) ! 854: ent->s.effects |= EF_PENT; ! 855: } ! 856: ! 857: // show cheaters!!! ! 858: if (ent->flags & FL_GODMODE) ! 859: { ! 860: ent->s.effects |= EF_COLOR_SHELL; ! 861: ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE); ! 862: } ! 863: ! 864: //PGM ! 865: if (ent->client->torch_framenum > level.framenum) ! 866: { ! 867: gi.WriteByte (svc_temp_entity); ! 868: gi.WriteByte (TE_FLASHLIGHT); ! 869: gi.WritePosition (ent->s.origin); ! 870: gi.WriteShort (ent - g_edicts); ! 871: gi.multicast (ent->s.origin, MULTICAST_PVS); ! 872: } ! 873: //PGM ! 874: } ! 875: ! 876: ! 877: /* ! 878: =============== ! 879: G_SetClientEvent ! 880: =============== ! 881: */ ! 882: void G_SetClientEvent (edict_t *ent) ! 883: { ! 884: if (ent->s.event) ! 885: return; ! 886: ! 887: if ( ent->groundentity && xyspeed > 225) ! 888: { ! 889: if ( (int)(current_client->bobtime+bobmove) != bobcycle ) ! 890: ent->s.event = EV_FOOTSTEP; ! 891: } ! 892: } ! 893: ! 894: /* ! 895: =============== ! 896: G_SetClientSound ! 897: =============== ! 898: */ ! 899: void G_SetClientSound (edict_t *ent) ! 900: { ! 901: char *weap; ! 902: ! 903: if (ent->client->pers.game_helpchanged != game.helpchanged) ! 904: { ! 905: ent->client->pers.game_helpchanged = game.helpchanged; ! 906: ent->client->pers.helpchanged = 1; ! 907: } ! 908: ! 909: // help beep (no more than three times) ! 910: if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) ) ! 911: { ! 912: ent->client->pers.helpchanged++; ! 913: gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0); ! 914: } ! 915: ! 916: ! 917: if (ent->client->pers.weapon) ! 918: weap = ent->client->pers.weapon->classname; ! 919: else ! 920: weap = ""; ! 921: ! 922: if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 923: ent->s.sound = snd_fry; ! 924: else if (strcmp(weap, "weapon_railgun") == 0) ! 925: ent->s.sound = gi.soundindex("weapons/rg_hum.wav"); ! 926: else if (strcmp(weap, "weapon_bfg") == 0) ! 927: ent->s.sound = gi.soundindex("weapons/bfg_hum.wav"); ! 928: else if (ent->client->weapon_sound) ! 929: ent->s.sound = ent->client->weapon_sound; ! 930: else ! 931: ent->s.sound = 0; ! 932: } ! 933: ! 934: /* ! 935: =============== ! 936: G_SetClientFrame ! 937: =============== ! 938: */ ! 939: void G_SetClientFrame (edict_t *ent) ! 940: { ! 941: gclient_t *client; ! 942: qboolean duck, run; ! 943: ! 944: if (ent->s.modelindex != 255) ! 945: return; // not in the player model ! 946: ! 947: client = ent->client; ! 948: ! 949: if (client->ps.pmove.pm_flags & PMF_DUCKED) ! 950: duck = true; ! 951: else ! 952: duck = false; ! 953: if (xyspeed) ! 954: run = true; ! 955: else ! 956: run = false; ! 957: ! 958: // check for stand/duck and stop/go transitions ! 959: if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH) ! 960: goto newanim; ! 961: if (run != client->anim_run && client->anim_priority == ANIM_BASIC) ! 962: goto newanim; ! 963: if (!ent->groundentity && client->anim_priority <= ANIM_WAVE) ! 964: goto newanim; ! 965: ! 966: if(client->anim_priority == ANIM_REVERSE) ! 967: { ! 968: if(ent->s.frame > client->anim_end) ! 969: { ! 970: ent->s.frame--; ! 971: return; ! 972: } ! 973: } ! 974: else if (ent->s.frame < client->anim_end) ! 975: { // continue an animation ! 976: ent->s.frame++; ! 977: return; ! 978: } ! 979: ! 980: if (client->anim_priority == ANIM_DEATH) ! 981: return; // stay there ! 982: if (client->anim_priority == ANIM_JUMP) ! 983: { ! 984: if (!ent->groundentity) ! 985: return; // stay there ! 986: ent->client->anim_priority = ANIM_WAVE; ! 987: ent->s.frame = FRAME_jump3; ! 988: ent->client->anim_end = FRAME_jump6; ! 989: return; ! 990: } ! 991: ! 992: newanim: ! 993: // return to either a running or standing frame ! 994: client->anim_priority = ANIM_BASIC; ! 995: client->anim_duck = duck; ! 996: client->anim_run = run; ! 997: ! 998: if (!ent->groundentity) ! 999: { ! 1000: client->anim_priority = ANIM_JUMP; ! 1001: if (ent->s.frame != FRAME_jump2) ! 1002: ent->s.frame = FRAME_jump1; ! 1003: client->anim_end = FRAME_jump2; ! 1004: } ! 1005: else if (run) ! 1006: { // running ! 1007: if (duck) ! 1008: { ! 1009: ent->s.frame = FRAME_crwalk1; ! 1010: client->anim_end = FRAME_crwalk6; ! 1011: } ! 1012: else ! 1013: { ! 1014: ent->s.frame = FRAME_run1; ! 1015: client->anim_end = FRAME_run6; ! 1016: } ! 1017: } ! 1018: else ! 1019: { // standing ! 1020: if (duck) ! 1021: { ! 1022: ent->s.frame = FRAME_crstnd01; ! 1023: client->anim_end = FRAME_crstnd19; ! 1024: } ! 1025: else ! 1026: { ! 1027: ent->s.frame = FRAME_stand01; ! 1028: client->anim_end = FRAME_stand40; ! 1029: } ! 1030: } ! 1031: } ! 1032: ! 1033: ! 1034: /* ! 1035: ================= ! 1036: ClientEndServerFrame ! 1037: ! 1038: Called for each player at the end of the server frame ! 1039: and right after spawning ! 1040: ================= ! 1041: */ ! 1042: void ClientEndServerFrame (edict_t *ent) ! 1043: { ! 1044: float bobtime; ! 1045: int i; ! 1046: ! 1047: current_player = ent; ! 1048: current_client = ent->client; ! 1049: ! 1050: // ! 1051: // If the origin or velocity have changed since ClientThink(), ! 1052: // update the pmove values. This will happen when the client ! 1053: // is pushed by a bmodel or kicked by an explosion. ! 1054: // ! 1055: // If it wasn't updated here, the view position would lag a frame ! 1056: // behind the body position when pushed -- "sinking into plats" ! 1057: // ! 1058: for (i=0 ; i<3 ; i++) ! 1059: { ! 1060: current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0; ! 1061: current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0; ! 1062: } ! 1063: ! 1064: // ! 1065: // If the end of unit layout is displayed, don't give ! 1066: // the player any normal movement attributes ! 1067: // ! 1068: if (level.intermissiontime) ! 1069: { ! 1070: // FIXME: add view drifting here? ! 1071: current_client->ps.blend[3] = 0; ! 1072: current_client->ps.fov = 90; ! 1073: G_SetStats (ent); ! 1074: return; ! 1075: } ! 1076: ! 1077: AngleVectors (ent->client->v_angle, forward, right, up); ! 1078: ! 1079: // burn from lava, etc ! 1080: P_WorldEffects (); ! 1081: ! 1082: // ! 1083: // set model angles from view angles so other things in ! 1084: // the world can tell which direction you are looking ! 1085: // ! 1086: if (ent->client->v_angle[PITCH] > 180) ! 1087: ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3; ! 1088: else ! 1089: ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3; ! 1090: ent->s.angles[YAW] = ent->client->v_angle[YAW]; ! 1091: ent->s.angles[ROLL] = 0; ! 1092: ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4; ! 1093: ! 1094: // ! 1095: // calculate speed and cycle to be used for ! 1096: // all cyclic walking effects ! 1097: // ! 1098: xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]); ! 1099: ! 1100: if (xyspeed < 5) ! 1101: { ! 1102: bobmove = 0; ! 1103: current_client->bobtime = 0; // start at beginning of cycle again ! 1104: } ! 1105: else if (ent->groundentity) ! 1106: { // so bobbing only cycles when on ground ! 1107: if (xyspeed > 210) ! 1108: bobmove = 0.25; ! 1109: else if (xyspeed > 100) ! 1110: bobmove = 0.125; ! 1111: else ! 1112: bobmove = 0.0625; ! 1113: } ! 1114: ! 1115: bobtime = (current_client->bobtime += bobmove); ! 1116: ! 1117: if (current_client->ps.pmove.pm_flags & PMF_DUCKED) ! 1118: bobtime *= 4; ! 1119: ! 1120: bobcycle = (int)bobtime; ! 1121: bobfracsin = fabs(sin(bobtime*M_PI)); ! 1122: ! 1123: // detect hitting the floor ! 1124: P_FallingDamage (ent); ! 1125: ! 1126: // apply all the damage taken this frame ! 1127: P_DamageFeedback (ent); ! 1128: ! 1129: // determine the view offsets ! 1130: SV_CalcViewOffset (ent); ! 1131: ! 1132: // determine the gun offsets ! 1133: SV_CalcGunOffset (ent); ! 1134: ! 1135: // determine the full screen color blend ! 1136: // must be after viewoffset, so eye contents can be ! 1137: // accurately determined ! 1138: // FIXME: with client prediction, the contents ! 1139: // should be determined by the client ! 1140: SV_CalcBlend (ent); ! 1141: ! 1142: // chase cam stuff ! 1143: if (ent->client->resp.spectator) ! 1144: G_SetSpectatorStats(ent); ! 1145: else ! 1146: G_SetStats (ent); ! 1147: ! 1148: G_CheckChaseStats(ent); ! 1149: ! 1150: G_SetClientEvent (ent); ! 1151: ! 1152: G_SetClientEffects (ent); ! 1153: ! 1154: G_SetClientSound (ent); ! 1155: ! 1156: G_SetClientFrame (ent); ! 1157: ! 1158: VectorCopy (ent->velocity, ent->client->oldvelocity); ! 1159: VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles); ! 1160: ! 1161: // clear weapon kicks ! 1162: VectorClear (ent->client->kick_origin); ! 1163: VectorClear (ent->client->kick_angles); ! 1164: ! 1165: // if the scoreboard is up, update it ! 1166: if (ent->client->showscores && !(level.framenum & 31) ) ! 1167: { ! 1168: DeathmatchScoreboardMessage (ent, ent->enemy); ! 1169: gi.unicast (ent, false); ! 1170: } ! 1171: } ! 1172:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.