2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Created from version 1.11 of main\wall.c
29 #include "editor/medwall.h"
31 #include "editor/editor.h"
39 #include "editor/eswitch.h"
51 int wall_add_door_flag(sbyte flag);
52 int wall_add_to_side(segment *segp, int side, sbyte type);
53 int wall_remove_door_flag(sbyte flag);
54 //-------------------------------------------------------------------------
55 // Variables for this module...
56 //-------------------------------------------------------------------------
57 static UI_WINDOW *MainWindow = NULL;
58 static UI_GADGET_USERBOX *WallViewBox;
59 static UI_GADGET_BUTTON *QuitButton;
60 static UI_GADGET_CHECKBOX *DoorFlag[4];
61 static UI_GADGET_RADIO *KeyFlag[4];
63 static int old_wall_num;
65 static int framenum=0;
66 static int Current_door_type=1;
68 typedef struct count_wall {
73 //---------------------------------------------------------------------
74 extern void create_removable_wall(segment *sp, int sidenum, int tmap_num);
76 // Add a wall (removable 2 sided)
77 int add_wall(segment *seg, short side)
82 if (Num_walls < MAX_WALLS-2)
83 if (IS_CHILD(seg->children[side])) {
84 if (seg->sides[side].wall_num == -1) {
85 seg->sides[side].wall_num = Num_walls;
89 csegp = &Segments[seg->children[side]];
90 Connectside = find_connect_side(seg, csegp);
92 if (csegp->sides[Connectside].wall_num == -1) {
93 csegp->sides[Connectside].wall_num = Num_walls;
97 create_removable_wall( seg, side, CurrentTexture );
98 create_removable_wall( csegp, Connectside, CurrentTexture );
106 int wall_assign_door(int door_type)
111 if (Cursegp->sides[Curside].wall_num == -1) {
112 editor_status("Cannot assign door. No wall at Curside.");
116 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) {
117 editor_status("Cannot assign door. No door at Curside.");
121 Current_door_type = door_type;
123 csegp = &Segments[Cursegp->children[Curside]];
124 Connectside = find_connect_side(Cursegp, csegp);
126 Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
127 Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
129 if (WallAnims[door_type].flags & WCF_TMAP1) {
130 Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0];
131 csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0];
132 Cursegp->sides[Curside].tmap_num2 = 0;
133 csegp->sides[Connectside].tmap_num2 = 0;
136 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
137 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
140 Update_flags |= UF_WORLD_CHANGED;
144 int wall_add_blastable()
146 return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
151 return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
154 int wall_add_closed_wall()
156 return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
159 int wall_add_external_wall()
161 if (Cursegp->children[Curside] == -2) {
162 editor_status( "Wall is already external!" );
166 if (IS_CHILD(Cursegp->children[Curside])) {
167 editor_status( "Cannot add external wall here - seg has children" );
171 Cursegp->children[Curside] = -2;
176 int wall_add_illusion()
178 return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
183 return wall_add_door_flag(WALL_DOOR_LOCKED);
186 int wall_unlock_door()
188 return wall_remove_door_flag(WALL_DOOR_LOCKED);
191 int wall_automate_door()
193 return wall_add_door_flag(WALL_DOOR_AUTO);
196 int wall_deautomate_door()
198 return wall_remove_door_flag(WALL_DOOR_AUTO);
204 if (Cursegp->sides[Curside].wall_num < 0)
205 current_wall = Num_walls;
207 current_wall = Cursegp->sides[Curside].wall_num;
210 if (current_wall < 0) current_wall = Num_walls-1;
211 if (current_wall >= Num_walls) current_wall = Num_walls-1;
213 if (Walls[current_wall].segnum == -1) {
214 mprintf((0, "Trying to goto wall at bogus segnum\n"));
218 if (Walls[current_wall].sidenum == -1) {
219 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
223 Cursegp = &Segments[Walls[current_wall].segnum];
224 Curside = Walls[current_wall].sidenum;
233 current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
237 if (current_wall >= Num_walls) current_wall = 0;
238 if (current_wall < 0) current_wall = 0;
240 if (Walls[current_wall].segnum == -1) {
241 mprintf((0, "Trying to goto wall at bogus segnum\n"));
245 if (Walls[current_wall].sidenum == -1) {
246 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
250 Cursegp = &Segments[Walls[current_wall].segnum];
251 Curside = Walls[current_wall].sidenum;
260 if (Cursegp->sides[Curside].wall_num == -1) {
261 editor_status("Cannot assign new wall. No wall on curside.");
265 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
267 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
274 wall_type = Num_wall_anims-1;
276 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
277 Error("Cannot find clip for door.");
279 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
283 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
290 wall_type = Num_wall_anims-1;
292 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
293 Error("Cannot find clip for blastable wall.");
295 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
299 wall_assign_door(wall_type);
301 Update_flags |= UF_WORLD_CHANGED;
308 if (Cursegp->sides[Curside].wall_num == -1) {
309 editor_status("Cannot assign new wall. No wall on curside.");
313 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
315 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
321 if (wall_type >= Num_wall_anims) {
323 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
324 Error("Cannot find clip for door.");
327 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
330 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
336 if (wall_type >= Num_wall_anims) {
338 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
339 Error("Cannot find clip for blastable wall.");
342 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
346 wall_assign_door(wall_type);
348 Update_flags |= UF_WORLD_CHANGED;
353 //-------------------------------------------------------------------------
354 // Called from the editor... does one instance of the wall dialog box
355 //-------------------------------------------------------------------------
360 // Only open 1 instance of this window...
361 if ( MainWindow != NULL ) return 0;
363 // Close other windows.
366 // Open a window with a quit button
367 MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
368 QuitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL );
370 // These are the checkboxes for each door flag.
372 DoorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24;
373 DoorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24;
374 DoorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24;
376 KeyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24;
377 KeyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24;
378 KeyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" ); i += 24;
379 KeyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24;
381 // The little box the wall will appear in.
382 WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
384 // A bunch of buttons...
386 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall );
387 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25;
388 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25;
389 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door ); i += 25;
390 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion); i += 25;
391 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25;
392 // ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all ); i += 25;
393 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall );
394 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25;
395 ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25;
396 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25;
397 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25;
399 old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame.
404 void close_wall_window()
406 if ( MainWindow!=NULL ) {
407 ui_close_window( MainWindow );
412 void do_wall_window()
418 if ( MainWindow == NULL ) return;
420 //------------------------------------------------------------
421 // Call the ui code..
422 //------------------------------------------------------------
423 ui_button_any_drawn = 0;
424 ui_window_do_gadgets(MainWindow);
426 //------------------------------------------------------------
427 // If we change walls, we need to reset the ui code for all
428 // of the checkboxes that control the wall flags.
429 //------------------------------------------------------------
430 if (old_wall_num != Cursegp->sides[Curside].wall_num)
432 if ( Cursegp->sides[Curside].wall_num != -1)
434 wall *w = &Walls[Cursegp->sides[Curside].wall_num];
436 ui_checkbox_check(DoorFlag[0], w->flags & WALL_DOOR_LOCKED);
437 ui_checkbox_check(DoorFlag[1], w->flags & WALL_DOOR_AUTO);
438 ui_checkbox_check(DoorFlag[2], w->flags & WALL_ILLUSION_OFF);
440 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
441 ui_radio_set_value(KeyFlag[0], 1);
442 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
443 ui_radio_set_value(KeyFlag[1], 1);
444 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
445 ui_radio_set_value(KeyFlag[2], 1);
446 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
447 ui_radio_set_value(KeyFlag[3], 1);
451 //------------------------------------------------------------
452 // If any of the checkboxes that control the wallflags are set, then
453 // update the corresponding wall flag.
454 //------------------------------------------------------------
456 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
457 if ( DoorFlag[0]->flag == 1 )
458 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
460 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
461 if ( DoorFlag[1]->flag == 1 )
462 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
464 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
466 //------------------------------------------------------------
467 // If any of the radio buttons that control the mode are set, then
468 // update the corresponding key.
469 //------------------------------------------------------------
470 for ( i=0; i < 4; i++ ) {
471 if ( KeyFlag[i]->flag == 1 ) {
472 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
473 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
477 for (i = 0; i < 2; i++)
478 ui_checkbox_check(DoorFlag[i], 0);
479 for ( i=0; i < 4; i++ ) {
480 if ( KeyFlag[i]->flag == 1 ) {
481 KeyFlag[i]->flag = 0;
482 KeyFlag[i]->status = 1;
487 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
488 if ( DoorFlag[2]->flag == 1 )
489 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
491 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
493 for ( i=2; i < 3; i++ )
494 if (DoorFlag[i]->flag == 1) {
495 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
496 DoorFlag[i]->status = 1; // Tells ui to redraw button
499 //------------------------------------------------------------
500 // A simple frame time counter for animating the walls...
501 //------------------------------------------------------------
502 Temp = timer_get_fixed_seconds();
503 DeltaTime = Temp - Time;
505 //------------------------------------------------------------
506 // Draw the wall in the little 64x64 box
507 //------------------------------------------------------------
508 gr_set_current_canvas( WallViewBox->canvas );
509 if (Cursegp->sides[Curside].wall_num != -1) {
510 type = Walls[Cursegp->sides[Curside].wall_num].type;
511 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
512 if (DeltaTime > ((F1_0*200)/1000)) {
516 if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
518 PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
519 gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
521 if (type == WALL_OPEN)
522 gr_clear_canvas( CBLACK );
524 if (Cursegp->sides[Curside].tmap_num2 > 0)
525 gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
527 PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
528 gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
533 gr_clear_canvas( CGREY );
535 //------------------------------------------------------------
536 // If anything changes in the ui system, redraw all the text that
537 // identifies this wall.
538 //------------------------------------------------------------
539 if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
540 if ( Cursegp->sides[Curside].wall_num > -1 ) {
541 ui_wprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num);
542 switch (Walls[Cursegp->sides[Curside].wall_num].type) {
544 ui_wprintf_at( MainWindow, 12, 23, " Type: Normal " );
547 ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
550 ui_wprintf_at( MainWindow, 12, 23, " Type: Door " );
551 ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
554 ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
557 ui_wprintf_at( MainWindow, 12, 23, " Type: Open " );
560 ui_wprintf_at( MainWindow, 12, 23, " Type: Closed " );
563 ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown " );
566 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
567 ui_wprintf_at( MainWindow, 223, 6, " " );
569 ui_wprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
570 ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger );
572 ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
573 ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
574 ui_wprintf_at( MainWindow, 12, 40, " Clip: none ");
575 ui_wprintf_at( MainWindow, 12, 57, " Trigger: none ");
577 Update_flags |= UF_WORLD_CHANGED;
579 if ( QuitButton->pressed || (last_keypress==KEY_ESC) ) {
584 old_wall_num = Cursegp->sides[Curside].wall_num;
588 //---------------------------------------------------------------------
589 extern void wall_close_door_num(int door_num);
591 // Restore all walls to original status (closed doors, repaired walls)
592 int wall_restore_all()
597 for (i=0;i<Num_walls;i++) {
598 if (Walls[i].flags & WALL_BLASTED) {
599 Walls[i].hps = WALL_HPS;
600 Walls[i].flags &= ~WALL_BLASTED;
602 if (Walls[i].flags & WALL_DOOR_OPENED)
603 Walls[i].flags &= ~WALL_DOOR_OPENED;
604 if (Walls[i].flags & WALL_DOOR_OPENING)
605 Walls[i].flags &= ~WALL_DOOR_OPENING;
608 for (i=0;i<Num_open_doors;i++)
609 wall_close_door_num(i);
611 for (i=0;i<Num_segments;i++)
612 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
613 wall_num = Segments[i].sides[j].wall_num;
615 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
616 (Walls[wall_num].type == WALL_DOOR))
617 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
620 for (i=0;i<Num_triggers;i++)
621 Triggers[i].flags |= TRIGGER_ON;
623 Update_flags |= UF_GAME_VIEW_CHANGED;
629 //---------------------------------------------------------------------
630 // Delete a specific wall.
631 int wall_delete_bogus(short wall_num)
636 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
637 mprintf((0,"WALL IS NOT BOGUS.\n"));
641 // Delete bogus wall and slide all above walls down one slot
642 for (w=wall_num; w<Num_walls; w++) {
643 Walls[w] = Walls[w+1];
648 for (seg=0;seg<=Highest_segment_index;seg++)
649 if (Segments[seg].segnum != -1)
650 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
651 if (Segments[seg].sides[side].wall_num > wall_num)
652 Segments[seg].sides[side].wall_num--;
654 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
660 //---------------------------------------------------------------------
661 // Remove a specific side.
662 int wall_remove_side(segment *seg, short side)
669 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
670 csegp = &Segments[seg->children[side]];
671 Connectside = find_connect_side(seg, csegp);
673 remove_trigger(seg, side);
674 remove_trigger(csegp, Connectside);
676 // Remove walls 'wall_num' and connecting side 'wall_num'
678 lower_wallnum = seg->sides[side].wall_num;
679 if (csegp->sides[Connectside].wall_num < lower_wallnum)
680 lower_wallnum = csegp->sides[Connectside].wall_num;
682 if (Walls[lower_wallnum].linked_wall != -1)
683 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
684 if (Walls[lower_wallnum+1].linked_wall != -1)
685 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
687 for (w=lower_wallnum;w<Num_walls-2;w++)
688 Walls[w] = Walls[w+2];
692 for (s=0;s<=Highest_segment_index;s++)
693 if (Segments[s].segnum != -1)
694 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
695 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
696 Segments[s].sides[w].wall_num -= 2;
698 // Destroy any links to the deleted wall.
699 for (t=0;t<Num_triggers;t++)
700 for (l=0;l<Triggers[t].num_links;l++)
701 if ((Triggers[t].seg[l] == SEGMENT_NUMBER(seg)) && (Triggers[t].side[l] == side)) {
702 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
703 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
704 Triggers[t].side[t1] = Triggers[t].side[t1+1];
706 Triggers[t].num_links--;
709 // Destroy control center links as well.
710 for (l=0;l<ControlCenterTriggers.num_links;l++)
711 if ((ControlCenterTriggers.seg[l] == SEGMENT_NUMBER(seg)) && (ControlCenterTriggers.side[l] == side)) {
712 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
713 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
714 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
716 ControlCenterTriggers.num_links--;
719 seg->sides[side].wall_num = -1;
720 csegp->sides[Connectside].wall_num = -1;
722 Update_flags |= UF_WORLD_CHANGED;
726 editor_status( "Can't remove wall. No wall present.");
730 //---------------------------------------------------------------------
731 // Remove a special wall.
734 return wall_remove_side(Cursegp, Curside);
737 //---------------------------------------------------------------------
738 // Add a wall to curside
739 int wall_add_to_side(segment *segp, int side, sbyte type)
744 if (add_wall(segp, side)) {
745 csegp = &Segments[segp->children[side]];
746 connectside = find_connect_side(segp, csegp);
748 Walls[segp->sides[side].wall_num].segnum = SEGMENT_NUMBER(segp);
749 Walls[csegp->sides[connectside].wall_num].segnum = SEGMENT_NUMBER(csegp);
751 Walls[segp->sides[side].wall_num].sidenum = side;
752 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
754 Walls[segp->sides[side].wall_num].flags = 0;
755 Walls[csegp->sides[connectside].wall_num].flags = 0;
757 Walls[segp->sides[side].wall_num].type = type;
758 Walls[csegp->sides[connectside].wall_num].type = type;
760 // Walls[segp->sides[side].wall_num].trigger = -1;
761 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
763 Walls[segp->sides[side].wall_num].clip_num = -1;
764 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
766 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
767 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
769 if (type == WALL_BLASTABLE) {
770 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
771 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
773 //Walls[segp->sides[side].wall_num].clip_num = 0;
774 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
777 if (type != WALL_DOOR) {
778 segp->sides[side].tmap_num2 = 0;
779 csegp->sides[connectside].tmap_num2 = 0;
782 if (type == WALL_DOOR) {
783 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
784 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
786 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
787 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
790 //Update_flags |= UF_WORLD_CHANGED;
793 // return NextWall(); //assign a clip num
794 return wall_assign_door(Current_door_type);
797 editor_status( "Cannot add wall here, no children" );
803 //---------------------------------------------------------------------
804 // Add a wall to markedside
805 int wall_add_to_markedside(sbyte type)
810 if (add_wall(Markedsegp, Markedside)) {
811 int wall_num, cwall_num;
812 csegp = &Segments[Markedsegp->children[Markedside]];
814 Connectside = find_connect_side(Markedsegp, csegp);
816 wall_num = Markedsegp->sides[Markedside].wall_num;
817 cwall_num = csegp->sides[Connectside].wall_num;
819 Walls[wall_num].segnum = SEGMENT_NUMBER(Markedsegp);
820 Walls[cwall_num].segnum = SEGMENT_NUMBER(csegp);
822 Walls[wall_num].sidenum = Markedside;
823 Walls[cwall_num].sidenum = Connectside;
825 Walls[wall_num].flags = 0;
826 Walls[cwall_num].flags = 0;
828 Walls[wall_num].type = type;
829 Walls[cwall_num].type = type;
831 Walls[wall_num].trigger = -1;
832 Walls[cwall_num].trigger = -1;
834 Walls[wall_num].clip_num = -1;
835 Walls[cwall_num].clip_num = -1;
837 Walls[wall_num].keys = KEY_NONE;
838 Walls[cwall_num].keys = KEY_NONE;
840 if (type == WALL_BLASTABLE) {
841 Walls[wall_num].hps = WALL_HPS;
842 Walls[cwall_num].hps = WALL_HPS;
844 Walls[wall_num].clip_num = 0;
845 Walls[cwall_num].clip_num = 0;
848 if (type != WALL_DOOR) {
849 Markedsegp->sides[Markedside].tmap_num2 = 0;
850 csegp->sides[Connectside].tmap_num2 = 0;
853 Update_flags |= UF_WORLD_CHANGED;
856 editor_status( "Cannot add wall here, no children" );
862 int wall_add_door_flag(sbyte flag)
867 if (Cursegp->sides[Curside].wall_num == -1)
869 editor_status("Cannot change flag. No wall at Curside.");
873 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
875 editor_status("Cannot change flag. No door at Curside.");
879 csegp = &Segments[Cursegp->children[Curside]];
880 Connectside = find_connect_side(Cursegp, csegp);
882 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
883 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
885 Update_flags |= UF_ED_STATE_CHANGED;
889 int wall_remove_door_flag(sbyte flag)
894 if (Cursegp->sides[Curside].wall_num == -1)
896 editor_status("Cannot change flag. No wall at Curside.");
900 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
902 editor_status("Cannot change flag. No door at Curside.");
906 csegp = &Segments[Cursegp->children[Curside]];
907 Connectside = find_connect_side(Cursegp, csegp);
909 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
910 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
912 Update_flags |= UF_ED_STATE_CHANGED;
917 int bind_wall_to_control_center() {
922 if (Cursegp->sides[Curside].wall_num == -1) {
923 editor_status("No wall at Curside.");
927 link_num = ControlCenterTriggers.num_links;
928 for (i=0;i<link_num;i++)
929 if ((SEGMENT_NUMBER(Cursegp) == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
930 editor_status("Curside already bound to Control Center.");
934 // Error checking completed, actual binding begins
935 ControlCenterTriggers.seg[link_num] = SEGMENT_NUMBER(Cursegp);
936 ControlCenterTriggers.side[link_num] = Curside;
937 ControlCenterTriggers.num_links++;
939 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
940 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
942 editor_status("Wall linked to control center");
947 //link two doors, curseg/curside and markedseg/markedside
948 int wall_link_doors()
950 wall *w1=NULL,*w2=NULL;
952 if (Cursegp->sides[Curside].wall_num != -1)
953 w1 = &Walls[Cursegp->sides[Curside].wall_num];
955 if (Markedsegp->sides[Markedside].wall_num != -1)
956 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
958 if (!w1 || w1->type != WALL_DOOR) {
959 editor_status("Curseg/curside is not a door");
963 if (!w2 || w2->type != WALL_DOOR) {
964 editor_status("Markedseg/markedside is not a door");
968 if (w1->linked_wall != -1)
969 editor_status("Curseg/curside is already linked");
971 if (w2->linked_wall != -1)
972 editor_status("Markedseg/markedside is already linked");
974 w1->linked_wall = w2-Walls;
975 w2->linked_wall = w1-Walls;
980 int wall_unlink_door()
984 if (Cursegp->sides[Curside].wall_num != -1)
985 w1 = &Walls[Cursegp->sides[Curside].wall_num];
987 if (!w1 || w1->type != WALL_DOOR) {
988 editor_status("Curseg/curside is not a door");
992 if (w1->linked_wall == -1)
993 editor_status("Curseg/curside is not linked");
995 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
997 Walls[w1->linked_wall].linked_wall = -1;
998 w1->linked_wall = -1;
1004 #define DIAGNOSTIC_MESSAGE_MAX 150
1008 int w, seg, side, wall_count, trigger_count;
1010 count_wall CountedWalls[MAX_WALLS];
1011 char Message[DIAGNOSTIC_MESSAGE_MAX];
1015 for (seg=0;seg<=Highest_segment_index;seg++)
1016 if (Segments[seg].segnum != -1) {
1017 // Check fuelcenters
1018 matcen_num = Segment2s[seg].matcen_num;
1019 if (matcen_num == 0)
1020 if (RobotCenters[0].segnum != seg) {
1021 mprintf((0,"Fixing Matcen 0\n"));
1022 Segment2s[seg].matcen_num = -1;
1025 if (matcen_num > -1)
1026 if (RobotCenters[matcen_num].segnum != seg) {
1027 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1028 mprintf((0,"Fixing....\n"));
1029 RobotCenters[matcen_num].segnum = seg;
1032 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1033 if (Segments[seg].sides[side].wall_num != -1) {
1034 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1035 CountedWalls[wall_count].segnum = seg;
1036 CountedWalls[wall_count].sidenum = side;
1038 // Check if segnum is bogus
1039 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1040 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1043 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1044 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1051 mprintf((0,"Wall Count = %d\n", wall_count));
1053 if (wall_count != Num_walls) {
1054 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1055 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1056 Num_walls = wall_count;
1057 editor_status("Num_walls set to %d\n", Num_walls);
1061 // Check validity of Walls array.
1062 for (w=0; w<Num_walls; w++) {
1063 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1064 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1065 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1066 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1067 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1068 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1069 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1073 if (CountedWalls[w].wallnum >= Num_walls)
1074 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1076 if (Walls[w].segnum == -1) {
1077 mprintf((0, "Wall[%d] is BOGUS\n", w));
1078 for (seg=0;seg<=Highest_segment_index;seg++)
1079 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1080 if (Segments[seg].sides[side].wall_num == w) {
1081 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1087 for (w1=0; w1<wall_count; w1++) {
1088 for (w2=w1+1; w2<wall_count; w2++)
1089 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1090 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1091 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1092 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1094 if (Walls[w1].trigger != -1) trigger_count++;
1097 if (trigger_count != Num_triggers) {
1098 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1099 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1100 Num_triggers = trigger_count;
1101 editor_status("Num_triggers set to %d\n", Num_triggers);
1105 mprintf((0,"Trigger Count = %d\n", trigger_count));
1107 for (t=0; t<trigger_count; t++) {
1108 if (Triggers[t].flags & TRIGGER_MATCEN)
1110 if (Triggers[t].num_links < 1)
1111 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1113 for (l=0;l<Triggers[t].num_links;l++) {
1114 if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1115 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1119 if (Triggers[t].flags & TRIGGER_EXIT)
1120 if (Triggers[t].num_links != 0)
1121 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1123 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1124 for (l=0;l<Triggers[t].num_links;l++) {
1125 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1126 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1127 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1132 for (l=0;l<ControlCenterTriggers.num_links;l++)
1133 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1134 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1135 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1143 int delete_all_walls()
1145 char Message[DIAGNOSTIC_MESSAGE_MAX];
1148 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1149 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1150 for (seg=0;seg<=Highest_segment_index;seg++)
1151 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1152 Segments[seg].sides[side].wall_num = -1;
1162 int delete_all_triggers()
1164 char Message[DIAGNOSTIC_MESSAGE_MAX];
1167 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1168 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1170 for (w=0; w<Num_walls; w++)
1171 Walls[w].trigger=-1;
1180 int dump_walls_info()
1185 fp = fopen("WALL.OUT", "wt");
1187 fprintf(fp, "Num_walls %d\n", Num_walls);
1189 for (w=0; w<Num_walls; w++) {
1191 fprintf(fp, "WALL #%d\n", w);
1192 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1193 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1195 switch (Walls[w].type) {
1197 fprintf(fp, " type: NORMAL\n");
1199 case WALL_BLASTABLE:
1200 fprintf(fp, " type: BLASTABLE\n");
1203 fprintf(fp, " type: DOOR\n");
1206 fprintf(fp, " type: ILLUSION\n");
1209 fprintf(fp, " type: OPEN\n");
1212 fprintf(fp, " type: CLOSED\n");
1215 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1219 fprintf(fp, " flags:\n");
1221 if (Walls[w].flags & WALL_BLASTED)
1222 fprintf(fp, " BLASTED\n");
1223 if (Walls[w].flags & WALL_DOOR_OPENED)
1224 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1225 if (Walls[w].flags & WALL_DOOR_OPENING)
1226 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1227 if (Walls[w].flags & WALL_DOOR_LOCKED)
1228 fprintf(fp, " DOOR_LOCKED\n");
1229 if (Walls[w].flags & WALL_DOOR_AUTO)
1230 fprintf(fp, " DOOR_AUTO\n");
1231 if (Walls[w].flags & WALL_ILLUSION_OFF)
1232 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1233 //if (Walls[w].flags & WALL_FUELCEN)
1234 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1236 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1237 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1239 switch (Walls[w].keys) {
1241 fprintf(fp, " key: NONE\n");
1244 fprintf(fp, " key: BLUE\n");
1247 fprintf(fp, " key: RED\n");
1250 fprintf(fp, " key: NONE\n");
1253 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1257 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1264 // ------------------------------------------------------------------------------------------------
1265 void copy_old_wall_data_to_new(int owall, int nwall)
1267 Walls[nwall].flags = Walls[owall].flags;
1268 Walls[nwall].type = Walls[owall].type;
1269 Walls[nwall].clip_num = Walls[owall].clip_num;
1270 Walls[nwall].keys = Walls[owall].keys;
1271 Walls[nwall].hps = Walls[owall].hps;
1272 Walls[nwall].state = Walls[owall].state;
1273 Walls[nwall].linked_wall = -1;
1275 Walls[nwall].trigger = -1;
1277 if (Walls[owall].trigger != -1) {
1278 editor_status("Warning: Trigger not copied in group copy.");
1282 //typedef struct trigger {
1289 // short seg[MAX_WALLS_PER_LINK];
1290 // short side[MAX_WALLS_PER_LINK];
1294 // ------------------------------------------------------------------------------------------------
1295 void copy_group_walls(int old_group, int new_group)
1297 int i,j,old_seg, new_seg;
1299 for (i=0; i<GroupList[old_group].num_segments; i++) {
1300 old_seg = GroupList[old_group].segments[i];
1301 new_seg = GroupList[new_group].segments[i];
1303 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1304 if (Segments[old_seg].sides[j].wall_num != -1) {
1305 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1306 Segments[new_seg].sides[j].wall_num = Num_walls;
1307 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1308 Walls[Num_walls].segnum = new_seg;
1309 Walls[Num_walls].sidenum = j;
1311 Assert(Num_walls < MAX_WALLS);
1317 int Validate_walls=1;
1319 // --------------------------------------------------------------------------------------------------------
1320 // This function should be in medwall.c.
1321 // Make sure all wall/segment connections are valid.
1322 void check_wall_validity(void)
1325 int segnum, sidenum, wall_num;
1326 sbyte wall_flags[MAX_WALLS];
1328 if (!Validate_walls)
1331 for (i=0; i<Num_walls; i++) {
1332 segnum = Walls[i].segnum;
1333 sidenum = Walls[i].sidenum;
1335 if (Segments[segnum].sides[sidenum].wall_num != i) {
1336 if (!Validate_walls)
1338 Int3(); // Error! Your mine has been invalidated!
1339 // Do not continue! Do not save!
1340 // Remember your last action and Contact Mike!
1341 // To continue, set the variable Validate_walls to 1 by doing:
1342 // /Validate_walls = 1
1343 // Then do the usual /eip++;g
1348 for (i=0; i<MAX_WALLS; i++)
1351 for (i=0; i<=Highest_segment_index; i++) {
1352 if (Segments[i].segnum != -1)
1353 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1355 wall_num = Segments[i].sides[j].wall_num;
1356 if (wall_num != -1) {
1357 if (wall_flags[wall_num] != 0) {
1358 if (!Validate_walls)
1360 Int3(); // Error! Your mine has been invalidated!
1361 // Do not continue! Do not save!
1362 // Remember your last action and Contact Mike!
1363 // To continue, set the variable Validate_walls to 1 by doing:
1364 // /Validate_walls = 1
1365 // Then do the usual /eip++;g
1368 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1369 if (!Validate_walls)
1371 Int3(); // Error! Your mine has been invalidated!
1372 // Do not continue! Do not save!
1373 // Remember your last action and Contact Mike!
1374 // To continue, set the variable Validate_walls to 1 by doing:
1375 // /Validate_walls = 1
1376 // Then do the usual /eip++;g
1379 wall_flags[wall_num] = 1;