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