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 the
6 * source.
7 *
8 */
9
10
11
12
13
14 #include "bmpman/bmpman.h"
15 #include "freespace.h"
16 #include "gamesnd/gamesnd.h"
17 #include "globalincs/linklist.h"
18 #include "graphics/font.h"
19 #include "graphics/matrix.h"
20 #include "iff_defs/iff_defs.h"
21 #include "io/timer.h"
22 #include "jumpnode/jumpnode.h"
23 #include "localization/localize.h"
24 #include "network/multi.h"
25 #include "object/object.h"
26 #include "playerman/player.h"
27 #include "radar/radar.h"
28 #include "ship/awacs.h"
29 #include "ship/ship.h"
30 #include "ship/subsysdamage.h"
31 #include "weapon/emp.h"
32 #include "weapon/weapon.h"
33
34 extern int radar_target_id_flags;
35
HudGaugeRadarStd()36 HudGaugeRadarStd::HudGaugeRadarStd():
37 HudGaugeRadar(HUD_OBJECT_RADAR_STD, 255, 255, 255)
38 {
39 gr_init_alphacolor( &radar_crosshairs, 255, 255, 255, 196);
40 }
41
initCenterOffsets(float x,float y)42 void HudGaugeRadarStd::initCenterOffsets(float x, float y)
43 {
44 Radar_center_offsets[0] = x;
45 Radar_center_offsets[1] = y;
46 }
47
initBitmaps(char * fname)48 void HudGaugeRadarStd::initBitmaps(char *fname)
49 {
50 Radar_gauge.first_frame = bm_load_animation(fname, &Radar_gauge.num_frames);
51 if ( Radar_gauge.first_frame < 0 ) {
52 Warning(LOCATION,"Cannot load hud ani: %s\n", fname);
53 }
54 }
55
blipDrawDistorted(blip * b,int x,int y)56 void HudGaugeRadarStd::blipDrawDistorted(blip *b, int x, int y)
57 {
58 int xdiff, ydiff;
59 float scale;
60 xdiff = Random::next(-10, 9);
61 ydiff = Random::next(-10, 9);
62
63 // maybe scale the effect if EMP is active
64 if(emp_active_local()){
65 scale = emp_current_intensity();
66
67 xdiff = (int)((float)xdiff * scale);
68 ydiff = (int)((float)ydiff * scale);
69 }
70
71 drawContactCircle(x + xdiff, y + ydiff, b->rad);
72 }
blipDrawFlicker(blip * b,int x,int y)73 void HudGaugeRadarStd::blipDrawFlicker(blip *b, int x, int y)
74 {
75 int xdiff=0, ydiff=0, flicker_index;
76
77 if ( (b-Blips) & 1 ) {
78 flicker_index=0;
79 } else {
80 flicker_index=1;
81 }
82
83 if ( timestamp_elapsed(Radar_flicker_timer[flicker_index]) ) {
84 Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000);
85 Radar_flicker_on[flicker_index] ^= 1;
86 }
87
88 if ( !Radar_flicker_on[flicker_index] ) {
89 return;
90 }
91
92 if (Random::flip_coin()) {
93 xdiff = Random::next(-2, 1);
94 ydiff = Random::next(-2, 1);
95 }
96
97 drawContactCircle(x + xdiff, y + ydiff, b->rad);
98 }
blitGauge()99 void HudGaugeRadarStd::blitGauge()
100 {
101 renderBitmap(Radar_gauge.first_frame+1, position[0], position[1] );
102 }
drawBlips(int blip_type,int bright,int distort)103 void HudGaugeRadarStd::drawBlips(int blip_type, int bright, int distort)
104 {
105 blip *b = NULL;
106 blip *blip_head = NULL;
107 int x, y;
108
109 Assert((blip_type >= 0) && (blip_type < MAX_BLIP_TYPES));
110
111
112 // Need to set font.
113 font::set_font(font::FONT1);
114
115
116 // get the appropriate blip list
117 if (bright)
118 blip_head = &Blip_bright_list[blip_type];
119 else
120 blip_head = &Blip_dim_list[blip_type];
121
122
123 // draw all blips of this type
124 for (b = GET_FIRST(blip_head); b != END_OF_LIST(blip_head); b = GET_NEXT(b))
125 {
126 gr_set_color_fast(b->blip_color);
127 plotBlip(b, &x, &y);
128
129 // maybe draw cool blip to indicate current target
130 if (b->flags & BLIP_CURRENT_TARGET)
131 {
132 b->rad = Radar_blip_radius_target;
133 current_target_x = x;
134 current_target_y = y;
135 }
136 else
137 {
138 b->rad = Radar_blip_radius_normal;
139 }
140
141 // maybe distort blip
142 if (distort)
143 {
144 blipDrawDistorted(b, x, y);
145 }
146 else if (b->flags & BLIP_DRAW_DISTORTED)
147 {
148 blipDrawFlicker(b, x, y);
149 }
150 else
151 {
152 if (b->radar_image_2d == -1 && b->radar_color_image_2d == -1)
153 drawContactCircle(x, y, b->rad);
154 else
155 drawContactImage(x, y, b->rad, b->radar_image_2d, b->radar_color_image_2d, b->radar_image_size);
156 }
157 }
158 }
drawBlipsSorted(int distort)159 void HudGaugeRadarStd::drawBlipsSorted(int distort)
160 {
161 current_target_x = 0;
162 current_target_y = 0;
163 // draw dim blips first, then bright blips
164 for (int is_bright = 0; is_bright < 2; is_bright++)
165 {
166 drawBlips(BLIP_TYPE_JUMP_NODE, is_bright, distort);
167 drawBlips(BLIP_TYPE_WARPING_SHIP, is_bright, distort);
168 drawBlips(BLIP_TYPE_NAVBUOY_CARGO, is_bright, distort);
169 drawBlips(BLIP_TYPE_NORMAL_SHIP, is_bright, distort);
170 drawBlips(BLIP_TYPE_BOMB, is_bright, distort);
171 drawBlips(BLIP_TYPE_TAGGED_SHIP, is_bright, distort);
172 }
173 // draw crosshairs last - if at all.
174 if(radar_target_id_flags & RTIF_CROSSHAIRS) {
175 drawCrosshairs(current_target_x, current_target_y);
176 }
177 }
drawContactCircle(int x,int y,int rad)178 void HudGaugeRadarStd::drawContactCircle( int x, int y, int rad )
179 {
180 if ( rad == Radar_blip_radius_target ) {
181 if (radar_target_id_flags & RTIF_BLINK) {
182 if (Missiontime & 8192)
183 return;
184 }
185 renderCircle(x, y, 6);
186 } else {
187 // rad = RADAR_BLIP_RADIUS_NORMAL;
188 renderCircle(x, y, 4);
189 }
190 }
drawContactImage(int x,int y,int rad,int idx,int clr_idx,int size)191 void HudGaugeRadarStd::drawContactImage( int x, int y, int rad, int idx, int clr_idx, int size )
192 {
193 // this we will move as ships.tbl option (or use for radar scaling etc etc)
194 //int size = 24;
195
196 int w, h, old_bottom, old_bottom_unscaled, old_right, old_right_unscaled;
197 float scalef, wf, hf, xf, yf;
198 vec3d blip_scaler;
199
200 if(bm_get_info(idx, &w, &h) < 0)
201 {
202 // Just if something goes terribly wrong
203 drawContactCircle(x, y, rad);
204 return;
205 }
206
207 // just to make sure the missing casts wont screw the math
208 wf = (float) w;
209 hf = (float) h;
210 xf = (float) x;
211 yf = (float) y;
212
213 // make sure we use the larger dimension for the scaling
214 // lets go case by case to make sure there are no probs
215 if (size == -1)
216 scalef = 1.0f;
217 else if ((h == w) && (size == h))
218 scalef = 1.0f;
219 else if ( h > w)
220 scalef = ((float) size) / hf;
221 else
222 scalef = ((float) size) / wf;
223
224 Assert(scalef != 0);
225
226 // animate the targeted icon - option 1 of highlighting the targets
227 if ( rad == Radar_blip_radius_target ) {
228 if (radar_target_id_flags & RTIF_PULSATE) {
229 scalef *= 1.3f + (sinf(10 * f2fl(Missiontime)) * 0.3f);
230 }
231 if (radar_target_id_flags & RTIF_BLINK) {
232 if (Missiontime & 8192)
233 return;
234 }
235 if (radar_target_id_flags & RTIF_ENLARGE) {
236 scalef *= 1.3f;
237 }
238 }
239
240 // setup the scaler
241 blip_scaler.xyz.x = scalef;
242 blip_scaler.xyz.y = scalef;
243 blip_scaler.xyz.z = 1.0f;
244
245 old_bottom = gr_screen.clip_bottom;
246 old_bottom_unscaled = gr_screen.clip_bottom_unscaled;
247 gr_screen.clip_bottom = (int) (old_bottom/scalef);
248 gr_screen.clip_bottom_unscaled = (int) (old_bottom_unscaled/scalef);
249
250 old_right = gr_screen.clip_right;
251 old_right_unscaled = gr_screen.clip_right_unscaled;
252 gr_screen.clip_right = (int) (old_right/scalef);
253 gr_screen.clip_right_unscaled = (int) (old_right_unscaled/scalef);
254
255 // scale the drawing coordinates
256 x = (int) ((xf / scalef) - wf/2.0f);
257 y = (int) ((yf / scalef) - hf/2.0f);
258
259 gr_push_scale_matrix(&blip_scaler);
260
261 if ( idx >= 0 ) {
262 gr_set_bitmap(idx,GR_ALPHABLEND_NONE,GR_BITBLT_MODE_NORMAL,1.0f);
263 renderBitmap( x, y );
264 }
265
266 if ( clr_idx >= 0 ) {
267 gr_set_screen_scale(base_w, base_h);
268 gr_bitmap(x, y);
269 gr_reset_screen_scale();
270 }
271
272 gr_pop_scale_matrix();
273
274 gr_screen.clip_bottom = old_bottom;
275 gr_screen.clip_bottom_unscaled = old_bottom_unscaled;
276
277 gr_screen.clip_right = old_right;
278 gr_screen.clip_right_unscaled = old_right_unscaled;
279 }
280
render(float)281 void HudGaugeRadarStd::render(float /*frametime*/)
282 {
283 //WMC - This strikes me as a bit hackish
284 bool g3_yourself = !g3_in_frame();
285 if(g3_yourself)
286 g3_start_frame(1);
287
288 float sensors_str;
289 int ok_to_blit_radar;
290
291 ok_to_blit_radar = 1;
292
293 sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
294
295 if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
296 sensors_str = MIN_SENSOR_STR_TO_RADAR-1;
297 }
298
299 // note that on lowest skill level, there is no radar effects due to sensors damage
300 if ( (Game_skill_level == 0) || (sensors_str > SENSOR_STR_RADAR_NO_EFFECTS) ) {
301 Radar_static_playing = 0;
302 Radar_static_next = 0;
303 Radar_death_timer = 0;
304 Radar_avail_prev_frame = 1;
305 } else if ( sensors_str < MIN_SENSOR_STR_TO_RADAR ) {
306 if ( Radar_avail_prev_frame ) {
307 Radar_death_timer = timestamp(2000);
308 Radar_static_next = 1;
309 }
310 Radar_avail_prev_frame = 0;
311 } else {
312 Radar_death_timer = 0;
313 if ( Radar_static_next == 0 )
314 Radar_static_next = 1;
315 }
316
317 if ( timestamp_elapsed(Radar_death_timer) ) {
318 ok_to_blit_radar = 0;
319 }
320
321 setGaugeColor();
322 blitGauge();
323 drawRange();
324
325 if ( timestamp_elapsed(Radar_static_next) ) {
326 Radar_static_playing ^= 1;
327 Radar_static_next = timestamp_rand(50, 750);
328 }
329
330 // if the emp effect is active, always draw the radar wackily
331 if(emp_active_local()){
332 Radar_static_playing = 1;
333 }
334
335 if ( ok_to_blit_radar ) {
336 if ( Radar_static_playing ) {
337 drawBlipsSorted(1); // passing 1 means to draw distorted
338 if (!Radar_static_looping.isValid()) {
339 Radar_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC));
340 }
341 } else {
342 drawBlipsSorted(0);
343 if (Radar_static_looping.isValid()) {
344 snd_stop(Radar_static_looping);
345 Radar_static_looping = sound_handle::invalid();
346 }
347 }
348 } else {
349 if (Radar_static_looping.isValid()) {
350 snd_stop(Radar_static_looping);
351 Radar_static_looping = sound_handle::invalid();
352 }
353 }
354
355 if(g3_yourself)
356 g3_end_frame();
357 }
pageIn()358 void HudGaugeRadarStd::pageIn()
359 {
360 bm_page_in_aabitmap( Radar_gauge.first_frame, Radar_gauge.num_frames );
361 }
362
clampBlip(vec3d * b)363 void HudGaugeRadarStd::clampBlip(vec3d* b)
364 {
365 float max_radius;
366 float hypotenuse;
367
368 max_radius = i2fl(Radar_radius[0] - 5);
369
370 // Scale blip to radar size
371 vm_vec_scale(b, i2fl(Radar_radius[0])/2.0f);
372
373 hypotenuse = hypotf(b->xyz.x, b->xyz.y);
374
375 // Clamp to inside of plot area, if needed
376 if (hypotenuse > max_radius) {
377 vm_vec_scale2(b, max_radius, hypotenuse);
378 }
379
380 // Scale Y to respect aspect ratio
381 b->xyz.y *= (i2fl(Radar_radius[1]) / i2fl(Radar_radius[0]));
382 }
383
plotBlip(blip * b,int * x,int * y)384 void HudGaugeRadarStd::plotBlip(blip *b, int *x, int *y)
385 {
386 float zdist, rscale;
387 vec3d *pos = &b->position;
388
389 if (b->dist < pos->xyz.z) {
390 rscale = 0.0f;
391 } else {
392 rscale = (float) acosf_safe(pos->xyz.z / b->dist) / PI;
393 }
394
395 zdist = hypotf(pos->xyz.x, pos->xyz.y);
396
397 vec3d new_pos = {};
398
399 if (zdist >= 0.01f)
400 {
401 new_pos = *pos;
402 new_pos.xyz.z = 0.0f;
403 vm_vec_scale(&new_pos, rscale / zdist); // Values are within +/- 1.0f
404 clampBlip(&new_pos);
405 }
406
407 *x = fl2i(position[0] + Radar_center_offsets[0] + new_pos.xyz.x);
408 *y = fl2i(position[1] + Radar_center_offsets[1] - new_pos.xyz.y);
409 }
410
drawCrosshairs(int x,int y)411 void HudGaugeRadarStd::drawCrosshairs(int x, int y)
412 {
413 int i,j,m;
414
415 gr_set_color_fast(&radar_crosshairs);
416
417 for(i = 0; i < 2; i++) {
418 m = (i * 2) - 1;
419 renderGradientLine(x + m*4,y,x + m*8,y);
420 }
421 for(j = 0; j < 2; j++) {
422 m = (j * 2) - 1;
423 renderGradientLine(x,y + m*4,x,y + m*8);
424 }
425 }
426