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