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