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