1 /* $Id: medwall.c,v 1.9 2005-07-03 13:12:47 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.9 2005-07-03 13:12:47 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 if ( Cursegp->sides[Curside].wall_num != -1)
439 wall *w = &Walls[Cursegp->sides[Curside].wall_num];
441 ui_checkbox_check(DoorFlag[0], w->flags & WALL_DOOR_LOCKED);
442 ui_checkbox_check(DoorFlag[1], w->flags & WALL_DOOR_AUTO);
443 ui_checkbox_check(DoorFlag[2], w->flags & WALL_ILLUSION_OFF);
445 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
446 ui_radio_set_value(KeyFlag[0], 1);
447 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
448 ui_radio_set_value(KeyFlag[1], 1);
449 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
450 ui_radio_set_value(KeyFlag[2], 1);
451 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
452 ui_radio_set_value(KeyFlag[3], 1);
456 //------------------------------------------------------------
457 // If any of the checkboxes that control the wallflags are set, then
458 // update the corresponding wall flag.
459 //------------------------------------------------------------
461 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
462 if ( DoorFlag[0]->flag == 1 )
463 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
465 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
466 if ( DoorFlag[1]->flag == 1 )
467 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
469 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
471 //------------------------------------------------------------
472 // If any of the radio buttons that control the mode are set, then
473 // update the corresponding key.
474 //------------------------------------------------------------
475 for ( i=0; i < 4; i++ ) {
476 if ( KeyFlag[i]->flag == 1 ) {
477 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
478 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
482 for (i = 0; i < 2; i++)
483 ui_checkbox_check(DoorFlag[i], 0);
484 for ( i=0; i < 4; i++ ) {
485 if ( KeyFlag[i]->flag == 1 ) {
486 KeyFlag[i]->flag = 0;
487 KeyFlag[i]->status = 1;
492 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
493 if ( DoorFlag[2]->flag == 1 )
494 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
496 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
498 for ( i=2; i < 3; i++ )
499 if (DoorFlag[i]->flag == 1) {
500 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
501 DoorFlag[i]->status = 1; // Tells ui to redraw button
504 //------------------------------------------------------------
505 // A simple frame time counter for animating the walls...
506 //------------------------------------------------------------
507 Temp = timer_get_fixed_seconds();
508 DeltaTime = Temp - Time;
510 //------------------------------------------------------------
511 // Draw the wall in the little 64x64 box
512 //------------------------------------------------------------
513 gr_set_current_canvas( WallViewBox->canvas );
514 if (Cursegp->sides[Curside].wall_num != -1) {
515 type = Walls[Cursegp->sides[Curside].wall_num].type;
516 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
517 if (DeltaTime > ((F1_0*200)/1000)) {
521 if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
523 PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
524 gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
526 if (type == WALL_OPEN)
527 gr_clear_canvas( CBLACK );
529 if (Cursegp->sides[Curside].tmap_num2 > 0)
530 gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
532 PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
533 gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
538 gr_clear_canvas( CGREY );
540 //------------------------------------------------------------
541 // If anything changes in the ui system, redraw all the text that
542 // identifies this wall.
543 //------------------------------------------------------------
544 if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
545 if ( Cursegp->sides[Curside].wall_num > -1 ) {
546 ui_wprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num);
547 switch (Walls[Cursegp->sides[Curside].wall_num].type) {
549 ui_wprintf_at( MainWindow, 12, 23, " Type: Normal " );
552 ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
555 ui_wprintf_at( MainWindow, 12, 23, " Type: Door " );
556 ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
559 ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
562 ui_wprintf_at( MainWindow, 12, 23, " Type: Open " );
565 ui_wprintf_at( MainWindow, 12, 23, " Type: Closed " );
568 ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown " );
571 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
572 ui_wprintf_at( MainWindow, 223, 6, " " );
574 ui_wprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
575 ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger );
577 ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
578 ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
579 ui_wprintf_at( MainWindow, 12, 40, " Clip: none ");
580 ui_wprintf_at( MainWindow, 12, 57, " Trigger: none ");
582 Update_flags |= UF_WORLD_CHANGED;
584 if ( QuitButton->pressed || (last_keypress==KEY_ESC) ) {
589 old_wall_num = Cursegp->sides[Curside].wall_num;
593 //---------------------------------------------------------------------
594 extern void wall_close_door_num(int door_num);
596 // Restore all walls to original status (closed doors, repaired walls)
597 int wall_restore_all()
602 for (i=0;i<Num_walls;i++) {
603 if (Walls[i].flags & WALL_BLASTED) {
604 Walls[i].hps = WALL_HPS;
605 Walls[i].flags &= ~WALL_BLASTED;
607 if (Walls[i].flags & WALL_DOOR_OPENED)
608 Walls[i].flags &= ~WALL_DOOR_OPENED;
609 if (Walls[i].flags & WALL_DOOR_OPENING)
610 Walls[i].flags &= ~WALL_DOOR_OPENING;
613 for (i=0;i<Num_open_doors;i++)
614 wall_close_door_num(i);
616 for (i=0;i<Num_segments;i++)
617 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
618 wall_num = Segments[i].sides[j].wall_num;
620 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
621 (Walls[wall_num].type == WALL_DOOR))
622 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
625 for (i=0;i<Num_triggers;i++)
626 Triggers[i].flags |= TRIGGER_ON;
628 Update_flags |= UF_GAME_VIEW_CHANGED;
634 //---------------------------------------------------------------------
635 // Delete a specific wall.
636 int wall_delete_bogus(short wall_num)
641 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
642 mprintf((0,"WALL IS NOT BOGUS.\n"));
646 // Delete bogus wall and slide all above walls down one slot
647 for (w=wall_num; w<Num_walls; w++) {
648 Walls[w] = Walls[w+1];
653 for (seg=0;seg<=Highest_segment_index;seg++)
654 if (Segments[seg].segnum != -1)
655 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
656 if (Segments[seg].sides[side].wall_num > wall_num)
657 Segments[seg].sides[side].wall_num--;
659 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
665 //---------------------------------------------------------------------
666 // Remove a specific side.
667 int wall_remove_side(segment *seg, short side)
674 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
675 csegp = &Segments[seg->children[side]];
676 Connectside = find_connect_side(seg, csegp);
678 remove_trigger(seg, side);
679 remove_trigger(csegp, Connectside);
681 // Remove walls 'wall_num' and connecting side 'wall_num'
683 lower_wallnum = seg->sides[side].wall_num;
684 if (csegp->sides[Connectside].wall_num < lower_wallnum)
685 lower_wallnum = csegp->sides[Connectside].wall_num;
687 if (Walls[lower_wallnum].linked_wall != -1)
688 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
689 if (Walls[lower_wallnum+1].linked_wall != -1)
690 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
692 for (w=lower_wallnum;w<Num_walls-2;w++)
693 Walls[w] = Walls[w+2];
697 for (s=0;s<=Highest_segment_index;s++)
698 if (Segments[s].segnum != -1)
699 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
700 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
701 Segments[s].sides[w].wall_num -= 2;
703 // Destroy any links to the deleted wall.
704 for (t=0;t<Num_triggers;t++)
705 for (l=0;l<Triggers[t].num_links;l++)
706 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
707 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
708 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
709 Triggers[t].side[t1] = Triggers[t].side[t1+1];
711 Triggers[t].num_links--;
714 // Destroy control center links as well.
715 for (l=0;l<ControlCenterTriggers.num_links;l++)
716 if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
717 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
718 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
719 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
721 ControlCenterTriggers.num_links--;
724 seg->sides[side].wall_num = -1;
725 csegp->sides[Connectside].wall_num = -1;
727 Update_flags |= UF_WORLD_CHANGED;
731 editor_status( "Can't remove wall. No wall present.");
735 //---------------------------------------------------------------------
736 // Remove a special wall.
739 return wall_remove_side(Cursegp, Curside);
742 //---------------------------------------------------------------------
743 // Add a wall to curside
744 int wall_add_to_side(segment *segp, int side, sbyte type)
749 if (add_wall(segp, side)) {
750 csegp = &Segments[segp->children[side]];
751 connectside = find_connect_side(segp, csegp);
753 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
754 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
756 Walls[segp->sides[side].wall_num].sidenum = side;
757 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
759 Walls[segp->sides[side].wall_num].flags = 0;
760 Walls[csegp->sides[connectside].wall_num].flags = 0;
762 Walls[segp->sides[side].wall_num].type = type;
763 Walls[csegp->sides[connectside].wall_num].type = type;
765 // Walls[segp->sides[side].wall_num].trigger = -1;
766 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
768 Walls[segp->sides[side].wall_num].clip_num = -1;
769 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
771 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
772 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
774 if (type == WALL_BLASTABLE) {
775 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
776 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
778 //Walls[segp->sides[side].wall_num].clip_num = 0;
779 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
782 if (type != WALL_DOOR) {
783 segp->sides[side].tmap_num2 = 0;
784 csegp->sides[connectside].tmap_num2 = 0;
787 if (type == WALL_DOOR) {
788 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
789 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
791 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
792 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
795 //Update_flags |= UF_WORLD_CHANGED;
798 // return NextWall(); //assign a clip num
799 return wall_assign_door(Current_door_type);
802 editor_status( "Cannot add wall here, no children" );
808 //---------------------------------------------------------------------
809 // Add a wall to markedside
810 int wall_add_to_markedside(sbyte type)
815 if (add_wall(Markedsegp, Markedside)) {
816 int wall_num, cwall_num;
817 csegp = &Segments[Markedsegp->children[Markedside]];
819 Connectside = find_connect_side(Markedsegp, csegp);
821 wall_num = Markedsegp->sides[Markedside].wall_num;
822 cwall_num = csegp->sides[Connectside].wall_num;
824 Walls[wall_num].segnum = Markedsegp-Segments;
825 Walls[cwall_num].segnum = csegp-Segments;
827 Walls[wall_num].sidenum = Markedside;
828 Walls[cwall_num].sidenum = Connectside;
830 Walls[wall_num].flags = 0;
831 Walls[cwall_num].flags = 0;
833 Walls[wall_num].type = type;
834 Walls[cwall_num].type = type;
836 Walls[wall_num].trigger = -1;
837 Walls[cwall_num].trigger = -1;
839 Walls[wall_num].clip_num = -1;
840 Walls[cwall_num].clip_num = -1;
842 Walls[wall_num].keys = KEY_NONE;
843 Walls[cwall_num].keys = KEY_NONE;
845 if (type == WALL_BLASTABLE) {
846 Walls[wall_num].hps = WALL_HPS;
847 Walls[cwall_num].hps = WALL_HPS;
849 Walls[wall_num].clip_num = 0;
850 Walls[cwall_num].clip_num = 0;
853 if (type != WALL_DOOR) {
854 Markedsegp->sides[Markedside].tmap_num2 = 0;
855 csegp->sides[Connectside].tmap_num2 = 0;
858 Update_flags |= UF_WORLD_CHANGED;
861 editor_status( "Cannot add wall here, no children" );
867 int wall_add_door_flag(sbyte flag)
872 if (Cursegp->sides[Curside].wall_num == -1)
874 editor_status("Cannot change flag. No wall at Curside.");
878 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
880 editor_status("Cannot change flag. No door at Curside.");
884 csegp = &Segments[Cursegp->children[Curside]];
885 Connectside = find_connect_side(Cursegp, csegp);
887 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
888 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
890 Update_flags |= UF_ED_STATE_CHANGED;
894 int wall_remove_door_flag(sbyte flag)
899 if (Cursegp->sides[Curside].wall_num == -1)
901 editor_status("Cannot change flag. No wall at Curside.");
905 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
907 editor_status("Cannot change flag. No door at Curside.");
911 csegp = &Segments[Cursegp->children[Curside]];
912 Connectside = find_connect_side(Cursegp, csegp);
914 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
915 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
917 Update_flags |= UF_ED_STATE_CHANGED;
922 int bind_wall_to_control_center() {
927 if (Cursegp->sides[Curside].wall_num == -1) {
928 editor_status("No wall at Curside.");
932 link_num = ControlCenterTriggers.num_links;
933 for (i=0;i<link_num;i++)
934 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
935 editor_status("Curside already bound to Control Center.");
939 // Error checking completed, actual binding begins
940 ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
941 ControlCenterTriggers.side[link_num] = Curside;
942 ControlCenterTriggers.num_links++;
944 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
945 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
947 editor_status("Wall linked to control center");
952 //link two doors, curseg/curside and markedseg/markedside
953 int wall_link_doors()
955 wall *w1=NULL,*w2=NULL;
957 if (Cursegp->sides[Curside].wall_num != -1)
958 w1 = &Walls[Cursegp->sides[Curside].wall_num];
960 if (Markedsegp->sides[Markedside].wall_num != -1)
961 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
963 if (!w1 || w1->type != WALL_DOOR) {
964 editor_status("Curseg/curside is not a door");
968 if (!w2 || w2->type != WALL_DOOR) {
969 editor_status("Markedseg/markedside is not a door");
973 if (w1->linked_wall != -1)
974 editor_status("Curseg/curside is already linked");
976 if (w2->linked_wall != -1)
977 editor_status("Markedseg/markedside is already linked");
979 w1->linked_wall = w2-Walls;
980 w2->linked_wall = w1-Walls;
985 int wall_unlink_door()
989 if (Cursegp->sides[Curside].wall_num != -1)
990 w1 = &Walls[Cursegp->sides[Curside].wall_num];
992 if (!w1 || w1->type != WALL_DOOR) {
993 editor_status("Curseg/curside is not a door");
997 if (w1->linked_wall == -1)
998 editor_status("Curseg/curside is not linked");
1000 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1002 Walls[w1->linked_wall].linked_wall = -1;
1003 w1->linked_wall = -1;
1009 #define DIAGNOSTIC_MESSAGE_MAX 150
1013 int w, seg, side, wall_count, trigger_count;
1015 count_wall CountedWalls[MAX_WALLS];
1016 char Message[DIAGNOSTIC_MESSAGE_MAX];
1020 for (seg=0;seg<=Highest_segment_index;seg++)
1021 if (Segments[seg].segnum != -1) {
1022 // Check fuelcenters
1023 matcen_num = Segment2s[seg].matcen_num;
1024 if (matcen_num == 0)
1025 if (RobotCenters[0].segnum != seg) {
1026 mprintf((0,"Fixing Matcen 0\n"));
1027 Segment2s[seg].matcen_num = -1;
1030 if (matcen_num > -1)
1031 if (RobotCenters[matcen_num].segnum != seg) {
1032 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1033 mprintf((0,"Fixing....\n"));
1034 RobotCenters[matcen_num].segnum = seg;
1037 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1038 if (Segments[seg].sides[side].wall_num != -1) {
1039 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1040 CountedWalls[wall_count].segnum = seg;
1041 CountedWalls[wall_count].sidenum = side;
1043 // Check if segnum is bogus
1044 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1045 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1048 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1049 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1056 mprintf((0,"Wall Count = %d\n", wall_count));
1058 if (wall_count != Num_walls) {
1059 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1060 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1061 Num_walls = wall_count;
1062 editor_status("Num_walls set to %d\n", Num_walls);
1066 // Check validity of Walls array.
1067 for (w=0; w<Num_walls; w++) {
1068 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1069 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1070 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1071 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1072 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1073 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1074 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1078 if (CountedWalls[w].wallnum >= Num_walls)
1079 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1081 if (Walls[w].segnum == -1) {
1082 mprintf((0, "Wall[%d] is BOGUS\n", w));
1083 for (seg=0;seg<=Highest_segment_index;seg++)
1084 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1085 if (Segments[seg].sides[side].wall_num == w) {
1086 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1092 for (w1=0; w1<wall_count; w1++) {
1093 for (w2=w1+1; w2<wall_count; w2++)
1094 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1095 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1096 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1097 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1099 if (Walls[w1].trigger != -1) trigger_count++;
1102 if (trigger_count != Num_triggers) {
1103 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1104 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1105 Num_triggers = trigger_count;
1106 editor_status("Num_triggers set to %d\n", Num_triggers);
1110 mprintf((0,"Trigger Count = %d\n", trigger_count));
1112 for (t=0; t<trigger_count; t++) {
1113 if (Triggers[t].flags & TRIGGER_MATCEN)
1115 if (Triggers[t].num_links < 1)
1116 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1118 for (l=0;l<Triggers[t].num_links;l++) {
1119 if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1120 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1124 if (Triggers[t].flags & TRIGGER_EXIT)
1125 if (Triggers[t].num_links != 0)
1126 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1128 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1129 for (l=0;l<Triggers[t].num_links;l++) {
1130 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1131 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1132 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1137 for (l=0;l<ControlCenterTriggers.num_links;l++)
1138 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1139 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1140 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1148 int delete_all_walls()
1150 char Message[DIAGNOSTIC_MESSAGE_MAX];
1153 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1154 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1155 for (seg=0;seg<=Highest_segment_index;seg++)
1156 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1157 Segments[seg].sides[side].wall_num = -1;
1167 int delete_all_triggers()
1169 char Message[DIAGNOSTIC_MESSAGE_MAX];
1172 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1173 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1175 for (w=0; w<Num_walls; w++)
1176 Walls[w].trigger=-1;
1185 int dump_walls_info()
1190 fp = fopen("WALL.OUT", "wt");
1192 fprintf(fp, "Num_walls %d\n", Num_walls);
1194 for (w=0; w<Num_walls; w++) {
1196 fprintf(fp, "WALL #%d\n", w);
1197 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1198 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1200 switch (Walls[w].type) {
1202 fprintf(fp, " type: NORMAL\n");
1204 case WALL_BLASTABLE:
1205 fprintf(fp, " type: BLASTABLE\n");
1208 fprintf(fp, " type: DOOR\n");
1211 fprintf(fp, " type: ILLUSION\n");
1214 fprintf(fp, " type: OPEN\n");
1217 fprintf(fp, " type: CLOSED\n");
1220 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1224 fprintf(fp, " flags:\n");
1226 if (Walls[w].flags & WALL_BLASTED)
1227 fprintf(fp, " BLASTED\n");
1228 if (Walls[w].flags & WALL_DOOR_OPENED)
1229 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1230 if (Walls[w].flags & WALL_DOOR_OPENING)
1231 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1232 if (Walls[w].flags & WALL_DOOR_LOCKED)
1233 fprintf(fp, " DOOR_LOCKED\n");
1234 if (Walls[w].flags & WALL_DOOR_AUTO)
1235 fprintf(fp, " DOOR_AUTO\n");
1236 if (Walls[w].flags & WALL_ILLUSION_OFF)
1237 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1238 //if (Walls[w].flags & WALL_FUELCEN)
1239 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1241 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1242 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1244 switch (Walls[w].keys) {
1246 fprintf(fp, " key: NONE\n");
1249 fprintf(fp, " key: BLUE\n");
1252 fprintf(fp, " key: RED\n");
1255 fprintf(fp, " key: NONE\n");
1258 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1262 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1269 // ------------------------------------------------------------------------------------------------
1270 void copy_old_wall_data_to_new(int owall, int nwall)
1272 Walls[nwall].flags = Walls[owall].flags;
1273 Walls[nwall].type = Walls[owall].type;
1274 Walls[nwall].clip_num = Walls[owall].clip_num;
1275 Walls[nwall].keys = Walls[owall].keys;
1276 Walls[nwall].hps = Walls[owall].hps;
1277 Walls[nwall].state = Walls[owall].state;
1278 Walls[nwall].linked_wall = -1;
1280 Walls[nwall].trigger = -1;
1282 if (Walls[owall].trigger != -1) {
1283 editor_status("Warning: Trigger not copied in group copy.");
1287 //typedef struct trigger {
1294 // short seg[MAX_WALLS_PER_LINK];
1295 // short side[MAX_WALLS_PER_LINK];
1299 // ------------------------------------------------------------------------------------------------
1300 void copy_group_walls(int old_group, int new_group)
1302 int i,j,old_seg, new_seg;
1304 for (i=0; i<GroupList[old_group].num_segments; i++) {
1305 old_seg = GroupList[old_group].segments[i];
1306 new_seg = GroupList[new_group].segments[i];
1308 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1309 if (Segments[old_seg].sides[j].wall_num != -1) {
1310 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1311 Segments[new_seg].sides[j].wall_num = Num_walls;
1312 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1313 Walls[Num_walls].segnum = new_seg;
1314 Walls[Num_walls].sidenum = j;
1316 Assert(Num_walls < MAX_WALLS);
1322 int Validate_walls=1;
1324 // --------------------------------------------------------------------------------------------------------
1325 // This function should be in medwall.c.
1326 // Make sure all wall/segment connections are valid.
1327 void check_wall_validity(void)
1330 int segnum, sidenum, wall_num;
1331 sbyte wall_flags[MAX_WALLS];
1333 if (!Validate_walls)
1336 for (i=0; i<Num_walls; i++) {
1337 segnum = Walls[i].segnum;
1338 sidenum = Walls[i].sidenum;
1340 if (Segments[segnum].sides[sidenum].wall_num != i) {
1341 if (!Validate_walls)
1343 Int3(); // Error! Your mine has been invalidated!
1344 // Do not continue! Do not save!
1345 // Remember your last action and Contact Mike!
1346 // To continue, set the variable Validate_walls to 1 by doing:
1347 // /Validate_walls = 1
1348 // Then do the usual /eip++;g
1353 for (i=0; i<MAX_WALLS; i++)
1356 for (i=0; i<=Highest_segment_index; i++) {
1357 if (Segments[i].segnum != -1)
1358 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1360 wall_num = Segments[i].sides[j].wall_num;
1361 if (wall_num != -1) {
1362 if (wall_flags[wall_num] != 0) {
1363 if (!Validate_walls)
1365 Int3(); // Error! Your mine has been invalidated!
1366 // Do not continue! Do not save!
1367 // Remember your last action and Contact Mike!
1368 // To continue, set the variable Validate_walls to 1 by doing:
1369 // /Validate_walls = 1
1370 // Then do the usual /eip++;g
1373 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1374 if (!Validate_walls)
1376 Int3(); // Error! Your mine has been invalidated!
1377 // Do not continue! Do not save!
1378 // Remember your last action and Contact Mike!
1379 // To continue, set the variable Validate_walls to 1 by doing:
1380 // /Validate_walls = 1
1381 // Then do the usual /eip++;g
1384 wall_flags[wall_num] = 1;