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
37 int wall_add_door_flag(sbyte flag);
38 int wall_add_to_side(segment *segp, int side, sbyte type);
39 int wall_remove_door_flag(sbyte flag);
40 //-------------------------------------------------------------------------
41 // Variables for this module...
42 //-------------------------------------------------------------------------
43 static UI_WINDOW *MainWindow = NULL;
44 static UI_GADGET_USERBOX *WallViewBox;
45 static UI_GADGET_BUTTON *QuitButton;
46 static UI_GADGET_CHECKBOX *DoorFlag[4];
47 static UI_GADGET_RADIO *KeyFlag[4];
49 static int old_wall_num;
51 static int framenum=0;
52 static int Current_door_type=1;
54 typedef struct count_wall {
59 //---------------------------------------------------------------------
60 extern void create_removable_wall(segment *sp, int sidenum, int tmap_num);
62 // Add a wall (removable 2 sided)
63 int add_wall(segment *seg, short side)
68 if (Num_walls < MAX_WALLS-2)
69 if (IS_CHILD(seg->children[side])) {
70 if (seg->sides[side].wall_num == -1) {
71 seg->sides[side].wall_num = Num_walls;
75 csegp = &Segments[seg->children[side]];
76 Connectside = find_connect_side(seg, csegp);
78 if (csegp->sides[Connectside].wall_num == -1) {
79 csegp->sides[Connectside].wall_num = Num_walls;
83 create_removable_wall( seg, side, CurrentTexture );
84 create_removable_wall( csegp, Connectside, CurrentTexture );
92 int wall_assign_door(int door_type)
97 if (Cursegp->sides[Curside].wall_num == -1) {
98 editor_status("Cannot assign door. No wall at Curside.");
102 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) {
103 editor_status("Cannot assign door. No door at Curside.");
107 Current_door_type = door_type;
109 csegp = &Segments[Cursegp->children[Curside]];
110 Connectside = find_connect_side(Cursegp, csegp);
112 Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
113 Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
115 if (WallAnims[door_type].flags & WCF_TMAP1) {
116 Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0];
117 csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0];
118 Cursegp->sides[Curside].tmap_num2 = 0;
119 csegp->sides[Connectside].tmap_num2 = 0;
122 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
123 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
126 Update_flags |= UF_WORLD_CHANGED;
130 int wall_add_blastable()
132 return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
137 return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
140 int wall_add_closed_wall()
142 return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
145 int wall_add_external_wall()
147 if (Cursegp->children[Curside] == -2) {
148 editor_status( "Wall is already external!" );
152 if (IS_CHILD(Cursegp->children[Curside])) {
153 editor_status( "Cannot add external wall here - seg has children" );
157 Cursegp->children[Curside] = -2;
162 int wall_add_illusion()
164 return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
169 return wall_add_door_flag(WALL_DOOR_LOCKED);
172 int wall_unlock_door()
174 return wall_remove_door_flag(WALL_DOOR_LOCKED);
177 int wall_automate_door()
179 return wall_add_door_flag(WALL_DOOR_AUTO);
182 int wall_deautomate_door()
184 return wall_remove_door_flag(WALL_DOOR_AUTO);
190 if (Cursegp->sides[Curside].wall_num < 0)
191 current_wall = Num_walls;
193 current_wall = Cursegp->sides[Curside].wall_num;
196 if (current_wall < 0) current_wall = Num_walls-1;
197 if (current_wall >= Num_walls) current_wall = Num_walls-1;
199 if (Walls[current_wall].segnum == -1) {
200 mprintf((0, "Trying to goto wall at bogus segnum\n"));
204 if (Walls[current_wall].sidenum == -1) {
205 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
209 Cursegp = &Segments[Walls[current_wall].segnum];
210 Curside = Walls[current_wall].sidenum;
219 current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
223 if (current_wall >= Num_walls) current_wall = 0;
224 if (current_wall < 0) current_wall = 0;
226 if (Walls[current_wall].segnum == -1) {
227 mprintf((0, "Trying to goto wall at bogus segnum\n"));
231 if (Walls[current_wall].sidenum == -1) {
232 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
236 Cursegp = &Segments[Walls[current_wall].segnum];
237 Curside = Walls[current_wall].sidenum;
246 if (Cursegp->sides[Curside].wall_num == -1) {
247 editor_status("Cannot assign new wall. No wall on curside.");
251 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
253 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
260 wall_type = Num_wall_anims-1;
262 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
263 Error("Cannot find clip for door.");
265 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
269 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
276 wall_type = Num_wall_anims-1;
278 if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
279 Error("Cannot find clip for blastable wall.");
281 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
285 wall_assign_door(wall_type);
287 Update_flags |= UF_WORLD_CHANGED;
294 if (Cursegp->sides[Curside].wall_num == -1) {
295 editor_status("Cannot assign new wall. No wall on curside.");
299 wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
301 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
307 if (wall_type >= Num_wall_anims) {
309 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
310 Error("Cannot find clip for door.");
313 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
316 else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
322 if (wall_type >= Num_wall_anims) {
324 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
325 Error("Cannot find clip for blastable wall.");
328 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
332 wall_assign_door(wall_type);
334 Update_flags |= UF_WORLD_CHANGED;
339 //-------------------------------------------------------------------------
340 // Called from the editor... does one instance of the wall dialog box
341 //-------------------------------------------------------------------------
346 // Only open 1 instance of this window...
347 if ( MainWindow != NULL ) return 0;
349 // Close other windows.
352 // Open a window with a quit button
353 MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
354 QuitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL );
356 // These are the checkboxes for each door flag.
358 DoorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24;
359 DoorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24;
360 DoorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24;
362 KeyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24;
363 KeyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24;
364 KeyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" ); i += 24;
365 KeyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24;
367 // The little box the wall will appear in.
368 WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
370 // A bunch of buttons...
372 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall );
373 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25;
374 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25;
375 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door ); i += 25;
376 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion); i += 25;
377 ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25;
378 // ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all ); i += 25;
379 ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall );
380 ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25;
381 ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25;
382 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25;
383 ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25;
385 old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame.
390 void close_wall_window()
392 if ( MainWindow!=NULL ) {
393 ui_close_window( MainWindow );
398 void do_wall_window()
404 if ( MainWindow == NULL ) return;
406 //------------------------------------------------------------
407 // Call the ui code..
408 //------------------------------------------------------------
409 ui_button_any_drawn = 0;
410 ui_window_do_gadgets(MainWindow);
412 //------------------------------------------------------------
413 // If we change walls, we need to reset the ui code for all
414 // of the checkboxes that control the wall flags.
415 //------------------------------------------------------------
416 if (old_wall_num != Cursegp->sides[Curside].wall_num)
418 if ( Cursegp->sides[Curside].wall_num != -1)
420 wall *w = &Walls[Cursegp->sides[Curside].wall_num];
422 ui_checkbox_check(DoorFlag[0], w->flags & WALL_DOOR_LOCKED);
423 ui_checkbox_check(DoorFlag[1], w->flags & WALL_DOOR_AUTO);
424 ui_checkbox_check(DoorFlag[2], w->flags & WALL_ILLUSION_OFF);
426 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
427 ui_radio_set_value(KeyFlag[0], 1);
428 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
429 ui_radio_set_value(KeyFlag[1], 1);
430 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
431 ui_radio_set_value(KeyFlag[2], 1);
432 if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
433 ui_radio_set_value(KeyFlag[3], 1);
437 //------------------------------------------------------------
438 // If any of the checkboxes that control the wallflags are set, then
439 // update the corresponding wall flag.
440 //------------------------------------------------------------
442 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
443 if ( DoorFlag[0]->flag == 1 )
444 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
446 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
447 if ( DoorFlag[1]->flag == 1 )
448 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
450 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
452 //------------------------------------------------------------
453 // If any of the radio buttons that control the mode are set, then
454 // update the corresponding key.
455 //------------------------------------------------------------
456 for ( i=0; i < 4; i++ ) {
457 if ( KeyFlag[i]->flag == 1 ) {
458 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i; // Set the ai_state to the cooresponding radio button
459 // mprintf((0, "1<<%d = %d\n", i, 1<<i));
463 for (i = 0; i < 2; i++)
464 ui_checkbox_check(DoorFlag[i], 0);
465 for ( i=0; i < 4; i++ ) {
466 if ( KeyFlag[i]->flag == 1 ) {
467 KeyFlag[i]->flag = 0;
468 KeyFlag[i]->status = 1;
473 if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
474 if ( DoorFlag[2]->flag == 1 )
475 Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
477 Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
479 for ( i=2; i < 3; i++ )
480 if (DoorFlag[i]->flag == 1) {
481 DoorFlag[i]->flag = 0; // Tells ui that this button isn't checked
482 DoorFlag[i]->status = 1; // Tells ui to redraw button
485 //------------------------------------------------------------
486 // A simple frame time counter for animating the walls...
487 //------------------------------------------------------------
488 Temp = timer_get_fixed_seconds();
489 DeltaTime = Temp - Time;
491 //------------------------------------------------------------
492 // Draw the wall in the little 64x64 box
493 //------------------------------------------------------------
494 gr_set_current_canvas( WallViewBox->canvas );
495 if (Cursegp->sides[Curside].wall_num != -1) {
496 type = Walls[Cursegp->sides[Curside].wall_num].type;
497 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
498 if (DeltaTime > ((F1_0*200)/1000)) {
502 if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
504 PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
505 gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
507 if (type == WALL_OPEN)
508 gr_clear_canvas( CBLACK );
510 if (Cursegp->sides[Curside].tmap_num2 > 0)
511 gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
513 PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
514 gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
519 gr_clear_canvas( CGREY );
521 //------------------------------------------------------------
522 // If anything changes in the ui system, redraw all the text that
523 // identifies this wall.
524 //------------------------------------------------------------
525 if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
526 if ( Cursegp->sides[Curside].wall_num > -1 ) {
527 ui_wprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num);
528 switch (Walls[Cursegp->sides[Curside].wall_num].type) {
530 ui_wprintf_at( MainWindow, 12, 23, " Type: Normal " );
533 ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
536 ui_wprintf_at( MainWindow, 12, 23, " Type: Door " );
537 ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
540 ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
543 ui_wprintf_at( MainWindow, 12, 23, " Type: Open " );
546 ui_wprintf_at( MainWindow, 12, 23, " Type: Closed " );
549 ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown " );
552 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
553 ui_wprintf_at( MainWindow, 223, 6, " " );
555 ui_wprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
556 ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger );
558 ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
559 ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
560 ui_wprintf_at( MainWindow, 12, 40, " Clip: none ");
561 ui_wprintf_at( MainWindow, 12, 57, " Trigger: none ");
563 Update_flags |= UF_WORLD_CHANGED;
565 if ( QuitButton->pressed || (last_keypress==KEY_ESC) ) {
570 old_wall_num = Cursegp->sides[Curside].wall_num;
574 //---------------------------------------------------------------------
575 extern void wall_close_door_num(int door_num);
577 // Restore all walls to original status (closed doors, repaired walls)
578 int wall_restore_all()
583 for (i=0;i<Num_walls;i++) {
584 if (Walls[i].flags & WALL_BLASTED) {
585 Walls[i].hps = WALL_HPS;
586 Walls[i].flags &= ~WALL_BLASTED;
588 if (Walls[i].flags & WALL_DOOR_OPENED)
589 Walls[i].flags &= ~WALL_DOOR_OPENED;
590 if (Walls[i].flags & WALL_DOOR_OPENING)
591 Walls[i].flags &= ~WALL_DOOR_OPENING;
594 for (i=0;i<Num_open_doors;i++)
595 wall_close_door_num(i);
597 for (i=0;i<Num_segments;i++)
598 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
599 wall_num = Segments[i].sides[j].wall_num;
601 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
602 (Walls[wall_num].type == WALL_DOOR))
603 Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
606 for (i=0;i<Num_triggers;i++)
607 Triggers[i].flags |= TRIGGER_ON;
609 Update_flags |= UF_GAME_VIEW_CHANGED;
615 //---------------------------------------------------------------------
616 // Delete a specific wall.
617 int wall_delete_bogus(short wall_num)
622 if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
623 mprintf((0,"WALL IS NOT BOGUS.\n"));
627 // Delete bogus wall and slide all above walls down one slot
628 for (w=wall_num; w<Num_walls; w++) {
629 Walls[w] = Walls[w+1];
634 for (seg=0;seg<=Highest_segment_index;seg++)
635 if (Segments[seg].segnum != -1)
636 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
637 if (Segments[seg].sides[side].wall_num > wall_num)
638 Segments[seg].sides[side].wall_num--;
640 mprintf((0,"BOGUS WALL DELETED!!!!\n"));
646 //---------------------------------------------------------------------
647 // Remove a specific side.
648 int wall_remove_side(segment *seg, short side)
655 if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
656 csegp = &Segments[seg->children[side]];
657 Connectside = find_connect_side(seg, csegp);
659 remove_trigger(seg, side);
660 remove_trigger(csegp, Connectside);
662 // Remove walls 'wall_num' and connecting side 'wall_num'
664 lower_wallnum = seg->sides[side].wall_num;
665 if (csegp->sides[Connectside].wall_num < lower_wallnum)
666 lower_wallnum = csegp->sides[Connectside].wall_num;
668 if (Walls[lower_wallnum].linked_wall != -1)
669 Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
670 if (Walls[lower_wallnum+1].linked_wall != -1)
671 Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
673 for (w=lower_wallnum;w<Num_walls-2;w++)
674 Walls[w] = Walls[w+2];
678 for (s=0;s<=Highest_segment_index;s++)
679 if (Segments[s].segnum != -1)
680 for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
681 if (Segments[s].sides[w].wall_num > lower_wallnum+1)
682 Segments[s].sides[w].wall_num -= 2;
684 // Destroy any links to the deleted wall.
685 for (t=0;t<Num_triggers;t++)
686 for (l=0;l<Triggers[t].num_links;l++)
687 if ((Triggers[t].seg[l] == SEGMENT_NUMBER(seg)) && (Triggers[t].side[l] == side)) {
688 for (t1=0;t1<Triggers[t].num_links-1;t1++) {
689 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
690 Triggers[t].side[t1] = Triggers[t].side[t1+1];
692 Triggers[t].num_links--;
695 // Destroy control center links as well.
696 for (l=0;l<ControlCenterTriggers.num_links;l++)
697 if ((ControlCenterTriggers.seg[l] == SEGMENT_NUMBER(seg)) && (ControlCenterTriggers.side[l] == side)) {
698 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
699 ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
700 ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
702 ControlCenterTriggers.num_links--;
705 seg->sides[side].wall_num = -1;
706 csegp->sides[Connectside].wall_num = -1;
708 Update_flags |= UF_WORLD_CHANGED;
712 editor_status( "Can't remove wall. No wall present.");
716 //---------------------------------------------------------------------
717 // Remove a special wall.
720 return wall_remove_side(Cursegp, Curside);
723 //---------------------------------------------------------------------
724 // Add a wall to curside
725 int wall_add_to_side(segment *segp, int side, sbyte type)
730 if (add_wall(segp, side)) {
731 csegp = &Segments[segp->children[side]];
732 connectside = find_connect_side(segp, csegp);
734 Walls[segp->sides[side].wall_num].segnum = SEGMENT_NUMBER(segp);
735 Walls[csegp->sides[connectside].wall_num].segnum = SEGMENT_NUMBER(csegp);
737 Walls[segp->sides[side].wall_num].sidenum = side;
738 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
740 Walls[segp->sides[side].wall_num].flags = 0;
741 Walls[csegp->sides[connectside].wall_num].flags = 0;
743 Walls[segp->sides[side].wall_num].type = type;
744 Walls[csegp->sides[connectside].wall_num].type = type;
746 // Walls[segp->sides[side].wall_num].trigger = -1;
747 // Walls[csegp->sides[connectside].wall_num].trigger = -1;
749 Walls[segp->sides[side].wall_num].clip_num = -1;
750 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
752 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
753 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
755 if (type == WALL_BLASTABLE) {
756 Walls[segp->sides[side].wall_num].hps = WALL_HPS;
757 Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
759 //Walls[segp->sides[side].wall_num].clip_num = 0;
760 //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
763 if (type != WALL_DOOR) {
764 segp->sides[side].tmap_num2 = 0;
765 csegp->sides[connectside].tmap_num2 = 0;
768 if (type == WALL_DOOR) {
769 Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
770 Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
772 Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
773 Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
776 //Update_flags |= UF_WORLD_CHANGED;
779 // return NextWall(); //assign a clip num
780 return wall_assign_door(Current_door_type);
783 editor_status( "Cannot add wall here, no children" );
789 //---------------------------------------------------------------------
790 // Add a wall to markedside
791 int wall_add_to_markedside(sbyte type)
796 if (add_wall(Markedsegp, Markedside)) {
797 int wall_num, cwall_num;
798 csegp = &Segments[Markedsegp->children[Markedside]];
800 Connectside = find_connect_side(Markedsegp, csegp);
802 wall_num = Markedsegp->sides[Markedside].wall_num;
803 cwall_num = csegp->sides[Connectside].wall_num;
805 Walls[wall_num].segnum = SEGMENT_NUMBER(Markedsegp);
806 Walls[cwall_num].segnum = SEGMENT_NUMBER(csegp);
808 Walls[wall_num].sidenum = Markedside;
809 Walls[cwall_num].sidenum = Connectside;
811 Walls[wall_num].flags = 0;
812 Walls[cwall_num].flags = 0;
814 Walls[wall_num].type = type;
815 Walls[cwall_num].type = type;
817 Walls[wall_num].trigger = -1;
818 Walls[cwall_num].trigger = -1;
820 Walls[wall_num].clip_num = -1;
821 Walls[cwall_num].clip_num = -1;
823 Walls[wall_num].keys = KEY_NONE;
824 Walls[cwall_num].keys = KEY_NONE;
826 if (type == WALL_BLASTABLE) {
827 Walls[wall_num].hps = WALL_HPS;
828 Walls[cwall_num].hps = WALL_HPS;
830 Walls[wall_num].clip_num = 0;
831 Walls[cwall_num].clip_num = 0;
834 if (type != WALL_DOOR) {
835 Markedsegp->sides[Markedside].tmap_num2 = 0;
836 csegp->sides[Connectside].tmap_num2 = 0;
839 Update_flags |= UF_WORLD_CHANGED;
842 editor_status( "Cannot add wall here, no children" );
848 int wall_add_door_flag(sbyte flag)
853 if (Cursegp->sides[Curside].wall_num == -1)
855 editor_status("Cannot change flag. No wall at Curside.");
859 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
861 editor_status("Cannot change flag. No door at Curside.");
865 csegp = &Segments[Cursegp->children[Curside]];
866 Connectside = find_connect_side(Cursegp, csegp);
868 Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
869 Walls[csegp->sides[Connectside].wall_num].flags |= flag;
871 Update_flags |= UF_ED_STATE_CHANGED;
875 int wall_remove_door_flag(sbyte flag)
880 if (Cursegp->sides[Curside].wall_num == -1)
882 editor_status("Cannot change flag. No wall at Curside.");
886 if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
888 editor_status("Cannot change flag. No door at Curside.");
892 csegp = &Segments[Cursegp->children[Curside]];
893 Connectside = find_connect_side(Cursegp, csegp);
895 Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
896 Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
898 Update_flags |= UF_ED_STATE_CHANGED;
903 int bind_wall_to_control_center() {
908 if (Cursegp->sides[Curside].wall_num == -1) {
909 editor_status("No wall at Curside.");
913 link_num = ControlCenterTriggers.num_links;
914 for (i=0;i<link_num;i++)
915 if ((SEGMENT_NUMBER(Cursegp) == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
916 editor_status("Curside already bound to Control Center.");
920 // Error checking completed, actual binding begins
921 ControlCenterTriggers.seg[link_num] = SEGMENT_NUMBER(Cursegp);
922 ControlCenterTriggers.side[link_num] = Curside;
923 ControlCenterTriggers.num_links++;
925 mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
926 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num));
928 editor_status("Wall linked to control center");
933 //link two doors, curseg/curside and markedseg/markedside
934 int wall_link_doors()
936 wall *w1=NULL,*w2=NULL;
938 if (Cursegp->sides[Curside].wall_num != -1)
939 w1 = &Walls[Cursegp->sides[Curside].wall_num];
941 if (Markedsegp->sides[Markedside].wall_num != -1)
942 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
944 if (!w1 || w1->type != WALL_DOOR) {
945 editor_status("Curseg/curside is not a door");
949 if (!w2 || w2->type != WALL_DOOR) {
950 editor_status("Markedseg/markedside is not a door");
954 if (w1->linked_wall != -1)
955 editor_status("Curseg/curside is already linked");
957 if (w2->linked_wall != -1)
958 editor_status("Markedseg/markedside is already linked");
960 w1->linked_wall = w2-Walls;
961 w2->linked_wall = w1-Walls;
966 int wall_unlink_door()
970 if (Cursegp->sides[Curside].wall_num != -1)
971 w1 = &Walls[Cursegp->sides[Curside].wall_num];
973 if (!w1 || w1->type != WALL_DOOR) {
974 editor_status("Curseg/curside is not a door");
978 if (w1->linked_wall == -1)
979 editor_status("Curseg/curside is not linked");
981 Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
983 Walls[w1->linked_wall].linked_wall = -1;
984 w1->linked_wall = -1;
990 #define DIAGNOSTIC_MESSAGE_MAX 150
994 int w, seg, side, wall_count, trigger_count;
996 count_wall CountedWalls[MAX_WALLS];
997 char Message[DIAGNOSTIC_MESSAGE_MAX];
1001 for (seg=0;seg<=Highest_segment_index;seg++)
1002 if (Segments[seg].segnum != -1) {
1003 // Check fuelcenters
1004 matcen_num = Segment2s[seg].matcen_num;
1005 if (matcen_num == 0)
1006 if (RobotCenters[0].segnum != seg) {
1007 mprintf((0,"Fixing Matcen 0\n"));
1008 Segment2s[seg].matcen_num = -1;
1011 if (matcen_num > -1)
1012 if (RobotCenters[matcen_num].segnum != seg) {
1013 mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1014 mprintf((0,"Fixing....\n"));
1015 RobotCenters[matcen_num].segnum = seg;
1018 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1019 if (Segments[seg].sides[side].wall_num != -1) {
1020 CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1021 CountedWalls[wall_count].segnum = seg;
1022 CountedWalls[wall_count].sidenum = side;
1024 // Check if segnum is bogus
1025 if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1026 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1029 if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1030 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1037 mprintf((0,"Wall Count = %d\n", wall_count));
1039 if (wall_count != Num_walls) {
1040 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1041 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1042 Num_walls = wall_count;
1043 editor_status("Num_walls set to %d\n", Num_walls);
1047 // Check validity of Walls array.
1048 for (w=0; w<Num_walls; w++) {
1049 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1050 (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1051 mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1052 sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1053 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1054 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1055 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1059 if (CountedWalls[w].wallnum >= Num_walls)
1060 mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1062 if (Walls[w].segnum == -1) {
1063 mprintf((0, "Wall[%d] is BOGUS\n", w));
1064 for (seg=0;seg<=Highest_segment_index;seg++)
1065 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1066 if (Segments[seg].sides[side].wall_num == w) {
1067 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1073 for (w1=0; w1<wall_count; w1++) {
1074 for (w2=w1+1; w2<wall_count; w2++)
1075 if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1076 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1077 mprintf((0, "Seg1:sides1 %d:%d ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1078 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1080 if (Walls[w1].trigger != -1) trigger_count++;
1083 if (trigger_count != Num_triggers) {
1084 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1085 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1086 Num_triggers = trigger_count;
1087 editor_status("Num_triggers set to %d\n", Num_triggers);
1091 mprintf((0,"Trigger Count = %d\n", trigger_count));
1093 for (t=0; t<trigger_count; t++) {
1094 if (Triggers[t].flags & TRIGGER_MATCEN)
1096 if (Triggers[t].num_links < 1)
1097 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1099 for (l=0;l<Triggers[t].num_links;l++) {
1100 if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1101 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1105 if (Triggers[t].flags & TRIGGER_EXIT)
1106 if (Triggers[t].num_links != 0)
1107 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1109 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1110 for (l=0;l<Triggers[t].num_links;l++) {
1111 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1112 mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1113 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1118 for (l=0;l<ControlCenterTriggers.num_links;l++)
1119 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1120 mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1121 mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1129 int delete_all_walls()
1131 char Message[DIAGNOSTIC_MESSAGE_MAX];
1134 sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1135 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1136 for (seg=0;seg<=Highest_segment_index;seg++)
1137 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1138 Segments[seg].sides[side].wall_num = -1;
1148 int delete_all_triggers()
1150 char Message[DIAGNOSTIC_MESSAGE_MAX];
1153 sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1154 if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1156 for (w=0; w<Num_walls; w++)
1157 Walls[w].trigger=-1;
1166 int dump_walls_info()
1171 fp = fopen("WALL.OUT", "wt");
1173 fprintf(fp, "Num_walls %d\n", Num_walls);
1175 for (w=0; w<Num_walls; w++) {
1177 fprintf(fp, "WALL #%d\n", w);
1178 fprintf(fp, " seg: %d\n", Walls[w].segnum);
1179 fprintf(fp, " sidenum: %d\n", Walls[w].sidenum);
1181 switch (Walls[w].type) {
1183 fprintf(fp, " type: NORMAL\n");
1185 case WALL_BLASTABLE:
1186 fprintf(fp, " type: BLASTABLE\n");
1189 fprintf(fp, " type: DOOR\n");
1192 fprintf(fp, " type: ILLUSION\n");
1195 fprintf(fp, " type: OPEN\n");
1198 fprintf(fp, " type: CLOSED\n");
1201 fprintf(fp, " type: ILLEGAL!!!!! <-----------------\n");
1205 fprintf(fp, " flags:\n");
1207 if (Walls[w].flags & WALL_BLASTED)
1208 fprintf(fp, " BLASTED\n");
1209 if (Walls[w].flags & WALL_DOOR_OPENED)
1210 fprintf(fp, " DOOR_OPENED <----------------- BAD!!!\n");
1211 if (Walls[w].flags & WALL_DOOR_OPENING)
1212 fprintf(fp, " DOOR_OPENING <---------------- BAD!!!\n");
1213 if (Walls[w].flags & WALL_DOOR_LOCKED)
1214 fprintf(fp, " DOOR_LOCKED\n");
1215 if (Walls[w].flags & WALL_DOOR_AUTO)
1216 fprintf(fp, " DOOR_AUTO\n");
1217 if (Walls[w].flags & WALL_ILLUSION_OFF)
1218 fprintf(fp, " ILLUSION_OFF <---------------- OUTDATED\n");
1219 //if (Walls[w].flags & WALL_FUELCEN)
1220 // fprintf(fp, " FUELCEN <--------------------- OUTDATED\n");
1222 fprintf(fp, " trigger: %d\n", Walls[w].trigger);
1223 fprintf(fp, " clip_num: %d\n", Walls[w].clip_num);
1225 switch (Walls[w].keys) {
1227 fprintf(fp, " key: NONE\n");
1230 fprintf(fp, " key: BLUE\n");
1233 fprintf(fp, " key: RED\n");
1236 fprintf(fp, " key: NONE\n");
1239 fprintf(fp, " key: ILLEGAL!!!!!! <-----------------\n");
1243 fprintf(fp, " linked_wall %d\n", Walls[w].linked_wall);
1250 // ------------------------------------------------------------------------------------------------
1251 void copy_old_wall_data_to_new(int owall, int nwall)
1253 Walls[nwall].flags = Walls[owall].flags;
1254 Walls[nwall].type = Walls[owall].type;
1255 Walls[nwall].clip_num = Walls[owall].clip_num;
1256 Walls[nwall].keys = Walls[owall].keys;
1257 Walls[nwall].hps = Walls[owall].hps;
1258 Walls[nwall].state = Walls[owall].state;
1259 Walls[nwall].linked_wall = -1;
1261 Walls[nwall].trigger = -1;
1263 if (Walls[owall].trigger != -1) {
1264 editor_status("Warning: Trigger not copied in group copy.");
1268 //typedef struct trigger {
1275 // short seg[MAX_WALLS_PER_LINK];
1276 // short side[MAX_WALLS_PER_LINK];
1280 // ------------------------------------------------------------------------------------------------
1281 void copy_group_walls(int old_group, int new_group)
1283 int i,j,old_seg, new_seg;
1285 for (i=0; i<GroupList[old_group].num_segments; i++) {
1286 old_seg = GroupList[old_group].segments[i];
1287 new_seg = GroupList[new_group].segments[i];
1289 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1290 if (Segments[old_seg].sides[j].wall_num != -1) {
1291 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1292 Segments[new_seg].sides[j].wall_num = Num_walls;
1293 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1294 Walls[Num_walls].segnum = new_seg;
1295 Walls[Num_walls].sidenum = j;
1297 Assert(Num_walls < MAX_WALLS);
1303 int Validate_walls=1;
1305 // --------------------------------------------------------------------------------------------------------
1306 // This function should be in medwall.c.
1307 // Make sure all wall/segment connections are valid.
1308 void check_wall_validity(void)
1311 int segnum, sidenum, wall_num;
1312 sbyte wall_flags[MAX_WALLS];
1314 if (!Validate_walls)
1317 for (i=0; i<Num_walls; i++) {
1318 segnum = Walls[i].segnum;
1319 sidenum = Walls[i].sidenum;
1321 if (Segments[segnum].sides[sidenum].wall_num != i) {
1322 if (!Validate_walls)
1324 Int3(); // Error! Your mine has been invalidated!
1325 // Do not continue! Do not save!
1326 // Remember your last action and Contact Mike!
1327 // To continue, set the variable Validate_walls to 1 by doing:
1328 // /Validate_walls = 1
1329 // Then do the usual /eip++;g
1334 for (i=0; i<MAX_WALLS; i++)
1337 for (i=0; i<=Highest_segment_index; i++) {
1338 if (Segments[i].segnum != -1)
1339 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1341 wall_num = Segments[i].sides[j].wall_num;
1342 if (wall_num != -1) {
1343 if (wall_flags[wall_num] != 0) {
1344 if (!Validate_walls)
1346 Int3(); // Error! Your mine has been invalidated!
1347 // Do not continue! Do not save!
1348 // Remember your last action and Contact Mike!
1349 // To continue, set the variable Validate_walls to 1 by doing:
1350 // /Validate_walls = 1
1351 // Then do the usual /eip++;g
1354 if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1355 if (!Validate_walls)
1357 Int3(); // Error! Your mine has been invalidated!
1358 // Do not continue! Do not save!
1359 // Remember your last action and Contact Mike!
1360 // To continue, set the variable Validate_walls to 1 by doing:
1361 // /Validate_walls = 1
1362 // Then do the usual /eip++;g
1365 wall_flags[wall_num] = 1;