1 /* $Id: medwall.c,v 1.3 2004-12-19 15:21:11 btb 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.3 2004-12-19 15:21:11 btb Exp $";
34 #include "editor/medwall.h"
36 #include "editor/editor.h"
44 #include "editor/eswitch.h"
50 //#include "fuelcen.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 // Add a wall (removable 2 sided)
80 int add_wall(segment *seg, short side)
85 if (Num_walls < MAX_WALLS-2)
86 if (IS_CHILD(seg->children[side])) {
87 if (seg->sides[side].wall_num == -1) {
88 seg->sides[side].wall_num = Num_walls;
92 csegp = &Segments[seg->children[side]];
93 Connectside = find_connect_side(seg, csegp);
95 if (csegp->sides[Connectside].wall_num == -1) {
96 csegp->sides[Connectside].wall_num = Num_walls;
100 create_removable_wall( seg, side, CurrentTexture );
101 create_removable_wall( csegp, Connectside, CurrentTexture );
109 int wall_assign_door(int door_type)
114 if (Cursegp->sides[Curside].wall_num == -1) {
115 editor_status("Cannot assign door. No wall at Curside.");
119 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) {
120 editor_status("Cannot assign door. No door at Curside.");
124 Current_door_type = door_type;
126 csegp = &Segments[Cursegp->children[Curside]];
127 Connectside = find_connect_side(Cursegp, csegp);
129 Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
130 Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
132 if (WallAnims[door_type].flags & WCF_TMAP1) {
133 Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0];
134 csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0];
135 Cursegp->sides[Curside].tmap_num2 = 0;
136 csegp->sides[Connectside].tmap_num2 = 0;
139 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
140 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
143 Update_flags |= UF_WORLD_CHANGED;
147 int wall_add_blastable()
149 return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
154 return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
157 int wall_add_closed_wall()
159 return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
162 int wall_add_external_wall()
164 if (Cursegp->children[Curside] == -2) {
165 editor_status( "Wall is already external!" );
169 if (IS_CHILD(Cursegp->children[Curside])) {
170 editor_status( "Cannot add external wall here - seg has children" );
174 Cursegp->children[Curside] = -2;
179 int wall_add_illusion()
181 return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
186 return wall_add_door_flag(WALL_DOOR_LOCKED);
189 int wall_unlock_door()
191 return wall_remove_door_flag(WALL_DOOR_LOCKED);
194 int wall_automate_door()
196 return wall_add_door_flag(WALL_DOOR_AUTO);
199 int wall_deautomate_door()
201 return wall_remove_door_flag(WALL_DOOR_AUTO);
207 if (Cursegp->sides[Curside].wall_num < 0)
208 current_wall = Num_walls;
210 current_wall = Cursegp->sides[Curside].wall_num;
213 if (current_wall < 0) current_wall = Num_walls-1;
214 if (current_wall >= Num_walls) current_wall = Num_walls-1;
216 if (Walls[current_wall].segnum == -1) {
217 mprintf((0, "Trying to goto wall at bogus segnum\n"));
221 if (Walls[current_wall].sidenum == -1) {
222 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
226 Cursegp = &Segments[Walls[current_wall].segnum];
227 Curside = Walls[current_wall].sidenum;
236 current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
240 if (current_wall >= Num_walls) current_wall = 0;
241 if (current_wall < 0) current_wall = 0;
243 if (Walls[current_wall].segnum == -1) {
244 mprintf((0, "Trying to goto wall at bogus segnum\n"));
248 if (Walls[current_wall].sidenum == -1) {
249 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
253 Cursegp = &Segments[Walls[current_wall].segnum];
254 Curside = Walls[current_wall].sidenum;
263 if (Cursegp->sides[Curside].wall_num == -1) {
264 editor_status("Cannot assign new wall. No wall on curside.");
268 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
270 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
277 wall_type = Num_wall_anims-1;
279 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
280 Error("Cannot find clip for door.");
282 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
286 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
293 wall_type = Num_wall_anims-1;
295 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
296 Error("Cannot find clip for blastable wall.");
298 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
302 wall_assign_door(wall_type);
304 Update_flags |= UF_WORLD_CHANGED;
311 if (Cursegp->sides[Curside].wall_num == -1) {
312 editor_status("Cannot assign new wall. No wall on curside.");
316 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
318 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
324 if (wall_type >= Num_wall_anims) {
326 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
327 Error("Cannot find clip for door.");
330 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
333 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
339 if (wall_type >= Num_wall_anims) {
341 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
342 Error("Cannot find clip for blastable wall.");
345 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
349 wall_assign_door(wall_type);
351 Update_flags |= UF_WORLD_CHANGED;
356 //-------------------------------------------------------------------------
357 // Called from the editor... does one instance of the wall dialog box
358 //-------------------------------------------------------------------------
363 // Only open 1 instance of this window...
364 if ( MainWindow != NULL ) return 0;
366 // Close other windows.
369 // Open a window with a quit button
370 MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
371 QuitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL );
373 // These are the checkboxes for each door flag.
375 DoorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24;
376 DoorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24;
377 DoorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24;
379 KeyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24;
380 KeyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24;
381 KeyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" ); i += 24;
382 KeyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24;
384 // The little box the wall will appear in.
385 WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
387 // A bunch of buttons...
389 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall );
390 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25;
391 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25;
392 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door ); i += 25;
393 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion); i += 25;
394 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25;
395 // ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all ); i += 25;
396 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall );
397 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25;
398 ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25;
399 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25;
400 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25;
402 old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame.
407 void close_wall_window()
409 if ( MainWindow!=NULL ) {
410 ui_close_window( MainWindow );
415 void do_wall_window()
421 if ( MainWindow == NULL ) return;
423 //------------------------------------------------------------
424 // Call the ui code..
425 //------------------------------------------------------------
426 ui_button_any_drawn = 0;
427 ui_window_do_gadgets(MainWindow);
429 //------------------------------------------------------------
430 // If we change walls, we need to reset the ui code for all
431 // of the checkboxes that control the wall flags.
432 //------------------------------------------------------------
433 if (old_wall_num != Cursegp->sides[Curside].wall_num) {
434 for ( i=0; i < 3; i++ ) {
435 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
436 DoorFlag[i]->status = 1; // Tells ui to redraw button
438 for ( i=0; i < 4; i++ ) {
439 KeyFlag[i]->flag = 0; // Tells ui that this button isn't checked
440 KeyFlag[i]->status = 1; // Tells ui to redraw button
443 if ( Cursegp->sides[Curside].wall_num != -1) {
444 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_LOCKED)
445 DoorFlag[0]->flag = 1; // Mark this button as checked
446 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_AUTO)
447 DoorFlag[1]->flag = 1; // Mark this button as checked
448 if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_ILLUSION_OFF)
449 DoorFlag[2]->flag = 1; // Mark this button as checked
451 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
452 KeyFlag[0]->flag = 1;
453 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
454 KeyFlag[1]->flag = 1;
455 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
456 KeyFlag[2]->flag = 1;
457 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
458 KeyFlag[3]->flag = 1;
462 //------------------------------------------------------------
463 // If any of the checkboxes that control the wallflags are set, then
464 // update the corresponding wall flag.
465 //------------------------------------------------------------
467 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
468 if ( DoorFlag[0]->flag == 1 )
469 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
471 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
472 if ( DoorFlag[1]->flag == 1 )
473 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
475 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
477 //------------------------------------------------------------
478 // If any of the radio buttons that control the mode are set, then
479 // update the corresponding key.
480 //------------------------------------------------------------
481 for ( i=0; i < 4; i++ ) {
482 if ( KeyFlag[i]->flag == 1 ) {
483 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
484 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
488 for ( i=0; i < 2; i++ )
489 if (DoorFlag[i]->flag == 1) {
490 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
491 DoorFlag[i]->status = 1; // Tells ui to redraw button
493 for ( i=0; i < 4; i++ ) {
494 if ( KeyFlag[i]->flag == 1 ) {
495 KeyFlag[i]->flag = 0;
496 KeyFlag[i]->status = 1;
501 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
502 if ( DoorFlag[2]->flag == 1 )
503 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
505 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
507 for ( i=2; i < 3; i++ )
508 if (DoorFlag[i]->flag == 1) {
509 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
510 DoorFlag[i]->status = 1; // Tells ui to redraw button
513 //------------------------------------------------------------
514 // A simple frame time counter for animating the walls...
515 //------------------------------------------------------------
516 Temp = timer_get_fixed_seconds();
517 DeltaTime = Temp - Time;
519 //------------------------------------------------------------
520 // Draw the wall in the little 64x64 box
521 //------------------------------------------------------------
522 gr_set_current_canvas( WallViewBox->canvas );
523 if (Cursegp->sides[Curside].wall_num != -1) {
524 type = Walls[Cursegp->sides[Curside].wall_num].type;
525 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
526 if (DeltaTime > ((F1_0*200)/1000)) {
530 if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
532 PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
533 gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
535 if (type == WALL_OPEN)
536 gr_clear_canvas( CBLACK );
538 if (Cursegp->sides[Curside].tmap_num2 > 0)
539 gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
541 PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
542 gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
547 gr_clear_canvas( CGREY );
549 //------------------------------------------------------------
550 // If anything changes in the ui system, redraw all the text that
551 // identifies this wall.
552 //------------------------------------------------------------
553 if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
554 if ( Cursegp->sides[Curside].wall_num > -1 ) {
555 ui_wprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num);
556 switch (Walls[Cursegp->sides[Curside].wall_num].type) {
558 ui_wprintf_at( MainWindow, 12, 23, " Type: Normal " );
561 ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
564 ui_wprintf_at( MainWindow, 12, 23, " Type: Door " );
565 ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
568 ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
571 ui_wprintf_at( MainWindow, 12, 23, " Type: Open " );
574 ui_wprintf_at( MainWindow, 12, 23, " Type: Closed " );
577 ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown " );
580 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
581 ui_wprintf_at( MainWindow, 223, 6, " " );
583 ui_wprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
584 ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger );
586 ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
587 ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
588 ui_wprintf_at( MainWindow, 12, 40, " Clip: none ");
589 ui_wprintf_at( MainWindow, 12, 57, " Trigger: none ");
591 Update_flags |= UF_WORLD_CHANGED;
593 if ( QuitButton->pressed || (last_keypress==KEY_ESC) ) {
598 old_wall_num = Cursegp->sides[Curside].wall_num;
602 //---------------------------------------------------------------------
603 // Restore all walls to original status (closed doors, repaired walls)
604 int wall_restore_all()
609 for (i=0;i<Num_walls;i++) {
610 if (Walls[i].flags & WALL_BLASTED) {
611 Walls[i].hps = WALL_HPS;
612 Walls[i].flags &= ~WALL_BLASTED;
614 if (Walls[i].flags & WALL_DOOR_OPENED)
615 Walls[i].flags &= ~WALL_DOOR_OPENED;
616 if (Walls[i].flags & WALL_DOOR_OPENING)
617 Walls[i].flags &= ~WALL_DOOR_OPENING;
620 for (i=0;i<Num_open_doors;i++)
623 for (i=0;i<Num_segments;i++)
624 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
625 wall_num = Segments[i].sides[j].wall_num;
627 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
628 (Walls[wall_num].type == WALL_DOOR))
629 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
632 for (i=0;i<Num_triggers;i++)
633 Triggers[i].flags |= TRIGGER_ON;
635 Update_flags |= UF_GAME_VIEW_CHANGED;
641 //---------------------------------------------------------------------
642 // Delete a specific wall.
643 int wall_delete_bogus(short wall_num)
648 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
649 mprintf((0,"WALL IS NOT BOGUS.\n"));
653 // Delete bogus wall and slide all above walls down one slot
654 for (w=wall_num; w<Num_walls; w++) {
655 Walls[w] = Walls[w+1];
660 for (seg=0;seg<=Highest_segment_index;seg++)
661 if (Segments[seg].segnum != -1)
662 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
663 if (Segments[seg].sides[side].wall_num > wall_num)
664 Segments[seg].sides[side].wall_num--;
666 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
672 //---------------------------------------------------------------------
673 // Remove a specific side.
674 int wall_remove_side(segment *seg, short side)
681 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
682 csegp = &Segments[seg->children[side]];
683 Connectside = find_connect_side(seg, csegp);
685 remove_trigger(seg, side);
686 remove_trigger(csegp, Connectside);
688 // Remove walls 'wall_num' and connecting side 'wall_num'
690 lower_wallnum = seg->sides[side].wall_num;
691 if (csegp->sides[Connectside].wall_num < lower_wallnum)
692 lower_wallnum = csegp->sides[Connectside].wall_num;
694 if (Walls[lower_wallnum].linked_wall != -1)
695 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
696 if (Walls[lower_wallnum+1].linked_wall != -1)
697 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
699 for (w=lower_wallnum;w<Num_walls-2;w++)
700 Walls[w] = Walls[w+2];
704 for (s=0;s<=Highest_segment_index;s++)
705 if (Segments[s].segnum != -1)
706 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
707 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
708 Segments[s].sides[w].wall_num -= 2;
710 // Destroy any links to the deleted wall.
711 for (t=0;t<Num_triggers;t++)
712 for (l=0;l<Triggers[t].num_links;l++)
713 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
714 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
715 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
716 Triggers[t].side[t1] = Triggers[t].side[t1+1];
718 Triggers[t].num_links--;
721 // Destroy control center links as well.
722 for (l=0;l<ControlCenterTriggers.num_links;l++)
723 if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
724 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
725 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
726 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
728 ControlCenterTriggers.num_links--;
731 seg->sides[side].wall_num = -1;
732 csegp->sides[Connectside].wall_num = -1;
734 Update_flags |= UF_WORLD_CHANGED;
738 editor_status( "Can't remove wall. No wall present.");
742 //---------------------------------------------------------------------
743 // Remove a special wall.
746 return wall_remove_side(Cursegp, Curside);
749 //---------------------------------------------------------------------
750 // Add a wall to curside
751 int wall_add_to_side(segment *segp, int side, sbyte type)
756 if (add_wall(segp, side)) {
757 csegp = &Segments[segp->children[side]];
758 connectside = find_connect_side(segp, csegp);
760 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
761 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
763 Walls[segp->sides[side].wall_num].sidenum = side;
764 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
766 Walls[segp->sides[side].wall_num].flags = 0;
767 Walls[csegp->sides[connectside].wall_num].flags = 0;
769 Walls[segp->sides[side].wall_num].type = type;
770 Walls[csegp->sides[connectside].wall_num].type = type;
772 // Walls[segp->sides[side].wall_num].trigger = -1;
773 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
775 Walls[segp->sides[side].wall_num].clip_num = -1;
776 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
778 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
779 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
781 if (type == WALL_BLASTABLE) {
782 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
783 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
785 //Walls[segp->sides[side].wall_num].clip_num = 0;
786 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
789 if (type != WALL_DOOR) {
790 segp->sides[side].tmap_num2 = 0;
791 csegp->sides[connectside].tmap_num2 = 0;
794 if (type == WALL_DOOR) {
795 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
796 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
798 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
799 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
802 //Update_flags |= UF_WORLD_CHANGED;
805 // return NextWall(); //assign a clip num
806 return wall_assign_door(Current_door_type);
809 editor_status( "Cannot add wall here, no children" );
815 //---------------------------------------------------------------------
816 // Add a wall to markedside
817 int wall_add_to_markedside(sbyte type)
822 if (add_wall(Markedsegp, Markedside)) {
823 int wall_num, cwall_num;
824 csegp = &Segments[Markedsegp->children[Markedside]];
826 Connectside = find_connect_side(Markedsegp, csegp);
828 wall_num = Markedsegp->sides[Markedside].wall_num;
829 cwall_num = csegp->sides[Connectside].wall_num;
831 Walls[wall_num].segnum = Markedsegp-Segments;
832 Walls[cwall_num].segnum = csegp-Segments;
834 Walls[wall_num].sidenum = Markedside;
835 Walls[cwall_num].sidenum = Connectside;
837 Walls[wall_num].flags = 0;
838 Walls[cwall_num].flags = 0;
840 Walls[wall_num].type = type;
841 Walls[cwall_num].type = type;
843 Walls[wall_num].trigger = -1;
844 Walls[cwall_num].trigger = -1;
846 Walls[wall_num].clip_num = -1;
847 Walls[cwall_num].clip_num = -1;
849 Walls[wall_num].keys = KEY_NONE;
850 Walls[cwall_num].keys = KEY_NONE;
852 if (type == WALL_BLASTABLE) {
853 Walls[wall_num].hps = WALL_HPS;
854 Walls[cwall_num].hps = WALL_HPS;
856 Walls[wall_num].clip_num = 0;
857 Walls[cwall_num].clip_num = 0;
860 if (type != WALL_DOOR) {
861 Markedsegp->sides[Markedside].tmap_num2 = 0;
862 csegp->sides[Connectside].tmap_num2 = 0;
865 Update_flags |= UF_WORLD_CHANGED;
868 editor_status( "Cannot add wall here, no children" );
874 int wall_add_door_flag(sbyte flag)
879 if (Cursegp->sides[Curside].wall_num == -1)
881 editor_status("Cannot change flag. No wall at Curside.");
885 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
887 editor_status("Cannot change flag. No door at Curside.");
891 csegp = &Segments[Cursegp->children[Curside]];
892 Connectside = find_connect_side(Cursegp, csegp);
894 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
895 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
897 Update_flags |= UF_ED_STATE_CHANGED;
901 int wall_remove_door_flag(sbyte flag)
906 if (Cursegp->sides[Curside].wall_num == -1)
908 editor_status("Cannot change flag. No wall at Curside.");
912 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
914 editor_status("Cannot change flag. No door at Curside.");
918 csegp = &Segments[Cursegp->children[Curside]];
919 Connectside = find_connect_side(Cursegp, csegp);
921 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
922 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
924 Update_flags |= UF_ED_STATE_CHANGED;
929 int bind_wall_to_control_center() {
934 if (Cursegp->sides[Curside].wall_num == -1) {
935 editor_status("No wall at Curside.");
939 link_num = ControlCenterTriggers.num_links;
940 for (i=0;i<link_num;i++)
941 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
942 editor_status("Curside already bound to Control Center.");
946 // Error checking completed, actual binding begins
947 ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
948 ControlCenterTriggers.side[link_num] = Curside;
949 ControlCenterTriggers.num_links++;
951 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
952 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
954 editor_status("Wall linked to control center");
959 //link two doors, curseg/curside and markedseg/markedside
960 int wall_link_doors()
962 wall *w1=NULL,*w2=NULL;
964 if (Cursegp->sides[Curside].wall_num != -1)
965 w1 = &Walls[Cursegp->sides[Curside].wall_num];
967 if (Markedsegp->sides[Markedside].wall_num != -1)
968 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
970 if (!w1 || w1->type != WALL_DOOR) {
971 editor_status("Curseg/curside is not a door");
975 if (!w2 || w2->type != WALL_DOOR) {
976 editor_status("Markedseg/markedside is not a door");
980 if (w1->linked_wall != -1)
981 editor_status("Curseg/curside is already linked");
983 if (w2->linked_wall != -1)
984 editor_status("Markedseg/markedside is already linked");
986 w1->linked_wall = w2-Walls;
987 w2->linked_wall = w1-Walls;
992 int wall_unlink_door()
996 if (Cursegp->sides[Curside].wall_num != -1)
997 w1 = &Walls[Cursegp->sides[Curside].wall_num];
999 if (!w1 || w1->type != WALL_DOOR) {
1000 editor_status("Curseg/curside is not a door");
1004 if (w1->linked_wall == -1)
1005 editor_status("Curseg/curside is not linked");
1007 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1009 Walls[w1->linked_wall].linked_wall = -1;
1010 w1->linked_wall = -1;
1016 #define DIAGNOSTIC_MESSAGE_MAX 150
1020 int w, seg, side, wall_count, trigger_count;
1022 count_wall CountedWalls[MAX_WALLS];
1023 char Message[DIAGNOSTIC_MESSAGE_MAX];
1027 for (seg=0;seg<=Highest_segment_index;seg++)
1028 if (Segments[seg].segnum != -1) {
1029 // Check fuelcenters
1030 matcen_num = Segments[seg].matcen_num;
1031 if (matcen_num == 0)
1032 if (RobotCenters[0].segnum != seg) {
1033 mprintf((0,"Fixing Matcen 0\n"));
1034 Segments[seg].matcen_num = -1;
1037 if (matcen_num > -1)
1038 if (RobotCenters[matcen_num].segnum != seg) {
1039 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1040 mprintf((0,"Fixing....\n"));
1041 RobotCenters[matcen_num].segnum = seg;
1044 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1045 if (Segments[seg].sides[side].wall_num != -1) {
1046 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1047 CountedWalls[wall_count].segnum = seg;
1048 CountedWalls[wall_count].sidenum = side;
1050 // Check if segnum is bogus
1051 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1052 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1055 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1056 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1063 mprintf((0,"Wall Count = %d\n", wall_count));
1065 if (wall_count != Num_walls) {
1066 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1067 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1068 Num_walls = wall_count;
1069 editor_status("Num_walls set to %d\n", Num_walls);
1073 // Check validity of Walls array.
1074 for (w=0; w<Num_walls; w++) {
1075 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1076 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1077 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1078 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1079 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1080 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1081 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1085 if (CountedWalls[w].wallnum >= Num_walls)
1086 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1088 if (Walls[w].segnum == -1) {
1089 mprintf((0, "Wall[%d] is BOGUS\n", w));
1090 for (seg=0;seg<=Highest_segment_index;seg++)
1091 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1092 if (Segments[seg].sides[side].wall_num == w) {
1093 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1099 for (w1=0; w1<wall_count; w1++) {
1100 for (w2=w1+1; w2<wall_count; w2++)
1101 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1102 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1103 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1104 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1106 if (Walls[w1].trigger != -1) trigger_count++;
1109 if (trigger_count != Num_triggers) {
1110 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1111 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1112 Num_triggers = trigger_count;
1113 editor_status("Num_triggers set to %d\n", Num_triggers);
1117 mprintf((0,"Trigger Count = %d\n", trigger_count));
1119 for (t=0; t<trigger_count; t++) {
1120 if (Triggers[t].flags & TRIGGER_MATCEN)
1122 if (Triggers[t].num_links < 1)
1123 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1125 for (l=0;l<Triggers[t].num_links;l++) {
1126 if (!Segments[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1127 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1131 if (Triggers[t].flags & TRIGGER_EXIT)
1132 if (Triggers[t].num_links != 0)
1133 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1135 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1136 for (l=0;l<Triggers[t].num_links;l++) {
1137 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1138 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1139 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1144 for (l=0;l<ControlCenterTriggers.num_links;l++)
1145 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1146 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1147 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1155 int delete_all_walls()
1157 char Message[DIAGNOSTIC_MESSAGE_MAX];
1160 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1161 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1162 for (seg=0;seg<=Highest_segment_index;seg++)
1163 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1164 Segments[seg].sides[side].wall_num = -1;
1174 int delete_all_triggers()
1176 char Message[DIAGNOSTIC_MESSAGE_MAX];
1179 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1180 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1182 for (w=0; w<Num_walls; w++)
1183 Walls[w].trigger=-1;
1192 int dump_walls_info()
1197 fp = fopen("WALL.OUT", "wt");
1199 fprintf(fp, "Num_walls %d\n", Num_walls);
1201 for (w=0; w<Num_walls; w++) {
1203 fprintf(fp, "WALL #%d\n", w);
1204 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1205 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1207 switch (Walls[w].type) {
1209 fprintf(fp, " type: NORMAL\n");
1211 case WALL_BLASTABLE:
1212 fprintf(fp, " type: BLASTABLE\n");
1215 fprintf(fp, " type: DOOR\n");
1218 fprintf(fp, " type: ILLUSION\n");
1221 fprintf(fp, " type: OPEN\n");
1224 fprintf(fp, " type: CLOSED\n");
1227 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1231 fprintf(fp, " flags:\n");
1233 if (Walls[w].flags & WALL_BLASTED)
1234 fprintf(fp, " BLASTED\n");
1235 if (Walls[w].flags & WALL_DOOR_OPENED)
1236 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1237 if (Walls[w].flags & WALL_DOOR_OPENING)
1238 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1239 if (Walls[w].flags & WALL_DOOR_LOCKED)
1240 fprintf(fp, " DOOR_LOCKED\n");
1241 if (Walls[w].flags & WALL_DOOR_AUTO)
1242 fprintf(fp, " DOOR_AUTO\n");
1243 if (Walls[w].flags & WALL_ILLUSION_OFF)
1244 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1245 //if (Walls[w].flags & WALL_FUELCEN)
1246 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1248 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1249 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1251 switch (Walls[w].keys) {
1253 fprintf(fp, " key: NONE\n");
1256 fprintf(fp, " key: BLUE\n");
1259 fprintf(fp, " key: RED\n");
1262 fprintf(fp, " key: NONE\n");
1265 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1269 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1276 // ------------------------------------------------------------------------------------------------
1277 void copy_old_wall_data_to_new(int owall, int nwall)
1279 Walls[nwall].flags = Walls[owall].flags;
1280 Walls[nwall].type = Walls[owall].type;
1281 Walls[nwall].clip_num = Walls[owall].clip_num;
1282 Walls[nwall].keys = Walls[owall].keys;
1283 Walls[nwall].hps = Walls[owall].hps;
1284 Walls[nwall].state = Walls[owall].state;
1285 Walls[nwall].linked_wall = -1;
1287 Walls[nwall].trigger = -1;
1289 if (Walls[owall].trigger != -1) {
1290 editor_status("Warning: Trigger not copied in group copy.");
1294 //typedef struct trigger {
1301 // short seg[MAX_WALLS_PER_LINK];
1302 // short side[MAX_WALLS_PER_LINK];
1306 // ------------------------------------------------------------------------------------------------
1307 void copy_group_walls(int old_group, int new_group)
1309 int i,j,old_seg, new_seg;
1311 for (i=0; i<GroupList[old_group].num_segments; i++) {
1312 old_seg = GroupList[old_group].segments[i];
1313 new_seg = GroupList[new_group].segments[i];
1315 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1316 if (Segments[old_seg].sides[j].wall_num != -1) {
1317 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1318 Segments[new_seg].sides[j].wall_num = Num_walls;
1319 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1320 Walls[Num_walls].segnum = new_seg;
1321 Walls[Num_walls].sidenum = j;
1323 Assert(Num_walls < MAX_WALLS);
1329 int Validate_walls=1;
1331 // --------------------------------------------------------------------------------------------------------
1332 // This function should be in medwall.c.
1333 // Make sure all wall/segment connections are valid.
1334 void check_wall_validity(void)
1337 int segnum, sidenum, wall_num;
1338 sbyte wall_flags[MAX_WALLS];
1340 if (!Validate_walls)
1343 for (i=0; i<Num_walls; i++) {
1344 segnum = Walls[i].segnum;
1345 sidenum = Walls[i].sidenum;
1347 if (Segments[segnum].sides[sidenum].wall_num != i) {
1348 if (!Validate_walls)
1350 Int3(); // Error! Your mine has been invalidated!
1351 // Do not continue! Do not save!
1352 // Remember your last action and Contact Mike!
1353 // To continue, set the variable Validate_walls to 1 by doing:
1354 // /Validate_walls = 1
1355 // Then do the usual /eip++;g
1360 for (i=0; i<MAX_WALLS; i++)
1363 for (i=0; i<=Highest_segment_index; i++) {
1364 if (Segments[i].segnum != -1)
1365 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1367 wall_num = Segments[i].sides[j].wall_num;
1368 if (wall_num != -1) {
1369 if (wall_flags[wall_num] != 0) {
1370 if (!Validate_walls)
1372 Int3(); // Error! Your mine has been invalidated!
1373 // Do not continue! Do not save!
1374 // Remember your last action and Contact Mike!
1375 // To continue, set the variable Validate_walls to 1 by doing:
1376 // /Validate_walls = 1
1377 // Then do the usual /eip++;g
1380 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1381 if (!Validate_walls)
1383 Int3(); // Error! Your mine has been invalidated!
1384 // Do not continue! Do not save!
1385 // Remember your last action and Contact Mike!
1386 // To continue, set the variable Validate_walls to 1 by doing:
1387 // /Validate_walls = 1
1388 // Then do the usual /eip++;g
1391 wall_flags[wall_num] = 1;