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