|
|
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: ent->client->ps.viewangles[ROLL] = 40; ! 223: ent->client->ps.viewangles[PITCH] = -15; ! 224: ent->client->ps.viewangles[YAW] = ent->client->killer_yaw; ! 225: } ! 226: else ! 227: { ! 228: // add angles based on weapon kick ! 229: ! 230: VectorCopy (ent->client->kick_angles, angles); ! 231: ! 232: // add angles based on damage kick ! 233: ! 234: ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME; ! 235: if (ratio < 0) ! 236: { ! 237: ratio = 0; ! 238: ent->client->v_dmg_pitch = 0; ! 239: ent->client->v_dmg_roll = 0; ! 240: } ! 241: angles[PITCH] += ratio * ent->client->v_dmg_pitch; ! 242: angles[ROLL] += ratio * ent->client->v_dmg_roll; ! 243: ! 244: // add pitch based on fall kick ! 245: ! 246: ratio = (ent->client->fall_time - level.time) / FALL_TIME; ! 247: if (ratio < 0) ! 248: ratio = 0; ! 249: angles[PITCH] += ratio * ent->client->fall_value; ! 250: ! 251: // add angles based on velocity ! 252: ! 253: delta = DotProduct (ent->velocity, forward); ! 254: angles[PITCH] += delta*run_pitch->value; ! 255: ! 256: delta = DotProduct (ent->velocity, right); ! 257: angles[ROLL] += delta*run_roll->value; ! 258: ! 259: // add angles based on bob ! 260: ! 261: delta = bobfracsin * bob_pitch->value * xyspeed; ! 262: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) ! 263: delta *= 6; // crouching ! 264: angles[PITCH] += delta; ! 265: delta = bobfracsin * bob_roll->value * xyspeed; ! 266: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) ! 267: delta *= 6; // crouching ! 268: if (bobcycle & 1) ! 269: delta = -delta; ! 270: angles[ROLL] += delta; ! 271: } ! 272: ! 273: //=================================== ! 274: ! 275: // base origin ! 276: ! 277: VectorClear (v); ! 278: ! 279: // add view height ! 280: ! 281: v[2] += ent->viewheight; ! 282: ! 283: // add fall height ! 284: ! 285: ratio = (ent->client->fall_time - level.time) / FALL_TIME; ! 286: if (ratio < 0) ! 287: ratio = 0; ! 288: v[2] -= ratio * ent->client->fall_value * 0.4; ! 289: ! 290: // add bob height ! 291: ! 292: bob = bobfracsin * xyspeed * bob_up->value; ! 293: if (bob > 6) ! 294: bob = 6; ! 295: //gi.DebugGraph (bob *2, 255); ! 296: v[2] += bob; ! 297: ! 298: // add kick offset ! 299: ! 300: VectorAdd (v, ent->client->kick_origin, v); ! 301: ! 302: // absolutely bound offsets ! 303: // so the view can never be outside the player box ! 304: ! 305: if (v[0] < -14) ! 306: v[0] = -14; ! 307: else if (v[0] > 14) ! 308: v[0] = 14; ! 309: if (v[1] < -14) ! 310: v[1] = -14; ! 311: else if (v[1] > 14) ! 312: v[1] = 14; ! 313: if (v[2] < -22) ! 314: v[2] = -22; ! 315: else if (v[2] > 30) ! 316: v[2] = 30; ! 317: ! 318: VectorCopy (v, ent->client->ps.viewoffset); ! 319: } ! 320: ! 321: /* ! 322: ============== ! 323: SV_CalcGunOffset ! 324: ============== ! 325: */ ! 326: void SV_CalcGunOffset (edict_t *ent) ! 327: { ! 328: int i; ! 329: float delta; ! 330: ! 331: // gun angles from bobbing ! 332: ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005; ! 333: ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01; ! 334: if (bobcycle & 1) ! 335: { ! 336: ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL]; ! 337: ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW]; ! 338: } ! 339: ! 340: ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005; ! 341: ! 342: // gun angles from delta movement ! 343: for (i=0 ; i<3 ; i++) ! 344: { ! 345: delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i]; ! 346: if (delta > 180) ! 347: delta -= 360; ! 348: if (delta < -180) ! 349: delta += 360; ! 350: if (delta > 45) ! 351: delta = 45; ! 352: if (delta < -45) ! 353: delta = -45; ! 354: if (i == YAW) ! 355: ent->client->ps.gunangles[ROLL] += 0.1*delta; ! 356: ent->client->ps.gunangles[i] += 0.2 * delta; ! 357: } ! 358: ! 359: // gun height ! 360: VectorClear (ent->client->ps.gunoffset); ! 361: // ent->ps->gunorigin[2] += bob; ! 362: ! 363: // gun_x / gun_y / gun_z are development tools ! 364: for (i=0 ; i<3 ; i++) ! 365: { ! 366: ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value); ! 367: ent->client->ps.gunoffset[i] += right[i]*gun_x->value; ! 368: ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value); ! 369: } ! 370: } ! 371: ! 372: ! 373: /* ! 374: ============= ! 375: SV_AddBlend ! 376: ============= ! 377: */ ! 378: void SV_AddBlend (float r, float g, float b, float a, float *v_blend) ! 379: { ! 380: float a2, a3; ! 381: ! 382: if (a <= 0) ! 383: return; ! 384: a2 = v_blend[3] + (1-v_blend[3])*a; // new total alpha ! 385: a3 = v_blend[3]/a2; // fraction of color from old ! 386: ! 387: v_blend[0] = v_blend[0]*a3 + r*(1-a3); ! 388: v_blend[1] = v_blend[1]*a3 + g*(1-a3); ! 389: v_blend[2] = v_blend[2]*a3 + b*(1-a3); ! 390: v_blend[3] = a2; ! 391: } ! 392: ! 393: ! 394: /* ! 395: ============= ! 396: SV_CalcBlend ! 397: ============= ! 398: */ ! 399: void SV_CalcBlend (edict_t *ent) ! 400: { ! 401: int contents; ! 402: vec3_t vieworg; ! 403: int remaining; ! 404: ! 405: ent->client->ps.blend[0] = ent->client->ps.blend[1] = ! 406: ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0; ! 407: ! 408: // add for contents ! 409: VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg); ! 410: contents = gi.pointcontents (vieworg); ! 411: if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) ) ! 412: ent->client->ps.rdflags |= RDF_UNDERWATER; ! 413: else ! 414: ent->client->ps.rdflags &= ~RDF_UNDERWATER; ! 415: ! 416: if (contents & (CONTENTS_SOLID|CONTENTS_LAVA)) ! 417: SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend); ! 418: else if (contents & CONTENTS_SLIME) ! 419: SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend); ! 420: else if (contents & CONTENTS_WATER) ! 421: SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend); ! 422: ! 423: // add for powerups ! 424: if (ent->client->quad_framenum > level.framenum) ! 425: { ! 426: remaining = ent->client->quad_framenum - level.framenum; ! 427: if (remaining == 30) // beginning to fade ! 428: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0); ! 429: if (remaining > 30 || (remaining & 4) ) ! 430: SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend); ! 431: } ! 432: else if (ent->client->invincible_framenum > level.framenum) ! 433: { ! 434: remaining = ent->client->invincible_framenum - level.framenum; ! 435: if (remaining == 30) // beginning to fade ! 436: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0); ! 437: if (remaining > 30 || (remaining & 4) ) ! 438: SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend); ! 439: } ! 440: else if (ent->client->enviro_framenum > level.framenum) ! 441: { ! 442: remaining = ent->client->enviro_framenum - level.framenum; ! 443: if (remaining == 30) // beginning to fade ! 444: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 445: if (remaining > 30 || (remaining & 4) ) ! 446: SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend); ! 447: } ! 448: else if (ent->client->breather_framenum > level.framenum) ! 449: { ! 450: remaining = ent->client->breather_framenum - level.framenum; ! 451: if (remaining == 30) // beginning to fade ! 452: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 453: if (remaining > 30 || (remaining & 4) ) ! 454: SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend); ! 455: } ! 456: ! 457: // add for damage ! 458: if (ent->client->damage_alpha > 0) ! 459: SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1] ! 460: ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend); ! 461: ! 462: if (ent->client->bonus_alpha > 0) ! 463: SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend); ! 464: ! 465: // drop the damage value ! 466: ent->client->damage_alpha -= 0.06; ! 467: if (ent->client->damage_alpha < 0) ! 468: ent->client->damage_alpha = 0; ! 469: ! 470: // drop the bonus value ! 471: ent->client->bonus_alpha -= 0.1; ! 472: if (ent->client->bonus_alpha < 0) ! 473: ent->client->bonus_alpha = 0; ! 474: } ! 475: ! 476: ! 477: /* ! 478: ================= ! 479: P_FallingDamage ! 480: ================= ! 481: */ ! 482: void P_FallingDamage (edict_t *ent) ! 483: { ! 484: float delta; ! 485: int damage; ! 486: vec3_t dir; ! 487: ! 488: if (ent->s.modelindex != 255) ! 489: return; // not in the player model ! 490: ! 491: if (ent->movetype == MOVETYPE_NOCLIP) ! 492: return; ! 493: ! 494: if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity)) ! 495: { ! 496: delta = ent->client->oldvelocity[2]; ! 497: } ! 498: else ! 499: { ! 500: if (!ent->groundentity) ! 501: return; ! 502: delta = ent->velocity[2] - ent->client->oldvelocity[2]; ! 503: } ! 504: delta = delta*delta * 0.0001; ! 505: ! 506: // never take falling damage if completely underwater ! 507: if (ent->waterlevel == 3) ! 508: return; ! 509: if (ent->waterlevel == 2) ! 510: delta *= 0.25; ! 511: if (ent->waterlevel == 1) ! 512: delta *= 0.5; ! 513: ! 514: if (delta < 1) ! 515: return; ! 516: ! 517: if (delta < 15) ! 518: { ! 519: ent->s.event = EV_FOOTSTEP; ! 520: return; ! 521: } ! 522: ! 523: ent->client->fall_value = delta*0.5; ! 524: if (ent->client->fall_value > 40) ! 525: ent->client->fall_value = 40; ! 526: ent->client->fall_time = level.time + FALL_TIME; ! 527: ! 528: if (delta > 30) ! 529: { ! 530: if (ent->health > 0) ! 531: { ! 532: if (delta >= 55) ! 533: ent->s.event = EV_FALLFAR; ! 534: else ! 535: ent->s.event = EV_FALL; ! 536: } ! 537: ent->pain_debounce_time = level.time; // no normal pain sound ! 538: damage = (delta-30)/2; ! 539: if (damage < 1) ! 540: damage = 1; ! 541: VectorSet (dir, 0, 0, 1); ! 542: ! 543: if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) ) ! 544: T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING); ! 545: } ! 546: else ! 547: { ! 548: ent->s.event = EV_FALLSHORT; ! 549: return; ! 550: } ! 551: } ! 552: ! 553: ! 554: ! 555: /* ! 556: ============= ! 557: P_WorldEffects ! 558: ============= ! 559: */ ! 560: void P_WorldEffects (void) ! 561: { ! 562: qboolean breather; ! 563: qboolean envirosuit; ! 564: int waterlevel, old_waterlevel; ! 565: ! 566: if (current_player->movetype == MOVETYPE_NOCLIP) ! 567: { ! 568: current_player->air_finished = level.time + 12; // don't need air ! 569: return; ! 570: } ! 571: ! 572: waterlevel = current_player->waterlevel; ! 573: old_waterlevel = current_client->old_waterlevel; ! 574: current_client->old_waterlevel = waterlevel; ! 575: ! 576: breather = current_client->breather_framenum > level.framenum; ! 577: envirosuit = current_client->enviro_framenum > level.framenum; ! 578: ! 579: // ! 580: // if just entered a water volume, play a sound ! 581: // ! 582: if (!old_waterlevel && waterlevel) ! 583: { ! 584: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 585: if (current_player->watertype & CONTENTS_LAVA) ! 586: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0); ! 587: else if (current_player->watertype & CONTENTS_SLIME) ! 588: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 589: else if (current_player->watertype & CONTENTS_WATER) ! 590: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 591: current_player->flags |= FL_INWATER; ! 592: ! 593: // clear damage_debounce, so the pain sound will play immediately ! 594: current_player->damage_debounce_time = level.time - 1; ! 595: } ! 596: ! 597: // ! 598: // if just completely exited a water volume, play a sound ! 599: // ! 600: if (old_waterlevel && ! waterlevel) ! 601: { ! 602: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 603: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0); ! 604: current_player->flags &= ~FL_INWATER; ! 605: } ! 606: ! 607: // ! 608: // check for head just going under water ! 609: // ! 610: if (old_waterlevel != 3 && waterlevel == 3) ! 611: { ! 612: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0); ! 613: } ! 614: ! 615: // ! 616: // check for head just coming out of water ! 617: // ! 618: if (old_waterlevel == 3 && waterlevel != 3) ! 619: { ! 620: if (current_player->air_finished < level.time) ! 621: { // gasp for air ! 622: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0); ! 623: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 624: } ! 625: else if (current_player->air_finished < level.time + 11) ! 626: { // just break surface ! 627: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0); ! 628: } ! 629: } ! 630: ! 631: // ! 632: // check for drowning ! 633: // ! 634: if (waterlevel == 3) ! 635: { ! 636: // breather or envirosuit give air ! 637: if (breather || envirosuit) ! 638: { ! 639: current_player->air_finished = level.time + 10; ! 640: ! 641: if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0) ! 642: { ! 643: if (!current_client->breather_sound) ! 644: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0); ! 645: else ! 646: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0); ! 647: current_client->breather_sound ^= 1; ! 648: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 649: //FIXME: release a bubble? ! 650: } ! 651: } ! 652: ! 653: // if out of air, start drowning ! 654: if (current_player->air_finished < level.time) ! 655: { // drown! ! 656: if (current_player->client->next_drown_time < level.time ! 657: && current_player->health > 0) ! 658: { ! 659: current_player->client->next_drown_time = level.time + 1; ! 660: ! 661: // take more damage the longer underwater ! 662: current_player->dmg += 2; ! 663: if (current_player->dmg > 15) ! 664: current_player->dmg = 15; ! 665: ! 666: // play a gurp sound instead of a normal pain sound ! 667: if (current_player->health <= current_player->dmg) ! 668: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0); ! 669: else if (rand()&1) ! 670: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0); ! 671: else ! 672: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0); ! 673: ! 674: current_player->pain_debounce_time = level.time; ! 675: ! 676: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER); ! 677: } ! 678: } ! 679: } ! 680: else ! 681: { ! 682: current_player->air_finished = level.time + 12; ! 683: current_player->dmg = 2; ! 684: } ! 685: ! 686: // ! 687: // check for sizzle damage ! 688: // ! 689: if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 690: { ! 691: if (current_player->watertype & CONTENTS_LAVA) ! 692: { ! 693: if (current_player->health > 0 ! 694: && current_player->pain_debounce_time <= level.time ! 695: && current_client->invincible_framenum < level.framenum) ! 696: { ! 697: if (rand()&1) ! 698: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0); ! 699: else ! 700: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0); ! 701: current_player->pain_debounce_time = level.time + 1; ! 702: } ! 703: ! 704: if (envirosuit) // take 1/3 damage with envirosuit ! 705: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA); ! 706: else ! 707: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA); ! 708: } ! 709: ! 710: if (current_player->watertype & CONTENTS_SLIME) ! 711: { ! 712: if (!envirosuit) ! 713: { // no damage from slime with envirosuit ! 714: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME); ! 715: } ! 716: } ! 717: } ! 718: } ! 719: ! 720: ! 721: /* ! 722: =============== ! 723: G_SetClientEffects ! 724: =============== ! 725: */ ! 726: void G_SetClientEffects (edict_t *ent) ! 727: { ! 728: int pa_type; ! 729: int remaining; ! 730: ! 731: ent->s.effects = 0; ! 732: ent->s.renderfx = 0; ! 733: ! 734: if (ent->health <= 0 || level.intermissiontime) ! 735: return; ! 736: ! 737: if (ent->powerarmor_time > level.time) ! 738: { ! 739: pa_type = PowerArmorType (ent); ! 740: if (pa_type == POWER_ARMOR_SCREEN) ! 741: { ! 742: ent->s.effects |= EF_POWERSCREEN; ! 743: } ! 744: else if (pa_type == POWER_ARMOR_SHIELD) ! 745: { ! 746: ent->s.effects |= EF_COLOR_SHELL; ! 747: ent->s.renderfx |= RF_SHELL_GREEN; ! 748: } ! 749: } ! 750: ! 751: if (ent->client->quad_framenum > level.framenum) ! 752: { ! 753: remaining = ent->client->quad_framenum - level.framenum; ! 754: if (remaining > 30 || (remaining & 4) ) ! 755: ent->s.effects |= EF_QUAD; ! 756: } ! 757: ! 758: if (ent->client->invincible_framenum > level.framenum) ! 759: { ! 760: remaining = ent->client->invincible_framenum - level.framenum; ! 761: if (remaining > 30 || (remaining & 4) ) ! 762: ent->s.effects |= EF_PENT; ! 763: } ! 764: ! 765: // show cheaters!!! ! 766: if (ent->flags & FL_GODMODE) ! 767: { ! 768: ent->s.effects |= EF_COLOR_SHELL; ! 769: ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE); ! 770: } ! 771: } ! 772: ! 773: ! 774: /* ! 775: =============== ! 776: G_SetClientEvent ! 777: =============== ! 778: */ ! 779: void G_SetClientEvent (edict_t *ent) ! 780: { ! 781: if (ent->s.event) ! 782: return; ! 783: ! 784: if ( ent->groundentity && xyspeed > 225) ! 785: { ! 786: if ( (int)(current_client->bobtime+bobmove) != bobcycle ) ! 787: ent->s.event = EV_FOOTSTEP; ! 788: } ! 789: } ! 790: ! 791: /* ! 792: =============== ! 793: G_SetClientSound ! 794: =============== ! 795: */ ! 796: void G_SetClientSound (edict_t *ent) ! 797: { ! 798: char *weap; ! 799: ! 800: if (ent->client->pers.game_helpchanged != game.helpchanged) ! 801: { ! 802: ent->client->pers.game_helpchanged = game.helpchanged; ! 803: ent->client->pers.helpchanged = 1; ! 804: } ! 805: ! 806: // help beep (no more than three times) ! 807: if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) ) ! 808: { ! 809: ent->client->pers.helpchanged++; ! 810: gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0); ! 811: } ! 812: ! 813: ! 814: if (ent->client->pers.weapon) ! 815: weap = ent->client->pers.weapon->classname; ! 816: else ! 817: weap = ""; ! 818: ! 819: if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 820: ent->s.sound = snd_fry; ! 821: else if (strcmp(weap, "weapon_railgun") == 0) ! 822: ent->s.sound = gi.soundindex("weapons/rg_hum.wav"); ! 823: else if (strcmp(weap, "weapon_bfg") == 0) ! 824: ent->s.sound = gi.soundindex("weapons/bfg_hum.wav"); ! 825: else if (ent->client->weapon_sound) ! 826: ent->s.sound = ent->client->weapon_sound; ! 827: else ! 828: ent->s.sound = 0; ! 829: } ! 830: ! 831: /* ! 832: =============== ! 833: G_SetClientFrame ! 834: =============== ! 835: */ ! 836: void G_SetClientFrame (edict_t *ent) ! 837: { ! 838: gclient_t *client; ! 839: qboolean duck, run; ! 840: ! 841: if (ent->s.modelindex != 255) ! 842: return; // not in the player model ! 843: ! 844: client = ent->client; ! 845: ! 846: if (client->ps.pmove.pm_flags & PMF_DUCKED) ! 847: duck = true; ! 848: else ! 849: duck = false; ! 850: if (xyspeed) ! 851: run = true; ! 852: else ! 853: run = false; ! 854: ! 855: // check for stand/duck and stop/go transitions ! 856: if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH) ! 857: goto newanim; ! 858: if (run != client->anim_run && client->anim_priority == ANIM_BASIC) ! 859: goto newanim; ! 860: if (!ent->groundentity && client->anim_priority <= ANIM_WAVE) ! 861: goto newanim; ! 862: ! 863: if(client->anim_priority == ANIM_REVERSE) ! 864: { ! 865: if(ent->s.frame > client->anim_end) ! 866: { ! 867: ent->s.frame--; ! 868: return; ! 869: } ! 870: } ! 871: else if (ent->s.frame < client->anim_end) ! 872: { // continue an animation ! 873: ent->s.frame++; ! 874: return; ! 875: } ! 876: ! 877: if (client->anim_priority == ANIM_DEATH) ! 878: return; // stay there ! 879: if (client->anim_priority == ANIM_JUMP) ! 880: { ! 881: if (!ent->groundentity) ! 882: return; // stay there ! 883: ent->client->anim_priority = ANIM_WAVE; ! 884: ent->s.frame = FRAME_jump3; ! 885: ent->client->anim_end = FRAME_jump6; ! 886: return; ! 887: } ! 888: ! 889: newanim: ! 890: // return to either a running or standing frame ! 891: client->anim_priority = ANIM_BASIC; ! 892: client->anim_duck = duck; ! 893: client->anim_run = run; ! 894: ! 895: if (!ent->groundentity) ! 896: { ! 897: client->anim_priority = ANIM_JUMP; ! 898: if (ent->s.frame != FRAME_jump2) ! 899: ent->s.frame = FRAME_jump1; ! 900: client->anim_end = FRAME_jump2; ! 901: } ! 902: else if (run) ! 903: { // running ! 904: if (duck) ! 905: { ! 906: ent->s.frame = FRAME_crwalk1; ! 907: client->anim_end = FRAME_crwalk6; ! 908: } ! 909: else ! 910: { ! 911: ent->s.frame = FRAME_run1; ! 912: client->anim_end = FRAME_run6; ! 913: } ! 914: } ! 915: else ! 916: { // standing ! 917: if (duck) ! 918: { ! 919: ent->s.frame = FRAME_crstnd01; ! 920: client->anim_end = FRAME_crstnd19; ! 921: } ! 922: else ! 923: { ! 924: ent->s.frame = FRAME_stand01; ! 925: client->anim_end = FRAME_stand40; ! 926: } ! 927: } ! 928: } ! 929: ! 930: ! 931: /* ! 932: ================= ! 933: ClientEndServerFrame ! 934: ! 935: Called for each player at the end of the server frame ! 936: and right after spawning ! 937: ================= ! 938: */ ! 939: void ClientEndServerFrame (edict_t *ent) ! 940: { ! 941: float bobtime; ! 942: int i; ! 943: ! 944: current_player = ent; ! 945: current_client = ent->client; ! 946: ! 947: // ! 948: // If the origin or velocity have changed since ClientThink(), ! 949: // update the pmove values. This will happen when the client ! 950: // is pushed by a bmodel or kicked by an explosion. ! 951: // ! 952: // If it wasn't updated here, the view position would lag a frame ! 953: // behind the body position when pushed -- "sinking into plats" ! 954: // ! 955: for (i=0 ; i<3 ; i++) ! 956: { ! 957: current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0; ! 958: current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0; ! 959: } ! 960: ! 961: // ! 962: // If the end of unit layout is displayed, don't give ! 963: // the player any normal movement attributes ! 964: // ! 965: if (level.intermissiontime) ! 966: { ! 967: // FIXME: add view drifting here? ! 968: current_client->ps.blend[3] = 0; ! 969: current_client->ps.fov = 90; ! 970: G_SetStats (ent); ! 971: return; ! 972: } ! 973: ! 974: AngleVectors (ent->client->v_angle, forward, right, up); ! 975: ! 976: // burn from lava, etc ! 977: P_WorldEffects (); ! 978: ! 979: // ! 980: // set model angles from view angles so other things in ! 981: // the world can tell which direction you are looking ! 982: // ! 983: if (ent->client->v_angle[PITCH] > 180) ! 984: ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3; ! 985: else ! 986: ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3; ! 987: ent->s.angles[YAW] = ent->client->v_angle[YAW]; ! 988: ent->s.angles[ROLL] = 0; ! 989: ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4; ! 990: ! 991: // ! 992: // calculate speed and cycle to be used for ! 993: // all cyclic walking effects ! 994: // ! 995: xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]); ! 996: ! 997: if (xyspeed < 5) ! 998: { ! 999: bobmove = 0; ! 1000: current_client->bobtime = 0; // start at beginning of cycle again ! 1001: } ! 1002: else if (ent->groundentity) ! 1003: { // so bobbing only cycles when on ground ! 1004: if (xyspeed > 210) ! 1005: bobmove = 0.25; ! 1006: else if (xyspeed > 100) ! 1007: bobmove = 0.125; ! 1008: else ! 1009: bobmove = 0.0625; ! 1010: } ! 1011: ! 1012: bobtime = (current_client->bobtime += bobmove); ! 1013: ! 1014: if (current_client->ps.pmove.pm_flags & PMF_DUCKED) ! 1015: bobtime *= 4; ! 1016: ! 1017: bobcycle = (int)bobtime; ! 1018: bobfracsin = fabs(sin(bobtime*M_PI)); ! 1019: ! 1020: // detect hitting the floor ! 1021: P_FallingDamage (ent); ! 1022: ! 1023: // apply all the damage taken this frame ! 1024: P_DamageFeedback (ent); ! 1025: ! 1026: // determine the view offsets ! 1027: SV_CalcViewOffset (ent); ! 1028: ! 1029: // determine the gun offsets ! 1030: SV_CalcGunOffset (ent); ! 1031: ! 1032: // determine the full screen color blend ! 1033: // must be after viewoffset, so eye contents can be ! 1034: // accurately determined ! 1035: // FIXME: with client prediction, the contents ! 1036: // should be determined by the client ! 1037: SV_CalcBlend (ent); ! 1038: ! 1039: G_SetStats (ent); ! 1040: ! 1041: G_SetClientEvent (ent); ! 1042: ! 1043: G_SetClientEffects (ent); ! 1044: ! 1045: G_SetClientSound (ent); ! 1046: ! 1047: G_SetClientFrame (ent); ! 1048: ! 1049: VectorCopy (ent->velocity, ent->client->oldvelocity); ! 1050: VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles); ! 1051: ! 1052: // clear weapon kicks ! 1053: VectorClear (ent->client->kick_origin); ! 1054: VectorClear (ent->client->kick_angles); ! 1055: ! 1056: // if the scoreboard is up, update it ! 1057: if (ent->client->showscores && !(level.framenum & 31) ) ! 1058: { ! 1059: DeathmatchScoreboardMessage (ent, ent->enemy); ! 1060: gi.unicast (ent, false); ! 1061: } ! 1062: } ! 1063:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.