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