1/* 2*/ 3void (entity targ, entity inflictor, entity attacker, float damage) T_Damage; 4void () player_run; 5void(entity bomb, entity attacker, float rad, entity ignore, string dtype) T_RadiusDamage; 6void(vector org, float damage) SpawnBlood; 7void() SuperDamageSound; 8 9 10// called by worldspawn 11void() W_Precache = 12{ 13 precache_sound ("weapons/r_exp3.wav"); // new rocket explosion 14 precache_sound ("weapons/rocket1i.wav"); // spike gun 15 precache_sound ("weapons/sgun1.wav"); 16 precache_sound ("weapons/guncock.wav"); // player shotgun 17 precache_sound ("weapons/ric1.wav"); // ricochet (used in c code) 18 precache_sound ("weapons/ric2.wav"); // ricochet (used in c code) 19 precache_sound ("weapons/ric3.wav"); // ricochet (used in c code) 20 precache_sound ("weapons/spike2.wav"); // super spikes 21 precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code) 22 precache_sound ("weapons/grenade.wav"); // grenade launcher 23 precache_sound ("weapons/bounce.wav"); // grenade bounce 24 precache_sound ("weapons/shotgn2.wav"); // super shotgun 25}; 26 27float() crandom = 28{ 29 return 2*(random() - 0.5); 30}; 31 32/* 33================ 34W_FireAxe 35================ 36*/ 37void() W_FireAxe = 38{ 39 local vector source; 40 local vector org; 41 42 makevectors (self.v_angle); 43 source = self.origin + '0 0 16'; 44 traceline (source, source + v_forward*64, FALSE, self); 45 if (trace_fraction == 1.0) 46 return; 47 48 org = trace_endpos - v_forward*4; 49 50 if (trace_ent.takedamage) 51 { 52 trace_ent.axhitme = 1; 53 SpawnBlood (org, 20); 54 if (deathmatch > 3) 55 T_Damage (trace_ent, self, self, 75); 56 else 57 T_Damage (trace_ent, self, self, 20); 58 } 59 else 60 { // hit wall 61 sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM); 62 63 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 64 WriteByte (MSG_MULTICAST, TE_GUNSHOT); 65 WriteByte (MSG_MULTICAST, 3); 66 WriteCoord (MSG_MULTICAST, org_x); 67 WriteCoord (MSG_MULTICAST, org_y); 68 WriteCoord (MSG_MULTICAST, org_z); 69 multicast (org, MULTICAST_PVS); 70 } 71}; 72 73 74//============================================================================ 75 76 77vector() wall_velocity = 78{ 79 local vector vel; 80 81 vel = normalize (self.velocity); 82 vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5)); 83 vel = vel + 2*trace_plane_normal; 84 vel = vel * 200; 85 86 return vel; 87}; 88 89 90/* 91================ 92SpawnMeatSpray 93================ 94*/ 95void(vector org, vector vel) SpawnMeatSpray = 96{ 97 local entity missile; 98 local vector org; 99 100 missile = spawn (); 101 missile.owner = self; 102 missile.movetype = MOVETYPE_BOUNCE; 103 missile.solid = SOLID_NOT; 104 105 makevectors (self.angles); 106 107 missile.velocity = vel; 108 missile.velocity_z = missile.velocity_z + 250 + 50*random(); 109 110 missile.avelocity = '3000 1000 2000'; 111 112// set missile duration 113 missile.nextthink = time + 1; 114 missile.think = SUB_Remove; 115 116 setmodel (missile, "progs/zom_gib.mdl"); 117 setsize (missile, '0 0 0', '0 0 0'); 118 setorigin (missile, org); 119}; 120 121/* 122================ 123SpawnBlood 124================ 125*/ 126void(vector org, float damage) SpawnBlood = 127{ 128 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 129 WriteByte (MSG_MULTICAST, TE_BLOOD); 130 WriteByte (MSG_MULTICAST, 1); 131 WriteCoord (MSG_MULTICAST, org_x); 132 WriteCoord (MSG_MULTICAST, org_y); 133 WriteCoord (MSG_MULTICAST, org_z); 134 multicast (org, MULTICAST_PVS); 135}; 136 137/* 138================ 139spawn_touchblood 140================ 141*/ 142void(float damage) spawn_touchblood = 143{ 144 local vector vel; 145 146 vel = wall_velocity () * 0.2; 147 SpawnBlood (self.origin + vel*0.01, damage); 148}; 149 150/* 151============================================================================== 152 153MULTI-DAMAGE 154 155Collects multiple small damages into a single damage 156 157============================================================================== 158*/ 159 160entity multi_ent; 161float multi_damage; 162 163vector blood_org; 164float blood_count; 165 166vector puff_org; 167float puff_count; 168 169void() ClearMultiDamage = 170{ 171 multi_ent = world; 172 multi_damage = 0; 173 blood_count = 0; 174 puff_count = 0; 175}; 176 177void() ApplyMultiDamage = 178{ 179 if (!multi_ent) 180 return; 181 T_Damage (multi_ent, self, self, multi_damage); 182}; 183 184void(entity hit, float damage) AddMultiDamage = 185{ 186 if (!hit) 187 return; 188 189 if (hit != multi_ent) 190 { 191 ApplyMultiDamage (); 192 multi_damage = damage; 193 multi_ent = hit; 194 } 195 else 196 multi_damage = multi_damage + damage; 197}; 198 199void() Multi_Finish = 200{ 201 if (puff_count) 202 { 203 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 204 WriteByte (MSG_MULTICAST, TE_GUNSHOT); 205 WriteByte (MSG_MULTICAST, puff_count); 206 WriteCoord (MSG_MULTICAST, puff_org_x); 207 WriteCoord (MSG_MULTICAST, puff_org_y); 208 WriteCoord (MSG_MULTICAST, puff_org_z); 209 multicast (puff_org, MULTICAST_PVS); 210 } 211 212 if (blood_count) 213 { 214 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 215 WriteByte (MSG_MULTICAST, TE_BLOOD); 216 WriteByte (MSG_MULTICAST, blood_count); 217 WriteCoord (MSG_MULTICAST, blood_org_x); 218 WriteCoord (MSG_MULTICAST, blood_org_y); 219 WriteCoord (MSG_MULTICAST, blood_org_z); 220 multicast (puff_org, MULTICAST_PVS); 221 } 222}; 223 224/* 225============================================================================== 226BULLETS 227============================================================================== 228*/ 229 230/* 231================ 232TraceAttack 233================ 234*/ 235void(float damage, vector dir) TraceAttack = 236{ 237 local vector vel, org; 238 239 vel = normalize(dir + v_up*crandom() + v_right*crandom()); 240 vel = vel + 2*trace_plane_normal; 241 vel = vel * 200; 242 243 org = trace_endpos - dir*4; 244 245 if (trace_ent.takedamage) 246 { 247 blood_count = blood_count + 1; 248 blood_org = org; 249 AddMultiDamage (trace_ent, damage); 250 } 251 else 252 { 253 puff_count = puff_count + 1; 254 } 255}; 256 257/* 258================ 259FireBullets 260 261Used by shotgun, super shotgun, and enemy soldier firing 262Go to the trouble of combining multiple pellets into a single damage call. 263================ 264*/ 265void(float shotcount, vector dir, vector spread) FireBullets = 266{ 267 local vector direction; 268 local vector src; 269 270 makevectors(self.v_angle); 271 272 src = self.origin + v_forward*10; 273 src_z = self.absmin_z + self.size_z * 0.7; 274 275 ClearMultiDamage (); 276 277 traceline (src, src + dir*2048, FALSE, self); 278 puff_org = trace_endpos - dir*4; 279 280 while (shotcount > 0) 281 { 282 direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up; 283 traceline (src, src + direction*2048, FALSE, self); 284 if (trace_fraction != 1.0) 285 TraceAttack (4, direction); 286 287 shotcount = shotcount - 1; 288 } 289 ApplyMultiDamage (); 290 Multi_Finish (); 291}; 292 293/* 294================ 295W_FireShotgun 296================ 297*/ 298void() W_FireShotgun = 299{ 300 local vector dir; 301 302 sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM); 303 304 msg_entity = self; 305 WriteByte (MSG_ONE, SVC_SMALLKICK); 306 307 if (deathmatch != 4 ) 308 self.currentammo = self.ammo_shells = self.ammo_shells - 1; 309 310 dir = aim (self, 100000); 311 FireBullets (6, dir, '0.04 0.04 0'); 312}; 313 314 315/* 316================ 317W_FireSuperShotgun 318================ 319*/ 320void() W_FireSuperShotgun = 321{ 322 local vector dir; 323 324 if (self.currentammo == 1) 325 { 326 W_FireShotgun (); 327 return; 328 } 329 330 sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM); 331 332 msg_entity = self; 333 WriteByte (MSG_ONE, SVC_BIGKICK); 334 335 if (deathmatch != 4) 336 self.currentammo = self.ammo_shells = self.ammo_shells - 2; 337 dir = aim (self, 100000); 338 FireBullets (14, dir, '0.14 0.08 0'); 339}; 340 341 342/* 343============================================================================== 344 345ROCKETS 346 347============================================================================== 348*/ 349 350void() T_MissileTouch = 351{ 352 local float damg; 353 354// if (deathmatch == 4) 355// { 356// if ( ((other.weapon == 32) || (other.weapon == 16))) 357// { 358// if (random() < 0.1) 359// { 360// if (other != world) 361// { 362// // bprint (PRINT_HIGH, "Got here\n"); 363// other.deathtype = "blaze"; 364// T_Damage (other, self, self.owner, 1000 ); 365// T_RadiusDamage (self, self.owner, 1000, other); 366// } 367// } 368// } 369// } 370 371 if (other == self.owner) 372 return; // don't explode on owner 373 374 if (self.voided) { 375 return; 376 } 377 self.voided = 1; 378 379 if (pointcontents(self.origin) == CONTENT_SKY) 380 { 381 remove(self); 382 return; 383 } 384 385 damg = 100 + random()*20; 386 387 if (other.health) 388 { 389 other.deathtype = "rocket"; 390 T_Damage (other, self, self.owner, damg ); 391 } 392 393 // don't do radius damage to the other, because all the damage 394 // was done in the impact 395 396 397 T_RadiusDamage (self, self.owner, 120, other, "rocket"); 398 399// sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM); 400 self.origin = self.origin - 8 * normalize(self.velocity); 401 402 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 403 WriteByte (MSG_MULTICAST, TE_EXPLOSION); 404 WriteCoord (MSG_MULTICAST, self.origin_x); 405 WriteCoord (MSG_MULTICAST, self.origin_y); 406 WriteCoord (MSG_MULTICAST, self.origin_z); 407 multicast (self.origin, MULTICAST_PHS); 408 409 remove(self); 410}; 411 412 413 414/* 415================ 416W_FireRocket 417================ 418*/ 419void() W_FireRocket = 420{ 421 if (deathmatch != 4) 422 self.currentammo = self.ammo_rockets = self.ammo_rockets - 1; 423 424 sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); 425 426 msg_entity = self; 427 WriteByte (MSG_ONE, SVC_SMALLKICK); 428 429 newmis = spawn (); 430 newmis.owner = self; 431 newmis.movetype = MOVETYPE_FLYMISSILE; 432 newmis.solid = SOLID_BBOX; 433 434// set newmis speed 435 436 makevectors (self.v_angle); 437 newmis.velocity = aim(self, 1000); 438 newmis.velocity = newmis.velocity * 1000; 439 newmis.angles = vectoangles(newmis.velocity); 440 441 newmis.touch = T_MissileTouch; 442 newmis.voided = 0; 443 444// set newmis duration 445 newmis.nextthink = time + 5; 446 newmis.think = SUB_Remove; 447 newmis.classname = "rocket"; 448 449 setmodel (newmis, "progs/missile.mdl"); 450 setsize (newmis, '0 0 0', '0 0 0'); 451 setorigin (newmis, self.origin + v_forward*8 + '0 0 16'); 452}; 453 454/* 455=============================================================================== 456LIGHTNING 457=============================================================================== 458*/ 459 460void(entity from, float damage) LightningHit = 461{ 462 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 463 WriteByte (MSG_MULTICAST, TE_LIGHTNINGBLOOD); 464 WriteCoord (MSG_MULTICAST, trace_endpos_x); 465 WriteCoord (MSG_MULTICAST, trace_endpos_y); 466 WriteCoord (MSG_MULTICAST, trace_endpos_z); 467 multicast (trace_endpos, MULTICAST_PVS); 468 469 T_Damage (trace_ent, from, from, damage); 470}; 471 472/* 473================= 474LightningDamage 475================= 476*/ 477void(vector p1, vector p2, entity from, float damage) LightningDamage = 478{ 479 local entity e1, e2; 480 local vector f; 481 482 f = p2 - p1; 483 normalize (f); 484 f_x = 0 - f_y; 485 f_y = f_x; 486 f_z = 0; 487 f = f*16; 488 489 e1 = e2 = world; 490 491 traceline (p1, p2, FALSE, self); 492 493 if (trace_ent.takedamage) 494 { 495 LightningHit (from, damage); 496 if (self.classname == "player") 497 { 498 if (other.classname == "player") 499 trace_ent.velocity_z = trace_ent.velocity_z + 400; 500 } 501 } 502 e1 = trace_ent; 503 504 traceline (p1 + f, p2 + f, FALSE, self); 505 if (trace_ent != e1 && trace_ent.takedamage) 506 { 507 LightningHit (from, damage); 508 } 509 e2 = trace_ent; 510 511 traceline (p1 - f, p2 - f, FALSE, self); 512 if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage) 513 { 514 LightningHit (from, damage); 515 } 516}; 517 518 519void() W_FireLightning = 520{ 521 local vector org; 522 local float cells; 523 524 if (self.ammo_cells < 1) 525 { 526 self.weapon = W_BestWeapon (); 527 W_SetCurrentAmmo (); 528 return; 529 } 530 531// explode if under water 532 if (self.waterlevel > 1) 533 { 534 if (deathmatch > 3) 535 { 536 if (random() <= 0.5) 537 { 538 self.deathtype = "selfwater"; 539 T_Damage (self, self, self.owner, 4000 ); 540 } 541 else 542 { 543 cells = self.ammo_cells; 544 self.ammo_cells = 0; 545 W_SetCurrentAmmo (); 546 T_RadiusDamage (self, self, 35*cells, world, ""); 547 return; 548 } 549 } 550 else 551 { 552 cells = self.ammo_cells; 553 self.ammo_cells = 0; 554 W_SetCurrentAmmo (); 555 T_RadiusDamage (self, self, 35*cells, world,""); 556 return; 557 } 558 } 559 560 if (self.t_width < time) 561 { 562 sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); 563 self.t_width = time + 0.6; 564 } 565 msg_entity = self; 566 WriteByte (MSG_ONE, SVC_SMALLKICK); 567 568 if (deathmatch != 4) 569 self.currentammo = self.ammo_cells = self.ammo_cells - 1; 570 571 org = self.origin + '0 0 16'; 572 573 traceline (org, org + v_forward*600, TRUE, self); 574 575 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 576 WriteByte (MSG_MULTICAST, TE_LIGHTNING2); 577 WriteEntity (MSG_MULTICAST, self); 578 WriteCoord (MSG_MULTICAST, org_x); 579 WriteCoord (MSG_MULTICAST, org_y); 580 WriteCoord (MSG_MULTICAST, org_z); 581 WriteCoord (MSG_MULTICAST, trace_endpos_x); 582 WriteCoord (MSG_MULTICAST, trace_endpos_y); 583 WriteCoord (MSG_MULTICAST, trace_endpos_z); 584 multicast (org, MULTICAST_PHS); 585 586 LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30); 587}; 588 589 590//============================================================================= 591 592 593void() GrenadeExplode = 594{ 595 if (self.voided) { 596 return; 597 } 598 self.voided = 1; 599 600 T_RadiusDamage (self, self.owner, 120, world, "grenade"); 601 602 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 603 WriteByte (MSG_MULTICAST, TE_EXPLOSION); 604 WriteCoord (MSG_MULTICAST, self.origin_x); 605 WriteCoord (MSG_MULTICAST, self.origin_y); 606 WriteCoord (MSG_MULTICAST, self.origin_z); 607 multicast (self.origin, MULTICAST_PHS); 608 609 remove (self); 610}; 611 612void() GrenadeTouch = 613{ 614 if (other == self.owner) 615 return; // don't explode on owner 616 if (other.takedamage == DAMAGE_AIM) 617 { 618 GrenadeExplode(); 619 return; 620 } 621 sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound 622 if (self.velocity == '0 0 0') 623 self.avelocity = '0 0 0'; 624}; 625 626/* 627================ 628W_FireGrenade 629================ 630*/ 631void() W_FireGrenade = 632{ 633 if (deathmatch != 4) 634 self.currentammo = self.ammo_rockets = self.ammo_rockets - 1; 635 636 sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM); 637 638 msg_entity = self; 639 WriteByte (MSG_ONE, SVC_SMALLKICK); 640 641 newmis = spawn (); 642 newmis.voided=0; 643 newmis.owner = self; 644 newmis.movetype = MOVETYPE_BOUNCE; 645 newmis.solid = SOLID_BBOX; 646 newmis.classname = "grenade"; 647 648// set newmis speed 649 650 makevectors (self.v_angle); 651 652 if (self.v_angle_x) 653 newmis.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10; 654 else 655 { 656 newmis.velocity = aim(self, 10000); 657 newmis.velocity = newmis.velocity * 600; 658 newmis.velocity_z = 200; 659 } 660 661 newmis.avelocity = '300 300 300'; 662 663 newmis.angles = vectoangles(newmis.velocity); 664 665 newmis.touch = GrenadeTouch; 666 667// set newmis duration 668 if (deathmatch == 4) 669 { 670 newmis.nextthink = time + 2.5; 671 self.attack_finished = time + 1.1; 672// self.health = self.health - 1; 673 T_Damage (self, self, self.owner, 10 ); 674 } 675 else 676 newmis.nextthink = time + 2.5; 677 678 newmis.think = GrenadeExplode; 679 680 setmodel (newmis, "progs/grenade.mdl"); 681 setsize (newmis, '0 0 0', '0 0 0'); 682 setorigin (newmis, self.origin); 683}; 684 685 686//============================================================================= 687 688void() spike_touch; 689void() superspike_touch; 690 691 692/* 693=============== 694launch_spike 695 696Used for both the player and the ogre 697=============== 698*/ 699void(vector org, vector dir) launch_spike = 700{ 701 newmis = spawn (); 702 newmis.voided=0; 703 newmis.owner = self; 704 newmis.movetype = MOVETYPE_FLYMISSILE; 705 newmis.solid = SOLID_BBOX; 706 707 newmis.angles = vectoangles(dir); 708 709 newmis.touch = spike_touch; 710 newmis.classname = "spike"; 711 newmis.think = SUB_Remove; 712 newmis.nextthink = time + 6; 713 setmodel (newmis, "progs/spike.mdl"); 714 setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); 715 setorigin (newmis, org); 716 717 newmis.velocity = dir * 1000; 718}; 719 720void() W_FireSuperSpikes = 721{ 722 local vector dir; 723 local entity old; 724 725 sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); 726 self.attack_finished = time + 0.2; 727 if (deathmatch != 4) 728 self.currentammo = self.ammo_nails = self.ammo_nails - 2; 729 dir = aim (self, 1000); 730 launch_spike (self.origin + '0 0 16', dir); 731 newmis.touch = superspike_touch; 732 setmodel (newmis, "progs/s_spike.mdl"); 733 setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); 734 msg_entity = self; 735 WriteByte (MSG_ONE, SVC_SMALLKICK); 736}; 737 738void(float ox) W_FireSpikes = 739{ 740 local vector dir; 741 local entity old; 742 743 makevectors (self.v_angle); 744 745 if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN) 746 { 747 W_FireSuperSpikes (); 748 return; 749 } 750 751 if (self.ammo_nails < 1) 752 { 753 self.weapon = W_BestWeapon (); 754 W_SetCurrentAmmo (); 755 return; 756 } 757 758 sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM); 759 self.attack_finished = time + 0.2; 760 if (deathmatch != 4) 761 self.currentammo = self.ammo_nails = self.ammo_nails - 1; 762 dir = aim (self, 1000); 763 launch_spike (self.origin + '0 0 16' + v_right*ox, dir); 764 765 msg_entity = self; 766 WriteByte (MSG_ONE, SVC_SMALLKICK); 767}; 768 769 770 771.float hit_z; 772void() spike_touch = 773{ 774local float rand; 775 if (other == self.owner) 776 return; 777 778 if (self.voided) { 779 return; 780 } 781 self.voided = 1; 782 783 if (other.solid == SOLID_TRIGGER) 784 return; // trigger field, do nothing 785 786 if (pointcontents(self.origin) == CONTENT_SKY) 787 { 788 remove(self); 789 return; 790 } 791 792// hit something that bleeds 793 if (other.takedamage) 794 { 795 spawn_touchblood (9); 796 other.deathtype = "nail"; 797 T_Damage (other, self, self.owner, 9); 798 } 799 else 800 { 801 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 802 if (self.classname == "wizspike") 803 WriteByte (MSG_MULTICAST, TE_WIZSPIKE); 804 else if (self.classname == "knightspike") 805 WriteByte (MSG_MULTICAST, TE_KNIGHTSPIKE); 806 else 807 WriteByte (MSG_MULTICAST, TE_SPIKE); 808 WriteCoord (MSG_MULTICAST, self.origin_x); 809 WriteCoord (MSG_MULTICAST, self.origin_y); 810 WriteCoord (MSG_MULTICAST, self.origin_z); 811 multicast (self.origin, MULTICAST_PHS); 812 } 813 814 remove(self); 815 816}; 817 818void() superspike_touch = 819{ 820local float rand; 821 if (other == self.owner) 822 return; 823 824 if (self.voided) { 825 return; 826 } 827 self.voided = 1; 828 829 830 if (other.solid == SOLID_TRIGGER) 831 return; // trigger field, do nothing 832 833 if (pointcontents(self.origin) == CONTENT_SKY) 834 { 835 remove(self); 836 return; 837 } 838 839// hit something that bleeds 840 if (other.takedamage) 841 { 842 spawn_touchblood (18); 843 other.deathtype = "supernail"; 844 T_Damage (other, self, self.owner, 18); 845 } 846 else 847 { 848 WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); 849 WriteByte (MSG_MULTICAST, TE_SUPERSPIKE); 850 WriteCoord (MSG_MULTICAST, self.origin_x); 851 WriteCoord (MSG_MULTICAST, self.origin_y); 852 WriteCoord (MSG_MULTICAST, self.origin_z); 853 multicast (self.origin, MULTICAST_PHS); 854 } 855 856 remove(self); 857 858}; 859 860 861/* 862=============================================================================== 863 864PLAYER WEAPON USE 865 866=============================================================================== 867*/ 868 869void() W_SetCurrentAmmo = 870{ 871 player_run (); // get out of any weapon firing states 872 873 self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) ); 874 875 if (self.weapon == IT_AXE) 876 { 877 self.currentammo = 0; 878 self.weaponmodel = "progs/v_axe.mdl"; 879 self.weaponframe = 0; 880 } 881 else if (self.weapon == IT_SHOTGUN) 882 { 883 self.currentammo = self.ammo_shells; 884 self.weaponmodel = "progs/v_shot.mdl"; 885 self.weaponframe = 0; 886 self.items = self.items | IT_SHELLS; 887 } 888 else if (self.weapon == IT_SUPER_SHOTGUN) 889 { 890 self.currentammo = self.ammo_shells; 891 self.weaponmodel = "progs/v_shot2.mdl"; 892 self.weaponframe = 0; 893 self.items = self.items | IT_SHELLS; 894 } 895 else if (self.weapon == IT_NAILGUN) 896 { 897 self.currentammo = self.ammo_nails; 898 self.weaponmodel = "progs/v_nail.mdl"; 899 self.weaponframe = 0; 900 self.items = self.items | IT_NAILS; 901 } 902 else if (self.weapon == IT_SUPER_NAILGUN) 903 { 904 self.currentammo = self.ammo_nails; 905 self.weaponmodel = "progs/v_nail2.mdl"; 906 self.weaponframe = 0; 907 self.items = self.items | IT_NAILS; 908 } 909 else if (self.weapon == IT_GRENADE_LAUNCHER) 910 { 911 self.currentammo = self.ammo_rockets; 912 self.weaponmodel = "progs/v_rock.mdl"; 913 self.weaponframe = 0; 914 self.items = self.items | IT_ROCKETS; 915 } 916 else if (self.weapon == IT_ROCKET_LAUNCHER) 917 { 918 self.currentammo = self.ammo_rockets; 919 self.weaponmodel = "progs/v_rock2.mdl"; 920 self.weaponframe = 0; 921 self.items = self.items | IT_ROCKETS; 922 } 923 else if (self.weapon == IT_LIGHTNING) 924 { 925 self.currentammo = self.ammo_cells; 926 self.weaponmodel = "progs/v_light.mdl"; 927 self.weaponframe = 0; 928 self.items = self.items | IT_CELLS; 929 } 930 else 931 { 932 self.currentammo = 0; 933 self.weaponmodel = ""; 934 self.weaponframe = 0; 935 } 936}; 937 938float() W_BestWeapon = 939{ 940 local float it; 941 942 it = self.items; 943 944 if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) ) 945 return IT_LIGHTNING; 946 else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) ) 947 return IT_SUPER_NAILGUN; 948 else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) ) 949 return IT_SUPER_SHOTGUN; 950 else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) ) 951 return IT_NAILGUN; 952 else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) ) 953 return IT_SHOTGUN; 954 955/* 956 if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) ) 957 return IT_ROCKET_LAUNCHER; 958 else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) ) 959 return IT_GRENADE_LAUNCHER; 960 961*/ 962 963 return IT_AXE; 964}; 965 966float() W_CheckNoAmmo = 967{ 968 if (self.currentammo > 0) 969 return TRUE; 970 971 if (self.weapon == IT_AXE) 972 return TRUE; 973 974 self.weapon = W_BestWeapon (); 975 976 W_SetCurrentAmmo (); 977 978// drop the weapon down 979 return FALSE; 980}; 981 982/* 983============ 984W_Attack 985 986An attack impulse can be triggered now 987============ 988*/ 989void() player_axe1; 990void() player_axeb1; 991void() player_axec1; 992void() player_axed1; 993void() player_shot1; 994void() player_nail1; 995void() player_light1; 996void() player_rocket1; 997 998void() W_Attack = 999{ 1000 local float r; 1001 1002 if (!W_CheckNoAmmo ()) 1003 return; 1004 1005 makevectors (self.v_angle); // calculate forward angle for velocity 1006 self.show_hostile = time + 1; // wake monsters up 1007 1008 if (self.weapon == IT_AXE) 1009 { 1010 self.attack_finished = time + 0.5; 1011 sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM); 1012 r = random(); 1013 if (r < 0.25) 1014 player_axe1 (); 1015 else if (r<0.5) 1016 player_axeb1 (); 1017 else if (r<0.75) 1018 player_axec1 (); 1019 else 1020 player_axed1 (); 1021 } 1022 else if (self.weapon == IT_SHOTGUN) 1023 { 1024 player_shot1 (); 1025 self.attack_finished = time + 0.5; 1026 W_FireShotgun (); 1027 } 1028 else if (self.weapon == IT_SUPER_SHOTGUN) 1029 { 1030 player_shot1 (); 1031 self.attack_finished = time + 0.7; 1032 W_FireSuperShotgun (); 1033 } 1034 else if (self.weapon == IT_NAILGUN) 1035 { 1036 player_nail1 (); 1037 } 1038 else if (self.weapon == IT_SUPER_NAILGUN) 1039 { 1040 player_nail1 (); 1041 } 1042 else if (self.weapon == IT_GRENADE_LAUNCHER) 1043 { 1044 player_rocket1(); 1045 self.attack_finished = time + 0.6; 1046 W_FireGrenade(); 1047 } 1048 else if (self.weapon == IT_ROCKET_LAUNCHER) 1049 { 1050 player_rocket1(); 1051 self.attack_finished = time + 0.8; 1052 W_FireRocket(); 1053 } 1054 else if (self.weapon == IT_LIGHTNING) 1055 { 1056 self.attack_finished = time + 0.1; 1057 sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); 1058 player_light1(); 1059 } 1060}; 1061 1062/* 1063============ 1064W_ChangeWeapon 1065 1066============ 1067*/ 1068void() W_ChangeWeapon = 1069{ 1070 local float it, am, fl; 1071 1072 it = self.items; 1073 am = 0; 1074 1075 if (self.impulse == 1) 1076 { 1077 fl = IT_AXE; 1078 } 1079 else if (self.impulse == 2) 1080 { 1081 fl = IT_SHOTGUN; 1082 if (self.ammo_shells < 1) 1083 am = 1; 1084 } 1085 else if (self.impulse == 3) 1086 { 1087 fl = IT_SUPER_SHOTGUN; 1088 if (self.ammo_shells < 2) 1089 am = 1; 1090 } 1091 else if (self.impulse == 4) 1092 { 1093 fl = IT_NAILGUN; 1094 if (self.ammo_nails < 1) 1095 am = 1; 1096 } 1097 else if (self.impulse == 5) 1098 { 1099 fl = IT_SUPER_NAILGUN; 1100 if (self.ammo_nails < 2) 1101 am = 1; 1102 } 1103 else if (self.impulse == 6) 1104 { 1105 fl = IT_GRENADE_LAUNCHER; 1106 if (self.ammo_rockets < 1) 1107 am = 1; 1108 } 1109 else if (self.impulse == 7) 1110 { 1111 fl = IT_ROCKET_LAUNCHER; 1112 if (self.ammo_rockets < 1) 1113 am = 1; 1114 } 1115 else if (self.impulse == 8) 1116 { 1117 fl = IT_LIGHTNING; 1118 if (self.ammo_cells < 1) 1119 am = 1; 1120 } 1121 1122 self.impulse = 0; 1123 1124 if (!(self.items & fl)) 1125 { // don't have the weapon or the ammo 1126 sprint (self, PRINT_HIGH, "no weapon.\n"); 1127 return; 1128 } 1129 1130 if (am) 1131 { // don't have the ammo 1132 sprint (self, PRINT_HIGH, "not enough ammo.\n"); 1133 return; 1134 } 1135 1136// 1137// set weapon, set ammo 1138// 1139 self.weapon = fl; 1140 W_SetCurrentAmmo (); 1141}; 1142 1143/* 1144============ 1145CheatCommand 1146============ 1147*/ 1148void() CheatCommand = 1149{ 1150// if (deathmatch || coop) 1151 return; 1152 1153 self.ammo_rockets = 100; 1154 self.ammo_nails = 200; 1155 self.ammo_shells = 100; 1156 self.items = self.items | 1157 IT_AXE | 1158 IT_SHOTGUN | 1159 IT_SUPER_SHOTGUN | 1160 IT_NAILGUN | 1161 IT_SUPER_NAILGUN | 1162 IT_GRENADE_LAUNCHER | 1163 IT_ROCKET_LAUNCHER | 1164 IT_KEY1 | IT_KEY2; 1165 1166 self.ammo_cells = 200; 1167 self.items = self.items | IT_LIGHTNING; 1168 1169 self.weapon = IT_ROCKET_LAUNCHER; 1170 self.impulse = 0; 1171 W_SetCurrentAmmo (); 1172}; 1173 1174/* 1175============ 1176CycleWeaponCommand 1177 1178Go to the next weapon with ammo 1179============ 1180*/ 1181void() CycleWeaponCommand = 1182{ 1183 local float it, am; 1184 1185 it = self.items; 1186 self.impulse = 0; 1187 1188 while (1) 1189 { 1190 am = 0; 1191 1192 if (self.weapon == IT_LIGHTNING) 1193 { 1194 self.weapon = IT_AXE; 1195 } 1196 else if (self.weapon == IT_AXE) 1197 { 1198 self.weapon = IT_SHOTGUN; 1199 if (self.ammo_shells < 1) 1200 am = 1; 1201 } 1202 else if (self.weapon == IT_SHOTGUN) 1203 { 1204 self.weapon = IT_SUPER_SHOTGUN; 1205 if (self.ammo_shells < 2) 1206 am = 1; 1207 } 1208 else if (self.weapon == IT_SUPER_SHOTGUN) 1209 { 1210 self.weapon = IT_NAILGUN; 1211 if (self.ammo_nails < 1) 1212 am = 1; 1213 } 1214 else if (self.weapon == IT_NAILGUN) 1215 { 1216 self.weapon = IT_SUPER_NAILGUN; 1217 if (self.ammo_nails < 2) 1218 am = 1; 1219 } 1220 else if (self.weapon == IT_SUPER_NAILGUN) 1221 { 1222 self.weapon = IT_GRENADE_LAUNCHER; 1223 if (self.ammo_rockets < 1) 1224 am = 1; 1225 } 1226 else if (self.weapon == IT_GRENADE_LAUNCHER) 1227 { 1228 self.weapon = IT_ROCKET_LAUNCHER; 1229 if (self.ammo_rockets < 1) 1230 am = 1; 1231 } 1232 else if (self.weapon == IT_ROCKET_LAUNCHER) 1233 { 1234 self.weapon = IT_LIGHTNING; 1235 if (self.ammo_cells < 1) 1236 am = 1; 1237 } 1238 1239 if ( (self.items & self.weapon) && am == 0) 1240 { 1241 W_SetCurrentAmmo (); 1242 return; 1243 } 1244 } 1245 1246}; 1247 1248 1249/* 1250============ 1251CycleWeaponReverseCommand 1252 1253Go to the prev weapon with ammo 1254============ 1255*/ 1256void() CycleWeaponReverseCommand = 1257{ 1258 local float it, am; 1259 1260 it = self.items; 1261 self.impulse = 0; 1262 1263 while (1) 1264 { 1265 am = 0; 1266 1267 if (self.weapon == IT_LIGHTNING) 1268 { 1269 self.weapon = IT_ROCKET_LAUNCHER; 1270 if (self.ammo_rockets < 1) 1271 am = 1; 1272 } 1273 else if (self.weapon == IT_ROCKET_LAUNCHER) 1274 { 1275 self.weapon = IT_GRENADE_LAUNCHER; 1276 if (self.ammo_rockets < 1) 1277 am = 1; 1278 } 1279 else if (self.weapon == IT_GRENADE_LAUNCHER) 1280 { 1281 self.weapon = IT_SUPER_NAILGUN; 1282 if (self.ammo_nails < 2) 1283 am = 1; 1284 } 1285 else if (self.weapon == IT_SUPER_NAILGUN) 1286 { 1287 self.weapon = IT_NAILGUN; 1288 if (self.ammo_nails < 1) 1289 am = 1; 1290 } 1291 else if (self.weapon == IT_NAILGUN) 1292 { 1293 self.weapon = IT_SUPER_SHOTGUN; 1294 if (self.ammo_shells < 2) 1295 am = 1; 1296 } 1297 else if (self.weapon == IT_SUPER_SHOTGUN) 1298 { 1299 self.weapon = IT_SHOTGUN; 1300 if (self.ammo_shells < 1) 1301 am = 1; 1302 } 1303 else if (self.weapon == IT_SHOTGUN) 1304 { 1305 self.weapon = IT_AXE; 1306 } 1307 else if (self.weapon == IT_AXE) 1308 { 1309 self.weapon = IT_LIGHTNING; 1310 if (self.ammo_cells < 1) 1311 am = 1; 1312 } 1313 1314 if ( (it & self.weapon) && am == 0) 1315 { 1316 W_SetCurrentAmmo (); 1317 return; 1318 } 1319 } 1320 1321}; 1322 1323 1324/* 1325============ 1326ServerflagsCommand 1327 1328Just for development 1329============ 1330*/ 1331void() ServerflagsCommand = 1332{ 1333 serverflags = serverflags * 2 + 1; 1334}; 1335 1336 1337/* 1338============ 1339ImpulseCommands 1340 1341============ 1342*/ 1343void() ImpulseCommands = 1344{ 1345 if (self.impulse >= 1 && self.impulse <= 8) 1346 W_ChangeWeapon (); 1347 1348 if (self.impulse == 9) 1349 CheatCommand (); 1350 if (self.impulse == 10) 1351 CycleWeaponCommand (); 1352 if (self.impulse == 11) 1353 ServerflagsCommand (); 1354 if (self.impulse == 12) 1355 CycleWeaponReverseCommand (); 1356 1357 self.impulse = 0; 1358}; 1359 1360/* 1361============ 1362W_WeaponFrame 1363 1364Called every frame so impulse events can be handled as well as possible 1365============ 1366*/ 1367void() W_WeaponFrame = 1368{ 1369 if (time < self.attack_finished) 1370 return; 1371 1372 ImpulseCommands (); 1373 1374// check for attack 1375 if (self.button0) 1376 { 1377 SuperDamageSound (); 1378 W_Attack (); 1379 } 1380}; 1381 1382/* 1383======== 1384SuperDamageSound 1385 1386Plays sound if needed 1387======== 1388*/ 1389void() SuperDamageSound = 1390{ 1391 if (self.super_damage_finished > time) 1392 { 1393 if (self.super_sound < time) 1394 { 1395 self.super_sound = time + 1; 1396 sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM); 1397 } 1398 } 1399 return; 1400}; 1401 1402 1403