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