cl_tent.c (40898B)
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 */ 20 // cl_tent.c -- client side temporary entities 21 22 #include "client.h" 23 24 typedef enum 25 { 26 ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2 27 } exptype_t; 28 29 typedef struct 30 { 31 exptype_t type; 32 entity_t ent; 33 34 int frames; 35 float light; 36 vec3_t lightcolor; 37 float start; 38 int baseframe; 39 } explosion_t; 40 41 42 43 #define MAX_EXPLOSIONS 32 44 explosion_t cl_explosions[MAX_EXPLOSIONS]; 45 46 47 #define MAX_BEAMS 32 48 typedef struct 49 { 50 int entity; 51 int dest_entity; 52 struct model_s *model; 53 int endtime; 54 vec3_t offset; 55 vec3_t start, end; 56 } beam_t; 57 beam_t cl_beams[MAX_BEAMS]; 58 //PMM - added this for player-linked beams. Currently only used by the plasma beam 59 beam_t cl_playerbeams[MAX_BEAMS]; 60 61 62 #define MAX_LASERS 32 63 typedef struct 64 { 65 entity_t ent; 66 int endtime; 67 } laser_t; 68 laser_t cl_lasers[MAX_LASERS]; 69 70 //ROGUE 71 cl_sustain_t cl_sustains[MAX_SUSTAINS]; 72 //ROGUE 73 74 //PGM 75 extern void CL_TeleportParticles (vec3_t org); 76 //PGM 77 78 void CL_BlasterParticles (vec3_t org, vec3_t dir); 79 void CL_ExplosionParticles (vec3_t org); 80 void CL_BFGExplosionParticles (vec3_t org); 81 // RAFAEL 82 void CL_BlueBlasterParticles (vec3_t org, vec3_t dir); 83 84 struct sfx_s *cl_sfx_ric1; 85 struct sfx_s *cl_sfx_ric2; 86 struct sfx_s *cl_sfx_ric3; 87 struct sfx_s *cl_sfx_lashit; 88 struct sfx_s *cl_sfx_spark5; 89 struct sfx_s *cl_sfx_spark6; 90 struct sfx_s *cl_sfx_spark7; 91 struct sfx_s *cl_sfx_railg; 92 struct sfx_s *cl_sfx_rockexp; 93 struct sfx_s *cl_sfx_grenexp; 94 struct sfx_s *cl_sfx_watrexp; 95 // RAFAEL 96 struct sfx_s *cl_sfx_plasexp; 97 struct sfx_s *cl_sfx_footsteps[4]; 98 99 struct model_s *cl_mod_explode; 100 struct model_s *cl_mod_smoke; 101 struct model_s *cl_mod_flash; 102 struct model_s *cl_mod_parasite_segment; 103 struct model_s *cl_mod_grapple_cable; 104 struct model_s *cl_mod_parasite_tip; 105 struct model_s *cl_mod_explo4; 106 struct model_s *cl_mod_bfg_explo; 107 struct model_s *cl_mod_powerscreen; 108 // RAFAEL 109 struct model_s *cl_mod_plasmaexplo; 110 111 //ROGUE 112 struct sfx_s *cl_sfx_lightning; 113 struct sfx_s *cl_sfx_disrexp; 114 struct model_s *cl_mod_lightning; 115 struct model_s *cl_mod_heatbeam; 116 struct model_s *cl_mod_monster_heatbeam; 117 struct model_s *cl_mod_explo4_big; 118 119 //ROGUE 120 /* 121 ================= 122 CL_RegisterTEntSounds 123 ================= 124 */ 125 void CL_RegisterTEntSounds (void) 126 { 127 int i; 128 char name[MAX_QPATH]; 129 130 // PMM - version stuff 131 // Com_Printf ("%s\n", ROGUE_VERSION_STRING); 132 // PMM 133 cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav"); 134 cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav"); 135 cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav"); 136 cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav"); 137 cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav"); 138 cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav"); 139 cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav"); 140 cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav"); 141 cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav"); 142 cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav"); 143 cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav"); 144 // RAFAEL 145 // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav"); 146 S_RegisterSound ("player/land1.wav"); 147 148 S_RegisterSound ("player/fall2.wav"); 149 S_RegisterSound ("player/fall1.wav"); 150 151 for (i=0 ; i<4 ; i++) 152 { 153 Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1); 154 cl_sfx_footsteps[i] = S_RegisterSound (name); 155 } 156 157 //PGM 158 cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav"); 159 cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav"); 160 // version stuff 161 sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID); 162 if (name[0] == 'w') 163 name[0] = 'W'; 164 //PGM 165 } 166 167 /* 168 ================= 169 CL_RegisterTEntModels 170 ================= 171 */ 172 void CL_RegisterTEntModels (void) 173 { 174 cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2"); 175 cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2"); 176 cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2"); 177 cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2"); 178 cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2"); 179 cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2"); 180 cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2"); 181 cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2"); 182 cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2"); 183 184 re.RegisterModel ("models/objects/laser/tris.md2"); 185 re.RegisterModel ("models/objects/grenade2/tris.md2"); 186 re.RegisterModel ("models/weapons/v_machn/tris.md2"); 187 re.RegisterModel ("models/weapons/v_handgr/tris.md2"); 188 re.RegisterModel ("models/weapons/v_shotg2/tris.md2"); 189 re.RegisterModel ("models/objects/gibs/bone/tris.md2"); 190 re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2"); 191 re.RegisterModel ("models/objects/gibs/bone2/tris.md2"); 192 // RAFAEL 193 // re.RegisterModel ("models/objects/blaser/tris.md2"); 194 195 re.RegisterPic ("w_machinegun"); 196 re.RegisterPic ("a_bullets"); 197 re.RegisterPic ("i_health"); 198 re.RegisterPic ("a_grenades"); 199 200 //ROGUE 201 cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2"); 202 cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2"); 203 cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2"); 204 cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2"); 205 //ROGUE 206 } 207 208 /* 209 ================= 210 CL_ClearTEnts 211 ================= 212 */ 213 void CL_ClearTEnts (void) 214 { 215 memset (cl_beams, 0, sizeof(cl_beams)); 216 memset (cl_explosions, 0, sizeof(cl_explosions)); 217 memset (cl_lasers, 0, sizeof(cl_lasers)); 218 219 //ROGUE 220 memset (cl_playerbeams, 0, sizeof(cl_playerbeams)); 221 memset (cl_sustains, 0, sizeof(cl_sustains)); 222 //ROGUE 223 } 224 225 /* 226 ================= 227 CL_AllocExplosion 228 ================= 229 */ 230 explosion_t *CL_AllocExplosion (void) 231 { 232 int i; 233 int time; 234 int index; 235 236 for (i=0 ; i<MAX_EXPLOSIONS ; i++) 237 { 238 if (cl_explosions[i].type == ex_free) 239 { 240 memset (&cl_explosions[i], 0, sizeof (cl_explosions[i])); 241 return &cl_explosions[i]; 242 } 243 } 244 // find the oldest explosion 245 time = cl.time; 246 index = 0; 247 248 for (i=0 ; i<MAX_EXPLOSIONS ; i++) 249 if (cl_explosions[i].start < time) 250 { 251 time = cl_explosions[i].start; 252 index = i; 253 } 254 memset (&cl_explosions[index], 0, sizeof (cl_explosions[index])); 255 return &cl_explosions[index]; 256 } 257 258 /* 259 ================= 260 CL_SmokeAndFlash 261 ================= 262 */ 263 void CL_SmokeAndFlash(vec3_t origin) 264 { 265 explosion_t *ex; 266 267 ex = CL_AllocExplosion (); 268 VectorCopy (origin, ex->ent.origin); 269 ex->type = ex_misc; 270 ex->frames = 4; 271 ex->ent.flags = RF_TRANSLUCENT; 272 ex->start = cl.frame.servertime - 100; 273 ex->ent.model = cl_mod_smoke; 274 275 ex = CL_AllocExplosion (); 276 VectorCopy (origin, ex->ent.origin); 277 ex->type = ex_flash; 278 ex->ent.flags = RF_FULLBRIGHT; 279 ex->frames = 2; 280 ex->start = cl.frame.servertime - 100; 281 ex->ent.model = cl_mod_flash; 282 } 283 284 /* 285 ================= 286 CL_ParseParticles 287 ================= 288 */ 289 void CL_ParseParticles (void) 290 { 291 int color, count; 292 vec3_t pos, dir; 293 294 MSG_ReadPos (&net_message, pos); 295 MSG_ReadDir (&net_message, dir); 296 297 color = MSG_ReadByte (&net_message); 298 299 count = MSG_ReadByte (&net_message); 300 301 CL_ParticleEffect (pos, dir, color, count); 302 } 303 304 /* 305 ================= 306 CL_ParseBeam 307 ================= 308 */ 309 int CL_ParseBeam (struct model_s *model) 310 { 311 int ent; 312 vec3_t start, end; 313 beam_t *b; 314 int i; 315 316 ent = MSG_ReadShort (&net_message); 317 318 MSG_ReadPos (&net_message, start); 319 MSG_ReadPos (&net_message, end); 320 321 // override any beam with the same entity 322 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 323 if (b->entity == ent) 324 { 325 b->entity = ent; 326 b->model = model; 327 b->endtime = cl.time + 200; 328 VectorCopy (start, b->start); 329 VectorCopy (end, b->end); 330 VectorClear (b->offset); 331 return ent; 332 } 333 334 // find a free beam 335 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 336 { 337 if (!b->model || b->endtime < cl.time) 338 { 339 b->entity = ent; 340 b->model = model; 341 b->endtime = cl.time + 200; 342 VectorCopy (start, b->start); 343 VectorCopy (end, b->end); 344 VectorClear (b->offset); 345 return ent; 346 } 347 } 348 Com_Printf ("beam list overflow!\n"); 349 return ent; 350 } 351 352 /* 353 ================= 354 CL_ParseBeam2 355 ================= 356 */ 357 int CL_ParseBeam2 (struct model_s *model) 358 { 359 int ent; 360 vec3_t start, end, offset; 361 beam_t *b; 362 int i; 363 364 ent = MSG_ReadShort (&net_message); 365 366 MSG_ReadPos (&net_message, start); 367 MSG_ReadPos (&net_message, end); 368 MSG_ReadPos (&net_message, offset); 369 370 // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); 371 372 // override any beam with the same entity 373 374 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 375 if (b->entity == ent) 376 { 377 b->entity = ent; 378 b->model = model; 379 b->endtime = cl.time + 200; 380 VectorCopy (start, b->start); 381 VectorCopy (end, b->end); 382 VectorCopy (offset, b->offset); 383 return ent; 384 } 385 386 // find a free beam 387 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 388 { 389 if (!b->model || b->endtime < cl.time) 390 { 391 b->entity = ent; 392 b->model = model; 393 b->endtime = cl.time + 200; 394 VectorCopy (start, b->start); 395 VectorCopy (end, b->end); 396 VectorCopy (offset, b->offset); 397 return ent; 398 } 399 } 400 Com_Printf ("beam list overflow!\n"); 401 return ent; 402 } 403 404 // ROGUE 405 /* 406 ================= 407 CL_ParsePlayerBeam 408 - adds to the cl_playerbeam array instead of the cl_beams array 409 ================= 410 */ 411 int CL_ParsePlayerBeam (struct model_s *model) 412 { 413 int ent; 414 vec3_t start, end, offset; 415 beam_t *b; 416 int i; 417 418 ent = MSG_ReadShort (&net_message); 419 420 MSG_ReadPos (&net_message, start); 421 MSG_ReadPos (&net_message, end); 422 // PMM - network optimization 423 if (model == cl_mod_heatbeam) 424 VectorSet(offset, 2, 7, -3); 425 else if (model == cl_mod_monster_heatbeam) 426 { 427 model = cl_mod_heatbeam; 428 VectorSet(offset, 0, 0, 0); 429 } 430 else 431 MSG_ReadPos (&net_message, offset); 432 433 // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); 434 435 // override any beam with the same entity 436 // PMM - For player beams, we only want one per player (entity) so.. 437 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) 438 { 439 if (b->entity == ent) 440 { 441 b->entity = ent; 442 b->model = model; 443 b->endtime = cl.time + 200; 444 VectorCopy (start, b->start); 445 VectorCopy (end, b->end); 446 VectorCopy (offset, b->offset); 447 return ent; 448 } 449 } 450 451 // find a free beam 452 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) 453 { 454 if (!b->model || b->endtime < cl.time) 455 { 456 b->entity = ent; 457 b->model = model; 458 b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams 459 VectorCopy (start, b->start); 460 VectorCopy (end, b->end); 461 VectorCopy (offset, b->offset); 462 return ent; 463 } 464 } 465 Com_Printf ("beam list overflow!\n"); 466 return ent; 467 } 468 //rogue 469 470 /* 471 ================= 472 CL_ParseLightning 473 ================= 474 */ 475 int CL_ParseLightning (struct model_s *model) 476 { 477 int srcEnt, destEnt; 478 vec3_t start, end; 479 beam_t *b; 480 int i; 481 482 srcEnt = MSG_ReadShort (&net_message); 483 destEnt = MSG_ReadShort (&net_message); 484 485 MSG_ReadPos (&net_message, start); 486 MSG_ReadPos (&net_message, end); 487 488 // override any beam with the same source AND destination entities 489 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 490 if (b->entity == srcEnt && b->dest_entity == destEnt) 491 { 492 // Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt); 493 b->entity = srcEnt; 494 b->dest_entity = destEnt; 495 b->model = model; 496 b->endtime = cl.time + 200; 497 VectorCopy (start, b->start); 498 VectorCopy (end, b->end); 499 VectorClear (b->offset); 500 return srcEnt; 501 } 502 503 // find a free beam 504 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 505 { 506 if (!b->model || b->endtime < cl.time) 507 { 508 // Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt); 509 b->entity = srcEnt; 510 b->dest_entity = destEnt; 511 b->model = model; 512 b->endtime = cl.time + 200; 513 VectorCopy (start, b->start); 514 VectorCopy (end, b->end); 515 VectorClear (b->offset); 516 return srcEnt; 517 } 518 } 519 Com_Printf ("beam list overflow!\n"); 520 return srcEnt; 521 } 522 523 /* 524 ================= 525 CL_ParseLaser 526 ================= 527 */ 528 void CL_ParseLaser (int colors) 529 { 530 vec3_t start; 531 vec3_t end; 532 laser_t *l; 533 int i; 534 535 MSG_ReadPos (&net_message, start); 536 MSG_ReadPos (&net_message, end); 537 538 for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++) 539 { 540 if (l->endtime < cl.time) 541 { 542 l->ent.flags = RF_TRANSLUCENT | RF_BEAM; 543 VectorCopy (start, l->ent.origin); 544 VectorCopy (end, l->ent.oldorigin); 545 l->ent.alpha = 0.30; 546 l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff; 547 l->ent.model = NULL; 548 l->ent.frame = 4; 549 l->endtime = cl.time + 100; 550 return; 551 } 552 } 553 } 554 555 //============= 556 //ROGUE 557 void CL_ParseSteam (void) 558 { 559 vec3_t pos, dir; 560 int id, i; 561 int r; 562 int cnt; 563 int color; 564 int magnitude; 565 cl_sustain_t *s, *free_sustain; 566 567 id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect 568 if (id != -1) // sustains 569 { 570 // Com_Printf ("Sustain effect id %d\n", id); 571 free_sustain = NULL; 572 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) 573 { 574 if (s->id == 0) 575 { 576 free_sustain = s; 577 break; 578 } 579 } 580 if (free_sustain) 581 { 582 s->id = id; 583 s->count = MSG_ReadByte (&net_message); 584 MSG_ReadPos (&net_message, s->org); 585 MSG_ReadDir (&net_message, s->dir); 586 r = MSG_ReadByte (&net_message); 587 s->color = r & 0xff; 588 s->magnitude = MSG_ReadShort (&net_message); 589 s->endtime = cl.time + MSG_ReadLong (&net_message); 590 s->think = CL_ParticleSteamEffect2; 591 s->thinkinterval = 100; 592 s->nextthink = cl.time; 593 } 594 else 595 { 596 // Com_Printf ("No free sustains!\n"); 597 // FIXME - read the stuff anyway 598 cnt = MSG_ReadByte (&net_message); 599 MSG_ReadPos (&net_message, pos); 600 MSG_ReadDir (&net_message, dir); 601 r = MSG_ReadByte (&net_message); 602 magnitude = MSG_ReadShort (&net_message); 603 magnitude = MSG_ReadLong (&net_message); // really interval 604 } 605 } 606 else // instant 607 { 608 cnt = MSG_ReadByte (&net_message); 609 MSG_ReadPos (&net_message, pos); 610 MSG_ReadDir (&net_message, dir); 611 r = MSG_ReadByte (&net_message); 612 magnitude = MSG_ReadShort (&net_message); 613 color = r & 0xff; 614 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude); 615 // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 616 } 617 } 618 619 void CL_ParseWidow (void) 620 { 621 vec3_t pos; 622 int id, i; 623 cl_sustain_t *s, *free_sustain; 624 625 id = MSG_ReadShort (&net_message); 626 627 free_sustain = NULL; 628 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) 629 { 630 if (s->id == 0) 631 { 632 free_sustain = s; 633 break; 634 } 635 } 636 if (free_sustain) 637 { 638 s->id = id; 639 MSG_ReadPos (&net_message, s->org); 640 s->endtime = cl.time + 2100; 641 s->think = CL_Widowbeamout; 642 s->thinkinterval = 1; 643 s->nextthink = cl.time; 644 } 645 else // no free sustains 646 { 647 // FIXME - read the stuff anyway 648 MSG_ReadPos (&net_message, pos); 649 } 650 } 651 652 void CL_ParseNuke (void) 653 { 654 vec3_t pos; 655 int i; 656 cl_sustain_t *s, *free_sustain; 657 658 free_sustain = NULL; 659 for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++) 660 { 661 if (s->id == 0) 662 { 663 free_sustain = s; 664 break; 665 } 666 } 667 if (free_sustain) 668 { 669 s->id = 21000; 670 MSG_ReadPos (&net_message, s->org); 671 s->endtime = cl.time + 1000; 672 s->think = CL_Nukeblast; 673 s->thinkinterval = 1; 674 s->nextthink = cl.time; 675 } 676 else // no free sustains 677 { 678 // FIXME - read the stuff anyway 679 MSG_ReadPos (&net_message, pos); 680 } 681 } 682 683 //ROGUE 684 //============= 685 686 687 /* 688 ================= 689 CL_ParseTEnt 690 ================= 691 */ 692 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8}; 693 694 void CL_ParseTEnt (void) 695 { 696 int type; 697 vec3_t pos, pos2, dir; 698 explosion_t *ex; 699 int cnt; 700 int color; 701 int r; 702 int ent; 703 int magnitude; 704 705 type = MSG_ReadByte (&net_message); 706 707 switch (type) 708 { 709 case TE_BLOOD: // bullet hitting flesh 710 MSG_ReadPos (&net_message, pos); 711 MSG_ReadDir (&net_message, dir); 712 CL_ParticleEffect (pos, dir, 0xe8, 60); 713 break; 714 715 case TE_GUNSHOT: // bullet hitting wall 716 case TE_SPARKS: 717 case TE_BULLET_SPARKS: 718 MSG_ReadPos (&net_message, pos); 719 MSG_ReadDir (&net_message, dir); 720 if (type == TE_GUNSHOT) 721 CL_ParticleEffect (pos, dir, 0, 40); 722 else 723 CL_ParticleEffect (pos, dir, 0xe0, 6); 724 725 if (type != TE_SPARKS) 726 { 727 CL_SmokeAndFlash(pos); 728 729 // impact sound 730 cnt = rand()&15; 731 if (cnt == 1) 732 S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0); 733 else if (cnt == 2) 734 S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0); 735 else if (cnt == 3) 736 S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0); 737 } 738 739 break; 740 741 case TE_SCREEN_SPARKS: 742 case TE_SHIELD_SPARKS: 743 MSG_ReadPos (&net_message, pos); 744 MSG_ReadDir (&net_message, dir); 745 if (type == TE_SCREEN_SPARKS) 746 CL_ParticleEffect (pos, dir, 0xd0, 40); 747 else 748 CL_ParticleEffect (pos, dir, 0xb0, 40); 749 //FIXME : replace or remove this sound 750 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 751 break; 752 753 case TE_SHOTGUN: // bullet hitting wall 754 MSG_ReadPos (&net_message, pos); 755 MSG_ReadDir (&net_message, dir); 756 CL_ParticleEffect (pos, dir, 0, 20); 757 CL_SmokeAndFlash(pos); 758 break; 759 760 case TE_SPLASH: // bullet hitting water 761 cnt = MSG_ReadByte (&net_message); 762 MSG_ReadPos (&net_message, pos); 763 MSG_ReadDir (&net_message, dir); 764 r = MSG_ReadByte (&net_message); 765 if (r > 6) 766 color = 0x00; 767 else 768 color = splash_color[r]; 769 CL_ParticleEffect (pos, dir, color, cnt); 770 771 if (r == SPLASH_SPARKS) 772 { 773 r = rand() & 3; 774 if (r == 0) 775 S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0); 776 else if (r == 1) 777 S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0); 778 else 779 S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0); 780 } 781 break; 782 783 case TE_LASER_SPARKS: 784 cnt = MSG_ReadByte (&net_message); 785 MSG_ReadPos (&net_message, pos); 786 MSG_ReadDir (&net_message, dir); 787 color = MSG_ReadByte (&net_message); 788 CL_ParticleEffect2 (pos, dir, color, cnt); 789 break; 790 791 // RAFAEL 792 case TE_BLUEHYPERBLASTER: 793 MSG_ReadPos (&net_message, pos); 794 MSG_ReadPos (&net_message, dir); 795 CL_BlasterParticles (pos, dir); 796 break; 797 798 case TE_BLASTER: // blaster hitting wall 799 MSG_ReadPos (&net_message, pos); 800 MSG_ReadDir (&net_message, dir); 801 CL_BlasterParticles (pos, dir); 802 803 ex = CL_AllocExplosion (); 804 VectorCopy (pos, ex->ent.origin); 805 ex->ent.angles[0] = acos(dir[2])/M_PI*180; 806 // PMM - fixed to correct for pitch of 0 807 if (dir[0]) 808 ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180; 809 else if (dir[1] > 0) 810 ex->ent.angles[1] = 90; 811 else if (dir[1] < 0) 812 ex->ent.angles[1] = 270; 813 else 814 ex->ent.angles[1] = 0; 815 816 ex->type = ex_misc; 817 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; 818 ex->start = cl.frame.servertime - 100; 819 ex->light = 150; 820 ex->lightcolor[0] = 1; 821 ex->lightcolor[1] = 1; 822 ex->ent.model = cl_mod_explode; 823 ex->frames = 4; 824 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 825 break; 826 827 case TE_RAILTRAIL: // railgun effect 828 MSG_ReadPos (&net_message, pos); 829 MSG_ReadPos (&net_message, pos2); 830 CL_RailTrail (pos, pos2); 831 S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0); 832 break; 833 834 case TE_EXPLOSION2: 835 case TE_GRENADE_EXPLOSION: 836 case TE_GRENADE_EXPLOSION_WATER: 837 MSG_ReadPos (&net_message, pos); 838 839 ex = CL_AllocExplosion (); 840 VectorCopy (pos, ex->ent.origin); 841 ex->type = ex_poly; 842 ex->ent.flags = RF_FULLBRIGHT; 843 ex->start = cl.frame.servertime - 100; 844 ex->light = 350; 845 ex->lightcolor[0] = 1.0; 846 ex->lightcolor[1] = 0.5; 847 ex->lightcolor[2] = 0.5; 848 ex->ent.model = cl_mod_explo4; 849 ex->frames = 19; 850 ex->baseframe = 30; 851 ex->ent.angles[1] = rand() % 360; 852 CL_ExplosionParticles (pos); 853 if (type == TE_GRENADE_EXPLOSION_WATER) 854 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); 855 else 856 S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0); 857 break; 858 859 // RAFAEL 860 case TE_PLASMA_EXPLOSION: 861 MSG_ReadPos (&net_message, pos); 862 ex = CL_AllocExplosion (); 863 VectorCopy (pos, ex->ent.origin); 864 ex->type = ex_poly; 865 ex->ent.flags = RF_FULLBRIGHT; 866 ex->start = cl.frame.servertime - 100; 867 ex->light = 350; 868 ex->lightcolor[0] = 1.0; 869 ex->lightcolor[1] = 0.5; 870 ex->lightcolor[2] = 0.5; 871 ex->ent.angles[1] = rand() % 360; 872 ex->ent.model = cl_mod_explo4; 873 if (frand() < 0.5) 874 ex->baseframe = 15; 875 ex->frames = 15; 876 CL_ExplosionParticles (pos); 877 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); 878 break; 879 880 case TE_EXPLOSION1: 881 case TE_EXPLOSION1_BIG: // PMM 882 case TE_ROCKET_EXPLOSION: 883 case TE_ROCKET_EXPLOSION_WATER: 884 case TE_EXPLOSION1_NP: // PMM 885 MSG_ReadPos (&net_message, pos); 886 887 ex = CL_AllocExplosion (); 888 VectorCopy (pos, ex->ent.origin); 889 ex->type = ex_poly; 890 ex->ent.flags = RF_FULLBRIGHT; 891 ex->start = cl.frame.servertime - 100; 892 ex->light = 350; 893 ex->lightcolor[0] = 1.0; 894 ex->lightcolor[1] = 0.5; 895 ex->lightcolor[2] = 0.5; 896 ex->ent.angles[1] = rand() % 360; 897 if (type != TE_EXPLOSION1_BIG) // PMM 898 ex->ent.model = cl_mod_explo4; // PMM 899 else 900 ex->ent.model = cl_mod_explo4_big; 901 if (frand() < 0.5) 902 ex->baseframe = 15; 903 ex->frames = 15; 904 if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM 905 CL_ExplosionParticles (pos); // PMM 906 if (type == TE_ROCKET_EXPLOSION_WATER) 907 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); 908 else 909 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); 910 break; 911 912 case TE_BFG_EXPLOSION: 913 MSG_ReadPos (&net_message, pos); 914 ex = CL_AllocExplosion (); 915 VectorCopy (pos, ex->ent.origin); 916 ex->type = ex_poly; 917 ex->ent.flags = RF_FULLBRIGHT; 918 ex->start = cl.frame.servertime - 100; 919 ex->light = 350; 920 ex->lightcolor[0] = 0.0; 921 ex->lightcolor[1] = 1.0; 922 ex->lightcolor[2] = 0.0; 923 ex->ent.model = cl_mod_bfg_explo; 924 ex->ent.flags |= RF_TRANSLUCENT; 925 ex->ent.alpha = 0.30; 926 ex->frames = 4; 927 break; 928 929 case TE_BFG_BIGEXPLOSION: 930 MSG_ReadPos (&net_message, pos); 931 CL_BFGExplosionParticles (pos); 932 break; 933 934 case TE_BFG_LASER: 935 CL_ParseLaser (0xd0d1d2d3); 936 break; 937 938 case TE_BUBBLETRAIL: 939 MSG_ReadPos (&net_message, pos); 940 MSG_ReadPos (&net_message, pos2); 941 CL_BubbleTrail (pos, pos2); 942 break; 943 944 case TE_PARASITE_ATTACK: 945 case TE_MEDIC_CABLE_ATTACK: 946 ent = CL_ParseBeam (cl_mod_parasite_segment); 947 break; 948 949 case TE_BOSSTPORT: // boss teleporting to station 950 MSG_ReadPos (&net_message, pos); 951 CL_BigTeleportParticles (pos); 952 S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0); 953 break; 954 955 case TE_GRAPPLE_CABLE: 956 ent = CL_ParseBeam2 (cl_mod_grapple_cable); 957 break; 958 959 // RAFAEL 960 case TE_WELDING_SPARKS: 961 cnt = MSG_ReadByte (&net_message); 962 MSG_ReadPos (&net_message, pos); 963 MSG_ReadDir (&net_message, dir); 964 color = MSG_ReadByte (&net_message); 965 CL_ParticleEffect2 (pos, dir, color, cnt); 966 967 ex = CL_AllocExplosion (); 968 VectorCopy (pos, ex->ent.origin); 969 ex->type = ex_flash; 970 // note to self 971 // we need a better no draw flag 972 ex->ent.flags = RF_BEAM; 973 ex->start = cl.frame.servertime - 0.1; 974 ex->light = 100 + (rand()%75); 975 ex->lightcolor[0] = 1.0; 976 ex->lightcolor[1] = 1.0; 977 ex->lightcolor[2] = 0.3; 978 ex->ent.model = cl_mod_flash; 979 ex->frames = 2; 980 break; 981 982 case TE_GREENBLOOD: 983 MSG_ReadPos (&net_message, pos); 984 MSG_ReadDir (&net_message, dir); 985 CL_ParticleEffect2 (pos, dir, 0xdf, 30); 986 break; 987 988 // RAFAEL 989 case TE_TUNNEL_SPARKS: 990 cnt = MSG_ReadByte (&net_message); 991 MSG_ReadPos (&net_message, pos); 992 MSG_ReadDir (&net_message, dir); 993 color = MSG_ReadByte (&net_message); 994 CL_ParticleEffect3 (pos, dir, color, cnt); 995 break; 996 997 //============= 998 //PGM 999 // PMM -following code integrated for flechette (different color) 1000 case TE_BLASTER2: // green blaster hitting wall 1001 case TE_FLECHETTE: // flechette 1002 MSG_ReadPos (&net_message, pos); 1003 MSG_ReadDir (&net_message, dir); 1004 1005 // PMM 1006 if (type == TE_BLASTER2) 1007 CL_BlasterParticles2 (pos, dir, 0xd0); 1008 else 1009 CL_BlasterParticles2 (pos, dir, 0x6f); // 75 1010 1011 ex = CL_AllocExplosion (); 1012 VectorCopy (pos, ex->ent.origin); 1013 ex->ent.angles[0] = acos(dir[2])/M_PI*180; 1014 // PMM - fixed to correct for pitch of 0 1015 if (dir[0]) 1016 ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180; 1017 else if (dir[1] > 0) 1018 ex->ent.angles[1] = 90; 1019 else if (dir[1] < 0) 1020 ex->ent.angles[1] = 270; 1021 else 1022 ex->ent.angles[1] = 0; 1023 1024 ex->type = ex_misc; 1025 ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; 1026 1027 // PMM 1028 if (type == TE_BLASTER2) 1029 ex->ent.skinnum = 1; 1030 else // flechette 1031 ex->ent.skinnum = 2; 1032 1033 ex->start = cl.frame.servertime - 100; 1034 ex->light = 150; 1035 // PMM 1036 if (type == TE_BLASTER2) 1037 ex->lightcolor[1] = 1; 1038 else // flechette 1039 { 1040 ex->lightcolor[0] = 0.19; 1041 ex->lightcolor[1] = 0.41; 1042 ex->lightcolor[2] = 0.75; 1043 } 1044 ex->ent.model = cl_mod_explode; 1045 ex->frames = 4; 1046 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 1047 break; 1048 1049 1050 case TE_LIGHTNING: 1051 ent = CL_ParseLightning (cl_mod_lightning); 1052 S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); 1053 break; 1054 1055 case TE_DEBUGTRAIL: 1056 MSG_ReadPos (&net_message, pos); 1057 MSG_ReadPos (&net_message, pos2); 1058 CL_DebugTrail (pos, pos2); 1059 break; 1060 1061 case TE_PLAIN_EXPLOSION: 1062 MSG_ReadPos (&net_message, pos); 1063 1064 ex = CL_AllocExplosion (); 1065 VectorCopy (pos, ex->ent.origin); 1066 ex->type = ex_poly; 1067 ex->ent.flags = RF_FULLBRIGHT; 1068 ex->start = cl.frame.servertime - 100; 1069 ex->light = 350; 1070 ex->lightcolor[0] = 1.0; 1071 ex->lightcolor[1] = 0.5; 1072 ex->lightcolor[2] = 0.5; 1073 ex->ent.angles[1] = rand() % 360; 1074 ex->ent.model = cl_mod_explo4; 1075 if (frand() < 0.5) 1076 ex->baseframe = 15; 1077 ex->frames = 15; 1078 if (type == TE_ROCKET_EXPLOSION_WATER) 1079 S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); 1080 else 1081 S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); 1082 break; 1083 1084 case TE_FLASHLIGHT: 1085 MSG_ReadPos(&net_message, pos); 1086 ent = MSG_ReadShort(&net_message); 1087 CL_Flashlight(ent, pos); 1088 break; 1089 1090 case TE_FORCEWALL: 1091 MSG_ReadPos(&net_message, pos); 1092 MSG_ReadPos(&net_message, pos2); 1093 color = MSG_ReadByte (&net_message); 1094 CL_ForceWall(pos, pos2, color); 1095 break; 1096 1097 case TE_HEATBEAM: 1098 ent = CL_ParsePlayerBeam (cl_mod_heatbeam); 1099 break; 1100 1101 case TE_MONSTER_HEATBEAM: 1102 ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam); 1103 break; 1104 1105 case TE_HEATBEAM_SPARKS: 1106 // cnt = MSG_ReadByte (&net_message); 1107 cnt = 50; 1108 MSG_ReadPos (&net_message, pos); 1109 MSG_ReadDir (&net_message, dir); 1110 // r = MSG_ReadByte (&net_message); 1111 // magnitude = MSG_ReadShort (&net_message); 1112 r = 8; 1113 magnitude = 60; 1114 color = r & 0xff; 1115 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude); 1116 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 1117 break; 1118 1119 case TE_HEATBEAM_STEAM: 1120 // cnt = MSG_ReadByte (&net_message); 1121 cnt = 20; 1122 MSG_ReadPos (&net_message, pos); 1123 MSG_ReadDir (&net_message, dir); 1124 // r = MSG_ReadByte (&net_message); 1125 // magnitude = MSG_ReadShort (&net_message); 1126 // color = r & 0xff; 1127 color = 0xe0; 1128 magnitude = 60; 1129 CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude); 1130 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 1131 break; 1132 1133 case TE_STEAM: 1134 CL_ParseSteam(); 1135 break; 1136 1137 case TE_BUBBLETRAIL2: 1138 // cnt = MSG_ReadByte (&net_message); 1139 cnt = 8; 1140 MSG_ReadPos (&net_message, pos); 1141 MSG_ReadPos (&net_message, pos2); 1142 CL_BubbleTrail2 (pos, pos2, cnt); 1143 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 1144 break; 1145 1146 case TE_MOREBLOOD: 1147 MSG_ReadPos (&net_message, pos); 1148 MSG_ReadDir (&net_message, dir); 1149 CL_ParticleEffect (pos, dir, 0xe8, 250); 1150 break; 1151 1152 case TE_CHAINFIST_SMOKE: 1153 dir[0]=0; dir[1]=0; dir[2]=1; 1154 MSG_ReadPos(&net_message, pos); 1155 CL_ParticleSmokeEffect (pos, dir, 0, 20, 20); 1156 break; 1157 1158 case TE_ELECTRIC_SPARKS: 1159 MSG_ReadPos (&net_message, pos); 1160 MSG_ReadDir (&net_message, dir); 1161 // CL_ParticleEffect (pos, dir, 109, 40); 1162 CL_ParticleEffect (pos, dir, 0x75, 40); 1163 //FIXME : replace or remove this sound 1164 S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); 1165 break; 1166 1167 case TE_TRACKER_EXPLOSION: 1168 MSG_ReadPos (&net_message, pos); 1169 CL_ColorFlash (pos, 0, 150, -1, -1, -1); 1170 CL_ColorExplosionParticles (pos, 0, 1); 1171 // CL_Tracker_Explode (pos); 1172 S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); 1173 break; 1174 1175 case TE_TELEPORT_EFFECT: 1176 case TE_DBALL_GOAL: 1177 MSG_ReadPos (&net_message, pos); 1178 CL_TeleportParticles (pos); 1179 break; 1180 1181 case TE_WIDOWBEAMOUT: 1182 CL_ParseWidow (); 1183 break; 1184 1185 case TE_NUKEBLAST: 1186 CL_ParseNuke (); 1187 break; 1188 1189 case TE_WIDOWSPLASH: 1190 MSG_ReadPos (&net_message, pos); 1191 CL_WidowSplash (pos); 1192 break; 1193 //PGM 1194 //============== 1195 1196 default: 1197 Com_Error (ERR_DROP, "CL_ParseTEnt: bad type"); 1198 } 1199 } 1200 1201 /* 1202 ================= 1203 CL_AddBeams 1204 ================= 1205 */ 1206 void CL_AddBeams (void) 1207 { 1208 int i,j; 1209 beam_t *b; 1210 vec3_t dist, org; 1211 float d; 1212 entity_t ent; 1213 float yaw, pitch; 1214 float forward; 1215 float len, steps; 1216 float model_length; 1217 1218 // update beams 1219 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) 1220 { 1221 if (!b->model || b->endtime < cl.time) 1222 continue; 1223 1224 // if coming from the player, update the start position 1225 if (b->entity == cl.playernum+1) // entity 0 is the world 1226 { 1227 VectorCopy (cl.refdef.vieworg, b->start); 1228 b->start[2] -= 22; // adjust for view height 1229 } 1230 VectorAdd (b->start, b->offset, org); 1231 1232 // calculate pitch and yaw 1233 VectorSubtract (b->end, org, dist); 1234 1235 if (dist[1] == 0 && dist[0] == 0) 1236 { 1237 yaw = 0; 1238 if (dist[2] > 0) 1239 pitch = 90; 1240 else 1241 pitch = 270; 1242 } 1243 else 1244 { 1245 // PMM - fixed to correct for pitch of 0 1246 if (dist[0]) 1247 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); 1248 else if (dist[1] > 0) 1249 yaw = 90; 1250 else 1251 yaw = 270; 1252 if (yaw < 0) 1253 yaw += 360; 1254 1255 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); 1256 pitch = (atan2(dist[2], forward) * -180.0 / M_PI); 1257 if (pitch < 0) 1258 pitch += 360.0; 1259 } 1260 1261 // add new entities for the beams 1262 d = VectorNormalize(dist); 1263 1264 memset (&ent, 0, sizeof(ent)); 1265 if (b->model == cl_mod_lightning) 1266 { 1267 model_length = 35.0; 1268 d-= 20.0; // correction so it doesn't end in middle of tesla 1269 } 1270 else 1271 { 1272 model_length = 30.0; 1273 } 1274 steps = ceil(d/model_length); 1275 len = (d-model_length)/(steps-1); 1276 1277 // PMM - special case for lightning model .. if the real length is shorter than the model, 1278 // flip it around & draw it from the end to the start. This prevents the model from going 1279 // through the tesla mine (instead it goes through the target) 1280 if ((b->model == cl_mod_lightning) && (d <= model_length)) 1281 { 1282 // Com_Printf ("special case\n"); 1283 VectorCopy (b->end, ent.origin); 1284 // offset to push beam outside of tesla model (negative because dist is from end to start 1285 // for this beam) 1286 // for (j=0 ; j<3 ; j++) 1287 // ent.origin[j] -= dist[j]*10.0; 1288 ent.model = b->model; 1289 ent.flags = RF_FULLBRIGHT; 1290 ent.angles[0] = pitch; 1291 ent.angles[1] = yaw; 1292 ent.angles[2] = rand()%360; 1293 V_AddEntity (&ent); 1294 return; 1295 } 1296 while (d > 0) 1297 { 1298 VectorCopy (org, ent.origin); 1299 ent.model = b->model; 1300 if (b->model == cl_mod_lightning) 1301 { 1302 ent.flags = RF_FULLBRIGHT; 1303 ent.angles[0] = -pitch; 1304 ent.angles[1] = yaw + 180.0; 1305 ent.angles[2] = rand()%360; 1306 } 1307 else 1308 { 1309 ent.angles[0] = pitch; 1310 ent.angles[1] = yaw; 1311 ent.angles[2] = rand()%360; 1312 } 1313 1314 // Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); 1315 V_AddEntity (&ent); 1316 1317 for (j=0 ; j<3 ; j++) 1318 org[j] += dist[j]*len; 1319 d -= model_length; 1320 } 1321 } 1322 } 1323 1324 1325 /* 1326 // Com_Printf ("Endpoint: %f %f %f\n", b->end[0], b->end[1], b->end[2]); 1327 // Com_Printf ("Pred View Angles: %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]); 1328 // Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]); 1329 // VectorCopy (cl.predicted_origin, b->start); 1330 // b->start[2] += 22; // adjust for view height 1331 // if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) { 1332 // b->start[2] = cl.refdef.vieworg[2]; 1333 // } 1334 1335 // Com_Printf ("Time: %d %d %f\n", cl.time, cls.realtime, cls.frametime); 1336 */ 1337 1338 extern cvar_t *hand; 1339 1340 /* 1341 ================= 1342 ROGUE - draw player locked beams 1343 CL_AddPlayerBeams 1344 ================= 1345 */ 1346 void CL_AddPlayerBeams (void) 1347 { 1348 int i,j; 1349 beam_t *b; 1350 vec3_t dist, org; 1351 float d; 1352 entity_t ent; 1353 float yaw, pitch; 1354 float forward; 1355 float len, steps; 1356 int framenum; 1357 float model_length; 1358 1359 float hand_multiplier; 1360 frame_t *oldframe; 1361 player_state_t *ps, *ops; 1362 1363 //PMM 1364 if (hand) 1365 { 1366 if (hand->value == 2) 1367 hand_multiplier = 0; 1368 else if (hand->value == 1) 1369 hand_multiplier = -1; 1370 else 1371 hand_multiplier = 1; 1372 } 1373 else 1374 { 1375 hand_multiplier = 1; 1376 } 1377 //PMM 1378 1379 // update beams 1380 for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++) 1381 { 1382 vec3_t f,r,u; 1383 if (!b->model || b->endtime < cl.time) 1384 continue; 1385 1386 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) 1387 { 1388 1389 // if coming from the player, update the start position 1390 if (b->entity == cl.playernum+1) // entity 0 is the world 1391 { 1392 // set up gun position 1393 // code straight out of CL_AddViewWeapon 1394 ps = &cl.frame.playerstate; 1395 j = (cl.frame.serverframe - 1) & UPDATE_MASK; 1396 oldframe = &cl.frames[j]; 1397 if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid) 1398 oldframe = &cl.frame; // previous frame was dropped or involid 1399 ops = &oldframe->playerstate; 1400 for (j=0 ; j<3 ; j++) 1401 { 1402 b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j] 1403 + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]); 1404 } 1405 VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org); 1406 VectorMA ( org, b->offset[1], cl.v_forward, org); 1407 VectorMA ( org, b->offset[2], cl.v_up, org); 1408 if ((hand) && (hand->value == 2)) { 1409 VectorMA (org, -1, cl.v_up, org); 1410 } 1411 // FIXME - take these out when final 1412 VectorCopy (cl.v_right, r); 1413 VectorCopy (cl.v_forward, f); 1414 VectorCopy (cl.v_up, u); 1415 1416 } 1417 else 1418 VectorCopy (b->start, org); 1419 } 1420 else 1421 { 1422 // if coming from the player, update the start position 1423 if (b->entity == cl.playernum+1) // entity 0 is the world 1424 { 1425 VectorCopy (cl.refdef.vieworg, b->start); 1426 b->start[2] -= 22; // adjust for view height 1427 } 1428 VectorAdd (b->start, b->offset, org); 1429 } 1430 1431 // calculate pitch and yaw 1432 VectorSubtract (b->end, org, dist); 1433 1434 //PMM 1435 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)) 1436 { 1437 vec_t len; 1438 1439 len = VectorLength (dist); 1440 VectorScale (f, len, dist); 1441 VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist); 1442 VectorMA (dist, b->offset[1], f, dist); 1443 VectorMA (dist, b->offset[2], u, dist); 1444 if ((hand) && (hand->value == 2)) { 1445 VectorMA (org, -1, cl.v_up, org); 1446 } 1447 } 1448 //PMM 1449 1450 if (dist[1] == 0 && dist[0] == 0) 1451 { 1452 yaw = 0; 1453 if (dist[2] > 0) 1454 pitch = 90; 1455 else 1456 pitch = 270; 1457 } 1458 else 1459 { 1460 // PMM - fixed to correct for pitch of 0 1461 if (dist[0]) 1462 yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); 1463 else if (dist[1] > 0) 1464 yaw = 90; 1465 else 1466 yaw = 270; 1467 if (yaw < 0) 1468 yaw += 360; 1469 1470 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); 1471 pitch = (atan2(dist[2], forward) * -180.0 / M_PI); 1472 if (pitch < 0) 1473 pitch += 360.0; 1474 } 1475 1476 if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) 1477 { 1478 if (b->entity != cl.playernum+1) 1479 { 1480 framenum = 2; 1481 // Com_Printf ("Third person\n"); 1482 ent.angles[0] = -pitch; 1483 ent.angles[1] = yaw + 180.0; 1484 ent.angles[2] = 0; 1485 // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]); 1486 AngleVectors(ent.angles, f, r, u); 1487 1488 // if it's a non-origin offset, it's a player, so use the hardcoded player offset 1489 if (!VectorCompare (b->offset, vec3_origin)) 1490 { 1491 VectorMA (org, -(b->offset[0])+1, r, org); 1492 VectorMA (org, -(b->offset[1]), f, org); 1493 VectorMA (org, -(b->offset[2])-10, u, org); 1494 } 1495 else 1496 { 1497 // if it's a monster, do the particle effect 1498 CL_MonsterPlasma_Shell(b->start); 1499 } 1500 } 1501 else 1502 { 1503 framenum = 1; 1504 } 1505 } 1506 1507 // if it's the heatbeam, draw the particle effect 1508 if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))) 1509 { 1510 CL_Heatbeam (org, dist); 1511 } 1512 1513 // add new entities for the beams 1514 d = VectorNormalize(dist); 1515 1516 memset (&ent, 0, sizeof(ent)); 1517 if (b->model == cl_mod_heatbeam) 1518 { 1519 model_length = 32.0; 1520 } 1521 else if (b->model == cl_mod_lightning) 1522 { 1523 model_length = 35.0; 1524 d-= 20.0; // correction so it doesn't end in middle of tesla 1525 } 1526 else 1527 { 1528 model_length = 30.0; 1529 } 1530 steps = ceil(d/model_length); 1531 len = (d-model_length)/(steps-1); 1532 1533 // PMM - special case for lightning model .. if the real length is shorter than the model, 1534 // flip it around & draw it from the end to the start. This prevents the model from going 1535 // through the tesla mine (instead it goes through the target) 1536 if ((b->model == cl_mod_lightning) && (d <= model_length)) 1537 { 1538 // Com_Printf ("special case\n"); 1539 VectorCopy (b->end, ent.origin); 1540 // offset to push beam outside of tesla model (negative because dist is from end to start 1541 // for this beam) 1542 // for (j=0 ; j<3 ; j++) 1543 // ent.origin[j] -= dist[j]*10.0; 1544 ent.model = b->model; 1545 ent.flags = RF_FULLBRIGHT; 1546 ent.angles[0] = pitch; 1547 ent.angles[1] = yaw; 1548 ent.angles[2] = rand()%360; 1549 V_AddEntity (&ent); 1550 return; 1551 } 1552 while (d > 0) 1553 { 1554 VectorCopy (org, ent.origin); 1555 ent.model = b->model; 1556 if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) 1557 { 1558 // ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; 1559 // ent.alpha = 0.3; 1560 ent.flags = RF_FULLBRIGHT; 1561 ent.angles[0] = -pitch; 1562 ent.angles[1] = yaw + 180.0; 1563 ent.angles[2] = (cl.time) % 360; 1564 // ent.angles[2] = rand()%360; 1565 ent.frame = framenum; 1566 } 1567 else if (b->model == cl_mod_lightning) 1568 { 1569 ent.flags = RF_FULLBRIGHT; 1570 ent.angles[0] = -pitch; 1571 ent.angles[1] = yaw + 180.0; 1572 ent.angles[2] = rand()%360; 1573 } 1574 else 1575 { 1576 ent.angles[0] = pitch; 1577 ent.angles[1] = yaw; 1578 ent.angles[2] = rand()%360; 1579 } 1580 1581 // Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); 1582 V_AddEntity (&ent); 1583 1584 for (j=0 ; j<3 ; j++) 1585 org[j] += dist[j]*len; 1586 d -= model_length; 1587 } 1588 } 1589 } 1590 1591 /* 1592 ================= 1593 CL_AddExplosions 1594 ================= 1595 */ 1596 void CL_AddExplosions (void) 1597 { 1598 entity_t *ent; 1599 int i; 1600 explosion_t *ex; 1601 float frac; 1602 int f; 1603 1604 memset (&ent, 0, sizeof(ent)); 1605 1606 for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++) 1607 { 1608 if (ex->type == ex_free) 1609 continue; 1610 frac = (cl.time - ex->start)/100.0; 1611 f = floor(frac); 1612 1613 ent = &ex->ent; 1614 1615 switch (ex->type) 1616 { 1617 case ex_mflash: 1618 if (f >= ex->frames-1) 1619 ex->type = ex_free; 1620 break; 1621 case ex_misc: 1622 if (f >= ex->frames-1) 1623 { 1624 ex->type = ex_free; 1625 break; 1626 } 1627 ent->alpha = 1.0 - frac/(ex->frames-1); 1628 break; 1629 case ex_flash: 1630 if (f >= 1) 1631 { 1632 ex->type = ex_free; 1633 break; 1634 } 1635 ent->alpha = 1.0; 1636 break; 1637 case ex_poly: 1638 if (f >= ex->frames-1) 1639 { 1640 ex->type = ex_free; 1641 break; 1642 } 1643 1644 ent->alpha = (16.0 - (float)f)/16.0; 1645 1646 if (f < 10) 1647 { 1648 ent->skinnum = (f>>1); 1649 if (ent->skinnum < 0) 1650 ent->skinnum = 0; 1651 } 1652 else 1653 { 1654 ent->flags |= RF_TRANSLUCENT; 1655 if (f < 13) 1656 ent->skinnum = 5; 1657 else 1658 ent->skinnum = 6; 1659 } 1660 break; 1661 case ex_poly2: 1662 if (f >= ex->frames-1) 1663 { 1664 ex->type = ex_free; 1665 break; 1666 } 1667 1668 ent->alpha = (5.0 - (float)f)/5.0; 1669 ent->skinnum = 0; 1670 ent->flags |= RF_TRANSLUCENT; 1671 break; 1672 } 1673 1674 if (ex->type == ex_free) 1675 continue; 1676 if (ex->light) 1677 { 1678 V_AddLight (ent->origin, ex->light*ent->alpha, 1679 ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]); 1680 } 1681 1682 VectorCopy (ent->origin, ent->oldorigin); 1683 1684 if (f < 0) 1685 f = 0; 1686 ent->frame = ex->baseframe + f + 1; 1687 ent->oldframe = ex->baseframe + f; 1688 ent->backlerp = 1.0 - cl.lerpfrac; 1689 1690 V_AddEntity (ent); 1691 } 1692 } 1693 1694 1695 /* 1696 ================= 1697 CL_AddLasers 1698 ================= 1699 */ 1700 void CL_AddLasers (void) 1701 { 1702 laser_t *l; 1703 int i; 1704 1705 for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++) 1706 { 1707 if (l->endtime >= cl.time) 1708 V_AddEntity (&l->ent); 1709 } 1710 } 1711 1712 /* PMM - CL_Sustains */ 1713 void CL_ProcessSustain () 1714 { 1715 cl_sustain_t *s; 1716 int i; 1717 1718 for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++) 1719 { 1720 if (s->id) 1721 if ((s->endtime >= cl.time) && (cl.time >= s->nextthink)) 1722 { 1723 // Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval); 1724 s->think (s); 1725 } 1726 else if (s->endtime < cl.time) 1727 s->id = 0; 1728 } 1729 } 1730 1731 /* 1732 ================= 1733 CL_AddTEnts 1734 ================= 1735 */ 1736 void CL_AddTEnts (void) 1737 { 1738 CL_AddBeams (); 1739 // PMM - draw plasma beams 1740 CL_AddPlayerBeams (); 1741 CL_AddExplosions (); 1742 CL_AddLasers (); 1743 // PMM - set up sustain 1744 CL_ProcessSustain(); 1745 }