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