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