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