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