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