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

  1. /*
  2.  * $Source: f:/miner/source/main/editor/rcs/eobject.c $
  3.  * $Revision: 2.0 $
  4.  * $Author: john $
  5.  * $Date: 1995/02/27 11:35:14 $
  6.  * 
  7.  * Editor object functions.
  8.  * 
  9.  * $Log: eobject.c $
  10.  * Revision 2.0  1995/02/27  11:35:14  john
  11.  * Version 2.0! No anonymous unions, Watcom 10.0, with no need
  12.  * for bitmaps.tbl.
  13.  * 
  14.  * Revision 1.93  1995/02/22  15:09:04  allender
  15.  * remove anonymous unions from object structure
  16.  * 
  17.  * Revision 1.92  1995/01/12  12:10:32  yuan
  18.  * Added coop object capability.
  19.  * 
  20.  * Revision 1.91  1994/12/20  17:57:02  yuan
  21.  * Multiplayer object stuff.
  22.  * 
  23.  * Revision 1.90  1994/11/27  23:17:49  matt
  24.  * Made changes for new mprintf calling convention
  25.  * 
  26.  * Revision 1.89  1994/11/17  14:48:06  mike
  27.  * validation functions moved from editor to game.
  28.  * 
  29.  * Revision 1.88  1994/11/14  11:40:03  mike
  30.  * fix default robot behavior.
  31.  * 
  32.  * Revision 1.87  1994/10/25  10:51:31  matt
  33.  * Vulcan cannon powerups now contain ammo count
  34.  * 
  35.  * Revision 1.86  1994/10/23  02:11:40  matt
  36.  * Got rid of obsolete hostage_info stuff
  37.  * 
  38.  * Revision 1.85  1994/10/17  21:35:32  matt
  39.  * Added support for new Control Center/Main Reactor
  40.  * 
  41.  * Revision 1.84  1994/10/10  17:23:13  mike
  42.  * Verify that not placing too many player objects.
  43.  * 
  44.  * Revision 1.83  1994/09/24  14:15:35  mike
  45.  * Custom colored object support.
  46.  * 
  47.  * Revision 1.82  1994/09/15  22:58:12  matt
  48.  * Made new objects be oriented to their segment
  49.  * Added keypad function to flip an object upside-down
  50.  * 
  51.  * Revision 1.81  1994/09/01  10:58:41  matt
  52.  * Sizes for powerups now specified in bitmaps.tbl; blob bitmaps now plot
  53.  * correctly if width & height of bitmap are different.
  54.  * 
  55.  * Revision 1.80  1994/08/25  21:58:14  mike
  56.  * Write ObjectSelectPrevInMine and something else, I think...
  57.  * 
  58.  * Revision 1.79  1994/08/16  20:19:54  mike
  59.  * Make STILL default (from CHASE_OBJECT).
  60.  * 
  61.  * Revision 1.78  1994/08/14  23:15:45  matt
  62.  * Added animating bitmap hostages, and cleaned up vclips a bit
  63.  * 
  64.  * Revision 1.77  1994/08/13  14:58:43  matt
  65.  * Finished adding support for miscellaneous objects
  66.  * 
  67.  * Revision 1.76  1994/08/12  22:24:58  matt
  68.  * Generalized polygon objects (such as control center)
  69.  * 
  70.  * Revision 1.75  1994/08/09  16:06:11  john
  71.  * Added the ability to place players.  Made old
  72.  * Player variable be ConsoleObject.
  73.  * 
  74.  * Revision 1.74  1994/08/05  18:18:55  matt
  75.  * Made object rotation have 4x resolution, and SHIFT+rotate do old resolution.
  76.  * 
  77.  * Revision 1.73  1994/08/01  13:30:56  matt
  78.  * Made fvi() check holes in transparent walls, and changed fvi() calling
  79.  * parms to take all input data in query structure.
  80.  * 
  81.  */
  82.  
  83.  
  84. #pragma off (unreferenced)
  85. static char rcsid[] = "$Id: eobject.c 2.0 1995/02/27 11:35:14 john Exp $";
  86. #pragma on (unreferenced)
  87.  
  88. #include <stdio.h>
  89. #include <stdlib.h>
  90. #include <stdarg.h>
  91. #include <math.h>
  92. #include <string.h>
  93.  
  94. #include "inferno.h"
  95. #include "segment.h"
  96. #include "editor.h"
  97.  
  98. #include "objpage.h"
  99. #include "fix.h"
  100. #include "mono.h"
  101. #include "error.h"
  102. #include "kdefs.h"
  103. #include    "object.h"
  104. #include "polyobj.h"
  105. #include "game.h"
  106. #include "ai.h"
  107. #include "bm.h"
  108. #include "3d.h"        //    For g3_point_to_vec
  109. #include    "fvi.h"
  110.  
  111. #include "powerup.h"
  112. #include "fuelcen.h"
  113. #include "hostage.h"
  114. #include "medrobot.h"
  115. #include "player.h"
  116. #include "gameseg.h"
  117.  
  118. #define    OBJ_SCALE        (F1_0/2)
  119. #define    OBJ_DEL_SIZE    (F1_0/2)
  120.  
  121. #define ROTATION_UNIT (4096/4)
  122.  
  123. //segment        *Cur_object_seg = -1;
  124.  
  125. void show_objects_in_segment(segment *sp)
  126. {
  127.     short        objid;
  128.  
  129.     mprintf((0,"Objects in segment #%i: ",sp-Segments));
  130.  
  131.     objid = sp->objects;
  132.     while (objid != -1) {
  133.         mprintf((0,"%2i ",objid));
  134.         objid = Objects[objid].next;
  135.     }
  136.     mprintf((0,"\n"));
  137. }
  138.  
  139. //returns the number of the first object in a segment, skipping the player
  140. int get_first_object(segment *seg)
  141. {
  142.     int id;
  143.  
  144.     id = seg->objects;
  145.  
  146.     if (id == (ConsoleObject-Objects))
  147.         id = Objects[id].next;
  148.  
  149.     return id;
  150. }
  151.  
  152. //returns the number of the next object in a segment, skipping the player
  153. int get_next_object(segment *seg,int id)
  154. {
  155.     if (id==-1 || (id=Objects[id].next)==-1)
  156.         return get_first_object(seg);
  157.  
  158.     if (id == (ConsoleObject-Objects))
  159.         return get_next_object(seg,id);
  160.  
  161.     return id;
  162. }
  163.  
  164.  
  165. //@@//    ------------------------------------------------------------------------------------------------------
  166. //@@// this should be called whenever the current segment may have changed
  167. //@@//    If Cur_object_seg != Cursegp, then update various variables.
  168. //@@// this used to be called update_due_to_new_segment()
  169. //@@void ObjectUpdateCurrent(void)
  170. //@@{
  171. //@@    if (Cur_object_seg != Cursegp) {
  172. //@@        Cur_object_seg = Cursegp;
  173. //@@        Cur_object_index = get_first_object(Cur_object_seg);
  174. //@@        Update_flags |= UF_WORLD_CHANGED;
  175. //@@    }
  176. //@@
  177. //@@}
  178.  
  179. //    ------------------------------------------------------------------------------------
  180. int place_object(segment *segp, vms_vector *object_pos, int object_type)
  181. {
  182.     short objnum;
  183.     object *obj;
  184.     vms_matrix seg_matrix;
  185.  
  186.     med_extract_matrix_from_segment(segp,&seg_matrix);
  187.  
  188.     switch(ObjType[object_type]) {
  189.  
  190.         case OL_HOSTAGE:
  191.  
  192.             objnum = obj_create(OBJ_HOSTAGE, -1, 
  193.                     segp-Segments,object_pos,&seg_matrix,HOSTAGE_SIZE,
  194.                     CT_NONE,MT_NONE,RT_HOSTAGE);
  195.  
  196.             if ( objnum < 0 )
  197.                 return 0;
  198.  
  199.             obj = &Objects[objnum];
  200.  
  201.             // Fill in obj->id and other hostage info
  202.             hostage_init_info( objnum );
  203.         
  204.             obj->control_type = CT_POWERUP;
  205.             
  206.             obj->rtype.vclip_info.vclip_num = Hostage_vclip_num[ObjId[object_type]];
  207.             obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time;
  208.             obj->rtype.vclip_info.framenum = 0;
  209.  
  210.             break;
  211.  
  212.         case OL_ROBOT:
  213.  
  214.             objnum = obj_create(OBJ_ROBOT,ObjId[object_type],segp-Segments,object_pos,
  215.                 &seg_matrix,Polygon_models[Robot_info[ObjId[object_type]].model_num].rad,
  216.                 CT_AI,MT_PHYSICS,RT_POLYOBJ);
  217.  
  218.             if ( objnum < 0 )
  219.                 return 0;
  220.  
  221.             obj = &Objects[objnum];
  222.  
  223.             //Set polygon-object-specific data 
  224.  
  225.             obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
  226.             obj->rtype.pobj_info.subobj_flags = 0;
  227.  
  228.             //set Physics info
  229.         
  230.             obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
  231.             obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
  232.  
  233.             obj->mtype.phys_info.flags |= (PF_LEVELLING);
  234.  
  235.             obj->shields = Robot_info[obj->id].strength;
  236.  
  237.             {    int    hide_segment;
  238.             if (Markedsegp)
  239.                 hide_segment = Markedsegp-Segments;
  240.             else
  241.                 hide_segment = -1;
  242.             //    robots which lunge forward to attack cannot have behavior type still.
  243.             if (Robot_info[obj->id].attack_type)
  244.                 init_ai_object(obj-Objects, AIB_NORMAL, hide_segment);
  245.             else
  246.                 init_ai_object(obj-Objects, AIB_STILL, hide_segment);
  247.             }
  248.             break;
  249.  
  250.         case OL_POWERUP:
  251.  
  252.             objnum = obj_create(OBJ_POWERUP,ObjId[object_type],
  253.                     segp-Segments,object_pos,&seg_matrix,Powerup_info[ObjId[object_type]].size,
  254.                     CT_POWERUP,MT_NONE,RT_POWERUP);
  255.  
  256.             if ( objnum < 0 )
  257.                 return 0;
  258.  
  259.             obj = &Objects[objnum];
  260.  
  261.             //set powerup-specific data
  262.  
  263.             obj->rtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num;
  264.             obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].play_time/Vclip[obj->rtype.vclip_info.vclip_num].num_frames;
  265.             obj->rtype.vclip_info.framenum = 0;
  266.  
  267.             if (obj->id == POW_VULCAN_WEAPON)
  268.                 obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
  269.             else
  270.                 obj->ctype.powerup_info.count = 1;
  271.  
  272.             break;
  273.  
  274.         case OL_CLUTTER:
  275.         case OL_CONTROL_CENTER: 
  276.         {
  277.             int obj_type,control_type;
  278.  
  279.             if (ObjType[object_type]==OL_CONTROL_CENTER) {
  280.                 obj_type = OBJ_CNTRLCEN;
  281.                 control_type = CT_CNTRLCEN;
  282.             }
  283.             else {
  284.                 obj_type = OBJ_CLUTTER;
  285.                 control_type = CT_NONE;
  286.             }
  287.  
  288.             objnum = obj_create(obj_type,object_type,segp-Segments,object_pos,
  289.                     &seg_matrix,Polygon_models[ObjId[object_type]].rad,
  290.                     control_type,MT_NONE,RT_POLYOBJ);
  291.  
  292.             if ( objnum < 0 )
  293.                 return 0;
  294.  
  295.             obj = &Objects[objnum];
  296.  
  297.             obj->shields = ObjStrength[object_type];
  298.  
  299.             //Set polygon-object-specific data 
  300.             obj->shields = ObjStrength[object_type];
  301.             obj->rtype.pobj_info.model_num = ObjId[object_type];
  302.             obj->rtype.pobj_info.subobj_flags = 0;
  303.  
  304.             break;
  305.         }
  306.  
  307.         case OL_PLAYER:    {
  308.             objnum = obj_create(OBJ_PLAYER,ObjId[object_type],segp-Segments,object_pos,
  309.                 &seg_matrix,Polygon_models[Player_ship->model_num].rad,
  310.                 CT_NONE,MT_PHYSICS,RT_POLYOBJ);
  311.  
  312.             if ( objnum < 0 )
  313.                 return 0;
  314.  
  315.             obj = &Objects[objnum];
  316.  
  317.             //Set polygon-object-specific data 
  318.  
  319.             obj->rtype.pobj_info.model_num = Player_ship->model_num;
  320.             obj->rtype.pobj_info.subobj_flags = 0;
  321.             //for (i=0;i<MAX_SUBMODELS;i++)
  322.             //    vm_angvec_zero(&obj->rtype.pobj_info.anim_angles[i]);
  323.  
  324.             //set Physics info
  325.  
  326.             vm_vec_zero(&obj->mtype.phys_info.velocity);
  327.             obj->mtype.phys_info.mass = Player_ship->mass;
  328.             obj->mtype.phys_info.drag = Player_ship->drag;
  329.             obj->mtype.phys_info.flags |= PF_TURNROLL | PF_LEVELLING | PF_WIGGLE;
  330.             obj->shields = i2f(100);
  331.  
  332.             break;
  333.         }
  334.         default:
  335.             break;    
  336.         }
  337.  
  338.     Cur_object_index = objnum;
  339.     //Cur_object_seg = Cursegp;
  340.  
  341.     show_objects_in_segment(Cursegp);        //mprintf the objects
  342.  
  343.     Update_flags |= UF_WORLD_CHANGED;
  344.  
  345.     return 1;
  346. }
  347.  
  348. //    ------------------------------------------------------------------------------------------------------
  349. //    Count number of player objects, return value.
  350. int compute_num_players(void)
  351. {
  352.     int    i, count = 0;
  353.  
  354.     for (i=0; i<=Highest_object_index; i++)
  355.         if (Objects[i].type == OBJ_PLAYER)
  356.             count++;
  357.  
  358.     return count;
  359.  
  360. }
  361.  
  362. int ObjectMakeCoop(void)
  363. {
  364.     Assert(Cur_object_index != -1);
  365.     Assert(Cur_object_index < MAX_OBJECTS);
  366. //    Assert(Objects[Cur_object_index.type == OBJ_PLAYER);
  367.  
  368.     if (Objects[Cur_object_index].type == OBJ_PLAYER ) {
  369.         Objects[Cur_object_index].type = OBJ_COOP;
  370.         editor_status("You just made a player object COOPERATIVE");
  371.     } else
  372.         editor_status("This is not a player object");
  373.  
  374.     return 1;
  375. }
  376.  
  377. //    ------------------------------------------------------------------------------------------------------
  378. //    Place current object at center of current segment.
  379. int ObjectPlaceObject(void)
  380. {
  381.     int    old_cur_object_index;
  382.     int    rval;
  383.  
  384.     vms_vector    cur_object_loc;
  385.  
  386. #ifdef SHAREWARE
  387.     if (ObjType[Cur_robot_type] == OL_PLAYER) {
  388.         int num_players = compute_num_players();
  389.         Assert(num_players <= MAX_PLAYERS);
  390.         if (num_players == MAX_PLAYERS) {
  391.             editor_status("Can't place player object.  Already %i players.", MAX_PLAYERS);
  392.             return -1;
  393.         }
  394.     }
  395. #endif
  396.  
  397. #ifndef SHAREWARE
  398.     if (ObjType[Cur_robot_type] == OL_PLAYER) {
  399.         int num_players = compute_num_players();
  400.         Assert(num_players <= MAX_MULTI_PLAYERS);
  401.         if (num_players > MAX_PLAYERS)
  402.             editor_status("You just placed a cooperative player object");
  403.         if (num_players == MAX_MULTI_PLAYERS) {
  404.             editor_status("Can't place player object.  Already %i players.", MAX_MULTI_PLAYERS);
  405.             return -1;
  406.         }
  407.     }
  408. #endif
  409.  
  410.     //update_due_to_new_segment();
  411.     compute_segment_center(&cur_object_loc, Cursegp);
  412.  
  413.     old_cur_object_index = Cur_object_index;
  414.     rval = place_object(Cursegp, &cur_object_loc, Cur_robot_type);
  415.  
  416.     if (old_cur_object_index != Cur_object_index)
  417.         Objects[Cur_object_index].rtype.pobj_info.tmap_override = -1;
  418.  
  419.     return rval;
  420.  
  421. }
  422.  
  423. //    ------------------------------------------------------------------------------------------------------
  424. //    Place current object at center of current segment.
  425. int ObjectPlaceObjectTmap(void)
  426. {
  427.     int    rval, old_cur_object_index;
  428.     vms_vector    cur_object_loc;
  429.  
  430.     //update_due_to_new_segment();
  431.     compute_segment_center(&cur_object_loc, Cursegp);
  432.  
  433.     old_cur_object_index = Cur_object_index;
  434.     rval = place_object(Cursegp, &cur_object_loc, Cur_robot_type);
  435.  
  436.     if ((Cur_object_index != old_cur_object_index) && (Objects[Cur_object_index].render_type == RT_POLYOBJ))
  437.         Objects[Cur_object_index].rtype.pobj_info.tmap_override = CurrentTexture;
  438.     else
  439.         editor_status("Unable to apply current texture map to this object.");
  440.     
  441.     return rval;
  442. }
  443.  
  444. //    ------------------------------------------------------------------------------------------------------
  445. int ObjectSelectNextinSegment(void)
  446. {
  447.     int    id;
  448.     segment *objsegp;
  449.  
  450.  
  451.     //update_due_to_new_segment();
  452.  
  453.     //Assert(Cur_object_seg == Cursegp);
  454.  
  455.     if (Cur_object_index == -1) {
  456.         objsegp = Cursegp;
  457.         Cur_object_index = objsegp->objects;
  458.     } else {
  459.         objsegp = Cursegp;
  460.         if (Objects[Cur_object_index].segnum != Cursegp-Segments)
  461.             Cur_object_index = objsegp->objects;
  462.     }
  463.  
  464.  
  465.     //Debug: make sure current object is in current segment
  466.     for (id=objsegp->objects;(id != Cur_object_index)  && (id != -1);id=Objects[id].next);
  467.     Assert(id == Cur_object_index);        //should have found object
  468.  
  469.     //    Select the next object, wrapping back to start if we are at the end of the linked list for this segment.
  470.     if (id != -1)
  471.         Cur_object_index = get_next_object(objsegp,Cur_object_index);
  472.  
  473.     //mprintf((0,"Cur_object_index == %i\n", Cur_object_index));
  474.  
  475.     Update_flags |= UF_WORLD_CHANGED;
  476.  
  477.     return 1;
  478.  
  479. }
  480.  
  481. //Moves to next object in the mine, skipping the player
  482. int ObjectSelectNextInMine()
  483. {    int i;
  484.     for (i=0;i<MAX_OBJECTS;i++) {
  485.         Cur_object_index++;
  486.         if (Cur_object_index>= MAX_OBJECTS ) Cur_object_index= 0;
  487.  
  488.         if ((Objects[Cur_object_index ].type != OBJ_NONE) && (Cur_object_index != (ConsoleObject-Objects)) )    {
  489.             Cursegp = &Segments[Objects[Cur_object_index ].segnum];
  490.             med_create_new_segment_from_cursegp();
  491.             //Cur_object_seg = Cursegp;
  492.             return 1;
  493.         }
  494.     }
  495.     Cur_object_index = -1;
  496.  
  497.     Update_flags |= UF_WORLD_CHANGED;
  498.  
  499.     return 0;
  500. }
  501.  
  502. //Moves to next object in the mine, skipping the player
  503. int ObjectSelectPrevInMine()
  504. {    int i;
  505.     for (i=0;i<MAX_OBJECTS;i++) {
  506.         Cur_object_index--;
  507.         if (Cur_object_index < 0 )
  508.             Cur_object_index = MAX_OBJECTS-1;
  509.  
  510.         if ((Objects[Cur_object_index ].type != OBJ_NONE) && (Cur_object_index != (ConsoleObject-Objects)) )    {
  511.             Cursegp = &Segments[Objects[Cur_object_index ].segnum];
  512.             med_create_new_segment_from_cursegp();
  513.             //Cur_object_seg = Cursegp;
  514.             return 1;
  515.         }
  516.     }
  517.     Cur_object_index = -1;
  518.  
  519.     Update_flags |= UF_WORLD_CHANGED;
  520.  
  521.     return 0;
  522. }
  523.  
  524. //    ------------------------------------------------------------------------------------------------------
  525. //    Delete current object, if it exists.
  526. //    If it doesn't exist, reformat Matt's hard disk, even if he is in Boston.
  527. int ObjectDelete(void)
  528. {
  529.  
  530.     if (Cur_object_index != -1) {
  531.         int delete_objnum;
  532.  
  533.         delete_objnum = Cur_object_index;
  534.  
  535.         ObjectSelectNextinSegment();
  536.  
  537.         obj_delete(delete_objnum);
  538.  
  539.         if (delete_objnum == Cur_object_index)
  540.             Cur_object_index = -1;
  541.  
  542.         Update_flags |= UF_WORLD_CHANGED;
  543.     }
  544.  
  545.     return 1;
  546. }
  547.  
  548. //    -----------------------------------------------------------------------------------------------------------------
  549. //    Object has moved to another segment, (or at least poked through).
  550. //    If still in mine, that is legal, so relink into new segment.
  551. //    Return value:    0 = in mine, 1 = not in mine
  552. int move_object_within_mine(object * obj, vms_vector *newpos )
  553. {
  554.     int segnum;
  555.  
  556.     for (segnum=0;segnum <= Highest_segment_index; segnum++) {
  557.         segmasks    result = get_seg_masks(&obj->pos,segnum,0);
  558.         if (result.centermask == 0) {
  559.             int    fate;
  560.             fvi_info    hit_info;
  561.             fvi_query fq;
  562.  
  563.             //    See if the radius pokes through any wall.
  564.             fq.p0                        = &obj->pos;
  565.             fq.startseg                = obj->segnum;
  566.             fq.p1                        = newpos;
  567.             fq.rad                    = obj->size;
  568.             fq.thisobjnum            = -1;
  569.             fq.ignore_obj_list    = NULL;
  570.             fq.flags                    = 0;
  571.  
  572.             fate = find_vector_intersection(&fq,&hit_info);
  573.  
  574.             if (fate != HIT_WALL) {
  575.                 if ( segnum != obj->segnum )
  576.                     obj_relink( obj-Objects, segnum);
  577.                 obj->pos = *newpos;
  578.                 return 0;
  579.             } //else
  580.                 //mprintf((0, "Hit wall seg:side = %i:%i\n", hit_info.hit_seg, hit_info.hit_side));
  581.         }
  582.     }
  583.  
  584.     return 1;
  585.  
  586. }
  587.  
  588.  
  589. //    Return 0 if object is in expected segment, else return 1
  590. int verify_object_seg(object *objp, vms_vector *newpos)
  591. {
  592.     segmasks    result = get_seg_masks(newpos, objp->segnum, objp->size);
  593.  
  594.     if (result.facemask == 0)
  595.         return 0;
  596.     else
  597.         return move_object_within_mine(objp, newpos);
  598.  
  599. }
  600.  
  601. //    ------------------------------------------------------------------------------------------------------
  602. int    ObjectMoveForward(void)
  603. {
  604.     object *obj;
  605.     vms_vector    fvec;
  606.     vms_vector    newpos;
  607.  
  608.     if (Cur_object_index == -1) {
  609.         editor_status("No current object, cannot move.");
  610.         return 1;
  611.     }
  612.  
  613.     obj = &Objects[Cur_object_index];
  614.  
  615.     extract_forward_vector_from_segment(&Segments[obj->segnum], &fvec);
  616.     vm_vec_normalize(&fvec);
  617.  
  618.     vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&fvec, OBJ_SCALE));
  619.  
  620.     if (!verify_object_seg(obj, &newpos))
  621.         obj->pos = newpos;
  622.  
  623.     Update_flags |= UF_WORLD_CHANGED;
  624.  
  625.     return 1;
  626. }
  627.  
  628. //    ------------------------------------------------------------------------------------------------------
  629. int    ObjectMoveBack(void)
  630. {
  631.     object *obj;
  632.     vms_vector    fvec;
  633.     vms_vector    newpos;
  634.  
  635.     if (Cur_object_index == -1) {
  636.         editor_status("No current object, cannot move.");
  637.         return 1;
  638.     }
  639.  
  640.     obj = &Objects[Cur_object_index];
  641.  
  642.     extract_forward_vector_from_segment(&Segments[obj->segnum], &fvec);
  643.     vm_vec_normalize(&fvec);
  644.  
  645.     vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&fvec, OBJ_SCALE));
  646.  
  647.     if (!verify_object_seg(obj, &newpos))
  648.         obj->pos = newpos;
  649.  
  650.     Update_flags |= UF_WORLD_CHANGED;
  651.  
  652.     return 1;
  653. }
  654.  
  655. //    ------------------------------------------------------------------------------------------------------
  656. int    ObjectMoveLeft(void)
  657. {
  658.     object *obj;
  659.     vms_vector    rvec;
  660.     vms_vector    newpos;
  661.  
  662.     if (Cur_object_index == -1) {
  663.         editor_status("No current object, cannot move.");
  664.         return 1;
  665.     }
  666.  
  667.     obj = &Objects[Cur_object_index];
  668.  
  669.     extract_right_vector_from_segment(&Segments[obj->segnum], &rvec);
  670.     vm_vec_normalize(&rvec);
  671.  
  672.     vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&rvec, OBJ_SCALE));
  673.  
  674.     if (!verify_object_seg(obj, &newpos))
  675.         obj->pos = newpos;
  676.  
  677.     Update_flags |= UF_WORLD_CHANGED;
  678.  
  679.     return 1;
  680. }
  681.  
  682. //    ------------------------------------------------------------------------------------------------------
  683. int    ObjectMoveRight(void)
  684. {
  685.     object *obj;
  686.     vms_vector    rvec;
  687.     vms_vector    newpos;
  688.  
  689.     if (Cur_object_index == -1) {
  690.         editor_status("No current object, cannot move.");
  691.         return 1;
  692.     }
  693.  
  694.     obj = &Objects[Cur_object_index];
  695.  
  696.     extract_right_vector_from_segment(&Segments[obj->segnum], &rvec);
  697.     vm_vec_normalize(&rvec);
  698.  
  699.     vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&rvec, OBJ_SCALE));
  700.  
  701.     if (!verify_object_seg(obj, &newpos))
  702.         obj->pos = newpos;
  703.  
  704.     Update_flags |= UF_WORLD_CHANGED;
  705.  
  706.     return 1;
  707. }
  708.  
  709. //    ------------------------------------------------------------------------------------------------------
  710. int    ObjectSetDefault(void)
  711. {
  712.     //update_due_to_new_segment();
  713.  
  714.     if (Cur_object_index == -1) {
  715.         editor_status("No current object, cannot move.");
  716.         return 1;
  717.     }
  718.  
  719.     compute_segment_center(&Objects[Cur_object_index].pos, &Segments[Objects[Cur_object_index].segnum]);
  720.  
  721.     Update_flags |= UF_WORLD_CHANGED;
  722.  
  723.     return 1;
  724. }
  725.  
  726.  
  727. //    ------------------------------------------------------------------------------------------------------
  728. int    ObjectMoveUp(void)
  729. {
  730.     object *obj;
  731.     vms_vector    uvec;
  732.     vms_vector    newpos;
  733.  
  734.     if (Cur_object_index == -1) {
  735.         editor_status("No current object, cannot move.");
  736.         return 1;
  737.     }
  738.  
  739.     obj = &Objects[Cur_object_index];
  740.  
  741.     extract_up_vector_from_segment(&Segments[obj->segnum], &uvec);
  742.     vm_vec_normalize(&uvec);
  743.  
  744.     vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&uvec, OBJ_SCALE));
  745.  
  746.     if (!verify_object_seg(obj, &newpos))
  747.         obj->pos = newpos;
  748.  
  749.     Update_flags |= UF_WORLD_CHANGED;
  750.  
  751.     return 1;
  752. }
  753.  
  754. //    ------------------------------------------------------------------------------------------------------
  755. int    ObjectMoveDown(void)
  756. {
  757.     object *obj;
  758.     vms_vector    uvec;
  759.     vms_vector    newpos;
  760.  
  761.     if (Cur_object_index == -1) {
  762.         editor_status("No current object, cannot move.");
  763.         return 1;
  764.     }
  765.  
  766.     obj = &Objects[Cur_object_index];
  767.  
  768.     extract_up_vector_from_segment(&Segments[obj->segnum], &uvec);
  769.     vm_vec_normalize(&uvec);
  770.  
  771.     vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&uvec, OBJ_SCALE));
  772.  
  773.     if (!verify_object_seg(obj, &newpos))
  774.         obj->pos = newpos;
  775.  
  776.     Update_flags |= UF_WORLD_CHANGED;
  777.  
  778.     return 1;
  779. }
  780.  
  781. //    ------------------------------------------------------------------------------------------------------
  782. int    ObjectMakeSmaller(void)
  783. {
  784.     fix    cur_size;
  785.  
  786.     //update_due_to_new_segment();
  787.  
  788.     cur_size = Objects[Cur_object_index].size;
  789.  
  790.     cur_size -= OBJ_DEL_SIZE;
  791.     if (cur_size < OBJ_DEL_SIZE)
  792.         cur_size = OBJ_DEL_SIZE;
  793.  
  794.     Objects[Cur_object_index].size = cur_size;
  795.     
  796.     Update_flags |= UF_WORLD_CHANGED;
  797.  
  798.     return 1;
  799. }
  800.  
  801. //    ------------------------------------------------------------------------------------------------------
  802. int    ObjectMakeLarger(void)
  803. {
  804.     fix    cur_size;
  805.  
  806.     //update_due_to_new_segment();
  807.  
  808.     cur_size = Objects[Cur_object_index].size;
  809.  
  810.     cur_size += OBJ_DEL_SIZE;
  811.  
  812.     Objects[Cur_object_index].size = cur_size;
  813.     
  814.     Update_flags |= UF_WORLD_CHANGED;
  815.  
  816.     return 1;
  817. }
  818.  
  819. //    ------------------------------------------------------------------------------------------------------
  820.  
  821. int rotate_object(short objnum, int p, int b, int h)
  822. {
  823.     object *obj = &Objects[objnum];
  824.     vms_angvec ang;
  825.     vms_matrix rotmat,tempm;
  826.     
  827. //    vm_extract_angles_matrix( &ang,&obj->orient);
  828.  
  829. //    ang.p += p;
  830. //    ang.b += b;
  831. //    ang.h += h;
  832.  
  833.     ang.p = p;
  834.     ang.b = b;
  835.     ang.h = h;
  836.  
  837.     vm_angles_2_matrix(&rotmat, &ang);
  838.     vm_matrix_x_matrix(&tempm, &obj->orient, &rotmat);
  839.     obj->orient = tempm;
  840.  
  841. //   vm_angles_2_matrix(&obj->orient, &ang);
  842.  
  843.     Update_flags |= UF_WORLD_CHANGED;
  844.  
  845.     return 1;
  846. }
  847.  
  848.  
  849. void reset_object(short objnum)
  850. {
  851.     object *obj = &Objects[objnum];
  852.  
  853.     med_extract_matrix_from_segment(&Segments[obj->segnum],&obj->orient);
  854.  
  855. }
  856.  
  857.  
  858.  
  859. int ObjectResetObject()
  860. {
  861.     reset_object(Cur_object_index);
  862.  
  863.     Update_flags |= UF_WORLD_CHANGED;
  864.  
  865.     return 1;
  866. }
  867.  
  868.  
  869. int ObjectFlipObject()
  870. {
  871.     vms_matrix *m=&Objects[Cur_object_index].orient;
  872.  
  873.     vm_vec_negate(&m->uvec);
  874.     vm_vec_negate(&m->rvec);
  875.  
  876.     Update_flags |= UF_WORLD_CHANGED;
  877.  
  878.     return 1;
  879. }
  880.  
  881. int ObjectDecreaseBank()        {return rotate_object(Cur_object_index, 0, -ROTATION_UNIT, 0);}
  882. int ObjectIncreaseBank()        {return rotate_object(Cur_object_index, 0, ROTATION_UNIT, 0);}
  883. int ObjectDecreasePitch()        {return rotate_object(Cur_object_index, -ROTATION_UNIT, 0, 0);}
  884. int ObjectIncreasePitch()        {return rotate_object(Cur_object_index, ROTATION_UNIT, 0, 0);}
  885. int ObjectDecreaseHeading()    {return rotate_object(Cur_object_index, 0, 0, -ROTATION_UNIT);}
  886. int ObjectIncreaseHeading()    {return rotate_object(Cur_object_index, 0, 0, ROTATION_UNIT);}
  887.  
  888. int ObjectDecreaseBankBig()        {return rotate_object(Cur_object_index, 0, -(ROTATION_UNIT*4), 0);}
  889. int ObjectIncreaseBankBig()        {return rotate_object(Cur_object_index, 0, (ROTATION_UNIT*4), 0);}
  890. int ObjectDecreasePitchBig()        {return rotate_object(Cur_object_index, -(ROTATION_UNIT*4), 0, 0);}
  891. int ObjectIncreasePitchBig()        {return rotate_object(Cur_object_index, (ROTATION_UNIT*4), 0, 0);}
  892. int ObjectDecreaseHeadingBig()    {return rotate_object(Cur_object_index, 0, 0, -(ROTATION_UNIT*4));}
  893. int ObjectIncreaseHeadingBig()    {return rotate_object(Cur_object_index, 0, 0, (ROTATION_UNIT*4));}
  894.  
  895. //    -----------------------------------------------------------------------------------------------------
  896. //    Move object around based on clicks in 2d screen.
  897. //    Slide an object parallel to the 2d screen, to a point on a vector.
  898. //    The vector is defined by a point on the 2d screen and the eye.
  899.  
  900. //    V    =    vector from eye to 2d screen point.
  901. //    E    =    eye
  902. //    F    =    forward vector from eye
  903. //    O    =    3-space location of object
  904.  
  905. //    D    =    depth of object given forward vector F
  906. //        =    (OE dot norm(F))
  907.  
  908. //    Must solve intersection of:
  909. //        E + tV        ( equation of vector from eye through point on 2d screen)
  910. //        Fs + D        ( equation of plane parallel to 2d screen, at depth D)
  911. //        =    Fx(Ex + tVx) + Fy(Ey + tVy) + Fz(Ez + tVz) + D = 0
  912. //
  913. //                  FxEx + FyEy + FzEz - D
  914. //            t = - ----------------------
  915. //                      VxFx + VyFy + VzFz
  916.  
  917.  
  918. //void print_vec(vms_vector *vec, char *text)
  919. //{
  920. //    mprintf((0, "%10s = %9.5f %9.5f %9.5f\n", text, f2fl(vec->x), f2fl(vec->y), f2fl(vec->z)));
  921. //}
  922. //
  923. // void solve(vms_vector *result, vms_vector *E, vms_vector *V, vms_vector *O, vms_vector *F)
  924. // {
  925. //     fix    t, D;
  926. //     vms_vector    Fnorm, Vnorm;
  927. //     fix            num, denom;
  928. //     // float            test_plane;
  929. // 
  930. //     print_vec(E, "E");
  931. //     print_vec(V, "V");
  932. //     print_vec(O, "O");
  933. //     print_vec(F, "F");
  934. // 
  935. //     Fnorm = *F;    vm_vec_normalize(&Fnorm);
  936. //     Vnorm = *V;    vm_vec_normalize(&Vnorm);
  937. // 
  938. //     D = (fixmul(O->x, Fnorm.x) + fixmul(O->y, Fnorm.y) + fixmul(O->z, Fnorm.z));
  939. //     mprintf((0, "D = %9.5f\n", f2fl(D)));
  940. // 
  941. //     num = fixmul(Fnorm.x, E->x) + fixmul(Fnorm.y, E->y) + fixmul(Fnorm.z, E->z) - D;
  942. //     denom = vm_vec_dot(&Vnorm, &Fnorm);
  943. //     t = - num/denom;
  944. // 
  945. //     mprintf((0, "num = %9.5f, denom = %9.5f, t = %9.5f\n", f2fl(num), f2fl(denom), f2fl(t)));
  946. // 
  947. //     result->x = E->x + fixmul(t, Vnorm.x);
  948. //     result->y = E->y + fixmul(t, Vnorm.y);
  949. //     result->z = E->z + fixmul(t, Vnorm.z);
  950. // 
  951. //     print_vec(result, "result");
  952. // 
  953. //     // test_plane = fixmul(result->x, Fnorm.x) + fixmul(result->y, Fnorm.y) + fixmul(result->z, Fnorm.z) - D;
  954. //     // if (abs(test_plane) > .001)
  955. //     //     printf("OOPS: test_plane = %9.5f\n", test_plane);
  956. // }
  957.  
  958. void move_object_to_position(int objnum, vms_vector *newpos)
  959. {
  960.     object    *objp = &Objects[objnum];
  961.  
  962.     segmasks    result = get_seg_masks(newpos, objp->segnum, objp->size);
  963.  
  964.     if (result.facemask == 0) {
  965.         //mprintf((0, "Object #%i moved from (%7.3f %7.3f %7.3f) to (%7.3f %7.3f %7.3f)\n", objnum, f2fl(objp->pos.x), f2fl(objp->pos.y), f2fl(objp->pos.z), f2fl(newpos->x), f2fl(newpos->y), f2fl(newpos->z)));
  966.         objp->pos = *newpos;
  967.     } else {
  968.         if (verify_object_seg(&Objects[objnum], newpos)) {
  969.             int        fate, count;
  970.             int        viewer_segnum;
  971.             object    temp_viewer_obj;
  972.             fvi_query fq;
  973.             fvi_info    hit_info;
  974.             vms_vector    last_outside_pos;
  975.             vms_vector    last_inside_pos;
  976.  
  977.             temp_viewer_obj = *Viewer;
  978.             viewer_segnum = find_object_seg(&temp_viewer_obj);
  979.             temp_viewer_obj.segnum = viewer_segnum;
  980.  
  981.             //    If the viewer is outside the mine, get him in the mine!
  982.             if (viewer_segnum == -1) {
  983.                 //    While outside mine, move towards object
  984.                 count = 0;
  985.                 while (viewer_segnum == -1) {
  986.                     vms_vector    temp_vec;
  987.  
  988.                     //mprintf((0, "[towards %7.3f %7.3f %7.3f]\n", f2fl(temp_viewer_obj.pos.x), f2fl(temp_viewer_obj.pos.y), f2fl(temp_viewer_obj.pos.z)));
  989.                     last_outside_pos = temp_viewer_obj.pos;
  990.  
  991.                     vm_vec_avg(&temp_vec, &temp_viewer_obj.pos, newpos);
  992.                     temp_viewer_obj.pos = temp_vec;
  993.                     viewer_segnum = find_object_seg(&temp_viewer_obj);
  994.                     temp_viewer_obj.segnum = viewer_segnum;
  995.  
  996.                     if (count > 5) {
  997.                         editor_status("Unable to move object, can't get viewer in mine.  Aborting");
  998.                         return;
  999.                     }
  1000.                 }
  1001.  
  1002.                 count = 0;
  1003.                 //    While inside mine, move away from object.
  1004.                 while (viewer_segnum != -1) {
  1005.  
  1006.                     vms_vector    temp_vec;
  1007.  
  1008.                     //mprintf((0, "[away %7.3f %7.3f %7.3f]\n", f2fl(temp_viewer_obj.pos.x), f2fl(temp_viewer_obj.pos.y), f2fl(temp_viewer_obj.pos.z)));
  1009.                     last_inside_pos = temp_viewer_obj.pos;
  1010.  
  1011.                     vm_vec_avg(&temp_vec, &temp_viewer_obj.pos, &last_outside_pos);
  1012.                     temp_viewer_obj.pos = temp_vec;
  1013.                     update_object_seg(&temp_viewer_obj);
  1014.                     viewer_segnum = find_object_seg(&temp_viewer_obj);
  1015.                     temp_viewer_obj.segnum = viewer_segnum;
  1016.  
  1017.                     if (count > 5) {
  1018.                         editor_status("Unable to move object, can't get viewer back out of mine.  Aborting");
  1019.                         return;
  1020.                     }
  1021.                 }
  1022.             }
  1023.  
  1024.             fq.p0                        = &temp_viewer_obj.pos;
  1025.             fq.startseg                = temp_viewer_obj.segnum;
  1026.             fq.p1                        = newpos;
  1027.             fq.rad                    = temp_viewer_obj.size;
  1028.             fq.thisobjnum            = -1;
  1029.             fq.ignore_obj_list    = NULL;
  1030.             fq.flags                    = 0;
  1031.  
  1032.             fate = find_vector_intersection(&fq,&hit_info);
  1033.             if (fate == HIT_WALL) {
  1034.                 int    new_segnum;
  1035.  
  1036.                 //mprintf((0, "Hit wall seg:side = %i:%i, point = (%7.3f %7.3f %7.3f)\n", hit_info.hit_seg, hit_info.hit_side, f2fl(hit_info.hit_pnt.x), f2fl(hit_info.hit_pnt.y), f2fl(hit_info.hit_pnt.z)));
  1037.                 objp->pos = hit_info.hit_pnt;
  1038.                 new_segnum = find_object_seg(objp);
  1039.                 Assert(new_segnum != -1);
  1040.                 obj_relink(objp-Objects, new_segnum);
  1041.                 //mprintf((0, "Object moved from segment %i to %i\n", old_segnum, objp->segnum));
  1042.             } else {
  1043.                 editor_status("Attempted to move object out of mine.  Object not moved.");
  1044.                 //mprintf((0,"Attempted to move object out of mine.  Object not moved."));
  1045.             }
  1046.         }
  1047.     }
  1048.  
  1049.     Update_flags |= UF_WORLD_CHANGED;
  1050. }
  1051.  
  1052. void move_object_to_vector(vms_vector *vec_through_screen, fix delta_distance)
  1053. {
  1054.     vms_vector    result;
  1055.  
  1056.     vm_vec_scale_add(&result, &Viewer->pos, vec_through_screen, vm_vec_dist(&Viewer->pos,&Objects[Cur_object_index].pos)+delta_distance);
  1057.  
  1058.     move_object_to_position(Cur_object_index, &result);
  1059.  
  1060. }
  1061.  
  1062. void move_object_to_mouse_click_delta(fix delta_distance)
  1063. {
  1064.     short            xcrd,ycrd;
  1065.     vms_vector    vec_through_screen;
  1066.  
  1067.     if (Cur_object_index == -1) {
  1068.         editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!");
  1069.         return;
  1070.     }
  1071.  
  1072.     xcrd = GameViewBox->b1_drag_x1;
  1073.     ycrd = GameViewBox->b1_drag_y1;
  1074.  
  1075.     med_point_2_vec(&_canv_editor_game, &vec_through_screen, xcrd, ycrd);
  1076.  
  1077.     //mprintf((0, "Mouse click at %i %i, vector = %7.3f %7.3f %7.3f\n", xcrd, ycrd, f2fl(vec_through_screen.x), f2fl(vec_through_screen.y), f2fl(vec_through_screen.z)));
  1078.  
  1079.     move_object_to_vector(&vec_through_screen, delta_distance);
  1080.  
  1081. }
  1082.  
  1083. void move_object_to_mouse_click(void)
  1084. {
  1085.     move_object_to_mouse_click_delta(0);
  1086. }
  1087.  
  1088. int    ObjectMoveNearer(void)
  1089. {
  1090.     vms_vector    result;
  1091.  
  1092.     if (Cur_object_index == -1) {
  1093.         editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!");
  1094.         return 1;
  1095.     }
  1096.  
  1097. //    move_object_to_mouse_click_delta(-4*F1_0);        //    Move four units closer to eye
  1098.  
  1099.     vm_vec_sub(&result, &Objects[Cur_object_index].pos, &Viewer->pos);
  1100.     vm_vec_normalize(&result);
  1101.     move_object_to_vector(&result, -4*F1_0);
  1102.  
  1103.     return 1;    
  1104. }
  1105.  
  1106. int    ObjectMoveFurther(void)
  1107. {
  1108.     vms_vector    result;
  1109.  
  1110.     if (Cur_object_index == -1) {
  1111.         editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!");
  1112.         return 1;
  1113.     }
  1114.  
  1115. //    move_object_to_mouse_click_delta(+4*F1_0);        //    Move four units further from eye
  1116.  
  1117.     vm_vec_sub(&result, &Objects[Cur_object_index].pos, &Viewer->pos);
  1118.     vm_vec_normalize(&result);
  1119.     move_object_to_vector(&result, 4*F1_0);
  1120.  
  1121.     return 1;    
  1122. }
  1123.  
  1124.