]> icculus.org git repositories - btb/d2x.git/blob - main/editor/medwall.c
d2f5e3b31a93bad66d46e8a3a5e9454a58083ce6
[btb/d2x.git] / main / editor / medwall.c
1 /*
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.
12 */
13 /*
14  * $Source: /cvs/cvsroot/d2x/main/editor/medwall.c,v $
15  * $Revision: 1.1 $
16  * $Author: btb $
17  * $Date: 2004-12-19 13:54:27 $
18  * 
19  * Created from version 1.11 of main\wall.c
20  * 
21  * $Log: not supported by cvs2svn $
22  * Revision 1.2  2003/03/09 06:34:09  donut
23  * change byte typedef to sbyte to avoid conflict with win32 byte which is unsigned
24  *
25  * Revision 1.1.1.1  1999/06/14 22:04:04  donut
26  * Import of d1x 1.37 source.
27  *
28  * Revision 2.0  1995/02/27  11:35:47  john
29  * Version 2.0! No anonymous unions, Watcom 10.0, with no need
30  * for bitmaps.tbl.
31  * 
32  * Revision 1.71  1995/02/01  16:30:03  yuan
33  * Stabilizing triggers and matcens.
34  * 
35  * Revision 1.70  1995/01/28  15:28:08  yuan
36  * Return proper bug description.
37  * 
38  * Revision 1.69  1995/01/14  19:18:07  john
39  * First version of object paging.
40  * 
41  * Revision 1.68  1995/01/12  12:10:44  yuan
42  * Added delete trigger function
43  * 
44  * Revision 1.67  1994/11/29  16:51:53  yuan
45  * Fixed false bogus trigger info.
46  * 
47  * Revision 1.66  1994/11/27  23:17:29  matt
48  * Made changes for new mprintf calling convention
49  * 
50  * Revision 1.65  1994/11/15  11:59:42  john
51  * Changed timing for door to use fixed seconds instead of milliseconds.
52  * 
53  * Revision 1.64  1994/11/03  10:41:17  yuan
54  * Made walls add whichever the previous type was.
55  * 
56  * Revision 1.63  1994/10/13  13:14:59  yuan
57  * Fixed trigger removal bug.
58  * 
59  * Revision 1.62  1994/10/07  17:43:39  yuan
60  * Make validate walls default to 1.
61  * 
62  * Revision 1.61  1994/10/03  23:40:20  mike
63  * Fix hosedness in walls in group copying.
64  * 
65  * Revision 1.60  1994/09/29  00:20:36  matt
66  * Took out reference to unused external wall type
67  * 
68  * Revision 1.59  1994/09/28  17:32:24  mike
69  * Functions to copy walls withing groups.
70  * 
71  * Revision 1.58  1994/09/28  13:40:46  yuan
72  * Fixed control center trigger bug.
73  * 
74  * Revision 1.57  1994/09/24  12:41:52  matt
75  * Took out references to obsolete constants
76  * 
77  * Revision 1.56  1994/09/23  18:03:55  yuan
78  * Finished wall checking code.
79  * 
80  * Revision 1.55  1994/09/22  14:35:25  matt
81  * Made blastable walls work again
82  * 
83  * Revision 1.54  1994/09/21  16:46:07  yuan
84  * Fixed bug that reset wall slot which was just deleted.
85  * 
86  * Revision 1.53  1994/09/20  18:31:21  yuan
87  * Output right Wallnum
88  * 
89  * Revision 1.52  1994/09/20  18:23:24  yuan
90  * Killed the BOGIFYING WALL DRAGON...
91  * 
92  * There was a problem with triggers being created that had bogus
93  * pointers back to their segments.
94  * 
95  * Revision 1.51  1994/09/20  11:13:11  yuan
96  * Delete all bogus walls when checking walls.
97  * 
98  * Revision 1.50  1994/09/19  23:31:14  yuan
99  * Adding wall checking stuff.
100  * 
101  * Revision 1.49  1994/09/13  21:11:20  matt
102  * Added wclips that use tmap1 instead of tmap2, saving lots of merging
103  * 
104  * Revision 1.48  1994/09/10  13:32:08  matt
105  * Made exploding walls a type of blastable walls.
106  * Cleaned up blastable walls, making them tmap2 bitmaps.
107  * 
108  * Revision 1.47  1994/09/10  09:47:47  yuan
109  * Added wall checking function.
110  * 
111  * Revision 1.46  1994/08/26  14:14:56  yuan
112  * Fixed wall clip being set to -2 bug.
113  * 
114  * Revision 1.45  1994/08/25  21:56:26  mike
115  * IS_CHILD stuff.
116  * 
117  * Revision 1.44  1994/08/19  19:30:27  matt
118  * Added informative message if wall is already external when making it so.
119  * 
120  * Revision 1.43  1994/08/17  11:13:46  matt
121  * Changed way external walls work
122  * 
123  * Revision 1.42  1994/08/15  17:47:29  yuan
124  * Added external walls
125  * 
126  * Revision 1.41  1994/08/05  21:18:09  matt
127  * Allow two doors to be linked together
128  * 
129  * Revision 1.40  1994/08/02  14:18:06  mike
130  * Clean up dialog boxes.
131  * 
132  * Revision 1.39  1994/08/01  11:04:33  yuan
133  * New materialization centers.
134  * 
135  * Revision 1.38  1994/07/22  17:19:11  yuan
136  * Working on dialog box for refuel/repair/material/control centers.
137  * 
138  * Revision 1.37  1994/07/20  17:35:33  yuan
139  * Added new gold key.
140  * 
141  * Revision 1.36  1994/07/19  14:31:44  yuan
142  * Fixed keys bug.
143  * 
144  * Revision 1.35  1994/07/18  15:58:31  yuan
145  * Hopefully prevent any "Adam door bombouts"
146  * 
147  * Revision 1.34  1994/07/18  15:48:40  yuan
148  * Made minor cosmetic change.
149  * 
150  * Revision 1.33  1994/07/15  16:09:22  yuan
151  * Error checking
152  * 
153  * Revision 1.32  1994/07/14  16:47:05  yuan
154  * Fixed wall dialog for selected dooranims.
155  * 
156  * Revision 1.31  1994/07/11  15:09:16  yuan
157  * Wall anim filenames stored in wclip structure.
158  * 
159  * Revision 1.30  1994/07/06  10:56:01  john
160  * New structures for hostages.
161  * 
162  * Revision 1.29  1994/07/01  16:35:54  yuan
163  * Added key system
164  * 
165  * Revision 1.28  1994/06/21  18:50:12  john
166  * Made ESC key exit dialog.
167  * 
168  * Revision 1.27  1994/06/20  22:29:59  yuan
169  * Fixed crazy runaway trigger bug that Adam found
170  * 
171  * Revision 1.26  1994/06/01  15:50:25  yuan
172  * Added one more door... Needs to be set by bm.c in the future.
173  * 
174  * Revision 1.25  1994/05/30  20:22:34  yuan
175  * New triggers.
176  * 
177  * Revision 1.24  1994/05/27  10:34:31  yuan
178  * Added new Dialog boxes for Walls and Triggers.
179  * 
180  * Revision 1.23  1994/05/25  18:08:45  yuan
181  * Revamping walls and triggers interface.
182  * Wall interface complete, but triggers are still in progress.
183  * 
184  * Revision 1.22  1994/05/18  18:21:56  yuan
185  * Fixed delete segment and walls bug.
186  * 
187  * Revision 1.21  1994/05/11  18:24:29  yuan
188  * Oops.. trigger not triggers..
189  * 
190  * Revision 1.20  1994/05/11  18:23:53  yuan
191  * Fixed trigger not set to -1 bug.
192  * 
193  */
194
195
196 #ifdef RCS
197 static char rcsid[] = "$Id: medwall.c,v 1.1 2004-12-19 13:54:27 btb Exp $";
198 #endif
199
200 #include <stdio.h>
201 #include <stdlib.h>
202 #include <math.h>
203 #include <string.h>
204
205 #include "editor/medwall.h"
206 #include "inferno.h"
207 #include "editor/editor.h"
208 #include "segment.h"
209 #include "error.h"
210 #include "gameseg.h"
211
212 #include "textures.h"
213 #include "screens.h"
214 #include "switch.h"
215 #include "editor/eswitch.h"
216
217 #include "texmerge.h"
218 #include "medrobot.h"
219 #include "timer.h"
220 #include "mono.h"
221 //#include "fuelcen.h"
222 #include "key.h"
223 #include "ehostage.h"
224 #include "centers.h"
225 #include "piggy.h"
226
227 int wall_add_door_flag(sbyte flag);
228 int wall_add_to_side(segment *segp, int side, sbyte type);
229 int wall_remove_door_flag(sbyte flag);
230 //-------------------------------------------------------------------------
231 // Variables for this module...
232 //-------------------------------------------------------------------------
233 static UI_WINDOW                                *MainWindow = NULL;
234 static UI_GADGET_USERBOX        *WallViewBox;
235 static UI_GADGET_BUTTON         *QuitButton;
236 static UI_GADGET_CHECKBOX       *DoorFlag[4];
237 static UI_GADGET_RADIO          *KeyFlag[4];
238
239 static int old_wall_num;
240 static fix Time;
241 static int framenum=0;
242 static int Current_door_type=1;
243
244 typedef struct count_wall {
245         short wallnum;
246         short   segnum,sidenum; 
247 } count_wall;
248
249 //---------------------------------------------------------------------
250 // Add a wall (removable 2 sided)
251 int add_wall(segment *seg, short side)
252 {
253         int Connectside;
254         segment *csegp;
255
256         if (Num_walls < MAX_WALLS-2)
257         if (IS_CHILD(seg->children[side])) {
258                 if (seg->sides[side].wall_num == -1) {
259                         seg->sides[side].wall_num = Num_walls;
260                         Num_walls++;
261                         }
262                                  
263                 csegp = &Segments[seg->children[side]];
264                 Connectside = find_connect_side(seg, csegp);
265
266                 if (csegp->sides[Connectside].wall_num == -1) {
267                         csegp->sides[Connectside].wall_num = Num_walls;
268                         Num_walls++;
269                         }
270                 
271                 create_removable_wall( seg, side, CurrentTexture );
272                 create_removable_wall( csegp, Connectside, CurrentTexture );
273
274                 return 1;
275                 }
276
277         return 0;
278 }
279
280 int wall_assign_door(int door_type)
281 {
282         int Connectside;
283         segment *csegp;
284
285         if (Cursegp->sides[Curside].wall_num == -1) {
286                 editor_status("Cannot assign door. No wall at Curside.");
287                 return 0;
288         }
289
290         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR  &&  Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) {
291                 editor_status("Cannot assign door. No door at Curside.");
292                 return 0;
293         }
294
295         Current_door_type = door_type;
296
297         csegp = &Segments[Cursegp->children[Curside]];
298         Connectside = find_connect_side(Cursegp, csegp);
299         
300         Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
301         Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
302
303         if (WallAnims[door_type].flags & WCF_TMAP1) {
304                 Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0];
305                 csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0];
306                 Cursegp->sides[Curside].tmap_num2 = 0;
307                 csegp->sides[Connectside].tmap_num2 = 0;
308         }
309         else {
310                 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
311                 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
312         }
313
314         Update_flags |= UF_WORLD_CHANGED;
315         return 1;
316 }
317
318 int wall_add_blastable()
319 {
320         return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
321 }
322
323 int wall_add_door()
324 {
325         return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
326 }
327
328 int wall_add_closed_wall()
329 {
330         return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
331 }
332
333 int wall_add_external_wall()
334 {
335         if (Cursegp->children[Curside] == -2) {
336                 editor_status( "Wall is already external!" );
337                 return 1;
338         }
339
340         if (IS_CHILD(Cursegp->children[Curside])) {
341                 editor_status( "Cannot add external wall here - seg has children" );
342                 return 0;
343         }
344
345         Cursegp->children[Curside] = -2;
346
347         return 1;
348 }
349
350 int wall_add_illusion()
351 {
352         return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
353 }
354
355 int wall_lock_door()
356 {
357         return wall_add_door_flag(WALL_DOOR_LOCKED);
358 }
359
360 int wall_unlock_door()
361 {
362         return wall_remove_door_flag(WALL_DOOR_LOCKED);
363 }
364
365 int wall_automate_door()
366 {
367         return wall_add_door_flag(WALL_DOOR_AUTO);
368 }
369         
370 int wall_deautomate_door()
371 {
372         return wall_remove_door_flag(WALL_DOOR_AUTO);
373 }
374
375 int GotoPrevWall() {
376         int current_wall;
377
378         if (Cursegp->sides[Curside].wall_num < 0)
379                 current_wall = Num_walls;
380         else
381                 current_wall = Cursegp->sides[Curside].wall_num;
382
383         current_wall--;
384         if (current_wall < 0) current_wall = Num_walls-1;
385         if (current_wall >= Num_walls) current_wall = Num_walls-1;
386
387         if (Walls[current_wall].segnum == -1) {
388                 mprintf((0, "Trying to goto wall at bogus segnum\n"));
389                 return 0;
390         }
391
392         if (Walls[current_wall].sidenum == -1) {
393                 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
394                 return 0;
395         }
396
397         Cursegp = &Segments[Walls[current_wall].segnum];
398         Curside = Walls[current_wall].sidenum;
399
400         return 1;
401 }
402
403
404 int GotoNextWall() {
405         int current_wall;
406
407         current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
408
409         current_wall++;
410
411         if (current_wall >= Num_walls) current_wall = 0;
412         if (current_wall < 0) current_wall = 0;
413
414         if (Walls[current_wall].segnum == -1) {
415                 mprintf((0, "Trying to goto wall at bogus segnum\n"));
416                 return 0;
417         }
418
419         if (Walls[current_wall].sidenum == -1) {
420                 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
421                 return 0;
422         }
423
424         Cursegp = &Segments[Walls[current_wall].segnum];
425         Curside = Walls[current_wall].sidenum;  
426
427         return 1;
428 }
429
430
431 int PrevWall() {
432         int wall_type;
433
434         if (Cursegp->sides[Curside].wall_num == -1) {
435                 editor_status("Cannot assign new wall. No wall on curside.");
436                 return 0;
437         }
438
439         wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
440
441         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
442
443                 do {
444
445                         wall_type--;
446
447                         if (wall_type < 0)
448                                 wall_type = Num_wall_anims-1;
449
450                         if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
451                                 Error("Cannot find clip for door."); 
452
453                 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
454
455         }
456
457         else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
458
459                 do {
460
461                         wall_type--;
462
463                         if (wall_type < 0)
464                                 wall_type = Num_wall_anims-1;
465
466                         if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
467                                 Error("Cannot find clip for blastable wall."); 
468
469                 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
470
471         }
472
473         wall_assign_door(wall_type);
474
475         Update_flags |= UF_WORLD_CHANGED;
476         return 1;
477 }
478
479 int NextWall() {
480         int wall_type;
481
482         if (Cursegp->sides[Curside].wall_num == -1) {
483                 editor_status("Cannot assign new wall. No wall on curside.");
484                 return 0;
485         }
486
487         wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
488
489         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
490
491                 do {
492
493                         wall_type++;
494
495                         if (wall_type >= Num_wall_anims) {
496                                 wall_type = 0;
497                                 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
498                                         Error("Cannot find clip for door."); 
499                         }
500
501                 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
502
503         }
504         else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
505
506                 do {
507
508                         wall_type++;
509
510                         if (wall_type >= Num_wall_anims) {
511                                 wall_type = 0;
512                                 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
513                                         Error("Cannot find clip for blastable wall."); 
514                         }
515
516                 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
517
518         }
519
520         wall_assign_door(wall_type);    
521
522         Update_flags |= UF_WORLD_CHANGED;
523         return 1;
524
525 }
526
527 //-------------------------------------------------------------------------
528 // Called from the editor... does one instance of the wall dialog box
529 //-------------------------------------------------------------------------
530 int do_wall_dialog()
531 {
532         int i;
533
534         // Only open 1 instance of this window...
535         if ( MainWindow != NULL ) return 0;
536
537         // Close other windows. 
538         close_all_windows();
539
540         // Open a window with a quit button
541         MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
542         QuitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL );
543
544         // These are the checkboxes for each door flag.
545         i = 80;
546         DoorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24;
547         DoorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24;
548         DoorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24;
549
550         KeyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24;
551         KeyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24;
552         KeyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" );  i += 24;
553         KeyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24;
554
555         // The little box the wall will appear in.
556         WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
557
558         // A bunch of buttons...
559         i = 80;
560         ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall );
561         ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25;                
562         ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25;
563         ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door  );   i += 25;
564         ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion);     i += 25;
565         ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25;
566 //      ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all );        i += 25;
567         ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall );
568         ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25;
569         ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25;
570         ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25;
571         ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25;
572         
573         old_wall_num = -2;              // Set to some dummy value so everything works ok on the first frame.
574
575         return 1;
576 }
577
578 void close_wall_window()
579 {
580         if ( MainWindow!=NULL ) {
581                 ui_close_window( MainWindow );
582                 MainWindow = NULL;
583         }
584 }
585
586 void do_wall_window()
587 {
588         int i;
589         sbyte type;
590         fix DeltaTime, Temp;
591
592         if ( MainWindow == NULL ) return;
593
594         //------------------------------------------------------------
595         // Call the ui code..
596         //------------------------------------------------------------
597         ui_button_any_drawn = 0;
598         ui_window_do_gadgets(MainWindow);
599
600         //------------------------------------------------------------
601         // If we change walls, we need to reset the ui code for all
602         // of the checkboxes that control the wall flags.  
603         //------------------------------------------------------------
604         if (old_wall_num != Cursegp->sides[Curside].wall_num) {
605                 for (   i=0; i < 3; i++ )       {
606                         DoorFlag[i]->flag = 0;          // Tells ui that this button isn't checked
607                         DoorFlag[i]->status = 1;        // Tells ui to redraw button
608                 }
609                 for (   i=0; i < 4; i++ )       {
610                         KeyFlag[i]->flag = 0;           // Tells ui that this button isn't checked
611                         KeyFlag[i]->status = 1;         // Tells ui to redraw button
612                 }
613
614                 if ( Cursegp->sides[Curside].wall_num != -1) {
615                         if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_LOCKED)                   
616                                 DoorFlag[0]->flag = 1;  // Mark this button as checked
617                         if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_DOOR_AUTO)
618                                 DoorFlag[1]->flag = 1;  // Mark this button as checked
619                         if (Walls[Cursegp->sides[Curside].wall_num].flags & WALL_ILLUSION_OFF)
620                                 DoorFlag[2]->flag = 1;  // Mark this button as checked
621
622                         if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_NONE)
623                                 KeyFlag[0]->flag = 1;
624                         if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_BLUE)
625                                 KeyFlag[1]->flag = 1;
626                         if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_RED)
627                                 KeyFlag[2]->flag = 1;
628                         if (Walls[Cursegp->sides[Curside].wall_num].keys & KEY_GOLD)
629                                 KeyFlag[3]->flag = 1;
630                 }
631         }
632         
633         //------------------------------------------------------------
634         // If any of the checkboxes that control the wallflags are set, then
635         // update the corresponding wall flag.
636         //------------------------------------------------------------
637
638         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
639                 if ( DoorFlag[0]->flag == 1 )   
640                         Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED;
641                 else
642                         Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED;
643                 if ( DoorFlag[1]->flag == 1 )   
644                         Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO;
645                 else
646                         Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
647
648                 //------------------------------------------------------------
649                 // If any of the radio buttons that control the mode are set, then
650                 // update the corresponding key.
651                 //------------------------------------------------------------
652                 for (   i=0; i < 4; i++ )       {
653                         if ( KeyFlag[i]->flag == 1 ) {
654                                 Walls[Cursegp->sides[Curside].wall_num].keys = 1<<i;            // Set the ai_state to the cooresponding radio button
655 //                              mprintf((0, "1<<%d = %d\n", i, 1<<i));
656                         }
657                 }
658         } else {
659                 for (   i=0; i < 2; i++ )       
660                         if (DoorFlag[i]->flag == 1) { 
661                                 DoorFlag[i]->flag = 0;          // Tells ui that this button isn't checked
662                                 DoorFlag[i]->status = 1;        // Tells ui to redraw button
663                         }
664                 for (   i=0; i < 4; i++ )       {
665                         if ( KeyFlag[i]->flag == 1 ) {
666                                 KeyFlag[i]->flag = 0;           
667                                 KeyFlag[i]->status = 1;         
668                         }
669                 }
670         }
671
672         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) {
673                 if ( DoorFlag[2]->flag == 1 )   
674                         Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF;
675                 else
676                         Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
677         } else 
678                 for (   i=2; i < 3; i++ )       
679                         if (DoorFlag[i]->flag == 1) { 
680                                 DoorFlag[i]->flag = 0;          // Tells ui that this button isn't checked
681                                 DoorFlag[i]->status = 1;        // Tells ui to redraw button
682                         }
683
684         //------------------------------------------------------------
685         // A simple frame time counter for animating the walls...
686         //------------------------------------------------------------
687         Temp = timer_get_fixed_seconds();
688         DeltaTime = Temp - Time;
689
690         //------------------------------------------------------------
691         // Draw the wall in the little 64x64 box
692         //------------------------------------------------------------
693         gr_set_current_canvas( WallViewBox->canvas );
694         if (Cursegp->sides[Curside].wall_num != -1) {
695                 type = Walls[Cursegp->sides[Curside].wall_num].type;
696                 if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) {
697                         if (DeltaTime > ((F1_0*200)/1000)) {
698                                 framenum++;
699                                 Time = Temp;
700                         }
701                         if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
702                                 framenum=0;
703                         PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]]);
704                         gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[framenum]].index]);
705                 } else {
706                         if (type == WALL_OPEN)
707                                 gr_clear_canvas( CBLACK );
708                         else {
709                                 if (Cursegp->sides[Curside].tmap_num2 > 0)
710                                         gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2));
711                                 else    {
712                                         PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
713                                         gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
714                                 }
715                         }
716                 }
717         } else
718                 gr_clear_canvas( CGREY );
719
720         //------------------------------------------------------------
721         // If anything changes in the ui system, redraw all the text that
722         // identifies this wall.
723         //------------------------------------------------------------
724         if (ui_button_any_drawn || (old_wall_num != Cursegp->sides[Curside].wall_num) ) {
725                 if ( Cursegp->sides[Curside].wall_num > -1 )    {
726                         ui_wprintf_at( MainWindow, 12, 6, "Wall: %d    ", Cursegp->sides[Curside].wall_num);
727                         switch (Walls[Cursegp->sides[Curside].wall_num].type) {
728                                 case WALL_NORMAL:
729                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Normal   " );
730                                         break;
731                                 case WALL_BLASTABLE:
732                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
733                                         break;
734                                 case WALL_DOOR:
735                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Door     " );
736                                         ui_wprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename);
737                                         break;
738                                 case WALL_ILLUSION:
739                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
740                                         break;
741                                 case WALL_OPEN:
742                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Open     " );
743                                         break;
744                                 case WALL_CLOSED:
745                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Closed   " );
746                                         break;
747                                 default:
748                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown  " );
749                                         break;
750                         }                       
751                         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
752                                         ui_wprintf_at( MainWindow, 223, 6, "            " );
753
754                         ui_wprintf_at( MainWindow, 12, 40, " Clip: %d   ", Walls[Cursegp->sides[Curside].wall_num].clip_num );
755                         ui_wprintf_at( MainWindow, 12, 57, " Trigger: %d  ", Walls[Cursegp->sides[Curside].wall_num].trigger );
756                 }       else {
757                         ui_wprintf_at( MainWindow, 12, 6, "Wall: none ");
758                         ui_wprintf_at( MainWindow, 12, 23, " Type: none ");
759                         ui_wprintf_at( MainWindow, 12, 40, " Clip: none   ");
760                         ui_wprintf_at( MainWindow, 12, 57, " Trigger: none  ");
761                 }
762                 Update_flags |= UF_WORLD_CHANGED;
763         }
764         if ( QuitButton->pressed || (last_keypress==KEY_ESC) )  {
765                 close_wall_window();
766                 return;
767         }               
768
769         old_wall_num = Cursegp->sides[Curside].wall_num;
770 }
771
772
773 //---------------------------------------------------------------------
774 // Restore all walls to original status (closed doors, repaired walls)
775 int wall_restore_all()
776 {
777         int i, j;
778         int wall_num;
779
780         for (i=0;i<Num_walls;i++) {
781                 if (Walls[i].flags & WALL_BLASTED) {
782                         Walls[i].hps = WALL_HPS;
783                         Walls[i].flags &= ~WALL_BLASTED;
784                 }
785                 if (Walls[i].flags & WALL_DOOR_OPENED)
786                         Walls[i].flags &= ~WALL_DOOR_OPENED;
787                 if (Walls[i].flags & WALL_DOOR_OPENING)
788                         Walls[i].flags &= ~WALL_DOOR_OPENING;
789         }
790
791         for (i=0;i<Num_open_doors;i++)
792                 wall_close_door(i);
793
794         for (i=0;i<Num_segments;i++)
795                 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
796                         wall_num = Segments[i].sides[j].wall_num;
797                         if (wall_num != -1)
798                                 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
799                                          (Walls[wall_num].type == WALL_DOOR))
800                                         Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
801                 }
802
803         for (i=0;i<Num_triggers;i++)
804                 Triggers[i].flags |= TRIGGER_ON;
805         
806         Update_flags |= UF_GAME_VIEW_CHANGED;
807
808         return 1;
809 }
810
811
812 //---------------------------------------------------------------------
813 //      Delete a specific wall.
814 int wall_delete_bogus(short wall_num)
815 {
816         int w;
817         int seg, side;
818
819         if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
820                 mprintf((0,"WALL IS NOT BOGUS.\n"));
821                 return 0;
822         }
823
824         // Delete bogus wall and slide all above walls down one slot
825         for (w=wall_num; w<Num_walls; w++) {
826                 Walls[w] = Walls[w+1];
827         }
828                 
829         Num_walls--;
830
831         for (seg=0;seg<=Highest_segment_index;seg++)
832                 if (Segments[seg].segnum != -1)
833                 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
834                         if      (Segments[seg].sides[side].wall_num > wall_num)
835                                 Segments[seg].sides[side].wall_num--;
836
837         mprintf((0,"BOGUS WALL DELETED!!!!\n"));
838
839         return 1;
840 }
841
842
843 //---------------------------------------------------------------------
844 //      Remove a specific side.
845 int wall_remove_side(segment *seg, short side)
846 {
847         int Connectside;
848         segment *csegp;
849         int lower_wallnum;
850         int w, s, t, l, t1;
851
852         if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
853                 csegp = &Segments[seg->children[side]];
854                 Connectside = find_connect_side(seg, csegp);
855
856                 remove_trigger(seg, side);
857                 remove_trigger(csegp, Connectside);
858
859                 // Remove walls 'wall_num' and connecting side 'wall_num'
860                 //  from Walls array.  
861                 lower_wallnum = seg->sides[side].wall_num;
862                 if (csegp->sides[Connectside].wall_num < lower_wallnum)
863                          lower_wallnum = csegp->sides[Connectside].wall_num;
864
865                 if (Walls[lower_wallnum].linked_wall != -1)
866                         Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
867                 if (Walls[lower_wallnum+1].linked_wall != -1)
868                         Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
869
870                 for (w=lower_wallnum;w<Num_walls-2;w++)
871                         Walls[w] = Walls[w+2];
872
873                 Num_walls -= 2;
874
875                 for (s=0;s<=Highest_segment_index;s++)
876                         if (Segments[s].segnum != -1)
877                         for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
878                                 if      (Segments[s].sides[w].wall_num > lower_wallnum+1)
879                                         Segments[s].sides[w].wall_num -= 2;
880
881                 // Destroy any links to the deleted wall.
882                 for (t=0;t<Num_triggers;t++)
883                         for (l=0;l<Triggers[t].num_links;l++)
884                                 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
885                                         for (t1=0;t1<Triggers[t].num_links-1;t1++) {
886                                                 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
887                                                 Triggers[t].side[t1] = Triggers[t].side[t1+1];
888                                         }
889                                         Triggers[t].num_links--;        
890                                 }
891
892                 // Destroy control center links as well.
893                 for (l=0;l<ControlCenterTriggers.num_links;l++)
894                         if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
895                                 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
896                                         ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
897                                         ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
898                                 }
899                                 ControlCenterTriggers.num_links--;      
900                         }
901
902                 seg->sides[side].wall_num = -1;
903                 csegp->sides[Connectside].wall_num = -1;
904
905                 Update_flags |= UF_WORLD_CHANGED;
906                 return 1;
907         }
908
909         editor_status( "Can't remove wall.  No wall present.");
910         return 0;
911 }
912
913 //---------------------------------------------------------------------
914 //      Remove a special wall.
915 int wall_remove()
916 {
917         return wall_remove_side(Cursegp, Curside);
918 }
919
920 //---------------------------------------------------------------------
921 // Add a wall to curside
922 int wall_add_to_side(segment *segp, int side, sbyte type)
923 {
924         int connectside;
925         segment *csegp;
926
927         if (add_wall(segp, side)) {
928                 csegp = &Segments[segp->children[side]];
929                 connectside = find_connect_side(segp, csegp);
930
931                 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
932                 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
933
934                 Walls[segp->sides[side].wall_num].sidenum = side;
935                 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
936
937                 Walls[segp->sides[side].wall_num].flags = 0;
938                 Walls[csegp->sides[connectside].wall_num].flags = 0;
939
940                 Walls[segp->sides[side].wall_num].type = type;
941                 Walls[csegp->sides[connectside].wall_num].type = type;
942
943 //              Walls[segp->sides[side].wall_num].trigger = -1;
944 //              Walls[csegp->sides[connectside].wall_num].trigger = -1;
945
946                 Walls[segp->sides[side].wall_num].clip_num = -1;
947                 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
948
949                 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
950                 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
951
952                 if (type == WALL_BLASTABLE) {
953                         Walls[segp->sides[side].wall_num].hps = WALL_HPS;
954                         Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
955                         
956                         //Walls[segp->sides[side].wall_num].clip_num = 0;
957                         //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
958                         }       
959
960                 if (type != WALL_DOOR) {
961                         segp->sides[side].tmap_num2 = 0;
962                         csegp->sides[connectside].tmap_num2 = 0;
963                         }
964
965                 if (type == WALL_DOOR) {
966                         Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
967                         Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
968
969                         Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
970                         Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
971                 }
972
973                 //Update_flags |= UF_WORLD_CHANGED;
974                 //return 1;
975
976 //              return NextWall();              //assign a clip num
977                 return wall_assign_door(Current_door_type);
978
979         } else {
980                 editor_status( "Cannot add wall here, no children" );
981                 return 0;
982         }
983 }
984
985
986 //---------------------------------------------------------------------
987 // Add a wall to markedside
988 int wall_add_to_markedside(sbyte type)
989 {
990         int Connectside;
991         segment *csegp;
992
993         if (add_wall(Markedsegp, Markedside)) {
994                 int     wall_num, cwall_num;
995                 csegp = &Segments[Markedsegp->children[Markedside]];
996
997                 Connectside = find_connect_side(Markedsegp, csegp);
998
999                 wall_num = Markedsegp->sides[Markedside].wall_num;
1000                 cwall_num = csegp->sides[Connectside].wall_num;
1001
1002                 Walls[wall_num].segnum = Markedsegp-Segments;
1003                 Walls[cwall_num].segnum = csegp-Segments;
1004
1005                 Walls[wall_num].sidenum = Markedside;
1006                 Walls[cwall_num].sidenum = Connectside;
1007
1008                 Walls[wall_num].flags = 0;
1009                 Walls[cwall_num].flags = 0;
1010
1011                 Walls[wall_num].type = type;
1012                 Walls[cwall_num].type = type;
1013
1014                 Walls[wall_num].trigger = -1;
1015                 Walls[cwall_num].trigger = -1;
1016
1017                 Walls[wall_num].clip_num = -1;
1018                 Walls[cwall_num].clip_num = -1;
1019
1020                 Walls[wall_num].keys = KEY_NONE;
1021                 Walls[cwall_num].keys = KEY_NONE;
1022
1023                 if (type == WALL_BLASTABLE) {
1024                         Walls[wall_num].hps = WALL_HPS;
1025                         Walls[cwall_num].hps = WALL_HPS;
1026                         
1027                         Walls[wall_num].clip_num = 0;
1028                         Walls[cwall_num].clip_num = 0;
1029                         }       
1030
1031                 if (type != WALL_DOOR) {
1032                         Markedsegp->sides[Markedside].tmap_num2 = 0;
1033                         csegp->sides[Connectside].tmap_num2 = 0;
1034                         }
1035
1036                 Update_flags |= UF_WORLD_CHANGED;
1037                 return 1;
1038         } else {
1039                 editor_status( "Cannot add wall here, no children" );
1040                 return 0;
1041         }
1042 }
1043
1044
1045 int wall_add_door_flag(sbyte flag)
1046 {
1047         int Connectside;
1048         segment *csegp;
1049
1050         if (Cursegp->sides[Curside].wall_num == -1)
1051                 {
1052                 editor_status("Cannot change flag. No wall at Curside.");
1053                 return 0;
1054                 }
1055
1056         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
1057                 {
1058                 editor_status("Cannot change flag. No door at Curside.");
1059                 return 0;
1060                 }
1061
1062         csegp = &Segments[Cursegp->children[Curside]];
1063         Connectside = find_connect_side(Cursegp, csegp);
1064
1065         Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
1066         Walls[csegp->sides[Connectside].wall_num].flags |= flag;
1067
1068         Update_flags |= UF_ED_STATE_CHANGED;
1069         return 1;
1070 }
1071
1072 int wall_remove_door_flag(sbyte flag)
1073 {
1074         int Connectside;
1075         segment *csegp;
1076
1077         if (Cursegp->sides[Curside].wall_num == -1)
1078                 {
1079                 editor_status("Cannot change flag. No wall at Curside.");
1080                 return 0;
1081                 }
1082
1083         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
1084                 {
1085                 editor_status("Cannot change flag. No door at Curside.");
1086                 return 0;
1087                 }
1088
1089         csegp = &Segments[Cursegp->children[Curside]];
1090         Connectside = find_connect_side(Cursegp, csegp);
1091
1092         Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
1093         Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
1094
1095         Update_flags |= UF_ED_STATE_CHANGED;
1096         return 1;
1097 }
1098
1099
1100 int bind_wall_to_control_center() {
1101
1102         int link_num;
1103         int i;
1104
1105         if (Cursegp->sides[Curside].wall_num == -1) {
1106                 editor_status("No wall at Curside.");
1107                 return 0;
1108         }
1109
1110         link_num = ControlCenterTriggers.num_links;
1111         for (i=0;i<link_num;i++)
1112                 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
1113                         editor_status("Curside already bound to Control Center.");
1114                         return 0;
1115                 }
1116
1117         // Error checking completed, actual binding begins
1118         ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
1119         ControlCenterTriggers.side[link_num] = Curside;
1120         ControlCenterTriggers.num_links++;
1121
1122         mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
1123                                 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num)); 
1124
1125         editor_status("Wall linked to control center");
1126
1127         return 1;
1128 }
1129
1130 //link two doors, curseg/curside and markedseg/markedside
1131 int wall_link_doors()
1132 {
1133         wall *w1=NULL,*w2=NULL;
1134
1135         if (Cursegp->sides[Curside].wall_num != -1)
1136                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
1137
1138         if (Markedsegp->sides[Markedside].wall_num != -1)
1139                 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
1140
1141         if (!w1 || w1->type != WALL_DOOR) {
1142                 editor_status("Curseg/curside is not a door");
1143                 return 0;
1144         }
1145
1146         if (!w2 || w2->type != WALL_DOOR) {
1147                 editor_status("Markedseg/markedside is not a door");
1148                 return 0;
1149         }
1150
1151         if (w1->linked_wall != -1)
1152                 editor_status("Curseg/curside is already linked");
1153
1154         if (w2->linked_wall != -1)
1155                 editor_status("Markedseg/markedside is already linked");
1156
1157         w1->linked_wall = w2-Walls;
1158         w2->linked_wall = w1-Walls;
1159
1160         return 1;
1161 }
1162
1163 int wall_unlink_door()
1164 {
1165         wall *w1=NULL;
1166
1167         if (Cursegp->sides[Curside].wall_num != -1)
1168                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
1169
1170         if (!w1 || w1->type != WALL_DOOR) {
1171                 editor_status("Curseg/curside is not a door");
1172                 return 0;
1173         }
1174
1175         if (w1->linked_wall == -1)
1176                 editor_status("Curseg/curside is not linked");
1177
1178         Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1179
1180         Walls[w1->linked_wall].linked_wall = -1;
1181         w1->linked_wall = -1;
1182
1183         return 1;
1184
1185 }
1186
1187 #define DIAGNOSTIC_MESSAGE_MAX                          150
1188
1189 int check_walls() 
1190 {
1191         int w, seg, side, wall_count, trigger_count;
1192         int w1, w2, t, l;
1193         count_wall CountedWalls[MAX_WALLS];
1194         char Message[DIAGNOSTIC_MESSAGE_MAX];
1195         int matcen_num;
1196
1197         wall_count = 0;
1198         for (seg=0;seg<=Highest_segment_index;seg++) 
1199                 if (Segments[seg].segnum != -1) {
1200                         // Check fuelcenters
1201                         matcen_num = Segments[seg].matcen_num;
1202                         if (matcen_num == 0)
1203                                 if (RobotCenters[0].segnum != seg) {
1204                                         mprintf((0,"Fixing Matcen 0\n"));
1205                                         Segments[seg].matcen_num = -1;
1206                                 }
1207         
1208                         if (matcen_num > -1)
1209                                 if (RobotCenters[matcen_num].segnum != seg) {
1210                                         mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1211                                         mprintf((0,"Fixing....\n"));
1212                                         RobotCenters[matcen_num].segnum = seg;
1213                                 }
1214         
1215                         for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1216                                 if (Segments[seg].sides[side].wall_num != -1) {
1217                                         CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1218                                         CountedWalls[wall_count].segnum = seg;
1219                                         CountedWalls[wall_count].sidenum = side;
1220         
1221                                         // Check if segnum is bogus
1222                                         if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1223                                                 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1224                                         }
1225         
1226                                         if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1227                                                 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1228                                         }
1229         
1230                                         wall_count++;
1231                                 }
1232                 }
1233
1234         mprintf((0,"Wall Count = %d\n", wall_count));
1235         
1236         if (wall_count != Num_walls) {
1237                 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1238                 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1239                         Num_walls = wall_count;
1240                         editor_status("Num_walls set to %d\n", Num_walls);
1241                 }
1242         }
1243
1244         // Check validity of Walls array.
1245         for (w=0; w<Num_walls; w++) {
1246                 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1247                         (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1248                         mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1249                         sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1250                         if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1251                                 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1252                                 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1253                         }
1254                 }
1255
1256                 if (CountedWalls[w].wallnum >= Num_walls)
1257                         mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1258
1259                 if (Walls[w].segnum == -1) {
1260                         mprintf((0, "Wall[%d] is BOGUS\n", w));
1261                         for (seg=0;seg<=Highest_segment_index;seg++) 
1262                                 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1263                                         if (Segments[seg].sides[side].wall_num == w) {
1264                                                 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1265                                         } 
1266                 }                               
1267         }
1268
1269         trigger_count = 0;
1270         for (w1=0; w1<wall_count; w1++) {
1271                 for (w2=w1+1; w2<wall_count; w2++) 
1272                         if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1273                                 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1274                                 mprintf((0, "Seg1:sides1 %d:%d  ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1275                                 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1276                         }
1277                 if (Walls[w1].trigger != -1) trigger_count++;
1278         }
1279
1280         if (trigger_count != Num_triggers) {
1281                 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1282                 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1283                         Num_triggers = trigger_count;
1284                         editor_status("Num_triggers set to %d\n", Num_triggers);
1285                 }
1286         }
1287
1288         mprintf((0,"Trigger Count = %d\n", trigger_count));
1289
1290         for (t=0; t<trigger_count; t++) {
1291                 if (Triggers[t].flags & TRIGGER_MATCEN)
1292                  {
1293                         if (Triggers[t].num_links < 1) 
1294                                 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1295                         else
1296                                 for (l=0;l<Triggers[t].num_links;l++) {
1297                                         if (!Segments[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1298                                                 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1299                                 }
1300                  }
1301
1302                 if (Triggers[t].flags & TRIGGER_EXIT)
1303                         if (Triggers[t].num_links != 0)
1304                                 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1305
1306                 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1307                         for (l=0;l<Triggers[t].num_links;l++) {
1308                                 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1309                                         mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1310                                         mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1311                                 }
1312                         }
1313         }
1314
1315         for (l=0;l<ControlCenterTriggers.num_links;l++)
1316                 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1317                         mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1318                         mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1319                 }
1320
1321         return 1;
1322
1323 }
1324
1325
1326 int delete_all_walls() 
1327 {
1328         char Message[DIAGNOSTIC_MESSAGE_MAX];
1329         int seg, side;
1330
1331         sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1332         if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1333                 for (seg=0;seg<=Highest_segment_index;seg++)
1334                         for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1335                                 Segments[seg].sides[side].wall_num = -1;
1336                 Num_walls=0;
1337                 Num_triggers=0;
1338
1339                 return 1;
1340         }
1341
1342         return 0;
1343 }
1344
1345 int delete_all_triggers()
1346 {
1347         char Message[DIAGNOSTIC_MESSAGE_MAX];
1348         int w;
1349
1350         sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1351         if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1352
1353                 for (w=0; w<Num_walls; w++)
1354                         Walls[w].trigger=-1;
1355                 Num_triggers=0;
1356
1357                 return 1;
1358         }
1359
1360         return 0;
1361 }
1362
1363 int dump_walls_info() 
1364 {
1365         int w; 
1366         FILE *fp;
1367
1368         fp = fopen("WALL.OUT", "wt");
1369
1370         fprintf(fp, "Num_walls %d\n", Num_walls);
1371
1372         for (w=0; w<Num_walls; w++) {
1373
1374                 fprintf(fp, "WALL #%d\n", w);
1375                 fprintf(fp, "  seg: %d\n", Walls[w].segnum);
1376                 fprintf(fp, "  sidenum: %d\n", Walls[w].sidenum);
1377         
1378                 switch (Walls[w].type) {
1379                         case WALL_NORMAL:
1380                                 fprintf(fp, "  type: NORMAL\n");
1381                                 break;
1382                         case WALL_BLASTABLE:
1383                                 fprintf(fp, "  type: BLASTABLE\n");
1384                                 break;
1385                         case WALL_DOOR:
1386                                 fprintf(fp, "  type: DOOR\n");
1387                                 break;
1388                         case WALL_ILLUSION:
1389                                 fprintf(fp, "  type: ILLUSION\n");
1390                                 break;
1391                         case WALL_OPEN:
1392                                 fprintf(fp, "  type: OPEN\n");
1393                                 break;
1394                         case WALL_CLOSED:
1395                                 fprintf(fp, "  type: CLOSED\n");
1396                                 break;
1397                         default:
1398                                 fprintf(fp, "  type: ILLEGAL!!!!! <-----------------\n");
1399                                 break;
1400                 }
1401         
1402                 fprintf(fp, "  flags:\n");
1403
1404                 if (Walls[w].flags & WALL_BLASTED)
1405                         fprintf(fp, "   BLASTED\n");
1406                 if (Walls[w].flags & WALL_DOOR_OPENED)
1407                         fprintf(fp, "   DOOR_OPENED <----------------- BAD!!!\n");
1408                 if (Walls[w].flags & WALL_DOOR_OPENING)
1409                         fprintf(fp, "   DOOR_OPENING <---------------- BAD!!!\n");
1410                 if (Walls[w].flags & WALL_DOOR_LOCKED)
1411                         fprintf(fp, "   DOOR_LOCKED\n");
1412                 if (Walls[w].flags & WALL_DOOR_AUTO)
1413                         fprintf(fp, "   DOOR_AUTO\n");
1414                 if (Walls[w].flags & WALL_ILLUSION_OFF)
1415                         fprintf(fp, "   ILLUSION_OFF <---------------- OUTDATED\n");
1416                 //if (Walls[w].flags & WALL_FUELCEN)
1417                 //      fprintf(fp, "   FUELCEN <--------------------- OUTDATED\n");
1418
1419                 fprintf(fp, "  trigger: %d\n", Walls[w].trigger);
1420                 fprintf(fp, "  clip_num: %d\n", Walls[w].clip_num);
1421
1422                 switch (Walls[w].keys) {
1423                         case KEY_NONE:
1424                                 fprintf(fp, "   key: NONE\n");
1425                                 break;
1426                         case KEY_BLUE:
1427                                 fprintf(fp, "   key: BLUE\n");
1428                                 break;
1429                         case KEY_RED:
1430                                 fprintf(fp, "   key: RED\n");
1431                                 break;
1432                         case KEY_GOLD:
1433                                 fprintf(fp, "   key: NONE\n");
1434                                 break;
1435                         default:
1436                                 fprintf(fp, "  key: ILLEGAL!!!!!! <-----------------\n");
1437                                 break;
1438                 }
1439
1440                 fprintf(fp, "  linked_wall %d\n", Walls[w].linked_wall);
1441         }
1442         
1443         fclose(fp);
1444         return 1;
1445 }
1446
1447 // ------------------------------------------------------------------------------------------------
1448 void copy_old_wall_data_to_new(int owall, int nwall)
1449 {
1450         Walls[nwall].flags = Walls[owall].flags;
1451         Walls[nwall].type = Walls[owall].type;
1452         Walls[nwall].clip_num = Walls[owall].clip_num;
1453         Walls[nwall].keys = Walls[owall].keys;
1454         Walls[nwall].hps = Walls[owall].hps;
1455         Walls[nwall].state = Walls[owall].state;
1456         Walls[nwall].linked_wall = -1;
1457
1458         Walls[nwall].trigger = -1;
1459
1460         if (Walls[owall].trigger != -1) {
1461                 editor_status("Warning: Trigger not copied in group copy.");
1462         }
1463 }
1464
1465 //typedef struct trigger {
1466 //      sbyte           type;
1467 //      short           flags;
1468 //      fix             value;
1469 //      fix             time;
1470 //      sbyte           link_num;
1471 //      short   num_links;
1472 //      short   seg[MAX_WALLS_PER_LINK];
1473 //      short           side[MAX_WALLS_PER_LINK];
1474 //      } trigger;
1475
1476
1477 // ------------------------------------------------------------------------------------------------
1478 void copy_group_walls(int old_group, int new_group)
1479 {
1480         int     i,j,old_seg, new_seg;
1481
1482         for (i=0; i<GroupList[old_group].num_segments; i++) {
1483                 old_seg = GroupList[old_group].segments[i];
1484                 new_seg = GroupList[new_group].segments[i];
1485
1486                 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1487                         if (Segments[old_seg].sides[j].wall_num != -1) {
1488                                 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1489                                 Segments[new_seg].sides[j].wall_num = Num_walls;
1490                                 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1491                                 Walls[Num_walls].segnum = new_seg;
1492                                 Walls[Num_walls].sidenum = j;
1493                                 Num_walls++;
1494                                 Assert(Num_walls < MAX_WALLS);
1495                         }
1496                 }
1497         }
1498 }
1499
1500 int     Validate_walls=1;
1501
1502 //      --------------------------------------------------------------------------------------------------------
1503 //      This function should be in medwall.c.
1504 //      Make sure all wall/segment connections are valid.
1505 void check_wall_validity(void)
1506 {
1507         int     i, j;
1508         int     segnum, sidenum, wall_num;
1509         sbyte   wall_flags[MAX_WALLS];
1510
1511         if (!Validate_walls)
1512                 return;
1513
1514         for (i=0; i<Num_walls; i++) {
1515                 segnum = Walls[i].segnum;
1516                 sidenum = Walls[i].sidenum;
1517
1518                 if (Segments[segnum].sides[sidenum].wall_num != i) {
1519                         if (!Validate_walls)
1520                                 return;
1521                         Int3();         //      Error! Your mine has been invalidated!
1522                                                         // Do not continue!  Do not save!
1523                                                         //      Remember your last action and Contact Mike!
1524                                                         //      To continue, set the variable Validate_walls to 1 by doing:
1525                                                         //              /Validate_walls = 1
1526                                                         //      Then do the usual /eip++;g
1527
1528                 }
1529         }
1530
1531         for (i=0; i<MAX_WALLS; i++)
1532                 wall_flags[i] = 0;
1533
1534         for (i=0; i<=Highest_segment_index; i++) {
1535                 if (Segments[i].segnum != -1)
1536                         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1537                                 // Check walls
1538                                 wall_num = Segments[i].sides[j].wall_num;
1539                                 if (wall_num != -1) {
1540                                         if (wall_flags[wall_num] != 0) {
1541                                                 if (!Validate_walls)
1542                                                         return;
1543                                                 Int3();         //      Error! Your mine has been invalidated!
1544                                                                                 // Do not continue!  Do not save!
1545                                                                                 //      Remember your last action and Contact Mike!
1546                                                                                 //      To continue, set the variable Validate_walls to 1 by doing:
1547                                                                                 //              /Validate_walls = 1
1548                                                                                 //      Then do the usual /eip++;g
1549                                         }
1550
1551                                         if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1552                                                 if (!Validate_walls)
1553                                                         return;
1554                                                 Int3();         //      Error! Your mine has been invalidated!
1555                                                                                 // Do not continue!  Do not save!
1556                                                                                 //      Remember your last action and Contact Mike!
1557                                                                                 //      To continue, set the variable Validate_walls to 1 by doing:
1558                                                                                 //              /Validate_walls = 1
1559                                                                                 //      Then do the usual /eip++;g
1560                                         }
1561
1562                                         wall_flags[wall_num] = 1;
1563                                 }
1564                         }
1565
1566         }
1567 }
1568