]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudlock.cpp
initial loading/progress screen for emscripten
[taylor/freespace2.git] / src / hud / hudlock.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Hud/HUDlock.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module that controls missile locking
16  *
17  * $Log$
18  * Revision 1.6  2003/05/25 02:30:42  taylor
19  * Freespace 1 support
20  *
21  * Revision 1.5  2002/06/17 06:33:09  relnev
22  * ryan's struct patch for gcc 2.95
23  *
24  * Revision 1.4  2002/06/09 04:41:21  relnev
25  * added copyright header
26  *
27  * Revision 1.3  2002/05/31 07:24:28  relnev
28  * warning
29  *
30  * Revision 1.2  2002/05/07 03:16:45  theoddone33
31  * The Great Newline Fix
32  *
33  * Revision 1.1.1.1  2002/05/03 03:28:09  root
34  * Initial import.
35  *
36  * 
37  * 19    8/09/99 10:50a Jasenw
38  * 
39  * 18    7/30/99 5:42p Jasenw
40  * changed coords to center HUD lock indicator.
41  * 
42  * 17    7/28/99 2:49p Andsager
43  * Make hud target speed use vm_vec_mag (not vm_vec_mag_quick)
44  * 
45  * 16    6/08/99 7:41p Dave
46  * Animated hud lockup icon a bit differently.
47  * 
48  * 15    6/08/99 8:35a Jasenw
49  * new coords for new lock ani
50  * 
51  * 14    6/07/99 4:20p Andsager
52  * Add HUD color for tagged object.  Apply to target and radar.
53  * 
54  * 13    6/07/99 1:42p Jasenw
55  * 
56  * 12    6/04/99 10:58a Dave
57  * Updated hud lock gauge.
58  * 
59  * 11    6/03/99 2:32p Jasenw
60  * changed coords for new HUD stuff
61  * 
62  * 10    6/02/99 5:41p Andsager
63  * Reduce range of secondary weapons not fired from turrets in nebula.
64  * Reduce range of beams fired from turrrets in nebula
65  * 
66  * 9     4/23/99 12:01p Johnson
67  * Added SIF_HUGE_SHIP
68  * 
69  * 8     2/25/99 4:19p Dave
70  * Added multiplayer_beta defines. Added cd_check define. Fixed a few
71  * release build warnings. Added more data to the squad war request and
72  * response packets.
73  * 
74  * 7     1/07/99 9:07a Jasen
75  * HUD coords
76  * 
77  * 6     12/30/98 7:47a Jasen
78  * added coordinates for hi res
79  * 
80  * 5     12/28/98 3:17p Dave
81  * Support for multiple hud bitmap filenames for hi-res mode.
82  * 
83  * 4     12/21/98 5:02p Dave
84  * Modified all hud elements to be multi-resolution friendly.
85  * 
86  * 3     11/05/98 5:55p Dave
87  * Big pass at reducing #includes
88  * 
89  * 2     10/07/98 10:53a Dave
90  * Initial checkin.
91  * 
92  * 1     10/07/98 10:49a Dave
93  * 
94  * 55    8/25/98 1:48p Dave
95  * First rev of EMP effect. Player side stuff basically done. Next comes
96  * AI code.
97  * 
98  * 54    5/11/98 3:48p Lawrance
99  * Break lock when banks switch
100  * 
101  * 53    5/10/98 7:05p Dave
102  * Fix endgame sequencing ESC key. Changed how host options warning popups
103  * are done. Fixed pause/message scrollback/options screen problems in mp.
104  * Make sure observer HUD doesn't try to lock weapons.
105  * 
106  * 52    5/04/98 10:50p Lawrance
107  * Don't break lock when switching to secondary weapons of the same type
108  * 
109  * 51    4/20/98 12:36a Mike
110  * Make team vs. team work when player is hostile.  Several targeting
111  * problems.
112  * 
113  * 50    4/15/98 12:55a Lawrance
114  * Make shockwave damage 1/4 if bomb detonated by another weapon.  Allow
115  * missiles to lock on bombs.
116  * 
117  * 49    4/13/98 4:52p Allender
118  * remove AI_frametime and us flFrametime instead.  Make lock warning work
119  * in multiplayer for aspect seeking missiles.  Debris fixups
120  * 
121  * 48    4/08/98 8:33p Lawrance
122  * Make player re-acquire lock when targeting subsystems on a locked ship.
123  * 
124  * 47    4/03/98 10:29a Mike
125  * Make aspect seekers home on a ship even if the targeted subsystem is
126  * backfacing.  Too confusing.
127  * 
128  * 46    3/26/98 5:46p Lawrance
129  * call obj_team() instead of ship_team_from_obj()
130  * 
131  * 45    3/26/98 5:26p John
132  * added new paging code. nonfunctional.
133  * 
134  * 44    3/10/98 4:19p John
135  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
136  * & Glide have popups and print screen.  Took out all >8bpp software
137  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
138  * support Fred.  Made zbuffering key off of functions rather than one
139  * global variable.
140  * 
141  * 43    3/10/98 11:16a Lawrance
142  * Fix potential bug with missles not locking on a subsystem that appeared
143  * in view
144  * 
145  * 42    2/28/98 7:03p Lawrance
146  * Change player missile locking to use dot product, so we can use it in
147  * the external views
148  * 
149  * 41    2/22/98 4:17p John
150  * More string externalization classification... 190 left to go!
151  * 
152  * 40    1/25/98 10:31p Lawrance
153  * Don't draw most hud gauges when viewing from another ship.
154  * 
155  * 39    1/24/98 4:48p Lawrance
156  * Add 'locking_subsys_parent', needed to save/restore locking_subsys
157  * pointer.
158  * 
159  * 38    1/23/98 6:25p Lawrance
160  * Change player missile locking to lock on subsystem points automatically
161  * 
162  * 37    1/21/98 7:20p Lawrance
163  * Make subsystem locking only work with line-of-sight, cleaned up locking
164  * code, moved globals to player struct.
165  * 
166  * 36    1/19/98 10:02p Lawrance
167  * Fix bug with locking on friendlies
168  * 
169  * 35    12/30/97 4:28p Lawrance
170  * remove .ani extensions from filenames
171  * 
172  * 34    12/10/97 9:57a Lawrance
173  * allow missile locks on all ships but friendly
174  * 
175  * 33    11/17/97 6:37p Lawrance
176  * new gauges: extended target view, new lock triangles, support ship view
177  * 
178  * 32    11/17/97 5:51p Lawrance
179  * fix bug that was sometimes causing lock to not occur
180  * 
181  * 31    11/13/97 10:46p Lawrance
182  * ensure only attempt lock on HOSTILE
183  * 
184  * 30    11/11/97 12:59a Lawrance
185  * fix couple of bugs with lock indicator not going away
186  * 
187  * 29    11/08/97 11:07p Lawrance
188  * add in new lock indicator
189  * 
190  * 28    10/28/97 9:02a Lawrance
191  * don't loop lock sound, some minor reformatting
192  * 
193  * 27    10/08/97 5:07p Lawrance
194  * don't lock on friendly ships
195  * 
196  * 26    9/07/97 10:02p Lawrance
197  * don't lock on a ship if player doesn't have any missiles
198  * 
199  * 25    7/02/97 9:35a Hoffoss
200  * Changed all references to weapon variables in ships to 'weapons'
201  * structure variables in ships.
202  * 
203  * 24    6/05/97 1:07a Lawrance
204  * changes to support sound interface
205  * 
206  * 23    5/20/97 2:45p Mike
207  * Move current_target and a bunch of other stuff out of player struct.
208  * 
209  * 22    4/24/97 10:55a Lawrance
210  * added Show_lock_cone to DCF
211  * 
212  * 21    4/18/97 2:54p Lawrance
213  * sounds now have a default volume, when playing, pass a scaling factor
214  * not the actual volume
215  * 
216  * 20    4/15/97 8:36a Lawrance
217  * fixed bug where lock indicator was lagging locked target
218  * 
219  * 19    4/13/97 3:53p Lawrance
220  * separate out the non-rendering dependant portions of the HUD ( sounds,
221  * updating lock position, changing targets, etc) and put into
222  * hud_update_frame()
223  * 
224  * 18    4/12/97 4:29p Lawrance
225  * get missle locking and offscreen indicator working properly with
226  * different sized screens
227  * 
228  * 17    4/10/97 5:29p Lawrance
229  * hud rendering split up into hud_render_3d(), hud_render_2d() and
230  * hud_render_target_model()
231  * 
232  * 16    4/09/97 4:34p Lawrance
233  * allow looped sounds to be cut off after they complete the full sample
234  * duration
235  * 
236  * 15    3/25/97 8:17p Lawrance
237  * don't allow ASPECT homing missles to lock on debris
238  * 
239  * 14    3/19/97 5:53p Lawrance
240  * integrating new Misc_sounds[] array (replaces old Game_sounds
241  * structure)
242  * 
243  * 13    3/10/97 8:53a Lawrance
244  * using hud_stop_looped_locking_sounds() in place of
245  * hud_stop_looped_sounds()
246  * 
247  * 12    3/07/97 4:37p Mike
248  * Make rockeye missile home.
249  * Remove UNKNOWN and NEUTRAL teams.
250  * 
251  * 11    3/04/97 2:27p Lawrance
252  * check to ensure player ship has missile banks
253  * 
254  * 10    3/04/97 11:19a Lawrance
255  * supporting banked weapons
256  * 
257  * 9     1/23/97 12:00p Lawrance
258  * made lock sound play at normal volume.
259  * 
260  * 8     1/20/97 7:58p John
261  * Fixed some link errors with testcode.
262  * 
263  * 7     1/13/97 5:36p Lawrance
264  * integrating new Game_sounds structure for general game sounds
265  * 
266  * 6     1/06/97 10:43p Lawrance
267  * Changes to make save/restore functional
268  * 
269  * 5     1/02/97 7:12p Lawrance
270  * adding hooks for more sounds
271  * 
272  * 4     1/02/97 10:32a Lawrance
273  * fixed some bugs related to stopping looped sounds when targets die and
274  * going to menus
275  * 
276  * 3     12/24/96 4:32p Lawrance
277  * some minor improvements
278  * 
279  * 2     12/23/96 7:53p Lawrance
280  * missile locking working in new source files
281  *
282  * $NoKeywords: $
283  */
284
285 #include "hud.h"
286 #include "hudlock.h"
287 #include "hudtarget.h"
288 #include "hudreticle.h"
289 #include "player.h"
290 #include "ship.h"
291 #include "weapon.h"
292 #include "sound.h"
293 #include "timer.h"
294 #include "freespace.h"
295 #include "gamesequence.h"
296 #include "gamesnd.h"
297 #include "ai.h"
298 #include "bmpman.h"
299 #include "3d.h"
300 #include "linklist.h"
301 #include "multi.h"
302 #include "emp.h"
303
304
305 static float Lock_start_dist;
306 static int Rotate_time_id = 1;  // timer id for controlling how often to rotate triangles around lock indicator
307
308 int Missile_track_loop = -1;
309 int Missile_lock_loop = -1;
310
311 int Lock_target_box_width[GR_NUM_RESOLUTIONS] = {
312         19,
313         30
314 };
315 int Lock_target_box_height[GR_NUM_RESOLUTIONS] = {
316         19,
317         30
318 };
319
320 // the locked triangles (that orbit lock indicator) dimensions
321 float Lock_triangle_base[GR_NUM_RESOLUTIONS] = {
322         4.0f,
323         6.5f
324 };
325 float Lock_triangle_height[GR_NUM_RESOLUTIONS] = {
326         4.0f,
327         6.5f
328 };
329
330 int Lock_gauge_half_w[GR_NUM_RESOLUTIONS] = {
331 #ifdef MAKE_FS1
332         15,
333 #else
334         17,     
335 #endif
336         28
337 };
338 int Lock_gauge_half_h[GR_NUM_RESOLUTIONS] = {
339         15, 
340         25
341 };
342
343 // hud_frames Lock_gauge;
344 int Lock_gauge_loaded = 0;
345 hud_anim Lock_gauge;
346 int Lock_gauge_draw = 0;
347 int Lock_gauge_draw_stamp = -1;
348 #define LOCK_GAUGE_BLINK_RATE                   5                       // blinks/sec
349
350 int Lockspin_half_w[GR_NUM_RESOLUTIONS] = {
351 #ifdef MAKE_FS1
352         16,
353 #else
354         31,
355 #endif
356         50
357 };
358 int Lockspin_half_h[GR_NUM_RESOLUTIONS] = {
359 #ifdef MAKE_FS1
360         16,
361 #else
362         32, 
363 #endif
364         52
365 };
366 hud_anim        Lock_anim;
367
368 char Lock_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
369         "lock1",
370         "2_lock1"
371 };
372
373 char Lockspin_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
374         "lockspin",
375         "2_lockspin"
376 };
377
378 void hud_lock_determine_lock_point(vector *lock_world_pos_out);
379
380 // hud_init_missile_lock() is called at the beginning of a mission
381 //
382 void hud_init_missile_lock()
383 {
384         Players[Player_num].lock_indicator_start_x = -1;
385         Players[Player_num].lock_indicator_start_y = -1;
386         Players[Player_num].lock_indicator_visible = 0;
387         Player_ai->current_target_is_locked = 0;
388
389         Player_ai->last_secondary_index = -1;
390
391         Rotate_time_id = 1;
392
393         // Load in the frames need for the lead indicator
394         if (!Lock_gauge_loaded) {
395                 /*
396                 Lock_gauge.first_frame = bm_load_animation(Lock_fname[gr_screen.res], &Lock_gauge.num_frames);
397                 if ( Lock_gauge.first_frame < 0 ) {
398                         Warning(LOCATION,"Cannot load hud ani: Lock_fname[gr_screen.res]\n");
399                 }
400                 */
401                 hud_anim_init(&Lock_gauge, 0, 0, Lock_fname[gr_screen.res]);
402                 hud_anim_load(&Lock_gauge);
403
404                 hud_anim_init(&Lock_anim, 0, 0, Lockspin_fname[gr_screen.res]);
405                 hud_anim_load(&Lock_anim);
406
407                 Lock_gauge_loaded = 1;
408                 
409                 Lock_gauge_draw_stamp = -1;
410                 Lock_gauge_draw = 0;
411         }
412 }
413
414 void hud_draw_diamond(int x, int y, int width, int height)
415 {
416         SDL_assert(height>0);
417         SDL_assert(width>0);
418
419         int x1,x2,x3,x4,y1,y2,y3,y4;
420
421         x1=x;
422         y1=y-height/2;
423
424         x2=x+width/2;
425         y2=y;
426
427         x3=x;
428         y3=y+height/2;
429
430         x4=x-width/2;
431         y4=y;
432
433         gr_line(x1,y1,x2,y2);
434         gr_line(x2,y2,x3,y3);
435         gr_line(x3,y3,x4,y4);
436         gr_line(x4,y4,x1,y1);
437 }
438
439
440 // hud_show_lock_indicator() will display the lock indicator for homing missiles
441 void hud_show_lock_indicator(float frametime)
442 {
443         int                     target_objnum, sx, sy;
444         object          *targetp;
445
446         if (!Players[Player_num].lock_indicator_visible){
447                 return;
448         }
449
450         target_objnum = Player_ai->target_objnum;
451         SDL_assert(target_objnum != -1);
452         targetp = &Objects[target_objnum];
453
454         // check to see if there are any missile to fire.. we don't want to show the 
455         // lock indicator if there are missiles to fire.
456         if ( !ship_secondary_bank_has_ammo(Player_obj->instance) ) {
457                 return;
458         }
459         
460         hud_set_iff_color(targetp);
461 //      nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy));
462
463         if (Player_ai->current_target_is_locked) {
464                 sx = Player->current_target_sx;
465                 sy = Player->current_target_sy;
466                 // show the rotating triangles if target is locked
467                 hud_draw_lock_triangles(sx, sy, frametime);
468         } else {
469                 sx = Players[Player_num].lock_indicator_x;
470                 sy = Players[Player_num].lock_indicator_y;
471         }
472
473         // show locked indicator
474         /*
475         if ( Lock_gauge.first_frame >= 0 ) {
476                 gr_set_bitmap(Lock_gauge.first_frame);
477                 gr_aabitmap(sx - Lock_gauge_half_w[gr_screen.res], sy - Lock_gauge_half_h[gr_screen.res]);
478         } else {
479                 hud_draw_diamond(sx, sy, Lock_target_box_width[gr_screen.res], Lock_target_box_height[gr_screen.res]);
480         }
481         */
482         Lock_gauge.sx = sx - Lock_gauge_half_w[gr_screen.res];
483         Lock_gauge.sy = sy - Lock_gauge_half_h[gr_screen.res];
484         if(Player_ai->current_target_is_locked){
485                 Lock_gauge.time_elapsed = 0.0f;                 
486                 hud_anim_render(&Lock_gauge, 0.0f, 1);          
487         } else {
488                 hud_anim_render(&Lock_gauge, frametime, 1);
489         }
490 }
491
492 // Reset data used for player lock indicator
493 void hud_lock_reset(float lock_time_scale)
494 {
495         weapon_info     *wip;
496         ship_weapon     *swp;
497
498         swp = &Player_ship->weapons;
499         wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
500
501         Player_ai->current_target_is_locked = 0;
502         Players[Player_num].lock_indicator_visible = 0;
503         Player->target_in_lock_cone = 0;
504         Player->lock_time_to_target = i2fl(wip->min_lock_time*lock_time_scale);
505         Player->current_target_sx = -1;
506         Player->current_target_sy = -1;
507         Player->locking_subsys=NULL;
508         Player->locking_on_center=0;
509         Player->locking_subsys_parent=-1;
510         hud_stop_looped_locking_sounds();
511
512         Lock_gauge_draw_stamp = -1;
513         Lock_gauge_draw = 0;
514
515         // reset the lock anim time elapsed
516         Lock_anim.time_elapsed = 0.0f;
517 }
518
519 // Determine if the locking code has a point to track
520 int hud_lock_has_homing_point()
521 {
522         if ( Player_ai->targeted_subsys || Player->locking_subsys || Player->locking_on_center ) {
523                 return 1;
524         }
525         return 0;
526 }
527
528 int Nebula_sec_range = 0;
529 DCF_BOOL(nebula_sec_range, Nebula_sec_range)
530
531 int hud_lock_world_pos_in_range(vector *target_world_pos, vector *vec_to_target)
532 {
533         float                   dist_to_target, weapon_range;
534         weapon_info     *wip;
535         ship_weapon     *swp;
536
537         int target_in_range=1;
538
539         swp = &Player_ship->weapons;
540         wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
541
542         vm_vec_sub(vec_to_target, target_world_pos, &Player_obj->pos);
543         dist_to_target = vm_vec_mag(vec_to_target);
544
545         // calculate the range of the weapon, and only display the lead target indicator when
546         // if the weapon can actually hit the target
547         weapon_range = wip->max_speed * wip->lifetime;
548
549         // reduce firing range in nebula
550         if ((The_mission.flags & MISSION_FLAG_FULLNEB) && Nebula_sec_range) {
551                 weapon_range *= 0.8f;
552         }
553
554         if (dist_to_target > weapon_range) {
555                 target_in_range=0;
556         }
557
558         return target_in_range;
559 }
560
561 // Determine if point to lock on is in range
562 int hud_lock_target_in_range()
563 {
564         vector          target_world_pos, vec_to_target;
565         object          *targetp;
566
567         if ( !hud_lock_has_homing_point() ) {
568                 return 0;
569         }
570
571         targetp = &Objects[Player_ai->target_objnum];
572
573         if ( Player_ai->targeted_subsys != NULL ) {
574                 vm_vec_unrotate(&target_world_pos, &Player_ai->targeted_subsys->system_info->pnt, &targetp->orient);
575                 vm_vec_add2(&target_world_pos, &targetp->pos);
576         } else {
577                 if ( Player->locking_subsys ) {
578                         vm_vec_unrotate(&target_world_pos, &Player->locking_subsys->system_info->pnt, &targetp->orient);
579                         vm_vec_add2(&target_world_pos, &targetp->pos);
580                 } else {
581                         SDL_assert(Player->locking_on_center);
582                         target_world_pos = targetp->pos;
583                 }
584         }
585
586         return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
587 }
588
589 int hud_abort_lock()
590 {
591         int target_team;
592
593         target_team = obj_team(&Objects[Player_ai->target_objnum]);
594
595         if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
596                 return 1;
597         }
598
599         if ( Player_ship->weapons.current_secondary_bank < 0 ) {
600                 return 1;
601         }
602
603         // check to see if there are any missile to fire.. we don't want to show the 
604         // lock indicator if there are no missiles to fire.
605         if ( !ship_secondary_bank_has_ammo(Player_obj->instance) ) {
606                 return 1;
607         }
608
609         // if the target is friendly, don't lock!
610         if ( hud_team_matches_filter(Player_ship->team, target_team)) {
611                 // if we're in multiplayer dogfight, ignore this
612                 if(!((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT))){
613                         return 1;
614                 }
615         }
616
617         return 0;
618 }
619
620 // determine if the subsystem to lock on to has a direct line of sight
621 int hud_lock_on_subsys_ok()
622 {
623         ship_subsys             *subsys;
624         vector                  subobj_pos;
625         object                  *target_objp;
626         int                             in_sight=0;
627         
628         SDL_assert(Player_ai->target_objnum >= 0);
629         target_objp     = &Objects[Player_ai->target_objnum];
630
631         subsys = Player_ai->targeted_subsys;
632         if ( !subsys ) {
633                 return 0;
634         }
635
636         vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient);
637         vm_vec_add2(&subobj_pos, &target_objp->pos);
638
639         if ( Player->subsys_in_view < 0 ) {
640                 in_sight = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos);
641         } else {
642                 in_sight = Player->subsys_in_view;
643         }
644
645         return in_sight;
646 }
647
648 // Determine if locking point is in the locking cone
649 void hud_lock_check_if_target_in_lock_cone(vector *lock_world_pos)
650 {
651         float           dot;
652         vector  vec_to_target;
653
654         vm_vec_normalized_dir(&vec_to_target, lock_world_pos, &Player_obj->pos);
655         dot = vm_vec_dot(&Player_obj->orient.v.fvec, &vec_to_target);
656
657         if ( dot > 0.85) {
658                 Player->target_in_lock_cone = 1;
659         } else {
660                 Player->target_in_lock_cone = 0;
661         }
662
663 }
664
665 // return 1 if current secondary weapon is different than previous secondary weapon
666 int hud_lock_secondary_weapon_changed(ship_weapon *swp)
667 {
668
669         if ( swp->current_secondary_bank != Player_ai->last_secondary_index ) {
670                 return 1;
671         }
672
673         return 0;
674 /*
675         int last_wi_index = -1;
676         int current_wi_index = -1;
677
678
679         // do a quick out if same bank is selected
680         if ( swp->current_secondary_bank == Player_ai->last_secondary_index ) {
681                 return 0;
682         }
683
684         // bank has changed, but it still may be the same weapon type
685         if ( swp->current_secondary_bank >= 0 ) {
686                 current_wi_index = swp->secondary_bank_weapons[swp->current_secondary_bank];
687         }
688
689         if ( Player_ai->last_secondary_index >= 0 ) {
690                 last_wi_index = swp->secondary_bank_weapons[Player_ai->last_secondary_index];
691         }
692
693         if ( current_wi_index != last_wi_index ) {
694                 return 1;
695         }
696
697         return 0;
698 */
699
700 }
701
702 // hud_update_lock_indicator() will manage the non-rendering dependant part of
703 // missle locking
704 void hud_update_lock_indicator(float frametime)
705 {
706         ship_weapon *swp;
707         weapon_info     *wip;
708         vector          lock_world_pos;
709
710         // if i'm a multiplayer observer, bail here
711         if((Game_mode & GM_MULTIPLAYER) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
712                 return;
713         }
714
715         SDL_assert(Player_ai->target_objnum != -1);
716
717         // be sure to unset this flag, then possibly set later in this function so that
718         // threat indicators work properly.
719         Player_ai->ai_flags &= ~AIF_SEEK_LOCK;
720
721         if ( hud_abort_lock() ) {
722                 hud_lock_reset();
723                 return;
724         }
725
726         // if there is an EMP effect active, never update lock
727         if(emp_active_local()){
728                 hud_lock_reset();
729                 return;
730         }
731
732         swp = &Player_ship->weapons;
733         wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
734
735         Lock_start_dist = wip->min_lock_time * wip->lock_pixels_per_sec;
736
737         // if secondary weapons change, reset the lock
738         if ( hud_lock_secondary_weapon_changed(swp) ) {
739                 hud_lock_reset();
740         }
741                 
742         Player_ai->last_secondary_index = swp->current_secondary_bank;
743
744         if ( !(wip->wi_flags & WIF_HOMING_ASPECT) ) {
745                 hud_lock_reset();
746                 return;         
747         }
748
749         // Allow locking on ships and bombs (only targeted weapon allowed is a bomb, so don't bother checking flags)
750         if ( (Objects[Player_ai->target_objnum].type != OBJ_SHIP) && (Objects[Player_ai->target_objnum].type != OBJ_WEAPON) ) { 
751                 hud_lock_reset();
752                 return;
753         }
754
755         hud_lock_determine_lock_point(&lock_world_pos);
756
757         if ( !hud_lock_has_homing_point() ) {
758                 Player->target_in_lock_cone=0;
759         }
760
761         hud_lock_check_if_target_in_lock_cone(&lock_world_pos);
762
763         // check if the target is within range of the current secondary weapon.  If it is not,
764         // a lock will not be detected
765         if ( !hud_lock_target_in_range() ) {
766                 Player->target_in_lock_cone = 0;
767         }
768
769         // If locking on a subsystem, and not in sight... can't lock
770         //      Changed by MK on 4/3/98.  It was confusing me that my hornets would not lock on my target.
771         //      It will now be confusing that they lock, but don't home on your subsystem, but I think that's preferable.
772         //      Often you really care about destroying the target, not just the subsystem.
773         /*if ( Player_ai->targeted_subsys ) {
774                 if ( !hud_lock_on_subsys_ok() ) {
775                         Player->target_in_lock_cone=0;
776                 }
777         }*/
778
779         if ( !Player->target_in_lock_cone ) {
780                 Player->locking_on_center=0;
781                 Player->locking_subsys_parent=-1;
782                 Player->locking_subsys=NULL;
783         }
784                 
785         hud_calculate_lock_position(frametime);
786
787         if (!Players[Player_num].lock_indicator_visible)
788                 return;
789
790         if (Player_ai->current_target_is_locked) {
791                 if ( Missile_track_loop > -1 )  {
792                         snd_chg_loop_status(Missile_track_loop, 0);
793                         Missile_track_loop = -1;
794                         Missile_lock_loop = snd_play(&Snds[SND_MISSILE_LOCK]);
795                 }
796         }
797         else {
798                 Player_ai->ai_flags |= AIF_SEEK_LOCK;           // set this flag so multiplayer's properly track lock on other ships
799                 if ( Missile_lock_loop != -1 && snd_is_playing(Missile_lock_loop) ) {
800                         snd_stop(Missile_lock_loop);
801                         Missile_lock_loop = -1;
802                 }
803         }
804 }
805
806 // hud_draw_lock_triangles() will draw the 4 rotating triangles around a lock indicator
807 // (This is done when a lock has been acquired)
808 #define ROTATE_DELAY 40
809 void hud_draw_lock_triangles_old(int center_x, int center_y, int radius)
810 {
811         static float ang = 0.0f;
812
813         float end_ang = ang + 2*PI;
814         float x3,y3,x4,y4,xpos,ypos;
815
816         if ( timestamp_elapsed(Rotate_time_id) ) {
817                 Rotate_time_id = timestamp(ROTATE_DELAY);
818                 ang += PI/12;
819         }
820
821         for (; ang <= end_ang; ang += PI/2.0f) {
822
823                 // draw the orbiting triangles
824
825                 //ang = atan2(target_point.y,target_point.x);
826                 xpos = center_x + (float)cos(ang)*(radius + Lock_triangle_height[gr_screen.res] + 2);
827                 ypos = center_y - (float)sin(ang)*(radius + Lock_triangle_height[gr_screen.res] + 2);
828                         
829                 x3 = xpos - Lock_triangle_base[gr_screen.res] * (float)sin(-ang);
830                 y3 = ypos + Lock_triangle_base[gr_screen.res] * (float)cos(-ang);
831                 x4 = xpos + Lock_triangle_base[gr_screen.res] * (float)sin(-ang);
832                 y4 = ypos - Lock_triangle_base[gr_screen.res] * (float)cos(-ang);
833
834                 xpos = xpos - Lock_triangle_base[gr_screen.res] * (float)cos(ang);
835                 ypos = ypos + Lock_triangle_base[gr_screen.res] * (float)sin(ang);
836
837                 hud_tri(x3, y3, xpos, ypos, x4, y4);
838         } // end for
839 }
840
841 // draw a frame of the rotating lock triangles animation
842 void hud_draw_lock_triangles(int center_x, int center_y, float frametime)
843 {
844         if ( Lock_anim.first_frame == -1 ) {
845                 hud_draw_lock_triangles_old(center_x, center_y, Lock_target_box_width[gr_screen.res]/2);
846         } else {
847                 // render the anim
848                 Lock_anim.sx = center_x - Lockspin_half_w[gr_screen.res];
849                 Lock_anim.sy = center_y - Lockspin_half_h[gr_screen.res];
850
851                 // if its still animating
852                 if(Lock_anim.time_elapsed < Lock_anim.total_time){
853 #ifdef MAKE_FS1
854                         // loop it
855                         hud_anim_render(&Lock_anim, frametime, 1, 1, 0);
856 #else
857                         hud_anim_render(&Lock_anim, frametime, 1, 0, 1);
858 #endif
859                 } else {
860                         // if the timestamp is unset or expired
861                         if((Lock_gauge_draw_stamp < 0) || timestamp_elapsed(Lock_gauge_draw_stamp)){
862                                 // reset timestamp
863                                 Lock_gauge_draw_stamp = timestamp(1000 / (2 * LOCK_GAUGE_BLINK_RATE));
864
865                                 // switch between draw and dont-draw
866                                 Lock_gauge_draw = !Lock_gauge_draw;
867                         }
868
869                         // maybe draw the anim
870                         Lock_gauge.time_elapsed = 0.0f;                 
871                         if(Lock_gauge_draw){
872 #ifdef MAKE_FS1
873                                 // loop it
874                                 hud_anim_render(&Lock_anim, frametime, 1, 1, 0);
875 #else
876                                 hud_anim_render(&Lock_anim, frametime, 1, 0, 1);
877 #endif
878                         }                       
879                 }               
880         }
881 }
882
883 // hud_calculate_lock_position()  will determine where on the screen to draw the lock 
884 // indicator, and will determine when a lock has occurred.  If the lock indicator is not
885 // on the screen yet, hud_calculate_lock_start_pos() is called to pick a starting location
886 void hud_calculate_lock_position(float frametime)
887 {
888         ship_weapon *swp;
889         weapon_info     *wip;
890
891         static float pixels_moved_while_locking;
892         static float pixels_moved_while_degrading;
893         static int Need_new_start_pos = 0;
894
895         static double accumulated_x_pixels, accumulated_y_pixels;
896         double int_portion;
897
898         static float last_dist_to_target;
899         
900         static int catching_up;
901
902         static int maintain_lock_count = 0;
903
904         static float catch_up_distance = 0.0f;
905
906         float hypotenuse, delta_x, delta_y;
907
908         swp = &Player_ship->weapons;
909         wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
910
911         if (Player->target_in_lock_cone) {
912                 if (!Players[Player_num].lock_indicator_visible) {
913                         hud_calculate_lock_start_pos();
914                         last_dist_to_target = 0.0f;
915
916                         Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x;
917                         Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y;
918                         Players[Player_num].lock_indicator_visible = 1;
919
920                         Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time);
921                         catching_up = 0;
922                 }
923
924                 Need_new_start_pos = 1;
925
926                 if (Player_ai->current_target_is_locked) {
927                         Players[Player_num].lock_indicator_x = Player->current_target_sx;
928                         Players[Player_num].lock_indicator_y = Player->current_target_sy;
929                         return;
930                 }
931
932                 delta_x = i2fl(Players[Player_num].lock_indicator_x - Player->current_target_sx);
933                 delta_y = i2fl(Players[Player_num].lock_indicator_y - Player->current_target_sy);
934
935                 if (!delta_y && !delta_x) {
936                         hypotenuse = 0.0f;
937                 }
938                 else {
939                         hypotenuse = hypotf(delta_y, delta_x);
940                 }
941
942                 Players[Player_num].lock_dist_to_target = hypotenuse;
943
944                 if (last_dist_to_target == 0) {
945                         last_dist_to_target = Players[Player_num].lock_dist_to_target;
946                 }
947
948                 //nprintf(("Alan","dist to target: %.2f\n",Players[Player_num].lock_dist_to_target));
949                 //nprintf(("Alan","last to target: %.2f\n\n",last_dist_to_target));
950
951                 if (catching_up) {
952                         //nprintf(("Alan","IN CATCH UP MODE  catch_up_dist is %.2f\n",catch_up_distance));      
953                         if ( Players[Player_num].lock_dist_to_target < catch_up_distance )
954                                 catching_up = 0;
955                 }
956                 else {
957                         //nprintf(("Alan","IN NORMAL MODE\n"));
958                         if ( (Players[Player_num].lock_dist_to_target - last_dist_to_target) > 2.0f ) {
959                                 catching_up = 1;
960                                 catch_up_distance = last_dist_to_target + wip->catchup_pixel_penalty;
961                         }
962                 }
963
964                 last_dist_to_target = Players[Player_num].lock_dist_to_target;
965
966                 if (!catching_up) {
967                         Players[Player_num].lock_time_to_target -= frametime;
968                         if (Players[Player_num].lock_time_to_target < 0.0f)
969                                 Players[Player_num].lock_time_to_target = 0.0f;
970                 }
971
972                 float lock_pixels_per_sec;
973                 if (Players[Player_num].lock_time_to_target > 0) {
974                         lock_pixels_per_sec = Players[Player_num].lock_dist_to_target / Players[Player_num].lock_time_to_target;
975                 } else {
976                         lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec);
977                 }
978
979                 if (lock_pixels_per_sec > wip->lock_pixels_per_sec) {
980                         lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec);
981                 }
982                 
983                 if (catching_up) {
984                         pixels_moved_while_locking = wip->catchup_pixels_per_sec * frametime;
985                 } else {
986                         pixels_moved_while_locking = lock_pixels_per_sec * frametime;
987                 }
988                 
989                 if (delta_x != 0.0f) {
990                         accumulated_x_pixels += pixels_moved_while_locking * delta_x/hypotenuse; 
991                 }
992
993                 if (delta_y != 0.0f) {
994                         accumulated_y_pixels += pixels_moved_while_locking * delta_y/hypotenuse; 
995                 }
996
997                 if (fl_abs(accumulated_x_pixels) > 1.0f) {
998                         modf(accumulated_x_pixels, &int_portion);
999
1000                         Players[Player_num].lock_indicator_x -= (int)int_portion;
1001
1002                         if ( fl_abs(Players[Player_num].lock_indicator_x - Player->current_target_sx) < fl_abs(int_portion) )
1003                                 Players[Player_num].lock_indicator_x = Player->current_target_sx;
1004
1005                         accumulated_x_pixels -= int_portion;
1006                 }
1007
1008                 if (fl_abs(accumulated_y_pixels) > 1.0f) {
1009                         modf(accumulated_y_pixels, &int_portion);
1010
1011                         Players[Player_num].lock_indicator_y -= (int)int_portion;
1012
1013                         if ( fl_abs(Players[Player_num].lock_indicator_y - Player->current_target_sy) < fl_abs(int_portion) )
1014                                 Players[Player_num].lock_indicator_y = Player->current_target_sy;
1015
1016                         accumulated_y_pixels -= int_portion;
1017                 }
1018
1019                 if ( Missile_track_loop == -1 ) {       
1020                         Missile_track_loop = snd_play_looping( &Snds[SND_MISSILE_TRACKING], 0.0f);
1021                 }
1022
1023                 if (!Players[Player_num].lock_time_to_target) {
1024                         if ( (Players[Player_num].lock_indicator_x == Player->current_target_sx) && (Players[Player_num].lock_indicator_y == Player->current_target_sy) ) {
1025                                 if (maintain_lock_count++ > 1) {
1026                                         Player_ai->current_target_is_locked = 1;
1027                                 }
1028                         } else {
1029                                 maintain_lock_count = 0;
1030                         }
1031                 }
1032
1033         } else {
1034
1035                 if ( Missile_track_loop > -1 )  {
1036                         snd_chg_loop_status(Missile_track_loop, 0);
1037                         Missile_track_loop = -1;
1038                 }
1039
1040                 Player_ai->current_target_is_locked = 0;
1041
1042                 if (!Players[Player_num].lock_indicator_visible) {
1043                         return;
1044                 }
1045
1046                 catching_up = 0;
1047                 last_dist_to_target = 0.0f;
1048
1049                 if (Need_new_start_pos) {
1050                         hud_calculate_lock_start_pos();
1051                         Need_new_start_pos = 0;
1052                         accumulated_x_pixels = 0.0f;
1053                         accumulated_y_pixels = 0.0f;
1054                 }
1055
1056                 delta_x = i2fl(Players[Player_num].lock_indicator_x - Players[Player_num].lock_indicator_start_x);
1057                 delta_y = i2fl(Players[Player_num].lock_indicator_y - Players[Player_num].lock_indicator_start_y);
1058
1059                 if (!delta_y && !delta_x) {
1060                         hypotenuse = 0.0f;
1061                 }
1062                 else {
1063                         hypotenuse = hypotf(delta_y, delta_x);
1064                 }
1065
1066                 Players[Player_num].lock_time_to_target += frametime;
1067
1068                 if (Players[Player_num].lock_time_to_target > wip->min_lock_time)
1069                         Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time);
1070
1071                 pixels_moved_while_degrading = 2.0f * wip->lock_pixels_per_sec * frametime;
1072
1073                 if (delta_x != 0.0f)
1074                         accumulated_x_pixels += pixels_moved_while_degrading * delta_x/hypotenuse; 
1075
1076                 if (delta_y != 0.0f)
1077                         accumulated_y_pixels += pixels_moved_while_degrading * delta_y/hypotenuse; 
1078
1079                 if (fl_abs(accumulated_x_pixels) > 1.0f) {
1080                         modf(accumulated_x_pixels, &int_portion);
1081
1082                         Players[Player_num].lock_indicator_x -= (int)int_portion;
1083
1084                         if ( fl_abs(Players[Player_num].lock_indicator_x - Players[Player_num].lock_indicator_start_x) < fl_abs(int_portion) )
1085                                 Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x;
1086
1087                         accumulated_x_pixels -= int_portion;
1088                 }
1089
1090                 if (fl_abs(accumulated_y_pixels) > 1.0f) {
1091                         modf(accumulated_y_pixels, &int_portion);
1092
1093                         Players[Player_num].lock_indicator_y -= (int)int_portion;
1094
1095                         if ( fl_abs(Players[Player_num].lock_indicator_y - Players[Player_num].lock_indicator_start_y) < fl_abs(int_portion) )
1096                                 Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y;
1097
1098                         accumulated_y_pixels -= int_portion;
1099                 }
1100
1101                 if ( (Players[Player_num].lock_indicator_x == Players[Player_num].lock_indicator_start_x) && (Players[Player_num].lock_indicator_y == Players[Player_num].lock_indicator_start_y) ) {
1102                         Players[Player_num].lock_indicator_visible = 0;
1103                 }
1104         }
1105 }
1106
1107 // hud_calculate_lock_start_pos() will determine where to draw the starting location of the lock
1108 // indicator.  It does this by picking a location that is Lock_start_dist pixels away from the current
1109 // target (in 2D).  This is accomplished by finding the endpoint of a line that passes through the 
1110 // origin, and connects the target and lock indicator postion (and has a magnitude of Lock_start_dist)
1111 void hud_calculate_lock_start_pos()
1112 {
1113         float hypotenuse;
1114         float delta_y;
1115         float delta_x;
1116         float target_mag, target_x, target_y;
1117
1118         delta_x = Player->current_target_sx - SCREEN_CENTER_X;
1119         delta_y = Player->current_target_sy - SCREEN_CENTER_Y;
1120
1121         if (!delta_x && !delta_y) {
1122                 Players[Player_num].lock_indicator_start_x = fl2i(SCREEN_CENTER_X + Lock_start_dist);
1123                 Players[Player_num].lock_indicator_start_y = fl2i(SCREEN_CENTER_Y);
1124                 return;
1125         }
1126
1127         hypotenuse = hypotf(delta_y, delta_x);
1128
1129         if (hypotenuse >= Lock_start_dist) {
1130                 Players[Player_num].lock_indicator_start_x = fl2i(SCREEN_CENTER_X);
1131                 Players[Player_num].lock_indicator_start_y = fl2i(SCREEN_CENTER_Y);
1132                 return;
1133         }
1134
1135         target_mag = Lock_start_dist - hypotenuse;
1136         target_x = target_mag * (delta_x / hypotenuse);
1137         target_y = target_mag * (delta_y / hypotenuse);
1138
1139         Players[Player_num].lock_indicator_start_x = fl2i(SCREEN_CENTER_X - target_x);
1140         Players[Player_num].lock_indicator_start_y = fl2i(SCREEN_CENTER_Y - target_y);
1141
1142         if (Players[Player_num].lock_indicator_start_x > gr_screen.clip_right)
1143                 Players[Player_num].lock_indicator_start_x = gr_screen.clip_right;
1144
1145         if (Players[Player_num].lock_indicator_start_y > gr_screen.clip_bottom)
1146                 Players[Player_num].lock_indicator_start_y = gr_screen.clip_bottom;
1147
1148         if (Players[Player_num].lock_indicator_start_x < gr_screen.clip_left)
1149                 Players[Player_num].lock_indicator_start_x = gr_screen.clip_left;
1150
1151         if (Players[Player_num].lock_indicator_start_y < gr_screen.clip_top)
1152                 Players[Player_num].lock_indicator_start_y = gr_screen.clip_top;
1153 }
1154
1155 // hud_stop_looped_locking_sounds() will terminate any hud related looping sounds that are playing
1156 void hud_stop_looped_locking_sounds()
1157 {
1158         if ( Missile_track_loop > -1 )  {
1159                 snd_stop(Missile_track_loop);
1160                 Missile_track_loop = -1;
1161         }
1162 }
1163
1164 // Get a new world pos for the locking point
1165 void hud_lock_update_lock_pos(object *target_objp, vector *lock_world_pos)
1166 {
1167         if ( Player_ai->targeted_subsys ) {
1168                 get_subsystem_world_pos(target_objp, Player_ai->targeted_subsys, lock_world_pos);
1169                 return;
1170         }
1171
1172         if ( Player->locking_on_center ) {
1173                 *lock_world_pos = target_objp->pos;
1174         } else {
1175                 SDL_assert(Player->locking_subsys);
1176                 get_subsystem_world_pos(target_objp, Player->locking_subsys, lock_world_pos);
1177         }
1178 }
1179
1180 // Try and find a new locking point
1181 void hud_lock_get_new_lock_pos(object *target_objp, vector *lock_world_pos)
1182 {
1183         ship                    *target_shipp=NULL;
1184         int                     lock_in_range=0;
1185         float                   best_lock_dot=-1.0f, lock_dot=-1.0f;
1186         ship_subsys     *ss;
1187         vector          subsys_world_pos, vec_to_lock;
1188
1189         if ( target_objp->type == OBJ_SHIP ) {
1190                 target_shipp = &Ships[target_objp->instance];
1191         }
1192
1193         // if a large ship, lock to pos closest to center and within range
1194         if ( (target_shipp) && (Ship_info[target_shipp->ship_info_index].flags & (SIF_BIG_SHIP|SIF_HUGE_SHIP)) ) {
1195                 // check all the subsystems and the center of the ship
1196                 
1197                 // assume best lock pos is the center of the ship
1198                 *lock_world_pos=target_objp->pos;
1199                 Player->locking_on_center=1;
1200                 Player->locking_subsys=NULL;
1201                 Player->locking_subsys_parent=-1;
1202                 lock_in_range = hud_lock_world_pos_in_range(lock_world_pos, &vec_to_lock);
1203                 vm_vec_normalize(&vec_to_lock);
1204                 if ( lock_in_range ) {
1205                         best_lock_dot=vm_vec_dot(&Player_obj->orient.v.fvec, &vec_to_lock);
1206                 } 
1207                 // take center if reasonable dot
1208                 if ( best_lock_dot > 0.95 ) {
1209                         return;
1210                 }
1211
1212                 // iterate through subsystems to see if we can get a better choice
1213                 ss = GET_FIRST(&target_shipp->subsys_list);
1214                 while ( ss != END_OF_LIST( &target_shipp->subsys_list ) ) {
1215
1216                         // get world pos of subsystem
1217                         get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);
1218
1219                         if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
1220                                 vm_vec_normalize(&vec_to_lock);
1221                                 lock_dot=vm_vec_dot(&Player_obj->orient.v.fvec, &vec_to_lock);
1222                                 if ( lock_dot > best_lock_dot ) {
1223                                         best_lock_dot=lock_dot;
1224                                         Player->locking_on_center=0;
1225                                         Player->locking_subsys=ss;
1226                                         Player->locking_subsys_parent=Player_ai->target_objnum;
1227                                         *lock_world_pos=subsys_world_pos;
1228                                 }
1229                         }
1230                         ss = GET_NEXT( ss );
1231                 }
1232         } else {
1233                 // if small ship (or weapon), just go for the center
1234                 *lock_world_pos = target_objp->pos;
1235                 Player->locking_on_center=1;
1236                 Player->locking_subsys=NULL;
1237                 Player->locking_subsys_parent=-1;
1238         }
1239 }
1240
1241 // Decide which point lock should be homing on
1242 void hud_lock_determine_lock_point(vector *lock_world_pos_out)
1243 {
1244         vector  lock_world_pos;
1245         vertex  lock_point;
1246         object  *target_objp;
1247
1248         SDL_assert(Player_ai->target_objnum >= 0);
1249         target_objp = &Objects[Player_ai->target_objnum];
1250
1251         Player->current_target_sx = -1;
1252         Player->current_target_sx = -1;
1253
1254         // If subsystem is targeted, we must try to lock on that
1255         if ( Player_ai->targeted_subsys ) {
1256                 hud_lock_update_lock_pos(target_objp, &lock_world_pos);
1257                 Player->locking_on_center=0;
1258                 Player->locking_subsys=NULL;
1259                 Player->locking_subsys_parent=-1;
1260         } else {
1261                 // See if we already have a successful locked point
1262                 if ( hud_lock_has_homing_point() ) {
1263                         hud_lock_update_lock_pos(target_objp, &lock_world_pos);
1264                 } else {
1265                         hud_lock_get_new_lock_pos(target_objp, &lock_world_pos);
1266                 }
1267         }
1268
1269         *lock_world_pos_out=lock_world_pos;
1270
1271         g3_rotate_vertex(&lock_point,&lock_world_pos);
1272         g3_project_vertex(&lock_point);
1273
1274         if (!(lock_point.flags & PF_OVERFLOW)) {  // make sure point projected
1275                 Player->current_target_sx = (int)lock_point.sx;
1276                 Player->current_target_sy = (int)lock_point.sy;
1277         }
1278 }
1279
1280 void hudlock_page_in()
1281 {
1282         bm_page_in_aabitmap( Lock_gauge.first_frame, Lock_gauge.num_frames );
1283 }