]> icculus.org git repositories - btb/d2x.git/blob - main/editor/eswitch.c
include conf.h in new editor files
[btb/d2x.git] / main / editor / eswitch.c
1 /* $Id: eswitch.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  * Editor switch functions.
18  *
19  */
20
21 #ifdef RCS
22 static char rcsid[] = "$Id: eswitch.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 "inferno.h"
35 #include "editor.h"
36 #include "eswitch.h"
37 #include "segment.h"
38 #include "error.h"
39 #include "gameseg.h"
40 #include "mono.h"
41 #include "wall.h"
42 #include "medwall.h"
43
44 #include "screens.h"
45
46 #include "textures.h"
47 #include "texmerge.h"
48 #include "medrobot.h"
49 #include "timer.h"
50 #include "key.h"
51 #include "ehostage.h"
52 #include "centers.h"
53 #include "piggy.h"
54
55 //-------------------------------------------------------------------------
56 // Variables for this module...
57 //-------------------------------------------------------------------------
58 #define NUM_TRIGGER_FLAGS 10
59
60 static UI_WINDOW                                *MainWindow = NULL;
61 static UI_GADGET_USERBOX        *WallViewBox;
62 static UI_GADGET_BUTTON         *QuitButton;
63 static UI_GADGET_CHECKBOX       *TriggerFlag[NUM_TRIGGER_FLAGS];
64
65 static int old_trigger_num;
66
67 //-----------------------------------------------------------------
68 // Adds a trigger to wall, and returns the trigger number. 
69 // If there is a trigger already present, it returns the trigger number. (To be replaced)
70 int add_trigger(segment *seg, short side)
71 {
72         int trigger_num = Num_triggers;
73         int wall_num = seg->sides[side].wall_num;
74
75         Assert(trigger_num < MAX_TRIGGERS);
76         if (trigger_num>=MAX_TRIGGERS) return -1;
77
78         if (wall_num == -1) {
79                 wall_add_to_markedside(WALL_OPEN);
80                 wall_num = seg->sides[side].wall_num;
81                 Walls[wall_num].trigger = trigger_num;
82                 
83                 // Set default values first time trigger is added
84                 Triggers[trigger_num].flags = 0;
85                 Triggers[trigger_num].value = F1_0*5;
86                 Triggers[trigger_num].num_links = 0;
87                 Triggers[trigger_num].flags &= TRIGGER_ON;              
88
89                 Num_triggers++;
90                 return trigger_num;
91         } else {
92                 if (Walls[wall_num].trigger != -1)
93                         return Walls[wall_num].trigger;
94
95                 // Create new trigger.
96                 Walls[wall_num].trigger = trigger_num;
97
98                 // Set default values first time trigger is added
99                 Triggers[trigger_num].flags = 0;
100                 Triggers[trigger_num].value = F1_0*5;
101                 Triggers[trigger_num].num_links = 0;
102                 Triggers[trigger_num].flags &= TRIGGER_ON;
103
104                 Num_triggers++;
105                 return trigger_num;
106         }
107 }               
108
109 //-----------------------------------------------------------------
110 // Adds a specific trigger flag to Markedsegp/Markedside if it is possible.
111 // Automatically adds flag to Connectside if possible unless it is a control trigger.
112 // Returns 1 if trigger flag added.
113 // Returns 0 if trigger flag cannot be added.
114 int trigger_add_to_Markedside(short flag) {
115         int trigger_num; //, ctrigger_num;
116
117         if (!Markedsegp) {
118                 editor_status("No Markedside.");
119                 return 0;
120         }
121
122         // If no child on Markedside return
123         if (!IS_CHILD(Markedsegp->children[Markedside])) return 0;
124
125         trigger_num = add_trigger(Markedsegp, Markedside);
126
127         if (trigger_num == -1) {
128                 editor_status("Cannot add trigger at Markedside.");
129                 return 0;
130         }
131
132         Triggers[trigger_num].flags |= flag;
133
134         return 1;
135 }
136
137 int trigger_remove_flag_from_Markedside(short flag) {
138         int trigger_num; //, ctrigger_num;
139         int wall_num;
140         
141         if (!Markedsegp) {
142                 editor_status("No Markedside.");
143                 return 0;
144         }
145
146         // If no child on Markedside return
147         if (!IS_CHILD(Markedsegp->children[Markedside])) return 0;
148
149         // If no wall just return
150         wall_num = Markedsegp->sides[Markedside].wall_num;
151         if (wall_num == -1) return 0;
152
153         trigger_num = Walls[wall_num].trigger;
154
155         // If flag is already cleared, then don't change anything.
156         if ( trigger_num == -1 ) {
157                 editor_status("No trigger at Markedside.");
158                 return 0;
159         }
160
161         if (!Triggers[trigger_num].flags & flag)
162                 return 1;
163
164         Triggers[trigger_num].flags &= ~flag;
165
166         return 1;
167 }
168
169
170 int bind_matcen_to_trigger() {
171
172         int wall_num, trigger_num, link_num;
173         int i;
174
175         if (!Markedsegp) {
176                 editor_status("No marked segment.");
177                 return 0;
178         }
179
180         wall_num = Markedsegp->sides[Markedside].wall_num;
181         if (wall_num == -1) {
182                 editor_status("No wall at Markedside.");
183                 return 0;
184         }
185
186         trigger_num = Walls[wall_num].trigger;  
187
188         if (trigger_num == -1) {
189                 editor_status("No trigger at Markedside.");
190                 return 0;
191         }
192
193         if (!(Cursegp->special & SEGMENT_IS_ROBOTMAKER)) {
194                 editor_status("No Matcen at Cursegp.");
195                 return 0;
196         }
197
198         link_num = Triggers[trigger_num].num_links;
199         for (i=0;i<link_num;i++)
200                 if (Cursegp-Segments == Triggers[trigger_num].seg[i]) {
201                         editor_status("Matcen already bound to Markedside.");
202                         return 0;
203                 }
204
205         // Error checking completed, actual binding begins
206         Triggers[trigger_num].seg[link_num] = Cursegp - Segments;
207         Triggers[trigger_num].num_links++;
208
209         mprintf((0, "seg %d linked to link_num %d\n",
210                                 Triggers[trigger_num].seg[link_num], link_num)); 
211
212         editor_status("Matcen linked to trigger");
213
214         return 1;
215 }
216
217
218 int bind_wall_to_trigger() {
219
220         int wall_num, trigger_num, link_num;
221         int i;
222
223         if (!Markedsegp) {
224                 editor_status("No marked segment.");
225                 return 0;
226         }
227
228         wall_num = Markedsegp->sides[Markedside].wall_num;
229         if (wall_num == -1) {
230                 editor_status("No wall at Markedside.");
231                 return 0;
232         }
233
234         trigger_num = Walls[wall_num].trigger;  
235
236         if (trigger_num == -1) {
237                 editor_status("No trigger at Markedside.");
238                 return 0;
239         }
240
241         if (Cursegp->sides[Curside].wall_num == -1) {
242                 editor_status("No wall at Curside.");
243                 return 0;
244         }
245
246         if ((Cursegp==Markedsegp) && (Curside==Markedside)) {
247                 editor_status("Cannot bind wall to itself.");
248                 return 0;
249         }
250
251         link_num = Triggers[trigger_num].num_links;
252         for (i=0;i<link_num;i++)
253                 if ((Cursegp-Segments == Triggers[trigger_num].seg[i]) && (Curside == Triggers[trigger_num].side[i])) {
254                         editor_status("Curside already bound to Markedside.");
255                         return 0;
256                 }
257
258         // Error checking completed, actual binding begins
259         Triggers[trigger_num].seg[link_num] = Cursegp - Segments;
260         Triggers[trigger_num].side[link_num] = Curside;
261         Triggers[trigger_num].num_links++;
262
263         mprintf((0, "seg %d:side %d linked to link_num %d\n",
264                                 Triggers[trigger_num].seg[link_num], Triggers[trigger_num].side[link_num], link_num)); 
265
266         editor_status("Wall linked to trigger");
267
268         return 1;
269 }
270
271 int remove_trigger(segment *seg, short side)
272 {       
273         int trigger_num, t, w;
274
275         if (seg->sides[side].wall_num == -1) {
276                 mprintf((0, "Can't remove trigger from wall_num -1\n"));        
277                 return 0;
278         }
279
280         trigger_num = Walls[seg->sides[side].wall_num].trigger;
281
282         if (trigger_num != -1) {
283                 Walls[seg->sides[side].wall_num].trigger = -1;
284                 for (t=trigger_num;t<Num_triggers-1;t++)
285                         Triggers[t] = Triggers[t+1];
286         
287                 for (w=0; w<Num_walls; w++) {
288                         if (Walls[w].trigger > trigger_num) 
289                                 Walls[w].trigger--;
290                 }
291
292                 Num_triggers--;
293                 for (t=0;t<Num_walls;t++)
294                         if (Walls[seg->sides[side].wall_num].trigger > trigger_num)
295                                 Walls[seg->sides[side].wall_num].trigger--;
296                 
297                 return 1;
298         }
299
300         editor_status("No trigger to remove");
301         return 0;
302 }
303
304
305 int add_trigger_control()
306 {
307         trigger_add_to_Markedside(TRIGGER_CONTROL_DOORS);
308         Update_flags = UF_WORLD_CHANGED;
309         return 1;
310 }
311
312 int trigger_remove()
313 {
314         remove_trigger(Markedsegp, Markedside);
315         Update_flags = UF_WORLD_CHANGED;
316         return 1;
317 }
318
319 int trigger_turn_all_ON()
320 {
321         int t;
322
323         for (t=0;t<Num_triggers;t++)
324                 Triggers[t].flags &= TRIGGER_ON;
325         return 1;
326 }
327
328 //-------------------------------------------------------------------------
329 // Called from the editor... does one instance of the trigger dialog box
330 //-------------------------------------------------------------------------
331 int do_trigger_dialog()
332 {
333         int i;
334
335         if (!Markedsegp) {
336                 editor_status("Trigger requires Marked Segment & Side.");
337                 return 0;
338         }
339
340         // Only open 1 instance of this window...
341         if ( MainWindow != NULL ) return 0;
342
343         // Close other windows. 
344         robot_close_window();
345         close_wall_window();
346         close_centers_window();
347         hostage_close_window();
348
349         // Open a window with a quit button
350         MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
351
352         // These are the checkboxes for each door flag.
353         i = 44;
354         TriggerFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Door Control" );        i+=22;
355         TriggerFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Shield damage" );       i+=22;
356         TriggerFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Energy drain" );                i+=22;
357         TriggerFlag[3] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Exit" );                                        i+=22;
358         TriggerFlag[4] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "One-shot" );                    i+=22;
359         TriggerFlag[5] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion ON" );         i+=22;
360         TriggerFlag[6] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" );                i+=22;
361         TriggerFlag[7] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Trigger ON" );                  i+=22;
362         TriggerFlag[8] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Matcen Trigger" );      i+=22;
363         TriggerFlag[9] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Secret Exit" );                 i+=22;
364
365         QuitButton = ui_add_gadget_button( MainWindow, 20, i, 48, 40, "Done", NULL );
366                                                                                                                                                                  
367         // The little box the wall will appear in.
368         WallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 );
369
370         // A bunch of buttons...
371         i = 80;
372 //      ui_add_gadget_button( MainWindow,155,i,140, 26, "Add Door Control", add_trigger_control ); i += 29;
373         ui_add_gadget_button( MainWindow,155,i,140, 26, "Remove Trigger", trigger_remove ); i += 29;
374         ui_add_gadget_button( MainWindow,155,i,140, 26, "Bind Wall", bind_wall_to_trigger ); i += 29;
375         ui_add_gadget_button( MainWindow,155,i,140, 26, "Bind Matcen", bind_matcen_to_trigger ); i += 29;
376         ui_add_gadget_button( MainWindow,155,i,140, 26, "All Triggers ON", trigger_turn_all_ON ); i += 29;
377
378         old_trigger_num = -2;           // Set to some dummy value so everything works ok on the first frame.
379
380         return 1;
381 }
382
383 void close_trigger_window()
384 {
385         if ( MainWindow!=NULL ) {
386                 ui_close_window( MainWindow );
387                 MainWindow = NULL;
388         }
389 }
390
391 void do_trigger_window()
392 {
393         int i;
394         short Markedwall, trigger_num;
395
396         if ( MainWindow == NULL ) return;
397         if (!Markedsegp) {
398                 close_trigger_window();
399                 return;
400         }
401
402         //------------------------------------------------------------
403         // Call the ui code..
404         //------------------------------------------------------------
405         ui_button_any_drawn = 0;
406         ui_window_do_gadgets(MainWindow);
407         
408         //------------------------------------------------------------
409         // If we change walls, we need to reset the ui code for all
410         // of the checkboxes that control the wall flags.  
411         //------------------------------------------------------------
412         Markedwall = Markedsegp->sides[Markedside].wall_num;
413         if (Markedwall != -1)
414                 trigger_num = Walls[Markedwall].trigger;
415         else trigger_num = -1;
416
417         if (old_trigger_num != trigger_num ) {
418                 for (   i=0; i < NUM_TRIGGER_FLAGS; i++ )       {
419                         TriggerFlag[i]->flag = 0;                               // Tells ui that this button isn't checked
420                         TriggerFlag[i]->status = 1;                             // Tells ui to redraw button
421                 }
422
423                 if (trigger_num != -1) {
424                         if (Triggers[trigger_num].flags & TRIGGER_CONTROL_DOORS)
425                                 TriggerFlag[0]->flag = 1;
426                         if (Triggers[trigger_num].flags & TRIGGER_SHIELD_DAMAGE)
427                                 TriggerFlag[1]->flag = 1;
428                         if (Triggers[trigger_num].flags & TRIGGER_ENERGY_DRAIN)
429                                 TriggerFlag[2]->flag = 1;
430                         if (Triggers[trigger_num].flags & TRIGGER_EXIT)
431                                 TriggerFlag[3]->flag = 1;
432                         if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT)
433                                 TriggerFlag[4]->flag = 1;
434                         if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_ON)
435                                 TriggerFlag[5]->flag = 1;
436                         if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_OFF)
437                                 TriggerFlag[6]->flag = 1;
438                         if (Triggers[trigger_num].flags & TRIGGER_ON)
439                                 TriggerFlag[7]->flag = 1;
440                         if (Triggers[trigger_num].flags & TRIGGER_MATCEN)
441                                 TriggerFlag[8]->flag = 1;
442                         if (Triggers[trigger_num].flags & TRIGGER_SECRET_EXIT)
443                                 TriggerFlag[9]->flag = 1;
444                 }
445         }
446         
447         //------------------------------------------------------------
448         // If any of the checkboxes that control the wallflags are set, then
449         // update the cooresponding wall flag.
450         //------------------------------------------------------------
451         if (IS_CHILD(Markedsegp->children[Markedside])) {
452                 if (TriggerFlag[0]->flag == 1) 
453                         trigger_add_to_Markedside(TRIGGER_CONTROL_DOORS); 
454                 else
455                         trigger_remove_flag_from_Markedside(TRIGGER_CONTROL_DOORS);
456                 if (TriggerFlag[1]->flag == 1)
457                         trigger_add_to_Markedside(TRIGGER_SHIELD_DAMAGE); 
458                 else
459                         trigger_remove_flag_from_Markedside(TRIGGER_SHIELD_DAMAGE);
460                 if (TriggerFlag[2]->flag == 1)
461                         trigger_add_to_Markedside(TRIGGER_ENERGY_DRAIN); 
462                 else
463                         trigger_remove_flag_from_Markedside(TRIGGER_ENERGY_DRAIN);
464                 if (TriggerFlag[3]->flag == 1)
465                         trigger_add_to_Markedside(TRIGGER_EXIT); 
466                 else
467                         trigger_remove_flag_from_Markedside(TRIGGER_EXIT);
468                 if (TriggerFlag[4]->flag == 1)
469                         trigger_add_to_Markedside(TRIGGER_ONE_SHOT); 
470                 else
471                         trigger_remove_flag_from_Markedside(TRIGGER_ONE_SHOT);
472                 if (TriggerFlag[5]->flag == 1)
473                         trigger_add_to_Markedside(TRIGGER_ILLUSION_ON); 
474                 else
475                         trigger_remove_flag_from_Markedside(TRIGGER_ILLUSION_ON);
476                 if (TriggerFlag[6]->flag == 1)
477                         trigger_add_to_Markedside(TRIGGER_ILLUSION_OFF);
478                 else
479                         trigger_remove_flag_from_Markedside(TRIGGER_ILLUSION_OFF);
480                 if (TriggerFlag[7]->flag == 1)
481                         trigger_add_to_Markedside(TRIGGER_ON);
482                 else
483                         trigger_remove_flag_from_Markedside(TRIGGER_ON);
484
485                 if (TriggerFlag[8]->flag == 1) 
486                         trigger_add_to_Markedside(TRIGGER_MATCEN);
487                 else
488                         trigger_remove_flag_from_Markedside(TRIGGER_MATCEN);
489
490                 if (TriggerFlag[9]->flag == 1) 
491                         trigger_add_to_Markedside(TRIGGER_SECRET_EXIT);
492                 else
493                         trigger_remove_flag_from_Markedside(TRIGGER_SECRET_EXIT);
494
495         } else
496                 for (   i=0; i < NUM_TRIGGER_FLAGS; i++ )
497                         if (TriggerFlag[i]->flag == 1) { 
498                                 TriggerFlag[i]->flag = 0;                                       // Tells ui that this button isn't checked
499                                 TriggerFlag[i]->status = 1;                             // Tells ui to redraw button
500                         }
501         
502         //------------------------------------------------------------
503         // Draw the wall in the little 64x64 box
504         //------------------------------------------------------------
505         gr_set_current_canvas( WallViewBox->canvas );
506
507         if ((Markedsegp->sides[Markedside].wall_num == -1) || (Walls[Markedsegp->sides[Markedside].wall_num].trigger) == -1)
508                 gr_clear_canvas( CBLACK );
509         else {
510                 if (Markedsegp->sides[Markedside].tmap_num2 > 0)  {
511                         gr_ubitmap(0,0, texmerge_get_cached_bitmap( Markedsegp->sides[Markedside].tmap_num, Markedsegp->sides[Markedside].tmap_num2));
512                 } else {
513                         if (Markedsegp->sides[Markedside].tmap_num > 0) {
514                                 PIGGY_PAGE_IN(Textures[Markedsegp->sides[Markedside].tmap_num]);
515                                 gr_ubitmap(0,0, &GameBitmaps[Textures[Markedsegp->sides[Markedside].tmap_num].index]);
516                         } else
517                                 gr_clear_canvas( CGREY );
518                 }
519         }
520
521         //------------------------------------------------------------
522         // If anything changes in the ui system, redraw all the text that
523         // identifies this robot.
524         //------------------------------------------------------------
525         if (ui_button_any_drawn || (old_trigger_num != trigger_num) ) {
526                 if ( Markedsegp->sides[Markedside].wall_num > -1 )      {
527                         ui_wprintf_at( MainWindow, 12, 6, "Trigger: %d    ", trigger_num);
528                 }       else {
529                         ui_wprintf_at( MainWindow, 12, 6, "Trigger: none ");
530                 }
531                 Update_flags |= UF_WORLD_CHANGED;
532         }
533
534         if ( QuitButton->pressed || (last_keypress==KEY_ESC))   {
535                 close_trigger_window();
536                 return;
537         }               
538
539         old_trigger_num = trigger_num;
540 }
541
542
543
544
545