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