]> icculus.org git repositories - btb/d2x.git/blob - main/editor/medwall.c
use wall_close_door_num, not wall_close_door
[btb/d2x.git] / main / editor / medwall.c
1 /* $Id: medwall.c,v 1.6 2005-01-25 19:34:50 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.6 2005-01-25 19:34:50 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 extern void wall_close_door_num(int door_num);
606
607 // Restore all walls to original status (closed doors, repaired walls)
608 int wall_restore_all()
609 {
610         int i, j;
611         int wall_num;
612
613         for (i=0;i<Num_walls;i++) {
614                 if (Walls[i].flags & WALL_BLASTED) {
615                         Walls[i].hps = WALL_HPS;
616                         Walls[i].flags &= ~WALL_BLASTED;
617                 }
618                 if (Walls[i].flags & WALL_DOOR_OPENED)
619                         Walls[i].flags &= ~WALL_DOOR_OPENED;
620                 if (Walls[i].flags & WALL_DOOR_OPENING)
621                         Walls[i].flags &= ~WALL_DOOR_OPENING;
622         }
623
624         for (i=0;i<Num_open_doors;i++)
625                 wall_close_door_num(i);
626
627         for (i=0;i<Num_segments;i++)
628                 for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
629                         wall_num = Segments[i].sides[j].wall_num;
630                         if (wall_num != -1)
631                                 if ((Walls[wall_num].type == WALL_BLASTABLE) ||
632                                          (Walls[wall_num].type == WALL_DOOR))
633                                         Segments[i].sides[j].tmap_num2 = WallAnims[Walls[wall_num].clip_num].frames[0];
634                 }
635
636         for (i=0;i<Num_triggers;i++)
637                 Triggers[i].flags |= TRIGGER_ON;
638         
639         Update_flags |= UF_GAME_VIEW_CHANGED;
640
641         return 1;
642 }
643
644
645 //---------------------------------------------------------------------
646 //      Delete a specific wall.
647 int wall_delete_bogus(short wall_num)
648 {
649         int w;
650         int seg, side;
651
652         if ((Walls[wall_num].segnum != -1) && (Walls[wall_num].sidenum != -1)) {
653                 mprintf((0,"WALL IS NOT BOGUS.\n"));
654                 return 0;
655         }
656
657         // Delete bogus wall and slide all above walls down one slot
658         for (w=wall_num; w<Num_walls; w++) {
659                 Walls[w] = Walls[w+1];
660         }
661                 
662         Num_walls--;
663
664         for (seg=0;seg<=Highest_segment_index;seg++)
665                 if (Segments[seg].segnum != -1)
666                 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
667                         if      (Segments[seg].sides[side].wall_num > wall_num)
668                                 Segments[seg].sides[side].wall_num--;
669
670         mprintf((0,"BOGUS WALL DELETED!!!!\n"));
671
672         return 1;
673 }
674
675
676 //---------------------------------------------------------------------
677 //      Remove a specific side.
678 int wall_remove_side(segment *seg, short side)
679 {
680         int Connectside;
681         segment *csegp;
682         int lower_wallnum;
683         int w, s, t, l, t1;
684
685         if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) {
686                 csegp = &Segments[seg->children[side]];
687                 Connectside = find_connect_side(seg, csegp);
688
689                 remove_trigger(seg, side);
690                 remove_trigger(csegp, Connectside);
691
692                 // Remove walls 'wall_num' and connecting side 'wall_num'
693                 //  from Walls array.  
694                 lower_wallnum = seg->sides[side].wall_num;
695                 if (csegp->sides[Connectside].wall_num < lower_wallnum)
696                          lower_wallnum = csegp->sides[Connectside].wall_num;
697
698                 if (Walls[lower_wallnum].linked_wall != -1)
699                         Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1;
700                 if (Walls[lower_wallnum+1].linked_wall != -1)
701                         Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1;
702
703                 for (w=lower_wallnum;w<Num_walls-2;w++)
704                         Walls[w] = Walls[w+2];
705
706                 Num_walls -= 2;
707
708                 for (s=0;s<=Highest_segment_index;s++)
709                         if (Segments[s].segnum != -1)
710                         for (w=0;w<MAX_SIDES_PER_SEGMENT;w++)
711                                 if      (Segments[s].sides[w].wall_num > lower_wallnum+1)
712                                         Segments[s].sides[w].wall_num -= 2;
713
714                 // Destroy any links to the deleted wall.
715                 for (t=0;t<Num_triggers;t++)
716                         for (l=0;l<Triggers[t].num_links;l++)
717                                 if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) {
718                                         for (t1=0;t1<Triggers[t].num_links-1;t1++) {
719                                                 Triggers[t].seg[t1] = Triggers[t].seg[t1+1];
720                                                 Triggers[t].side[t1] = Triggers[t].side[t1+1];
721                                         }
722                                         Triggers[t].num_links--;        
723                                 }
724
725                 // Destroy control center links as well.
726                 for (l=0;l<ControlCenterTriggers.num_links;l++)
727                         if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) {
728                                 for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) {
729                                         ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1];
730                                         ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1];
731                                 }
732                                 ControlCenterTriggers.num_links--;      
733                         }
734
735                 seg->sides[side].wall_num = -1;
736                 csegp->sides[Connectside].wall_num = -1;
737
738                 Update_flags |= UF_WORLD_CHANGED;
739                 return 1;
740         }
741
742         editor_status( "Can't remove wall.  No wall present.");
743         return 0;
744 }
745
746 //---------------------------------------------------------------------
747 //      Remove a special wall.
748 int wall_remove()
749 {
750         return wall_remove_side(Cursegp, Curside);
751 }
752
753 //---------------------------------------------------------------------
754 // Add a wall to curside
755 int wall_add_to_side(segment *segp, int side, sbyte type)
756 {
757         int connectside;
758         segment *csegp;
759
760         if (add_wall(segp, side)) {
761                 csegp = &Segments[segp->children[side]];
762                 connectside = find_connect_side(segp, csegp);
763
764                 Walls[segp->sides[side].wall_num].segnum = segp-Segments;
765                 Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments;
766
767                 Walls[segp->sides[side].wall_num].sidenum = side;
768                 Walls[csegp->sides[connectside].wall_num].sidenum = connectside;
769
770                 Walls[segp->sides[side].wall_num].flags = 0;
771                 Walls[csegp->sides[connectside].wall_num].flags = 0;
772
773                 Walls[segp->sides[side].wall_num].type = type;
774                 Walls[csegp->sides[connectside].wall_num].type = type;
775
776 //              Walls[segp->sides[side].wall_num].trigger = -1;
777 //              Walls[csegp->sides[connectside].wall_num].trigger = -1;
778
779                 Walls[segp->sides[side].wall_num].clip_num = -1;
780                 Walls[csegp->sides[connectside].wall_num].clip_num = -1;
781
782                 Walls[segp->sides[side].wall_num].keys = KEY_NONE;
783                 Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE;
784
785                 if (type == WALL_BLASTABLE) {
786                         Walls[segp->sides[side].wall_num].hps = WALL_HPS;
787                         Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS;
788                         
789                         //Walls[segp->sides[side].wall_num].clip_num = 0;
790                         //Walls[csegp->sides[connectside].wall_num].clip_num = 0;
791                         }       
792
793                 if (type != WALL_DOOR) {
794                         segp->sides[side].tmap_num2 = 0;
795                         csegp->sides[connectside].tmap_num2 = 0;
796                         }
797
798                 if (type == WALL_DOOR) {
799                         Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO;
800                         Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO;
801
802                         Walls[segp->sides[side].wall_num].clip_num = Current_door_type;
803                         Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type;
804                 }
805
806                 //Update_flags |= UF_WORLD_CHANGED;
807                 //return 1;
808
809 //              return NextWall();              //assign a clip num
810                 return wall_assign_door(Current_door_type);
811
812         } else {
813                 editor_status( "Cannot add wall here, no children" );
814                 return 0;
815         }
816 }
817
818
819 //---------------------------------------------------------------------
820 // Add a wall to markedside
821 int wall_add_to_markedside(sbyte type)
822 {
823         int Connectside;
824         segment *csegp;
825
826         if (add_wall(Markedsegp, Markedside)) {
827                 int     wall_num, cwall_num;
828                 csegp = &Segments[Markedsegp->children[Markedside]];
829
830                 Connectside = find_connect_side(Markedsegp, csegp);
831
832                 wall_num = Markedsegp->sides[Markedside].wall_num;
833                 cwall_num = csegp->sides[Connectside].wall_num;
834
835                 Walls[wall_num].segnum = Markedsegp-Segments;
836                 Walls[cwall_num].segnum = csegp-Segments;
837
838                 Walls[wall_num].sidenum = Markedside;
839                 Walls[cwall_num].sidenum = Connectside;
840
841                 Walls[wall_num].flags = 0;
842                 Walls[cwall_num].flags = 0;
843
844                 Walls[wall_num].type = type;
845                 Walls[cwall_num].type = type;
846
847                 Walls[wall_num].trigger = -1;
848                 Walls[cwall_num].trigger = -1;
849
850                 Walls[wall_num].clip_num = -1;
851                 Walls[cwall_num].clip_num = -1;
852
853                 Walls[wall_num].keys = KEY_NONE;
854                 Walls[cwall_num].keys = KEY_NONE;
855
856                 if (type == WALL_BLASTABLE) {
857                         Walls[wall_num].hps = WALL_HPS;
858                         Walls[cwall_num].hps = WALL_HPS;
859                         
860                         Walls[wall_num].clip_num = 0;
861                         Walls[cwall_num].clip_num = 0;
862                         }       
863
864                 if (type != WALL_DOOR) {
865                         Markedsegp->sides[Markedside].tmap_num2 = 0;
866                         csegp->sides[Connectside].tmap_num2 = 0;
867                         }
868
869                 Update_flags |= UF_WORLD_CHANGED;
870                 return 1;
871         } else {
872                 editor_status( "Cannot add wall here, no children" );
873                 return 0;
874         }
875 }
876
877
878 int wall_add_door_flag(sbyte flag)
879 {
880         int Connectside;
881         segment *csegp;
882
883         if (Cursegp->sides[Curside].wall_num == -1)
884                 {
885                 editor_status("Cannot change flag. No wall at Curside.");
886                 return 0;
887                 }
888
889         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
890                 {
891                 editor_status("Cannot change flag. No door at Curside.");
892                 return 0;
893                 }
894
895         csegp = &Segments[Cursegp->children[Curside]];
896         Connectside = find_connect_side(Cursegp, csegp);
897
898         Walls[Cursegp->sides[Curside].wall_num].flags |= flag;
899         Walls[csegp->sides[Connectside].wall_num].flags |= flag;
900
901         Update_flags |= UF_ED_STATE_CHANGED;
902         return 1;
903 }
904
905 int wall_remove_door_flag(sbyte flag)
906 {
907         int Connectside;
908         segment *csegp;
909
910         if (Cursegp->sides[Curside].wall_num == -1)
911                 {
912                 editor_status("Cannot change flag. No wall at Curside.");
913                 return 0;
914                 }
915
916         if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR)
917                 {
918                 editor_status("Cannot change flag. No door at Curside.");
919                 return 0;
920                 }
921
922         csegp = &Segments[Cursegp->children[Curside]];
923         Connectside = find_connect_side(Cursegp, csegp);
924
925         Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag;
926         Walls[csegp->sides[Connectside].wall_num].flags &= ~flag;
927
928         Update_flags |= UF_ED_STATE_CHANGED;
929         return 1;
930 }
931
932
933 int bind_wall_to_control_center() {
934
935         int link_num;
936         int i;
937
938         if (Cursegp->sides[Curside].wall_num == -1) {
939                 editor_status("No wall at Curside.");
940                 return 0;
941         }
942
943         link_num = ControlCenterTriggers.num_links;
944         for (i=0;i<link_num;i++)
945                 if ((Cursegp-Segments == ControlCenterTriggers.seg[i]) && (Curside == ControlCenterTriggers.side[i])) {
946                         editor_status("Curside already bound to Control Center.");
947                         return 0;
948                 }
949
950         // Error checking completed, actual binding begins
951         ControlCenterTriggers.seg[link_num] = Cursegp - Segments;
952         ControlCenterTriggers.side[link_num] = Curside;
953         ControlCenterTriggers.num_links++;
954
955         mprintf((0, "seg %d:side %d linked to control center link_num %d\n",
956                                 ControlCenterTriggers.seg[link_num], ControlCenterTriggers.side[link_num], link_num)); 
957
958         editor_status("Wall linked to control center");
959
960         return 1;
961 }
962
963 //link two doors, curseg/curside and markedseg/markedside
964 int wall_link_doors()
965 {
966         wall *w1=NULL,*w2=NULL;
967
968         if (Cursegp->sides[Curside].wall_num != -1)
969                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
970
971         if (Markedsegp->sides[Markedside].wall_num != -1)
972                 w2 = &Walls[Markedsegp->sides[Markedside].wall_num];
973
974         if (!w1 || w1->type != WALL_DOOR) {
975                 editor_status("Curseg/curside is not a door");
976                 return 0;
977         }
978
979         if (!w2 || w2->type != WALL_DOOR) {
980                 editor_status("Markedseg/markedside is not a door");
981                 return 0;
982         }
983
984         if (w1->linked_wall != -1)
985                 editor_status("Curseg/curside is already linked");
986
987         if (w2->linked_wall != -1)
988                 editor_status("Markedseg/markedside is already linked");
989
990         w1->linked_wall = w2-Walls;
991         w2->linked_wall = w1-Walls;
992
993         return 1;
994 }
995
996 int wall_unlink_door()
997 {
998         wall *w1=NULL;
999
1000         if (Cursegp->sides[Curside].wall_num != -1)
1001                 w1 = &Walls[Cursegp->sides[Curside].wall_num];
1002
1003         if (!w1 || w1->type != WALL_DOOR) {
1004                 editor_status("Curseg/curside is not a door");
1005                 return 0;
1006         }
1007
1008         if (w1->linked_wall == -1)
1009                 editor_status("Curseg/curside is not linked");
1010
1011         Assert(Walls[w1->linked_wall].linked_wall == w1-Walls);
1012
1013         Walls[w1->linked_wall].linked_wall = -1;
1014         w1->linked_wall = -1;
1015
1016         return 1;
1017
1018 }
1019
1020 #define DIAGNOSTIC_MESSAGE_MAX                          150
1021
1022 int check_walls() 
1023 {
1024         int w, seg, side, wall_count, trigger_count;
1025         int w1, w2, t, l;
1026         count_wall CountedWalls[MAX_WALLS];
1027         char Message[DIAGNOSTIC_MESSAGE_MAX];
1028         int matcen_num;
1029
1030         wall_count = 0;
1031         for (seg=0;seg<=Highest_segment_index;seg++) 
1032                 if (Segments[seg].segnum != -1) {
1033                         // Check fuelcenters
1034                         matcen_num = Segment2s[seg].matcen_num;
1035                         if (matcen_num == 0)
1036                                 if (RobotCenters[0].segnum != seg) {
1037                                         mprintf((0,"Fixing Matcen 0\n"));
1038                                         Segment2s[seg].matcen_num = -1;
1039                                 }
1040         
1041                         if (matcen_num > -1)
1042                                 if (RobotCenters[matcen_num].segnum != seg) {
1043                                         mprintf((0,"Matcen [%d] (seg %d) doesn't point back to correct segment %d\n", matcen_num, RobotCenters[matcen_num].segnum, seg));
1044                                         mprintf((0,"Fixing....\n"));
1045                                         RobotCenters[matcen_num].segnum = seg;
1046                                 }
1047         
1048                         for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1049                                 if (Segments[seg].sides[side].wall_num != -1) {
1050                                         CountedWalls[wall_count].wallnum = Segments[seg].sides[side].wall_num;
1051                                         CountedWalls[wall_count].segnum = seg;
1052                                         CountedWalls[wall_count].sidenum = side;
1053         
1054                                         // Check if segnum is bogus
1055                                         if (Walls[Segments[seg].sides[side].wall_num].segnum == -1) {
1056                                                 mprintf((0, "Wall %d at seg:side %d:%d is BOGUS\n", Segments[seg].sides[side].wall_num, seg, side));
1057                                         }
1058         
1059                                         if (Walls[Segments[seg].sides[side].wall_num].type == WALL_NORMAL) {
1060                                                 mprintf((0, "Wall %d at seg:side %d:%d is NORMAL (BAD)\n", Segments[seg].sides[side].wall_num, seg, side));
1061                                         }
1062         
1063                                         wall_count++;
1064                                 }
1065                 }
1066
1067         mprintf((0,"Wall Count = %d\n", wall_count));
1068         
1069         if (wall_count != Num_walls) {
1070                 sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n");
1071                 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1072                         Num_walls = wall_count;
1073                         editor_status("Num_walls set to %d\n", Num_walls);
1074                 }
1075         }
1076
1077         // Check validity of Walls array.
1078         for (w=0; w<Num_walls; w++) {
1079                 if ((Walls[CountedWalls[w].wallnum].segnum != CountedWalls[w].segnum) ||
1080                         (Walls[CountedWalls[w].wallnum].sidenum != CountedWalls[w].sidenum)) {
1081                         mprintf((0,"Unmatched walls on wall_num %d\n", CountedWalls[w].wallnum));
1082                         sprintf( Message, "Unmatched wall detected\nDo you wish to correct it?\n");
1083                         if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1084                                 Walls[CountedWalls[w].wallnum].segnum = CountedWalls[w].segnum;
1085                                 Walls[CountedWalls[w].wallnum].sidenum = CountedWalls[w].sidenum;
1086                         }
1087                 }
1088
1089                 if (CountedWalls[w].wallnum >= Num_walls)
1090                         mprintf((0,"wallnum %d in Segments exceeds Num_walls!\n", CountedWalls[w].wallnum));
1091
1092                 if (Walls[w].segnum == -1) {
1093                         mprintf((0, "Wall[%d] is BOGUS\n", w));
1094                         for (seg=0;seg<=Highest_segment_index;seg++) 
1095                                 for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1096                                         if (Segments[seg].sides[side].wall_num == w) {
1097                                                 mprintf((0, " BOGUS WALL found at seg:side %d:%d\n", seg, side));
1098                                         } 
1099                 }                               
1100         }
1101
1102         trigger_count = 0;
1103         for (w1=0; w1<wall_count; w1++) {
1104                 for (w2=w1+1; w2<wall_count; w2++) 
1105                         if (CountedWalls[w1].wallnum == CountedWalls[w2].wallnum) {
1106                                 mprintf((0, "Duplicate Walls %d and %d. Wallnum=%d. ", w1, w2, CountedWalls[w1].wallnum));
1107                                 mprintf((0, "Seg1:sides1 %d:%d  ", CountedWalls[w1].segnum, CountedWalls[w1].sidenum));
1108                                 mprintf((0, "Seg2:sides2 %d:%d\n", CountedWalls[w2].segnum, CountedWalls[w2].sidenum));
1109                         }
1110                 if (Walls[w1].trigger != -1) trigger_count++;
1111         }
1112
1113         if (trigger_count != Num_triggers) {
1114                 sprintf( Message, "Num_triggers is bogus\nDo you wish to correct it?\n");
1115                 if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
1116                         Num_triggers = trigger_count;
1117                         editor_status("Num_triggers set to %d\n", Num_triggers);
1118                 }
1119         }
1120
1121         mprintf((0,"Trigger Count = %d\n", trigger_count));
1122
1123         for (t=0; t<trigger_count; t++) {
1124                 if (Triggers[t].flags & TRIGGER_MATCEN)
1125                  {
1126                         if (Triggers[t].num_links < 1) 
1127                                 mprintf((0,"No valid links on Matcen Trigger %d\n", t));
1128                         else
1129                                 for (l=0;l<Triggers[t].num_links;l++) {
1130                                         if (!Segment2s[Triggers[t].seg[l]].special & SEGMENT_IS_ROBOTMAKER)
1131                                                 mprintf((0,"Bogus Matcen trigger detected on Trigger %d, No matcen at seg %d\n", t, Triggers[t].seg[l]));
1132                                 }
1133                  }
1134
1135                 if (Triggers[t].flags & TRIGGER_EXIT)
1136                         if (Triggers[t].num_links != 0)
1137                                 mprintf((0,"Bogus links detected on Exit Trigger %d\n", t));
1138
1139                 if (Triggers[t].flags & TRIGGER_CONTROL_DOORS)
1140                         for (l=0;l<Triggers[t].num_links;l++) {
1141                                 if (Segments[Triggers[t].seg[l]].sides[Triggers[t].side[l]].wall_num == -1) {
1142                                         mprintf((0,"Bogus Link detected on Door Control Trigger %d, link %d\n", t, l));
1143                                         mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1144                                 }
1145                         }
1146         }
1147
1148         for (l=0;l<ControlCenterTriggers.num_links;l++)
1149                 if (Segments[ControlCenterTriggers.seg[l]].sides[ControlCenterTriggers.side[l]].wall_num == -1) {
1150                         mprintf((0,"Bogus Link detected on Control Center Trigger, link %d\n", l));
1151                         mprintf((0,"Bogus Link at seg %d, side %d\n", Triggers[t].seg[l], Triggers[t].side[l]));
1152                 }
1153
1154         return 1;
1155
1156 }
1157
1158
1159 int delete_all_walls() 
1160 {
1161         char Message[DIAGNOSTIC_MESSAGE_MAX];
1162         int seg, side;
1163
1164         sprintf( Message, "Are you sure that walls are hosed so\n badly that you want them ALL GONE!?\n");
1165         if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1166                 for (seg=0;seg<=Highest_segment_index;seg++)
1167                         for (side=0;side<MAX_SIDES_PER_SEGMENT;side++)
1168                                 Segments[seg].sides[side].wall_num = -1;
1169                 Num_walls=0;
1170                 Num_triggers=0;
1171
1172                 return 1;
1173         }
1174
1175         return 0;
1176 }
1177
1178 int delete_all_triggers()
1179 {
1180         char Message[DIAGNOSTIC_MESSAGE_MAX];
1181         int w;
1182
1183         sprintf( Message, "Are you sure that triggers are hosed so\n badly that you want them ALL GONE!?\n");
1184         if (MessageBox( -2, -2, 2, Message, "YES!", "No" )==1) {
1185
1186                 for (w=0; w<Num_walls; w++)
1187                         Walls[w].trigger=-1;
1188                 Num_triggers=0;
1189
1190                 return 1;
1191         }
1192
1193         return 0;
1194 }
1195
1196 int dump_walls_info() 
1197 {
1198         int w; 
1199         FILE *fp;
1200
1201         fp = fopen("WALL.OUT", "wt");
1202
1203         fprintf(fp, "Num_walls %d\n", Num_walls);
1204
1205         for (w=0; w<Num_walls; w++) {
1206
1207                 fprintf(fp, "WALL #%d\n", w);
1208                 fprintf(fp, "  seg: %d\n", Walls[w].segnum);
1209                 fprintf(fp, "  sidenum: %d\n", Walls[w].sidenum);
1210         
1211                 switch (Walls[w].type) {
1212                         case WALL_NORMAL:
1213                                 fprintf(fp, "  type: NORMAL\n");
1214                                 break;
1215                         case WALL_BLASTABLE:
1216                                 fprintf(fp, "  type: BLASTABLE\n");
1217                                 break;
1218                         case WALL_DOOR:
1219                                 fprintf(fp, "  type: DOOR\n");
1220                                 break;
1221                         case WALL_ILLUSION:
1222                                 fprintf(fp, "  type: ILLUSION\n");
1223                                 break;
1224                         case WALL_OPEN:
1225                                 fprintf(fp, "  type: OPEN\n");
1226                                 break;
1227                         case WALL_CLOSED:
1228                                 fprintf(fp, "  type: CLOSED\n");
1229                                 break;
1230                         default:
1231                                 fprintf(fp, "  type: ILLEGAL!!!!! <-----------------\n");
1232                                 break;
1233                 }
1234         
1235                 fprintf(fp, "  flags:\n");
1236
1237                 if (Walls[w].flags & WALL_BLASTED)
1238                         fprintf(fp, "   BLASTED\n");
1239                 if (Walls[w].flags & WALL_DOOR_OPENED)
1240                         fprintf(fp, "   DOOR_OPENED <----------------- BAD!!!\n");
1241                 if (Walls[w].flags & WALL_DOOR_OPENING)
1242                         fprintf(fp, "   DOOR_OPENING <---------------- BAD!!!\n");
1243                 if (Walls[w].flags & WALL_DOOR_LOCKED)
1244                         fprintf(fp, "   DOOR_LOCKED\n");
1245                 if (Walls[w].flags & WALL_DOOR_AUTO)
1246                         fprintf(fp, "   DOOR_AUTO\n");
1247                 if (Walls[w].flags & WALL_ILLUSION_OFF)
1248                         fprintf(fp, "   ILLUSION_OFF <---------------- OUTDATED\n");
1249                 //if (Walls[w].flags & WALL_FUELCEN)
1250                 //      fprintf(fp, "   FUELCEN <--------------------- OUTDATED\n");
1251
1252                 fprintf(fp, "  trigger: %d\n", Walls[w].trigger);
1253                 fprintf(fp, "  clip_num: %d\n", Walls[w].clip_num);
1254
1255                 switch (Walls[w].keys) {
1256                         case KEY_NONE:
1257                                 fprintf(fp, "   key: NONE\n");
1258                                 break;
1259                         case KEY_BLUE:
1260                                 fprintf(fp, "   key: BLUE\n");
1261                                 break;
1262                         case KEY_RED:
1263                                 fprintf(fp, "   key: RED\n");
1264                                 break;
1265                         case KEY_GOLD:
1266                                 fprintf(fp, "   key: NONE\n");
1267                                 break;
1268                         default:
1269                                 fprintf(fp, "  key: ILLEGAL!!!!!! <-----------------\n");
1270                                 break;
1271                 }
1272
1273                 fprintf(fp, "  linked_wall %d\n", Walls[w].linked_wall);
1274         }
1275         
1276         fclose(fp);
1277         return 1;
1278 }
1279
1280 // ------------------------------------------------------------------------------------------------
1281 void copy_old_wall_data_to_new(int owall, int nwall)
1282 {
1283         Walls[nwall].flags = Walls[owall].flags;
1284         Walls[nwall].type = Walls[owall].type;
1285         Walls[nwall].clip_num = Walls[owall].clip_num;
1286         Walls[nwall].keys = Walls[owall].keys;
1287         Walls[nwall].hps = Walls[owall].hps;
1288         Walls[nwall].state = Walls[owall].state;
1289         Walls[nwall].linked_wall = -1;
1290
1291         Walls[nwall].trigger = -1;
1292
1293         if (Walls[owall].trigger != -1) {
1294                 editor_status("Warning: Trigger not copied in group copy.");
1295         }
1296 }
1297
1298 //typedef struct trigger {
1299 //      sbyte           type;
1300 //      short           flags;
1301 //      fix             value;
1302 //      fix             time;
1303 //      sbyte           link_num;
1304 //      short   num_links;
1305 //      short   seg[MAX_WALLS_PER_LINK];
1306 //      short           side[MAX_WALLS_PER_LINK];
1307 //      } trigger;
1308
1309
1310 // ------------------------------------------------------------------------------------------------
1311 void copy_group_walls(int old_group, int new_group)
1312 {
1313         int     i,j,old_seg, new_seg;
1314
1315         for (i=0; i<GroupList[old_group].num_segments; i++) {
1316                 old_seg = GroupList[old_group].segments[i];
1317                 new_seg = GroupList[new_group].segments[i];
1318
1319                 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1320                         if (Segments[old_seg].sides[j].wall_num != -1) {
1321                                 mprintf((0, "Going to add wall to seg:side = %i:%i\n", new_seg, j));
1322                                 Segments[new_seg].sides[j].wall_num = Num_walls;
1323                                 copy_old_wall_data_to_new(Segments[old_seg].sides[j].wall_num, Num_walls);
1324                                 Walls[Num_walls].segnum = new_seg;
1325                                 Walls[Num_walls].sidenum = j;
1326                                 Num_walls++;
1327                                 Assert(Num_walls < MAX_WALLS);
1328                         }
1329                 }
1330         }
1331 }
1332
1333 int     Validate_walls=1;
1334
1335 //      --------------------------------------------------------------------------------------------------------
1336 //      This function should be in medwall.c.
1337 //      Make sure all wall/segment connections are valid.
1338 void check_wall_validity(void)
1339 {
1340         int     i, j;
1341         int     segnum, sidenum, wall_num;
1342         sbyte   wall_flags[MAX_WALLS];
1343
1344         if (!Validate_walls)
1345                 return;
1346
1347         for (i=0; i<Num_walls; i++) {
1348                 segnum = Walls[i].segnum;
1349                 sidenum = Walls[i].sidenum;
1350
1351                 if (Segments[segnum].sides[sidenum].wall_num != i) {
1352                         if (!Validate_walls)
1353                                 return;
1354                         Int3();         //      Error! Your mine has been invalidated!
1355                                                         // Do not continue!  Do not save!
1356                                                         //      Remember your last action and Contact Mike!
1357                                                         //      To continue, set the variable Validate_walls to 1 by doing:
1358                                                         //              /Validate_walls = 1
1359                                                         //      Then do the usual /eip++;g
1360
1361                 }
1362         }
1363
1364         for (i=0; i<MAX_WALLS; i++)
1365                 wall_flags[i] = 0;
1366
1367         for (i=0; i<=Highest_segment_index; i++) {
1368                 if (Segments[i].segnum != -1)
1369                         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1370                                 // Check walls
1371                                 wall_num = Segments[i].sides[j].wall_num;
1372                                 if (wall_num != -1) {
1373                                         if (wall_flags[wall_num] != 0) {
1374                                                 if (!Validate_walls)
1375                                                         return;
1376                                                 Int3();         //      Error! Your mine has been invalidated!
1377                                                                                 // Do not continue!  Do not save!
1378                                                                                 //      Remember your last action and Contact Mike!
1379                                                                                 //      To continue, set the variable Validate_walls to 1 by doing:
1380                                                                                 //              /Validate_walls = 1
1381                                                                                 //      Then do the usual /eip++;g
1382                                         }
1383
1384                                         if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) {
1385                                                 if (!Validate_walls)
1386                                                         return;
1387                                                 Int3();         //      Error! Your mine has been invalidated!
1388                                                                                 // Do not continue!  Do not save!
1389                                                                                 //      Remember your last action and Contact Mike!
1390                                                                                 //      To continue, set the variable Validate_walls to 1 by doing:
1391                                                                                 //              /Validate_walls = 1
1392                                                                                 //      Then do the usual /eip++;g
1393                                         }
1394
1395                                         wall_flags[wall_num] = 1;
1396                                 }
1397                         }
1398
1399         }
1400 }
1401