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