|
|
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: // RAFAEL ! 433: else if (ent->client->quadfire_framenum > level.framenum) ! 434: { ! 435: remaining = ent->client->quadfire_framenum - level.framenum; ! 436: if (remaining == 30) // beginning to fade ! 437: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/quadfire2.wav"), 1, ATTN_NORM, 0); ! 438: if (remaining > 30 || (remaining & 4) ) ! 439: SV_AddBlend (1, 0.2, 0.5, 0.08, ent->client->ps.blend); ! 440: } ! 441: else if (ent->client->invincible_framenum > level.framenum) ! 442: { ! 443: remaining = ent->client->invincible_framenum - level.framenum; ! 444: if (remaining == 30) // beginning to fade ! 445: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0); ! 446: if (remaining > 30 || (remaining & 4) ) ! 447: SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend); ! 448: } ! 449: else if (ent->client->enviro_framenum > level.framenum) ! 450: { ! 451: remaining = ent->client->enviro_framenum - level.framenum; ! 452: if (remaining == 30) // beginning to fade ! 453: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 454: if (remaining > 30 || (remaining & 4) ) ! 455: SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend); ! 456: } ! 457: else if (ent->client->breather_framenum > level.framenum) ! 458: { ! 459: remaining = ent->client->breather_framenum - level.framenum; ! 460: if (remaining == 30) // beginning to fade ! 461: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); ! 462: if (remaining > 30 || (remaining & 4) ) ! 463: SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend); ! 464: } ! 465: ! 466: // add for damage ! 467: if (ent->client->damage_alpha > 0) ! 468: SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1] ! 469: ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend); ! 470: ! 471: if (ent->client->bonus_alpha > 0) ! 472: SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend); ! 473: ! 474: // drop the damage value ! 475: ent->client->damage_alpha -= 0.06; ! 476: if (ent->client->damage_alpha < 0) ! 477: ent->client->damage_alpha = 0; ! 478: ! 479: // drop the bonus value ! 480: ent->client->bonus_alpha -= 0.1; ! 481: if (ent->client->bonus_alpha < 0) ! 482: ent->client->bonus_alpha = 0; ! 483: } ! 484: ! 485: ! 486: /* ! 487: ================= ! 488: P_FallingDamage ! 489: ================= ! 490: */ ! 491: void P_FallingDamage (edict_t *ent) ! 492: { ! 493: float delta; ! 494: int damage; ! 495: vec3_t dir; ! 496: ! 497: if (ent->s.modelindex != 255) ! 498: return; // not in the player model ! 499: ! 500: if (ent->movetype == MOVETYPE_NOCLIP) ! 501: return; ! 502: ! 503: if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity)) ! 504: { ! 505: delta = ent->client->oldvelocity[2]; ! 506: } ! 507: else ! 508: { ! 509: if (!ent->groundentity) ! 510: return; ! 511: delta = ent->velocity[2] - ent->client->oldvelocity[2]; ! 512: } ! 513: delta = delta*delta * 0.0001; ! 514: ! 515: // never take falling damage if completely underwater ! 516: if (ent->waterlevel == 3) ! 517: return; ! 518: if (ent->waterlevel == 2) ! 519: delta *= 0.25; ! 520: if (ent->waterlevel == 1) ! 521: delta *= 0.5; ! 522: ! 523: if (delta < 1) ! 524: return; ! 525: ! 526: if (delta < 15) ! 527: { ! 528: ent->s.event = EV_FOOTSTEP; ! 529: return; ! 530: } ! 531: ! 532: ent->client->fall_value = delta*0.5; ! 533: if (ent->client->fall_value > 40) ! 534: ent->client->fall_value = 40; ! 535: ent->client->fall_time = level.time + FALL_TIME; ! 536: ! 537: if (delta > 30) ! 538: { ! 539: if (ent->health > 0) ! 540: { ! 541: if (delta >= 55) ! 542: ent->s.event = EV_FALLFAR; ! 543: else ! 544: ent->s.event = EV_FALL; ! 545: } ! 546: ent->pain_debounce_time = level.time; // no normal pain sound ! 547: damage = (delta-30)/2; ! 548: if (damage < 1) ! 549: damage = 1; ! 550: VectorSet (dir, 0, 0, 1); ! 551: ! 552: if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) ) ! 553: T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING); ! 554: } ! 555: else ! 556: { ! 557: ent->s.event = EV_FALLSHORT; ! 558: return; ! 559: } ! 560: } ! 561: ! 562: ! 563: ! 564: /* ! 565: ============= ! 566: P_WorldEffects ! 567: ============= ! 568: */ ! 569: void P_WorldEffects (void) ! 570: { ! 571: qboolean breather; ! 572: qboolean envirosuit; ! 573: int waterlevel, old_waterlevel; ! 574: ! 575: if (current_player->movetype == MOVETYPE_NOCLIP) ! 576: { ! 577: current_player->air_finished = level.time + 12; // don't need air ! 578: return; ! 579: } ! 580: ! 581: waterlevel = current_player->waterlevel; ! 582: old_waterlevel = current_client->old_waterlevel; ! 583: current_client->old_waterlevel = waterlevel; ! 584: ! 585: breather = current_client->breather_framenum > level.framenum; ! 586: envirosuit = current_client->enviro_framenum > level.framenum; ! 587: ! 588: // ! 589: // if just entered a water volume, play a sound ! 590: // ! 591: if (!old_waterlevel && waterlevel) ! 592: { ! 593: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 594: if (current_player->watertype & CONTENTS_LAVA) ! 595: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0); ! 596: else if (current_player->watertype & CONTENTS_SLIME) ! 597: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 598: else if (current_player->watertype & CONTENTS_WATER) ! 599: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0); ! 600: current_player->flags |= FL_INWATER; ! 601: ! 602: // clear damage_debounce, so the pain sound will play immediately ! 603: current_player->damage_debounce_time = level.time - 1; ! 604: } ! 605: ! 606: // ! 607: // if just completely exited a water volume, play a sound ! 608: // ! 609: if (old_waterlevel && ! waterlevel) ! 610: { ! 611: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 612: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0); ! 613: current_player->flags &= ~FL_INWATER; ! 614: } ! 615: ! 616: // ! 617: // check for head just going under water ! 618: // ! 619: if (old_waterlevel != 3 && waterlevel == 3) ! 620: { ! 621: gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0); ! 622: } ! 623: ! 624: // ! 625: // check for head just coming out of water ! 626: // ! 627: if (old_waterlevel == 3 && waterlevel != 3) ! 628: { ! 629: if (current_player->air_finished < level.time) ! 630: { // gasp for air ! 631: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0); ! 632: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 633: } ! 634: else if (current_player->air_finished < level.time + 11) ! 635: { // just break surface ! 636: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0); ! 637: } ! 638: } ! 639: ! 640: // ! 641: // check for drowning ! 642: // ! 643: if (waterlevel == 3) ! 644: { ! 645: // breather or envirosuit give air ! 646: if (breather || envirosuit) ! 647: { ! 648: current_player->air_finished = level.time + 10; ! 649: ! 650: if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0) ! 651: { ! 652: if (!current_client->breather_sound) ! 653: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0); ! 654: else ! 655: gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0); ! 656: current_client->breather_sound ^= 1; ! 657: PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF); ! 658: //FIXME: release a bubble? ! 659: } ! 660: } ! 661: ! 662: // if out of air, start drowning ! 663: if (current_player->air_finished < level.time) ! 664: { // drown! ! 665: if (current_player->client->next_drown_time < level.time ! 666: && current_player->health > 0) ! 667: { ! 668: current_player->client->next_drown_time = level.time + 1; ! 669: ! 670: // take more damage the longer underwater ! 671: current_player->dmg += 2; ! 672: if (current_player->dmg > 15) ! 673: current_player->dmg = 15; ! 674: ! 675: // play a gurp sound instead of a normal pain sound ! 676: if (current_player->health <= current_player->dmg) ! 677: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0); ! 678: else if (rand()&1) ! 679: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0); ! 680: else ! 681: gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0); ! 682: ! 683: current_player->pain_debounce_time = level.time; ! 684: ! 685: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER); ! 686: } ! 687: } ! 688: } ! 689: else ! 690: { ! 691: current_player->air_finished = level.time + 12; ! 692: current_player->dmg = 2; ! 693: } ! 694: ! 695: // ! 696: // check for sizzle damage ! 697: // ! 698: if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 699: { ! 700: if (current_player->watertype & CONTENTS_LAVA) ! 701: { ! 702: if (current_player->health > 0 ! 703: && current_player->pain_debounce_time <= level.time ! 704: && current_client->invincible_framenum < level.framenum) ! 705: { ! 706: if (rand()&1) ! 707: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0); ! 708: else ! 709: gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0); ! 710: current_player->pain_debounce_time = level.time + 1; ! 711: } ! 712: ! 713: if (envirosuit) // take 1/3 damage with envirosuit ! 714: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA); ! 715: else ! 716: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA); ! 717: } ! 718: ! 719: if (current_player->watertype & CONTENTS_SLIME) ! 720: { ! 721: if (!envirosuit) ! 722: { // no damage from slime with envirosuit ! 723: T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME); ! 724: } ! 725: } ! 726: } ! 727: } ! 728: ! 729: ! 730: /* ! 731: =============== ! 732: G_SetClientEffects ! 733: =============== ! 734: */ ! 735: void G_SetClientEffects (edict_t *ent) ! 736: { ! 737: int pa_type; ! 738: int remaining; ! 739: ! 740: ent->s.effects = 0; ! 741: ent->s.renderfx = 0; ! 742: ! 743: if (ent->health <= 0 || level.intermissiontime) ! 744: return; ! 745: ! 746: if (ent->powerarmor_time > level.time) ! 747: { ! 748: pa_type = PowerArmorType (ent); ! 749: if (pa_type == POWER_ARMOR_SCREEN) ! 750: { ! 751: ent->s.effects |= EF_POWERSCREEN; ! 752: } ! 753: else if (pa_type == POWER_ARMOR_SHIELD) ! 754: { ! 755: ent->s.effects |= EF_COLOR_SHELL; ! 756: ent->s.renderfx |= RF_SHELL_GREEN; ! 757: } ! 758: } ! 759: ! 760: if (ent->client->quad_framenum > level.framenum) ! 761: { ! 762: remaining = ent->client->quad_framenum - level.framenum; ! 763: if (remaining > 30 || (remaining & 4) ) ! 764: ent->s.effects |= EF_QUAD; ! 765: } ! 766: ! 767: // RAFAEL ! 768: if (ent->client->quadfire_framenum > level.framenum) ! 769: { ! 770: remaining = ent->client->quadfire_framenum - level.framenum; ! 771: if (remaining > 30 || (remaining & 4) ) ! 772: ent->s.effects |= EF_QUAD; ! 773: } ! 774: ! 775: ! 776: if (ent->client->invincible_framenum > level.framenum) ! 777: { ! 778: remaining = ent->client->invincible_framenum - level.framenum; ! 779: if (remaining > 30 || (remaining & 4) ) ! 780: ent->s.effects |= EF_PENT; ! 781: } ! 782: ! 783: // show cheaters!!! ! 784: if (ent->flags & FL_GODMODE) ! 785: { ! 786: ent->s.effects |= EF_COLOR_SHELL; ! 787: ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE); ! 788: } ! 789: } ! 790: ! 791: ! 792: /* ! 793: =============== ! 794: G_SetClientEvent ! 795: =============== ! 796: */ ! 797: void G_SetClientEvent (edict_t *ent) ! 798: { ! 799: if (ent->s.event) ! 800: return; ! 801: ! 802: if ( ent->groundentity && xyspeed > 225) ! 803: { ! 804: if ( (int)(current_client->bobtime+bobmove) != bobcycle ) ! 805: ent->s.event = EV_FOOTSTEP; ! 806: } ! 807: } ! 808: ! 809: /* ! 810: =============== ! 811: G_SetClientSound ! 812: =============== ! 813: */ ! 814: void G_SetClientSound (edict_t *ent) ! 815: { ! 816: char *weap; ! 817: ! 818: if (ent->client->pers.game_helpchanged != game.helpchanged) ! 819: { ! 820: ent->client->pers.game_helpchanged = game.helpchanged; ! 821: ent->client->pers.helpchanged = 1; ! 822: } ! 823: ! 824: // help beep (no more than three times) ! 825: if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) ) ! 826: { ! 827: ent->client->pers.helpchanged++; ! 828: gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0); ! 829: } ! 830: ! 831: ! 832: if (ent->client->pers.weapon) ! 833: weap = ent->client->pers.weapon->classname; ! 834: else ! 835: weap = ""; ! 836: ! 837: if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) ! 838: ent->s.sound = snd_fry; ! 839: else if (strcmp(weap, "weapon_railgun") == 0) ! 840: ent->s.sound = gi.soundindex("weapons/rg_hum.wav"); ! 841: else if (strcmp(weap, "weapon_bfg") == 0) ! 842: ent->s.sound = gi.soundindex("weapons/bfg_hum.wav"); ! 843: // RAFAEL ! 844: else if (strcmp (weap, "weapon_phalanx") == 0) ! 845: ent->s.sound = gi.soundindex ("weapons/phaloop.wav"); ! 846: else if (ent->client->weapon_sound) ! 847: ent->s.sound = ent->client->weapon_sound; ! 848: else ! 849: ent->s.sound = 0; ! 850: } ! 851: ! 852: /* ! 853: =============== ! 854: G_SetClientFrame ! 855: =============== ! 856: */ ! 857: void G_SetClientFrame (edict_t *ent) ! 858: { ! 859: gclient_t *client; ! 860: qboolean duck, run; ! 861: ! 862: if (ent->s.modelindex != 255) ! 863: return; // not in the player model ! 864: ! 865: client = ent->client; ! 866: ! 867: if (client->ps.pmove.pm_flags & PMF_DUCKED) ! 868: duck = true; ! 869: else ! 870: duck = false; ! 871: if (xyspeed) ! 872: run = true; ! 873: else ! 874: run = false; ! 875: ! 876: // check for stand/duck and stop/go transitions ! 877: if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH) ! 878: goto newanim; ! 879: if (run != client->anim_run && client->anim_priority == ANIM_BASIC) ! 880: goto newanim; ! 881: if (!ent->groundentity && client->anim_priority <= ANIM_WAVE) ! 882: goto newanim; ! 883: ! 884: if(client->anim_priority == ANIM_REVERSE) ! 885: { ! 886: if(ent->s.frame > client->anim_end) ! 887: { ! 888: ent->s.frame--; ! 889: return; ! 890: } ! 891: } ! 892: else if (ent->s.frame < client->anim_end) ! 893: { // continue an animation ! 894: ent->s.frame++; ! 895: return; ! 896: } ! 897: ! 898: if (client->anim_priority == ANIM_DEATH) ! 899: return; // stay there ! 900: if (client->anim_priority == ANIM_JUMP) ! 901: { ! 902: if (!ent->groundentity) ! 903: return; // stay there ! 904: ent->client->anim_priority = ANIM_WAVE; ! 905: ent->s.frame = FRAME_jump3; ! 906: ent->client->anim_end = FRAME_jump6; ! 907: return; ! 908: } ! 909: ! 910: newanim: ! 911: // return to either a running or standing frame ! 912: client->anim_priority = ANIM_BASIC; ! 913: client->anim_duck = duck; ! 914: client->anim_run = run; ! 915: ! 916: if (!ent->groundentity) ! 917: { ! 918: client->anim_priority = ANIM_JUMP; ! 919: if (ent->s.frame != FRAME_jump2) ! 920: ent->s.frame = FRAME_jump1; ! 921: client->anim_end = FRAME_jump2; ! 922: } ! 923: else if (run) ! 924: { // running ! 925: if (duck) ! 926: { ! 927: ent->s.frame = FRAME_crwalk1; ! 928: client->anim_end = FRAME_crwalk6; ! 929: } ! 930: else ! 931: { ! 932: ent->s.frame = FRAME_run1; ! 933: client->anim_end = FRAME_run6; ! 934: } ! 935: } ! 936: else ! 937: { // standing ! 938: if (duck) ! 939: { ! 940: ent->s.frame = FRAME_crstnd01; ! 941: client->anim_end = FRAME_crstnd19; ! 942: } ! 943: else ! 944: { ! 945: ent->s.frame = FRAME_stand01; ! 946: client->anim_end = FRAME_stand40; ! 947: } ! 948: } ! 949: } ! 950: ! 951: ! 952: /* ! 953: ================= ! 954: ClientEndServerFrame ! 955: ! 956: Called for each player at the end of the server frame ! 957: and right after spawning ! 958: ================= ! 959: */ ! 960: void ClientEndServerFrame (edict_t *ent) ! 961: { ! 962: float bobtime; ! 963: int i; ! 964: ! 965: current_player = ent; ! 966: current_client = ent->client; ! 967: ! 968: // ! 969: // If the origin or velocity have changed since ClientThink(), ! 970: // update the pmove values. This will happen when the client ! 971: // is pushed by a bmodel or kicked by an explosion. ! 972: // ! 973: // If it wasn't updated here, the view position would lag a frame ! 974: // behind the body position when pushed -- "sinking into plats" ! 975: // ! 976: for (i=0 ; i<3 ; i++) ! 977: { ! 978: current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0; ! 979: current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0; ! 980: } ! 981: ! 982: // ! 983: // If the end of unit layout is displayed, don't give ! 984: // the player any normal movement attributes ! 985: // ! 986: if (level.intermissiontime) ! 987: { ! 988: // FIXME: add view drifting here? ! 989: current_client->ps.blend[3] = 0; ! 990: current_client->ps.fov = 90; ! 991: G_SetStats (ent); ! 992: return; ! 993: } ! 994: ! 995: AngleVectors (ent->client->v_angle, forward, right, up); ! 996: ! 997: // burn from lava, etc ! 998: P_WorldEffects (); ! 999: ! 1000: // ! 1001: // set model angles from view angles so other things in ! 1002: // the world can tell which direction you are looking ! 1003: // ! 1004: if (ent->client->v_angle[PITCH] > 180) ! 1005: ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3; ! 1006: else ! 1007: ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3; ! 1008: ent->s.angles[YAW] = ent->client->v_angle[YAW]; ! 1009: ent->s.angles[ROLL] = 0; ! 1010: ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4; ! 1011: ! 1012: // ! 1013: // calculate speed and cycle to be used for ! 1014: // all cyclic walking effects ! 1015: // ! 1016: xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]); ! 1017: ! 1018: if (xyspeed < 5) ! 1019: { ! 1020: bobmove = 0; ! 1021: current_client->bobtime = 0; // start at beginning of cycle again ! 1022: } ! 1023: else if (ent->groundentity) ! 1024: { // so bobbing only cycles when on ground ! 1025: if (xyspeed > 210) ! 1026: bobmove = 0.25; ! 1027: else if (xyspeed > 100) ! 1028: bobmove = 0.125; ! 1029: else ! 1030: bobmove = 0.0625; ! 1031: } ! 1032: ! 1033: bobtime = (current_client->bobtime += bobmove); ! 1034: ! 1035: if (current_client->ps.pmove.pm_flags & PMF_DUCKED) ! 1036: bobtime *= 4; ! 1037: ! 1038: bobcycle = (int)bobtime; ! 1039: bobfracsin = fabs(sin(bobtime*M_PI)); ! 1040: ! 1041: // detect hitting the floor ! 1042: P_FallingDamage (ent); ! 1043: ! 1044: // apply all the damage taken this frame ! 1045: P_DamageFeedback (ent); ! 1046: ! 1047: // determine the view offsets ! 1048: SV_CalcViewOffset (ent); ! 1049: ! 1050: // determine the gun offsets ! 1051: SV_CalcGunOffset (ent); ! 1052: ! 1053: // determine the full screen color blend ! 1054: // must be after viewoffset, so eye contents can be ! 1055: // accurately determined ! 1056: // FIXME: with client prediction, the contents ! 1057: // should be determined by the client ! 1058: SV_CalcBlend (ent); ! 1059: ! 1060: // chase cam stuff ! 1061: if (ent->client->resp.spectator) ! 1062: G_SetSpectatorStats(ent); ! 1063: else ! 1064: G_SetStats (ent); ! 1065: G_CheckChaseStats(ent); ! 1066: ! 1067: G_SetClientEvent (ent); ! 1068: ! 1069: G_SetClientEffects (ent); ! 1070: ! 1071: G_SetClientSound (ent); ! 1072: ! 1073: G_SetClientFrame (ent); ! 1074: ! 1075: VectorCopy (ent->velocity, ent->client->oldvelocity); ! 1076: VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles); ! 1077: ! 1078: // clear weapon kicks ! 1079: VectorClear (ent->client->kick_origin); ! 1080: VectorClear (ent->client->kick_angles); ! 1081: ! 1082: // if the scoreboard is up, update it ! 1083: if (ent->client->showscores && !(level.framenum & 31) ) ! 1084: { ! 1085: DeathmatchScoreboardMessage (ent, ent->enemy); ! 1086: gi.unicast (ent, false); ! 1087: } ! 1088: } ! 1089:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.