1 #include <stdlib.h>
2 #include <math.h>
3 #include <string.h>
4 #include <SDL.h>
5 #include "actors.h"
6 #include "actor_scripts.h"
7 #include "asc.h"
8 #include "bbox_tree.h"
9 #include "buffs.h"
10 #include "cal.h"
11 #include "cursors.h"
12 #include "draw_scene.h"
13 #include "errors.h"
14 #include "events.h"
15 #include "gl_init.h"
16 #include "interface.h"
17 #include "load_gl_extensions.h"
18 #include "map.h"
19 #include "missiles.h"
20 #include "new_actors.h"
21 #include "platform.h"
22 #include "shadows.h"
23 #include "special_effects.h"
24 #include "textures.h"
25 #include "translate.h"
26 #include "vmath.h"
27 #ifdef CLUSTER_INSIDES
28 #include "cluster.h"
29 #endif
30 #include "eye_candy_wrapper.h"
31 #include "minimap.h"
32 #include "actor_init.h"
33 #ifdef	FSAA
34 #include "fsaa/fsaa.h"
35 #endif	/* FSAA */
36 
37 actor *actors_list[MAX_ACTORS];
38 int max_actors=0;
39 SDL_mutex *actors_lists_mutex = NULL;	//used for locking between the timer and main threads
40 actor *your_actor = NULL;
41 
42 actor_types actors_defs[MAX_ACTOR_DEFS];
43 
44 attached_actors_types attached_actors_defs[MAX_ACTOR_DEFS];
45 
46 static void draw_actor_overtext(actor* actor_ptr, double x, double y, double z); /* forward declaration */
47 
48 int no_near_actors=0;
49 #ifdef NEW_SOUND
50 int no_near_enhanced_actors = 0;
51 float distanceSq_to_near_enhanced_actors;
52 #endif // NEW_SOUND
53 near_actor near_actors[MAX_ACTORS];
54 
55 #ifdef MUTEX_DEBUG
56 SDL_threadID have_actors_lock = 0;
57 #endif
58 
59 int cm_mouse_over_banner = 0;		/* use to trigger banner context menu */
60 
get_closest_actor(int tile_x,int tile_y,float max_distance)61 int get_closest_actor(int tile_x, int tile_y, float max_distance)
62 {
63 	int i;
64 	int found_actor = -1;
65 	float x=tile_x / 2.0f;
66 	float y=tile_y / 2.0f;
67 	float distance;
68 	float min_distance_found = 50;
69 
70 	// check if too far
71 	actor *me = get_our_actor();
72 	if (me)
73 	{
74 		distance = sqrt((me->x_pos - x) * (me->x_pos - x) + (me->y_pos - y) * (me->y_pos - y));
75 		if (distance > 6)
76 			return -1;
77 	}
78 
79 	for (i=0; i<max_actors; i++)
80 		if (actors_list[i])
81 			if (!actors_list[i]->dead)
82 				if (actors_list[i]->kind_of_actor != NPC && actors_list[i]->kind_of_actor != HUMAN && actors_list[i]->kind_of_actor != COMPUTER_CONTROLLED_HUMAN)
83 				{
84 					distance = sqrt((actors_list[i]->x_pos - x) * (actors_list[i]->x_pos - x) + (actors_list[i]->y_pos - y ) * (actors_list[i]->y_pos - y));
85 					if (distance < max_distance)
86 						if (distance < min_distance_found)
87 						{
88 							found_actor = actors_list[i]->actor_id;
89 							min_distance_found = distance;
90 						}
91 				}
92 
93 	return found_actor;
94 }
95 
96 //Threading support for actors_lists
init_actors_lists()97 void init_actors_lists()
98 {
99 	int	i;
100 
101 	actors_lists_mutex=SDL_CreateMutex();
102 	LOCK_ACTORS_LISTS();	//lock it to avoid timing issues
103 	for (i=0; i < MAX_ACTORS; i++)
104 		actors_list[i] = NULL;
105 	UNLOCK_ACTORS_LISTS();	// release now that we are done
106 }
107 
108 //return the ID (number in the actors_list[]) of the new allocated actor
add_actor(int actor_type,char * skin_name,float x_pos,float y_pos,float z_pos,float z_rot,float scale,char remappable,short skin_color,short hair_color,short eyes_color,short shirt_color,short pants_color,short boots_color,int actor_id)109 int add_actor (int actor_type, char * skin_name, float x_pos, float y_pos, float z_pos, float z_rot, float scale, char remappable, short skin_color, short hair_color, short eyes_color, short shirt_color, short pants_color, short boots_color, int actor_id)
110 {
111 	int texture_id;
112 	int i;
113 	int k;
114 	actor *our_actor;
115 #ifdef CLUSTER_INSIDES
116 	int x, y;
117 #endif
118 
119 #ifdef EXTRA_DEBUG
120 	ERR();
121 #endif
122 
123 	if (actors_defs[actor_type].ghost)
124 	{
125 		texture_id = load_texture_cached(skin_name, tt_mesh);
126 	}
127 	else
128 	{
129 		if (!remappable)
130 		{
131 			texture_id = load_texture_cached(skin_name, tt_mesh);
132 		}
133 		else
134 		{
135 			LOG_ERROR("remapped skin for %s", skin_name);
136 			exit(-1);
137 		}
138 	}
139 
140 	our_actor = calloc(1, sizeof(actor));
141 
142 	memset(our_actor->current_displayed_text, 0, sizeof(our_actor->current_displayed_text));
143 	our_actor->current_displayed_text_lines = 0;
144 	our_actor->current_displayed_text_time_left =  0;
145 
146 	our_actor->is_enhanced_model=0;
147 	our_actor->remapped_colors=remappable;
148 	our_actor->actor_id=actor_id;
149 	our_actor->cur_anim_sound_cookie = 0;
150 
151 	our_actor->cal_h_rot_start = 0.0;
152 	our_actor->cal_h_rot_end = 0.0;
153 	our_actor->cal_v_rot_start = 0.0;
154 	our_actor->cal_v_rot_end = 0.0;
155 	our_actor->cal_rotation_blend = -1.0;
156 	our_actor->cal_rotation_speed = 0.0;
157 	our_actor->are_bones_rotating = 0;
158 	our_actor->in_aim_mode = 0;
159 	our_actor->range_actions_count = 0;
160 	our_actor->delayed_item_changes_count = 0;
161 
162 	our_actor->x_pos=x_pos;
163 	our_actor->y_pos=y_pos;
164 	our_actor->z_pos=z_pos;
165 	our_actor->scale=scale;
166 
167 	our_actor->x_speed=0;
168 	our_actor->y_speed=0;
169 	our_actor->z_speed=0;
170 
171 	our_actor->x_rot=0;
172 	our_actor->y_rot=0;
173 	our_actor->z_rot=z_rot;
174 
175 	our_actor->last_range_attacker_id = -1;
176 
177 	//reset the script related things
178 	our_actor->move_x_speed=0;
179 	our_actor->move_y_speed=0;
180 	our_actor->move_z_speed=0;
181 	our_actor->rotate_x_speed=0;
182 	our_actor->rotate_y_speed=0;
183 	our_actor->rotate_z_speed=0;
184 	our_actor->movement_time_left=0;
185 	our_actor->moving=0;
186 	our_actor->rotating=0;
187 	our_actor->busy=0;
188 	our_actor->last_command=nothing;
189 #ifdef	ANIMATION_SCALING
190 	our_actor->animation_scale = 1.0f;
191 #endif	/* ANIMATION_SCALING*/
192 
193     /* load the texture in case it's not already loaded and look if it has
194      * an alpha map */
195 	our_actor->has_alpha = get_texture_alpha(texture_id);
196 
197 	//clear the que
198 	for(k=0;k<MAX_CMD_QUEUE;k++)	our_actor->que[k]=nothing;
199 	//clear emotes
200 	for(k=0;k<MAX_EMOTE_QUEUE;k++)	{
201 		our_actor->emote_que[k].emote=NULL;
202 		our_actor->emote_que[k].origin=NO_EMOTE;
203 		our_actor->emote_que[k].create_time=0;
204 		}
205 	memset(&our_actor->cur_emote,0,sizeof(emote_anim));
206 	memset(&our_actor->poses,0,sizeof(emote_data*)*4);
207 	for(k=0;k<MAX_EMOTE_FRAME;k++) our_actor->cur_emote.frames[k].anim_index=-1;
208 	our_actor->cur_emote.idle.anim_index=-1;
209 	our_actor->cur_emote_sound_cookie=0;
210 
211 
212 
213 
214 	our_actor->texture_id=texture_id;
215 	our_actor->skin=skin_color;
216 	our_actor->hair=hair_color;
217 	our_actor->eyes=eyes_color;
218 	our_actor->pants=pants_color;
219 	our_actor->boots=boots_color;
220 	our_actor->shirt=shirt_color;
221 	our_actor->stand_idle=0;
222 	our_actor->sit_idle=0;
223 
224 	our_actor->attached_actor = -1;
225 	our_actor->attachment_shift[0] = our_actor->attachment_shift[1] = our_actor->attachment_shift[2] = 0.0;
226 
227 	for (i = 0; i < NUM_BUFFS; i++)
228 	{
229 		our_actor->ec_buff_reference[i] = NULL;
230 	}
231 
232 #ifdef CLUSTER_INSIDES
233 	x = (int) (our_actor->x_pos / 0.5f);
234 	y = (int) (our_actor->y_pos / 0.5f);
235 	our_actor->cluster = get_cluster (x, y);
236 #endif
237 
238 	//find a free spot, in the actors_list
239 	LOCK_ACTORS_LISTS();
240 
241 	for(i=0;i<max_actors;i++)
242 		{
243 			if(!actors_list[i])break;
244 		}
245 
246 	if(actor_id == yourself)
247 		set_our_actor (our_actor);
248 
249 	actors_list[i]=our_actor;
250 	if(i>=max_actors)max_actors=i+1;
251 
252 	//It's unlocked later
253 
254 	ec_add_actor_obstruction(our_actor, 3.0);
255 	return i;
256 }
257 
add_actor_attachment(int actor_id,int attachment_type)258 void add_actor_attachment(int actor_id, int attachment_type)
259 {
260 	int i;
261 	actor *parent = NULL;
262 
263 	for (i = 0; i < max_actors; ++i)
264 		if (actors_list[i]->actor_id == actor_id)
265 		{
266 			parent = actors_list[i];
267 			break;
268 		}
269 
270 	if (!parent)
271 		LOG_ERROR("unable to add an attached actor: actor with id %d doesn't exist!", actor_id);
272 	else if(attachment_type < 0 || attachment_type >= MAX_ACTOR_DEFS || (attachment_type > 0 && actors_defs[attachment_type].actor_type != attachment_type) )
273 		LOG_ERROR("unable to add an attached actor: illegal/missing actor definition %d", attachment_type);
274 	else
275 	{
276 		int id = add_actor(attachment_type, actors_defs[attachment_type].skin_name,
277 						   parent->x_pos, parent->y_pos, parent->z_pos, parent->z_rot, get_actor_scale(parent),
278 						   0, 0, 0, 0, 0, 0, 0, -1);
279 		actors_list[id]->attached_actor = i;
280 		parent->attached_actor = id;
281 
282 		actors_list[id]->async_fighting = 0;
283 		actors_list[id]->async_x_tile_pos = parent->async_x_tile_pos;
284 		actors_list[id]->async_y_tile_pos = parent->async_y_tile_pos;
285 		actors_list[id]->async_z_rot = parent->async_z_rot;
286 
287 		actors_list[id]->x_tile_pos=parent->x_tile_pos;
288 		actors_list[id]->y_tile_pos=parent->y_tile_pos;
289 		actors_list[id]->buffs=parent->buffs & BUFF_DOUBLE_SPEED; // the attachment can only have this buff
290 		actors_list[id]->actor_type=attachment_type;
291 		actors_list[id]->damage=0;
292 		actors_list[id]->damage_ms=0;
293 		actors_list[id]->sitting=0;
294 		actors_list[id]->fighting=0;
295 		//test only
296 		actors_list[id]->max_health=0;
297 		actors_list[id]->cur_health=0;
298 		actors_list[id]->ghost=actors_defs[attachment_type].ghost;
299 		actors_list[id]->dead=0;
300 		actors_list[id]->stop_animation=1;//helps when the actor is dead...
301 		actors_list[id]->kind_of_actor=0;
302 
303 		if (attached_actors_defs[attachment_type].actor_type[parent->actor_type].is_holder)
304 			actors_list[id]->step_duration = actors_defs[attachment_type].step_duration;
305 		else
306 			actors_list[id]->step_duration = parent->step_duration;
307 
308 		if (actors_list[id]->buffs & BUFF_DOUBLE_SPEED)
309 			actors_list[id]->step_duration /= 2;
310 
311 		actors_list[id]->z_pos = get_actor_z(actors_list[id]);
312 
313 		//printf("attached actor n°%d of type %d to actor n°%d with id %d\n", id, attachment_type, i, actor_id);
314 
315 		if (actors_defs[attachment_type].coremodel!=NULL) {
316 			//Setup cal3d model
317 			actors_list[id]->calmodel = model_new(actors_defs[attachment_type].coremodel);
318 			//Attach meshes
319 			if(actors_list[id]->calmodel) {
320 				model_attach_mesh(actors_list[id], actors_defs[attachment_type].shirt[0].mesh_index);
321 				set_on_idle(id);
322 
323 				build_actor_bounding_box(actors_list[id]);
324 				if (use_animation_program)
325 					set_transformation_buffers(actors_list[id]);
326 			}
327 		}
328 		else
329 			actors_list[id]->calmodel=NULL;
330 
331 		UNLOCK_ACTORS_LISTS();
332 	}
333 }
334 
remove_actor_attachment(int actor_id)335 void remove_actor_attachment(int actor_id)
336 {
337 	int i;
338 
339 	LOCK_ACTORS_LISTS();
340 
341 	for (i = 0; i < max_actors; ++i)
342 		if (actors_list[i]->actor_id == actor_id)
343 		{
344 			int att = actors_list[i]->attached_actor;
345 			actors_list[i]->attached_actor = -1;
346 			actors_list[i]->attachment_shift[0] = 0.0;
347 			actors_list[i]->attachment_shift[1] = 0.0;
348 			actors_list[i]->attachment_shift[2] = 0.0;
349 			free_actor_special_effect(actors_list[att]->actor_id);
350 			free_actor_data(att);
351 			free(actors_list[att]);
352 			actors_list[att]=NULL;
353 			if(att==max_actors-1)max_actors--;
354 			else {
355 				//copy the last one down and fill in the hole
356 				max_actors--;
357 				actors_list[att]=actors_list[max_actors];
358 				actors_list[max_actors]=NULL;
359 				if (actors_list[att] && actors_list[att]->attached_actor >= 0)
360 					actors_list[actors_list[att]->attached_actor]->attached_actor = att;
361 			}
362 			break;
363 		}
364 
365 	UNLOCK_ACTORS_LISTS();
366 }
367 
set_health_color(actor * actor_id,float percent,float multiplier,float a)368 static void set_health_color(actor * actor_id, float percent, float multiplier, float a)
369 {
370 	float r,g;
371 
372 	if (actor_id != NULL)
373 	{
374 		// Only a subset of actors have health bars, so the choice
375 		// here is limited.
376 		if (actor_id->actor_id == yourself)
377 		{
378 			if (!dynamic_banner_colour.yourself)
379 				percent = 1.0f;
380 		}
381 		else if (actor_id->is_enhanced_model)
382 		{
383 			if (!dynamic_banner_colour.other_players)
384 				percent = 1.0f;
385 		}
386 		else if (!dynamic_banner_colour.creatures)
387 			percent = 1.0f;
388 	}
389 
390 	r=(1.0f-percent)*2.0f;
391 	g=(percent/1.25f)*2.0f;
392 
393 	if(r<0.0f)r=0.0f;
394 	else if(r>1.0f)r=1.0f;
395 	if(g<0.0f)g=0.0f;
396 	else if(g>1.0f)g=1.0f;
397 
398 	glColor4f(r*multiplier,g*multiplier,0.0f, a);
399 }
400 
set_mana_color(float percent,float multiplier,float a)401 static void set_mana_color(float percent, float multiplier, float a)
402 {
403 	float c;
404 
405 	if (!dynamic_banner_colour.yourself)
406 		percent = 1.0f;
407 
408 	c=0.6f - percent*0.6f;
409 
410 	if(c<0.0f)c=0.0f;
411 	else if(c>1.0f)c=1.0f;
412 
413 	glColor4f(c,c,2.0f, a);
414 }
415 
416 
draw_actor_banner(actor * actor_id,float offset_z)417 void draw_actor_banner(actor * actor_id, float offset_z)
418 {
419 	unsigned char str[60];
420 	GLdouble model[16],proj[16];
421 	GLint view[4];
422 
423 	GLdouble hx,hy,hz,a_bounce;
424 	float name_zoom = font_scales[NAME_FONT];
425 	float font_scale = 1.0f/ALT_INGAME_FONT_X_LEN;
426 	float stat_font_size = font_scale * ALT_INGAME_FONT_X_LEN; // base it on font_scale - OK so this makes it 1.0f currently
427 	float name_font_size = font_scale * SMALL_INGAME_FONT_X_LEN;
428 	double healthbar_x=0.0f;
429 	double healthbar_y=0.0f;
430 	double healthbar_z=offset_z+0.1;
431 	double healthbar_x_len_converted=0;
432 	double healthbar_x_len_loss=0;
433 	double healthbar_x_loss_fade=1.0f;
434 	double y_top, y_bottom;
435 
436 	//we use health bar variables if possible, all the extras we need for ether bar are:
437 	double ether_str_x_len = 0;
438 	double etherbar_x_len_converted=0;
439 	GLdouble name_bot_y, health_bot_y, ether_bot_y;
440 
441 	//some general values valid for whole banner
442 	double bar_x_len = 0;
443 	double bar_y_len = get_line_height(NAME_FONT, stat_font_size);
444 	float banner_width = 0.0f;
445 
446 	//define inner display_xxxxx variables to have more control over displaying inside this function
447 	//necesary to implement instance mode makes code a bit more easy to understand imho
448 	int display_hp = view_hp;
449 	int display_names = view_names;
450 	int display_health_bar = view_health_bar;
451 	int display_ether_bar = view_ether_bar;
452 	int display_ether = view_ether;
453 	int display_banner_alpha = use_alpha_banner;
454 
455 	//some general info about "what's going on" - allows not to repeat complex conditions later
456 	int displaying_me = 0;
457 	int displaying_other_player = 0;
458 	int display_health_line = 0;
459 	int display_ether_line = 0;
460 
461 	//if first person, dont draw banner
462 	actor *me = get_our_actor();
463 	if (me && me->actor_id==actor_id->actor_id) {
464 		displaying_me = 1;
465 	};
466 	if (displaying_me && first_person) return;
467 
468 	//if not drawing me, can't display ether and ether bar
469 	if (!displaying_me) {
470 		display_ether_bar = 0;
471 		display_ether = 0;
472 	}
473 
474 	//if instance mode enabled, overwrite default view banner view options according to it
475 	if (view_mode_instance) {
476 		//for my banner - use standard banner settings
477 		if (!actor_id->is_enhanced_model) {
478 			//creatures
479 			display_hp = im_creature_view_hp;
480 			display_names = im_creature_view_names;
481 			display_health_bar = im_creature_view_hp_bar;
482 			display_banner_alpha = im_creature_banner_bg;
483 		//TODO: it shows healthbar above mule & summons too - probably no way to solve this issue
484 		} else if (!displaying_me && actor_id->is_enhanced_model){
485 			//other players
486 			displaying_other_player = (actor_id->kind_of_actor != NPC);
487 			display_hp = im_other_player_view_hp;
488 			display_names = im_other_player_view_names;
489 			display_health_bar = im_other_player_view_hp_bar;
490 			display_banner_alpha = im_other_player_banner_bg;
491 		}
492 	}
493 
494 	//Figure out where the point just above the actor's head is in the viewport
495 	//See if Projection and viewport can be saved elsewhere to prevent doing this so often
496 	//MODELVIEW is hopeless
497 	glGetDoublev(GL_MODELVIEW_MATRIX, model);
498 	glGetDoublev(GL_PROJECTION_MATRIX, proj);
499 	glGetIntegerv(GL_VIEWPORT, view);
500 	// Input adjusted healthbar_y value to scale hy according to actor scale
501 	gluProject(healthbar_x, healthbar_y, healthbar_z * actor_id->scale * actors_defs[actor_id->actor_type].actor_scale + 0.02, model, proj, view, &hx, &hy, &hz);
502 
503 	//Save World-view and Projection matrices to allow precise raster placement of quads
504 	glPushMatrix();
505 	glLoadIdentity();
506 	glMatrixMode(GL_PROJECTION);
507 	glPushMatrix();
508 	glLoadIdentity();
509 	//Don't forget that the viewport is expressed in X+W,Y+H, or point-displacement,
510 	//versus the Ortho projection which expects x1,x2,y1,y2, or absolute coordinates
511 	glOrtho(view[0],view[2]+view[0],view[1],view[3]+view[1],0.0f,-1.0f);
512 
513 	glColor3f (1.0f, 0.0f, 0.0f);
514 
515 	glDepthFunc(GL_ALWAYS);
516 	if(actor_id->damage_ms){
517 		if(floatingmessages_enabled){
518 			float a=(float)(cur_time-actor_id->last_health_loss)/2000.0f;
519 			if(actor_id->damage>0){
520 				sprintf((char*)str,"%i",actor_id->damage);
521 				glColor4f(1.0f, 0.1f, 0.2f, 1.0-(a*a));
522 			} else {
523 				sprintf((char*)str,"%i",-actor_id->damage);
524 				glColor4f(0.3f, 1.0f, 0.3f, 1.0-(a*a));
525 			}
526 
527 			glEnable(GL_BLEND);
528 			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
529 
530 			//Make damage numbers bounce on the actor's head. Owie!
531 			a*=2000;
532 			a_bounce=0;
533 			if (a < 500){
534 				a_bounce = 50.0 - 0.0002 * powf(a,2);
535 			} else if ( a < 950.0){
536 				a_bounce = 0.09*(a-500.0) - .0002 * powf((a-500.0), 2);
537 			} else if ( a < 1355.0 ){
538 				a_bounce = 0.081*(a-950.0) - .0002 * powf((a-950.0), 2);
539 			} else if ( a < 1720 ){
540 				a_bounce = 0.0730*(a-1355.0) - .0002 * powf((a-1355.0), 2);
541 			} else {
542 				a_bounce = 0.0640*(a-1720.0) - .0002 * powf((a-1720.0), 2);
543 			}
544 			/* Schmurk: actually we never reach this code as long as there's
545 			 * an exit condition at the beginning of the function */
546 			if ((first_person)&&(actor_id->actor_id==yourself)){
547 				float x,y;
548 				x = window_width / 2.0 - 0.5f * (float)get_string_width_zoom(str, NAME_FONT,  font_scale*0.17);
549 				y = a_bounce + window_height/2.0-40.0;
550 				draw_ortho_ingame_string(x, y, 0, str, 1, NAME_FONT, font_scale*.14, font_scale*.14);
551 			}
552 			else
553 			{
554 				float font_scale2 = font_scale*powf(1.0f+((float)abs(actor_id->damage)/2.0f)/1000.0f, 4.0);
555 				int extra_y = (view_mode_instance && displaying_me) ?view_mode_instance_damage_height * bar_y_len : 0;
556 				int lines = (!(view_mode_instance && displaying_me) && (display_hp || display_health_bar) && (display_ether || display_ether_bar)) ? 3 : 2;
557 				draw_ortho_ingame_string(hx - 0.5f * (float)get_string_width_zoom(str, NAME_FONT, font_scale2*0.17),
558 					a_bounce + hy + extra_y + get_text_height(lines, NAME_FONT, name_zoom), 0, str, 1,
559 					NAME_FONT, font_scale2*.14, font_scale2*.14);
560 			}
561 			glDisable(GL_BLEND);
562 		}
563 		else
564 		{	//No floating messages
565 			sprintf((char*)str,"%i",actor_id->damage);
566 			glColor3f (1.0f, 0.3f, 0.3f);
567 			draw_ortho_ingame_string(-0.1f, 0.5*healthbar_z, 0.0f, str, 1, NAME_FONT,
568 				INGAME_FONT_X_LEN*10.0, INGAME_FONT_X_LEN*10.0);
569 		}
570 		if (view_mode_instance && im_other_player_show_banner_on_damage && displaying_other_player && !display_hp && !display_health_bar && actor_id->damage>0) {
571 			display_hp = 1;
572 			display_names = 1;
573 		}
574 	}
575 
576 	glDepthFunc(GL_LESS);
577 
578 	//figure out which lines should we display
579 	display_health_line = (actor_id->kind_of_actor != NPC && (display_hp || display_health_bar) && actor_id->cur_health > 0 && actor_id->max_health > 0);
580 	display_ether_line = ((display_ether || display_ether_bar) && displaying_me && your_info.ethereal_points.base > 0 );
581 	if (view_mode_instance && displaying_me) {
582 		//make your bar a bit more above everything else so you can see it good enough
583 		//and got no problems with attacking mobs
584 		hy += view_mode_instance_banner_height*bar_y_len;
585 	}
586 
587 	// calculate the bottom y coord for the displayed info lines, keep centred around a the same point whether 3, 2 or 1 line being displays
588 	hy += bar_y_len;
589 	name_bot_y = (display_names) ?hy + (display_health_line * bar_y_len / 2) + (display_ether_line * bar_y_len / 2) :0.0;
590 	health_bot_y = (display_health_line) ?hy - (display_names * bar_y_len / 2) + (display_ether_line * bar_y_len / 2) :0.0;
591 	ether_bot_y = (display_ether_line) ?hy -(display_names * bar_y_len / 2) - (display_health_line * bar_y_len / 2) : 0.0;
592 	// printf("hy=%.1lf name=%.1lf health=%.1lf ether=%.1lf\n", hy, name_bot_y, health_bot_y, ether_bot_y);
593 
594 	// main block that draws the name, health and ether text
595 	if (!((first_person)&&(actor_id->actor_id==yourself)))
596 	{
597 		if(actor_id->actor_name[0] && (display_names || display_health_line || display_ether_line))
598 		{
599 			if (display_names)
600 			{
601 				if(actor_id->kind_of_actor==NPC){
602 					glColor3f(0.3f,0.8f,1.0f);
603 				} else if(actor_id->kind_of_actor==HUMAN || actor_id->kind_of_actor==COMPUTER_CONTROLLED_HUMAN){
604 					if(map_type == 2){
605 						glColor3f(0.6f,0.9f,0.9f);
606 					} else {
607 						glColor3f(1.0f,1.0f,1.0f);
608 					}
609 				} else if(actor_id->is_enhanced_model && (actor_id->kind_of_actor==PKABLE_HUMAN || actor_id->kind_of_actor==PKABLE_COMPUTER_CONTROLLED)){
610 					glColor3f(1.0f,0.0f,0.0f);
611 				} else {
612 					glColor3f(1.0f,1.0f,0.0f);
613 				}
614 				banner_width = 0.5 * (float)get_string_width_zoom((unsigned char*)actor_id->actor_name, NAME_FONT, name_font_size);
615 				draw_ortho_ingame_string(hx - banner_width, name_bot_y, hz,
616 					(const unsigned char*)actor_id->actor_name, 1, NAME_FONT, name_font_size, name_font_size);
617 			}
618 			if (view_buffs)
619 			{
620 				draw_buffs(actor_id->actor_id, hx, hy, hz);
621 			}
622 
623 			if(  (!actor_id->dead) && (actor_id->kind_of_actor != NPC) && (display_health_line || display_ether_line)){
624 				unsigned char hp[200];
625 				unsigned char mana[200];
626 				double health_str_x_len = 0.0;
627 
628 				// make the heath bar the same length as the the health text so they are balanced
629 				// use the same length health bar, even if not displaying the health text
630 				sprintf((char*)hp,"%u/%u", actor_id->cur_health, actor_id->max_health);
631 				health_str_x_len = (float)get_string_width_zoom(hp, NAME_FONT, stat_font_size);
632 				//do the same with mana if we want to display it
633 				if (display_ether || display_ether_bar) {
634 					sprintf((char*)mana,"%d/%d", your_info.ethereal_points.cur, your_info.ethereal_points.base);
635 					ether_str_x_len=(float)get_string_width_zoom(mana, NAME_FONT, stat_font_size);
636 				}
637 				//set bar length to longer one (mana or health) - not really clean solution
638 				if (ether_str_x_len > health_str_x_len) {
639 					bar_x_len = ether_str_x_len;
640 				} else {
641 					bar_x_len = health_str_x_len;
642 				}
643 
644 				if (display_hp || display_ether) {
645 					float hp_off=(bar_x_len - health_str_x_len)/2.0;
646 					float eth_off=(bar_x_len - ether_str_x_len)/2.0;
647 					float disp;
648 					disp=(bar_x_len/2.0);
649 
650 					if(display_health_bar){
651 						hp_off+=5.0+disp;
652 					}
653 					if(display_ether_bar){
654 						eth_off+=5.0+disp;
655 					}
656 					if (display_hp && (disp+hp_off > banner_width)) {
657 						banner_width = disp + hp_off;
658 					}
659 					if (display_ether && (disp+eth_off > banner_width)) {
660 						banner_width = disp + eth_off;
661 					}
662 
663 					if (display_hp) {
664 						//choose color for the health
665 						set_health_color(actor_id, (float)actor_id->cur_health/(float)actor_id->max_health, 1.0f, 1.0f);
666 						draw_ortho_ingame_string(hx - disp + hp_off, health_bot_y,
667 							hz, hp, 1, NAME_FONT, stat_font_size, stat_font_size);
668 					}
669 
670 					if (display_ether) {
671 						set_mana_color((float)your_info.ethereal_points.cur / (float)your_info.ethereal_points.base, 1.0f, 1.0f);
672 						draw_ortho_ingame_string(hx - disp + eth_off, ether_bot_y,
673 							hz, mana, 1, NAME_FONT, stat_font_size, stat_font_size);
674 					}
675 				}
676 			}
677 		}
678 	}
679 
680 	//draw the health bar
681 	glDisable(GL_TEXTURE_2D);
682 
683 	if(display_health_bar && display_health_line && (!actor_id->dead) && (actor_id->kind_of_actor != NPC)){
684 		float percentage = (float)actor_id->cur_health/(float)actor_id->max_health;
685 		float off;
686 		float top_y = health_bot_y + bar_y_len / 3.0;
687 		float bot_y = health_bot_y + 2 * bar_y_len / 3.0;
688 
689 		if(percentage>1.1f) //deal with massive bars by trimming at 110%
690 			percentage = 1.1f;
691 		if (display_hp){
692 			off = bar_x_len + 5.0f;
693 		} else {
694 			off = bar_x_len / 2.0f;
695 		}
696 
697 		if(actor_id->last_health_loss && cur_time-actor_id->last_health_loss<1000){//only when using floatingmessages
698 			if(actor_id->damage>0){
699 				healthbar_x_len_converted=bar_x_len*percentage;
700 				healthbar_x_len_loss=bar_x_len*(float)((float)actor_id->damage/(float)actor_id->max_health);
701 				healthbar_x_loss_fade=1.0f-((float)(cur_time-actor_id->last_health_loss)/1000.0f);
702 			} else {
703 				healthbar_x_len_converted=bar_x_len*(float)((float)(actor_id->cur_health+actor_id->damage)/(float)actor_id->max_health);
704 				healthbar_x_len_loss=bar_x_len*(float)((float)(-actor_id->damage)/(float)actor_id->max_health);
705 				healthbar_x_loss_fade=((float)(cur_time-actor_id->last_health_loss)/1000.0f);
706 			}
707 		} else {
708 			healthbar_x_len_converted=bar_x_len*percentage;
709 			actor_id->last_health_loss=0;
710 		}
711 
712 		if (bar_x_len / 2.0f > banner_width) {
713 			banner_width = bar_x_len / 2.0f;
714 		}
715 
716 		hx-=off;
717 
718 		//choose tint color
719 		set_health_color(actor_id, percentage, 0.5f, 1.0f);
720 		glBegin(GL_QUADS);
721 			glVertex3d(hx, top_y, hz);
722 			glVertex3d(hx + healthbar_x_len_converted, top_y, hz);
723 
724 		set_health_color(actor_id, percentage, 1.0f, 1.0f);
725 
726 			glVertex3d(hx + healthbar_x_len_converted, bot_y, hz);
727 			glVertex3d(hx, bot_y, hz);
728 		glEnd();
729 
730 		if(healthbar_x_len_loss){
731 			glEnable(GL_BLEND);
732 			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
733 
734 			set_health_color(actor_id, percentage, 0.5f, healthbar_x_loss_fade);
735 
736 			glBegin(GL_QUADS);
737 				glVertex3d(hx + healthbar_x_len_converted, top_y, hz);
738 				glVertex3d(hx + healthbar_x_len_converted + healthbar_x_len_loss, top_y, hz);
739 
740 			set_health_color(actor_id, percentage, 1.0f, healthbar_x_loss_fade);
741 
742 				glVertex3d(hx + healthbar_x_len_converted + healthbar_x_len_loss, bot_y, hz);
743 				glVertex3d(hx + healthbar_x_len_converted, bot_y, hz);
744 			glEnd();
745 
746 			glDisable(GL_BLEND);
747 		}
748 
749 		//draw the frame
750 		glDepthFunc(GL_LEQUAL);
751 		glColor3f(0.0f, 0.0f, 0.0f);
752 		glBegin(GL_LINE_LOOP);
753 			glVertex3f(hx - 1.0, top_y - 1.0, hz);
754 			glVertex3f(hx + bar_x_len + 1.0, top_y - 1.0, hz);
755 			glVertex3f(hx + bar_x_len + 1.0, bot_y + 1.0, hz);
756 			glVertex3f(hx - 1.0, bot_y + 1.0, hz);
757 		glEnd();
758 
759 		hx+=off;
760 	}
761 
762 	if (display_ether_bar && display_ether_line) {
763 		float percentage = (float)your_info.ethereal_points.cur / (float)your_info.ethereal_points.base;
764 		float off;
765 		float top_y = ether_bot_y + bar_y_len / 3.0;
766 		float bot_y = ether_bot_y + 2 * bar_y_len / 3.0;
767 		if(percentage>1.1f) // limit bar length to +10%
768 			percentage = 1.1f;
769 		if (display_ether){
770 			off = bar_x_len + 5.0f;
771 		} else {
772 			off = bar_x_len / 2.0f;
773 		}
774 		if (bar_x_len / 2.0f > banner_width) {
775 			banner_width = bar_x_len / 2.0f;
776 		}
777 		hx-=off;
778 
779 		set_mana_color(percentage, 0.5f, 1.0f);
780 		etherbar_x_len_converted = percentage * bar_x_len;
781 		glBegin(GL_QUADS);
782 			glVertex3d(hx, top_y, hz);
783 			glVertex3d(hx + etherbar_x_len_converted, top_y, hz);
784 
785 		set_mana_color(percentage, 1.0f, 1.0f);
786 
787 			glVertex3d(hx + etherbar_x_len_converted, bot_y, hz);
788 			glVertex3d(hx, bot_y, hz);
789 		glEnd();
790 		set_health_color(actor_id, percentage, 1.0f, 1.0f);
791 		glDepthFunc(GL_LEQUAL);
792 		glColor3f (0.0f, 0.0f, 0.0f);
793 		glBegin(GL_LINE_LOOP);
794 			glVertex3f (hx - 1.0, top_y - 1.0 , hz);
795 			glVertex3f (hx + bar_x_len + 1.0, top_y - 1.0, hz);
796 			glVertex3f (hx + bar_x_len + 1.0, bot_y + 1.0, hz);
797 			glVertex3f (hx - 1.0, bot_y + 1.0, hz);
798 		glEnd();
799 		hx+=off;
800 	}
801 
802 	// draw the alpha background (if ness)
803 	y_bottom = ((ether_bot_y > 0) ?ether_bot_y :((health_bot_y > 0) ?health_bot_y : name_bot_y)) - 0.2 * bar_y_len;
804 	y_top = ((name_bot_y > 0) ?name_bot_y :((health_bot_y > 0) ?health_bot_y : ether_bot_y)) + 1.2 * bar_y_len;
805 	if (display_banner_alpha && banner_width > 0) {
806 		//if banner width > 0 there MUST be something displayed in the banner
807 		banner_width += name_zoom * 3;
808 		glEnable(GL_BLEND);
809 		glBlendFunc(GL_ONE, GL_SRC_ALPHA);
810 		glColor4f(0.0f, 0.0f, 0.0f, 0.6f);
811 		glBegin(GL_QUADS);
812 			glVertex3f(hx-banner_width, y_bottom, hz + 0.0001);
813 			glVertex3f(hx+banner_width, y_bottom, hz + 0.0001);
814 			glVertex3f(hx+banner_width, y_top, hz + 0.0001);
815 			glVertex3f(hx-banner_width, y_top, hz + 0.0001);
816 		glEnd();
817 		glDisable(GL_BLEND);
818 	}
819 
820 	glEnable(GL_TEXTURE_2D);
821 
822 	if ((actor_id->current_displayed_text_time_left>0)&&(actor_id->current_displayed_text[0] != 0)){
823 		draw_actor_overtext(actor_id, hx, y_top, hz);
824 	}
825 
826 	glMatrixMode(GL_PROJECTION);
827 	glPopMatrix();
828 	glMatrixMode(GL_MODELVIEW);
829 	glPopMatrix();
830 
831 	if(floatingmessages_enabled)drawactor_floatingmessages(actor_id->actor_id, healthbar_z);
832 
833 	/* set cm_mouse_over_banner true if the mouse is over your banner, or a box where it might be */
834 	if (actor_id->actor_id == yourself)
835 	{
836 		/* use the same calculation as for the alpha background but have a fallback if no banner shown */
837 		int xoff = (banner_width > 0) ?banner_width: 60;
838 		int yoff = (banner_width > 0) ?y_top - y_bottom: bar_y_len;
839 		if ((mouse_x > hx-xoff) && (mouse_x < hx+xoff) &&
840 			((window_height - mouse_y) > y_bottom) && ((window_height - mouse_y) < (y_bottom + yoff)))
841 			cm_mouse_over_banner = 1;
842 		else
843 			cm_mouse_over_banner = 0;
844 	}
845 
846 	glColor3f(1,1,1);
847 #ifdef OPENGL_TRACE
848 CHECK_GL_ERRORS();
849 #endif //OPENGL_TRACE
850 }
851 
852 
draw_bubble(float x_left,float x_right,float x_leg_left,float x_leg_right,float y_top,float y_bottom,float y_actor,float z,float r)853 static void draw_bubble(float x_left, float x_right, float x_leg_left, float x_leg_right,
854 	float y_top, float y_bottom, float y_actor, float z, float r)
855 {
856 	const float mul = M_PI/180.0f;
857 	int angle;
858 
859 	glEnable(GL_BLEND);
860 	glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
861 	glBlendFunc(GL_NONE, GL_SRC_ALPHA);
862 
863 	glBegin(GL_POLYGON);
864 	for (angle = 0; angle <= 90; angle += 10)
865 	{
866 		float rad = mul * angle;
867 		glVertex3f(x_right - r + cos(rad)*r, y_top - r + sin(rad)*r, z);
868 	}
869 
870 	for (angle = 90;angle <= 180; angle += 10)
871 	{
872 		float rad = mul*angle;
873 		glVertex3f(x_left + r + cos(rad)*r, y_top - r + sin(rad)*r, z);
874 	}
875 
876 	for(angle = 180; angle < 270; angle += 10)
877 	{
878 		float rad = mul*angle;
879 		glVertex3f(x_left + r + cos(rad)*r, y_bottom + r + sin(rad)*r, z);
880 	}
881 	// Explicitly include the vertices where the leg attaches to the bubble, to prevent a gap
882 	// between the bubble and the leg
883 	glVertex3f(x_leg_left, y_bottom, z);
884 	glVertex3f(x_leg_right, y_bottom, z);
885 
886 	for (angle = 270; angle <= 360; angle += 10)
887 	{
888 		float rad = mul*angle;
889 		glVertex3f(x_right - r + cos(rad)*r, y_bottom + r + sin(rad)*r, z);
890 	}
891 	glEnd(); // GL_POLYGON
892 
893 	glBegin(GL_TRIANGLES);
894 		glVertex3f(x_leg_left, y_bottom, z);
895 		glVertex3f(x_leg_right, y_actor, z);
896 		glVertex3f(x_leg_right, y_bottom, z);
897 	glEnd();
898 
899 	glDisable(GL_BLEND);
900 #ifdef OPENGL_TRACE
901 CHECK_GL_ERRORS();
902 #endif //OPENGL_TRACE
903 }
904 
905 //-- Logan Dugenoux [5/26/2004]
draw_actor_overtext(actor * actor_ptr,double x,double y,double z)906 static void draw_actor_overtext(actor* actor_ptr, double x, double y, double z)
907 {
908 	int lines = min2i(actor_ptr->current_displayed_text_lines, MAX_CURRENT_DISPLAYED_TEXT_LINES);
909 	float font_scale = 0.14f / ALT_INGAME_FONT_X_LEN;
910 	float x_left, x_right, x_leg_left, x_leg_right, y_top, y_bottom;
911 	int text_width, line_height, text_height;
912 	float margin;
913 
914 	actor *me = get_our_actor();
915 	if (me && me != actor_ptr)
916 	{
917 		const float s_rx = sin(rx * M_PI / 180);
918 		const float c_rx = cos(rx * M_PI / 180);
919 		const float s_rz = sin(rz * M_PI / 180);
920 		const float c_rz = cos(rz * M_PI / 180);
921 		float cam_x = me->x_pos + zoom_level*camera_distance * s_rx * s_rz;
922 		float cam_y = me->y_pos + zoom_level*camera_distance * s_rx * c_rz;
923 		float cam_z = me->z_pos + zoom_level*camera_distance * c_rx;
924 		double dx, dy, dz, actor_dsq, me_dsq;
925 		dx = actor_ptr->x_pos - cam_x;
926 		dy = actor_ptr->y_pos - cam_y;
927 		dz = actor_ptr->z_pos - cam_z;
928 		actor_dsq = dx*dx + dy*dy + dz*dz;
929 		me_dsq = zoom_level*zoom_level * camera_distance*camera_distance;
930 		font_scale *= 0.5 + 0.5 * me_dsq / actor_dsq;
931 	}
932 
933 	get_buf_dimensions((const unsigned char*)actor_ptr->current_displayed_text,
934 		strlen(actor_ptr->current_displayed_text),
935 		CHAT_FONT, font_scale, &text_width, &text_height);
936 	line_height = get_line_height(CHAT_FONT, font_scale);
937 
938 	margin = 0.5 * line_height;
939 
940 	x_left = x - 0.5*text_width - margin;
941 	x_right = x + 0.5*text_width + margin;
942 	x_leg_left = x - margin;
943 	x_leg_right = x;
944 
945 	y_bottom = y + 1.5*margin;
946 	y_top = y_bottom + text_height + 2*margin;
947 
948 	glDisable(GL_TEXTURE_2D);
949 	draw_bubble(x_left, x_right, x_leg_left, x_leg_right, y_top, y_bottom, y, z+0.0001f, 1.5*margin);
950 	glEnable(GL_TEXTURE_2D);
951 
952 	//---
953 	// Draw text
954 
955 	draw_ortho_ingame_string(x - 0.5f * text_width, y_bottom + margin + text_height - line_height, z,
956 		(const unsigned char*)actor_ptr->current_displayed_text, lines,
957 		CHAT_FONT, font_scale, font_scale);
958 
959 	//-- decrease display time
960 	actor_ptr->current_displayed_text_time_left -= (cur_time-last_time);
961 	if (actor_ptr->current_displayed_text_time_left <= 0)
962 	{	// clear if needed
963 		actor_ptr->current_displayed_text_time_left = 0;
964 		actor_ptr->current_displayed_text_lines = 0;
965 		actor_ptr->current_displayed_text[0] = '\0';
966 	}
967 #ifdef OPENGL_TRACE
968 CHECK_GL_ERRORS();
969 #endif //OPENGL_TRACE
970 }
971 
draw_actor_without_banner(actor * actor_id,Uint32 use_lightning,Uint32 use_textures,Uint32 use_glow)972 void draw_actor_without_banner(actor * actor_id, Uint32 use_lightning, Uint32 use_textures, Uint32 use_glow)
973 {
974 	double x_pos,y_pos,z_pos;
975 	float x_rot,y_rot,z_rot;
976 	//if first person, dont draw actor
977 	actor *me = get_our_actor();
978 	if (me&&me->actor_id==actor_id->actor_id&&first_person) return;
979 	if (use_textures)
980 	{
981 		if (actor_id->is_enhanced_model)
982 		{
983 			if (bind_actor_texture(actor_id->texture_id, &actor_id->has_alpha) == 0)
984 			{
985 				return;
986 			}
987 		}
988 		else
989 		{
990 			if (!actor_id->remapped_colors)
991 			{
992 				bind_texture(actor_id->texture_id);
993 			}
994 			else
995 			{
996 				if (bind_actor_texture(actor_id->texture_id, &actor_id->has_alpha) == 0)
997 				{
998 					return;
999 				}
1000 			}
1001 		}
1002 	}
1003 
1004 	glPushMatrix();//we don't want to affect the rest of the scene
1005 
1006 	x_pos = actor_id->x_pos;
1007 	y_pos = actor_id->y_pos;
1008 	z_pos = actor_id->z_pos;
1009 
1010 	if (z_pos == 0.0f)
1011 	{
1012 		//actor is walking, as opposed to flying, get the height underneath
1013 		z_pos = get_tile_height(actor_id->x_tile_pos, actor_id->y_tile_pos);
1014 	}
1015 
1016 	x_rot = actor_id->x_rot;
1017 	y_rot = actor_id->y_rot;
1018 	z_rot = 180 - actor_id->z_rot;
1019 
1020 	glTranslatef(x_pos + 0.25f, y_pos + 0.25f, z_pos);
1021 
1022 	glRotatef(z_rot, 0.0f, 0.0f, 1.0f);
1023 	glRotatef(x_rot, 1.0f, 0.0f, 0.0f);
1024 	glRotatef(y_rot, 0.0f, 1.0f, 0.0f);
1025 
1026 	if (actor_id->attached_actor >= 0)
1027 		glTranslatef(actor_id->attachment_shift[0], actor_id->attachment_shift[1], actor_id->attachment_shift[2]);
1028 
1029 	if (use_animation_program)
1030 	{
1031 		cal_render_actor_shader(actor_id, use_lightning, use_textures, use_glow);
1032 	}
1033 	else
1034 	{
1035 		cal_render_actor(actor_id, use_lightning, use_textures, use_glow);
1036 	}
1037 
1038 	//now, draw their damage & nametag
1039 	glPopMatrix();  // restore the matrix
1040 
1041 #ifdef OPENGL_TRACE
1042 CHECK_GL_ERRORS();
1043 #endif //OPENGL_TRACE
1044 }
1045 
draw_actor_banner_new(actor * actor_id)1046 static __inline__ void draw_actor_banner_new(actor * actor_id)
1047 {
1048 	float x_pos, y_pos, z_pos;
1049 	float healthbar_z;
1050 
1051 	healthbar_z = actor_id->max_z + 0.2;
1052 
1053 	glPushMatrix();//we don't want to affect the rest of the scene
1054 
1055 	x_pos = actor_id->x_pos;
1056 	y_pos = actor_id->y_pos;
1057 	z_pos = actor_id->z_pos;
1058 
1059 	if (z_pos == 0.0f)
1060 	{
1061 		//actor is walking, as opposed to flying, get the height underneath
1062 		z_pos = get_tile_height(actor_id->x_tile_pos, actor_id->y_tile_pos);
1063 	}
1064 
1065 	glTranslatef(x_pos + 0.25f, y_pos + 0.25f, z_pos);
1066 
1067 	if (actor_id->attached_actor >= 0)
1068 	{
1069 		glRotatef(180 - actor_id->z_rot, 0.0f, 0.0f, 1.0f);
1070 		glTranslatef(actor_id->attachment_shift[0], actor_id->attachment_shift[1], actor_id->attachment_shift[2]);
1071 		glRotatef(180 - actor_id->z_rot, 0.0f, 0.0f, -1.0f);
1072 	}
1073 
1074 	glRotatef(-rz, 0.0f, 0.0f, 1.0f);
1075 
1076 	draw_actor_banner(actor_id, healthbar_z);
1077 
1078 	glPopMatrix();	//we don't want to affect the rest of the scene
1079 #ifdef OPENGL_TRACE
1080 CHECK_GL_ERRORS();
1081 #endif //OPENGL_TRACE
1082 }
1083 
comp_actors(const void * in_a,const void * in_b)1084 static int comp_actors(const void *in_a, const void *in_b)
1085 {
1086 	near_actor *a, *b;
1087 	int at, bt;
1088 
1089 	a = (near_actor *)in_a;
1090 	b = (near_actor *)in_b;
1091 
1092 	at = a->type;
1093 	bt = b->type;
1094 
1095 	if (at < bt)
1096 	{
1097 		return (-1);
1098 	}
1099 	else
1100 	{
1101 		if (at == bt)
1102 		{
1103 			return (0);
1104 		}
1105 		else
1106 		{
1107 			return (1);
1108 		}
1109 	}
1110 }
1111 
get_actors_in_range()1112 void get_actors_in_range()
1113 {
1114 	VECTOR3 pos;
1115 	unsigned int i;
1116 #ifdef NEW_SOUND
1117 	unsigned int tmp_nr_enh_act;		// Use temp variables to stop crowd sound interference during count
1118 	float tmp_dist_to_nr_enh_act;
1119 #endif // NEW_SOUND
1120 	actor *me;
1121 	AABBOX bbox;
1122 
1123 	me = get_our_actor ();
1124 
1125 	if (!me) return;
1126 
1127 	no_near_actors = 0;
1128 #ifdef NEW_SOUND
1129 	tmp_nr_enh_act = 0;
1130 	tmp_dist_to_nr_enh_act = 0;
1131 #endif // NEW_SOUND
1132 
1133 	set_current_frustum(get_cur_intersect_type(main_bbox_tree));
1134 
1135 	for (i = 0; i < max_actors; i++)
1136 	{
1137 		if(actors_list[i]
1138 #ifdef CLUSTER_INSIDES
1139 		   && (actors_list[i]->cluster == me->cluster || actors_list[i]->cluster == 0)
1140 #endif
1141 		)
1142 		{
1143 			// if we have an attached actor, we maybe have to modify the position of the current actor
1144 			if (actors_list[i]->attached_actor >= 0)
1145 			{
1146 				actor *att = actors_list[actors_list[i]->attached_actor];
1147 				attachment_props *att_props;
1148 				float loc_pos[3];
1149 				float att_pos[3];
1150 				float loc_scale = get_actor_scale(actors_list[i]);
1151 				float att_scale = get_actor_scale(att);
1152 				if (actors_list[i]->actor_id < 0) // we are on a attached actor
1153 				{
1154 					att_props = &attached_actors_defs[actors_list[i]->actor_type].actor_type[att->actor_type];
1155 					if (!att_props->is_holder) // the attachment is not a holder so we have to move it
1156 					{
1157 						cal_get_actor_bone_local_position(att, att_props->parent_bone_id, NULL, att_pos);
1158 						cal_get_actor_bone_local_position(actors_list[i], att_props->local_bone_id, NULL, loc_pos);
1159 						actors_list[i]->attachment_shift[0] = att_pos[0] * att_scale - (loc_pos[0] - att_props->shift[0]) * loc_scale;
1160 						actors_list[i]->attachment_shift[1] = att_pos[1] * att_scale - (loc_pos[1] - att_props->shift[1]) * loc_scale;
1161 						actors_list[i]->attachment_shift[2] = att_pos[2] * att_scale - (loc_pos[2] - att_props->shift[2]) * loc_scale;
1162 					}
1163 				}
1164 				else if (actors_list[i]->actor_id >= 0) // we are on a standard actor
1165 				{
1166 					att_props = &attached_actors_defs[att->actor_type].actor_type[actors_list[i]->actor_type];
1167 					if (att_props->is_holder) // the attachment is an holder, we have to move the current actor
1168 					{
1169 						cal_get_actor_bone_local_position(att, att_props->local_bone_id, NULL, att_pos);
1170 						cal_get_actor_bone_local_position(actors_list[i], att_props->parent_bone_id, NULL, loc_pos);
1171 						actors_list[i]->attachment_shift[0] = att_pos[0] * att_scale - (loc_pos[0] - att_props->shift[0]) * loc_scale;
1172 						actors_list[i]->attachment_shift[1] = att_pos[1] * att_scale - (loc_pos[1] - att_props->shift[1]) * loc_scale;
1173 						actors_list[i]->attachment_shift[2] = att_pos[2] * att_scale - (loc_pos[2] - att_props->shift[2]) * loc_scale;
1174 					}
1175 				}
1176 			}
1177 			pos[X] = actors_list[i]->x_pos + actors_list[i]->attachment_shift[X];
1178 			pos[Y] = actors_list[i]->y_pos + actors_list[i]->attachment_shift[Y];
1179 			pos[Z] = actors_list[i]->z_pos + actors_list[i]->attachment_shift[Z];
1180 
1181 			if (pos[Z] == 0.0f)
1182 			{
1183 				//actor is walking, as opposed to flying, get the height underneath
1184 				pos[Z] = get_tile_height(actors_list[i]->x_tile_pos, actors_list[i]->y_tile_pos);
1185 			}
1186 
1187 			if (actors_list[i]->calmodel == NULL) continue;
1188 
1189 			memcpy(&bbox, &actors_list[i]->bbox, sizeof(AABBOX));
1190 			rotate_aabb(&bbox, actors_list[i]->x_rot, actors_list[i]->y_rot, 180.0f-actors_list[i]->z_rot);
1191 
1192 			VAddEq(bbox.bbmin, pos);
1193 			VAddEq(bbox.bbmax, pos);
1194 
1195 			if (aabb_in_frustum(bbox))
1196 			{
1197 				near_actors[no_near_actors].actor = i;
1198 				near_actors[no_near_actors].ghost = actors_list[i]->ghost;
1199 				near_actors[no_near_actors].buffs = actors_list[i]->buffs;
1200 				near_actors[no_near_actors].select = 0;
1201 				near_actors[no_near_actors].type = actors_list[i]->actor_type;
1202 				if (actors_list[i]->ghost)
1203 				{
1204 					near_actors[no_near_actors].alpha = 0;
1205 				}
1206 				else
1207 				{
1208 					near_actors[no_near_actors].alpha =
1209 						actors_list[i]->has_alpha;
1210 				}
1211 
1212 				actors_list[i]->max_z = actors_list[i]->bbox.bbmax[Z];
1213 
1214 				if (read_mouse_now && (get_cur_intersect_type(main_bbox_tree) == INTERSECTION_TYPE_DEFAULT))
1215 				{
1216 					near_actors[no_near_actors].select = 1;
1217 				}
1218 				no_near_actors++;
1219 #ifdef NEW_SOUND
1220 				if (actors_list[i]->is_enhanced_model && actors_list[i]->actor_id != me->actor_id)
1221 				{
1222 					tmp_nr_enh_act++;
1223 					tmp_dist_to_nr_enh_act += ((me->x_pos - actors_list[i]->x_pos) *
1224 														(me->x_pos - actors_list[i]->x_pos)) +
1225 														((me->y_pos - actors_list[i]->y_pos) *
1226 														(me->y_pos - actors_list[i]->y_pos));
1227 				}
1228 #endif // NEW_SOUND
1229 			}
1230 		}
1231 	}
1232 #ifdef NEW_SOUND
1233 	if (tmp_nr_enh_act > 0)
1234 		tmp_dist_to_nr_enh_act = tmp_dist_to_nr_enh_act / tmp_nr_enh_act;
1235 	no_near_enhanced_actors = tmp_nr_enh_act;
1236 	distanceSq_to_near_enhanced_actors = tmp_dist_to_nr_enh_act;
1237 #endif // NEW_SOUND
1238 	qsort(near_actors, no_near_actors, sizeof(near_actor), comp_actors);
1239 }
1240 
display_actors(int banner,int render_pass)1241 void display_actors(int banner, int render_pass)
1242 {
1243 	Sint32 i, has_alpha, has_ghosts;
1244 	Uint32 use_lightning = 0, use_textures = 0;
1245 
1246 	get_actors_in_range();
1247 
1248 	glEnable(GL_CULL_FACE);
1249 
1250 	if (use_animation_program)
1251 	{
1252 		set_actor_animation_program(render_pass, 0);
1253 	}
1254 
1255 	switch (render_pass)
1256 	{
1257 		case DEFAULT_RENDER_PASS:
1258 		case SHADOW_RENDER_PASS:
1259 		case REFLECTION_RENDER_PASS:
1260 			use_lightning = 1;
1261 			use_textures = 1;
1262 			break;
1263 		case DEPTH_RENDER_PASS:
1264 			use_lightning = 0;
1265 			use_textures = 1;
1266 			break;
1267 	}
1268 
1269 	has_alpha = 0;
1270 	has_ghosts = 0;
1271 
1272 #ifdef	FSAA
1273 	if (fsaa > 1)
1274 	{
1275 		glEnable(GL_MULTISAMPLE);
1276 	}
1277 #endif	/* FSAA */
1278 	for (i = 0; i < no_near_actors; i++)
1279 	{
1280 		if (near_actors[i].ghost || (near_actors[i].buffs & BUFF_INVISIBILITY))
1281 		{
1282 			if ((render_pass == DEFAULT_RENDER_PASS) ||
1283 				(render_pass == SHADOW_RENDER_PASS))
1284 			{
1285 				has_ghosts = 1;
1286 			}
1287 		}
1288 		else if (near_actors[i].alpha)
1289 		{
1290 			has_alpha = 1;
1291 		}
1292 		else
1293 		{
1294 			actor *cur_actor = actors_list[near_actors[i].actor];
1295 			if (cur_actor)
1296 			{
1297 				draw_actor_without_banner(cur_actor, use_lightning, use_textures, 1);
1298 				if (near_actors[i].select)
1299 				{
1300 					if (cur_actor->kind_of_actor == NPC)
1301 					{
1302 						anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_NPC);
1303 					}
1304 					else
1305 					{
1306 						if ((cur_actor->kind_of_actor == HUMAN) ||
1307 							(cur_actor->kind_of_actor == COMPUTER_CONTROLLED_HUMAN) ||
1308 							(cur_actor->is_enhanced_model &&
1309 							((cur_actor->kind_of_actor == PKABLE_HUMAN) ||
1310 							(cur_actor->kind_of_actor == PKABLE_COMPUTER_CONTROLLED))))
1311 						{
1312 							anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_PLAYER);
1313 						}
1314 						else
1315 						{
1316 							anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_ANIMAL);
1317 						}
1318 					}
1319 				}
1320 			}
1321 		}
1322 	}
1323 	if (has_alpha)
1324 	{
1325 		glEnable(GL_ALPHA_TEST);
1326 		glAlphaFunc(GL_GREATER, 0.4f);
1327 		for (i = 0; i < no_near_actors; i++)
1328 		{
1329 
1330 			if (near_actors[i].alpha && !(near_actors[i].ghost || (near_actors[i].buffs & BUFF_INVISIBILITY)))
1331 			{
1332 
1333 				actor *cur_actor = actors_list[near_actors[i].actor];
1334 				if (cur_actor)
1335 				{
1336 					draw_actor_without_banner(cur_actor, use_lightning, 1, 1);
1337 
1338 					if (near_actors[i].select)
1339 					{
1340 						if (cur_actor->kind_of_actor == NPC)
1341 						{
1342 							anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_NPC);
1343 						}
1344 						else
1345 						{
1346 							if ((cur_actor->kind_of_actor == HUMAN) ||
1347 								(cur_actor->kind_of_actor == COMPUTER_CONTROLLED_HUMAN) ||
1348 								(cur_actor->is_enhanced_model &&
1349 								 ((cur_actor->kind_of_actor == PKABLE_HUMAN) ||
1350 								 (cur_actor->kind_of_actor == PKABLE_COMPUTER_CONTROLLED))))
1351 							{
1352 								anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_PLAYER);
1353 							}
1354 							else
1355 							{
1356 								anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_ANIMAL);
1357 							}
1358 						}
1359 					}
1360 				}
1361 			}
1362 		}
1363 		glDisable(GL_ALPHA_TEST);
1364 	}
1365 	if (has_ghosts)
1366 	{
1367 		glEnable(GL_BLEND);
1368 		glDisable(GL_LIGHTING);
1369 		if (use_animation_program)
1370 		{
1371 			set_actor_animation_program(render_pass, 1);
1372 		}
1373 
1374 		for (i = 0; i < no_near_actors; i++)
1375 		{
1376 
1377 			if (near_actors[i].ghost || (near_actors[i].buffs & BUFF_INVISIBILITY))
1378 			{
1379 
1380 				actor *cur_actor = actors_list[near_actors[i].actor];
1381 				if (cur_actor)
1382 				{
1383 					//if any ghost has a glowing weapon, we need to reset the blend function each ghost actor.
1384 					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1385 
1386 					if (!use_animation_program)
1387 					{
1388 						if ((near_actors[i].buffs & BUFF_INVISIBILITY))
1389 						{
1390 							glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
1391 						}
1392 						else
1393 						{
1394 							glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1395 						}
1396 					}
1397 
1398 					draw_actor_without_banner(cur_actor, use_lightning, use_textures, 1);
1399 
1400 					if (near_actors[i].select)
1401 					{
1402 						if (cur_actor->kind_of_actor == NPC)
1403 						{
1404 							anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_NPC);
1405 						}
1406 						else
1407 						{
1408 							if ((cur_actor->kind_of_actor == HUMAN) ||
1409 								(cur_actor->kind_of_actor == COMPUTER_CONTROLLED_HUMAN) ||
1410 								(cur_actor->is_enhanced_model &&
1411 								 ((cur_actor->kind_of_actor == PKABLE_HUMAN) ||
1412 								 (cur_actor->kind_of_actor == PKABLE_COMPUTER_CONTROLLED))))
1413 							{
1414 								anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_PLAYER);
1415 							}
1416 							else
1417 							{
1418 								anything_under_the_mouse(near_actors[i].actor, UNDER_MOUSE_ANIMAL);
1419 							}
1420 						}
1421 					}
1422 				}
1423 			}
1424 		}
1425 		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1426 		glDisable(GL_BLEND);
1427 		glEnable(GL_LIGHTING);
1428 	}
1429 #ifdef	FSAA
1430 	if (fsaa > 1)
1431 	{
1432 		glDisable(GL_MULTISAMPLE);
1433 	}
1434 #endif	/* FSAA */
1435 
1436 	if (use_animation_program)
1437 	{
1438 		disable_actor_animation_program();
1439 	}
1440 
1441 	if (banner)
1442 	{
1443 		if (use_shadow_mapping)
1444 		{
1445 			glPushAttrib(GL_TEXTURE_BIT|GL_ENABLE_BIT);
1446 			glDisable(GL_TEXTURE_2D);
1447 			ELglActiveTextureARB(shadow_unit);
1448 			glDisable(depth_texture_target);
1449 			disable_texgen();
1450 			ELglActiveTextureARB(GL_TEXTURE0);
1451 			glEnable(GL_TEXTURE_2D);
1452 			glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1453 		}
1454 
1455 		glDisable(GL_LIGHTING);
1456 		glDisable(GL_BLEND);
1457 
1458 		for (i = 0; i < no_near_actors; i++)
1459 		{
1460 			actor *cur_actor = actors_list[near_actors[i].actor];
1461 			if (cur_actor
1462 				&& cur_actor->actor_id >= 0
1463 				)
1464 			{
1465 				draw_actor_banner_new(cur_actor);
1466 			}
1467 		}
1468 
1469 		if (use_shadow_mapping)
1470 		{
1471 			last_texture = -1;
1472 			glPopAttrib();
1473 		}
1474 
1475 		glDisable(GL_BLEND);
1476 		glEnable(GL_LIGHTING);
1477 	}
1478 #ifdef OPENGL_TRACE
1479 CHECK_GL_ERRORS();
1480 #endif //OPENGL_TRACE
1481 }
1482 
1483 
add_actor_from_server(const char * in_data,int len)1484 void add_actor_from_server (const char *in_data, int len)
1485 {
1486 	short actor_id;
1487 	Uint32 buffs = 0;
1488 	short x_pos;
1489 	short y_pos;
1490 	short z_rot;
1491 	short max_health;
1492 	short cur_health;
1493 	short actor_type;
1494 	Uint8 frame;
1495 	int i;
1496 	int dead=0;
1497 	int kind_of_actor;
1498 
1499 	double f_x_pos,f_y_pos,f_z_rot;
1500 	float scale= 1.0f;
1501 	emote_data *pose=NULL;
1502 	int attachment_type = -1;
1503 
1504 	actor_id=SDL_SwapLE16(*((short *)(in_data)));
1505 #ifndef EL_BIG_ENDIAN
1506 	buffs=((*((char *)(in_data+3))>>3)&0x1F) | (((*((char*)(in_data+5))>>3)&0x1F)<<5);	// Strip the last 5 bits of the X and Y coords for the buffs
1507 	x_pos=*((short *)(in_data+2)) & 0x7FF;
1508 	y_pos=*((short *)(in_data+4)) & 0x7FF;
1509 #else
1510 	buffs=((SDL_SwapLE16(*((char*)(in_data+3)))>>3)&0x1F | (SDL_SwapLE16(((*((char*)(in_data+5)))>>3)&0x1F)<<5));	// Strip the last 5 bits of the X and Y coords for the buffs
1511 	x_pos=SDL_SwapLE16(*((short *)(in_data+2))) & 0x7FF;
1512 	y_pos=SDL_SwapLE16(*((short *)(in_data+4))) & 0x7FF;
1513 #endif //EL_BIG_ENDIAN
1514 	buffs |= (SDL_SwapLE16(*((short *)(in_data+6))) & 0xFF80) << 3; // we get the 9 MSB for the buffs and leave the 7 LSB for a further use
1515 	z_rot=SDL_SwapLE16(*((short *)(in_data+8)));
1516 	actor_type=*(in_data+10);
1517 
1518 	frame=*(in_data+11);
1519 	max_health=SDL_SwapLE16(*((short *)(in_data+12)));
1520 	cur_health=SDL_SwapLE16(*((short *)(in_data+14)));
1521 	kind_of_actor=*(in_data+16);
1522 	if(len > 17+(int)strlen(in_data+17)+2){
1523 		scale=((float)SDL_SwapLE16(*((short *)(in_data+17+strlen(in_data+17)+1)))/((float)ACTOR_SCALE_BASE));
1524 
1525 		if(len > 17+(int)strlen(in_data+17)+3)
1526 			attachment_type = (unsigned char)in_data[17+strlen(in_data+17)+3];
1527 	}
1528 
1529 	if(actor_type < 0 || actor_type >= MAX_ACTOR_DEFS || (actor_type > 0 && actors_defs[actor_type].actor_type != actor_type) ){
1530 		LOG_ERROR("Illegal/missing actor definition %d", actor_type);
1531 	}
1532 
1533 	//translate from tile to world
1534 	f_x_pos=x_pos*0.5;
1535 	f_y_pos=y_pos*0.5;
1536 	f_z_rot=z_rot;
1537 
1538 	//get the current frame
1539 	switch(frame) {
1540 	case frame_walk:
1541 	case frame_run:
1542 		break;
1543 	case frame_die1:
1544 	case frame_die2:
1545 		dead=1;
1546 		break;
1547 	case frame_pain1:
1548 	case frame_pain2:
1549 	case frame_pick:
1550 	case frame_drop:
1551 	case frame_idle:
1552 	case frame_sit_idle:
1553 	case frame_harvest:
1554 	case frame_cast:
1555 	case frame_attack_up_1:
1556 	case frame_attack_up_2:
1557 	case frame_attack_up_3:
1558 	case frame_attack_up_4:
1559 	case frame_attack_up_5:
1560 	case frame_attack_up_6:
1561 	case frame_attack_up_7:
1562 	case frame_attack_up_8:
1563 	case frame_attack_up_9:
1564 	case frame_attack_up_10:
1565 	case frame_attack_down_1:
1566 	case frame_attack_down_2:
1567 	case frame_attack_down_3:
1568 	case frame_attack_down_4:
1569 	case frame_attack_down_5:
1570 	case frame_attack_down_6:
1571 	case frame_attack_down_7:
1572 	case frame_attack_down_8:
1573 	case frame_attack_down_9:
1574 	case frame_attack_down_10:
1575 	case frame_combat_idle:
1576 		break;
1577 	default:
1578 		{
1579 		if(frame>=frame_poses_start&&frame<=frame_poses_end) {
1580 			//we have a pose, get it! (frame is the emote_id)
1581 			hash_entry *he;
1582 			he=hash_get(emotes,(void*)(uintptr_t)frame);
1583 			if(!he) LOG_ERROR("unknown pose %d", frame);
1584 			else pose = he->item;
1585 			break;
1586 		}
1587 
1588 			LOG_ERROR("%s %d - %s\n", unknown_frame, frame, &in_data[17]);
1589 		}
1590 	}
1591 
1592 #ifdef EXTRA_DEBUG
1593 	ERR();
1594 #endif
1595 
1596 	//find out if there is another actor with that ID
1597 	//ideally this shouldn't happen, but just in case
1598 
1599 	for(i=0;i<max_actors;i++)
1600 		{
1601 			if(actors_list[i])
1602 				if(actors_list[i]->actor_id==actor_id)
1603 					{
1604 						LOG_ERROR(duplicate_actors_str,actor_id, actors_list[i]->actor_name, &in_data[17]);
1605 						destroy_actor(actors_list[i]->actor_id);//we don't want two actors with the same ID
1606 						i--;// last actor was put here, he needs to be checked too
1607 					}
1608 		}
1609 
1610 	i= add_actor(actor_type, actors_defs[actor_type].skin_name, f_x_pos, f_y_pos, 0.0, f_z_rot, scale, 0, 0, 0, 0, 0, 0, 0, actor_id);
1611 
1612 	if(i==-1)
1613 	{
1614 		UNLOCK_ACTORS_LISTS();
1615 		return;//A nasty error occured and we couldn't add the actor. Ignore it.
1616 	}
1617 
1618 	//The actors list is locked when we get here...
1619 
1620 	actors_list[i]->async_fighting = 0;
1621 	actors_list[i]->async_x_tile_pos = x_pos;
1622 	actors_list[i]->async_y_tile_pos = y_pos;
1623 	actors_list[i]->async_z_rot = z_rot;
1624 
1625 	actors_list[i]->x_tile_pos=x_pos;
1626 	actors_list[i]->y_tile_pos=y_pos;
1627 	actors_list[i]->buffs=buffs;
1628 	actors_list[i]->actor_type=actor_type;
1629 	actors_list[i]->damage=0;
1630 	actors_list[i]->damage_ms=0;
1631 	actors_list[i]->sitting=0;
1632 	actors_list[i]->fighting=0;
1633 	//test only
1634 	actors_list[i]->max_health=max_health;
1635 	actors_list[i]->cur_health=cur_health;
1636 
1637     actors_list[i]->step_duration = actors_defs[actor_type].step_duration;
1638 	if (actors_list[i]->buffs & BUFF_DOUBLE_SPEED)
1639 		actors_list[i]->step_duration /= 2;
1640 
1641 	actors_list[i]->z_pos = get_actor_z(actors_list[i]);
1642 	if(frame==frame_sit_idle||(pose!=NULL&&pose->pose==EMOTE_SITTING)){ //sitting pose sent by the server
1643 			actors_list[i]->poses[EMOTE_SITTING]=pose;
1644 			actors_list[i]->sitting=1;
1645 		}
1646 	else if(frame==frame_stand||(pose!=NULL&&pose->pose==EMOTE_STANDING)){//standing pose sent by server
1647 			actors_list[i]->poses[EMOTE_STANDING]=pose;
1648 			actors_list[i]->sitting=0;
1649 		}
1650 	else if(frame==frame_walk||(pose!=NULL&&pose->pose==EMOTE_WALKING)){//walking pose sent by server
1651 			actors_list[i]->poses[EMOTE_WALKING]=pose;
1652 		}
1653 	else if(frame==frame_run||(pose!=NULL&&pose->pose==EMOTE_RUNNING)){//running pose sent by server
1654 			actors_list[i]->poses[EMOTE_RUNNING]=pose;
1655 		}
1656 	else
1657 		{
1658 			if(frame==frame_combat_idle)
1659 				actors_list[i]->fighting=1;
1660 			else if (frame == frame_ranged)
1661 				actors_list[i]->in_aim_mode = 1;
1662 		}
1663 	//ghost or not?
1664 	actors_list[i]->ghost=actors_defs[actor_type].ghost;
1665 
1666 	actors_list[i]->dead=dead;
1667 	actors_list[i]->stop_animation=1;//helps when the actor is dead...
1668 	actors_list[i]->kind_of_actor=kind_of_actor;
1669 	if(strlen(&in_data[17]) >= 30)
1670 		{
1671 			LOG_ERROR("%s (%d): %s/%d\n", bad_actor_name_length, actors_list[i]->actor_type,&in_data[17], (int)strlen(&in_data[17]));
1672 		}
1673 	else safe_strncpy(actors_list[i]->actor_name,&in_data[17],30);
1674 
1675 	if (attachment_type >= 0)
1676 		add_actor_attachment(actor_id, attachment_type);
1677 
1678 	if (actors_defs[actor_type].coremodel!=NULL) {
1679 		//Setup cal3d model
1680 		actors_list[i]->calmodel = model_new(actors_defs[actor_type].coremodel);
1681 		//Attach meshes
1682 		if(actors_list[i]->calmodel){
1683 			model_attach_mesh(actors_list[i], actors_defs[actor_type].shirt[0].mesh_index);
1684 			if(dead){
1685 				cal_actor_set_anim(i, actors_defs[actors_list[i]->actor_type].cal_frames[cal_actor_die1_frame]);
1686 				actors_list[i]->stop_animation=1;
1687 				CalModel_Update(actors_list[i]->calmodel,1000);
1688 			}
1689             else {
1690                 /* Schmurk: we explicitly go on idle here to avoid weird
1691                  * flickering when actors appear */
1692                 set_on_idle(i);
1693                 /* CalModel_Update(actors_list[i]->calmodel,0); */
1694             }
1695 			build_actor_bounding_box(actors_list[i]);
1696 			if (use_animation_program)
1697 			{
1698 				set_transformation_buffers(actors_list[i]);
1699 			}
1700             /* lines commented by Schmurk: we've set an animation just before
1701              * so we don't want do screw it up */
1702 			/* actors_list[i]->cur_anim.anim_index=-1; */
1703 			/* actors_list[i]->cur_anim_sound_cookie=0; */
1704 			/* actors_list[i]->IsOnIdle=0; */
1705 		}
1706 	}
1707 	else
1708 	{
1709 		actors_list[i]->calmodel=NULL;
1710 	}
1711 	update_actor_buffs(actor_id, buffs);
1712 
1713 	check_if_new_actor_last_summoned(actors_list[i]);
1714 
1715 	UNLOCK_ACTORS_LISTS();	//unlock it
1716 #ifdef EXTRA_DEBUG
1717 	ERR();
1718 #endif
1719 
1720 }
1721 
1722 //--- LoganDugenoux [5/25/2004]
1723 #define MS_PER_CHAR	200
1724 #define MINI_BUBBLE_MS	500
add_displayed_text_to_actor(actor * actor_ptr,const char * text)1725 void add_displayed_text_to_actor(actor *actor_ptr, const char* text)
1726 {
1727 	char *dest = actor_ptr->current_displayed_text;
1728 	const size_t size = sizeof(actor_ptr->current_displayed_text);
1729 	safe_snprintf(dest, size, "%s", text);
1730 	actor_ptr->current_displayed_text_lines = reset_soft_breaks((unsigned char*)dest, strlen(dest),
1731 		size, CHAT_FONT, 1.0, window_width/3, NULL, NULL);
1732 	actor_ptr->current_displayed_text_time_left = MINI_BUBBLE_MS + strlen(text) * MS_PER_CHAR;
1733 }
1734 
1735 //--- LoganDugenoux [5/25/2004]
get_actor_ptr_from_id(int actor_id)1736 actor *	get_actor_ptr_from_id( int actor_id )
1737 {
1738 	int i;
1739 	for (i = 0; i < max_actors; i++)
1740 	{
1741 		if (actors_list[i]->actor_id == actor_id)
1742 			return actors_list[i];
1743 	}
1744 	return NULL;
1745 }
1746 
end_actors_lists()1747 void end_actors_lists()
1748 {
1749 	SDL_DestroyMutex(actors_lists_mutex);
1750 	actors_lists_mutex=NULL;
1751 }
1752 
1753 
on_the_move(const actor * act)1754 int on_the_move (const actor *act){
1755 	if (act == NULL) return 0;
1756 	return act->moving || (act->que[0] >= move_n && act->que[0] <= move_nw);
1757 }
1758 
get_actor_rotation_matrix(actor * in_act,float * out_rot)1759 void get_actor_rotation_matrix(actor *in_act, float *out_rot)
1760 {
1761 	float tmp_rot1[9], tmp_rot2[9];
1762 
1763 	MAT3_ROT_Z(out_rot, (180.0 - in_act->z_rot) * (M_PI / 180.0));
1764 	MAT3_ROT_X(tmp_rot1, in_act->x_rot * (M_PI / 180.0));
1765 	MAT3_MULT(tmp_rot2, out_rot, tmp_rot1);
1766 	MAT3_ROT_Y(tmp_rot1, in_act->y_rot * (M_PI / 180.0));
1767 	MAT3_MULT(out_rot, tmp_rot2, tmp_rot1);
1768 }
1769 
transform_actor_local_position_to_absolute(actor * in_act,float * in_local_pos,float * in_act_rot,float * out_pos)1770 void transform_actor_local_position_to_absolute(actor *in_act, float *in_local_pos, float *in_act_rot, float *out_pos)
1771 {
1772 	float scale = get_actor_scale(in_act);
1773 	float rot[9];
1774 
1775 	if (!in_act_rot)
1776 	{
1777 		get_actor_rotation_matrix(in_act, rot);
1778 		in_act_rot = rot;
1779 	}
1780 
1781 	MAT3_VECT3_MULT(out_pos, in_act_rot, in_local_pos);
1782 
1783 	out_pos[0] = out_pos[0] * scale + in_act->x_pos + 0.25;
1784 	out_pos[1] = out_pos[1] * scale + in_act->y_pos + 0.25;
1785 	out_pos[2] = out_pos[2] * scale + get_actor_z(in_act);
1786 
1787 	if (in_act->attached_actor >= 0)
1788 	{
1789 		float shift[3];
1790 		MAT3_VECT3_MULT(shift, in_act_rot, in_act->attachment_shift);
1791 		out_pos[0] += shift[0];
1792 		out_pos[1] += shift[1];
1793 		out_pos[2] += shift[2];
1794 	}
1795 }
1796 
1797 // Split the given string into basic name and, if any, guild parts.
1798 // For players, the size should be at least MAX_ACTOR_NAME
1799 // For non players, the size should be at least ACTOR_NAME_SIZE
1800 // Name format is <name part> then optional <space><colour character><guild past>
split_name_and_guild(const char * full_name,char * name_part,char * guild_part,size_t parts_size)1801 static void split_name_and_guild(const char *full_name, char *name_part, char *guild_part, size_t parts_size)
1802 {
1803 		size_t i, ni=0, gi=0;
1804 		if ((full_name == NULL) || (name_part == NULL) || (guild_part == NULL) || (parts_size < strlen(full_name)))
1805 		{
1806 			LOG_ERROR("invalid parameters");
1807 			return;
1808 		}
1809 		name_part[0] = '\0';
1810 		guild_part[0] = '\0';
1811 
1812 		// get the name without any guild part
1813 		for (i=0; i<strlen(full_name); ni++, i++)
1814 		{
1815 			if (is_color(full_name[i]))
1816 			{
1817 				name_part[ni - ((ni==0) ?0: 1)] = '\0';
1818 				i++;
1819 				break;
1820 			}
1821 			else
1822 				name_part[ni] = full_name[i];
1823 		}
1824 		name_part[ni] = '\0';
1825 
1826 		// get the guild if any
1827 		for (; i<strlen(full_name); gi++, i++)
1828 		{
1829 			guild_part[gi] = full_name[i];
1830 		}
1831 		guild_part[gi] = '\0';
1832 }
1833 
1834 // A simple structure to hold state for the last summoned creature
1835 static struct last_summoned
1836 {
1837 	Uint32 summoned_time;
1838 	char summoned_name[256];
1839 	int actor_id;
1840 } last_summoned_var = {0, "", -1};
1841 
1842 
1843 // Store the time and the name of the last sucessful summons by the player
remember_new_summoned(const char * summoned_name)1844 void remember_new_summoned(const char *summoned_name)
1845 {
1846 	last_summoned_var.summoned_time = SDL_GetTicks();
1847 	safe_strncpy2(last_summoned_var.summoned_name, summoned_name, sizeof(summoned_name), strlen(summoned_name));
1848 	//printf("%u new summoned [%s]\n", last_summoned_var.summoned_time, last_summoned_var.summoned_name);
1849 }
1850 
1851 // Check if the new actor ....
1852 // 		has been created close in time to the last sucessful summons
1853 //		has the same name a the last sucessful summons
1854 //		has the same guild (if any) of the player
1855 // Must be called while we have the LOCK_ACTORS_LISTS() lock
check_if_new_actor_last_summoned(actor * new_actor)1856 void check_if_new_actor_last_summoned(actor *new_actor)
1857 {
1858 	if (SDL_GetTicks() < last_summoned_var.summoned_time + 250)
1859 	{
1860 		actor *me = get_our_actor();
1861 		if (me)
1862 		{
1863 			char me_name_part[MAX_ACTOR_NAME] = "", me_guild_part[MAX_ACTOR_NAME] = "";
1864 			char summoned_name_part[ACTOR_DEF_NAME_SIZE] = "", summoned_guild_part[ACTOR_DEF_NAME_SIZE] = "";
1865 
1866 			split_name_and_guild(me->actor_name, me_name_part, me_guild_part, MAX_ACTOR_NAME);
1867 			split_name_and_guild(new_actor->actor_name, summoned_name_part, summoned_guild_part, ACTOR_DEF_NAME_SIZE);
1868 
1869 			if ((strcmp(last_summoned_var.summoned_name, summoned_name_part) == 0) &&
1870 					(strcmp(summoned_guild_part, me_guild_part) == 0))
1871 				last_summoned_var.actor_id = new_actor->actor_id;
1872 
1873 			//printf("%u %s id=%d wanted [%s/%s] got [%s/%s]\n", SDL_GetTicks(),
1874 			//	((last_summoned_var.actor_id == new_actor->actor_id) ?"MATCHED" : "NO MATCH"), new_actor->actor_id,
1875 			//	last_summoned_var.summoned_name, me_guild_part, summoned_name_part, summoned_guild_part);
1876 		}
1877 	}
1878 }
1879 
1880 // Return the id of the last sucessful summoned creature, if its still present
get_id_last_summoned(void)1881 int get_id_last_summoned(void)
1882 {
1883 	size_t i;
1884 	if (last_summoned_var.actor_id < 0)
1885 		return -1;
1886 
1887 	// check if the actor is still present
1888 	LOCK_ACTORS_LISTS();
1889 	for (i=0; i<max_actors; i++)
1890 		if (actors_list[i]->actor_id == last_summoned_var.actor_id)
1891 			break;
1892 	UNLOCK_ACTORS_LISTS();
1893 
1894 	if (i == max_actors)
1895 		last_summoned_var.actor_id = -1;
1896 	return last_summoned_var.actor_id;
1897 }
1898