|
|
1.1.1.2 ! root 1: /* ! 2: Copyright (C) 1997-2001 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ 1.1 root 20: #include "g_local.h" 21: 22: /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) 23: Fire an origin based temp entity event to the clients. 24: "style" type byte 25: */ 26: void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator) 27: { 28: gi.WriteByte (svc_temp_entity); 29: gi.WriteByte (ent->style); 30: gi.WritePosition (ent->s.origin); 31: gi.multicast (ent->s.origin, MULTICAST_PVS); 32: } 33: 34: void SP_target_temp_entity (edict_t *ent) 35: { 36: ent->use = Use_Target_Tent; 37: } 38: 39: 40: //========================================================== 41: 42: //========================================================== 43: 44: /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable 45: "noise" wav file to play 46: "attenuation" 47: -1 = none, send to whole level 48: 1 = normal fighting sounds 49: 2 = idle sound level 50: 3 = ambient sound level 51: "volume" 0.0 to 1.0 52: 53: Normal sounds play each time the target is used. The reliable flag can be set for crucial voiceovers. 54: 55: Looped sounds are allways atten 3 / vol 1, and the use function toggles it on/off. 56: Multiple identical looping sounds will just increase volume without any speed cost. 57: */ 58: void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator) 59: { 60: int chan; 61: 62: if (ent->spawnflags & 3) 63: { // looping sound toggles 64: if (ent->s.sound) 65: ent->s.sound = 0; // turn it off 66: else 67: ent->s.sound = ent->noise_index; // start it 68: } 69: else 70: { // normal sound 71: if (ent->spawnflags & 4) 72: chan = CHAN_VOICE|CHAN_RELIABLE; 73: else 74: chan = CHAN_VOICE; 75: // use a positioned_sound, because this entity won't normally be 76: // sent to any clients because it is invisible 77: gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0); 78: } 79: } 80: 81: void SP_target_speaker (edict_t *ent) 82: { 83: char buffer[MAX_QPATH]; 84: 85: if(!st.noise) 86: { 87: gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin)); 88: return; 89: } 90: if (!strstr (st.noise, ".wav")) 91: Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise); 92: else 93: strncpy (buffer, st.noise, sizeof(buffer)); 94: ent->noise_index = gi.soundindex (buffer); 95: 96: if (!ent->volume) 97: ent->volume = 1.0; 98: 99: if (!ent->attenuation) 100: ent->attenuation = 1.0; 101: else if (ent->attenuation == -1) // use -1 so 0 defaults to 1 102: ent->attenuation = 0; 103: 104: // check for prestarted looping sound 105: if (ent->spawnflags & 1) 106: ent->s.sound = ent->noise_index; 107: 108: ent->use = Use_Target_Speaker; 109: 110: // must link the entity so we get areas and clusters so 111: // the server can determine who to send updates to 112: gi.linkentity (ent); 113: } 114: 115: 116: //========================================================== 117: 118: void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator) 119: { 120: if (ent->spawnflags & 1) 121: strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1); 122: else 123: strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1); 124: 125: game.helpchanged++; 126: } 127: 128: /*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1 129: When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars. 130: */ 131: void SP_target_help(edict_t *ent) 132: { 133: if (deathmatch->value) 134: { // auto-remove for deathmatch 135: G_FreeEdict (ent); 136: return; 137: } 138: 139: if (!ent->message) 140: { 141: gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin)); 142: G_FreeEdict (ent); 143: return; 144: } 145: ent->use = Use_Target_Help; 146: } 147: 148: //========================================================== 149: 150: /*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8) 151: Counts a secret found. 152: These are single use targets. 153: */ 154: void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator) 155: { 156: gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0); 157: 158: level.found_secrets++; 159: 160: G_UseTargets (ent, activator); 161: G_FreeEdict (ent); 162: } 163: 164: void SP_target_secret (edict_t *ent) 165: { 166: if (deathmatch->value) 167: { // auto-remove for deathmatch 168: G_FreeEdict (ent); 169: return; 170: } 171: 172: ent->use = use_target_secret; 173: if (!st.noise) 174: st.noise = "misc/secret.wav"; 175: ent->noise_index = gi.soundindex (st.noise); 176: ent->svflags = SVF_NOCLIENT; 177: level.total_secrets++; 178: // map bug hack 179: if (!stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624) 180: ent->message = "You have found a secret area."; 181: } 182: 183: //========================================================== 184: 185: /*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8) 186: Counts a goal completed. 187: These are single use targets. 188: */ 189: void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator) 190: { 191: gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0); 192: 193: level.found_goals++; 194: 195: if (level.found_goals == level.total_goals) 196: gi.configstring (CS_CDTRACK, "0"); 197: 198: G_UseTargets (ent, activator); 199: G_FreeEdict (ent); 200: } 201: 202: void SP_target_goal (edict_t *ent) 203: { 204: if (deathmatch->value) 205: { // auto-remove for deathmatch 206: G_FreeEdict (ent); 207: return; 208: } 209: 210: ent->use = use_target_goal; 211: if (!st.noise) 212: st.noise = "misc/secret.wav"; 213: ent->noise_index = gi.soundindex (st.noise); 214: ent->svflags = SVF_NOCLIENT; 215: level.total_goals++; 216: } 217: 218: //========================================================== 219: 220: 221: /*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) 222: Spawns an explosion temporary entity when used. 223: 224: "delay" wait this long before going off 225: "dmg" how much radius damage should be done, defaults to 0 226: */ 227: void target_explosion_explode (edict_t *self) 228: { 229: float save; 230: 231: gi.WriteByte (svc_temp_entity); 232: gi.WriteByte (TE_EXPLOSION1); 233: gi.WritePosition (self->s.origin); 234: gi.multicast (self->s.origin, MULTICAST_PHS); 235: 236: T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE); 237: 238: save = self->delay; 239: self->delay = 0; 240: G_UseTargets (self, self->activator); 241: self->delay = save; 242: } 243: 244: void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator) 245: { 246: self->activator = activator; 247: 248: if (!self->delay) 249: { 250: target_explosion_explode (self); 251: return; 252: } 253: 254: self->think = target_explosion_explode; 255: self->nextthink = level.time + self->delay; 256: } 257: 258: void SP_target_explosion (edict_t *ent) 259: { 260: ent->use = use_target_explosion; 261: ent->svflags = SVF_NOCLIENT; 262: } 263: 264: 265: //========================================================== 266: 267: /*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) 268: Changes level to "map" when fired 269: */ 270: void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator) 271: { 272: if (level.intermissiontime) 273: return; // allready activated 274: 275: if (!deathmatch->value && !coop->value) 276: { 277: if (g_edicts[1].health <= 0) 278: return; 279: } 280: 281: // if noexit, do a ton of damage to other 282: if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world) 283: { 284: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT); 285: return; 286: } 287: 288: // if multiplayer, let everyone know who hit the exit 289: if (deathmatch->value) 290: { 291: if (activator && activator->client) 292: gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname); 293: } 294: 295: // if going to a new unit, clear cross triggers 296: if (strstr(self->map, "*")) 297: game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK); 298: 299: BeginIntermission (self); 300: } 301: 302: void SP_target_changelevel (edict_t *ent) 303: { 304: if (!ent->map) 305: { 306: gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin)); 307: G_FreeEdict (ent); 308: return; 309: } 310: 311: // ugly hack because *SOMEBODY* screwed up their map 312: if((stricmp(level.mapname, "fact1") == 0) && (stricmp(ent->map, "fact3") == 0)) 313: ent->map = "fact3$secret1"; 314: 315: ent->use = use_target_changelevel; 316: ent->svflags = SVF_NOCLIENT; 317: } 318: 319: 320: //========================================================== 321: 322: /*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) 323: Creates a particle splash effect when used. 324: 325: Set "sounds" to one of the following: 326: 1) sparks 327: 2) blue water 328: 3) brown water 329: 4) slime 330: 5) lava 331: 6) blood 332: 333: "count" how many pixels in the splash 334: "dmg" if set, does a radius damage at this location when it splashes 335: useful for lava/sparks 336: */ 337: 338: void use_target_splash (edict_t *self, edict_t *other, edict_t *activator) 339: { 340: gi.WriteByte (svc_temp_entity); 341: gi.WriteByte (TE_SPLASH); 342: gi.WriteByte (self->count); 343: gi.WritePosition (self->s.origin); 344: gi.WriteDir (self->movedir); 345: gi.WriteByte (self->sounds); 346: gi.multicast (self->s.origin, MULTICAST_PVS); 347: 348: if (self->dmg) 349: T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH); 350: } 351: 352: void SP_target_splash (edict_t *self) 353: { 354: self->use = use_target_splash; 355: G_SetMovedir (self->s.angles, self->movedir); 356: 357: if (!self->count) 358: self->count = 32; 359: 360: self->svflags = SVF_NOCLIENT; 361: } 362: 363: 364: //========================================================== 365: 366: /*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) 367: Set target to the type of entity you want spawned. 368: Useful for spawning monsters and gibs in the factory levels. 369: 370: For monsters: 371: Set direction to the facing you want it to have. 372: 373: For gibs: 374: Set direction if you want it moving and 375: speed how fast it should be moving otherwise it 376: will just be dropped 377: */ 378: void ED_CallSpawn (edict_t *ent); 379: 380: void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator) 381: { 382: edict_t *ent; 383: 384: ent = G_Spawn(); 385: ent->classname = self->target; 386: VectorCopy (self->s.origin, ent->s.origin); 387: VectorCopy (self->s.angles, ent->s.angles); 388: ED_CallSpawn (ent); 389: gi.unlinkentity (ent); 390: KillBox (ent); 391: gi.linkentity (ent); 392: if (self->speed) 393: VectorCopy (self->movedir, ent->velocity); 394: } 395: 396: void SP_target_spawner (edict_t *self) 397: { 398: self->use = use_target_spawner; 399: self->svflags = SVF_NOCLIENT; 400: if (self->speed) 401: { 402: G_SetMovedir (self->s.angles, self->movedir); 403: VectorScale (self->movedir, self->speed, self->movedir); 404: } 405: } 406: 407: //========================================================== 408: 409: /*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS 410: Fires a blaster bolt in the set direction when triggered. 411: 412: dmg default is 15 413: speed default is 1000 414: */ 415: 416: void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator) 417: { 418: int effect; 419: 420: if (self->spawnflags & 2) 421: effect = 0; 422: else if (self->spawnflags & 1) 423: effect = EF_HYPERBLASTER; 424: else 425: effect = EF_BLASTER; 426: 427: fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER); 428: gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0); 429: } 430: 431: void SP_target_blaster (edict_t *self) 432: { 433: self->use = use_target_blaster; 434: G_SetMovedir (self->s.angles, self->movedir); 435: self->noise_index = gi.soundindex ("weapons/laser2.wav"); 436: 437: if (!self->dmg) 438: self->dmg = 15; 439: if (!self->speed) 440: self->speed = 1000; 441: 442: self->svflags = SVF_NOCLIENT; 443: } 444: 445: 446: //========================================================== 447: 448: /*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 449: Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work. 450: */ 451: void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator) 452: { 453: game.serverflags |= self->spawnflags; 454: G_FreeEdict (self); 455: } 456: 457: void SP_target_crosslevel_trigger (edict_t *self) 458: { 459: self->svflags = SVF_NOCLIENT; 460: self->use = trigger_crosslevel_trigger_use; 461: } 462: 463: /*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 464: Triggered by a trigger_crosslevel elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and 465: killtarget also work. 466: 467: "delay" delay before using targets if the trigger has been activated (default 1) 468: */ 469: void target_crosslevel_target_think (edict_t *self) 470: { 471: if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags)) 472: { 473: G_UseTargets (self, self); 474: G_FreeEdict (self); 475: } 476: } 477: 478: void SP_target_crosslevel_target (edict_t *self) 479: { 480: if (! self->delay) 481: self->delay = 1; 482: self->svflags = SVF_NOCLIENT; 483: 484: self->think = target_crosslevel_target_think; 485: self->nextthink = level.time + self->delay; 486: } 487: 488: //========================================================== 489: 490: /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT 491: When triggered, fires a laser. You can either set a target 492: or a direction. 493: */ 494: 495: void target_laser_think (edict_t *self) 496: { 497: edict_t *ignore; 498: vec3_t start; 499: vec3_t end; 500: trace_t tr; 501: vec3_t point; 502: vec3_t last_movedir; 503: int count; 504: 505: if (self->spawnflags & 0x80000000) 506: count = 8; 507: else 508: count = 4; 509: 510: if (self->enemy) 511: { 512: VectorCopy (self->movedir, last_movedir); 513: VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point); 514: VectorSubtract (point, self->s.origin, self->movedir); 515: VectorNormalize (self->movedir); 516: if (!VectorCompare(self->movedir, last_movedir)) 517: self->spawnflags |= 0x80000000; 518: } 519: 520: ignore = self; 521: VectorCopy (self->s.origin, start); 522: VectorMA (start, 2048, self->movedir, end); 523: while(1) 524: { 525: tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER); 526: 527: if (!tr.ent) 528: break; 529: 530: // hurt it if we can 531: if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER)) 532: T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER); 533: 534: // if we hit something that's not a monster or player or is immune to lasers, we're done 535: if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) 536: { 537: if (self->spawnflags & 0x80000000) 538: { 539: self->spawnflags &= ~0x80000000; 540: gi.WriteByte (svc_temp_entity); 541: gi.WriteByte (TE_LASER_SPARKS); 542: gi.WriteByte (count); 543: gi.WritePosition (tr.endpos); 544: gi.WriteDir (tr.plane.normal); 545: gi.WriteByte (self->s.skinnum); 546: gi.multicast (tr.endpos, MULTICAST_PVS); 547: } 548: break; 549: } 550: 551: ignore = tr.ent; 552: VectorCopy (tr.endpos, start); 553: } 554: 555: VectorCopy (tr.endpos, self->s.old_origin); 556: 557: self->nextthink = level.time + FRAMETIME; 558: } 559: 560: void target_laser_on (edict_t *self) 561: { 562: if (!self->activator) 563: self->activator = self; 564: self->spawnflags |= 0x80000001; 565: self->svflags &= ~SVF_NOCLIENT; 566: target_laser_think (self); 567: } 568: 569: void target_laser_off (edict_t *self) 570: { 571: self->spawnflags &= ~1; 572: self->svflags |= SVF_NOCLIENT; 573: self->nextthink = 0; 574: } 575: 576: void target_laser_use (edict_t *self, edict_t *other, edict_t *activator) 577: { 578: self->activator = activator; 579: if (self->spawnflags & 1) 580: target_laser_off (self); 581: else 582: target_laser_on (self); 583: } 584: 585: void target_laser_start (edict_t *self) 586: { 587: edict_t *ent; 588: 589: self->movetype = MOVETYPE_NONE; 590: self->solid = SOLID_NOT; 591: self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT; 592: self->s.modelindex = 1; // must be non-zero 593: 594: // set the beam diameter 595: if (self->spawnflags & 64) 596: self->s.frame = 16; 597: else 598: self->s.frame = 4; 599: 600: // set the color 601: if (self->spawnflags & 2) 602: self->s.skinnum = 0xf2f2f0f0; 603: else if (self->spawnflags & 4) 604: self->s.skinnum = 0xd0d1d2d3; 605: else if (self->spawnflags & 8) 606: self->s.skinnum = 0xf3f3f1f1; 607: else if (self->spawnflags & 16) 608: self->s.skinnum = 0xdcdddedf; 609: else if (self->spawnflags & 32) 610: self->s.skinnum = 0xe0e1e2e3; 611: 612: if (!self->enemy) 613: { 614: if (self->target) 615: { 616: ent = G_Find (NULL, FOFS(targetname), self->target); 617: if (!ent) 618: gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target); 619: self->enemy = ent; 620: } 621: else 622: { 623: G_SetMovedir (self->s.angles, self->movedir); 624: } 625: } 626: self->use = target_laser_use; 627: self->think = target_laser_think; 628: 629: if (!self->dmg) 630: self->dmg = 1; 631: 632: VectorSet (self->mins, -8, -8, -8); 633: VectorSet (self->maxs, 8, 8, 8); 634: gi.linkentity (self); 635: 636: if (self->spawnflags & 1) 637: target_laser_on (self); 638: else 639: target_laser_off (self); 640: } 641: 642: void SP_target_laser (edict_t *self) 643: { 644: // let everything else get spawned before we start firing 645: self->think = target_laser_start; 646: self->nextthink = level.time + 1; 647: } 648: 649: //========================================================== 650: 651: /*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE 652: speed How many seconds the ramping will take 653: message two letters; starting lightlevel and ending lightlevel 654: */ 655: 656: void target_lightramp_think (edict_t *self) 657: { 658: char style[2]; 659: 660: style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2]; 661: style[1] = 0; 662: gi.configstring (CS_LIGHTS+self->enemy->style, style); 663: 664: if ((level.time - self->timestamp) < self->speed) 665: { 666: self->nextthink = level.time + FRAMETIME; 667: } 668: else if (self->spawnflags & 1) 669: { 670: char temp; 671: 672: temp = self->movedir[0]; 673: self->movedir[0] = self->movedir[1]; 674: self->movedir[1] = temp; 675: self->movedir[2] *= -1; 676: } 677: } 678: 679: void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator) 680: { 681: if (!self->enemy) 682: { 683: edict_t *e; 684: 685: // check all the targets 686: e = NULL; 687: while (1) 688: { 689: e = G_Find (e, FOFS(targetname), self->target); 690: if (!e) 691: break; 692: if (strcmp(e->classname, "light") != 0) 693: { 694: gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin)); 695: gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin)); 696: } 697: else 698: { 699: self->enemy = e; 700: } 701: } 702: 703: if (!self->enemy) 704: { 705: gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin)); 706: G_FreeEdict (self); 707: return; 708: } 709: } 710: 711: self->timestamp = level.time; 712: target_lightramp_think (self); 713: } 714: 715: void SP_target_lightramp (edict_t *self) 716: { 717: if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1]) 718: { 719: gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin)); 720: G_FreeEdict (self); 721: return; 722: } 723: 724: if (deathmatch->value) 725: { 726: G_FreeEdict (self); 727: return; 728: } 729: 730: if (!self->target) 731: { 732: gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin)); 733: G_FreeEdict (self); 734: return; 735: } 736: 737: self->svflags |= SVF_NOCLIENT; 738: self->use = target_lightramp_use; 739: self->think = target_lightramp_think; 740: 741: self->movedir[0] = self->message[0] - 'a'; 742: self->movedir[1] = self->message[1] - 'a'; 743: self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME); 744: } 745: 746: //========================================================== 747: 748: /*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) 749: When triggered, this initiates a level-wide earthquake. 750: All players and monsters are affected. 751: "speed" severity of the quake (default:200) 752: "count" duration of the quake (default:5) 753: */ 754: 755: void target_earthquake_think (edict_t *self) 756: { 757: int i; 758: edict_t *e; 759: 760: if (self->last_move_time < level.time) 761: { 762: gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0); 763: self->last_move_time = level.time + 0.5; 764: } 765: 766: for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++) 767: { 768: if (!e->inuse) 769: continue; 770: if (!e->client) 771: continue; 772: if (!e->groundentity) 773: continue; 774: 775: e->groundentity = NULL; 776: e->velocity[0] += crandom()* 150; 777: e->velocity[1] += crandom()* 150; 778: e->velocity[2] = self->speed * (100.0 / e->mass); 779: } 780: 781: if (level.time < self->timestamp) 782: self->nextthink = level.time + FRAMETIME; 783: } 784: 785: void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator) 786: { 787: self->timestamp = level.time + self->count; 788: self->nextthink = level.time + FRAMETIME; 789: self->activator = activator; 790: self->last_move_time = 0; 791: } 792: 793: void SP_target_earthquake (edict_t *self) 794: { 795: if (!self->targetname) 796: gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin)); 797: 798: if (!self->count) 799: self->count = 5; 800: 801: if (!self->speed) 802: self->speed = 200; 803: 804: self->svflags |= SVF_NOCLIENT; 805: self->think = target_earthquake_think; 806: self->use = target_earthquake_use; 807: 808: self->noise_index = gi.soundindex ("world/quake.wav"); 809: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.