]> icculus.org git repositories - btb/d2x.git/blob - main/editor/medwall.c
Rename include/error.h to include/dxxerror.h
[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 /*
15  *
16  * Created from version 1.11 of main\wall.c
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "conf.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28
29 #include "inferno.h"
30 #include "editor.h"
31 #include "dxxerror.h"
32 #include "timer.h"
33 #include "mono.h"
34 #include "key.h"
35
36
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];
48
49 static int old_wall_num;
50 static fix Time;
51 static int framenum=0;
52 static int Current_door_type=1;
53
54 typedef struct count_wall {
55         short wallnum;
56         short   segnum,sidenum; 
57 } count_wall;
58
59 //---------------------------------------------------------------------
60 extern void create_removable_wall(segment *sp, int sidenum, int tmap_num);
61
62 // Add a wall (removable 2 sided)
63 int add_wall(segment *seg, short side)
64 {
65         int Connectside;
66         segment *csegp;
67
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;
72                         Num_walls++;
73                         }
74                                  
75                 csegp = &Segments[seg->children[side]];
76                 Connectside = find_connect_side(seg, csegp);
77
78                 if (csegp->sides[Connectside].wall_num == -1) {
79                         csegp->sides[Connectside].wall_num = Num_walls;
80                         Num_walls++;
81                         }
82                 
83                 create_removable_wall( seg, side, CurrentTexture );
84                 create_removable_wall( csegp, Connectside, CurrentTexture );
85
86                 return 1;
87                 }
88
89         return 0;
90 }
91
92 int wall_assign_door(int door_type)
93 {
94         int Connectside;
95         segment *csegp;
96
97         if (Cursegp->sides[Curside].wall_num == -1) {
98                 editor_status("Cannot assign door. No wall at Curside.");
99                 return 0;
100         }
101
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.");
104                 return 0;
105         }
106
107         Current_door_type = door_type;
108
109         csegp = &Segments[Cursegp->children[Curside]];
110         Connectside = find_connect_side(Cursegp, csegp);
111         
112         Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type;
113         Walls[csegp->sides[Connectside].wall_num].clip_num = door_type;
114
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;
120         }
121         else {
122                 Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0];
123                 csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0];
124         }
125
126         Update_flags |= UF_WORLD_CHANGED;
127         return 1;
128 }
129
130 int wall_add_blastable()
131 {
132         return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE);
133 }
134
135 int wall_add_door()
136 {
137         return wall_add_to_side(Cursegp, Curside, WALL_DOOR);
138 }
139
140 int wall_add_closed_wall()
141 {
142         return wall_add_to_side(Cursegp, Curside, WALL_CLOSED);
143 }
144
145 int wall_add_external_wall()
146 {
147         if (Cursegp->children[Curside] == -2) {
148                 editor_status( "Wall is already external!" );
149                 return 1;
150         }
151
152         if (IS_CHILD(Cursegp->children[Curside])) {
153                 editor_status( "Cannot add external wall here - seg has children" );
154                 return 0;
155         }
156
157         Cursegp->children[Curside] = -2;
158
159         return 1;
160 }
161
162 int wall_add_illusion()
163 {
164         return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION);
165 }
166
167 int wall_lock_door()
168 {
169         return wall_add_door_flag(WALL_DOOR_LOCKED);
170 }
171
172 int wall_unlock_door()
173 {
174         return wall_remove_door_flag(WALL_DOOR_LOCKED);
175 }
176
177 int wall_automate_door()
178 {
179         return wall_add_door_flag(WALL_DOOR_AUTO);
180 }
181         
182 int wall_deautomate_door()
183 {
184         return wall_remove_door_flag(WALL_DOOR_AUTO);
185 }
186
187 int GotoPrevWall() {
188         int current_wall;
189
190         if (Cursegp->sides[Curside].wall_num < 0)
191                 current_wall = Num_walls;
192         else
193                 current_wall = Cursegp->sides[Curside].wall_num;
194
195         current_wall--;
196         if (current_wall < 0) current_wall = Num_walls-1;
197         if (current_wall >= Num_walls) current_wall = Num_walls-1;
198
199         if (Walls[current_wall].segnum == -1) {
200                 mprintf((0, "Trying to goto wall at bogus segnum\n"));
201                 return 0;
202         }
203
204         if (Walls[current_wall].sidenum == -1) {
205                 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
206                 return 0;
207         }
208
209         Cursegp = &Segments[Walls[current_wall].segnum];
210         Curside = Walls[current_wall].sidenum;
211
212         return 1;
213 }
214
215
216 int GotoNextWall() {
217         int current_wall;
218
219         current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0
220
221         current_wall++;
222
223         if (current_wall >= Num_walls) current_wall = 0;
224         if (current_wall < 0) current_wall = 0;
225
226         if (Walls[current_wall].segnum == -1) {
227                 mprintf((0, "Trying to goto wall at bogus segnum\n"));
228                 return 0;
229         }
230
231         if (Walls[current_wall].sidenum == -1) {
232                 mprintf((0, "Trying to goto wall at bogus sidenum\n"));
233                 return 0;
234         }
235
236         Cursegp = &Segments[Walls[current_wall].segnum];
237         Curside = Walls[current_wall].sidenum;  
238
239         return 1;
240 }
241
242
243 int PrevWall() {
244         int wall_type;
245
246         if (Cursegp->sides[Curside].wall_num == -1) {
247                 editor_status("Cannot assign new wall. No wall on curside.");
248                 return 0;
249         }
250
251         wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
252
253         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
254
255                 do {
256
257                         wall_type--;
258
259                         if (wall_type < 0)
260                                 wall_type = Num_wall_anims-1;
261
262                         if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
263                                 Error("Cannot find clip for door."); 
264
265                 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
266
267         }
268
269         else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
270
271                 do {
272
273                         wall_type--;
274
275                         if (wall_type < 0)
276                                 wall_type = Num_wall_anims-1;
277
278                         if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num)
279                                 Error("Cannot find clip for blastable wall."); 
280
281                 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
282
283         }
284
285         wall_assign_door(wall_type);
286
287         Update_flags |= UF_WORLD_CHANGED;
288         return 1;
289 }
290
291 int NextWall() {
292         int wall_type;
293
294         if (Cursegp->sides[Curside].wall_num == -1) {
295                 editor_status("Cannot assign new wall. No wall on curside.");
296                 return 0;
297         }
298
299         wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num;
300
301         if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) {
302
303                 do {
304
305                         wall_type++;
306
307                         if (wall_type >= Num_wall_anims) {
308                                 wall_type = 0;
309                                 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
310                                         Error("Cannot find clip for door."); 
311                         }
312
313                 } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE);
314
315         }
316         else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) {
317
318                 do {
319
320                         wall_type++;
321
322                         if (wall_type >= Num_wall_anims) {
323                                 wall_type = 0;
324                                 if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1)
325                                         Error("Cannot find clip for blastable wall."); 
326                         }
327
328                 } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE));
329
330         }
331
332         wall_assign_door(wall_type);    
333
334         Update_flags |= UF_WORLD_CHANGED;
335         return 1;
336
337 }
338
339 //-------------------------------------------------------------------------
340 // Called from the editor... does one instance of the wall dialog box
341 //-------------------------------------------------------------------------
342 int do_wall_dialog()
343 {
344         int i;
345
346         // Only open 1 instance of this window...
347         if ( MainWindow != NULL ) return 0;
348
349         // Close other windows. 
350         close_all_windows();
351
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 );
355
356         // These are the checkboxes for each door flag.
357         i = 80;
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;
361
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;
366
367         // The little box the wall will appear in.
368         WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
369
370         // A bunch of buttons...
371         i = 80;
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;
384         
385         old_wall_num = -2;              // Set to some dummy value so everything works ok on the first frame.
386
387         return 1;
388 }
389
390 void close_wall_window()
391 {
392         if ( MainWindow!=NULL ) {
393                 ui_close_window( MainWindow );
394                 MainWindow = NULL;
395         }
396 }
397
398 void do_wall_window()
399 {
400         int i;
401         sbyte type;
402         fix DeltaTime, Temp;
403
404         if ( MainWindow == NULL ) return;
405
406         //------------------------------------------------------------
407         // Call the ui code..
408         //------------------------------------------------------------
409         ui_button_any_drawn = 0;
410         ui_window_do_gadgets(MainWindow);
411
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)
417         {
418                 if ( Cursegp->sides[Curside].wall_num != -1)
419                 {
420                         wall *w = &Walls[Cursegp->sides[Curside].wall_num];
421
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);
425
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);
434                 }
435         }
436         
437         //------------------------------------------------------------
438         // If any of the checkboxes that control the wallflags are set, then
439         // update the corresponding wall flag.
440         //------------------------------------------------------------
441
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;
445                 else
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;
449                 else
450                         Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO;
451
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));
460                         }
461                 }
462         } else {
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;         
469                         }
470                 }
471         }
472
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;
476                 else
477                         Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF;
478         } else 
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
483                         }
484
485         //------------------------------------------------------------
486         // A simple frame time counter for animating the walls...
487         //------------------------------------------------------------
488         Temp = timer_get_fixed_seconds();
489         DeltaTime = Temp - Time;
490
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)) {
499                                 framenum++;
500                                 Time = Temp;
501                         }
502                         if (framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames)
503                                 framenum=0;
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]);
506                 } else {
507                         if (type == WALL_OPEN)
508                                 gr_clear_canvas( CBLACK );
509                         else {
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));
512                                 else    {
513                                         PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]);
514                                         gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]);
515                                 }
516                         }
517                 }
518         } else
519                 gr_clear_canvas( CGREY );
520
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) {
529                                 case WALL_NORMAL:
530                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Normal   " );
531                                         break;
532                                 case WALL_BLASTABLE:
533                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Blastable" );
534                                         break;
535                                 case WALL_DOOR:
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);
538                                         break;
539                                 case WALL_ILLUSION:
540                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Illusion " );
541                                         break;
542                                 case WALL_OPEN:
543                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Open     " );
544                                         break;
545                                 case WALL_CLOSED:
546                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Closed   " );
547                                         break;
548                                 default:
549                                         ui_wprintf_at( MainWindow, 12, 23, " Type: Unknown  " );
550                                         break;
551                         }                       
552                         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
553                                         ui_wprintf_at( MainWindow, 223, 6, "            " );
554
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 );
557                 }       else {
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  ");
562                 }
563                 Update_flags |= UF_WORLD_CHANGED;
564         }
565         if ( QuitButton->pressed || (last_keypress==KEY_ESC) )  {
566                 close_wall_window();
567                 return;
568         }               
569
570         old_wall_num = Cursegp->sides[Curside].wall_num;
571 }
572
573
574 //---------------------------------------------------------------------
575 extern void wall_close_door_num(int door_num);
576
577 // Restore all walls to original status (closed doors, repaired walls)
578 int wall_restore_all()
579 {
580         int i, j;
581         int wall_num;
582
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;
587                 }
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;
592         }
593
594         for (i=0;i<Num_open_doors;i++)
595                 wall_close_door_num(i);
596
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;
600                         if (wall_num != -1)
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];
604                 }
605
606         for (i=0;i<Num_triggers;i++)
607                 Triggers[i].flags |= TRIGGER_ON;
608         
609         Update_flags |= UF_GAME_VIEW_CHANGED;
610
611         return 1;
612 }
613
614
615 //---------------------------------------------------------------------
616 //      Delete a specific wall.
617 int wall_delete_bogus(short wall_num)
618 {
619         int w;
620         int seg, side;
621
622         if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
623                 mprintf((0,"WALL IS NOT BOGUS.\n"));
624                 return 0;
625         }
626
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];
630         }
631                 
632         Num_walls--;
633
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--;
639
640         mprintf((0,"BOGUS WALL DELETED!!!!\n"));
641
642         return 1;
643 }
644
645
646 //---------------------------------------------------------------------
647 //      Remove a specific side.
648 int wall_remove_side(segment *seg, short side)
649 {
650         int Connectside;
651         segment *csegp;
652         int lower_wallnum;
653         int w, s, t, l, t1;
654
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);
658
659                 remove_trigger(seg, side);
660                 remove_trigger(csegp, Connectside);
661
662                 // Remove walls 'wall_num' and connecting side 'wall_num'
663                 //  from Walls array.  
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;
667
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;
672
673                 for (w=lower_wallnum;w<Num_walls-2;w++)
674                         Walls[w] = Walls[w+2];
675
676                 Num_walls -= 2;
677
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;
683
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];
691                                         }
692                                         Triggers[t].num_links--;        
693                                 }
694
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];
701                                 }
702                                 ControlCenterTriggers.num_links--;      
703                         }
704
705                 seg->sides[side].wall_num = -1;
706                 csegp->sides[Connectside].wall_num = -1;
707
708                 Update_flags |= UF_WORLD_CHANGED;
709                 return 1;
710         }
711
712         editor_status( "Can't remove wall.  No wall present.");
713         return 0;
714 }
715
716 //---------------------------------------------------------------------
717 //      Remove a special wall.
718 int wall_remove()
719 {
720         return wall_remove_side(Cursegp, Curside);
721 }
722
723 //---------------------------------------------------------------------
724 // Add a wall to curside
725 int wall_add_to_side(segment *segp, int side, sbyte type)
726 {
727         int connectside;
728         segment *csegp;
729
730         if (add_wall(segp, side)) {
731                 csegp = &Segments[segp->children[side]];
732                 connectside = find_connect_side(segp, csegp);
733
734                 Walls[segp->sides[side].wall_num].segnum = SEGMENT_NUMBER(segp);
735                 Walls[csegp->sides[connectside].wall_num].segnum = SEGMENT_NUMBER(csegp);
736
737                 Walls[segp->sides[side].wall_num].sidenum = side;
738                 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
739
740                 Walls[segp->sides[side].wall_num].flags = 0;
741                 Walls[csegp->sides[connectside].wall_num].flags = 0;
742
743                 Walls[segp->sides[side].wall_num].type = type;
744                 Walls[csegp->sides[connectside].wall_num].type = type;
745
746 //              Walls[segp->sides[side].wall_num].trigger = -1;
747 //              Walls[csegp->sides[connectside].wall_num].trigger = -1;
748
749                 Walls[segp->sides[side].wall_num].clip_num = -1;
750                 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
751
752                 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
753                 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
754
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;
758                         
759                         //Walls[segp->sides[side].wall_num].clip_num = 0;
760                         //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
761                         }       
762
763                 if (type != WALL_DOOR) {
764                         segp->sides[side].tmap_num2 = 0;
765                         csegp->sides[connectside].tmap_num2 = 0;
766                         }
767
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;
771
772                         Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
773                         Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
774                 }
775
776                 //Update_flags |= UF_WORLD_CHANGED;
777                 //return 1;
778
779 //              return NextWall();              //assign a clip num
780                 return wall_assign_door(Current_door_type);
781
782         } else {
783                 editor_status( "Cannot add wall here, no children" );
784                 return 0;
785         }
786 }
787
788
789 //---------------------------------------------------------------------
790 // Add a wall to markedside
791 int wall_add_to_markedside(sbyte type)
792 {
793         int Connectside;
794         segment *csegp;
795
796         if (add_wall(Markedsegp, Markedside)) {
797                 int     wall_num, cwall_num;
798                 csegp = &Segments[Markedsegp->children[Markedside]];
799
800                 Connectside = find_connect_side(Markedsegp, csegp);
801
802                 wall_num = Markedsegp->sides[Markedside].wall_num;
803                 cwall_num = csegp->sides[Connectside].wall_num;
804
805                 Walls[wall_num].segnum = SEGMENT_NUMBER(Markedsegp);
806                 Walls[cwall_num].segnum = SEGMENT_NUMBER(csegp);
807
808                 Walls[wall_num].sidenum = Markedside;
809                 Walls[cwall_num].sidenum = Connectside;
810
811                 Walls[wall_num].flags = 0;
812                 Walls[cwall_num].flags = 0;
813
814                 Walls[wall_num].type = type;
815                 Walls[cwall_num].type = type;
816
817                 Walls[wall_num].trigger = -1;
818                 Walls[cwall_num].trigger = -1;
819
820                 Walls[wall_num].clip_num = -1;
821                 Walls[cwall_num].clip_num = -1;
822
823                 Walls[wall_num].keys = KEY_NONE;
824                 Walls[cwall_num].keys = KEY_NONE;
825
826                 if (type == WALL_BLASTABLE) {
827                         Walls[wall_num].hps = WALL_HPS;
828                         Walls[cwall_num].hps = WALL_HPS;
829                         
830                         Walls[wall_num].clip_num = 0;
831                         Walls[cwall_num].clip_num = 0;
832                         }       
833
834                 if (type != WALL_DOOR) {
835                         Markedsegp->sides[Markedside].tmap_num2 = 0;
836                         csegp->sides[Connectside].tmap_num2 = 0;
837                         }
838
839                 Update_flags |= UF_WORLD_CHANGED;
840                 return 1;
841         } else {
842                 editor_status( "Cannot add wall here, no children" );
843                 return 0;
844         }
845 }
846
847
848 int wall_add_door_flag(sbyte flag)
849 {
850         int Connectside;
851         segment *csegp;
852
853         if (Cursegp->sides[Curside].wall_num == -1)
854                 {
855                 editor_status("Cannot change flag. No wall at Curside.");
856                 return 0;
857                 }
858
859         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
860                 {
861                 editor_status("Cannot change flag. No door at Curside.");
862                 return 0;
863                 }
864
865         csegp = &Segments[Cursegp->children[Curside]];
866         Connectside = find_connect_side(Cursegp, csegp);
867
868         Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
869         Walls[csegp->sides[Connectside].wall_num].flags |= flag;
870
871         Update_flags |= UF_ED_STATE_CHANGED;
872         return 1;
873 }
874
875 int wall_remove_door_flag(sbyte flag)
876 {
877         int Connectside;
878         segment *csegp;
879
880         if (Cursegp->sides[Curside].wall_num == -1)
881                 {
882                 editor_status("Cannot change flag. No wall at Curside.");
883                 return 0;
884                 }
885
886         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
887                 {
888                 editor_status("Cannot change flag. No door at Curside.");
889                 return 0;
890                 }
891
892         csegp = &Segments[Cursegp->children[Curside]];
893         Connectside = find_connect_side(Cursegp, csegp);
894
895         Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
896         Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
897
898         Update_flags |= UF_ED_STATE_CHANGED;
899         return 1;
900 }
901
902
903 int bind_wall_to_control_center() {
904
905         int link_num;
906         int i;
907
908         if (Cursegp->sides[Curside].wall_num == -1) {
909                 editor_status("No wall at Curside.");
910                 return 0;
911         }
912
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.");
917                         return 0;
918                 }
919
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++;
924
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)); 
927
928         editor_status("Wall linked to control center");
929
930         return 1;
931 }
932
933 //link two doors, curseg/curside and markedseg/markedside
934 int wall_link_doors()
935 {
936         wall *w1=NULL,*w2=NULL;
937
938         if (Cursegp->sides[Curside].wall_num != -1)
939                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
940
941         if (Markedsegp->sides[Markedside].wall_num != -1)
942                 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
943
944         if (!w1 || w1->type != WALL_DOOR) {
945                 editor_status("Curseg/curside is not a door");
946                 return 0;
947         }
948
949         if (!w2 || w2->type != WALL_DOOR) {
950                 editor_status("Markedseg/markedside is not a door");
951                 return 0;
952         }
953
954         if (w1->linked_wall != -1)
955                 editor_status("Curseg/curside is already linked");
956
957         if (w2->linked_wall != -1)
958                 editor_status("Markedseg/markedside is already linked");
959
960         w1->linked_wall = WALL_NUMBER(w2);
961         w2->linked_wall = WALL_NUMBER(w1);
962
963         return 1;
964 }
965
966 int wall_unlink_door()
967 {
968         wall *w1=NULL;
969
970         if (Cursegp->sides[Curside].wall_num != -1)
971                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
972
973         if (!w1 || w1->type != WALL_DOOR) {
974                 editor_status("Curseg/curside is not a door");
975                 return 0;
976         }
977
978         if (w1->linked_wall == -1)
979                 editor_status("Curseg/curside is not linked");
980
981         Assert(Walls[w1->linked_wall].linked_wall == WALL_NUMBER(w1));
982
983         Walls[w1->linked_wall].linked_wall = -1;
984         w1->linked_wall = -1;
985
986         return 1;
987
988 }
989
990 #define DIAGNOSTIC_MESSAGE_MAX                          150
991
992 int check_walls() 
993 {
994         int w, seg, side, wall_count, trigger_count;
995         int w1, w2, t, l;
996         count_wall CountedWalls[MAX_WALLS];
997         char Message[DIAGNOSTIC_MESSAGE_MAX];
998         int matcen_num;
999
1000         wall_count = 0;
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;
1009                                 }
1010         
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;
1016                                 }
1017         
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;
1023         
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));
1027                                         }
1028         
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));
1031                                         }
1032         
1033                                         wall_count++;
1034                                 }
1035                 }
1036
1037         mprintf((0,"Wall Count = %d\n", wall_count));
1038         
1039         if (wall_count != Num_walls) {
1040                 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1041                 if (ui_messagebox( -2, -2, 2, Message, "Yes", "No" )==1) {
1042                         Num_walls = wall_count;
1043                         editor_status("Num_walls set to %d\n", Num_walls);
1044                 }
1045         }
1046
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 (ui_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;
1056                         }
1057                 }
1058
1059                 if (CountedWalls[w].wallnum >= Num_walls)
1060                         mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1061
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));
1068                                         } 
1069                 }                               
1070         }
1071
1072         trigger_count = 0;
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));
1079                         }
1080                 if (Walls[w1].trigger != -1) trigger_count++;
1081         }
1082
1083         if (trigger_count != Num_triggers) {
1084                 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1085                 if (ui_messagebox( -2, -2, 2, Message, "Yes", "No" )==1) {
1086                         Num_triggers = trigger_count;
1087                         editor_status("Num_triggers set to %d\n", Num_triggers);
1088                 }
1089         }
1090
1091         mprintf((0,"Trigger Count = %d\n", trigger_count));
1092
1093         for (t=0; t<trigger_count; t++) {
1094                 if (Triggers[t].flags & TRIGGER_MATCEN)
1095                  {
1096                         if (Triggers[t].num_links < 1) 
1097                                 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1098                         else
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]));
1102                                 }
1103                  }
1104
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));
1108
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]));
1114                                 }
1115                         }
1116         }
1117
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]));
1122                 }
1123
1124         return 1;
1125
1126 }
1127
1128
1129 int delete_all_walls() 
1130 {
1131         char Message[DIAGNOSTIC_MESSAGE_MAX];
1132         int seg, side;
1133
1134         sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1135         if (ui_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;
1139                 Num_walls=0;
1140                 Num_triggers=0;
1141
1142                 return 1;
1143         }
1144
1145         return 0;
1146 }
1147
1148 int delete_all_triggers()
1149 {
1150         char Message[DIAGNOSTIC_MESSAGE_MAX];
1151         int w;
1152
1153         sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1154         if (ui_messagebox( -2, -2, 2, Message, "YES!", "No" )==1) {
1155
1156                 for (w=0; w<Num_walls; w++)
1157                         Walls[w].trigger=-1;
1158                 Num_triggers=0;
1159
1160                 return 1;
1161         }
1162
1163         return 0;
1164 }
1165
1166 int dump_walls_info() 
1167 {
1168         int w; 
1169         FILE *fp;
1170
1171         fp = fopen("WALL.OUT", "wt");
1172
1173         fprintf(fp, "Num_walls %d\n", Num_walls);
1174
1175         for (w=0; w<Num_walls; w++) {
1176
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);
1180         
1181                 switch (Walls[w].type) {
1182                         case WALL_NORMAL:
1183                                 fprintf(fp, "  type: NORMAL\n");
1184                                 break;
1185                         case WALL_BLASTABLE:
1186                                 fprintf(fp, "  type: BLASTABLE\n");
1187                                 break;
1188                         case WALL_DOOR:
1189                                 fprintf(fp, "  type: DOOR\n");
1190                                 break;
1191                         case WALL_ILLUSION:
1192                                 fprintf(fp, "  type: ILLUSION\n");
1193                                 break;
1194                         case WALL_OPEN:
1195                                 fprintf(fp, "  type: OPEN\n");
1196                                 break;
1197                         case WALL_CLOSED:
1198                                 fprintf(fp, "  type: CLOSED\n");
1199                                 break;
1200                         default:
1201                                 fprintf(fp, "  type: ILLEGAL!!!!! <-----------------\n");
1202                                 break;
1203                 }
1204         
1205                 fprintf(fp, "  flags:\n");
1206
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");
1221
1222                 fprintf(fp, "  trigger: %d\n", Walls[w].trigger);
1223                 fprintf(fp, "  clip_num: %d\n", Walls[w].clip_num);
1224
1225                 switch (Walls[w].keys) {
1226                         case KEY_NONE:
1227                                 fprintf(fp, "   key: NONE\n");
1228                                 break;
1229                         case KEY_BLUE:
1230                                 fprintf(fp, "   key: BLUE\n");
1231                                 break;
1232                         case KEY_RED:
1233                                 fprintf(fp, "   key: RED\n");
1234                                 break;
1235                         case KEY_GOLD:
1236                                 fprintf(fp, "   key: NONE\n");
1237                                 break;
1238                         default:
1239                                 fprintf(fp, "  key: ILLEGAL!!!!!! <-----------------\n");
1240                                 break;
1241                 }
1242
1243                 fprintf(fp, "  linked_wall %d\n", Walls[w].linked_wall);
1244         }
1245         
1246         fclose(fp);
1247         return 1;
1248 }
1249
1250 // ------------------------------------------------------------------------------------------------
1251 void copy_old_wall_data_to_new(int owall, int nwall)
1252 {
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;
1260
1261         Walls[nwall].trigger = -1;
1262
1263         if (Walls[owall].trigger != -1) {
1264                 editor_status("Warning: Trigger not copied in group copy.");
1265         }
1266 }
1267
1268 //typedef struct trigger {
1269 //      sbyte           type;
1270 //      short           flags;
1271 //      fix             value;
1272 //      fix             time;
1273 //      sbyte           link_num;
1274 //      short   num_links;
1275 //      short   seg[MAX_WALLS_PER_LINK];
1276 //      short           side[MAX_WALLS_PER_LINK];
1277 //      } trigger;
1278
1279
1280 // ------------------------------------------------------------------------------------------------
1281 void copy_group_walls(int old_group, int new_group)
1282 {
1283         int     i,j,old_seg, new_seg;
1284
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];
1288
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;
1296                                 Num_walls++;
1297                                 Assert(Num_walls < MAX_WALLS);
1298                         }
1299                 }
1300         }
1301 }
1302
1303 int     Validate_walls=1;
1304
1305 //      --------------------------------------------------------------------------------------------------------
1306 //      This function should be in medwall.c.
1307 //      Make sure all wall/segment connections are valid.
1308 void check_wall_validity(void)
1309 {
1310         int     i, j;
1311         int     segnum, sidenum, wall_num;
1312         sbyte   wall_flags[MAX_WALLS];
1313
1314         if (!Validate_walls)
1315                 return;
1316
1317         for (i=0; i<Num_walls; i++) {
1318                 segnum = Walls[i].segnum;
1319                 sidenum = Walls[i].sidenum;
1320
1321                 if (Segments[segnum].sides[sidenum].wall_num != i) {
1322                         if (!Validate_walls)
1323                                 return;
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
1330
1331                 }
1332         }
1333
1334         for (i=0; i<MAX_WALLS; i++)
1335                 wall_flags[i] = 0;
1336
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++) {
1340                                 // Check walls
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)
1345                                                         return;
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
1352                                         }
1353
1354                                         if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1355                                                 if (!Validate_walls)
1356                                                         return;
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
1363                                         }
1364
1365                                         wall_flags[wall_num] = 1;
1366                                 }
1367                         }
1368
1369         }
1370 }
1371