2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * New Triggers and Switches.
37 #include "editor/editor.h"
41 trigger Triggers[MAX_TRIGGERS];
44 //link Links[MAX_WALL_LINKS];
48 fix trigger_time_count=F1_0;
50 //-----------------------------------------------------------------
51 // Initializes all the switches.
58 for (i=0;i<MAX_TRIGGERS;i++)
61 Triggers[i].flags = 0;
62 Triggers[i].num_links = 0;
63 Triggers[i].value = 0;
64 Triggers[i].time = -1;
69 //-----------------------------------------------------------------
70 // Executes a link, attached to a trigger.
71 // Toggles all walls linked to the switch.
72 // Opens doors, Blasts blast walls, turns off illusions.
73 void do_link(sbyte trigger_num)
77 mprintf((0, "Door link!\n"));
79 if (trigger_num != -1) {
80 for (i=0;i<Triggers[trigger_num].num_links;i++) {
81 wall_toggle(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
82 mprintf((0," trigger_num %d : seg %d, side %d\n",
83 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
89 void do_close_door(sbyte trigger_num)
93 mprintf((0, "Door close!\n"));
95 if (trigger_num != -1) {
96 for (i=0;i<Triggers[trigger_num].num_links;i++)
97 wall_close_door(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
101 //turns lighting on. returns true if lights were actually turned on. (they
102 //would not be if they had previously been shot out).
103 int do_light_on(sbyte trigger_num)
107 mprintf((0, "Lighting on!\n"));
109 if (trigger_num != -1) {
110 for (i=0;i<Triggers[trigger_num].num_links;i++) {
112 segnum = Triggers[trigger_num].seg[i];
113 sidenum = Triggers[trigger_num].side[i];
115 //check if tmap2 casts light before turning the light on. This
116 //is to keep us from turning on blown-out lights
117 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
118 ret |= add_light(segnum, sidenum); //any light sets flag
119 enable_flicker(segnum, sidenum);
127 //turns lighting off. returns true if lights were actually turned off. (they
128 //would not be if they had previously been shot out).
129 int do_light_off(sbyte trigger_num)
133 mprintf((0, "Lighting off!\n"));
135 if (trigger_num != -1) {
136 for (i=0;i<Triggers[trigger_num].num_links;i++) {
138 segnum = Triggers[trigger_num].seg[i];
139 sidenum = Triggers[trigger_num].side[i];
141 //check if tmap2 casts light before turning the light off. This
142 //is to keep us from turning off blown-out lights
143 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
144 ret |= subtract_light(segnum, sidenum); //any light sets flag
145 disable_flicker(segnum, sidenum);
153 // Unlocks all doors linked to the switch.
154 void do_unlock_doors(sbyte trigger_num)
158 mprintf((0, "Door unlock!\n"));
160 if (trigger_num != -1) {
161 for (i=0;i<Triggers[trigger_num].num_links;i++) {
162 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags &= ~WALL_DOOR_LOCKED;
163 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].keys = KEY_NONE;
168 // Return trigger number if door is controlled by a wall switch, else return -1.
169 int door_is_wall_switched(int wall_num)
173 for (t=0; t<Num_triggers; t++) {
174 for (i=0; i<Triggers[t].num_links; i++) {
175 if (Segments[Triggers[t].seg[i]].sides[Triggers[t].side[i]].wall_num == wall_num) {
176 mprintf((0, "Wall #%i is keyed to trigger #%i, link #%i\n", wall_num, t, i));
185 void flag_wall_switched_doors(void)
189 for (i=0; i<Num_walls; i++) {
190 if (door_is_wall_switched(i))
191 Walls[i].flags |= WALL_WALL_SWITCH;
196 // Locks all doors linked to the switch.
197 void do_lock_doors(sbyte trigger_num)
201 mprintf((0, "Door lock!\n"));
203 if (trigger_num != -1) {
204 for (i=0;i<Triggers[trigger_num].num_links;i++) {
205 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags |= WALL_DOOR_LOCKED;
210 // Changes walls pointed to by a trigger. returns true if any walls changed
211 int do_change_walls(sbyte trigger_num)
215 mprintf((0, "Wall remove!\n"));
217 if (trigger_num != -1) {
218 for (i=0;i<Triggers[trigger_num].num_links;i++) {
219 segment *segp,*csegp;
223 segp = &Segments[Triggers[trigger_num].seg[i]];
224 side = Triggers[trigger_num].side[i];
226 if (segp->children[side] < 0)
233 csegp = &Segments[segp->children[side]];
234 cside = find_connect_side(segp, csegp);
238 //segp->sides[side].wall_num = -1;
239 //csegp->sides[cside].wall_num = -1;
241 switch (Triggers[trigger_num].type) {
242 case TT_OPEN_WALL: new_wall_type = WALL_OPEN; break;
243 case TT_CLOSE_WALL: new_wall_type = WALL_CLOSED; break;
244 case TT_ILLUSORY_WALL: new_wall_type = WALL_ILLUSION; break;
246 Assert(0); /* new_wall_type unset */
251 if (Walls[segp->sides[side].wall_num].type == new_wall_type &&
252 (cside < 0 || csegp->sides[cside].wall_num < 0 ||
253 Walls[csegp->sides[cside].wall_num].type == new_wall_type))
254 continue; //already in correct state, so skip
258 switch (Triggers[trigger_num].type) {
261 mprintf((0,"Open wall\n"));
263 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
265 compute_center_point_on_side(&pos, segp, side );
266 digi_link_sound_to_pos( SOUND_FORCEFIELD_OFF, SEGMENT_NUMBER(segp), side, &pos, 0, F1_0 );
267 Walls[segp->sides[side].wall_num].type = new_wall_type;
268 digi_kill_sound_linked_to_segment(SEGMENT_NUMBER(segp), side, SOUND_FORCEFIELD_HUM);
269 if (cside > -1 && csegp->sides[cside].wall_num > -1)
271 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
272 digi_kill_sound_linked_to_segment(SEGMENT_NUMBER(csegp), cside, SOUND_FORCEFIELD_HUM);
276 start_wall_cloak(segp,side);
283 mprintf((0,"Close wall\n"));
285 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
287 compute_center_point_on_side(&pos, segp, side );
288 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM, SEGMENT_NUMBER(segp), side, &pos, 1, F1_0/2);
289 Walls[segp->sides[side].wall_num].type = new_wall_type;
290 if (cside > -1 && csegp->sides[cside].wall_num > -1)
291 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
294 start_wall_decloak(segp,side);
297 case TT_ILLUSORY_WALL:
298 mprintf((0,"Illusory wall\n"));
299 Walls[segp->sides[side].wall_num].type = new_wall_type;
300 if (cside > -1 && csegp->sides[cside].wall_num > -1)
301 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
306 kill_stuck_objects(segp->sides[side].wall_num);
307 if (cside > -1 && csegp->sides[cside].wall_num > -1)
308 kill_stuck_objects(csegp->sides[cside].wall_num);
316 void print_trigger_message (int pnum,int trig,int shot,char *message)
318 char *pl; //points to 's' or nothing for plural word
320 if (pnum!=Player_num)
323 pl = (Triggers[trig].num_links>1)?"s":"";
325 if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
326 HUD_init_message (message,pl);
330 void do_matcen(sbyte trigger_num)
334 mprintf((0, "Matcen link!\n"));
336 if (trigger_num != -1) {
337 for (i=0;i<Triggers[trigger_num].num_links;i++) {
338 trigger_matcen(Triggers[trigger_num].seg[i] );
339 mprintf((0," trigger_num %d : seg %d\n",
340 trigger_num, Triggers[trigger_num].seg[i]));
346 void do_il_on(sbyte trigger_num)
350 mprintf((0, "Illusion ON\n"));
352 if (trigger_num != -1) {
353 for (i=0;i<Triggers[trigger_num].num_links;i++) {
354 wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
355 mprintf((0," trigger_num %d : seg %d, side %d\n",
356 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
361 void do_il_off(sbyte trigger_num)
365 mprintf((0, "Illusion OFF\n"));
367 if (trigger_num != -1) {
368 for (i=0;i<Triggers[trigger_num].num_links;i++) {
370 segment *seg = &Segments[Triggers[trigger_num].seg[i]];
371 int side = Triggers[trigger_num].side[i];
373 wall_illusion_off(seg, side);
375 mprintf((0," trigger_num %d : seg %d, side %d\n",
376 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
378 compute_center_point_on_side(&cp, seg, side );
379 digi_link_sound_to_pos( SOUND_WALL_REMOVED, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
385 extern void EnterSecretLevel(void);
386 extern void ExitSecretLevel(void);
387 extern int p_secret_level_destroyed(void);
389 int wall_is_forcefield(trigger *trig)
393 for (i=0;i<trig->num_links;i++)
394 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
397 return (i<trig->num_links);
400 int check_trigger_sub(int trigger_num, int pnum,int shot)
402 trigger *trig = &Triggers[trigger_num];
404 mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
406 if (trig->flags & TF_DISABLED)
407 return 1; //1 means don't send trigger hit to other players
409 if (trig->flags & TF_ONE_SHOT) //if this is a one-shot...
410 trig->flags |= TF_DISABLED; //..then don't let it happen again
412 switch (trig->type) {
416 if (pnum!=Player_num)
419 digi_stop_all(); //kill the sounds
421 if (Current_level_num > 0) {
422 start_endlevel_sequence();
423 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
424 } else if (Current_level_num < 0) {
425 if ((Players[Player_num].shields < 0) || Player_is_dead)
432 nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
434 Int3(); //level num == 0, but no editor!
440 case TT_SECRET_EXIT: {
445 if (pnum!=Player_num)
448 if ((Players[Player_num].shields < 0) || Player_is_dead)
451 if (Game_mode & GM_MULTI) {
452 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
453 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
458 truth = p_secret_level_destroyed();
460 if (Newdemo_state == ND_STATE_RECORDING) // record whether we're really going to the secret level
461 newdemo_record_secret_exit_blown(truth);
463 if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
464 HUD_init_message("Secret Level destroyed. Exit disabled.");
465 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
471 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
472 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
476 if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording
477 Newdemo_state = ND_STATE_PAUSED;
479 digi_stop_all(); //kill the sounds
481 digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
482 mprintf((0,"Exiting to secret level\n"));
484 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
485 // -- BOGUS -- IMPOSSIBLE -- multi_send_endlevel_start(1);
486 // -- BOGUS -- IMPOSSIBLE --
487 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
488 // -- BOGUS -- IMPOSSIBLE -- network_do_frame(1, 1);
490 gr_palette_fade_out(gr_palette, 32, 0);
492 Control_center_destroyed = 0;
500 do_link(trigger_num);
501 print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
506 do_close_door(trigger_num);
507 print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
512 do_unlock_doors(trigger_num);
513 print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
519 do_lock_doors(trigger_num);
520 print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
525 if (do_change_walls(trigger_num))
527 if (wall_is_forcefield(trig))
528 print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
530 print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
535 if (do_change_walls(trigger_num))
537 if (wall_is_forcefield(trig))
538 print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
540 print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
544 case TT_ILLUSORY_WALL:
545 //don't know what to say, so say nothing
546 do_change_walls(trigger_num);
550 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
551 do_matcen(trigger_num);
556 do_il_on(trigger_num);
557 print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
560 case TT_ILLUSION_OFF:
562 do_il_off(trigger_num);
563 print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
567 if (do_light_off(trigger_num))
568 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
572 if (do_light_on(trigger_num))
573 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
585 //-----------------------------------------------------------------
586 // Checks for a trigger whenever an object hits a trigger side.
587 void check_trigger(segment *seg, short side, short objnum,int shot)
589 int wall_num, trigger_num; //, ctrigger_num;
595 if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
597 if ( Newdemo_state == ND_STATE_RECORDING )
598 newdemo_record_trigger( SEGMENT_NUMBER(seg), side, objnum, shot );
600 wall_num = seg->sides[side].wall_num;
601 if ( wall_num == -1 ) return;
603 trigger_num = Walls[wall_num].trigger;
605 if (trigger_num == -1)
608 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
609 //## if (Triggers[trigger_num].type == TT_EXIT) {
610 //## start_endlevel_sequence();
615 if (check_trigger_sub(trigger_num, Player_num,shot))
618 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
619 //@@ Triggers[trigger_num].flags &= ~TRIGGER_ON;
621 //@@ csegp = &Segments[seg->children[side]];
622 //@@ cside = find_connect_side(seg, csegp);
623 //@@ Assert(cside != -1);
625 //@@ wall_num = csegp->sides[cside].wall_num;
626 //@@ if ( wall_num == -1 ) return;
628 //@@ ctrigger_num = Walls[wall_num].trigger;
630 //@@ Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
634 if (Game_mode & GM_MULTI)
635 multi_send_trigger(trigger_num);
640 void triggers_frame_process()
644 for (i=0;i<Num_triggers;i++)
645 if (Triggers[i].time >= 0)
646 Triggers[i].time -= FrameTime;
651 * reads a v29_trigger structure from a CFILE
653 extern void v29_trigger_read(v29_trigger *t, CFILE *fp)
657 t->type = cfile_read_byte(fp);
658 t->flags = cfile_read_short(fp);
659 t->value = cfile_read_fix(fp);
660 t->time = cfile_read_fix(fp);
661 t->link_num = cfile_read_byte(fp);
662 t->num_links = cfile_read_short(fp);
663 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
664 t->seg[i] = cfile_read_short(fp);
665 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
666 t->side[i] = cfile_read_short(fp);
670 * reads a v30_trigger structure from a CFILE
672 extern void v30_trigger_read(v30_trigger *t, CFILE *fp)
676 t->flags = cfile_read_short(fp);
677 t->num_links = cfile_read_byte(fp);
678 t->pad = cfile_read_byte(fp);
679 t->value = cfile_read_fix(fp);
680 t->time = cfile_read_fix(fp);
681 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
682 t->seg[i] = cfile_read_short(fp);
683 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
684 t->side[i] = cfile_read_short(fp);
688 * reads a trigger structure from a CFILE
690 extern void trigger_read(trigger *t, CFILE *fp)
694 t->type = cfile_read_byte(fp);
695 t->flags = cfile_read_byte(fp);
696 t->num_links = cfile_read_byte(fp);
697 t->pad = cfile_read_byte(fp);
698 t->value = cfile_read_fix(fp);
699 t->time = cfile_read_fix(fp);
700 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
701 t->seg[i] = cfile_read_short(fp);
702 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
703 t->side[i] = cfile_read_short(fp);
707 void trigger_write(trigger *t, short version, PHYSFS_file *fp)
712 PHYSFSX_writeU8(fp, t->type);
718 PHYSFS_writeSLE16(fp, TRIGGER_CONTROL_DOORS);
722 PHYSFS_writeSLE16(fp, TRIGGER_EXIT);
726 PHYSFS_writeSLE16(fp, TRIGGER_MATCEN);
729 case TT_ILLUSION_OFF:
730 PHYSFS_writeSLE16(fp, TRIGGER_ILLUSION_OFF);
734 PHYSFS_writeSLE16(fp, TRIGGER_SECRET_EXIT);
738 PHYSFS_writeSLE16(fp, TRIGGER_ILLUSION_ON);
742 PHYSFS_writeSLE16(fp, TRIGGER_UNLOCK_DOORS);
746 PHYSFS_writeSLE16(fp, TRIGGER_OPEN_WALL);
750 PHYSFS_writeSLE16(fp, TRIGGER_CLOSE_WALL);
753 case TT_ILLUSORY_WALL:
754 PHYSFS_writeSLE16(fp, TRIGGER_ILLUSORY_WALL);
759 PHYSFS_writeSLE16(fp, 0);
763 PHYSFSX_writeU8(fp, t->flags);
767 PHYSFSX_writeU8(fp, t->num_links);
768 PHYSFSX_writeU8(fp, t->pad);
771 PHYSFSX_writeFix(fp, t->value);
772 PHYSFSX_writeFix(fp, t->time);
776 PHYSFSX_writeU8(fp, -1); //t->link_num
777 PHYSFS_writeSLE16(fp, t->num_links);
780 for (i = 0; i < MAX_WALLS_PER_LINK; i++)
781 PHYSFS_writeSLE16(fp, t->seg[i]);
782 for (i = 0; i < MAX_WALLS_PER_LINK; i++)
783 PHYSFS_writeSLE16(fp, t->side[i]);