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