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