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