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