1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include "map.h"
5 #include "2d_objects.h"
6 #include "3d_objects.h"
7 #include "asc.h"
8 #include "bbox_tree.h"
9 #include "consolewin.h"
10 #include "cursors.h"
11 #include "dialogues.h"
12 #include "elwindows.h"
13 #include "errors.h"
14 #include "gamewin.h"
15 #include "gl_init.h"
16 #include "init.h"
17 #include "interface.h"
18 #include "lights.h"
19 #include "loading_win.h"
20 #include "loginwin.h"
21 #include "mapwin.h"
22 #include "missiles.h"
23 #include "multiplayer.h"
24 #include "particles.h"
25 #include "pathfinder.h"
26 #include "reflection.h"
27 #include "sound.h"
28 #include "storage.h"
29 #include "tiles.h"
30 #include "translate.h"
31 #include "weather.h"
32 #ifdef CLUSTER_INSIDES
33 #include "cluster.h"
34 #endif
35 #include "counters.h"
36 #include "eye_candy_wrapper.h"
37 #include "minimap.h"
38 #include "io/elpathwrapper.h"
39 #ifdef PAWN
40 #include "pawn/elpawn.h"
41 #endif
42 #include "sky.h"
43 #include "mines.h"
44 #include "highlight.h"
45 
46 int map_type=1;
47 Uint32 map_flags=0;
48 
49 hash_table *server_marks=NULL;
50 
51 
destroy_map()52 void destroy_map()
53 {
54 	int i;
55 #ifdef EXTRA_DEBUG
56 	ERR();
57 #endif
58 
59 	have_a_map = 0;
60 
61 	clear_bbox_tree(main_bbox_tree);
62 	//kill the tile and height map
63 	if(tile_map)
64 	{
65 		free (tile_map);
66 		tile_map = NULL;
67 	}
68 	memset(tile_list,0,sizeof(tile_list));
69 	tile_map_size_x = tile_map_size_y = 0;
70 
71 	if(height_map)
72 	{
73 		free (height_map);
74 		height_map = NULL;
75 	}
76 
77 #ifndef MAP_EDITOR2
78 	///kill the pathfinding tile map
79 	if(pf_tile_map)
80 	{
81 		free(pf_tile_map);
82 		pf_tile_map = NULL;
83 
84 		if (pf_follow_path)
85 			pf_destroy_path();
86 	}
87 #endif
88 
89 	//kill the 3d objects links
90 	destroy_all_3d_objects();
91 
92 	//kill the 2d objects links
93 	destroy_all_2d_objects();
94 
95 	//kill the lights links
96 	for(i=0;i<MAX_LIGHTS;i++)
97 		{
98 			if(lights_list[i])
99 				{
100 					free(lights_list[i]);
101 					lights_list[i]= NULL;	//kill any refference to it
102 				}
103 		}
104 	num_lights= 0;
105 
106 #ifdef CLUSTER_INSIDES
107 	destroy_clusters_array ();
108 #endif
109 }
110 
111 #ifndef MAP_EDITOR2
get_cur_map(const char * file_name)112 int get_cur_map (const char * file_name)
113 {
114 	int i;
115 
116 	for (i=0; continent_maps[i].name != NULL; i++)
117 	{
118 		if (strcmp (continent_maps[i].name, file_name) == 0)
119 		{
120 			return i;
121 		}
122 	}
123 
124 	return -1;
125 }
126 #endif
127 
init_map_loading(const char * file_name)128 static void init_map_loading(const char *file_name)
129 {
130 	destroy_map();
131 
132 	/*
133 	 * Grum: the below is wrong: it never sets cur_map for the new map
134 	 * when you're leaving an inside map. Perhaps it would be useful not
135 	 * to set cur_map if you're *entering* an indide map, but we don't
136 	 * know that at this point.
137 	 *
138 	 * I wonder why we souldn't want to set it anyway...
139 	 */
140 	/*
141 	//Otherwise we pretend that we don't know where we are - if anyone wants to do the work and input all coordinates it's fine by me however :o)
142 	if (!dungeon) cur_map = get_cur_map (file_name);
143 	else cur_map=-1;
144 	*/
145 	cur_map = get_cur_map (file_name);
146 
147 	create_loading_win(window_width, window_height, 1);
148 	show_window(loading_win);
149 }
150 
build_path_map()151 static __inline__ void build_path_map()
152 {
153 	int i, x, y;
154 
155 	//create the tile map that will be used for pathfinding
156 	pf_tile_map = calloc(tile_map_size_x*tile_map_size_y*6*6, sizeof(PF_TILE));
157 
158 	i = 0;
159 	for (y = 0; y < tile_map_size_y*6; y++)
160 	{
161 		for (x = 0; x < tile_map_size_x*6; x++, i++)
162 		{
163 			pf_tile_map[i].x = x;
164 			pf_tile_map[i].y = y;
165 			pf_tile_map[i].z = height_map[i];
166 		}
167 	}
168 }
169 
updat_func(char * str,float percent)170 void updat_func(char *str, float percent)
171 {
172 	update_loading_win(str, percent);
173 }
174 
el_load_map(const char * file_name)175 static int el_load_map(const char * file_name)
176 {
177 	int ret;
178 
179 	init_map_loading(file_name);
180 	ret = load_map(file_name, &updat_func);
181 	if (!ret)
182 		// don't try to build pathfinder maps etc. when loading
183 		// the map failed...
184 		return ret;
185 
186 
187 	if (strstr(file_name, "underworld") != NULL)
188 	{
189 		skybox_set_type(SKYBOX_UNDERWORLD);
190 		skybox_update_colors();
191 	}
192 	else if (dungeon)
193 	{
194 		skybox_set_type(SKYBOX_NONE);
195 		skybox_update_colors();
196 	}
197 	else
198 	{
199 		skybox_set_type(SKYBOX_CLOUDY);
200 		skybox_init_defs(file_name);
201 	}
202 	build_path_map();
203 	init_buffers();
204 
205 	// reset light levels in case we enter or leave an inside map
206 	new_minute();
207 
208 	destroy_loading_win();
209 	return ret;
210 }
211 
change_map(const char * mapname)212 void change_map (const char *mapname)
213 {
214 #ifndef	MAP_EDITOR
215 	remove_all_bags();
216 	remove_all_mines();
217 #endif	//MAP_EDITOR
218 
219 	set_all_intersect_update_needed(main_bbox_tree);
220 	object_under_mouse=-1;//to prevent a nasty crash, while looking for bags, when we change the map
221 #ifndef MAP_EDITOR2
222 #ifdef EXTRA_DEBUG
223 	ERR();
224 #endif
225 	close_dialogue();	// close the dialogue window if open
226 	close_storagewin(); //if storage is open, close it
227 	destroy_all_particles();
228 	ec_delete_all_effects();
229 #ifdef NEW_SOUND
230 	stop_all_sounds();
231 #endif	//NEW_SOUND
232 	missiles_clear();
233 	if (!el_load_map(mapname)) {
234 		char error[255];
235 		safe_snprintf(error, sizeof(error), cant_change_map, mapname);
236 		LOG_TO_CONSOLE(c_red4, error);
237 		LOG_TO_CONSOLE(c_red4, empty_map_str);
238 		LOG_ERROR(cant_change_map, mapname);
239 		load_empty_map();
240 	} else {
241 		locked_to_console = 0;
242 	}
243 	load_map_marks();
244 
245 #ifdef NEW_SOUND
246 	get_map_playlist();
247 	setup_map_sounds(mapname);
248 #endif // NEW_SOUND
249 	have_a_map=1;
250 	//also, stop the rain
251 	weather_clear();
252 
253 	if (get_show_window_MW(MW_TABMAP))
254 	{
255 		hide_window_MW(MW_TABMAP);
256 		show_window(game_root_win);
257 	}
258 #else // !MAP_EDITOR2
259 	destroy_all_particles();
260 #ifdef NEW_SOUND
261 	stop_all_sounds();
262 #endif	//NEW_SOUND
263 	if (!load_map(mapname)) {
264 		char error[255];
265 		safe_snprintf(error, sizeof(error), cant_change_map, mapname);
266 		LOG_TO_CONSOLE(c_red4, error);
267 		LOG_TO_CONSOLE(c_red4, empty_map_str);
268 		LOG_ERROR(cant_change_map, mapname);
269 		load_empty_map();
270 	}
271 
272 #ifdef NEW_SOUND
273 	get_map_playlist();
274 	setup_map_sounds(mapname);
275 #endif // NEW_SOUND
276 	have_a_map=1;
277 #endif  //MAP_EDITOR2
278 	change_minimap();
279 
280 #ifdef PAWN
281 	run_pawn_map_function ("change_map", "s", mapname);
282 #endif
283 }
284 
load_empty_map()285 int load_empty_map()
286 {
287 	if (!el_load_map("./maps/nomap.elm"))
288 	{
289 #ifndef MAP_EDITOR2
290 		locked_to_console = 1;
291 		hide_window (game_root_win);
292 		show_window_MW(MW_CONSOLE);
293 		LOG_TO_CONSOLE(c_red4, no_nomap_str);
294 		LOG_ERROR(cant_change_map, "./maps/nomap.elm");
295 		SDLNet_TCP_Close(my_socket);
296 		disconnected = 1;
297 #ifdef NEW_SOUND
298 		stop_all_sounds();
299 #endif // NEW_SOUND
300 		disconnect_time = SDL_GetTicks();
301 		SDLNet_Quit();
302 		LOG_TO_CONSOLE(c_red3, disconnected_from_server);
303 		//Fake a map to make sure we don't get any crashes.
304 #endif
305 		safe_snprintf(map_file_name, sizeof(map_file_name), "./maps/nomap.elm");
306 		tile_map_size_y = 256;
307 		tile_map_size_x = 256;
308 		dungeon = 0;
309 		ambient_r = 0;
310 		ambient_g = 0;
311 		ambient_b = 0;
312 		tile_map = calloc(tile_map_size_x*tile_map_size_y, sizeof(unsigned char));
313 		height_map = calloc(tile_map_size_x*tile_map_size_y*6*6, sizeof(unsigned char));
314 #ifndef MAP_EDITOR2
315 		pf_tile_map = calloc(tile_map_size_x*tile_map_size_y*6*6, sizeof(PF_TILE));
316 #endif
317 		return 0;
318 	}
319 	return 1;
320 }
321 
322 
init_server_markers()323 void init_server_markers(){
324 	//init hash table
325 	destroy_hash_table(server_marks);
326 	server_marks= create_hash_table(50,hash_fn_int,cmp_fn_int,free);
327 }
328 
add_server_markers()329 void add_server_markers(){
330 
331 	hash_entry *he;
332 	server_mark *sm;
333 	int i,l;
334 	char *mapname = map_file_name;
335 
336 	//find the slot to add server marks
337 	for(i=0;i<max_mark;i++)
338 		if(marks[i].server_side) break;
339 	l=i;
340 
341 	if(!server_marks) init_server_markers();
342 	if(server_marks) {
343 		hash_start_iterator(server_marks);
344 		while((he=hash_get_next(server_marks))){
345 			sm = (server_mark *) he->item;
346 			//is it in this map?
347 			if(strcmp(mapname,sm->map_name)) continue;
348 			//find the next slot. If not there, add 1
349 			for(i=l;i<MAX_MARKINGS;i++)
350 				if(marks[i].server_side||i>=max_mark) {l=i; if(l>=max_mark) max_mark=l+1; break;}
351 			//add the marker
352 			marks[l].x=sm->x;
353 			marks[l].y=sm->y;
354 			marks[l].server_side=1;
355 			marks[l].server_side_id=sm->id;
356 			safe_strncpy(marks[l].text, sm->text, sizeof(marks[l].text));
357 			l++;
358 		}
359 		//remove server side markings if necessary
360 		for(i=l+1;i<max_mark;i++)
361 			if(marks[i].server_side) {marks[i].server_side=0;marks[i].server_side_id=marks[i].x=marks[i].y=-1;}
362 	}
363 }
364 
load_marks_to_buffer(char * mapname,marking * buffer,int * max)365 void load_marks_to_buffer(char* mapname, marking* buffer, int* max)
366 {
367 	FILE * fp = NULL;
368 	char marks_file[256] = {0}, text[600] = {0};
369 
370 	if(mapname == NULL) {
371 		//Oops
372 		return;
373 	}
374 	safe_snprintf (marks_file, sizeof (marks_file), "%s.txt", mapname);
375 	//LOG_TO_CONSOLE(c_red2, marks_file);
376 	fp = open_file_config(marks_file, "r");
377 	*max = 0;
378 
379 	if (fp == NULL) return;
380 
381 	//load user markers
382 	while ( fgets(text, 600,fp) ) {
383 		if (strlen (text) > 1) {
384 			int r,g,b;
385 			sscanf (text, "%d %d", &buffer[*max].x, &buffer[*max].y);
386 			//scanning mark color. It can be optional -> default=green
387 			if(sscanf(text,"%*d %*d|%d,%d,%d|",&r,&g,&b)<3) { //NO SPACES in RGB format string!
388 				r=b=0;
389 				g=255;
390 			}
391 			buffer[*max].server_side=0;
392 			buffer[*max].server_side_id=-1;
393 			text[strlen(text)-1] = '\0'; //remove the newline
394 			rtrim_string(text); //remove trailing white space
395 			if ((strstr(text, " ") == NULL) || (strstr(strstr(text, " ")+1, " ") == NULL)) {
396  				LOG_ERROR("Bad map mark file=[%s] text=[%s]", marks_file, text);
397 			}
398 			else {
399 				safe_strncpy(buffer[*max].text, strstr(strstr(text, " ")+1, " ") + 1, sizeof(buffer[*max].text));
400 				buffer[*max].r=r;
401 				buffer[*max].g=g;
402 				buffer[*max].b=b;
403 				*max = *max + 1;
404 				if ( *max >= MAX_USER_MARKS ) break;
405 			}
406 		}
407 	}
408 
409 	fclose(fp);
410 
411 	LOG_DEBUG("Read map markings from file '%s'", marks_file);
412 
413 }
414 
load_map_marks()415 void load_map_marks()
416 {
417 	//load user markers
418 	load_marks_to_buffer(map_file_name, marks, &max_mark);
419 
420 	//load server markers on this map
421 	add_server_markers();
422 
423 }
424 
save_markings()425 void save_markings()
426 {
427 	FILE * fp;
428 	char marks_file[256];
429 	int i;
430 
431 	safe_snprintf (marks_file, sizeof (marks_file), "%s.txt", map_file_name);
432 	//LOG_TO_CONSOLE(c_red2, marks_file);
433 	fp = open_file_config(marks_file,"w");
434 	if ( fp == NULL ){
435 		LOG_ERROR("%s: %s \"%s\": %s\n", reg_error_str, cant_open_file, marks_file, strerror(errno));
436 	} else {
437 		for ( i = 0 ; i < max_mark ; i ++){
438 			if ( marks[i].x > 0 && !marks[i].server_side){
439 				fprintf(fp,"%d %d|%d,%d,%d| %s\n",marks[i].x,marks[i].y,marks[i].r,marks[i].g,marks[i].b,marks[i].text);
440 			}
441 		}
442 		fclose(fp);
443 	}
444 
445 	LOG_DEBUG("Wrote map markings to file '%s'", marks_file);
446 }
447 
448 
449 
450 
load_server_markings()451 void load_server_markings(){
452 	char fname[128];
453 	FILE *fp;
454 	server_mark sm;
455 	int rf;
456 
457 	init_server_markers();
458 
459 	//open server markings file
460 	safe_snprintf(fname, sizeof(fname), "servermarks_%s.dat",get_lowercase_username());
461 
462 	/* sliently ignore non existing file */
463 	if (file_exists_config(fname)!=1)
464 		return;
465 
466 	fp = open_file_config(fname,"r");
467 	if(fp == NULL){
468 		LOG_ERROR("%s: %s \"%s\": %s\n", reg_error_str, cant_open_file, fname, strerror(errno));
469 		return;
470 	}
471 
472 	while((rf=fscanf(fp,"%d %d %d %s %[^\n]s\n",&sm.id,&sm.x,&sm.y,sm.map_name,sm.text))==5){
473 		server_mark *nm = calloc(1,sizeof(server_mark));
474 		memcpy(nm,&sm,sizeof(server_mark));
475 		hash_add(server_marks,(void *)(uintptr_t)sm.id,(void*) nm);
476 	}
477 
478 	fclose (fp);
479 
480 	LOG_DEBUG("Read server markings from file '%s'", fname);
481 
482 	add_server_markers();
483 }
484 
485 
save_server_markings()486 void save_server_markings(){
487 	char fname[128];
488 	FILE *fp;
489 	server_mark *sm;
490 	hash_entry *he;
491 
492 	if(!server_marks) return;
493 
494 	//open server markings file
495 	safe_snprintf(fname, sizeof(fname), "servermarks_%s.dat",get_lowercase_username());
496 	fp = open_file_config(fname,"w");
497 	if(fp == NULL){
498 		LOG_ERROR("%s: %s \"%s\": %s\n", reg_error_str, cant_open_file, fname, strerror(errno));
499 		return;
500 	}
501 
502 	hash_start_iterator(server_marks);
503 
504 	while((he=hash_get_next(server_marks))){
505 		sm = (server_mark *) he->item;
506 		fprintf(fp,"%d %d %d %s %s\n",sm->id, sm->x, sm->y, sm->map_name, sm->text);
507 	}
508 
509 	fclose (fp);
510 
511 	LOG_DEBUG("Wrote server markings to file '%s'", fname);
512 }
513 
514 //called in elconfig.c when turning markers on/off
change_3d_marks(int * rel)515 void change_3d_marks(int *rel){
516 	*rel= !*rel;
517 }
518 
519 
init_buffers()520 void init_buffers()
521 {
522 	int terrain_buffer_size;
523 	int water_buffer_size;
524 	int i, j, cur_tile;
525 
526 	terrain_buffer_size = 0;
527 	water_buffer_size = 0;
528 
529 	for(i = 0; i < tile_map_size_y; i++)
530 	{
531 		for(j = 0; j < tile_map_size_x; j++)
532 		{
533 			cur_tile = tile_map[i*tile_map_size_x+j];
534 			if (cur_tile != 255)
535 			{
536 				if (IS_WATER_TILE(cur_tile))
537 				{
538 					water_buffer_size++;
539 				}
540 				else
541 				{
542 					terrain_buffer_size++;
543 				}
544 			}
545 		}
546 	}
547 	init_water_buffers(water_buffer_size);
548 	init_terrain_buffers(terrain_buffer_size);
549 	init_reflection_portals(water_buffer_size);
550 }
551 
free_buffers()552 void free_buffers()
553 {
554 	if (water_tile_buffer)
555 		free(water_tile_buffer);
556 	if (terrain_tile_buffer)
557 		free(terrain_tile_buffer);
558 	if (reflection_portals)
559 		free(reflection_portals);
560 }
561 
get_3d_objects_from_server(int nr_objs,const Uint8 * data,int len)562 int get_3d_objects_from_server (int nr_objs, const Uint8 *data, int len)
563 {
564 	int iobj;
565 	int obj_x, obj_y;
566 	int offset, nb_left;
567 	float x = 0.0f, y = 0.0f, z = 0.0f, rx = 0.0f, ry = 0.0f, rz = 0.0f;
568 	char obj_name[128];
569 	int name_len, max_name_len;
570 	int id = -1;
571 	int all_ok = 1;
572 
573 	offset = 0;
574 	nb_left = len;
575 	for (iobj = 0; iobj < nr_objs; iobj++)
576 	{
577 		int obj_err = 0;
578 
579 		if (nb_left < 14)
580 		{
581 			// Warn about this error!
582                         LOG_WARNING("Incomplete 3D objects list!");
583 			all_ok = 0;
584                         break;
585 		}
586 
587 		obj_x = SDL_SwapLE16 (*((Uint16 *)(&data[offset])));
588 		offset += 2;
589 		obj_y = SDL_SwapLE16 (*((Uint16 *)(&data[offset])));
590 		offset += 2;
591 		if (obj_x > tile_map_size_x * 6 || obj_y > tile_map_size_y * 6)
592 		{
593 			// Warn about this error!
594 			LOG_WARNING("A 3D object was located OUTSIDE the map!");
595 			offset += 8;
596 			obj_err = 1;
597                 }
598 		else
599 		{
600 			rx = SwapLEFloat (*((float *)(&data[offset])));
601 			offset += 2;
602 			ry = SwapLEFloat (*((float *)(&data[offset])));
603 			offset += 2;
604 			rz = SwapLEFloat (*((float *)(&data[offset])));
605 			offset += 2;
606 			id = SDL_SwapLE16 (*((Uint16 *)(&data[offset])));
607 			offset += 2;
608 
609 			x = 0.5f * obj_x + 0.25f;
610 			y = 0.5f * obj_y + 0.25f;
611 			z = get_tile_height(obj_x, obj_y);
612 		}
613 
614 		nb_left -= 12;
615 		max_name_len = nb_left > sizeof (obj_name) ? sizeof (obj_name) : nb_left;
616 		name_len = safe_snprintf (obj_name, max_name_len, "%s", &data[offset]);
617 		if (name_len < 0 || name_len >= sizeof (obj_name))
618 		{
619 			// Warn about this error!
620                         LOG_WARNING("3D object has invalid or too long file name!");
621 			all_ok = 0;
622                         break;
623 		}
624 
625 		offset += name_len + 1;
626 		nb_left -= name_len + 1;
627 
628 		if (!obj_err)
629 			add_e3d_at_id (id, obj_name, x, y, z, rx, ry, rz, 0, 0, 1.0f, 1.0f, 1.0f, 1);
630 		else
631 			all_ok = 0;
632 	}
633 
634 	return all_ok;
635 }
636 
remove_3d_object_from_server(int id)637 void remove_3d_object_from_server (int id)
638 {
639 	if (id < 0 || id > MAX_OBJ_3D)
640 	{
641 		LOG_ERROR ("Trying to remove object with invalid id %d", id);
642 		return;
643 	}
644 	if (objects_list[id] == NULL)
645 	{
646 		LOG_ERROR ("Trying to remove non-existant object");
647 		return;
648 	}
649 
650 	destroy_3d_object (id);
651 }
652 
653 
654 //3D MAP MARKERS
655 #define MAX(a,b) ( ((a)>(b)) ? (a):(b) )
656 #define ABS(a) ( ((a)<0)?(-(a)):(a)  )
657 #define DST(xa,ya,xb,yb) ( MAX(ABS(xa-xb),ABS(ya-yb))  )
658 int marks_3d=1;
659 float mark_z_rot=0;
660 
animate_map_markers()661 void animate_map_markers(){
662 
663 	int dt;
664 	static int last_rot=0;
665 
666 	dt=cur_time-last_rot;
667 	last_rot+=dt;
668 	mark_z_rot+=0.1*dt;
669 	if(mark_z_rot>360) mark_z_rot-=360;
670 
671 }
672 
display_map_marks()673 void display_map_marks(){
674 	actor *me;
675 	float x,y,z;
676 	int i,ax,ay;
677 	float dx = (TILESIZE_X / 6);
678 	float dy = (TILESIZE_Y / 6);
679 	float fr = mark_z_rot/360;
680 	float j,ff=0;
681 
682 	me = get_our_actor();
683 	if(!me) return;
684 	ax = me->x_pos;
685 	ay = me->y_pos;
686 
687 	glDisable(GL_TEXTURE_2D);
688 	glDisable(GL_LIGHTING);
689 	glEnable(GL_BLEND);
690 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
691 	glEnable(GL_ALPHA_TEST);
692 
693 	for(i=0;i<max_mark;i++){
694 		x=marks[i].x/2.0;
695 		y=marks[i].y/2.0;
696 		x += (TILESIZE_X / 2);
697 		y += (TILESIZE_Y / 2);
698 		if(DST(ax,ay,x,y)>MARK_DIST||marks[i].x<0||!marks_3d) continue;
699 		z = get_tile_height(marks[i].x, marks[i].y);
700 		for(j=z-fr/5,ff=1;j<z+2;j+=0.1,ff=(2-(j-z))/2) {
701 			if(marks[i].server_side) glColor4f(0.0f, 0.0f, 1.0f, 0.9f-(j-z)/3);
702 			else glColor4f((float)marks[i].r/255, (float)marks[i].g/255, (float)marks[i].b/255, 0.7f-(j-z)/3);
703 			glBegin(GL_QUADS);
704 				glVertex3f(x-dx*ff,y-dy*ff,j);
705 				glVertex3f(x-dx*ff,y+dy*ff,j);
706 				glVertex3f(x+dx*ff,y+dy*ff,j);
707 				glVertex3f(x+dx*ff,y-dy*ff,j);
708 			glEnd();
709 		}
710 
711 	}
712 
713 	glDisable(GL_ALPHA_TEST);
714 	//glEnable(GL_LIGHTING);
715 	glDisable(GL_BLEND);
716 	glEnable(GL_TEXTURE_2D);
717 
718 }
719 
display_map_markers()720 void display_map_markers() {
721 	int ax, ay;
722 	float z,x,y;
723 	int i;
724 	GLdouble model[16],proj[16];
725 	GLint view[4];
726 	GLdouble hx,hy,hz;
727 	float banner_width;
728 	float font_scale = 1.0f/ALT_INGAME_FONT_X_LEN;
729 	float font_size_x=font_scale*SMALL_INGAME_FONT_X_LEN;
730 	float font_size_y=font_scale*SMALL_INGAME_FONT_X_LEN;
731 	char tmpb[4];
732 	actor *me;
733 
734 	me = get_our_actor();
735 	if(!me) return;
736 	ax = me->x_pos;
737 	ay = me->y_pos;
738 
739 	glGetDoublev(GL_MODELVIEW_MATRIX, model);
740 	glGetDoublev(GL_PROJECTION_MATRIX, proj);
741 	glGetIntegerv(GL_VIEWPORT, view);
742 	glPushMatrix();
743 	glLoadIdentity();
744 	glMatrixMode(GL_PROJECTION);
745 	glPushMatrix();
746 	glLoadIdentity();
747 	glOrtho(view[0],view[2]+view[0],view[1],view[3]+view[1],0.0f,-1.0f);
748 	glDepthFunc(GL_LEQUAL);
749 	glEnable(GL_TEXTURE_2D);
750 	glColor4f(1.0,1.0,1.0,1.0);
751 	glDisable(GL_LIGHTING);
752 	glEnable(GL_BLEND);
753 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
754 
755 	for(i=0;i<max_mark;i++){
756 		x=marks[i].x/2.0;
757 		y=marks[i].y/2.0;
758 		x += (TILESIZE_X / 2);
759 		y += (TILESIZE_Y / 2);
760 		if(DST(ax,ay,x,y)>MARK_DIST||marks[i].x<0||!marks_3d) continue;
761 		z = get_tile_height(marks[i].x, marks[i].y)+2.3;
762 		gluProject(x, y, z, model, proj, view, &hx, &hy, &hz);
763 		//shorten text
764 		memcpy(tmpb,marks[i].text+MARK_CLIP_POS,4);
765 		marks[i].text[MARK_CLIP_POS]=marks[i].text[MARK_CLIP_POS+1]=marks[i].text[MARK_CLIP_POS+2]='.';
766 		marks[i].text[MARK_CLIP_POS+3]=0;
767 		banner_width = 0.5 * (float)get_string_width_zoom((unsigned char*)marks[i].text, NAME_FONT, font_size_x);
768 		draw_ortho_ingame_string(hx-banner_width, hy, hz, (unsigned char*)marks[i].text,
769 			4, NAME_FONT, font_size_x, font_size_y);
770 		//restore text
771 		memcpy(marks[i].text+MARK_CLIP_POS,tmpb,4);
772 
773 	}
774 	glDisable(GL_BLEND);
775 	glDisable(GL_TEXTURE_2D);
776 	glMatrixMode(GL_PROJECTION);
777 	glPopMatrix();
778 	glMatrixMode(GL_MODELVIEW);
779 	glPopMatrix();
780 	//glEnable(GL_LIGHTING);
781 	glDepthFunc(GL_LESS);
782 
783 
784 }
785 
786 
787 
788