09e2cd78eedff7bf08b6012d3d13be4b09016147
[btb/d2x.git] / main / editor / medrobot.c
1 /* $Id: medrobot.c,v 1.5 2005-01-24 22:26:06 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Dialog box to edit robot properties.
18  *
19  */
20
21 #ifdef RCS
22 static char rcsid[] = "$Id: medrobot.c,v 1.5 2005-01-24 22:26:06 schaffner Exp $";
23 #endif
24
25 #ifdef HAVE_CONFIG_H
26 #include "conf.h"
27 #endif
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #ifdef __MSDOS__
32 #include <conio.h>
33 #include <direct.h>
34 #include <dos.h>
35 #endif
36 #include <math.h>
37 #include <string.h>
38
39 #include "screens.h"
40 #include "inferno.h"
41 #include "segment.h"
42 #include "editor.h"
43
44 #include "timer.h"
45 #include "objpage.h"
46 #include "fix.h"
47 #include "mono.h"
48 #include "error.h"
49 #include "kdefs.h"
50 #include        "object.h"
51 #include "polyobj.h"
52 #include "game.h"
53 #include "powerup.h"
54 #include "ai.h"
55 #include "hostage.h"
56 #include "eobject.h"
57 #include "medwall.h"
58 #include "eswitch.h"
59 #include "ehostage.h"
60 #include "key.h"
61 #include "centers.h"
62 #include "bm.h"
63
64 #define NUM_BOXES               6                       //      Number of boxes, AI modes
65
66 int GoodyNextID();
67 int GoodyPrevID();
68 void robot_close_window();
69 //-------------------------------------------------------------------------
70 // Variables for this module...
71 //-------------------------------------------------------------------------
72 static UI_WINDOW                                *MainWindow = NULL;
73 static UI_GADGET_USERBOX        *RobotViewBox;
74 static UI_GADGET_USERBOX        *ContainsViewBox;
75 static UI_GADGET_BUTTON         *QuitButton;
76 static UI_GADGET_RADIO          *InitialMode[NUM_BOXES];
77
78 static int old_object;
79 static fix Time;
80 static vms_angvec angles={0,0,0}, goody_angles={0,0,0};
81
82 //-------------------------------------------------------------------------
83 // Given a pointer to an object, returns a number that cooresponds to the
84 // object id as used in the objpage stuff.
85 //-------------------------------------------------------------------------
86 int get_object_id( object * obj )
87 {
88         int i;
89         int goal_type;
90
91         switch( obj->type )     {
92         case OBJ_PLAYER: goal_type=OL_PLAYER; break;
93         case OBJ_ROBOT: goal_type=OL_ROBOT; break;
94         case OBJ_POWERUP: goal_type=OL_POWERUP; break;
95         case OBJ_CNTRLCEN: goal_type=OL_CONTROL_CENTER; break;
96         case OBJ_HOSTAGE: goal_type=OL_HOSTAGE; break;
97         case OBJ_CLUTTER: goal_type=OL_CLUTTER; break;
98         default:
99                 Int3(); // Invalid object type
100                 return -1;
101         }
102
103         // Find first object with the same type as this
104         // one and then add the object id to that to find
105         // the offset into the list.
106
107         for (i=0; i< Num_total_object_types; i++ )      {
108                 if ( ObjType[i]==goal_type)
109                         return obj->id + i;
110         }
111         return -1;
112 }
113
114 void call_init_ai_object(object *objp, int behavior)
115 {
116         int     hide_segment;
117
118         if (behavior == AIB_STATION)
119                 hide_segment = Cursegp-Segments;
120         else {
121                 if (Markedsegp != NULL)
122                         hide_segment = Markedsegp-Segments;
123                 else
124                         hide_segment = Cursegp-Segments;
125         }
126
127         mprintf((0, "Initializing AI object with hide segment = %i\n", hide_segment));
128         init_ai_object(objp-Objects, behavior, hide_segment);
129
130         if (behavior == AIB_STATION) {
131                 int     cseg, mseg;
132
133                 cseg = 0;
134                 mseg = 0;
135
136                 if (Cursegp != NULL)
137                         cseg = Cursegp-Segments;
138
139                 if (Markedsegp != NULL) {
140                         mseg = Markedsegp-Segments;
141                 }
142
143                 //objp->ctype.ai_info.follow_path_start_seg = Cursegp-Segments;
144                 //objp->ctype.ai_info.follow_path_end_seg = Markedsegp-Segments;
145         }
146 }
147
148 //-------------------------------------------------------------------------
149 // Called when user presses "Next Type" button.  This only works for polygon
150 // objects and it just selects the next polygon model for the current object.
151 //-------------------------------------------------------------------------
152 int RobotNextType()
153 {
154         if (Cur_object_index > -1 )     {
155                 if ( Objects[Cur_object_index].type == OBJ_ROBOT )      {
156                         object * obj = &Objects[Cur_object_index];
157                         obj->id++;
158                         if (obj->id >= N_robot_types )
159                                 obj->id = 0;
160
161                         //Set polygon-object-specific data
162                         obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
163                         obj->rtype.pobj_info.subobj_flags = 0;
164                         //set Physics info
165                         obj->mtype.phys_info.flags |= (PF_LEVELLING);
166                         obj->shields = Robot_info[obj->id].strength;
167                         call_init_ai_object(obj, AIB_NORMAL);
168
169                         Cur_robot_type = obj->id;
170                 }
171         }
172         Update_flags |= UF_WORLD_CHANGED;
173         return 1;
174 }
175
176 //-------------------------------------------------------------------------
177 // Called when user presses "Prev Type" button.  This only works for polygon
178 // objects and it just selects the prev polygon model for the current object.
179 //-------------------------------------------------------------------------
180 int RobotPrevType()
181 {
182         if (Cur_object_index > -1 )     {
183                 if ( Objects[Cur_object_index].type == OBJ_ROBOT )      {
184                         object * obj = &Objects[Cur_object_index];
185                         if (obj->id == 0 ) 
186                                 obj->id = N_robot_types-1;
187                         else
188                                 obj->id--;
189
190                         //Set polygon-object-specific data
191                         obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
192                         obj->rtype.pobj_info.subobj_flags = 0;
193                         //set Physics info
194                         obj->mtype.phys_info.flags |= (PF_LEVELLING);
195                         obj->shields = Robot_info[obj->id].strength;
196                         call_init_ai_object(obj, AIB_NORMAL);
197
198                         Cur_robot_type = obj->id;
199                 }
200         }
201         Update_flags |= UF_WORLD_CHANGED;
202         return 1;
203 }
204
205 //-------------------------------------------------------------------------
206 // Dummy function for Mike to write.
207 //-------------------------------------------------------------------------
208 int med_set_ai_path()
209 {
210         mprintf( (0, "med-set-ai-path called -- it does nothing, paths automatically set!\n" ));
211
212         return 1;
213 }
214
215 // #define OBJ_NONE             255     //unused object
216 // #define OBJ_WALL             0               //A wall... not really an object, but used for collisions
217 // #define OBJ_FIREBALL 1               //a fireball, part of an explosion
218 // #define OBJ_ROBOT            2               //an evil enemy
219 // #define OBJ_HOSTAGE  3               //a hostage you need to rescue
220 // #define OBJ_PLAYER   4               //the player on the console
221 // #define OBJ_WEAPON   5               //a laser, missile, etc
222 // #define OBJ_CAMERA   6               //a camera to slew around with
223 // #define OBJ_POWERUP  7               //a powerup you can pick up
224 // #define OBJ_DEBRIS   8               //a piece of robot
225 // #define OBJ_CNTRLCEN 9               //the control center
226 // #define OBJ_FLARE            10              //the control center
227 // #define MAX_OBJECT_TYPES     11
228
229
230 #define GOODY_TYPE_MAX  MAX_OBJECT_TYPES
231 #define GOODY_X 6
232 #define GOODY_Y 132
233
234 //#define       GOODY_ID_MAX_ROBOT      6
235 //#define       GOODY_ID_MAX_POWERUP    9
236 #define GOODY_COUNT_MAX 4
237
238 int             Cur_goody_type = OBJ_POWERUP;
239 int             Cur_goody_id = 0;
240 int             Cur_goody_count = 0;
241
242 void update_goody_info(void)
243 {
244         if (Cur_object_index > -1 )     {
245                 if ( Objects[Cur_object_index].type == OBJ_ROBOT )      {
246                         object * obj = &Objects[Cur_object_index];
247
248                         obj->contains_type = Cur_goody_type;
249                         obj->contains_id = Cur_goody_id;
250                         obj->contains_count = Cur_goody_count;
251                 }
252         }
253 }
254
255 // #define OBJ_WALL             0               //A wall... not really an object, but used for collisions
256 // #define OBJ_FIREBALL 1               //a fireball, part of an explosion
257 // #define OBJ_ROBOT            2               //an evil enemy
258 // #define OBJ_HOSTAGE  3               //a hostage you need to rescue
259 // #define OBJ_PLAYER   4               //the player on the console
260 // #define OBJ_WEAPON   5               //a laser, missile, etc
261 // #define OBJ_CAMERA   6               //a camera to slew around with
262 // #define OBJ_POWERUP  7               //a powerup you can pick up
263 // #define OBJ_DEBRIS   8               //a piece of robot
264 // #define OBJ_CNTRLCEN 9               //the control center
265 // #define OBJ_FLARE            10              //the control center
266 // #define MAX_OBJECT_TYPES     11
267
268
269 int GoodyNextType()
270 {
271         Cur_goody_type++;
272         while (!((Cur_goody_type == OBJ_ROBOT) || (Cur_goody_type == OBJ_POWERUP))) {
273                 if (Cur_goody_type > GOODY_TYPE_MAX)
274                         Cur_goody_type=0;
275                 else
276                         Cur_goody_type++;
277         }
278
279         GoodyNextID();
280         GoodyPrevID();
281
282         update_goody_info();
283         return 1;
284 }
285
286 int GoodyPrevType()
287 {
288         Cur_goody_type--;
289         while (!((Cur_goody_type == OBJ_ROBOT) || (Cur_goody_type == OBJ_POWERUP))) {
290                 if (Cur_goody_type < 0)
291                         Cur_goody_type = GOODY_TYPE_MAX;
292                 else
293                         Cur_goody_type--;
294         }
295
296         GoodyNextID();
297         GoodyPrevID();
298
299         update_goody_info();
300         return 1;
301 }
302
303 int GoodyNextID()
304 {
305         Cur_goody_id++;
306         if (Cur_goody_type == OBJ_ROBOT) {
307                 if (Cur_goody_id >= N_robot_types)
308                         Cur_goody_id=0;
309         } else {
310                 if (Cur_goody_id >= N_powerup_types)
311                         Cur_goody_id=0;
312         }
313
314         update_goody_info();
315         return 1;
316 }
317
318 int GoodyPrevID()
319 {
320         Cur_goody_id--;
321         if (Cur_goody_type == OBJ_ROBOT) {
322                 if (Cur_goody_id < 0)
323                         Cur_goody_id = N_robot_types-1;
324         } else {
325                 if (Cur_goody_id < 0)
326                         Cur_goody_id = N_powerup_types-1;
327         }
328
329         update_goody_info();
330         return 1;
331 }
332
333 int GoodyNextCount()
334 {
335         Cur_goody_count++;
336         if (Cur_goody_count > GOODY_COUNT_MAX)
337                 Cur_goody_count=0;
338
339         update_goody_info();
340         return 1;
341 }
342
343 int GoodyPrevCount()
344 {
345         Cur_goody_count--;
346         if (Cur_goody_count < 0)
347                 Cur_goody_count=GOODY_COUNT_MAX;
348
349         update_goody_info();
350         return 1;
351 }
352
353 int is_legal_type(int the_type)
354 {
355         return (the_type == OBJ_ROBOT) || (the_type == OBJ_CLUTTER);
356 }
357
358 int is_legal_type_for_this_window(int objnum)
359 {
360         if (objnum == -1)
361                 return 1;
362         else
363                 return is_legal_type(Objects[objnum].type);
364 }
365
366 int LocalObjectSelectNextinSegment(void)
367 {
368         int     rval, first_obj;
369
370         rval = ObjectSelectNextinSegment();
371         first_obj = Cur_object_index;
372
373         if (Cur_object_index != -1) {
374                 while (!is_legal_type_for_this_window(Cur_object_index)) {
375                         //mprintf((0, "Skipping object #%i of type %i\n", Cur_object_index, Objects[Cur_object_index].type));
376                         rval = ObjectSelectNextinSegment();
377                         if (first_obj == Cur_object_index)
378                                 break;
379                 }
380
381                 Cur_goody_type = Objects[Cur_object_index].contains_type;
382                 Cur_goody_id = Objects[Cur_object_index].contains_id;
383                 if (Objects[Cur_object_index].contains_count < 0)
384                         Objects[Cur_object_index].contains_count = 0;
385                 Cur_goody_count = Objects[Cur_object_index].contains_count;
386         }
387
388         if (Cur_object_index != first_obj)
389                 set_view_target_from_segment(Cursegp);
390
391         return rval;
392 }
393
394 int LocalObjectSelectNextinMine(void)
395 {
396         int     rval, first_obj;
397
398         rval = ObjectSelectNextInMine();
399
400         first_obj = Cur_object_index;
401
402         if (Cur_object_index != -1) {
403                 while (!is_legal_type_for_this_window(Cur_object_index)) {
404                         //mprintf((0, "Skipping object #%i of type %i\n", Cur_object_index, Objects[Cur_object_index].type));
405                         ObjectSelectNextInMine();
406                         if (Cur_object_index == first_obj)
407                                 break;
408                 }
409
410                 Cur_goody_type = Objects[Cur_object_index].contains_type;
411                 Cur_goody_id = Objects[Cur_object_index].contains_id;
412                 if (Objects[Cur_object_index].contains_count < 0)
413                         Objects[Cur_object_index].contains_count = 0;
414                 Cur_goody_count = Objects[Cur_object_index].contains_count;
415         }
416
417         if (Cur_object_index != first_obj)
418                 set_view_target_from_segment(Cursegp);
419
420         return rval;
421 }
422
423 int LocalObjectSelectPrevinMine(void)
424 {
425         int     rval, first_obj;
426
427         rval = ObjectSelectPrevInMine();
428
429         first_obj = Cur_object_index;
430
431         if (Cur_object_index != -1) {
432                 while (!is_legal_type_for_this_window(Cur_object_index)) {
433                         //mprintf((0, "Skipping object #%i of type %i\n", Cur_object_index, Objects[Cur_object_index].type));
434                         ObjectSelectPrevInMine();
435                         if (first_obj == Cur_object_index)
436                                 break;
437                 }
438
439                 Cur_goody_type = Objects[Cur_object_index].contains_type;
440                 Cur_goody_id = Objects[Cur_object_index].contains_id;
441                 if (Objects[Cur_object_index].contains_count < 0)
442                         Objects[Cur_object_index].contains_count = 0;
443                 Cur_goody_count = Objects[Cur_object_index].contains_count;
444         }
445
446         if (Cur_object_index != first_obj)
447                 set_view_target_from_segment(Cursegp);
448
449         return rval;
450 }
451
452 int LocalObjectDelete(void)
453 {
454         int     rval;
455
456         rval = ObjectDelete();
457
458         if (Cur_object_index != -1) {
459                 Cur_goody_type = Objects[Cur_object_index].contains_type;
460                 Cur_goody_id = Objects[Cur_object_index].contains_id;
461                 Cur_goody_count = Objects[Cur_object_index].contains_count;
462         }
463
464         set_view_target_from_segment(Cursegp);
465
466         return rval;
467 }
468
469 int LocalObjectPlaceObject(void)
470 {
471         int     rval;
472
473         Cur_goody_count = 0;
474
475         while (ObjType[Cur_robot_type] != OL_ROBOT) { // && (ObjType[Cur_robot_type] != OL_POWERUP)) {
476                 Cur_robot_type++;
477                 if (Cur_robot_type >= N_robot_types)
478                         Cur_robot_type = 0;
479         }
480
481         rval = ObjectPlaceObject();
482         if (rval == -1)
483                 return -1;
484
485         Objects[Cur_object_index].contains_type = Cur_goody_type;
486         Objects[Cur_object_index].contains_id = Cur_goody_id;
487         Objects[Cur_object_index].contains_count = Cur_goody_count;
488
489         set_view_target_from_segment(Cursegp);
490
491         return rval;
492 }
493
494 void close_all_windows(void)
495 {
496         close_trigger_window();
497         close_wall_window();
498         close_centers_window();
499         hostage_close_window();
500         robot_close_window();
501 }
502
503
504 //-------------------------------------------------------------------------
505 // Called from the editor... does one instance of the robot dialog box
506 //-------------------------------------------------------------------------
507 int do_robot_dialog()
508 {
509         int i;
510
511         // Only open 1 instance of this window...
512         if ( MainWindow != NULL ) return 0;
513         
514         // Close other windows
515         close_all_windows();
516         Cur_goody_count = 0;
517
518         // Open a window with a quit button
519         MainWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
520         QuitButton = ui_add_gadget_button( MainWindow, 20, 286, 40, 32, "Done", NULL );
521
522         ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y-3, 25, 22, "<<", GoodyPrevType );
523         ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y-3, 25, 22, ">>", GoodyNextType );
524
525         ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y+21, 25, 22, "<<", GoodyPrevID );
526         ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y+21, 25, 22, ">>", GoodyNextID );
527
528         ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y+45, 25, 22, "<<", GoodyPrevCount );
529         ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y+45, 25, 22, ">>", GoodyNextCount );
530
531         InitialMode[0] = ui_add_gadget_radio( MainWindow,  6, 58, 16, 16, 0, "Hover" );
532         InitialMode[1] = ui_add_gadget_radio( MainWindow, 76, 58, 16, 16, 0, "Normal" );
533         InitialMode[2] = ui_add_gadget_radio( MainWindow,  6, 78, 16, 16, 0, "(hide)" );
534         InitialMode[3] = ui_add_gadget_radio( MainWindow, 76, 78, 16, 16, 0, "Avoid" );
535         InitialMode[4] = ui_add_gadget_radio( MainWindow,  6, 98, 16, 16, 0, "Follow" );
536         InitialMode[5] = ui_add_gadget_radio( MainWindow, 76, 98, 16, 16, 0, "Station" );
537
538         // The little box the robots will spin in.
539         RobotViewBox = ui_add_gadget_userbox( MainWindow,155, 5, 150, 125 );
540
541         // The little box the robots will spin in.
542         ContainsViewBox = ui_add_gadget_userbox( MainWindow,10, 202, 100, 80 );
543
544         // A bunch of buttons...
545         i = 135;
546         ui_add_gadget_button( MainWindow,190,i,53, 26, "<<Typ",                         RobotPrevType );
547         ui_add_gadget_button( MainWindow,247,i,53, 26, "Typ>>",                         RobotNextType );                                                        i += 29;                
548         ui_add_gadget_button( MainWindow,190,i,110, 26, "Next in Seg", LocalObjectSelectNextinSegment );        i += 29;                
549
550         ui_add_gadget_button( MainWindow,190,i,53, 26, "<<Obj",                 LocalObjectSelectPrevinMine );
551         ui_add_gadget_button( MainWindow,247,i,53, 26, ">>Obj",                 LocalObjectSelectNextinMine );          i += 29;                
552
553         ui_add_gadget_button( MainWindow,190,i,110, 26, "Delete",               LocalObjectDelete );                                            i += 29;                
554         ui_add_gadget_button( MainWindow,190,i,110, 26, "Create New",   LocalObjectPlaceObject );                               i += 29;                
555         ui_add_gadget_button( MainWindow,190,i,110, 26, "Set Path",     med_set_ai_path );
556         
557         Time = timer_get_fixed_seconds();
558
559         old_object = -2;                // Set to some dummy value so everything works ok on the first frame.
560
561         if ( Cur_object_index == -1 )
562                 LocalObjectSelectNextinMine();
563
564         return 1;
565
566 }
567
568 void robot_close_window()
569 {
570         if ( MainWindow!=NULL ) {
571                 ui_close_window( MainWindow );
572                 MainWindow = NULL;
573         }
574
575 }
576
577 #define STRING_LENGTH   8
578
579 void do_robot_window()
580 {
581         int     i;
582         fix     DeltaTime, Temp;
583         int     first_object_index;
584
585         if ( MainWindow == NULL ) return;
586
587         first_object_index = Cur_object_index;
588         while (!is_legal_type_for_this_window(Cur_object_index)) {
589                 LocalObjectSelectNextinMine();
590                 if (first_object_index == Cur_object_index) {
591                         break;
592                 }
593         }
594
595         //------------------------------------------------------------
596         // Call the ui code..
597         //------------------------------------------------------------
598         ui_button_any_drawn = 0;
599         ui_window_do_gadgets(MainWindow);
600
601         //------------------------------------------------------------
602         // If we change objects, we need to reset the ui code for all
603         // of the radio buttons that control the ai mode.  Also makes
604         // the current AI mode button be flagged as pressed down.
605         //------------------------------------------------------------
606         if (old_object != Cur_object_index )    {
607                 for (   i=0; i < NUM_BOXES; i++ )       {
608                         InitialMode[i]->flag = 0;               // Tells ui that this button isn't checked
609                         InitialMode[i]->status = 1;     // Tells ui to redraw button
610                 }
611                 if ( Cur_object_index > -1 ) {
612                         int     behavior = Objects[Cur_object_index].ctype.ai_info.behavior;
613                         if ( !((behavior >= MIN_BEHAVIOR) && (behavior <= MAX_BEHAVIOR))) {
614                                 mprintf((0, "Object #%i behavior id (%i) out of bounds, setting to AIB_NORMAL.\n", Cur_object_index, behavior));
615                                 Objects[Cur_object_index].ctype.ai_info.behavior = AIB_NORMAL;
616                                 behavior = AIB_NORMAL;
617                         }
618                         InitialMode[behavior - MIN_BEHAVIOR]->flag = 1; // Mark this button as checked
619                 }
620         }
621
622         //------------------------------------------------------------
623         // If any of the radio buttons that control the mode are set, then
624         // update the cooresponding AI state.
625         //------------------------------------------------------------
626         for (   i=0; i < NUM_BOXES; i++ )       {
627                 if ( InitialMode[i]->flag == 1 )        
628                         if (Objects[Cur_object_index].ctype.ai_info.behavior != MIN_BEHAVIOR+i) {
629                                 Objects[Cur_object_index].ctype.ai_info.behavior = MIN_BEHAVIOR+i;              // Set the ai_state to the cooresponding radio button
630                                 call_init_ai_object(&Objects[Cur_object_index], MIN_BEHAVIOR+i);
631                         }
632         }
633
634         //------------------------------------------------------------
635         // A simple frame time counter for spinning the objects...
636         //------------------------------------------------------------
637         Temp = timer_get_fixed_seconds();
638         DeltaTime = Temp - Time;
639         Time = Temp;
640
641         //------------------------------------------------------------
642         // Redraw the object in the little 64x64 box
643         //------------------------------------------------------------
644         if (Cur_object_index > -1 )     {
645                 int id;
646                 gr_set_current_canvas( RobotViewBox->canvas );
647                 id = get_object_id(&Objects[Cur_object_index]);
648                 if ( id > -1 )  
649                         draw_robot_picture(id, &angles, -1 );
650                 else
651                         gr_clear_canvas( CGREY );
652                 angles.h += fixmul(0x1000, DeltaTime );
653         } else {
654                 // no object, so just blank out
655                 gr_set_current_canvas( RobotViewBox->canvas );
656                 gr_clear_canvas( CGREY );
657
658 //              LocalObjectSelectNextInMine();
659         }
660
661         //------------------------------------------------------------
662         // Redraw the contained object in the other little box
663         //------------------------------------------------------------
664         if ((Cur_object_index > -1 ) && (Cur_goody_count > 0))  {
665                 int id;
666
667                 gr_set_current_canvas( ContainsViewBox->canvas );
668                 id = Cur_goody_id;
669                 if ( id > -1 )   {
670                         int ol_type=0;
671                         if (Cur_goody_type == OBJ_ROBOT)
672                                 ol_type = OL_ROBOT;
673                         else if (Cur_goody_type == OBJ_POWERUP)
674                                 ol_type = OL_POWERUP;
675                         else
676                                 Int3(); //      Error?  Unknown goody type!
677
678                         draw_robot_picture(id, &goody_angles, ol_type );
679                 } else
680                         gr_clear_canvas( CGREY );
681                 goody_angles.h += fixmul(0x1000, DeltaTime );
682         } else {
683                 // no object, so just blank out
684                 gr_set_current_canvas( ContainsViewBox->canvas );
685                 gr_clear_canvas( CGREY );
686
687 //              LocalObjectSelectNextInMine();
688         }
689
690         //------------------------------------------------------------
691         // If anything changes in the ui system, redraw all the text that
692         // identifies this robot.
693         //------------------------------------------------------------
694
695         if (ui_button_any_drawn || (old_object != Cur_object_index) )   {
696                 int     i;
697                 char    type_text[STRING_LENGTH+1],id_text[STRING_LENGTH+1];
698
699                 if (Cur_object_index != -1) {
700                         Cur_goody_type = Objects[Cur_object_index].contains_type;
701                         Cur_goody_id = Objects[Cur_object_index].contains_id;
702                         if (Objects[Cur_object_index].contains_count < 0)
703                                 Objects[Cur_object_index].contains_count = 0;
704                         Cur_goody_count = Objects[Cur_object_index].contains_count;
705                 }
706
707                 ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y,    " Type:");
708                 ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y+24, "   ID:");
709                 ui_wprintf_at( MainWindow, GOODY_X, GOODY_Y+48, "Count:");
710
711                 for (i=0; i<STRING_LENGTH; i++)
712                         id_text[i] = ' ';
713                 id_text[i] = 0;
714
715                 switch (Cur_goody_type) {
716                         case OBJ_ROBOT:
717                                 strcpy(type_text, "Robot  ");
718                                 strncpy(id_text, Robot_names[Cur_goody_id], strlen(Robot_names[Cur_goody_id]));
719                                 break;
720                         case OBJ_POWERUP:
721                                 strcpy(type_text, "Powerup");
722                                 strncpy(id_text, Powerup_names[Cur_goody_id], strlen(Powerup_names[Cur_goody_id]));
723                                 break;
724                         default:
725                                 editor_status("Illegal contained object type (%i), changing to powerup.", Cur_goody_type);
726                                 Cur_goody_type = OBJ_POWERUP;
727                                 Cur_goody_id = 0;
728                                 strcpy(type_text, "Powerup");
729                                 strncpy(id_text, Powerup_names[Cur_goody_id], strlen(Powerup_names[Cur_goody_id]));
730                                 break;
731                 }
732
733                 ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y, type_text);
734                 ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y+24, id_text);
735                 ui_wprintf_at( MainWindow, GOODY_X+108, GOODY_Y+48, "%i", Cur_goody_count);
736
737                 if ( Cur_object_index > -1 )    {
738                         int     id = Objects[Cur_object_index].id;
739                         char    id_text[12];
740                         int     i;
741
742                         for (i=0; i<STRING_LENGTH; i++)
743                                 id_text[i] = ' ';
744                         id_text[i] = 0;
745
746                         strncpy(id_text, Robot_names[id], strlen(Robot_names[id]));
747
748                         ui_wprintf_at( MainWindow, 12,  6, "Robot: %3d ", Cur_object_index );
749                         ui_wprintf_at( MainWindow, 12, 22, "   Id: %3d", id);
750                         ui_wprintf_at( MainWindow, 12, 38, " Name: %8s", id_text);
751
752                 }       else {
753                         ui_wprintf_at( MainWindow, 12,  6, "Robot: none" );
754                         ui_wprintf_at( MainWindow, 12, 22, " Type: ?  "  );
755                         ui_wprintf_at( MainWindow, 12, 38, " Name: ________" );
756                 }
757                 Update_flags |= UF_WORLD_CHANGED;
758         }
759
760         if ( QuitButton->pressed || (last_keypress==KEY_ESC))   {
761                 robot_close_window();
762                 return;
763         }               
764
765         old_object = Cur_object_index;
766 }
767
768 //      --------------------------------------------------------------------------------------------------------------------------
769 #define NUM_MATT_THINGS 2
770
771 #define MATT_LEN                                20
772
773 static UI_WINDOW                                *MattWindow = NULL;
774
775 void object_close_window()
776 {
777         if ( MattWindow!=NULL ) {
778                 ui_close_window( MattWindow );
779                 MattWindow = NULL;
780         }
781
782 }
783
784
785 UI_GADGET_INPUTBOX      *Xtext, *Ytext, *Ztext;
786
787 //-------------------------------------------------------------------------
788 // Called from the editor... does one instance of the object dialog box
789 //-------------------------------------------------------------------------
790 int do_object_dialog()
791 {
792         char    Xmessage[MATT_LEN], Ymessage[MATT_LEN], Zmessage[MATT_LEN];
793         object *obj=&Objects[Cur_object_index];
794
795         if (obj->type == OBJ_ROBOT)             //don't do this for robots
796                 return 0;
797
798         // Only open 1 instance of this window...
799         if ( MattWindow != NULL )
800                 return 0;
801         
802         Cur_goody_count = 0;
803
804         // Open a window with a quit button
805         MattWindow = ui_open_window( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, WIN_DIALOG );
806         QuitButton = ui_add_gadget_button( MattWindow, 20, 286, 40, 32, "Done", NULL );
807
808         QuitButton->hotkey = KEY_ENTER;
809
810         // These are the radio buttons for each mode
811         InitialMode[0] = ui_add_gadget_radio( MattWindow, 10, 50, 16, 16, 0, "None" );
812         InitialMode[1] = ui_add_gadget_radio( MattWindow, 80, 50, 16, 16, 0, "Spinning" );
813
814         InitialMode[obj->movement_type == MT_SPINNING?1:0]->flag = 1;
815
816         sprintf(Xmessage,"%.2f",f2fl(obj->mtype.spin_rate.x));
817         sprintf(Ymessage,"%.2f",f2fl(obj->mtype.spin_rate.y));
818         sprintf(Zmessage,"%.2f",f2fl(obj->mtype.spin_rate.z));
819
820         ui_wprintf_at( MattWindow, 10, 132,"&X:" );
821         Xtext = ui_add_gadget_inputbox( MattWindow, 30, 132, MATT_LEN, MATT_LEN, Xmessage );
822
823         ui_wprintf_at( MattWindow, 10, 162,"&Y:" );
824         Ytext = ui_add_gadget_inputbox( MattWindow, 30, 162, MATT_LEN, MATT_LEN, Ymessage );
825
826         ui_wprintf_at( MattWindow, 10, 192,"&Z:" );
827         Ztext = ui_add_gadget_inputbox( MattWindow, 30, 192, MATT_LEN, MATT_LEN, Zmessage );
828
829         ui_gadget_calc_keys(MattWindow);
830
831         MattWindow->keyboard_focus_gadget = (UI_GADGET *) InitialMode[0];
832
833         mprintf((0, "X = %08x, Y = %08x, Z = %08x\n", atoi(Xmessage), atoi(Ymessage), atoi(Zmessage)));
834
835         return 1;
836
837 }
838
839 void do_object_window()
840 {
841         object *obj=&Objects[Cur_object_index];
842
843         if ( MattWindow == NULL ) return;
844
845         //------------------------------------------------------------
846         // Call the ui code..
847         //------------------------------------------------------------
848         ui_button_any_drawn = 0;
849         ui_window_do_gadgets(MattWindow);
850
851
852         if ( QuitButton->pressed || (last_keypress==KEY_ESC))   {
853
854                 if (InitialMode[0]->flag) obj->movement_type = MT_NONE;
855                 if (InitialMode[1]->flag) obj->movement_type = MT_SPINNING;
856
857                 obj->mtype.spin_rate.x = fl2f(atof(Xtext->text));
858                 obj->mtype.spin_rate.y = fl2f(atof(Ytext->text));
859                 obj->mtype.spin_rate.z = fl2f(atof(Ztext->text));
860
861                 object_close_window();
862                 return;
863         }               
864
865         old_object = Cur_object_index;
866 }
867
868 void set_all_modes_to_hover(void)
869 {
870         int     i;
871
872         for (i=0; i<=Highest_object_index; i++)
873                 if (Objects[i].control_type == CT_AI)
874                         Objects[i].ctype.ai_info.behavior = AIB_STILL;
875 }
876