1 /* $Id: medwall.c,v 1.7 2005-01-25 19:36:27 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-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Created from version 1.11 of main\wall.c
22 static char rcsid[] = "$Id: medwall.c,v 1.7 2005-01-25 19:36:27 schaffner Exp $";
34 #include "editor/medwall.h"
36 #include "editor/editor.h"
44 #include "editor/eswitch.h"
56 int wall_add_door_flag(sbyte flag);
57 int wall_add_to_side(segment *segp, int side, sbyte type);
58 int wall_remove_door_flag(sbyte flag);
59 //-------------------------------------------------------------------------
60 // Variables for this module...
61 //-------------------------------------------------------------------------
62 static UI_WINDOW *MainWindow = NULL;
63 static UI_GADGET_USERBOX *WallViewBox;
64 static UI_GADGET_BUTTON *QuitButton;
65 static UI_GADGET_CHECKBOX *DoorFlag[4];
66 static UI_GADGET_RADIO *KeyFlag[4];
68 static int old_wall_num;
70 static int framenum=0;
71 static int Current_door_type=1;
73 typedef struct count_wall {
78 //---------------------------------------------------------------------
79 extern void create_removable_wall(segment *sp, int sidenum, int tmap_num);
81 // Add a wall (removable 2 sided)
82 int add_wall(segment *seg, short side)
87 if (Num_walls < MAX_WALLS-2)
88 if (IS_CHILD(seg->children[side])) {
89 if (seg->sides[side].wall_num == -1) {
90 seg->sides[side].wall_num = Num_walls;
94 csegp = &Segments[seg->children[side]];
95 Connectside = find_connect_side(seg, csegp);
97 if (csegp->sides[Connectside].wall_num == -1) {
98 csegp->sides[Connectside].wall_num = Num_walls;
102 create_removable_wall( seg, side, CurrentTexture );
103 create_removable_wall( csegp, Connectside, CurrentTexture );
111 int wall_assign_door(int door_type)
116 if (Cursegp->sides[Curside].wall_num == -1) {
117 editor_status("Cannot assign door. No wall at Curside.");
121 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) {
122 editor_status("Cannot assign door. No door at Curside.");
126 Current_door_type = door_type;
128 csegp = &Segments[Cursegp->children[Curside]];
129 Connectside = find_connect_side(Cursegp, csegp);
131 Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
132 Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
134 if (WallAnims[door_type].flags & WCF_TMAP1) {
135 Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0];
136 csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0];
137 Cursegp->sides[Curside].tmap_num2 = 0;
138 csegp->sides[Connectside].tmap_num2 = 0;
141 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
142 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
145 Update_flags |= UF_WORLD_CHANGED;
149 int wall_add_blastable()
151 return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
156 return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
159 int wall_add_closed_wall()
161 return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
164 int wall_add_external_wall()
166 if (Cursegp->children[Curside] == -2) {
167 editor_status( "Wall is already external!" );
171 if (IS_CHILD(Cursegp->children[Curside])) {
172 editor_status( "Cannot add external wall here - seg has children" );
176 Cursegp->children[Curside] = -2;
181 int wall_add_illusion()
183 return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
188 return wall_add_door_flag(WALL_DOOR_LOCKED);
191 int wall_unlock_door()
193 return wall_remove_door_flag(WALL_DOOR_LOCKED);
196 int wall_automate_door()
198 return wall_add_door_flag(WALL_DOOR_AUTO);
201 int wall_deautomate_door()
203 return wall_remove_door_flag(WALL_DOOR_AUTO);
209 if (Cursegp->sides[Curside].wall_num < 0)
210 current_wall = Num_walls;
212 current_wall = Cursegp->sides[Curside].wall_num;
215 if (current_wall < 0) current_wall = Num_walls-1;
216 if (current_wall >= Num_walls) current_wall = Num_walls-1;
218 if (Walls[current_wall].segnum == -1) {
219 mprintf((0, "Trying to goto wall at bogus segnum\n"));
223 if (Walls[current_wall].sidenum == -1) {
224 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
228 Cursegp = &Segments[Walls[current_wall].segnum];
229 Curside = Walls[current_wall].sidenum;
238 current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
242 if (current_wall >= Num_walls) current_wall = 0;
243 if (current_wall < 0) current_wall = 0;
245 if (Walls[current_wall].segnum == -1) {
246 mprintf((0, "Trying to goto wall at bogus segnum\n"));
250 if (Walls[current_wall].sidenum == -1) {
251 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
255 Cursegp = &Segments[Walls[current_wall].segnum];
256 Curside = Walls[current_wall].sidenum;
265 if (Cursegp->sides[Curside].wall_num == -1) {
266 editor_status("Cannot assign new wall. No wall on curside.");
270 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
272 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
279 wall_type = Num_wall_anims-1;
281 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
282 Error("Cannot find clip for door.");
284 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
288 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
295 wall_type = Num_wall_anims-1;
297 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
298 Error("Cannot find clip for blastable wall.");
300 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
304 wall_assign_door(wall_type);
306 Update_flags |= UF_WORLD_CHANGED;
313 if (Cursegp->sides[Curside].wall_num == -1) {
314 editor_status("Cannot assign new wall. No wall on curside.");
318 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
320 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
326 if (wall_type >= Num_wall_anims) {
328 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
329 Error("Cannot find clip for door.");
332 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
335 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
341 if (wall_type >= Num_wall_anims) {
343 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
344 Error("Cannot find clip for blastable wall.");
347 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
351 wall_assign_door(wall_type);
353 Update_flags |= UF_WORLD_CHANGED;
358 //-------------------------------------------------------------------------
359 // Called from the editor... does one instance of the wall dialog box
360 //-------------------------------------------------------------------------
365 // Only open 1 instance of this window...
366 if ( MainWindow != NULL ) return 0;
368 // Close other windows.
371 // Open a window with a quit button
372 MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
373 QuitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL );
375 // These are the checkboxes for each door flag.
377 DoorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24;
378 DoorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24;
379 DoorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24;
381 KeyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24;
382 KeyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24;
383 KeyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" ); i += 24;
384 KeyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24;
386 // The little box the wall will appear in.
387 WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
389 // A bunch of buttons...
391 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall );
392 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25;
393 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25;
394 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door ); i += 25;
395 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion); i += 25;
396 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25;
397 // ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all ); i += 25;
398 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall );
399 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25;
400 ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25;
401 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25;
402 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25;
404 old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame.
409 void close_wall_window()
411 if ( MainWindow!=NULL ) {
412 ui_close_window( MainWindow );
417 void do_wall_window()
423 if ( MainWindow == NULL ) return;
425 //------------------------------------------------------------
426 // Call the ui code..
427 //------------------------------------------------------------
428 ui_button_any_drawn = 0;
429 ui_window_do_gadgets(MainWindow);
431 //------------------------------------------------------------
432 // If we change walls, we need to reset the ui code for all
433 // of the checkboxes that control the wall flags.
434 //------------------------------------------------------------
435 if (old_wall_num != Cursegp->sides[Curside].wall_num) {
436 for ( i=0; i < 3; i++ ) {
437 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
438 DoorFlag[i]->status = 1; // Tells ui to redraw button
440 for ( i=0; i < 4; i++ ) {
441 KeyFlag[i]->flag = 0; // Tells ui that this button isn't checked
442 KeyFlag[i]->status = 1; // Tells ui to redraw button
445 if ( Cursegp->sides[Curside].wall_num != -1) {
446 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_LOCKED)
447 DoorFlag[0]->flag = 1; // Mark this button as checked
448 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_AUTO)
449 DoorFlag[1]->flag = 1; // Mark this button as checked
450 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_ILLUSION_OFF)
451 DoorFlag[2]->flag = 1; // Mark this button as checked
453 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
454 KeyFlag[0]->flag = 1;
455 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
456 KeyFlag[1]->flag = 1;
457 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
458 KeyFlag[2]->flag = 1;
459 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
460 KeyFlag[3]->flag = 1;
464 //------------------------------------------------------------
465 // If any of the checkboxes that control the wallflags are set, then
466 // update the corresponding wall flag.
467 //------------------------------------------------------------
469 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
470 if ( DoorFlag[0]->flag == 1 )
471 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
473 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
474 if ( DoorFlag[1]->flag == 1 )
475 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
477 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
479 //------------------------------------------------------------
480 // If any of the radio buttons that control the mode are set, then
481 // update the corresponding key.
482 //------------------------------------------------------------
483 for ( i=0; i < 4; i++ ) {
484 if ( KeyFlag[i]->flag == 1 ) {
485 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
486 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
490 for ( i=0; i < 2; i++ )
491 if (DoorFlag[i]->flag == 1) {
492 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
493 DoorFlag[i]->status = 1; // Tells ui to redraw button
495 for ( i=0; i < 4; i++ ) {
496 if ( KeyFlag[i]->flag == 1 ) {
497 KeyFlag[i]->flag = 0;
498 KeyFlag[i]->status = 1;
503 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
504 if ( DoorFlag[2]->flag == 1 )
505 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
507 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
509 for ( i=2; i < 3; i++ )
510 if (DoorFlag[i]->flag == 1) {
511 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
512 DoorFlag[i]->status = 1; // Tells ui to redraw button
515 //------------------------------------------------------------
516 // A simple frame time counter for animating the walls...
517 //------------------------------------------------------------
518 Temp = timer_get_fixed_seconds();
519 DeltaTime = Temp - Time;
521 //------------------------------------------------------------
522 // Draw the wall in the little 64x64 box
523 //------------------------------------------------------------
524 gr_set_current_canvas( WallViewBox->canvas );
525 if (Cursegp->sides[Curside].wall_num != -1) {
526 type = Walls[Cursegp->sides[Curside].wall_num].type;
527 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
528 if (DeltaTime > ((F1_0*200)/1000)) {
532 if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
534 PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
535 gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
537 if (type == WALL_OPEN)
538 gr_clear_canvas( CBLACK );
540 if (Cursegp->sides[Curside].tmap_num2 > 0)
541 gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
543 PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
544 gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
549 gr_clear_canvas( CGREY );
551 //------------------------------------------------------------
552 // If anything changes in the ui system, redraw all the text that
553 // identifies this wall.
554 //------------------------------------------------------------
555 if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
556 if ( Cursegp->sides[Curside].wall_num > -1 ) {
557 ui_wprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num);
558 switch (Walls[Cursegp->sides[Curside].wall_num].type) {
560 ui_wprintf_at( MainWindow, 12, 23, " Type: Normal " );
563 ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
566 ui_wprintf_at( MainWindow, 12, 23, " Type: Door " );
567 ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
570 ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
573 ui_wprintf_at( MainWindow, 12, 23, " Type: Open " );
576 ui_wprintf_at( MainWindow, 12, 23, " Type: Closed " );
579 ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown " );
582 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
583 ui_wprintf_at( MainWindow, 223, 6, " " );
585 ui_wprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
586 ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger );
588 ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
589 ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
590 ui_wprintf_at( MainWindow, 12, 40, " Clip: none ");
591 ui_wprintf_at( MainWindow, 12, 57, " Trigger: none ");
593 Update_flags |= UF_WORLD_CHANGED;
595 if ( QuitButton->pressed || (last_keypress==KEY_ESC) ) {
600 old_wall_num = Cursegp->sides[Curside].wall_num;
604 //---------------------------------------------------------------------
605 extern void wall_close_door_num(int door_num);
607 // Restore all walls to original status (closed doors, repaired walls)
608 int wall_restore_all()
613 for (i=0;i<Num_walls;i++) {
614 if (Walls[i].flags & WALL_BLASTED) {
615 Walls[i].hps = WALL_HPS;
616 Walls[i].flags &= ~WALL_BLASTED;
618 if (Walls[i].flags & WALL_DOOR_OPENED)
619 Walls[i].flags &= ~WALL_DOOR_OPENED;
620 if (Walls[i].flags & WALL_DOOR_OPENING)
621 Walls[i].flags &= ~WALL_DOOR_OPENING;
624 for (i=0;i<Num_open_doors;i++)
625 wall_close_door_num(i);
627 for (i=0;i<Num_segments;i++)
628 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
629 wall_num = Segments[i].sides[j].wall_num;
631 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
632 (Walls[wall_num].type == WALL_DOOR))
633 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
636 for (i=0;i<Num_triggers;i++)
637 Triggers[i].flags |= TRIGGER_ON;
639 Update_flags |= UF_GAME_VIEW_CHANGED;
645 //---------------------------------------------------------------------
646 // Delete a specific wall.
647 int wall_delete_bogus(short wall_num)
652 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
653 mprintf((0,"WALL IS NOT BOGUS.\n"));
657 // Delete bogus wall and slide all above walls down one slot
658 for (w=wall_num; w<Num_walls; w++) {
659 Walls[w] = Walls[w+1];
664 for (seg=0;seg<=Highest_segment_index;seg++)
665 if (Segments[seg].segnum != -1)
666 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
667 if (Segments[seg].sides[side].wall_num > wall_num)
668 Segments[seg].sides[side].wall_num--;
670 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
676 //---------------------------------------------------------------------
677 // Remove a specific side.
678 int wall_remove_side(segment *seg, short side)
685 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
686 csegp = &Segments[seg->children[side]];
687 Connectside = find_connect_side(seg, csegp);
689 remove_trigger(seg, side);
690 remove_trigger(csegp, Connectside);
692 // Remove walls 'wall_num' and connecting side 'wall_num'
694 lower_wallnum = seg->sides[side].wall_num;
695 if (csegp->sides[Connectside].wall_num < lower_wallnum)
696 lower_wallnum = csegp->sides[Connectside].wall_num;
698 if (Walls[lower_wallnum].linked_wall != -1)
699 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
700 if (Walls[lower_wallnum+1].linked_wall != -1)
701 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
703 for (w=lower_wallnum;w<Num_walls-2;w++)
704 Walls[w] = Walls[w+2];
708 for (s=0;s<=Highest_segment_index;s++)
709 if (Segments[s].segnum != -1)
710 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
711 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
712 Segments[s].sides[w].wall_num -= 2;
714 // Destroy any links to the deleted wall.
715 for (t=0;t<Num_triggers;t++)
716 for (l=0;l<Triggers[t].num_links;l++)
717 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
718 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
719 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
720 Triggers[t].side[t1] = Triggers[t].side[t1+1];
722 Triggers[t].num_links--;
725 // Destroy control center links as well.
726 for (l=0;l<ControlCenterTriggers.num_links;l++)
727 if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
728 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
729 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
730 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
732 ControlCenterTriggers.num_links--;
735 seg->sides[side].wall_num = -1;
736 csegp->sides[Connectside].wall_num = -1;
738 Update_flags |= UF_WORLD_CHANGED;
742 editor_status( "Can't remove wall. No wall present.");
746 //---------------------------------------------------------------------
747 // Remove a special wall.
750 return wall_remove_side(Cursegp, Curside);
753 //---------------------------------------------------------------------
754 // Add a wall to curside
755 int wall_add_to_side(segment *segp, int side, sbyte type)
760 if (add_wall(segp, side)) {
761 csegp = &Segments[segp->children[side]];
762 connectside = find_connect_side(segp, csegp);
764 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
765 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
767 Walls[segp->sides[side].wall_num].sidenum = side;
768 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
770 Walls[segp->sides[side].wall_num].flags = 0;
771 Walls[csegp->sides[connectside].wall_num].flags = 0;
773 Walls[segp->sides[side].wall_num].type = type;
774 Walls[csegp->sides[connectside].wall_num].type = type;
776 // Walls[segp->sides[side].wall_num].trigger = -1;
777 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
779 Walls[segp->sides[side].wall_num].clip_num = -1;
780 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
782 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
783 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
785 if (type == WALL_BLASTABLE) {
786 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
787 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
789 //Walls[segp->sides[side].wall_num].clip_num = 0;
790 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
793 if (type != WALL_DOOR) {
794 segp->sides[side].tmap_num2 = 0;
795 csegp->sides[connectside].tmap_num2 = 0;
798 if (type == WALL_DOOR) {
799 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
800 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
802 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
803 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
806 //Update_flags |= UF_WORLD_CHANGED;
809 // return NextWall(); //assign a clip num
810 return wall_assign_door(Current_door_type);
813 editor_status( "Cannot add wall here, no children" );
819 //---------------------------------------------------------------------
820 // Add a wall to markedside
821 int wall_add_to_markedside(sbyte type)
826 if (add_wall(Markedsegp, Markedside)) {
827 int wall_num, cwall_num;
828 csegp = &Segments[Markedsegp->children[Markedside]];
830 Connectside = find_connect_side(Markedsegp, csegp);
832 wall_num = Markedsegp->sides[Markedside].wall_num;
833 cwall_num = csegp->sides[Connectside].wall_num;
835 Walls[wall_num].segnum = Markedsegp-Segments;
836 Walls[cwall_num].segnum = csegp-Segments;
838 Walls[wall_num].sidenum = Markedside;
839 Walls[cwall_num].sidenum = Connectside;
841 Walls[wall_num].flags = 0;
842 Walls[cwall_num].flags = 0;
844 Walls[wall_num].type = type;
845 Walls[cwall_num].type = type;
847 Walls[wall_num].trigger = -1;
848 Walls[cwall_num].trigger = -1;
850 Walls[wall_num].clip_num = -1;
851 Walls[cwall_num].clip_num = -1;
853 Walls[wall_num].keys = KEY_NONE;
854 Walls[cwall_num].keys = KEY_NONE;
856 if (type == WALL_BLASTABLE) {
857 Walls[wall_num].hps = WALL_HPS;
858 Walls[cwall_num].hps = WALL_HPS;
860 Walls[wall_num].clip_num = 0;
861 Walls[cwall_num].clip_num = 0;
864 if (type != WALL_DOOR) {
865 Markedsegp->sides[Markedside].tmap_num2 = 0;
866 csegp->sides[Connectside].tmap_num2 = 0;
869 Update_flags |= UF_WORLD_CHANGED;
872 editor_status( "Cannot add wall here, no children" );
878 int wall_add_door_flag(sbyte flag)
883 if (Cursegp->sides[Curside].wall_num == -1)
885 editor_status("Cannot change flag. No wall at Curside.");
889 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
891 editor_status("Cannot change flag. No door at Curside.");
895 csegp = &Segments[Cursegp->children[Curside]];
896 Connectside = find_connect_side(Cursegp, csegp);
898 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
899 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
901 Update_flags |= UF_ED_STATE_CHANGED;
905 int wall_remove_door_flag(sbyte flag)
910 if (Cursegp->sides[Curside].wall_num == -1)
912 editor_status("Cannot change flag. No wall at Curside.");
916 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
918 editor_status("Cannot change flag. No door at Curside.");
922 csegp = &Segments[Cursegp->children[Curside]];
923 Connectside = find_connect_side(Cursegp, csegp);
925 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
926 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
928 Update_flags |= UF_ED_STATE_CHANGED;
933 int bind_wall_to_control_center() {
938 if (Cursegp->sides[Curside].wall_num == -1) {
939 editor_status("No wall at Curside.");
943 link_num = ControlCenterTriggers.num_links;
944 for (i=0;i<link_num;i++)
945 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
946 editor_status("Curside already bound to Control Center.");
950 // Error checking completed, actual binding begins
951 ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
952 ControlCenterTriggers.side[link_num] = Curside;
953 ControlCenterTriggers.num_links++;
955 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
956 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
958 editor_status("Wall linked to control center");
963 //link two doors, curseg/curside and markedseg/markedside
964 int wall_link_doors()
966 wall *w1=NULL,*w2=NULL;
968 if (Cursegp->sides[Curside].wall_num != -1)
969 w1 = &Walls[Cursegp->sides[Curside].wall_num];
971 if (Markedsegp->sides[Markedside].wall_num != -1)
972 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
974 if (!w1 || w1->type != WALL_DOOR) {
975 editor_status("Curseg/curside is not a door");
979 if (!w2 || w2->type != WALL_DOOR) {
980 editor_status("Markedseg/markedside is not a door");
984 if (w1->linked_wall != -1)
985 editor_status("Curseg/curside is already linked");
987 if (w2->linked_wall != -1)
988 editor_status("Markedseg/markedside is already linked");
990 w1->linked_wall = w2-Walls;
991 w2->linked_wall = w1-Walls;
996 int wall_unlink_door()
1000 if (Cursegp->sides[Curside].wall_num != -1)
1001 w1 = &Walls[Cursegp->sides[Curside].wall_num];
1003 if (!w1 || w1->type != WALL_DOOR) {
1004 editor_status("Curseg/curside is not a door");
1008 if (w1->linked_wall == -1)
1009 editor_status("Curseg/curside is not linked");
1011 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1013 Walls[w1->linked_wall].linked_wall = -1;
1014 w1->linked_wall = -1;
1020 #define DIAGNOSTIC_MESSAGE_MAX 150
1024 int w, seg, side, wall_count, trigger_count;
1026 count_wall CountedWalls[MAX_WALLS];
1027 char Message[DIAGNOSTIC_MESSAGE_MAX];
1031 for (seg=0;seg<=Highest_segment_index;seg++)
1032 if (Segments[seg].segnum != -1) {
1033 // Check fuelcenters
1034 matcen_num = Segment2s[seg].matcen_num;
1035 if (matcen_num == 0)
1036 if (RobotCenters[0].segnum != seg) {
1037 mprintf((0,"Fixing Matcen 0\n"));
1038 Segment2s[seg].matcen_num = -1;
1041 if (matcen_num > -1)
1042 if (RobotCenters[matcen_num].segnum != seg) {
1043 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1044 mprintf((0,"Fixing....\n"));
1045 RobotCenters[matcen_num].segnum = seg;
1048 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1049 if (Segments[seg].sides[side].wall_num != -1) {
1050 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1051 CountedWalls[wall_count].segnum = seg;
1052 CountedWalls[wall_count].sidenum = side;
1054 // Check if segnum is bogus
1055 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1056 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1059 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1060 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1067 mprintf((0,"Wall Count = %d\n", wall_count));
1069 if (wall_count != Num_walls) {
1070 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1071 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1072 Num_walls = wall_count;
1073 editor_status("Num_walls set to %d\n", Num_walls);
1077 // Check validity of Walls array.
1078 for (w=0; w<Num_walls; w++) {
1079 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1080 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1081 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1082 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1083 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1084 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1085 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1089 if (CountedWalls[w].wallnum >= Num_walls)
1090 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1092 if (Walls[w].segnum == -1) {
1093 mprintf((0, "Wall[%d] is BOGUS\n", w));
1094 for (seg=0;seg<=Highest_segment_index;seg++)
1095 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1096 if (Segments[seg].sides[side].wall_num == w) {
1097 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1103 for (w1=0; w1<wall_count; w1++) {
1104 for (w2=w1+1; w2<wall_count; w2++)
1105 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1106 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1107 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1108 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1110 if (Walls[w1].trigger != -1) trigger_count++;
1113 if (trigger_count != Num_triggers) {
1114 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1115 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1116 Num_triggers = trigger_count;
1117 editor_status("Num_triggers set to %d\n", Num_triggers);
1121 mprintf((0,"Trigger Count = %d\n", trigger_count));
1123 for (t=0; t<trigger_count; t++) {
1124 if (Triggers[t].flags & TRIGGER_MATCEN)
1126 if (Triggers[t].num_links < 1)
1127 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1129 for (l=0;l<Triggers[t].num_links;l++) {
1130 if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1131 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1135 if (Triggers[t].flags & TRIGGER_EXIT)
1136 if (Triggers[t].num_links != 0)
1137 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1139 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1140 for (l=0;l<Triggers[t].num_links;l++) {
1141 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1142 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1143 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1148 for (l=0;l<ControlCenterTriggers.num_links;l++)
1149 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1150 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1151 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1159 int delete_all_walls()
1161 char Message[DIAGNOSTIC_MESSAGE_MAX];
1164 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1165 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1166 for (seg=0;seg<=Highest_segment_index;seg++)
1167 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1168 Segments[seg].sides[side].wall_num = -1;
1178 int delete_all_triggers()
1180 char Message[DIAGNOSTIC_MESSAGE_MAX];
1183 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1184 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1186 for (w=0; w<Num_walls; w++)
1187 Walls[w].trigger=-1;
1196 int dump_walls_info()
1201 fp = fopen("WALL.OUT", "wt");
1203 fprintf(fp, "Num_walls %d\n", Num_walls);
1205 for (w=0; w<Num_walls; w++) {
1207 fprintf(fp, "WALL #%d\n", w);
1208 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1209 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1211 switch (Walls[w].type) {
1213 fprintf(fp, " type: NORMAL\n");
1215 case WALL_BLASTABLE:
1216 fprintf(fp, " type: BLASTABLE\n");
1219 fprintf(fp, " type: DOOR\n");
1222 fprintf(fp, " type: ILLUSION\n");
1225 fprintf(fp, " type: OPEN\n");
1228 fprintf(fp, " type: CLOSED\n");
1231 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1235 fprintf(fp, " flags:\n");
1237 if (Walls[w].flags & WALL_BLASTED)
1238 fprintf(fp, " BLASTED\n");
1239 if (Walls[w].flags & WALL_DOOR_OPENED)
1240 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1241 if (Walls[w].flags & WALL_DOOR_OPENING)
1242 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1243 if (Walls[w].flags & WALL_DOOR_LOCKED)
1244 fprintf(fp, " DOOR_LOCKED\n");
1245 if (Walls[w].flags & WALL_DOOR_AUTO)
1246 fprintf(fp, " DOOR_AUTO\n");
1247 if (Walls[w].flags & WALL_ILLUSION_OFF)
1248 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1249 //if (Walls[w].flags & WALL_FUELCEN)
1250 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1252 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1253 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1255 switch (Walls[w].keys) {
1257 fprintf(fp, " key: NONE\n");
1260 fprintf(fp, " key: BLUE\n");
1263 fprintf(fp, " key: RED\n");
1266 fprintf(fp, " key: NONE\n");
1269 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1273 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1280 // ------------------------------------------------------------------------------------------------
1281 void copy_old_wall_data_to_new(int owall, int nwall)
1283 Walls[nwall].flags = Walls[owall].flags;
1284 Walls[nwall].type = Walls[owall].type;
1285 Walls[nwall].clip_num = Walls[owall].clip_num;
1286 Walls[nwall].keys = Walls[owall].keys;
1287 Walls[nwall].hps = Walls[owall].hps;
1288 Walls[nwall].state = Walls[owall].state;
1289 Walls[nwall].linked_wall = -1;
1291 Walls[nwall].trigger = -1;
1293 if (Walls[owall].trigger != -1) {
1294 editor_status("Warning: Trigger not copied in group copy.");
1298 //typedef struct trigger {
1305 // short seg[MAX_WALLS_PER_LINK];
1306 // short side[MAX_WALLS_PER_LINK];
1310 // ------------------------------------------------------------------------------------------------
1311 void copy_group_walls(int old_group, int new_group)
1313 int i,j,old_seg, new_seg;
1315 for (i=0; i<GroupList[old_group].num_segments; i++) {
1316 old_seg = GroupList[old_group].segments[i];
1317 new_seg = GroupList[new_group].segments[i];
1319 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1320 if (Segments[old_seg].sides[j].wall_num != -1) {
1321 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1322 Segments[new_seg].sides[j].wall_num = Num_walls;
1323 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1324 Walls[Num_walls].segnum = new_seg;
1325 Walls[Num_walls].sidenum = j;
1327 Assert(Num_walls < MAX_WALLS);
1333 int Validate_walls=1;
1335 // --------------------------------------------------------------------------------------------------------
1336 // This function should be in medwall.c.
1337 // Make sure all wall/segment connections are valid.
1338 void check_wall_validity(void)
1341 int segnum, sidenum, wall_num;
1342 sbyte wall_flags[MAX_WALLS];
1344 if (!Validate_walls)
1347 for (i=0; i<Num_walls; i++) {
1348 segnum = Walls[i].segnum;
1349 sidenum = Walls[i].sidenum;
1351 if (Segments[segnum].sides[sidenum].wall_num != i) {
1352 if (!Validate_walls)
1354 Int3(); // Error! Your mine has been invalidated!
1355 // Do not continue! Do not save!
1356 // Remember your last action and Contact Mike!
1357 // To continue, set the variable Validate_walls to 1 by doing:
1358 // /Validate_walls = 1
1359 // Then do the usual /eip++;g
1364 for (i=0; i<MAX_WALLS; i++)
1367 for (i=0; i<=Highest_segment_index; i++) {
1368 if (Segments[i].segnum != -1)
1369 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1371 wall_num = Segments[i].sides[j].wall_num;
1372 if (wall_num != -1) {
1373 if (wall_flags[wall_num] != 0) {
1374 if (!Validate_walls)
1376 Int3(); // Error! Your mine has been invalidated!
1377 // Do not continue! Do not save!
1378 // Remember your last action and Contact Mike!
1379 // To continue, set the variable Validate_walls to 1 by doing:
1380 // /Validate_walls = 1
1381 // Then do the usual /eip++;g
1384 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1385 if (!Validate_walls)
1387 Int3(); // Error! Your mine has been invalidated!
1388 // Do not continue! Do not save!
1389 // Remember your last action and Contact Mike!
1390 // To continue, set the variable Validate_walls to 1 by doing:
1391 // /Validate_walls = 1
1392 // Then do the usual /eip++;g
1395 wall_flags[wall_num] = 1;