|
|
1.1 ! root 1: #include "g_local.h" ! 2: ! 3: ! 4: /* ! 5: ================= ! 6: check_dodge ! 7: ! 8: This is a support routine used when a client is firing ! 9: a non-instant attack weapon. It checks to see if a ! 10: monster's dodge function should be called. ! 11: ================= ! 12: */ ! 13: static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed) ! 14: { ! 15: vec3_t end; ! 16: vec3_t v; ! 17: trace_t tr; ! 18: float eta; ! 19: ! 20: // easy mode only ducks one quarter the time ! 21: if (skill->value == 0) ! 22: { ! 23: if (random() > 0.25) ! 24: return; ! 25: } ! 26: VectorMA (start, 8192, dir, end); ! 27: tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT); ! 28: if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self)) ! 29: { ! 30: VectorSubtract (tr.endpos, start, v); ! 31: eta = (VectorLength(v) - tr.ent->maxs[0]) / speed; ! 32: tr.ent->monsterinfo.dodge (tr.ent, self, eta); ! 33: } ! 34: } ! 35: ! 36: ! 37: /* ! 38: ================= ! 39: fire_hit ! 40: ! 41: Used for all impact (hit/punch/slash) attacks ! 42: ================= ! 43: */ ! 44: qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick) ! 45: { ! 46: trace_t tr; ! 47: vec3_t forward, right, up; ! 48: vec3_t v; ! 49: vec3_t point; ! 50: float range; ! 51: vec3_t dir; ! 52: ! 53: //see if enemy is in range ! 54: VectorSubtract (self->enemy->s.origin, self->s.origin, dir); ! 55: range = VectorLength(dir); ! 56: if (range > aim[0]) ! 57: return false; ! 58: ! 59: if (aim[1] > self->mins[0] && aim[1] < self->maxs[0]) ! 60: { ! 61: // the hit is straight on so back the range up to the edge of their bbox ! 62: range -= self->enemy->maxs[0]; ! 63: } ! 64: else ! 65: { ! 66: // this is a side hit so adjust the "right" value out to the edge of their bbox ! 67: if (aim[1] < 0) ! 68: aim[1] = self->enemy->mins[0]; ! 69: else ! 70: aim[1] = self->enemy->maxs[0]; ! 71: } ! 72: ! 73: VectorMA (self->s.origin, range, dir, point); ! 74: ! 75: tr = gi.trace (self->s.origin, NULL, NULL, point, self, MASK_SHOT); ! 76: if (tr.fraction < 1) ! 77: { ! 78: if (!tr.ent->takedamage) ! 79: return false; ! 80: // if it will hit any client/monster then hit the one we wanted to hit ! 81: if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client)) ! 82: tr.ent = self->enemy; ! 83: } ! 84: ! 85: AngleVectors(self->s.angles, forward, right, up); ! 86: VectorMA (self->s.origin, range, forward, point); ! 87: VectorMA (point, aim[1], right, point); ! 88: VectorMA (point, aim[2], up, point); ! 89: VectorSubtract (point, self->enemy->s.origin, dir); ! 90: ! 91: // do the damage ! 92: T_Damage (tr.ent, self, self, dir, point, vec3_origin, damage, kick/2, DAMAGE_NO_KNOCKBACK, MOD_HIT); ! 93: ! 94: if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) ! 95: return false; ! 96: ! 97: // do our special form of knockback here ! 98: VectorMA (self->enemy->absmin, 0.5, self->enemy->size, v); ! 99: VectorSubtract (v, point, v); ! 100: VectorNormalize (v); ! 101: VectorMA (self->enemy->velocity, kick, v, self->enemy->velocity); ! 102: if (self->enemy->velocity[2] > 0) ! 103: self->enemy->groundentity = NULL; ! 104: return true; ! 105: } ! 106: ! 107: ! 108: /* ! 109: ================= ! 110: fire_lead ! 111: ! 112: This is an internal support routine used for bullet/pellet based weapons. ! 113: ================= ! 114: */ ! 115: static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod) ! 116: { ! 117: trace_t tr; ! 118: vec3_t dir; ! 119: vec3_t forward, right, up; ! 120: vec3_t end; ! 121: float r; ! 122: float u; ! 123: vec3_t water_start; ! 124: qboolean water = false; ! 125: int content_mask = MASK_SHOT | MASK_WATER; ! 126: ! 127: tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT); ! 128: if (!(tr.fraction < 1.0)) ! 129: { ! 130: vectoangles (aimdir, dir); ! 131: AngleVectors (dir, forward, right, up); ! 132: ! 133: r = crandom()*hspread; ! 134: u = crandom()*vspread; ! 135: VectorMA (start, 8192, forward, end); ! 136: VectorMA (end, r, right, end); ! 137: VectorMA (end, u, up, end); ! 138: ! 139: if (gi.pointcontents (start) & MASK_WATER) ! 140: { ! 141: water = true; ! 142: VectorCopy (start, water_start); ! 143: content_mask &= ~MASK_WATER; ! 144: } ! 145: ! 146: tr = gi.trace (start, NULL, NULL, end, self, content_mask); ! 147: ! 148: // see if we hit water ! 149: if (tr.contents & MASK_WATER) ! 150: { ! 151: int color; ! 152: ! 153: water = true; ! 154: VectorCopy (tr.endpos, water_start); ! 155: ! 156: if (!VectorCompare (start, tr.endpos)) ! 157: { ! 158: if (tr.contents & CONTENTS_WATER) ! 159: { ! 160: if (strcmp(tr.surface->name, "*brwater") == 0) ! 161: color = SPLASH_BROWN_WATER; ! 162: else ! 163: color = SPLASH_BLUE_WATER; ! 164: } ! 165: else if (tr.contents & CONTENTS_SLIME) ! 166: color = SPLASH_SLIME; ! 167: else if (tr.contents & CONTENTS_LAVA) ! 168: color = SPLASH_LAVA; ! 169: else ! 170: color = SPLASH_UNKNOWN; ! 171: ! 172: if (color != SPLASH_UNKNOWN) ! 173: { ! 174: gi.WriteByte (svc_temp_entity); ! 175: gi.WriteByte (TE_SPLASH); ! 176: gi.WriteByte (8); ! 177: gi.WritePosition (tr.endpos); ! 178: gi.WriteDir (tr.plane.normal); ! 179: gi.WriteByte (color); ! 180: gi.multicast (tr.endpos, MULTICAST_PVS); ! 181: } ! 182: ! 183: // change bullet's course when it enters water ! 184: VectorSubtract (end, start, dir); ! 185: vectoangles (dir, dir); ! 186: AngleVectors (dir, forward, right, up); ! 187: r = crandom()*hspread*2; ! 188: u = crandom()*vspread*2; ! 189: VectorMA (water_start, 8192, forward, end); ! 190: VectorMA (end, r, right, end); ! 191: VectorMA (end, u, up, end); ! 192: } ! 193: ! 194: // re-trace ignoring water this time ! 195: tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT); ! 196: } ! 197: } ! 198: ! 199: // send gun puff / flash ! 200: if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) ! 201: { ! 202: if (tr.fraction < 1.0) ! 203: { ! 204: if (tr.ent->takedamage) ! 205: { ! 206: T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod); ! 207: } ! 208: else ! 209: { ! 210: if (strncmp (tr.surface->name, "sky", 3) != 0) ! 211: { ! 212: gi.WriteByte (svc_temp_entity); ! 213: gi.WriteByte (te_impact); ! 214: gi.WritePosition (tr.endpos); ! 215: gi.WriteDir (tr.plane.normal); ! 216: gi.multicast (tr.endpos, MULTICAST_PVS); ! 217: ! 218: if (self->client) ! 219: PlayerNoise(self, tr.endpos, PNOISE_IMPACT); ! 220: } ! 221: } ! 222: } ! 223: } ! 224: ! 225: // if went through water, determine where the end and make a bubble trail ! 226: if (water) ! 227: { ! 228: vec3_t pos; ! 229: ! 230: VectorSubtract (tr.endpos, water_start, dir); ! 231: VectorNormalize (dir); ! 232: VectorMA (tr.endpos, -2, dir, pos); ! 233: if (gi.pointcontents (pos) & MASK_WATER) ! 234: VectorCopy (pos, tr.endpos); ! 235: else ! 236: tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER); ! 237: ! 238: VectorAdd (water_start, tr.endpos, pos); ! 239: VectorScale (pos, 0.5, pos); ! 240: ! 241: gi.WriteByte (svc_temp_entity); ! 242: gi.WriteByte (TE_BUBBLETRAIL); ! 243: gi.WritePosition (water_start); ! 244: gi.WritePosition (tr.endpos); ! 245: gi.multicast (pos, MULTICAST_PVS); ! 246: } ! 247: } ! 248: ! 249: ! 250: /* ! 251: ================= ! 252: fire_bullet ! 253: ! 254: Fires a single round. Used for machinegun and chaingun. Would be fine for ! 255: pistols, rifles, etc.... ! 256: ================= ! 257: */ ! 258: void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod) ! 259: { ! 260: fire_lead (self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod); ! 261: } ! 262: ! 263: ! 264: /* ! 265: ================= ! 266: fire_shotgun ! 267: ! 268: Shoots shotgun pellets. Used by shotgun and super shotgun. ! 269: ================= ! 270: */ ! 271: void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod) ! 272: { ! 273: int i; ! 274: ! 275: for (i = 0; i < count; i++) ! 276: fire_lead (self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod); ! 277: } ! 278: ! 279: ! 280: /* ! 281: ================= ! 282: fire_blaster ! 283: ! 284: Fires a single blaster bolt. Used by the blaster and hyper blaster. ! 285: ================= ! 286: */ ! 287: void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 288: { ! 289: int mod; ! 290: ! 291: if (other == self->owner) ! 292: return; ! 293: ! 294: if (surf && (surf->flags & SURF_SKY)) ! 295: { ! 296: G_FreeEdict (self); ! 297: return; ! 298: } ! 299: ! 300: if (self->owner->client) ! 301: PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); ! 302: ! 303: if (other->takedamage) ! 304: { ! 305: if (self->spawnflags & 1) ! 306: mod = MOD_HYPERBLASTER; ! 307: else ! 308: mod = MOD_BLASTER; ! 309: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); ! 310: } ! 311: else ! 312: { ! 313: gi.WriteByte (svc_temp_entity); ! 314: // RAFAEL ! 315: //if (self->s.effects & TE_BLUEHYPERBLASTER) ! 316: // gi.WriteByte (TE_BLUEHYPERBLASTER); ! 317: //else ! 318: gi.WriteByte (TE_BLASTER); ! 319: gi.WritePosition (self->s.origin); ! 320: if (!plane) ! 321: gi.WriteDir (vec3_origin); ! 322: else ! 323: gi.WriteDir (plane->normal); ! 324: gi.multicast (self->s.origin, MULTICAST_PVS); ! 325: } ! 326: ! 327: G_FreeEdict (self); ! 328: } ! 329: ! 330: void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper) ! 331: { ! 332: edict_t *bolt; ! 333: trace_t tr; ! 334: ! 335: VectorNormalize (dir); ! 336: ! 337: bolt = G_Spawn(); ! 338: bolt->svflags = SVF_DEADMONSTER; ! 339: // yes, I know it looks weird that projectiles are deadmonsters ! 340: // what this means is that when prediction is used against the object ! 341: // (blaster/hyperblaster shots), the player won't be solid clipped against ! 342: // the object. Right now trying to run into a firing hyperblaster ! 343: // is very jerky since you are predicted 'against' the shots. ! 344: VectorCopy (start, bolt->s.origin); ! 345: VectorCopy (start, bolt->s.old_origin); ! 346: vectoangles (dir, bolt->s.angles); ! 347: VectorScale (dir, speed, bolt->velocity); ! 348: bolt->movetype = MOVETYPE_FLYMISSILE; ! 349: bolt->clipmask = MASK_SHOT; ! 350: bolt->solid = SOLID_BBOX; ! 351: bolt->s.effects |= effect; ! 352: VectorClear (bolt->mins); ! 353: VectorClear (bolt->maxs); ! 354: bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2"); ! 355: bolt->s.sound = gi.soundindex ("misc/lasfly.wav"); ! 356: bolt->owner = self; ! 357: bolt->touch = blaster_touch; ! 358: bolt->nextthink = level.time + 2; ! 359: bolt->think = G_FreeEdict; ! 360: bolt->dmg = damage; ! 361: bolt->classname = "bolt"; ! 362: if (hyper) ! 363: bolt->spawnflags = 1; ! 364: gi.linkentity (bolt); ! 365: ! 366: if (self->client) ! 367: check_dodge (self, bolt->s.origin, dir, speed); ! 368: ! 369: tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT); ! 370: if (tr.fraction < 1.0) ! 371: { ! 372: VectorMA (bolt->s.origin, -10, dir, bolt->s.origin); ! 373: bolt->touch (bolt, tr.ent, NULL, NULL); ! 374: } ! 375: } ! 376: ! 377: // RAFAEL ! 378: void fire_blueblaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect) ! 379: { ! 380: edict_t *bolt; ! 381: trace_t tr; ! 382: ! 383: VectorNormalize (dir); ! 384: ! 385: bolt = G_Spawn (); ! 386: VectorCopy (start, bolt->s.origin); ! 387: VectorCopy (start, bolt->s.old_origin); ! 388: vectoangles (dir, bolt->s.angles); ! 389: VectorScale (dir, speed, bolt->velocity); ! 390: bolt->movetype = MOVETYPE_FLYMISSILE; ! 391: bolt->clipmask = MASK_SHOT; ! 392: bolt->solid = SOLID_BBOX; ! 393: bolt->s.effects |= effect; ! 394: VectorClear (bolt->mins); ! 395: VectorClear (bolt->maxs); ! 396: ! 397: bolt->s.modelindex = gi.modelindex ("models/objects/blaser/tris.md2"); ! 398: bolt->s.sound = gi.soundindex ("misc/lasfly.wav"); ! 399: bolt->owner = self; ! 400: bolt->touch = blaster_touch; ! 401: bolt->nextthink = level.time + 2; ! 402: bolt->think = G_FreeEdict; ! 403: bolt->dmg = damage; ! 404: bolt->classname = "bolt"; ! 405: gi.linkentity (bolt); ! 406: ! 407: if (self->client) ! 408: check_dodge (self, bolt->s.origin, dir, speed); ! 409: ! 410: tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT); ! 411: ! 412: if (tr.fraction < 1.0) ! 413: { ! 414: VectorMA (bolt->s.origin, -10, dir, bolt->s.origin); ! 415: bolt->touch (bolt, tr.ent, NULL, NULL); ! 416: } ! 417: ! 418: } ! 419: ! 420: /* ! 421: ================= ! 422: fire_grenade ! 423: ================= ! 424: */ ! 425: static void Grenade_Explode (edict_t *ent) ! 426: { ! 427: vec3_t origin; ! 428: int mod; ! 429: ! 430: if (ent->owner->client) ! 431: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT); ! 432: ! 433: //FIXME: if we are onground then raise our Z just a bit since we are a point? ! 434: if (ent->enemy) ! 435: { ! 436: float points; ! 437: vec3_t v; ! 438: vec3_t dir; ! 439: ! 440: VectorAdd (ent->enemy->mins, ent->enemy->maxs, v); ! 441: VectorMA (ent->enemy->s.origin, 0.5, v, v); ! 442: VectorSubtract (ent->s.origin, v, v); ! 443: points = ent->dmg - 0.5 * VectorLength (v); ! 444: VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir); ! 445: if (ent->spawnflags & 1) ! 446: mod = MOD_HANDGRENADE; ! 447: else ! 448: mod = MOD_GRENADE; ! 449: T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod); ! 450: } ! 451: ! 452: if (ent->spawnflags & 2) ! 453: mod = MOD_HELD_GRENADE; ! 454: else if (ent->spawnflags & 1) ! 455: mod = MOD_HG_SPLASH; ! 456: else ! 457: mod = MOD_G_SPLASH; ! 458: T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod); ! 459: ! 460: VectorMA (ent->s.origin, -0.02, ent->velocity, origin); ! 461: gi.WriteByte (svc_temp_entity); ! 462: if (ent->waterlevel) ! 463: { ! 464: if (ent->groundentity) ! 465: gi.WriteByte (TE_GRENADE_EXPLOSION_WATER); ! 466: else ! 467: gi.WriteByte (TE_ROCKET_EXPLOSION_WATER); ! 468: } ! 469: else ! 470: { ! 471: if (ent->groundentity) ! 472: gi.WriteByte (TE_GRENADE_EXPLOSION); ! 473: else ! 474: gi.WriteByte (TE_ROCKET_EXPLOSION); ! 475: } ! 476: gi.WritePosition (origin); ! 477: gi.multicast (ent->s.origin, MULTICAST_PHS); ! 478: ! 479: G_FreeEdict (ent); ! 480: } ! 481: ! 482: static void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) ! 483: { ! 484: if (other == ent->owner) ! 485: return; ! 486: ! 487: if (surf && (surf->flags & SURF_SKY)) ! 488: { ! 489: G_FreeEdict (ent); ! 490: return; ! 491: } ! 492: ! 493: if (!other->takedamage) ! 494: { ! 495: if (ent->spawnflags & 1) ! 496: { ! 497: if (random() > 0.5) ! 498: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0); ! 499: else ! 500: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0); ! 501: } ! 502: else ! 503: { ! 504: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0); ! 505: } ! 506: return; ! 507: } ! 508: ! 509: ent->enemy = other; ! 510: Grenade_Explode (ent); ! 511: } ! 512: ! 513: void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius) ! 514: { ! 515: edict_t *grenade; ! 516: vec3_t dir; ! 517: vec3_t forward, right, up; ! 518: ! 519: vectoangles (aimdir, dir); ! 520: AngleVectors (dir, forward, right, up); ! 521: ! 522: grenade = G_Spawn(); ! 523: VectorCopy (start, grenade->s.origin); ! 524: VectorScale (aimdir, speed, grenade->velocity); ! 525: VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity); ! 526: VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity); ! 527: VectorSet (grenade->avelocity, 300, 300, 300); ! 528: grenade->movetype = MOVETYPE_BOUNCE; ! 529: grenade->clipmask = MASK_SHOT; ! 530: grenade->solid = SOLID_BBOX; ! 531: grenade->s.effects |= EF_GRENADE; ! 532: VectorClear (grenade->mins); ! 533: VectorClear (grenade->maxs); ! 534: grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2"); ! 535: grenade->owner = self; ! 536: grenade->touch = Grenade_Touch; ! 537: grenade->nextthink = level.time + timer; ! 538: grenade->think = Grenade_Explode; ! 539: grenade->dmg = damage; ! 540: grenade->dmg_radius = damage_radius; ! 541: grenade->classname = "grenade"; ! 542: ! 543: gi.linkentity (grenade); ! 544: } ! 545: ! 546: void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held) ! 547: { ! 548: edict_t *grenade; ! 549: vec3_t dir; ! 550: vec3_t forward, right, up; ! 551: ! 552: vectoangles (aimdir, dir); ! 553: AngleVectors (dir, forward, right, up); ! 554: ! 555: grenade = G_Spawn(); ! 556: VectorCopy (start, grenade->s.origin); ! 557: VectorScale (aimdir, speed, grenade->velocity); ! 558: VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity); ! 559: VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity); ! 560: VectorSet (grenade->avelocity, 300, 300, 300); ! 561: grenade->movetype = MOVETYPE_BOUNCE; ! 562: grenade->clipmask = MASK_SHOT; ! 563: grenade->solid = SOLID_BBOX; ! 564: grenade->s.effects |= EF_GRENADE; ! 565: VectorClear (grenade->mins); ! 566: VectorClear (grenade->maxs); ! 567: grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2"); ! 568: grenade->owner = self; ! 569: grenade->touch = Grenade_Touch; ! 570: grenade->nextthink = level.time + timer; ! 571: grenade->think = Grenade_Explode; ! 572: grenade->dmg = damage; ! 573: grenade->dmg_radius = damage_radius; ! 574: grenade->classname = "hgrenade"; ! 575: if (held) ! 576: grenade->spawnflags = 3; ! 577: else ! 578: grenade->spawnflags = 1; ! 579: grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav"); ! 580: ! 581: if (timer <= 0.0) ! 582: Grenade_Explode (grenade); ! 583: else ! 584: { ! 585: gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0); ! 586: gi.linkentity (grenade); ! 587: } ! 588: } ! 589: ! 590: ! 591: /* ! 592: ================= ! 593: fire_rocket ! 594: ================= ! 595: */ ! 596: void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) ! 597: { ! 598: vec3_t origin; ! 599: int n; ! 600: ! 601: if (other == ent->owner) ! 602: return; ! 603: ! 604: if (surf && (surf->flags & SURF_SKY)) ! 605: { ! 606: G_FreeEdict (ent); ! 607: return; ! 608: } ! 609: ! 610: if (ent->owner->client) ! 611: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT); ! 612: ! 613: // calculate position for the explosion entity ! 614: VectorMA (ent->s.origin, -0.02, ent->velocity, origin); ! 615: ! 616: if (other->takedamage) ! 617: { ! 618: T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET); ! 619: } ! 620: else ! 621: { ! 622: // don't throw any debris in net games ! 623: if (!deathmatch->value && !coop->value) ! 624: { ! 625: if ((surf) && !(surf->flags & (SURF_WARP|SURF_TRANS33|SURF_TRANS66|SURF_FLOWING))) ! 626: { ! 627: n = rand() % 5; ! 628: while(n--) ! 629: ThrowDebris (ent, "models/objects/debris2/tris.md2", 2, ent->s.origin); ! 630: } ! 631: } ! 632: } ! 633: ! 634: T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH); ! 635: ! 636: gi.WriteByte (svc_temp_entity); ! 637: if (ent->waterlevel) ! 638: gi.WriteByte (TE_ROCKET_EXPLOSION_WATER); ! 639: else ! 640: gi.WriteByte (TE_ROCKET_EXPLOSION); ! 641: gi.WritePosition (origin); ! 642: gi.multicast (ent->s.origin, MULTICAST_PHS); ! 643: ! 644: G_FreeEdict (ent); ! 645: } ! 646: ! 647: void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage) ! 648: { ! 649: edict_t *rocket; ! 650: ! 651: rocket = G_Spawn(); ! 652: VectorCopy (start, rocket->s.origin); ! 653: VectorCopy (dir, rocket->movedir); ! 654: vectoangles (dir, rocket->s.angles); ! 655: VectorScale (dir, speed, rocket->velocity); ! 656: rocket->movetype = MOVETYPE_FLYMISSILE; ! 657: rocket->clipmask = MASK_SHOT; ! 658: rocket->solid = SOLID_BBOX; ! 659: rocket->s.effects |= EF_ROCKET; ! 660: VectorClear (rocket->mins); ! 661: VectorClear (rocket->maxs); ! 662: rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2"); ! 663: rocket->owner = self; ! 664: rocket->touch = rocket_touch; ! 665: rocket->nextthink = level.time + 8000/speed; ! 666: rocket->think = G_FreeEdict; ! 667: rocket->dmg = damage; ! 668: rocket->radius_dmg = radius_damage; ! 669: rocket->dmg_radius = damage_radius; ! 670: rocket->s.sound = gi.soundindex ("weapons/rockfly.wav"); ! 671: rocket->classname = "rocket"; ! 672: ! 673: if (self->client) ! 674: check_dodge (self, rocket->s.origin, dir, speed); ! 675: ! 676: gi.linkentity (rocket); ! 677: } ! 678: ! 679: ! 680: /* ! 681: ================= ! 682: fire_rail ! 683: ================= ! 684: */ ! 685: void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick) ! 686: { ! 687: vec3_t from; ! 688: vec3_t end; ! 689: trace_t tr; ! 690: edict_t *ignore; ! 691: int mask; ! 692: qboolean water; ! 693: ! 694: VectorMA (start, 8192, aimdir, end); ! 695: VectorCopy (start, from); ! 696: ignore = self; ! 697: water = false; ! 698: mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; ! 699: while (ignore) ! 700: { ! 701: tr = gi.trace (from, NULL, NULL, end, ignore, mask); ! 702: ! 703: if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA)) ! 704: { ! 705: mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA); ! 706: water = true; ! 707: } ! 708: else ! 709: { ! 710: if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client)) ! 711: ignore = tr.ent; ! 712: else ! 713: ignore = NULL; ! 714: ! 715: if ((tr.ent != self) && (tr.ent->takedamage)) ! 716: T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN); ! 717: } ! 718: ! 719: VectorCopy (tr.endpos, from); ! 720: } ! 721: ! 722: // send gun puff / flash ! 723: gi.WriteByte (svc_temp_entity); ! 724: gi.WriteByte (TE_RAILTRAIL); ! 725: gi.WritePosition (start); ! 726: gi.WritePosition (tr.endpos); ! 727: gi.multicast (self->s.origin, MULTICAST_PHS); ! 728: // gi.multicast (start, MULTICAST_PHS); ! 729: if (water) ! 730: { ! 731: gi.WriteByte (svc_temp_entity); ! 732: gi.WriteByte (TE_RAILTRAIL); ! 733: gi.WritePosition (start); ! 734: gi.WritePosition (tr.endpos); ! 735: gi.multicast (tr.endpos, MULTICAST_PHS); ! 736: } ! 737: ! 738: if (self->client) ! 739: PlayerNoise(self, tr.endpos, PNOISE_IMPACT); ! 740: } ! 741: ! 742: ! 743: /* ! 744: ================= ! 745: fire_bfg ! 746: ================= ! 747: */ ! 748: void bfg_explode (edict_t *self) ! 749: { ! 750: edict_t *ent; ! 751: float points; ! 752: vec3_t v; ! 753: float dist; ! 754: ! 755: if (self->s.frame == 0) ! 756: { ! 757: // the BFG effect ! 758: ent = NULL; ! 759: while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL) ! 760: { ! 761: if (!ent->takedamage) ! 762: continue; ! 763: if (ent == self->owner) ! 764: continue; ! 765: if (!CanDamage (ent, self)) ! 766: continue; ! 767: if (!CanDamage (ent, self->owner)) ! 768: continue; ! 769: ! 770: VectorAdd (ent->mins, ent->maxs, v); ! 771: VectorMA (ent->s.origin, 0.5, v, v); ! 772: VectorSubtract (self->s.origin, v, v); ! 773: dist = VectorLength(v); ! 774: points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius)); ! 775: if (ent == self->owner) ! 776: points = points * 0.5; ! 777: ! 778: gi.WriteByte (svc_temp_entity); ! 779: gi.WriteByte (TE_BFG_EXPLOSION); ! 780: gi.WritePosition (ent->s.origin); ! 781: gi.multicast (ent->s.origin, MULTICAST_PHS); ! 782: T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT); ! 783: } ! 784: } ! 785: ! 786: self->nextthink = level.time + FRAMETIME; ! 787: self->s.frame++; ! 788: if (self->s.frame == 5) ! 789: self->think = G_FreeEdict; ! 790: } ! 791: ! 792: void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 793: { ! 794: if (other == self->owner) ! 795: return; ! 796: ! 797: if (surf && (surf->flags & SURF_SKY)) ! 798: { ! 799: G_FreeEdict (self); ! 800: return; ! 801: } ! 802: ! 803: if (self->owner->client) ! 804: PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); ! 805: ! 806: // core explosion - prevents firing it into the wall/floor ! 807: if (other->takedamage) ! 808: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST); ! 809: T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST); ! 810: ! 811: gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0); ! 812: self->solid = SOLID_NOT; ! 813: self->touch = NULL; ! 814: VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin); ! 815: VectorClear (self->velocity); ! 816: self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2"); ! 817: self->s.frame = 0; ! 818: self->s.sound = 0; ! 819: self->s.effects &= ~EF_ANIM_ALLFAST; ! 820: self->think = bfg_explode; ! 821: self->nextthink = level.time + FRAMETIME; ! 822: self->enemy = other; ! 823: ! 824: gi.WriteByte (svc_temp_entity); ! 825: gi.WriteByte (TE_BFG_BIGEXPLOSION); ! 826: gi.WritePosition (self->s.origin); ! 827: gi.multicast (self->s.origin, MULTICAST_PVS); ! 828: } ! 829: ! 830: ! 831: void bfg_think (edict_t *self) ! 832: { ! 833: edict_t *ent; ! 834: edict_t *ignore; ! 835: vec3_t point; ! 836: vec3_t dir; ! 837: vec3_t start; ! 838: vec3_t end; ! 839: int dmg; ! 840: trace_t tr; ! 841: ! 842: if (deathmatch->value) ! 843: dmg = 5; ! 844: else ! 845: dmg = 10; ! 846: ! 847: ent = NULL; ! 848: while ((ent = findradius(ent, self->s.origin, 256)) != NULL) ! 849: { ! 850: if (ent == self) ! 851: continue; ! 852: ! 853: if (ent == self->owner) ! 854: continue; ! 855: ! 856: if (!ent->takedamage) ! 857: continue; ! 858: ! 859: if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0)) ! 860: continue; ! 861: ! 862: VectorMA (ent->absmin, 0.5, ent->size, point); ! 863: ! 864: VectorSubtract (point, self->s.origin, dir); ! 865: VectorNormalize (dir); ! 866: ! 867: ignore = self; ! 868: VectorCopy (self->s.origin, start); ! 869: VectorMA (start, 2048, dir, end); ! 870: while(1) ! 871: { ! 872: tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER); ! 873: ! 874: if (!tr.ent) ! 875: break; ! 876: ! 877: // hurt it if we can ! 878: if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner)) ! 879: T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER); ! 880: ! 881: // if we hit something that's not a monster or player we're done ! 882: if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) ! 883: { ! 884: gi.WriteByte (svc_temp_entity); ! 885: gi.WriteByte (TE_LASER_SPARKS); ! 886: gi.WriteByte (4); ! 887: gi.WritePosition (tr.endpos); ! 888: gi.WriteDir (tr.plane.normal); ! 889: gi.WriteByte (self->s.skinnum); ! 890: gi.multicast (tr.endpos, MULTICAST_PVS); ! 891: break; ! 892: } ! 893: ! 894: ignore = tr.ent; ! 895: VectorCopy (tr.endpos, start); ! 896: } ! 897: ! 898: gi.WriteByte (svc_temp_entity); ! 899: gi.WriteByte (TE_BFG_LASER); ! 900: gi.WritePosition (self->s.origin); ! 901: gi.WritePosition (tr.endpos); ! 902: gi.multicast (self->s.origin, MULTICAST_PHS); ! 903: } ! 904: ! 905: self->nextthink = level.time + FRAMETIME; ! 906: } ! 907: ! 908: ! 909: void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius) ! 910: { ! 911: edict_t *bfg; ! 912: ! 913: bfg = G_Spawn(); ! 914: VectorCopy (start, bfg->s.origin); ! 915: VectorCopy (dir, bfg->movedir); ! 916: vectoangles (dir, bfg->s.angles); ! 917: VectorScale (dir, speed, bfg->velocity); ! 918: bfg->movetype = MOVETYPE_FLYMISSILE; ! 919: bfg->clipmask = MASK_SHOT; ! 920: bfg->solid = SOLID_BBOX; ! 921: bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST; ! 922: VectorClear (bfg->mins); ! 923: VectorClear (bfg->maxs); ! 924: bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2"); ! 925: bfg->owner = self; ! 926: bfg->touch = bfg_touch; ! 927: bfg->nextthink = level.time + 8000/speed; ! 928: bfg->think = G_FreeEdict; ! 929: bfg->radius_dmg = damage; ! 930: bfg->dmg_radius = damage_radius; ! 931: bfg->classname = "bfg blast"; ! 932: bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav"); ! 933: ! 934: bfg->think = bfg_think; ! 935: bfg->nextthink = level.time + FRAMETIME; ! 936: bfg->teammaster = bfg; ! 937: bfg->teamchain = NULL; ! 938: ! 939: if (self->client) ! 940: check_dodge (self, bfg->s.origin, dir, speed); ! 941: ! 942: gi.linkentity (bfg); ! 943: } ! 944: ! 945: ! 946: // RAFAEL ! 947: ! 948: /* ! 949: fire_ionripper ! 950: */ ! 951: ! 952: void ionripper_sparks (edict_t *self) ! 953: { ! 954: gi.WriteByte (svc_temp_entity); ! 955: gi.WriteByte (TE_WELDING_SPARKS); ! 956: gi.WriteByte (0); ! 957: gi.WritePosition (self->s.origin); ! 958: gi.WriteDir (vec3_origin); ! 959: gi.WriteByte (0xe4 + (rand()&3)); ! 960: gi.multicast (self->s.origin, MULTICAST_PVS); ! 961: ! 962: G_FreeEdict (self); ! 963: } ! 964: ! 965: // RAFAEL ! 966: void ionripper_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 967: { ! 968: if (other == self->owner) ! 969: return; ! 970: ! 971: if (surf && (surf->flags & SURF_SKY)) ! 972: { ! 973: G_FreeEdict (self); ! 974: return; ! 975: } ! 976: ! 977: if (self->owner->client) ! 978: PlayerNoise (self->owner, self->s.origin, PNOISE_IMPACT); ! 979: ! 980: if (other->takedamage) ! 981: { ! 982: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, MOD_RIPPER); ! 983: ! 984: } ! 985: else ! 986: { ! 987: return; ! 988: } ! 989: ! 990: G_FreeEdict (self); ! 991: } ! 992: ! 993: ! 994: // RAFAEL ! 995: void fire_ionripper (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect) ! 996: { ! 997: edict_t *ion; ! 998: trace_t tr; ! 999: ! 1000: VectorNormalize (dir); ! 1001: ! 1002: ion = G_Spawn (); ! 1003: VectorCopy (start, ion->s.origin); ! 1004: VectorCopy (start, ion->s.old_origin); ! 1005: vectoangles (dir, ion->s.angles); ! 1006: VectorScale (dir, speed, ion->velocity); ! 1007: ! 1008: ion->movetype = MOVETYPE_WALLBOUNCE; ! 1009: ion->clipmask = MASK_SHOT; ! 1010: ion->solid = SOLID_BBOX; ! 1011: ion->s.effects |= effect; ! 1012: ! 1013: ion->s.renderfx |= RF_FULLBRIGHT; ! 1014: ! 1015: VectorClear (ion->mins); ! 1016: VectorClear (ion->maxs); ! 1017: ion->s.modelindex = gi.modelindex ("models/objects/boomrang/tris.md2"); ! 1018: ion->s.sound = gi.soundindex ("misc/lasfly.wav"); ! 1019: ion->owner = self; ! 1020: ion->touch = ionripper_touch; ! 1021: ion->nextthink = level.time + 3; ! 1022: ion->think = ionripper_sparks; ! 1023: ion->dmg = damage; ! 1024: ion->dmg_radius = 100; ! 1025: gi.linkentity (ion); ! 1026: ! 1027: if (self->client) ! 1028: check_dodge (self, ion->s.origin, dir, speed); ! 1029: ! 1030: tr = gi.trace (self->s.origin, NULL, NULL, ion->s.origin, ion, MASK_SHOT); ! 1031: if (tr.fraction < 1.0) ! 1032: { ! 1033: VectorMA (ion->s.origin, -10, dir, ion->s.origin); ! 1034: ion->touch (ion, tr.ent, NULL, NULL); ! 1035: } ! 1036: ! 1037: } ! 1038: ! 1039: ! 1040: // RAFAEL ! 1041: /* ! 1042: fire_heat ! 1043: */ ! 1044: ! 1045: ! 1046: void heat_think (edict_t *self) ! 1047: { ! 1048: edict_t *target = NULL; ! 1049: edict_t *aquire = NULL; ! 1050: vec3_t vec; ! 1051: vec3_t oldang; ! 1052: int len; ! 1053: int oldlen = 0; ! 1054: ! 1055: VectorClear (vec); ! 1056: ! 1057: // aquire new target ! 1058: while (( target = findradius (target, self->s.origin, 1024)) != NULL) ! 1059: { ! 1060: ! 1061: if (self->owner == target) ! 1062: continue; ! 1063: if (!target->svflags & SVF_MONSTER) ! 1064: continue; ! 1065: if (!target->client) ! 1066: continue; ! 1067: if (target->health <= 0) ! 1068: continue; ! 1069: if (!visible (self, target)) ! 1070: continue; ! 1071: ! 1072: // if we need to reduce the tracking cone ! 1073: /* ! 1074: { ! 1075: vec3_t vec; ! 1076: float dot; ! 1077: vec3_t forward; ! 1078: ! 1079: AngleVectors (self->s.angles, forward, NULL, NULL); ! 1080: VectorSubtract (target->s.origin, self->s.origin, vec); ! 1081: VectorNormalize (vec); ! 1082: dot = DotProduct (vec, forward); ! 1083: ! 1084: if (dot > 0.6) ! 1085: continue; ! 1086: } ! 1087: */ ! 1088: ! 1089: if (!infront (self, target)) ! 1090: continue; ! 1091: ! 1092: VectorSubtract (self->s.origin, target->s.origin, vec); ! 1093: len = VectorLength (vec); ! 1094: ! 1095: if (aquire == NULL || len < oldlen) ! 1096: { ! 1097: aquire = target; ! 1098: self->target_ent = aquire; ! 1099: oldlen = len; ! 1100: } ! 1101: } ! 1102: ! 1103: if (aquire != NULL) ! 1104: { ! 1105: VectorCopy (self->s.angles, oldang); ! 1106: VectorSubtract (aquire->s.origin, self->s.origin, vec); ! 1107: ! 1108: vectoangles (vec, self->s.angles); ! 1109: ! 1110: VectorNormalize (vec); ! 1111: VectorCopy (vec, self->movedir); ! 1112: VectorScale (vec, 500, self->velocity); ! 1113: } ! 1114: ! 1115: self->nextthink = level.time + 0.1; ! 1116: } ! 1117: ! 1118: // RAFAEL ! 1119: void fire_heat (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage) ! 1120: { ! 1121: edict_t *heat; ! 1122: ! 1123: heat = G_Spawn(); ! 1124: VectorCopy (start, heat->s.origin); ! 1125: VectorCopy (dir, heat->movedir); ! 1126: vectoangles (dir, heat->s.angles); ! 1127: VectorScale (dir, speed, heat->velocity); ! 1128: heat->movetype = MOVETYPE_FLYMISSILE; ! 1129: heat->clipmask = MASK_SHOT; ! 1130: heat->solid = SOLID_BBOX; ! 1131: heat->s.effects |= EF_ROCKET; ! 1132: VectorClear (heat->mins); ! 1133: VectorClear (heat->maxs); ! 1134: heat->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2"); ! 1135: heat->owner = self; ! 1136: heat->touch = rocket_touch; ! 1137: ! 1138: heat->nextthink = level.time + 0.1; ! 1139: heat->think = heat_think; ! 1140: ! 1141: heat->dmg = damage; ! 1142: heat->radius_dmg = radius_damage; ! 1143: heat->dmg_radius = damage_radius; ! 1144: heat->s.sound = gi.soundindex ("weapons/rockfly.wav"); ! 1145: ! 1146: if (self->client) ! 1147: check_dodge (self, heat->s.origin, dir, speed); ! 1148: ! 1149: gi.linkentity (heat); ! 1150: } ! 1151: ! 1152: ! 1153: ! 1154: // RAFAEL ! 1155: ! 1156: /* ! 1157: fire_plasma ! 1158: */ ! 1159: ! 1160: void plasma_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) ! 1161: { ! 1162: vec3_t origin; ! 1163: ! 1164: if (other == ent->owner) ! 1165: return; ! 1166: ! 1167: if (surf && (surf->flags & SURF_SKY)) ! 1168: { ! 1169: G_FreeEdict (ent); ! 1170: return; ! 1171: } ! 1172: ! 1173: if (ent->owner->client) ! 1174: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT); ! 1175: ! 1176: // calculate position for the explosion entity ! 1177: VectorMA (ent->s.origin, -0.02, ent->velocity, origin); ! 1178: ! 1179: if (other->takedamage) ! 1180: { ! 1181: T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_PHALANX); ! 1182: } ! 1183: ! 1184: T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_PHALANX); ! 1185: ! 1186: gi.WriteByte (svc_temp_entity); ! 1187: gi.WriteByte (TE_PLASMA_EXPLOSION); ! 1188: gi.WritePosition (origin); ! 1189: gi.multicast (ent->s.origin, MULTICAST_PVS); ! 1190: ! 1191: G_FreeEdict (ent); ! 1192: } ! 1193: ! 1194: ! 1195: // RAFAEL ! 1196: void fire_plasma (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage) ! 1197: { ! 1198: edict_t *plasma; ! 1199: ! 1200: plasma = G_Spawn(); ! 1201: VectorCopy (start, plasma->s.origin); ! 1202: VectorCopy (dir, plasma->movedir); ! 1203: vectoangles (dir, plasma->s.angles); ! 1204: VectorScale (dir, speed, plasma->velocity); ! 1205: plasma->movetype = MOVETYPE_FLYMISSILE; ! 1206: plasma->clipmask = MASK_SHOT; ! 1207: plasma->solid = SOLID_BBOX; ! 1208: ! 1209: VectorClear (plasma->mins); ! 1210: VectorClear (plasma->maxs); ! 1211: ! 1212: plasma->owner = self; ! 1213: plasma->touch = plasma_touch; ! 1214: plasma->nextthink = level.time + 8000/speed; ! 1215: plasma->think = G_FreeEdict; ! 1216: plasma->dmg = damage; ! 1217: plasma->radius_dmg = radius_damage; ! 1218: plasma->dmg_radius = damage_radius; ! 1219: plasma->s.sound = gi.soundindex ("weapons/rockfly.wav"); ! 1220: ! 1221: plasma->s.modelindex = gi.modelindex ("sprites/s_photon.sp2"); ! 1222: plasma->s.effects |= EF_PLASMA | EF_ANIM_ALLFAST; ! 1223: ! 1224: if (self->client) ! 1225: check_dodge (self, plasma->s.origin, dir, speed); ! 1226: ! 1227: gi.linkentity (plasma); ! 1228: ! 1229: ! 1230: } ! 1231: ! 1232: // RAFAEL ! 1233: extern void SP_item_foodcube (edict_t *best); ! 1234: // RAFAEL ! 1235: static void Trap_Think (edict_t *ent) ! 1236: { ! 1237: edict_t *target = NULL; ! 1238: edict_t *best = NULL; ! 1239: vec3_t vec; ! 1240: int len, i; ! 1241: int oldlen = 8000; ! 1242: vec3_t forward, right, up; ! 1243: ! 1244: if (ent->timestamp < level.time) ! 1245: { ! 1246: BecomeExplosion1(ent); ! 1247: // note to self ! 1248: // cause explosion damage??? ! 1249: return; ! 1250: } ! 1251: ! 1252: ent->nextthink = level.time + 0.1; ! 1253: ! 1254: if (!ent->groundentity) ! 1255: return; ! 1256: ! 1257: // ok lets do the blood effect ! 1258: if (ent->s.frame > 4) ! 1259: { ! 1260: if (ent->s.frame == 5) ! 1261: { ! 1262: if (ent->wait == 64) ! 1263: gi.sound(ent, CHAN_VOICE, gi.soundindex ("weapons/trapdown.wav"), 1, ATTN_IDLE, 0); ! 1264: ! 1265: ent->wait -= 2; ! 1266: ent->delay += level.time; ! 1267: ! 1268: for (i=0; i<3; i++) ! 1269: { ! 1270: ! 1271: best = G_Spawn(); ! 1272: ! 1273: if (strcmp (ent->enemy->classname, "monster_gekk") == 0) ! 1274: { ! 1275: best->s.modelindex = gi.modelindex ("models/objects/gekkgib/torso/tris.md2"); ! 1276: best->s.effects |= TE_GREENBLOOD; ! 1277: } ! 1278: else if (ent->mass > 200) ! 1279: { ! 1280: best->s.modelindex = gi.modelindex ("models/objects/gibs/chest/tris.md2"); ! 1281: best->s.effects |= TE_BLOOD; ! 1282: } ! 1283: else ! 1284: { ! 1285: best->s.modelindex = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2"); ! 1286: best->s.effects |= TE_BLOOD; ! 1287: } ! 1288: ! 1289: AngleVectors (ent->s.angles, forward, right, up); ! 1290: ! 1291: RotatePointAroundVector( vec, up, right, ((360.0/3)* i)+ent->delay); ! 1292: VectorMA (vec, ent->wait/2, vec, vec); ! 1293: VectorAdd(vec, ent->s.origin, vec); ! 1294: VectorAdd(vec, forward, best->s.origin); ! 1295: ! 1296: best->s.origin[2] = ent->s.origin[2] + ent->wait; ! 1297: ! 1298: VectorCopy (ent->s.angles, best->s.angles); ! 1299: ! 1300: best->solid = SOLID_NOT; ! 1301: best->s.effects |= EF_GIB; ! 1302: best->takedamage = DAMAGE_YES; ! 1303: ! 1304: best->movetype = MOVETYPE_TOSS; ! 1305: best->svflags |= SVF_MONSTER; ! 1306: best->deadflag = DEAD_DEAD; ! 1307: ! 1308: VectorClear (best->mins); ! 1309: VectorClear (best->maxs); ! 1310: ! 1311: best->watertype = gi.pointcontents(best->s.origin); ! 1312: if (best->watertype & MASK_WATER) ! 1313: best->waterlevel = 1; ! 1314: ! 1315: best->nextthink = level.time + 0.1; ! 1316: best->think = G_FreeEdict; ! 1317: gi.linkentity (best); ! 1318: } ! 1319: ! 1320: if (ent->wait < 19) ! 1321: ent->s.frame ++; ! 1322: ! 1323: return; ! 1324: } ! 1325: ent->s.frame ++; ! 1326: if (ent->s.frame == 8) ! 1327: { ! 1328: ent->nextthink = level.time + 1.0; ! 1329: ent->think = G_FreeEdict; ! 1330: ! 1331: best = G_Spawn (); ! 1332: SP_item_foodcube (best); ! 1333: VectorCopy (ent->s.origin, best->s.origin); ! 1334: best->s.origin[2]+= 16; ! 1335: best->velocity[2] = 400; ! 1336: best->count = ent->mass; ! 1337: gi.linkentity (best); ! 1338: return; ! 1339: } ! 1340: return; ! 1341: } ! 1342: ! 1343: ent->s.effects &= ~EF_TRAP; ! 1344: if (ent->s.frame >= 4) ! 1345: { ! 1346: ent->s.effects |= EF_TRAP; ! 1347: VectorClear (ent->mins); ! 1348: VectorClear (ent->maxs); ! 1349: ! 1350: } ! 1351: ! 1352: if (ent->s.frame < 4) ! 1353: ent->s.frame++; ! 1354: ! 1355: while ((target = findradius(target, ent->s.origin, 256)) != NULL) ! 1356: { ! 1357: if (target == ent) ! 1358: continue; ! 1359: if (!(target->svflags & SVF_MONSTER) && !target->client) ! 1360: continue; ! 1361: // if (target == ent->owner) ! 1362: // continue; ! 1363: if (target->health <= 0) ! 1364: continue; ! 1365: if (!visible (ent, target)) ! 1366: continue; ! 1367: if (!best) ! 1368: { ! 1369: best = target; ! 1370: continue; ! 1371: } ! 1372: VectorSubtract (ent->s.origin, target->s.origin, vec); ! 1373: len = VectorLength (vec); ! 1374: if (len < oldlen) ! 1375: { ! 1376: oldlen = len; ! 1377: best = target; ! 1378: } ! 1379: } ! 1380: ! 1381: // pull the enemy in ! 1382: if (best) ! 1383: { ! 1384: vec3_t forward; ! 1385: ! 1386: if (best->groundentity) ! 1387: { ! 1388: best->s.origin[2] += 1; ! 1389: best->groundentity = NULL; ! 1390: } ! 1391: VectorSubtract (ent->s.origin, best->s.origin, vec); ! 1392: len = VectorLength (vec); ! 1393: if (best->client) ! 1394: { ! 1395: VectorNormalize (vec); ! 1396: VectorMA (best->velocity, 250, vec, best->velocity); ! 1397: } ! 1398: else ! 1399: { ! 1400: best->ideal_yaw = vectoyaw(vec); ! 1401: M_ChangeYaw (best); ! 1402: AngleVectors (best->s.angles, forward, NULL, NULL); ! 1403: VectorScale (forward, 256, best->velocity); ! 1404: } ! 1405: ! 1406: gi.sound(ent, CHAN_VOICE, gi.soundindex ("weapons/trapsuck.wav"), 1, ATTN_IDLE, 0); ! 1407: ! 1408: if (len < 32) ! 1409: { ! 1410: if (best->mass < 400) ! 1411: { ! 1412: T_Damage (best, ent, ent->owner, vec3_origin, best->s.origin, vec3_origin, 100000, 1, 0, MOD_TRAP); ! 1413: ent->enemy = best; ! 1414: ent->wait = 64; ! 1415: VectorCopy (ent->s.origin, ent->s.old_origin); ! 1416: ent->timestamp = level.time + 30; ! 1417: if (deathmatch->value) ! 1418: ent->mass = best->mass/4; ! 1419: else ! 1420: ent->mass = best->mass/10; ! 1421: // ok spawn the food cube ! 1422: ent->s.frame = 5; ! 1423: } ! 1424: else ! 1425: { ! 1426: BecomeExplosion1(ent); ! 1427: // note to self ! 1428: // cause explosion damage??? ! 1429: return; ! 1430: } ! 1431: ! 1432: } ! 1433: } ! 1434: ! 1435: ! 1436: } ! 1437: ! 1438: ! 1439: // RAFAEL ! 1440: void fire_trap (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held) ! 1441: { ! 1442: edict_t *trap; ! 1443: vec3_t dir; ! 1444: vec3_t forward, right, up; ! 1445: ! 1446: vectoangles (aimdir, dir); ! 1447: AngleVectors (dir, forward, right, up); ! 1448: ! 1449: trap = G_Spawn(); ! 1450: VectorCopy (start, trap->s.origin); ! 1451: VectorScale (aimdir, speed, trap->velocity); ! 1452: VectorMA (trap->velocity, 200 + crandom() * 10.0, up, trap->velocity); ! 1453: VectorMA (trap->velocity, crandom() * 10.0, right, trap->velocity); ! 1454: VectorSet (trap->avelocity, 0, 300, 0); ! 1455: trap->movetype = MOVETYPE_BOUNCE; ! 1456: trap->clipmask = MASK_SHOT; ! 1457: trap->solid = SOLID_BBOX; ! 1458: // VectorClear (trap->mins); ! 1459: // VectorClear (trap->maxs); ! 1460: VectorSet (trap->mins, -4, -4, 0); ! 1461: VectorSet (trap->maxs, 4, 4, 8); ! 1462: trap->s.modelindex = gi.modelindex ("models/weapons/z_trap/tris.md2"); ! 1463: trap->owner = self; ! 1464: trap->nextthink = level.time + 1.0; ! 1465: trap->think = Trap_Think; ! 1466: trap->dmg = damage; ! 1467: trap->dmg_radius = damage_radius; ! 1468: trap->classname = "htrap"; ! 1469: // RAFAEL 16-APR-98 ! 1470: trap->s.sound = gi.soundindex ("weapons/traploop.wav"); ! 1471: // END 16-APR-98 ! 1472: if (held) ! 1473: trap->spawnflags = 3; ! 1474: else ! 1475: trap->spawnflags = 1; ! 1476: ! 1477: if (timer <= 0.0) ! 1478: Grenade_Explode (trap); ! 1479: else ! 1480: { ! 1481: // gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/trapdown.wav"), 1, ATTN_NORM, 0); ! 1482: gi.linkentity (trap); ! 1483: } ! 1484: ! 1485: trap->timestamp = level.time + 30; ! 1486: ! 1487: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.