1 /* $Id: switch.c,v 1.11 2004-08-28 23:17:45 schaffner Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * New Triggers and Switches.
26 static char rcsid[] = "$Id: switch.c,v 1.11 2004-08-28 23:17:45 schaffner Exp $";
60 #include "editor/editor.h"
63 trigger Triggers[MAX_TRIGGERS];
66 //link Links[MAX_WALL_LINKS];
70 fix trigger_time_count=F1_0;
72 //-----------------------------------------------------------------
73 // Initializes all the switches.
80 for (i=0;i<MAX_TRIGGERS;i++)
83 Triggers[i].flags = 0;
84 Triggers[i].num_links = 0;
85 Triggers[i].value = 0;
86 Triggers[i].time = -1;
91 //-----------------------------------------------------------------
92 // Executes a link, attached to a trigger.
93 // Toggles all walls linked to the switch.
94 // Opens doors, Blasts blast walls, turns off illusions.
95 void do_link(sbyte trigger_num)
99 mprintf((0, "Door link!\n"));
101 if (trigger_num != -1) {
102 for (i=0;i<Triggers[trigger_num].num_links;i++) {
103 wall_toggle(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
104 mprintf((0," trigger_num %d : seg %d, side %d\n",
105 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
111 void do_close_door(sbyte trigger_num)
115 mprintf((0, "Door close!\n"));
117 if (trigger_num != -1) {
118 for (i=0;i<Triggers[trigger_num].num_links;i++)
119 wall_close_door(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
123 //turns lighting on. returns true if lights were actually turned on. (they
124 //would not be if they had previously been shot out).
125 int do_light_on(sbyte trigger_num)
129 mprintf((0, "Lighting on!\n"));
131 if (trigger_num != -1) {
132 for (i=0;i<Triggers[trigger_num].num_links;i++) {
134 segnum = Triggers[trigger_num].seg[i];
135 sidenum = Triggers[trigger_num].side[i];
137 //check if tmap2 casts light before turning the light on. This
138 //is to keep us from turning on blown-out lights
139 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
140 ret |= add_light(segnum, sidenum); //any light sets flag
141 enable_flicker(segnum, sidenum);
149 //turns lighting off. returns true if lights were actually turned off. (they
150 //would not be if they had previously been shot out).
151 int do_light_off(sbyte trigger_num)
155 mprintf((0, "Lighting off!\n"));
157 if (trigger_num != -1) {
158 for (i=0;i<Triggers[trigger_num].num_links;i++) {
160 segnum = Triggers[trigger_num].seg[i];
161 sidenum = Triggers[trigger_num].side[i];
163 //check if tmap2 casts light before turning the light off. This
164 //is to keep us from turning off blown-out lights
165 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
166 ret |= subtract_light(segnum, sidenum); //any light sets flag
167 disable_flicker(segnum, sidenum);
175 // Unlocks all doors linked to the switch.
176 void do_unlock_doors(sbyte trigger_num)
180 mprintf((0, "Door unlock!\n"));
182 if (trigger_num != -1) {
183 for (i=0;i<Triggers[trigger_num].num_links;i++) {
184 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags &= ~WALL_DOOR_LOCKED;
185 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].keys = KEY_NONE;
190 // Return trigger number if door is controlled by a wall switch, else return -1.
191 int door_is_wall_switched(int wall_num)
195 for (t=0; t<Num_triggers; t++) {
196 for (i=0; i<Triggers[t].num_links; i++) {
197 if (Segments[Triggers[t].seg[i]].sides[Triggers[t].side[i]].wall_num == wall_num) {
198 mprintf((0, "Wall #%i is keyed to trigger #%i, link #%i\n", wall_num, t, i));
207 void flag_wall_switched_doors(void)
211 for (i=0; i<Num_walls; i++) {
212 if (door_is_wall_switched(i))
213 Walls[i].flags |= WALL_WALL_SWITCH;
218 // Locks all doors linked to the switch.
219 void do_lock_doors(sbyte trigger_num)
223 mprintf((0, "Door lock!\n"));
225 if (trigger_num != -1) {
226 for (i=0;i<Triggers[trigger_num].num_links;i++) {
227 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags |= WALL_DOOR_LOCKED;
232 // Changes walls pointed to by a trigger. returns true if any walls changed
233 int do_change_walls(sbyte trigger_num)
237 mprintf((0, "Wall remove!\n"));
239 if (trigger_num != -1) {
240 for (i=0;i<Triggers[trigger_num].num_links;i++) {
241 segment *segp,*csegp;
245 segp = &Segments[Triggers[trigger_num].seg[i]];
246 side = Triggers[trigger_num].side[i];
248 if (segp->children[side] < 0)
255 csegp = &Segments[segp->children[side]];
256 cside = find_connect_side(segp, csegp);
260 //segp->sides[side].wall_num = -1;
261 //csegp->sides[cside].wall_num = -1;
263 switch (Triggers[trigger_num].type) {
264 case TT_OPEN_WALL: new_wall_type = WALL_OPEN; break;
265 case TT_CLOSE_WALL: new_wall_type = WALL_CLOSED; break;
266 case TT_ILLUSORY_WALL: new_wall_type = WALL_ILLUSION; break;
268 Assert(0); /* new_wall_type unset */
273 if (Walls[segp->sides[side].wall_num].type == new_wall_type &&
274 (cside < 0 || csegp->sides[cside].wall_num < 0 ||
275 Walls[csegp->sides[cside].wall_num].type == new_wall_type))
276 continue; //already in correct state, so skip
280 switch (Triggers[trigger_num].type) {
283 mprintf((0,"Open 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_OFF, segp-Segments, side, &pos, 0, F1_0 );
289 Walls[segp->sides[side].wall_num].type = new_wall_type;
290 digi_kill_sound_linked_to_segment(segp-Segments,side,SOUND_FORCEFIELD_HUM);
291 if (cside > -1 && csegp->sides[cside].wall_num > -1)
293 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
294 digi_kill_sound_linked_to_segment(csegp-Segments, cside, SOUND_FORCEFIELD_HUM);
298 start_wall_cloak(segp,side);
305 mprintf((0,"Close wall\n"));
307 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
309 compute_center_point_on_side(&pos, segp, side );
310 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM,segp-Segments,side,&pos,1, F1_0/2);
311 Walls[segp->sides[side].wall_num].type = new_wall_type;
312 if (cside > -1 && csegp->sides[cside].wall_num > -1)
313 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
316 start_wall_decloak(segp,side);
319 case TT_ILLUSORY_WALL:
320 mprintf((0,"Illusory wall\n"));
321 Walls[segp->sides[side].wall_num].type = new_wall_type;
322 if (cside > -1 && csegp->sides[cside].wall_num > -1)
323 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
328 kill_stuck_objects(segp->sides[side].wall_num);
329 if (cside > -1 && csegp->sides[cside].wall_num > -1)
330 kill_stuck_objects(csegp->sides[cside].wall_num);
338 void print_trigger_message (int pnum,int trig,int shot,char *message)
340 char *pl; //points to 's' or nothing for plural word
342 if (pnum!=Player_num)
345 pl = (Triggers[trig].num_links>1)?"s":"";
347 if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
348 HUD_init_message (message,pl);
352 void do_matcen(sbyte trigger_num)
356 mprintf((0, "Matcen link!\n"));
358 if (trigger_num != -1) {
359 for (i=0;i<Triggers[trigger_num].num_links;i++) {
360 trigger_matcen(Triggers[trigger_num].seg[i] );
361 mprintf((0," trigger_num %d : seg %d\n",
362 trigger_num, Triggers[trigger_num].seg[i]));
368 void do_il_on(sbyte trigger_num)
372 mprintf((0, "Illusion ON\n"));
374 if (trigger_num != -1) {
375 for (i=0;i<Triggers[trigger_num].num_links;i++) {
376 wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
377 mprintf((0," trigger_num %d : seg %d, side %d\n",
378 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
383 void do_il_off(sbyte trigger_num)
387 mprintf((0, "Illusion OFF\n"));
389 if (trigger_num != -1) {
390 for (i=0;i<Triggers[trigger_num].num_links;i++) {
392 segment *seg = &Segments[Triggers[trigger_num].seg[i]];
393 int side = Triggers[trigger_num].side[i];
395 wall_illusion_off(seg, side);
397 mprintf((0," trigger_num %d : seg %d, side %d\n",
398 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
400 compute_center_point_on_side(&cp, seg, side );
401 digi_link_sound_to_pos( SOUND_WALL_REMOVED, seg-Segments, side, &cp, 0, F1_0 );
407 extern void EnterSecretLevel(void);
408 extern void ExitSecretLevel(void);
409 extern int p_secret_level_destroyed(void);
411 int wall_is_forcefield(trigger *trig)
415 for (i=0;i<trig->num_links;i++)
416 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
419 return (i<trig->num_links);
422 int check_trigger_sub(int trigger_num, int pnum,int shot)
424 trigger *trig = &Triggers[trigger_num];
426 mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
428 if (trig->flags & TF_DISABLED)
429 return 1; //1 means don't send trigger hit to other players
431 if (trig->flags & TF_ONE_SHOT) //if this is a one-shot...
432 trig->flags |= TF_DISABLED; //..then don't let it happen again
434 switch (trig->type) {
438 if (pnum!=Player_num)
441 digi_stop_all(); //kill the sounds
443 if (Current_level_num > 0) {
444 start_endlevel_sequence();
445 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
446 } else if (Current_level_num < 0) {
447 if ((Players[Player_num].shields < 0) || Player_is_dead)
454 nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
456 Int3(); //level num == 0, but no editor!
462 case TT_SECRET_EXIT: {
467 if (pnum!=Player_num)
470 if ((Players[Player_num].shields < 0) || Player_is_dead)
473 if (Game_mode & GM_MULTI) {
474 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
475 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
480 truth = p_secret_level_destroyed();
482 if (Newdemo_state == ND_STATE_RECORDING) // record whether we're really going to the secret level
483 newdemo_record_secret_exit_blown(truth);
485 if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
486 HUD_init_message("Secret Level destroyed. Exit disabled.");
487 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
493 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
494 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
498 if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording
499 Newdemo_state = ND_STATE_PAUSED;
501 digi_stop_all(); //kill the sounds
503 digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
504 mprintf((0,"Exiting to secret level\n"));
506 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
507 // -- BOGUS -- IMPOSSIBLE -- multi_send_endlevel_start(1);
508 // -- BOGUS -- IMPOSSIBLE --
509 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
510 // -- BOGUS -- IMPOSSIBLE -- network_do_frame(1, 1);
512 gr_palette_fade_out(gr_palette, 32, 0);
514 Control_center_destroyed = 0;
522 do_link(trigger_num);
523 print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
528 do_close_door(trigger_num);
529 print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
534 do_unlock_doors(trigger_num);
535 print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
541 do_lock_doors(trigger_num);
542 print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
547 if (do_change_walls(trigger_num))
549 if (wall_is_forcefield(trig))
550 print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
552 print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
557 if (do_change_walls(trigger_num))
559 if (wall_is_forcefield(trig))
560 print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
562 print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
566 case TT_ILLUSORY_WALL:
567 //don't know what to say, so say nothing
568 do_change_walls(trigger_num);
572 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
573 do_matcen(trigger_num);
578 do_il_on(trigger_num);
579 print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
582 case TT_ILLUSION_OFF:
584 do_il_off(trigger_num);
585 print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
589 if (do_light_off(trigger_num))
590 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
594 if (do_light_on(trigger_num))
595 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
607 //-----------------------------------------------------------------
608 // Checks for a trigger whenever an object hits a trigger side.
609 void check_trigger(segment *seg, short side, short objnum,int shot)
611 int wall_num, trigger_num; //, ctrigger_num;
617 if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
619 if ( Newdemo_state == ND_STATE_RECORDING )
620 newdemo_record_trigger( seg-Segments, side, objnum,shot);
622 wall_num = seg->sides[side].wall_num;
623 if ( wall_num == -1 ) return;
625 trigger_num = Walls[wall_num].trigger;
627 if (trigger_num == -1)
630 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
631 //## if (Triggers[trigger_num].type == TT_EXIT) {
632 //## start_endlevel_sequence();
637 if (check_trigger_sub(trigger_num, Player_num,shot))
640 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
641 //@@ Triggers[trigger_num].flags &= ~TRIGGER_ON;
643 //@@ csegp = &Segments[seg->children[side]];
644 //@@ cside = find_connect_side(seg, csegp);
645 //@@ Assert(cside != -1);
647 //@@ wall_num = csegp->sides[cside].wall_num;
648 //@@ if ( wall_num == -1 ) return;
650 //@@ ctrigger_num = Walls[wall_num].trigger;
652 //@@ Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
656 if (Game_mode & GM_MULTI)
657 multi_send_trigger(trigger_num);
662 void triggers_frame_process()
666 for (i=0;i<Num_triggers;i++)
667 if (Triggers[i].time >= 0)
668 Triggers[i].time -= FrameTime;
673 * reads a v29_trigger structure from a CFILE
675 extern void v29_trigger_read(v29_trigger *t, CFILE *fp)
679 t->type = cfile_read_byte(fp);
680 t->flags = cfile_read_short(fp);
681 t->value = cfile_read_fix(fp);
682 t->time = cfile_read_fix(fp);
683 t->link_num = cfile_read_byte(fp);
684 t->num_links = cfile_read_short(fp);
685 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
686 t->seg[i] = cfile_read_short(fp);
687 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
688 t->side[i] = cfile_read_short(fp);
692 * reads a v30_trigger structure from a CFILE
694 extern void v30_trigger_read(v30_trigger *t, CFILE *fp)
698 t->flags = cfile_read_short(fp);
699 t->num_links = cfile_read_byte(fp);
700 t->pad = cfile_read_byte(fp);
701 t->value = cfile_read_fix(fp);
702 t->time = cfile_read_fix(fp);
703 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
704 t->seg[i] = cfile_read_short(fp);
705 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
706 t->side[i] = cfile_read_short(fp);
710 * reads a trigger structure from a CFILE
712 extern void trigger_read(trigger *t, CFILE *fp)
716 t->type = cfile_read_byte(fp);
717 t->flags = cfile_read_byte(fp);
718 t->num_links = cfile_read_byte(fp);
719 t->pad = cfile_read_byte(fp);
720 t->value = cfile_read_fix(fp);
721 t->time = cfile_read_fix(fp);
722 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
723 t->seg[i] = cfile_read_short(fp);
724 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
725 t->side[i] = cfile_read_short(fp);