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