home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / medrobot.c < prev    next >
Text File  |  1998-06-08  |  27KB  |  919 lines

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