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 static char rcsid[] = "$Id: switch.c,v 1.2 2001-01-20 13:49:18 bradleyb Exp $";
50 #include "editor\editor.h"
53 trigger Triggers[MAX_TRIGGERS];
56 //link Links[MAX_WALL_LINKS];
60 fix trigger_time_count=F1_0;
62 //-----------------------------------------------------------------
63 // Initializes all the switches.
70 for (i=0;i<MAX_TRIGGERS;i++)
73 Triggers[i].flags = 0;
74 Triggers[i].num_links = 0;
75 Triggers[i].value = 0;
76 Triggers[i].time = -1;
81 //-----------------------------------------------------------------
82 // Executes a link, attached to a trigger.
83 // Toggles all walls linked to the switch.
84 // Opens doors, Blasts blast walls, turns off illusions.
85 void do_link(byte trigger_num)
89 mprintf((0, "Door link!\n"));
91 if (trigger_num != -1) {
92 for (i=0;i<Triggers[trigger_num].num_links;i++) {
93 wall_toggle(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
94 mprintf((0," trigger_num %d : seg %d, side %d\n",
95 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
101 void do_close_door(byte trigger_num)
105 mprintf((0, "Door close!\n"));
107 if (trigger_num != -1) {
108 for (i=0;i<Triggers[trigger_num].num_links;i++)
109 wall_close_door(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
113 //turns lighting on. returns true if lights were actually turned on. (they
114 //would not be if they had previously been shot out).
115 int do_light_on(byte trigger_num)
119 mprintf((0, "Lighting on!\n"));
121 if (trigger_num != -1) {
122 for (i=0;i<Triggers[trigger_num].num_links;i++) {
124 segnum = Triggers[trigger_num].seg[i];
125 sidenum = Triggers[trigger_num].side[i];
127 //check if tmap2 casts light before turning the light on. This
128 //is to keep us from turning on blown-out lights
129 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
130 ret |= add_light(segnum, sidenum); //any light sets flag
131 enable_flicker(segnum, sidenum);
139 //turns lighting off. returns true if lights were actually turned off. (they
140 //would not be if they had previously been shot out).
141 int do_light_off(byte trigger_num)
145 mprintf((0, "Lighting off!\n"));
147 if (trigger_num != -1) {
148 for (i=0;i<Triggers[trigger_num].num_links;i++) {
150 segnum = Triggers[trigger_num].seg[i];
151 sidenum = Triggers[trigger_num].side[i];
153 //check if tmap2 casts light before turning the light off. This
154 //is to keep us from turning off blown-out lights
155 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
156 ret |= subtract_light(segnum, sidenum); //any light sets flag
157 disable_flicker(segnum, sidenum);
165 // Unlocks all doors linked to the switch.
166 void do_unlock_doors(byte trigger_num)
170 mprintf((0, "Door unlock!\n"));
172 if (trigger_num != -1) {
173 for (i=0;i<Triggers[trigger_num].num_links;i++) {
174 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags &= ~WALL_DOOR_LOCKED;
175 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].keys = KEY_NONE;
180 // Return trigger number if door is controlled by a wall switch, else return -1.
181 int door_is_wall_switched(int wall_num)
185 for (t=0; t<Num_triggers; t++) {
186 for (i=0; i<Triggers[t].num_links; i++) {
187 if (Segments[Triggers[t].seg[i]].sides[Triggers[t].side[i]].wall_num == wall_num) {
188 mprintf((0, "Wall #%i is keyed to trigger #%i, link #%i\n", wall_num, t, i));
197 void flag_wall_switched_doors(void)
201 for (i=0; i<Num_walls; i++) {
202 if (door_is_wall_switched(i))
203 Walls[i].flags |= WALL_WALL_SWITCH;
208 // Locks all doors linked to the switch.
209 void do_lock_doors(byte trigger_num)
213 mprintf((0, "Door lock!\n"));
215 if (trigger_num != -1) {
216 for (i=0;i<Triggers[trigger_num].num_links;i++) {
217 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags |= WALL_DOOR_LOCKED;
222 // Changes walls pointed to by a trigger. returns true if any walls changed
223 int do_change_walls(byte trigger_num)
227 mprintf((0, "Wall remove!\n"));
229 if (trigger_num != -1) {
230 for (i=0;i<Triggers[trigger_num].num_links;i++) {
231 segment *segp,*csegp;
235 segp = &Segments[Triggers[trigger_num].seg[i]];
236 side = Triggers[trigger_num].side[i];
238 csegp = &Segments[segp->children[side]];
239 cside = find_connect_side(segp, csegp);
242 //segp->sides[side].wall_num = -1;
243 //csegp->sides[cside].wall_num = -1;
245 switch (Triggers[trigger_num].type) {
246 case TT_OPEN_WALL: new_wall_type = WALL_OPEN; break;
247 case TT_CLOSE_WALL: new_wall_type = WALL_CLOSED; break;
248 case TT_ILLUSORY_WALL: new_wall_type = WALL_ILLUSION; break;
250 Assert(0); /* new_wall_type unset */
255 if (Walls[segp->sides[side].wall_num].type == new_wall_type && Walls[csegp->sides[cside].wall_num].type == new_wall_type)
256 continue; //already in correct state, so skip
260 switch (Triggers[trigger_num].type) {
263 mprintf((0,"Open wall\n"));
265 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
267 compute_center_point_on_side(&pos, segp, side );
268 digi_link_sound_to_pos( SOUND_FORCEFIELD_OFF, segp-Segments, side, &pos, 0, F1_0 );
269 Walls[segp->sides[side].wall_num].type = new_wall_type;
270 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
271 digi_kill_sound_linked_to_segment(segp-Segments,side,SOUND_FORCEFIELD_HUM);
272 digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
275 start_wall_cloak(segp,side);
282 mprintf((0,"Close wall\n"));
284 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
286 compute_center_point_on_side(&pos, segp, side );
287 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM,segp-Segments,side,&pos,1, F1_0/2);
288 Walls[segp->sides[side].wall_num].type = new_wall_type;
289 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
292 start_wall_decloak(segp,side);
295 case TT_ILLUSORY_WALL:
296 mprintf((0,"Illusory wall\n"));
297 Walls[segp->sides[side].wall_num].type = new_wall_type;
298 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
303 kill_stuck_objects(segp->sides[side].wall_num);
304 kill_stuck_objects(csegp->sides[cside].wall_num);
312 void print_trigger_message (int pnum,int trig,int shot,char *message)
314 char *pl; //points to 's' or nothing for plural word
316 if (pnum!=Player_num)
319 pl = (Triggers[trig].num_links>1)?"s":"";
321 if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
322 HUD_init_message (message,pl);
326 void do_matcen(byte trigger_num)
330 mprintf((0, "Matcen link!\n"));
332 if (trigger_num != -1) {
333 for (i=0;i<Triggers[trigger_num].num_links;i++) {
334 trigger_matcen(Triggers[trigger_num].seg[i] );
335 mprintf((0," trigger_num %d : seg %d\n",
336 trigger_num, Triggers[trigger_num].seg[i]));
342 void do_il_on(byte trigger_num)
346 mprintf((0, "Illusion ON\n"));
348 if (trigger_num != -1) {
349 for (i=0;i<Triggers[trigger_num].num_links;i++) {
350 wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
351 mprintf((0," trigger_num %d : seg %d, side %d\n",
352 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
357 void do_il_off(byte trigger_num)
361 mprintf((0, "Illusion OFF\n"));
363 if (trigger_num != -1) {
364 for (i=0;i<Triggers[trigger_num].num_links;i++) {
366 segment *seg = &Segments[Triggers[trigger_num].seg[i]];
367 int side = Triggers[trigger_num].side[i];
369 wall_illusion_off(seg, side);
371 mprintf((0," trigger_num %d : seg %d, side %d\n",
372 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
374 compute_center_point_on_side(&cp, seg, side );
375 digi_link_sound_to_pos( SOUND_WALL_REMOVED, seg-Segments, side, &cp, 0, F1_0 );
381 extern void EnterSecretLevel(void);
382 extern void ExitSecretLevel(void);
383 extern int p_secret_level_destroyed(void);
385 int wall_is_forcefield(trigger *trig)
389 for (i=0;i<trig->num_links;i++)
390 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
393 return (i<trig->num_links);
396 int check_trigger_sub(int trigger_num, int pnum,int shot)
398 trigger *trig = &Triggers[trigger_num];
400 mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
402 if (trig->flags & TF_DISABLED)
403 return 1; //1 means don't send trigger hit to other players
405 if (trig->flags & TF_ONE_SHOT) //if this is a one-shot...
406 trig->flags |= TF_DISABLED; //..then don't let it happen again
408 switch (trig->type) {
412 if (pnum!=Player_num)
415 digi_stop_all(); //kill the sounds
417 if (Current_level_num > 0) {
418 start_endlevel_sequence();
419 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
420 } else if (Current_level_num < 0) {
421 if ((Players[Player_num].shields < 0) || Player_is_dead)
428 nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
430 Int3(); //level num == 0, but no editor!
436 case TT_SECRET_EXIT: {
439 if (pnum!=Player_num)
442 if ((Players[Player_num].shields < 0) || Player_is_dead)
445 if (Game_mode & GM_MULTI) {
446 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
447 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
452 truth = p_secret_level_destroyed();
454 if (Newdemo_state == ND_STATE_RECORDING) // record whether we're really going to the secret level
455 newdemo_record_secret_exit_blown(truth);
457 if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
458 HUD_init_message("Secret Level destroyed. Exit disabled.");
459 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
465 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
466 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
470 if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording
471 Newdemo_state = ND_STATE_PAUSED;
473 digi_stop_all(); //kill the sounds
475 digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
476 mprintf((0,"Exiting to secret level\n"));
478 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
479 // -- BOGUS -- IMPOSSIBLE -- multi_send_endlevel_start(1);
480 // -- BOGUS -- IMPOSSIBLE --
481 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
482 // -- BOGUS -- IMPOSSIBLE -- network_do_frame(1, 1);
484 gr_palette_fade_out(gr_palette, 32, 0);
486 Control_center_destroyed = 0;
494 do_link(trigger_num);
495 print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
500 do_close_door(trigger_num);
501 print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
506 do_unlock_doors(trigger_num);
507 print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
513 do_lock_doors(trigger_num);
514 print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
519 if (do_change_walls(trigger_num))
521 if (wall_is_forcefield(trig))
522 print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
524 print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
529 if (do_change_walls(trigger_num))
531 if (wall_is_forcefield(trig))
532 print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
534 print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
538 case TT_ILLUSORY_WALL:
539 //don't know what to say, so say nothing
540 do_change_walls(trigger_num);
544 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
545 do_matcen(trigger_num);
550 do_il_on(trigger_num);
551 print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
554 case TT_ILLUSION_OFF:
556 do_il_off(trigger_num);
557 print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
561 if (do_light_off(trigger_num))
562 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
566 if (do_light_on(trigger_num))
567 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
579 //-----------------------------------------------------------------
580 // Checks for a trigger whenever an object hits a trigger side.
581 void check_trigger(segment *seg, short side, short objnum,int shot)
583 int wall_num, trigger_num; //, ctrigger_num;
589 if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
591 if ( Newdemo_state == ND_STATE_RECORDING )
592 newdemo_record_trigger( seg-Segments, side, objnum,shot);
594 wall_num = seg->sides[side].wall_num;
595 if ( wall_num == -1 ) return;
597 trigger_num = Walls[wall_num].trigger;
599 if (trigger_num == -1)
602 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
603 //## if (Triggers[trigger_num].type == TT_EXIT) {
604 //## start_endlevel_sequence();
609 if (check_trigger_sub(trigger_num, Player_num,shot))
612 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
613 //@@ Triggers[trigger_num].flags &= ~TRIGGER_ON;
615 //@@ csegp = &Segments[seg->children[side]];
616 //@@ cside = find_connect_side(seg, csegp);
617 //@@ Assert(cside != -1);
619 //@@ wall_num = csegp->sides[cside].wall_num;
620 //@@ if ( wall_num == -1 ) return;
622 //@@ ctrigger_num = Walls[wall_num].trigger;
624 //@@ Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
628 if (Game_mode & GM_MULTI)
629 multi_send_trigger(trigger_num);
634 void triggers_frame_process()
638 for (i=0;i<Num_triggers;i++)
639 if (Triggers[i].time >= 0)
640 Triggers[i].time -= FrameTime;