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