1 /* $Id: medwall.c,v 1.8 2005-07-01 09:52:29 chris 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.8 2005-07-01 09:52:29 chris 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)
437 for ( i=0; i < 3; i++ ) {
438 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
439 DoorFlag[i]->status = 1; // Tells ui to redraw button
441 for ( i=0; i < 4; i++ ) {
442 KeyFlag[i]->flag = 0; // Tells ui that this button isn't checked
443 KeyFlag[i]->status = 1; // Tells ui to redraw button
446 if ( Cursegp->sides[Curside].wall_num != -1)
448 wall *w = &Walls[Cursegp->sides[Curside].wall_num];
450 ui_checkbox_check(DoorFlag[0], w->flags & WALL_DOOR_LOCKED);
451 ui_checkbox_check(DoorFlag[1], w->flags & WALL_DOOR_AUTO);
452 ui_checkbox_check(DoorFlag[2], w->flags & WALL_ILLUSION_OFF);
454 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
455 KeyFlag[0]->flag = 1;
456 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
457 KeyFlag[1]->flag = 1;
458 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
459 KeyFlag[2]->flag = 1;
460 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
461 KeyFlag[3]->flag = 1;
465 //------------------------------------------------------------
466 // If any of the checkboxes that control the wallflags are set, then
467 // update the corresponding wall flag.
468 //------------------------------------------------------------
470 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
471 if ( DoorFlag[0]->flag == 1 )
472 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
474 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
475 if ( DoorFlag[1]->flag == 1 )
476 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
478 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
480 //------------------------------------------------------------
481 // If any of the radio buttons that control the mode are set, then
482 // update the corresponding key.
483 //------------------------------------------------------------
484 for ( i=0; i < 4; i++ ) {
485 if ( KeyFlag[i]->flag == 1 ) {
486 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
487 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
491 for (i = 0; i < 2; i++)
492 ui_checkbox_check(DoorFlag[i], 0);
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 extern void wall_close_door_num(int door_num);
605 // Restore all walls to original status (closed doors, repaired walls)
606 int wall_restore_all()
611 for (i=0;i<Num_walls;i++) {
612 if (Walls[i].flags & WALL_BLASTED) {
613 Walls[i].hps = WALL_HPS;
614 Walls[i].flags &= ~WALL_BLASTED;
616 if (Walls[i].flags & WALL_DOOR_OPENED)
617 Walls[i].flags &= ~WALL_DOOR_OPENED;
618 if (Walls[i].flags & WALL_DOOR_OPENING)
619 Walls[i].flags &= ~WALL_DOOR_OPENING;
622 for (i=0;i<Num_open_doors;i++)
623 wall_close_door_num(i);
625 for (i=0;i<Num_segments;i++)
626 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
627 wall_num = Segments[i].sides[j].wall_num;
629 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
630 (Walls[wall_num].type == WALL_DOOR))
631 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
634 for (i=0;i<Num_triggers;i++)
635 Triggers[i].flags |= TRIGGER_ON;
637 Update_flags |= UF_GAME_VIEW_CHANGED;
643 //---------------------------------------------------------------------
644 // Delete a specific wall.
645 int wall_delete_bogus(short wall_num)
650 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
651 mprintf((0,"WALL IS NOT BOGUS.\n"));
655 // Delete bogus wall and slide all above walls down one slot
656 for (w=wall_num; w<Num_walls; w++) {
657 Walls[w] = Walls[w+1];
662 for (seg=0;seg<=Highest_segment_index;seg++)
663 if (Segments[seg].segnum != -1)
664 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
665 if (Segments[seg].sides[side].wall_num > wall_num)
666 Segments[seg].sides[side].wall_num--;
668 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
674 //---------------------------------------------------------------------
675 // Remove a specific side.
676 int wall_remove_side(segment *seg, short side)
683 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
684 csegp = &Segments[seg->children[side]];
685 Connectside = find_connect_side(seg, csegp);
687 remove_trigger(seg, side);
688 remove_trigger(csegp, Connectside);
690 // Remove walls 'wall_num' and connecting side 'wall_num'
692 lower_wallnum = seg->sides[side].wall_num;
693 if (csegp->sides[Connectside].wall_num < lower_wallnum)
694 lower_wallnum = csegp->sides[Connectside].wall_num;
696 if (Walls[lower_wallnum].linked_wall != -1)
697 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
698 if (Walls[lower_wallnum+1].linked_wall != -1)
699 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
701 for (w=lower_wallnum;w<Num_walls-2;w++)
702 Walls[w] = Walls[w+2];
706 for (s=0;s<=Highest_segment_index;s++)
707 if (Segments[s].segnum != -1)
708 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
709 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
710 Segments[s].sides[w].wall_num -= 2;
712 // Destroy any links to the deleted wall.
713 for (t=0;t<Num_triggers;t++)
714 for (l=0;l<Triggers[t].num_links;l++)
715 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
716 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
717 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
718 Triggers[t].side[t1] = Triggers[t].side[t1+1];
720 Triggers[t].num_links--;
723 // Destroy control center links as well.
724 for (l=0;l<ControlCenterTriggers.num_links;l++)
725 if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
726 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
727 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
728 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
730 ControlCenterTriggers.num_links--;
733 seg->sides[side].wall_num = -1;
734 csegp->sides[Connectside].wall_num = -1;
736 Update_flags |= UF_WORLD_CHANGED;
740 editor_status( "Can't remove wall. No wall present.");
744 //---------------------------------------------------------------------
745 // Remove a special wall.
748 return wall_remove_side(Cursegp, Curside);
751 //---------------------------------------------------------------------
752 // Add a wall to curside
753 int wall_add_to_side(segment *segp, int side, sbyte type)
758 if (add_wall(segp, side)) {
759 csegp = &Segments[segp->children[side]];
760 connectside = find_connect_side(segp, csegp);
762 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
763 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
765 Walls[segp->sides[side].wall_num].sidenum = side;
766 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
768 Walls[segp->sides[side].wall_num].flags = 0;
769 Walls[csegp->sides[connectside].wall_num].flags = 0;
771 Walls[segp->sides[side].wall_num].type = type;
772 Walls[csegp->sides[connectside].wall_num].type = type;
774 // Walls[segp->sides[side].wall_num].trigger = -1;
775 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
777 Walls[segp->sides[side].wall_num].clip_num = -1;
778 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
780 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
781 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
783 if (type == WALL_BLASTABLE) {
784 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
785 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
787 //Walls[segp->sides[side].wall_num].clip_num = 0;
788 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
791 if (type != WALL_DOOR) {
792 segp->sides[side].tmap_num2 = 0;
793 csegp->sides[connectside].tmap_num2 = 0;
796 if (type == WALL_DOOR) {
797 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
798 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
800 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
801 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
804 //Update_flags |= UF_WORLD_CHANGED;
807 // return NextWall(); //assign a clip num
808 return wall_assign_door(Current_door_type);
811 editor_status( "Cannot add wall here, no children" );
817 //---------------------------------------------------------------------
818 // Add a wall to markedside
819 int wall_add_to_markedside(sbyte type)
824 if (add_wall(Markedsegp, Markedside)) {
825 int wall_num, cwall_num;
826 csegp = &Segments[Markedsegp->children[Markedside]];
828 Connectside = find_connect_side(Markedsegp, csegp);
830 wall_num = Markedsegp->sides[Markedside].wall_num;
831 cwall_num = csegp->sides[Connectside].wall_num;
833 Walls[wall_num].segnum = Markedsegp-Segments;
834 Walls[cwall_num].segnum = csegp-Segments;
836 Walls[wall_num].sidenum = Markedside;
837 Walls[cwall_num].sidenum = Connectside;
839 Walls[wall_num].flags = 0;
840 Walls[cwall_num].flags = 0;
842 Walls[wall_num].type = type;
843 Walls[cwall_num].type = type;
845 Walls[wall_num].trigger = -1;
846 Walls[cwall_num].trigger = -1;
848 Walls[wall_num].clip_num = -1;
849 Walls[cwall_num].clip_num = -1;
851 Walls[wall_num].keys = KEY_NONE;
852 Walls[cwall_num].keys = KEY_NONE;
854 if (type == WALL_BLASTABLE) {
855 Walls[wall_num].hps = WALL_HPS;
856 Walls[cwall_num].hps = WALL_HPS;
858 Walls[wall_num].clip_num = 0;
859 Walls[cwall_num].clip_num = 0;
862 if (type != WALL_DOOR) {
863 Markedsegp->sides[Markedside].tmap_num2 = 0;
864 csegp->sides[Connectside].tmap_num2 = 0;
867 Update_flags |= UF_WORLD_CHANGED;
870 editor_status( "Cannot add wall here, no children" );
876 int wall_add_door_flag(sbyte flag)
881 if (Cursegp->sides[Curside].wall_num == -1)
883 editor_status("Cannot change flag. No wall at Curside.");
887 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
889 editor_status("Cannot change flag. No door at Curside.");
893 csegp = &Segments[Cursegp->children[Curside]];
894 Connectside = find_connect_side(Cursegp, csegp);
896 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
897 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
899 Update_flags |= UF_ED_STATE_CHANGED;
903 int wall_remove_door_flag(sbyte flag)
908 if (Cursegp->sides[Curside].wall_num == -1)
910 editor_status("Cannot change flag. No wall at Curside.");
914 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
916 editor_status("Cannot change flag. No door at Curside.");
920 csegp = &Segments[Cursegp->children[Curside]];
921 Connectside = find_connect_side(Cursegp, csegp);
923 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
924 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
926 Update_flags |= UF_ED_STATE_CHANGED;
931 int bind_wall_to_control_center() {
936 if (Cursegp->sides[Curside].wall_num == -1) {
937 editor_status("No wall at Curside.");
941 link_num = ControlCenterTriggers.num_links;
942 for (i=0;i<link_num;i++)
943 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
944 editor_status("Curside already bound to Control Center.");
948 // Error checking completed, actual binding begins
949 ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
950 ControlCenterTriggers.side[link_num] = Curside;
951 ControlCenterTriggers.num_links++;
953 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
954 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
956 editor_status("Wall linked to control center");
961 //link two doors, curseg/curside and markedseg/markedside
962 int wall_link_doors()
964 wall *w1=NULL,*w2=NULL;
966 if (Cursegp->sides[Curside].wall_num != -1)
967 w1 = &Walls[Cursegp->sides[Curside].wall_num];
969 if (Markedsegp->sides[Markedside].wall_num != -1)
970 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
972 if (!w1 || w1->type != WALL_DOOR) {
973 editor_status("Curseg/curside is not a door");
977 if (!w2 || w2->type != WALL_DOOR) {
978 editor_status("Markedseg/markedside is not a door");
982 if (w1->linked_wall != -1)
983 editor_status("Curseg/curside is already linked");
985 if (w2->linked_wall != -1)
986 editor_status("Markedseg/markedside is already linked");
988 w1->linked_wall = w2-Walls;
989 w2->linked_wall = w1-Walls;
994 int wall_unlink_door()
998 if (Cursegp->sides[Curside].wall_num != -1)
999 w1 = &Walls[Cursegp->sides[Curside].wall_num];
1001 if (!w1 || w1->type != WALL_DOOR) {
1002 editor_status("Curseg/curside is not a door");
1006 if (w1->linked_wall == -1)
1007 editor_status("Curseg/curside is not linked");
1009 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1011 Walls[w1->linked_wall].linked_wall = -1;
1012 w1->linked_wall = -1;
1018 #define DIAGNOSTIC_MESSAGE_MAX 150
1022 int w, seg, side, wall_count, trigger_count;
1024 count_wall CountedWalls[MAX_WALLS];
1025 char Message[DIAGNOSTIC_MESSAGE_MAX];
1029 for (seg=0;seg<=Highest_segment_index;seg++)
1030 if (Segments[seg].segnum != -1) {
1031 // Check fuelcenters
1032 matcen_num = Segment2s[seg].matcen_num;
1033 if (matcen_num == 0)
1034 if (RobotCenters[0].segnum != seg) {
1035 mprintf((0,"Fixing Matcen 0\n"));
1036 Segment2s[seg].matcen_num = -1;
1039 if (matcen_num > -1)
1040 if (RobotCenters[matcen_num].segnum != seg) {
1041 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1042 mprintf((0,"Fixing....\n"));
1043 RobotCenters[matcen_num].segnum = seg;
1046 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1047 if (Segments[seg].sides[side].wall_num != -1) {
1048 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1049 CountedWalls[wall_count].segnum = seg;
1050 CountedWalls[wall_count].sidenum = side;
1052 // Check if segnum is bogus
1053 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1054 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1057 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1058 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1065 mprintf((0,"Wall Count = %d\n", wall_count));
1067 if (wall_count != Num_walls) {
1068 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1069 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1070 Num_walls = wall_count;
1071 editor_status("Num_walls set to %d\n", Num_walls);
1075 // Check validity of Walls array.
1076 for (w=0; w<Num_walls; w++) {
1077 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1078 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1079 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1080 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1081 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1082 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1083 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1087 if (CountedWalls[w].wallnum >= Num_walls)
1088 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1090 if (Walls[w].segnum == -1) {
1091 mprintf((0, "Wall[%d] is BOGUS\n", w));
1092 for (seg=0;seg<=Highest_segment_index;seg++)
1093 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1094 if (Segments[seg].sides[side].wall_num == w) {
1095 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1101 for (w1=0; w1<wall_count; w1++) {
1102 for (w2=w1+1; w2<wall_count; w2++)
1103 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1104 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1105 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1106 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1108 if (Walls[w1].trigger != -1) trigger_count++;
1111 if (trigger_count != Num_triggers) {
1112 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1113 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1114 Num_triggers = trigger_count;
1115 editor_status("Num_triggers set to %d\n", Num_triggers);
1119 mprintf((0,"Trigger Count = %d\n", trigger_count));
1121 for (t=0; t<trigger_count; t++) {
1122 if (Triggers[t].flags & TRIGGER_MATCEN)
1124 if (Triggers[t].num_links < 1)
1125 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1127 for (l=0;l<Triggers[t].num_links;l++) {
1128 if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1129 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1133 if (Triggers[t].flags & TRIGGER_EXIT)
1134 if (Triggers[t].num_links != 0)
1135 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1137 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1138 for (l=0;l<Triggers[t].num_links;l++) {
1139 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1140 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1141 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1146 for (l=0;l<ControlCenterTriggers.num_links;l++)
1147 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1148 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1149 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1157 int delete_all_walls()
1159 char Message[DIAGNOSTIC_MESSAGE_MAX];
1162 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1163 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1164 for (seg=0;seg<=Highest_segment_index;seg++)
1165 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1166 Segments[seg].sides[side].wall_num = -1;
1176 int delete_all_triggers()
1178 char Message[DIAGNOSTIC_MESSAGE_MAX];
1181 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1182 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1184 for (w=0; w<Num_walls; w++)
1185 Walls[w].trigger=-1;
1194 int dump_walls_info()
1199 fp = fopen("WALL.OUT", "wt");
1201 fprintf(fp, "Num_walls %d\n", Num_walls);
1203 for (w=0; w<Num_walls; w++) {
1205 fprintf(fp, "WALL #%d\n", w);
1206 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1207 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1209 switch (Walls[w].type) {
1211 fprintf(fp, " type: NORMAL\n");
1213 case WALL_BLASTABLE:
1214 fprintf(fp, " type: BLASTABLE\n");
1217 fprintf(fp, " type: DOOR\n");
1220 fprintf(fp, " type: ILLUSION\n");
1223 fprintf(fp, " type: OPEN\n");
1226 fprintf(fp, " type: CLOSED\n");
1229 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1233 fprintf(fp, " flags:\n");
1235 if (Walls[w].flags & WALL_BLASTED)
1236 fprintf(fp, " BLASTED\n");
1237 if (Walls[w].flags & WALL_DOOR_OPENED)
1238 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1239 if (Walls[w].flags & WALL_DOOR_OPENING)
1240 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1241 if (Walls[w].flags & WALL_DOOR_LOCKED)
1242 fprintf(fp, " DOOR_LOCKED\n");
1243 if (Walls[w].flags & WALL_DOOR_AUTO)
1244 fprintf(fp, " DOOR_AUTO\n");
1245 if (Walls[w].flags & WALL_ILLUSION_OFF)
1246 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1247 //if (Walls[w].flags & WALL_FUELCEN)
1248 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1250 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1251 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1253 switch (Walls[w].keys) {
1255 fprintf(fp, " key: NONE\n");
1258 fprintf(fp, " key: BLUE\n");
1261 fprintf(fp, " key: RED\n");
1264 fprintf(fp, " key: NONE\n");
1267 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1271 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1278 // ------------------------------------------------------------------------------------------------
1279 void copy_old_wall_data_to_new(int owall, int nwall)
1281 Walls[nwall].flags = Walls[owall].flags;
1282 Walls[nwall].type = Walls[owall].type;
1283 Walls[nwall].clip_num = Walls[owall].clip_num;
1284 Walls[nwall].keys = Walls[owall].keys;
1285 Walls[nwall].hps = Walls[owall].hps;
1286 Walls[nwall].state = Walls[owall].state;
1287 Walls[nwall].linked_wall = -1;
1289 Walls[nwall].trigger = -1;
1291 if (Walls[owall].trigger != -1) {
1292 editor_status("Warning: Trigger not copied in group copy.");
1296 //typedef struct trigger {
1303 // short seg[MAX_WALLS_PER_LINK];
1304 // short side[MAX_WALLS_PER_LINK];
1308 // ------------------------------------------------------------------------------------------------
1309 void copy_group_walls(int old_group, int new_group)
1311 int i,j,old_seg, new_seg;
1313 for (i=0; i<GroupList[old_group].num_segments; i++) {
1314 old_seg = GroupList[old_group].segments[i];
1315 new_seg = GroupList[new_group].segments[i];
1317 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1318 if (Segments[old_seg].sides[j].wall_num != -1) {
1319 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1320 Segments[new_seg].sides[j].wall_num = Num_walls;
1321 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1322 Walls[Num_walls].segnum = new_seg;
1323 Walls[Num_walls].sidenum = j;
1325 Assert(Num_walls < MAX_WALLS);
1331 int Validate_walls=1;
1333 // --------------------------------------------------------------------------------------------------------
1334 // This function should be in medwall.c.
1335 // Make sure all wall/segment connections are valid.
1336 void check_wall_validity(void)
1339 int segnum, sidenum, wall_num;
1340 sbyte wall_flags[MAX_WALLS];
1342 if (!Validate_walls)
1345 for (i=0; i<Num_walls; i++) {
1346 segnum = Walls[i].segnum;
1347 sidenum = Walls[i].sidenum;
1349 if (Segments[segnum].sides[sidenum].wall_num != i) {
1350 if (!Validate_walls)
1352 Int3(); // Error! Your mine has been invalidated!
1353 // Do not continue! Do not save!
1354 // Remember your last action and Contact Mike!
1355 // To continue, set the variable Validate_walls to 1 by doing:
1356 // /Validate_walls = 1
1357 // Then do the usual /eip++;g
1362 for (i=0; i<MAX_WALLS; i++)
1365 for (i=0; i<=Highest_segment_index; i++) {
1366 if (Segments[i].segnum != -1)
1367 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1369 wall_num = Segments[i].sides[j].wall_num;
1370 if (wall_num != -1) {
1371 if (wall_flags[wall_num] != 0) {
1372 if (!Validate_walls)
1374 Int3(); // Error! Your mine has been invalidated!
1375 // Do not continue! Do not save!
1376 // Remember your last action and Contact Mike!
1377 // To continue, set the variable Validate_walls to 1 by doing:
1378 // /Validate_walls = 1
1379 // Then do the usual /eip++;g
1382 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1383 if (!Validate_walls)
1385 Int3(); // Error! Your mine has been invalidated!
1386 // Do not continue! Do not save!
1387 // Remember your last action and Contact Mike!
1388 // To continue, set the variable Validate_walls to 1 by doing:
1389 // /Validate_walls = 1
1390 // Then do the usual /eip++;g
1393 wall_flags[wall_num] = 1;