|
|
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: 23: void InitTrigger (edict_t *self) 24: { 25: if (!VectorCompare (self->s.angles, vec3_origin)) 26: G_SetMovedir (self->s.angles, self->movedir); 27: 28: self->solid = SOLID_TRIGGER; 29: self->movetype = MOVETYPE_NONE; 30: gi.setmodel (self, self->model); 31: self->svflags = SVF_NOCLIENT; 32: } 33: 34: 35: // the wait time has passed, so set back up for another activation 36: void multi_wait (edict_t *ent) 37: { 38: ent->nextthink = 0; 39: } 40: 41: 42: // the trigger was just activated 43: // ent->activator should be set to the activator so it can be held through a delay 44: // so wait for the delay time before firing 45: void multi_trigger (edict_t *ent) 46: { 47: if (ent->nextthink) 48: return; // already been triggered 49: 50: G_UseTargets (ent, ent->activator); 51: 52: if (ent->wait > 0) 53: { 54: ent->think = multi_wait; 55: ent->nextthink = level.time + ent->wait; 56: } 57: else 58: { // we can't just remove (self) here, because this is a touch function 59: // called while looping through area links... 60: ent->touch = NULL; 61: ent->nextthink = level.time + FRAMETIME; 62: ent->think = G_FreeEdict; 63: } 64: } 65: 66: void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator) 67: { 68: ent->activator = activator; 69: multi_trigger (ent); 70: } 71: 72: void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 73: { 74: if(other->client) 75: { 76: if (self->spawnflags & 2) 77: return; 78: } 79: else if (other->svflags & SVF_MONSTER) 80: { 81: if (!(self->spawnflags & 1)) 82: return; 83: } 84: else 85: return; 86: 87: if (!VectorCompare(self->movedir, vec3_origin)) 88: { 89: vec3_t forward; 90: 91: AngleVectors(other->s.angles, forward, NULL, NULL); 92: if (_DotProduct(forward, self->movedir) < 0) 93: return; 94: } 95: 96: self->activator = other; 97: multi_trigger (self); 98: } 99: 100: /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED 101: Variable sized repeatable trigger. Must be targeted at one or more entities. 102: If "delay" is set, the trigger waits some time after activating before firing. 103: "wait" : Seconds between triggerings. (.2 default) 104: sounds 105: 1) secret 106: 2) beep beep 107: 3) large switch 108: 4) 109: set "message" to text string 110: */ 111: void trigger_enable (edict_t *self, edict_t *other, edict_t *activator) 112: { 113: self->solid = SOLID_TRIGGER; 114: self->use = Use_Multi; 115: gi.linkentity (self); 116: } 117: 118: void SP_trigger_multiple (edict_t *ent) 119: { 120: if (ent->sounds == 1) 121: ent->noise_index = gi.soundindex ("misc/secret.wav"); 122: else if (ent->sounds == 2) 123: ent->noise_index = gi.soundindex ("misc/talk.wav"); 124: else if (ent->sounds == 3) 125: ent->noise_index = gi.soundindex ("misc/trigger1.wav"); 126: 127: if (!ent->wait) 128: ent->wait = 0.2; 129: ent->touch = Touch_Multi; 130: ent->movetype = MOVETYPE_NONE; 131: ent->svflags |= SVF_NOCLIENT; 132: 133: 134: if (ent->spawnflags & 4) 135: { 136: ent->solid = SOLID_NOT; 137: ent->use = trigger_enable; 138: } 139: else 140: { 141: ent->solid = SOLID_TRIGGER; 142: ent->use = Use_Multi; 143: } 144: 145: if (!VectorCompare(ent->s.angles, vec3_origin)) 146: G_SetMovedir (ent->s.angles, ent->movedir); 147: 148: gi.setmodel (ent, ent->model); 149: gi.linkentity (ent); 150: } 151: 152: 153: /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED 154: Triggers once, then removes itself. 155: You must set the key "target" to the name of another object in the level that has a matching "targetname". 156: 157: If TRIGGERED, this trigger must be triggered before it is live. 158: 159: sounds 160: 1) secret 161: 2) beep beep 162: 3) large switch 163: 4) 164: 165: "message" string to be displayed when triggered 166: */ 167: 168: void SP_trigger_once(edict_t *ent) 169: { 170: // make old maps work because I messed up on flag assignments here 171: // triggered was on bit 1 when it should have been on bit 4 172: if (ent->spawnflags & 1) 173: { 174: vec3_t v; 175: 176: VectorMA (ent->mins, 0.5, ent->size, v); 177: ent->spawnflags &= ~1; 178: ent->spawnflags |= 4; 179: gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v)); 180: } 181: 182: ent->wait = -1; 183: SP_trigger_multiple (ent); 184: } 185: 186: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) 187: This fixed size trigger cannot be touched, it can only be fired by other events. 188: */ 189: void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator) 190: { 191: G_UseTargets (self, activator); 192: } 193: 194: void SP_trigger_relay (edict_t *self) 195: { 196: self->use = trigger_relay_use; 197: } 198: 199: 200: /* 201: ============================================================================== 202: 203: trigger_key 204: 205: ============================================================================== 206: */ 207: 208: /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8) 209: A relay trigger that only fires it's targets if player has the proper key. 210: Use "item" to specify the required key, for example "key_data_cd" 211: */ 212: void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator) 213: { 214: int index; 215: 216: if (!self->item) 217: return; 218: if (!activator->client) 219: return; 220: 221: index = ITEM_INDEX(self->item); 222: if (!activator->client->pers.inventory[index]) 223: { 224: if (level.time < self->touch_debounce_time) 225: return; 226: self->touch_debounce_time = level.time + 5.0; 227: gi.centerprintf (activator, "You need the %s", self->item->pickup_name); 228: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0); 229: return; 230: } 231: 232: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0); 233: if (coop->value) 234: { 235: int player; 236: edict_t *ent; 237: 238: if (strcmp(self->item->classname, "key_power_cube") == 0) 239: { 240: int cube; 241: 242: for (cube = 0; cube < 8; cube++) 243: if (activator->client->pers.power_cubes & (1 << cube)) 244: break; 245: for (player = 1; player <= game.maxclients; player++) 246: { 247: ent = &g_edicts[player]; 248: if (!ent->inuse) 249: continue; 250: if (!ent->client) 251: continue; 252: if (ent->client->pers.power_cubes & (1 << cube)) 253: { 254: ent->client->pers.inventory[index]--; 255: ent->client->pers.power_cubes &= ~(1 << cube); 256: } 257: } 258: } 259: else 260: { 261: for (player = 1; player <= game.maxclients; player++) 262: { 263: ent = &g_edicts[player]; 264: if (!ent->inuse) 265: continue; 266: if (!ent->client) 267: continue; 268: ent->client->pers.inventory[index] = 0; 269: } 270: } 271: } 272: else 273: { 274: activator->client->pers.inventory[index]--; 275: } 276: 277: G_UseTargets (self, activator); 278: 279: self->use = NULL; 280: } 281: 282: void SP_trigger_key (edict_t *self) 283: { 284: if (!st.item) 285: { 286: gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin)); 287: return; 288: } 289: self->item = FindItemByClassname (st.item); 290: 291: if (!self->item) 292: { 293: gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin)); 294: return; 295: } 296: 297: if (!self->target) 298: { 299: gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin)); 300: return; 301: } 302: 303: gi.soundindex ("misc/keytry.wav"); 304: gi.soundindex ("misc/keyuse.wav"); 305: 306: self->use = trigger_key_use; 307: } 308: 309: 310: /* 311: ============================================================================== 312: 313: trigger_counter 314: 315: ============================================================================== 316: */ 317: 318: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage 319: Acts as an intermediary for an action that takes multiple inputs. 320: 321: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. 322: 323: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. 324: */ 325: 326: void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator) 327: { 328: if (self->count == 0) 329: return; 330: 331: self->count--; 332: 333: if (self->count) 334: { 335: if (! (self->spawnflags & 1)) 336: { 337: gi.centerprintf(activator, "%i more to go...", self->count); 338: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); 339: } 340: return; 341: } 342: 343: if (! (self->spawnflags & 1)) 344: { 345: gi.centerprintf(activator, "Sequence completed!"); 346: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); 347: } 348: self->activator = activator; 349: multi_trigger (self); 350: } 351: 352: void SP_trigger_counter (edict_t *self) 353: { 354: self->wait = -1; 355: if (!self->count) 356: self->count = 2; 357: 358: self->use = trigger_counter_use; 359: } 360: 361: 362: /* 363: ============================================================================== 364: 365: trigger_always 366: 367: ============================================================================== 368: */ 369: 370: /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) 371: This trigger will always fire. It is activated by the world. 372: */ 373: void SP_trigger_always (edict_t *ent) 374: { 375: // we must have some delay to make sure our use targets are present 376: if (ent->delay < 0.2) 377: ent->delay = 0.2; 378: G_UseTargets(ent, ent); 379: } 380: 381: 382: /* 383: ============================================================================== 384: 385: trigger_push 386: 387: ============================================================================== 388: */ 389: 390: #define PUSH_ONCE 1 391: 392: static int windsound; 393: 394: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 395: { 396: if (strcmp(other->classname, "grenade") == 0) 397: { 398: VectorScale (self->movedir, self->speed * 10, other->velocity); 399: } 400: else if (other->health > 0) 401: { 402: VectorScale (self->movedir, self->speed * 10, other->velocity); 403: 404: if (other->client) 405: { 406: // don't take falling damage immediately from this 407: VectorCopy (other->velocity, other->client->oldvelocity); 408: if (other->fly_sound_debounce_time < level.time) 409: { 410: other->fly_sound_debounce_time = level.time + 1.5; 411: gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); 412: } 413: } 414: } 415: if (self->spawnflags & PUSH_ONCE) 416: G_FreeEdict (self); 417: } 418: 419: 420: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE 421: Pushes the player 422: "speed" defaults to 1000 423: */ 424: void SP_trigger_push (edict_t *self) 425: { 426: InitTrigger (self); 427: windsound = gi.soundindex ("misc/windfly.wav"); 428: self->touch = trigger_push_touch; 429: if (!self->speed) 430: self->speed = 1000; 431: gi.linkentity (self); 432: } 433: 434: 435: /* 436: ============================================================================== 437: 438: trigger_hurt 439: 440: ============================================================================== 441: */ 442: 443: /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW 444: Any entity that touches this will be hurt. 445: 446: It does dmg points of damage each server frame 447: 448: SILENT supresses playing the sound 449: SLOW changes the damage rate to once per second 450: NO_PROTECTION *nothing* stops the damage 451: 452: "dmg" default 5 (whole numbers only) 453: 454: */ 455: void hurt_use (edict_t *self, edict_t *other, edict_t *activator) 456: { 457: if (self->solid == SOLID_NOT) 458: self->solid = SOLID_TRIGGER; 459: else 460: self->solid = SOLID_NOT; 461: gi.linkentity (self); 462: 463: if (!(self->spawnflags & 2)) 464: self->use = NULL; 465: } 466: 467: 468: void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 469: { 470: int dflags; 471: 472: if (!other->takedamage) 473: return; 474: 475: if (self->timestamp > level.time) 476: return; 477: 478: if (self->spawnflags & 16) 479: self->timestamp = level.time + 1; 480: else 481: self->timestamp = level.time + FRAMETIME; 482: 483: if (!(self->spawnflags & 4)) 484: { 485: if ((level.framenum % 10) == 0) 486: gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); 487: } 488: 489: if (self->spawnflags & 8) 490: dflags = DAMAGE_NO_PROTECTION; 491: else 492: dflags = 0; 493: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT); 494: } 495: 496: void SP_trigger_hurt (edict_t *self) 497: { 498: InitTrigger (self); 499: 500: self->noise_index = gi.soundindex ("world/electro.wav"); 501: self->touch = hurt_touch; 502: 503: if (!self->dmg) 504: self->dmg = 5; 505: 506: if (self->spawnflags & 1) 507: self->solid = SOLID_NOT; 508: else 509: self->solid = SOLID_TRIGGER; 510: 511: if (self->spawnflags & 2) 512: self->use = hurt_use; 513: 514: gi.linkentity (self); 515: } 516: 517: 518: /* 519: ============================================================================== 520: 521: trigger_gravity 522: 523: ============================================================================== 524: */ 525: 526: /*QUAKED trigger_gravity (.5 .5 .5) ? 527: Changes the touching entites gravity to 528: the value of "gravity". 1.0 is standard 529: gravity for the level. 530: */ 531: 532: void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 533: { 534: other->gravity = self->gravity; 535: } 536: 537: void SP_trigger_gravity (edict_t *self) 538: { 539: if (st.gravity == 0) 540: { 541: gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin)); 542: G_FreeEdict (self); 543: return; 544: } 545: 546: InitTrigger (self); 547: self->gravity = atoi(st.gravity); 548: self->touch = trigger_gravity_touch; 549: } 550: 551: 552: /* 553: ============================================================================== 554: 555: trigger_monsterjump 556: 557: ============================================================================== 558: */ 559: 560: /*QUAKED trigger_monsterjump (.5 .5 .5) ? 561: Walking monsters that touch this will jump in the direction of the trigger's angle 562: "speed" default to 200, the speed thrown forward 563: "height" default to 200, the speed thrown upwards 564: */ 565: 566: void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 567: { 568: if (other->flags & (FL_FLY | FL_SWIM) ) 569: return; 570: if (other->svflags & SVF_DEADMONSTER) 571: return; 572: if ( !(other->svflags & SVF_MONSTER)) 573: return; 574: 575: // set XY even if not on ground, so the jump will clear lips 576: other->velocity[0] = self->movedir[0] * self->speed; 577: other->velocity[1] = self->movedir[1] * self->speed; 578: 579: if (!other->groundentity) 580: return; 581: 582: other->groundentity = NULL; 583: other->velocity[2] = self->movedir[2]; 584: } 585: 586: void SP_trigger_monsterjump (edict_t *self) 587: { 588: if (!self->speed) 589: self->speed = 200; 590: if (!st.height) 591: st.height = 200; 592: if (self->s.angles[YAW] == 0) 593: self->s.angles[YAW] = 360; 594: InitTrigger (self); 595: self->touch = trigger_monsterjump_touch; 596: self->movedir[2] = st.height; 597: } 598:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.