1 #include <stdlib.h>
2 #include <string.h>
3 #include <math.h>
4 #include <ctype.h>
5 #include "new_character.h"
6 #include "2d_objects.h"
7 #include "3d_objects.h"
8 #include "actors.h"
9 #include "actor_scripts.h"
10 #include "asc.h"
11 #include "bbox_tree.h"
12 #include "books.h"
13 #include "cal3d_wrapper.h"
14 #include "chat.h"
15 #include "consolewin.h"
16 #include "cursors.h"
17 #include "draw_scene.h"
18 #include "elconfig.h"
19 #include "events.h"
20 #include "gamewin.h"
21 #include "gl_init.h"
22 #include "hud.h"
23 #include "icon_window.h"
24 #include "init.h"
25 #include "interface.h"
26 #include "lights.h"
27 #include "loginwin.h"
28 #include "map.h"
29 #include "misc.h"
30 #include "multiplayer.h"
31 #include "new_actors.h"
32 #include "particles.h"
33 #include "password_manager.h"
34 #include "reflection.h"
35 #include "shadows.h"
36 #include "sky.h"
37 #include "tabs.h"
38 #include "textures.h"
39 #include "tiles.h"
40 #include "translate.h"
41 #include "weather.h"
42 #include "widgets.h"
43 #include "actor_init.h"
44
45 static void add_text_to_buffer(int color, const char * text, int time_to_display);
46
47 typedef int my_enum;//This enumeration will decrease, then wrap to top, increase and then wrap to bottom, when using the inc() and dec() functions. Special purpose though, since you have to have between 2 and 255 values in the enumeration and you have to have the same value in enum[0] as in enum[max] - otherwise we'll probably segfault...
48
49 static my_enum normal_skin_enum[] = { SKIN_BROWN, SKIN_NORMAL, SKIN_PALE, SKIN_TAN, SKIN_BROWN };
50 static my_enum elf_skin_enum[] = { SKIN_BROWN, SKIN_NORMAL, SKIN_PALE, SKIN_TAN, SKIN_DARK_BLUE, SKIN_BROWN };
51 static my_enum draegoni_skin_enum[] = { SKIN_BROWN, SKIN_NORMAL, SKIN_PALE, SKIN_TAN, SKIN_WHITE, SKIN_BROWN };
52 static my_enum normal_hair_enum[] = { HAIR_BLACK, HAIR_BLOND, HAIR_BROWN, HAIR_GRAY, HAIR_RED, HAIR_WHITE, HAIR_DARK_BROWN, HAIR_STRAWBERRY, HAIR_LIGHT_BLOND, HAIR_DIRTY_BLOND, HAIR_BROWN_GRAY, HAIR_DARK_GRAY, HAIR_DARK_RED, HAIR_BLACK };
53 static my_enum draegoni_hair_enum[] = { HAIR_BLACK, HAIR_BLOND, HAIR_BROWN, HAIR_GRAY, HAIR_RED, HAIR_WHITE, HAIR_DARK_BROWN, HAIR_STRAWBERRY, HAIR_LIGHT_BLOND, HAIR_DIRTY_BLOND, HAIR_BROWN_GRAY, HAIR_DARK_GRAY, HAIR_DARK_RED, HAIR_BLUE, HAIR_GREEN, HAIR_PURPLE, HAIR_BLACK };
54 static my_enum eyes_enum[] = { EYES_BROWN, EYES_DARK_BROWN, EYES_BROWN_RED, EYES_LIGHT_BLUE, EYES_BLUE, EYES_DARK_BLUE, EYES_LIGHT_GREEN, EYES_GREEN, EYES_DARK_GREEN, EYES_LAVENDER, EYES_VIOLET, EYES_GOLD, EYES_BROWN };
55 static my_enum male_shirt_enum[] = { SHIRT_BLACK, SHIRT_BLUE, SHIRT_BROWN, SHIRT_GREY, SHIRT_GREEN, SHIRT_LIGHTBROWN, SHIRT_ORANGE, SHIRT_PURPLE, SHIRT_RED, SHIRT_WHITE, SHIRT_YELLOW, SHIRT_BLACK };
56 static my_enum normal_shirt_enum[] = { SHIRT_BLACK, SHIRT_BLUE, SHIRT_BROWN, SHIRT_GREY, SHIRT_GREEN, SHIRT_LIGHTBROWN, SHIRT_ORANGE, SHIRT_PINK, SHIRT_PURPLE, SHIRT_RED, SHIRT_WHITE, SHIRT_YELLOW, SHIRT_BLACK };
57 static my_enum normal_pants_enum[] = { PANTS_BLACK, PANTS_BLUE, PANTS_BROWN, PANTS_DARKBROWN, PANTS_GREY, PANTS_GREEN, PANTS_LIGHTBROWN, PANTS_RED, PANTS_WHITE, PANTS_BLACK };
58 static my_enum normal_boots_enum[] = { BOOTS_BLACK, BOOTS_BROWN, BOOTS_DARKBROWN, BOOTS_DULLBROWN, BOOTS_LIGHTBROWN, BOOTS_ORANGE, BOOTS_BLACK };
59 static my_enum normal_head_enum[] = { HEAD_1, HEAD_2, HEAD_3, HEAD_4, HEAD_1 };
60 static my_enum human_head_enum[] = { HEAD_1, HEAD_2, HEAD_3, HEAD_4, HEAD_5, HEAD_1 };
61
62 struct race_def {
63 int type;
64 my_enum *skin;
65 my_enum *hair;
66 my_enum *eyes;
67 my_enum *shirts;
68 my_enum *pants;
69 my_enum *boots;
70 my_enum *head;
71 float x, y, z_rot;
72 } races[12] = {
73 {human_female, normal_skin_enum, normal_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, human_head_enum, 43.0f, 156.0f, 140.0f},
74 {human_male, normal_skin_enum, normal_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, human_head_enum, 43.0f, 156.0f, 140.0f},
75 {elf_female, elf_skin_enum, normal_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 42.0f, 92.0f, 180.0f},
76 {elf_male, elf_skin_enum, normal_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 42.0f, 92.0f, 180.0f},
77 {dwarf_female, normal_skin_enum, normal_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 100.0f, 149.0f, 180.0f},
78 {dwarf_male, normal_skin_enum, normal_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 100.0f, 149.0f, 180.0f},
79 {gnome_female, normal_skin_enum, normal_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 43.0f, 156.0f, 180.0f},
80 {gnome_male, normal_skin_enum, normal_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 43.0f, 156.0f, 180.0f},
81 {orchan_female, normal_skin_enum, normal_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 42.0f, 92.0f, 180.0f},
82 {orchan_male, normal_skin_enum, normal_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 42.0f, 92.0f, 180.0f},
83 {draegoni_female, draegoni_skin_enum, draegoni_hair_enum, eyes_enum, normal_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 100.0f, 149.0f, 180.0f},
84 {draegoni_male, draegoni_skin_enum, draegoni_hair_enum, eyes_enum, male_shirt_enum, normal_pants_enum, normal_boots_enum, normal_head_enum, 100.0f, 149.0f, 180.0f},
85 };
86
87 struct char_def {
88 int male;
89 int race_id;//races[race_id]
90 int race;
91 int skin;
92 int hair;
93 int eyes;
94 int shirt;
95 int pants;
96 int boots;
97 int head;
98 struct race_def * def;
99 actor * our_model;
100 } our_actor = {
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 NULL,
103 NULL
104 };
105
106 //Enum handling
107
find_pos_in_enum(my_enum * def,int val)108 static int find_pos_in_enum(my_enum * def, int val)
109 {
110 int i;
111
112 for(i=1;i<255;i++){
113 if(def[i]==val) return i;
114 else if(def[i]==def[0])return 0;
115 }
116
117 return 0;
118 }
119
inc(my_enum * def,int val,int no_steps)120 static int inc(my_enum * def, int val, int no_steps)
121 {
122 my_enum * here=&def[find_pos_in_enum(def, val)];
123
124 while(no_steps--){
125 if(*here==def[0])here=&def[1];
126 else here++;
127 }
128
129 return *here;
130 }
131
dec(my_enum * def,int val,int no_steps)132 static int dec(my_enum * def, int val, int no_steps)
133 {
134 my_enum * top=&def[find_pos_in_enum(def, def[0])];
135 my_enum * here=&def[find_pos_in_enum(def, val)];
136
137 while(no_steps--){
138 if(*here==*top)here=top;
139 here--;
140 }
141
142 return *here;
143 }
144
145 //New char interface
146
147 #define ERR_STR_LEN 520
148 static unsigned char create_char_error_str[ERR_STR_LEN] = {0};
149 static int old_use_windowed_chat;
150 static int display_time=0;
151 static const int DEF_MESSAGE_TIMEOUT = 3000;
152
153 struct input_text {
154 char str[40];
155 int pos;
156 } inputs[3] = {
157 {"Player", 6},
158 {"", 0},
159 {"", 0}
160 };
161
162 static int clear_player_name = 1;
163
164 static int creating_char = 1;
165
set_create_char_error(const char * msg,int len)166 void set_create_char_error (const char *msg, int len)
167 {
168 char buf[ERR_STR_LEN];
169
170 if (len <= 0)
171 {
172 // server didn't send a message, use the default
173 safe_snprintf (buf, sizeof(buf), "%s: %s", reg_error_str, char_name_in_use);
174 }
175 else
176 {
177 safe_snprintf(buf, sizeof (buf), "%s: %.*s", reg_error_str, len, msg);
178 }
179 reset_soft_breaks((unsigned char*)buf, strlen(buf), sizeof(buf),
180 CHAT_FONT, 1.0, window_width - hud_x - 20, NULL, NULL);
181
182 LOG_TO_CONSOLE(c_red1, buf);
183
184 add_text_to_buffer(c_red1, msg, DEF_MESSAGE_TIMEOUT);
185
186 creating_char=1;
187 }
188
change_actor(void)189 static void change_actor (void)
190 {
191 // We only need to reload the core model, and attach all the correct mesh types.
192 if (our_actor.our_model){
193 if(our_actor.our_model->calmodel!=NULL)
194 model_delete(our_actor.our_model->calmodel);
195
196 our_actor.our_model->calmodel = model_new(actors_defs[our_actor.race].coremodel);
197 our_actor.our_model->actor_type = our_actor.race;
198
199 // Attach the Meshes.
200 model_attach_mesh(our_actor.our_model,
201 actors_defs[our_actor.race].head[our_actor.head].mesh_index);
202 model_attach_mesh(our_actor.our_model,
203 actors_defs[our_actor.race].shirt[our_actor.shirt].mesh_index);
204 model_attach_mesh(our_actor.our_model,
205 actors_defs[our_actor.race].legs[our_actor.pants].mesh_index);
206 model_attach_mesh(our_actor.our_model,
207 actors_defs[our_actor.race].boots[our_actor.boots].mesh_index);
208
209 // Save which mesh is which.
210 our_actor.our_model->body_parts->head_meshindex =
211 actors_defs[our_actor.race].head[our_actor.head].mesh_index;
212 our_actor.our_model->body_parts->torso_meshindex =
213 actors_defs[our_actor.race].shirt[our_actor.shirt].mesh_index;
214 our_actor.our_model->body_parts->legs_meshindex =
215 actors_defs[our_actor.race].legs[our_actor.pants].mesh_index;
216 our_actor.our_model->body_parts->boots_meshindex =
217 actors_defs[our_actor.race].boots[our_actor.boots].mesh_index;
218
219 // Recopy all of the textures.
220 safe_strncpy(our_actor.our_model->body_parts->hands_tex,actors_defs[our_actor.race].skin[our_actor.skin].hands_name,sizeof(our_actor.our_model->body_parts->hands_tex));
221 safe_strncpy(our_actor.our_model->body_parts->head_tex,actors_defs[our_actor.race].skin[our_actor.skin].head_name,sizeof(our_actor.our_model->body_parts->head_tex));
222
223 safe_strncpy(our_actor.our_model->body_parts->hair_tex,actors_defs[our_actor.race].hair[our_actor.hair].hair_name,sizeof(our_actor.our_model->body_parts->hair_tex));
224 #ifdef NEW_EYES
225 safe_strncpy(our_actor.our_model->body_parts->eyes_tex,actors_defs[our_actor.race].eyes[our_actor.eyes].eyes_name,sizeof(our_actor.our_model->body_parts->eyes_tex));
226 #endif
227 safe_strncpy(our_actor.our_model->body_parts->arms_tex,actors_defs[our_actor.race].shirt[our_actor.shirt].arms_name,sizeof(our_actor.our_model->body_parts->arms_tex));
228 safe_strncpy(our_actor.our_model->body_parts->torso_tex,actors_defs[our_actor.race].shirt[our_actor.shirt].torso_name,sizeof(our_actor.our_model->body_parts->torso_tex));
229
230 safe_strncpy(our_actor.our_model->body_parts->pants_tex,actors_defs[our_actor.race].legs[our_actor.pants].legs_name,sizeof(our_actor.our_model->body_parts->pants_tex));
231
232 safe_strncpy(our_actor.our_model->body_parts->boots_tex,actors_defs[our_actor.race].boots[our_actor.boots].boots_name,sizeof(our_actor.our_model->body_parts->boots_tex));
233
234 free_actor_texture(our_actor.our_model->texture_id);
235 our_actor.our_model->texture_id = load_enhanced_actor(our_actor.our_model->body_parts, 0); // Rebuild the actor's textures.
236
237 // Move the actor. Could be a little disorienting, though.
238 our_actor.our_model->x_tile_pos = our_actor.def->x;
239 our_actor.our_model->y_tile_pos = our_actor.def->y;
240 our_actor.our_model->x_pos = our_actor.def->x*0.5f;
241 our_actor.our_model->y_pos = our_actor.def->y*0.5f;
242 our_actor.our_model->z_rot = our_actor.def->z_rot;
243 }
244 }
245
246 //////////////////////////////////////////////////////////////////////////
247
248 // New character window code below.
249
250 int newchar_root_win = -1;
251 static int color_race_win = -1;
252 static int namepass_win = -1;
253 static int newchar_advice_win = -1;
254 static int newchar_hud_win = -1;
255 static int error_widget_id = -1;
256
ui_scale_advice_handler(window_info * win)257 static int ui_scale_advice_handler(window_info *win)
258 {
259 int sep = 5;
260 int len_x = 2 * sep
261 + get_string_width_zoom((const unsigned char*)newchar_warning,
262 win->font_category, win->current_scale);
263 int len_y = (int)(2*sep + win->default_font_len_y);
264 int pos_x = (int)((window_width - len_x - hud_x) / 2);
265 resize_window(win->window_id, len_x, len_y);
266 move_window(win->window_id, win->pos_id, win->pos_loc, pos_x, sep);
267 return 1;
268 }
269
change_advice_font_handler(window_info * win,font_cat cat)270 static int change_advice_font_handler(window_info *win, font_cat cat)
271 {
272 if (cat != win->font_category)
273 return 0;
274 ui_scale_advice_handler(win);
275 return 1;
276 }
277
278 // Display the "Character creation screen" and creation step help window.
279 //
display_advice_handler(window_info * win)280 static int display_advice_handler (window_info *win)
281 {
282 static int lastw = -1, lasth = -1;
283 static Uint32 last_time = 0;
284 static int flash = 0;
285 static char *last_help = NULL;
286 static char *help_str = NULL;
287 int sep = 5;
288
289 // Resize and move the window on first use and if window size changed.
290 // Place centred, just down from the top of the screen.
291 if (lastw != window_width || lasth != window_height)
292 {
293 ui_scale_advice_handler(win);
294 lastw = window_width;
295 lasth = window_height;
296 }
297
298 // Draw the warning text.
299 glEnable(GL_TEXTURE_2D);
300 glColor3f(1.0f,1.0f,1.0f);
301 draw_text(win->len_x/2, win->len_y/2, (const unsigned char *)newchar_warning, strlen(newchar_warning),
302 win->font_category, TDO_ALIGNMENT, CENTER, TDO_VERTICAL_ALIGNMENT, CENTER_LINE,
303 TDO_ZOOM, win->current_scale, TDO_END);
304
305 // Give eye icon help, then credentials icon help then "done" help.
306 if (color_race_win < 0)
307 help_str = newchar_cust_help;
308 else if (!get_show_window(namepass_win))
309 help_str = newchar_cred_help;
310 else
311 help_str = newchar_done_help;
312
313 // Remember the last help string so we can flash when it changes
314 if (help_str != last_help)
315 {
316 flash = 16;
317 last_help = help_str;
318 }
319
320 // Time flashing, flash for a few seconds then remain on.
321 if (flash && (SDL_GetTicks()-last_time) > 250)
322 {
323 flash--;
324 last_time = SDL_GetTicks();
325 }
326
327 // Either always on or 1 in 4 off.
328 if (!flash || (flash & 3))
329 {
330 int width = get_string_width_zoom((const unsigned char*)help_str,
331 win->font_category, win->current_scale_small);
332 int y = window_height - HUD_MARGIN_Y - 2*sep - win->small_font_len_y;
333 if (width < window_width - hud_x) //Does everything fit in one line?
334 {
335 show_help_colored_scaled_centered((const unsigned char*)help_str,
336 win->len_x / 2, y, 1.0f, 1.0f, 1.0f, win->current_scale_small);
337 }
338 else
339 {
340 size_t i, len = strlen(help_str);
341 for(i = len/2; i<=len; i++) //Find first space after the middle of the text
342 {
343 if(help_str[i] == ' ')
344 break;
345 }
346 help_str[i] = '\r';
347 show_help_colored_scaled_centered((const unsigned char*)help_str,
348 win->len_x / 2, y - win->small_font_len_y, 1.0f, 1.0f, 1.0f,
349 win->current_scale_small);
350 help_str[i] = ' ';
351 }
352 }
353
354 #ifdef OPENGL_TRACE
355 CHECK_GL_ERRORS();
356 #endif //OPENGL_TRACE
357 return 1;
358 }
359
360
display_newchar_handler(window_info * win)361 static int display_newchar_handler (window_info *win)
362 {
363 int any_reflection;
364 static int main_count = 0;
365
366 if (display_time && cur_time > display_time)
367 {
368 create_char_error_str[0] = '\0';
369 display_time = 0;
370 }
371
372 if(disconnected)
373 {
374 static int nested_flag = 0;
375 /* connect_to_server() calls draw_scene() so we need to prevent recursion */
376 if (!nested_flag)
377 {
378 LOG_TO_CONSOLE(c_red2, "Connection failed, please try again");
379 creating_char = 1; /* this was clear before the failed connect so reset */
380 nested_flag = 1;
381 connect_to_server();
382 nested_flag = 0;
383 }
384 }
385
386 //see if we have to load a model (male or female)
387 if (creating_char && !our_actor.our_model){
388 move_camera();//Make sure we lag a little...
389 our_actor.our_model = add_actor_interface (our_actor.def->x, our_actor.def->y, our_actor.def->z_rot, 1.0f, our_actor.race,
390 inputs[0].str, our_actor.skin, our_actor.hair, our_actor.eyes, our_actor.shirt, our_actor.pants, our_actor.boots, our_actor.head);
391 yourself = 0;
392 LOCK_ACTORS_LISTS();
393 set_our_actor (our_actor.our_model);
394 UNLOCK_ACTORS_LISTS();
395 }
396
397 if (!(main_count%10))
398 read_mouse_now = 1;
399 else
400 read_mouse_now = 0;
401
402 //This window is a bit special since it's not fully 2D
403 Leave2DMode ();
404 glPushMatrix ();
405
406 update_camera();
407
408 if (new_zoom_level != zoom_level) {
409 zoom_level = new_zoom_level;
410 resize_root_window ();
411 }
412
413 move_camera ();
414
415 CalculateFrustum ();
416 set_click_line();
417 any_reflection = find_reflection ();
418 CHECK_GL_ERRORS ();
419
420 reset_under_the_mouse();
421
422 draw_global_light ();
423
424 if (skybox_show_sky)
425 {
426 if (skybox_update_delay < 1)
427 skybox_update_colors();
428 skybox_compute_z_position();
429 glPushMatrix();
430 glTranslatef(0.0, 0.0, skybox_get_z_position());
431 skybox_display();
432 glPopMatrix();
433 }
434
435 update_scene_lights();
436 draw_lights();
437 CHECK_GL_ERRORS ();
438
439 if (shadows_on && is_day) {
440 render_light_view();
441 CHECK_GL_ERRORS ();
442 }
443
444 if (use_fog)
445 weather_render_fog();
446 if (any_reflection > 1) {
447 draw_sky_background ();
448 CHECK_GL_ERRORS ();
449 if (show_reflection) display_3d_reflection ();
450 }
451
452 CHECK_GL_ERRORS ();
453
454 if (shadows_on && is_day) {
455 draw_sun_shadowed_scene (any_reflection);
456 } else {
457 glNormal3f (0.0f,0.0f,1.0f);
458 if (any_reflection) draw_lake_tiles ();
459 draw_tile_map ();
460 CHECK_GL_ERRORS ();
461 display_2d_objects ();
462 CHECK_GL_ERRORS ();
463 anything_under_the_mouse (0, UNDER_MOUSE_NOTHING);
464 display_objects ();
465 display_ground_objects();
466 display_actors (1, DEFAULT_RENDER_PASS);
467 display_alpha_objects();
468 display_blended_objects();
469 }
470
471 CHECK_GL_ERRORS ();
472
473 //particles should be last, we have no Z writting
474 display_particles ();
475 CHECK_GL_ERRORS ();
476
477 Enter2DMode ();
478
479 draw_hud_interface(win);
480
481 CHECK_GL_ERRORS ();
482
483 {
484 int msg, offset;
485 int width = win->len_x - hud_x - 20;
486
487 if ( find_last_lines_time (&msg, &offset, current_filter, width) )
488 {
489 draw_messages(10, 40, display_text_buffer, DISPLAY_TEXT_BUFFER_SIZE,
490 FILTER_ALL, msg, offset, -1, width, win->len_y,
491 CHAT_FONT, 1.0, NULL);
492 }
493 }
494
495 glColor3f(251/255.0f, 250/255.0f, 190/255.0f);
496 {
497 int y_off = win->len_y - HUD_MARGIN_Y + (HUD_MARGIN_Y - 2 * win->small_font_len_y) / 2;
498 draw_string_small_zoomed(get_icons_win_active_len() + win->small_font_max_len_x, y_off, (unsigned char*)zoom_in_out, 1, win->current_scale);
499 y_off += win->small_font_len_y;
500 draw_string_small_zoomed(get_icons_win_active_len() + win->small_font_max_len_x, y_off, (unsigned char*)rotate_camera, 1, win->current_scale);
501 }
502
503 Leave2DMode ();
504
505 glEnable (GL_LIGHTING);
506 glPopMatrix (); // restore the state
507 Enter2DMode ();
508
509 main_count++;
510 #ifdef OPENGL_TRACE
511 CHECK_GL_ERRORS();
512 #endif //OPENGL_TRACE
513 return 1;
514 }
515
mouseover_newchar_handler(window_info * win,int mx,int my)516 static int mouseover_newchar_handler (window_info *win, int mx, int my)
517 {
518 return 1;
519 }
520
click_newchar_handler(window_info * win,int mx,int my,Uint32 flags)521 static int click_newchar_handler (window_info *win, int mx, int my, Uint32 flags)
522 {
523 if (flags & ELW_WHEEL_UP) {
524 if (camera_zoom_dir == -1)
525 camera_zoom_duration += 100;
526 else
527 camera_zoom_duration = 100;
528 camera_zoom_dir = -1;
529 return 1;
530 }
531
532 if (flags & ELW_WHEEL_DOWN) {
533 if (camera_zoom_dir == 1)
534 camera_zoom_duration += 100;
535 else
536 camera_zoom_duration = 100;
537 camera_zoom_dir = 1;
538 return 1;
539 }
540
541 return 1; // we captured this mouseclick
542 }
543
keypress_newchar_handler(window_info * win,int mx,int my,SDL_Keycode key_code,Uint32 key_unicode,Uint16 key_mod)544 static int keypress_newchar_handler (window_info *win, int mx, int my, SDL_Keycode key_code, Uint32 key_unicode, Uint16 key_mod)
545 {
546 static int last_time=0;
547
548 if ( check_quit_or_fullscreen (key_code, key_mod) ) {
549 return 1;
550 } else if(disconnected && !(key_mod & KMOD_ALT) && !(key_mod & KMOD_CTRL)){
551 connect_to_server();
552 } else if (KEY_DEF_CMP(K_CAMERAUP, key_code, key_mod)) {
553 camera_tilt_speed = -normal_camera_rotation_speed * 0.0005;
554 camera_tilt_duration += 100;
555 camera_tilt_deceleration = normal_camera_deceleration*0.5E-3;
556 } else if (KEY_DEF_CMP(K_CAMERADOWN, key_code, key_mod)) {
557 camera_tilt_speed = normal_camera_rotation_speed * 0.0005;
558 camera_tilt_duration += 100;
559 camera_tilt_deceleration = normal_camera_deceleration*0.5E-3;
560 } else if (KEY_DEF_CMP(K_ZOOMIN, key_code, key_mod)) {
561 if (camera_zoom_dir == -1)
562 camera_zoom_duration += 100;
563 else
564 camera_zoom_duration = 100;
565 camera_zoom_dir = -1;
566 } else if (KEY_DEF_CMP(K_ZOOMOUT, key_code, key_mod)) {
567 if (camera_zoom_dir == 1)
568 camera_zoom_duration += 100;
569 else
570 camera_zoom_duration = 100;
571 camera_zoom_dir = 1;
572 } else if(KEY_DEF_CMP(K_OPTIONS, key_code, key_mod)){
573 view_window(MW_CONFIG);
574 } else if(KEY_DEF_CMP(K_ENCYCLOPEDIA, key_code, key_mod)){
575 view_tab(MW_HELP, tab_help_collection_id, HELP_TAB_ENCYCLOPEDIA);
576 } else if(KEY_DEF_CMP(K_HELP, key_code, key_mod)) {
577 view_tab(MW_HELP, tab_help_collection_id, HELP_TAB_HELP);
578 } else if (KEY_DEF_CMP(K_RULES, key_code, key_mod)) {
579 view_tab(MW_HELP, tab_help_collection_id, HELP_TAB_RULES);
580 } else if (KEY_DEF_CMP(K_ROTATELEFT, key_code, key_mod)) {
581 camera_rotation_speed = normal_camera_rotation_speed / 800.0;
582 camera_rotation_duration = 800;
583 camera_rotation_deceleration = normal_camera_deceleration*0.5E-3;
584 if (fol_cam && !fol_cam_behind)
585 {
586 hold_camera += camera_kludge - last_kludge;
587 last_kludge = camera_kludge;
588 }
589 } else if (KEY_DEF_CMP(K_FROTATELEFT, key_code, key_mod)) {
590 camera_rotation_speed = fine_camera_rotation_speed / 200.0;
591 camera_rotation_duration = 200;
592 camera_rotation_speed /= 4.0;
593 camera_rotation_deceleration = normal_camera_deceleration*0.5E-3;
594 if (fol_cam && !fol_cam_behind)
595 {
596 hold_camera += camera_kludge - last_kludge;
597 last_kludge = camera_kludge;
598 }
599 } else if (KEY_DEF_CMP(K_ROTATERIGHT, key_code, key_mod)) {
600 camera_rotation_speed = -normal_camera_rotation_speed / 800.0;
601 camera_rotation_duration = 800;
602 camera_rotation_deceleration = normal_camera_deceleration*0.5E-3;
603 if (fol_cam && !fol_cam_behind)
604 {
605 hold_camera += camera_kludge - last_kludge;
606 last_kludge = camera_kludge;
607 }
608 } else if (KEY_DEF_CMP(K_FROTATERIGHT, key_code, key_mod)) {
609 camera_rotation_speed = -fine_camera_rotation_speed / 200.0;
610 camera_rotation_duration = 200;
611 camera_rotation_speed /= 4.0;
612 camera_rotation_deceleration = normal_camera_deceleration*0.5E-3;
613 if (fol_cam && !fol_cam_behind)
614 {
615 hold_camera += camera_kludge - last_kludge;
616 last_kludge = camera_kludge;
617 }
618 } else if(KEY_DEF_CMP(K_TURNLEFT, key_code, key_mod)){
619 if(last_time+666<cur_time){
620 add_command_to_actor(0, turn_left);
621 last_time=cur_time;
622 }
623 } else if(KEY_DEF_CMP(K_TURNRIGHT, key_code, key_mod)){
624 if(last_time+666<cur_time){
625 add_command_to_actor(0, turn_right);
626 last_time=cur_time;
627 }
628 }
629 else
630 return 0;
631 return 1;
632 }
633
634
show_newchar_handler(window_info * win)635 static int show_newchar_handler (window_info *win) {
636 init_hud_interface (HUD_INTERFACE_NEW_CHAR);
637 show_hud_windows();
638
639 return 1;
640 }
641
642 static void create_newchar_hud_window(void);
643
set_hud_width(window_info * win)644 static void set_hud_width(window_info *win)
645 {
646 int sep = (int)(0.5 + win->current_scale * 5);
647 float bit_small = 0.9f * win->current_scale;
648 float very_small = win->current_scale_small;
649 int width, min_width = (int)(0.5 + win->current_scale * NEW_CHARACTER_BASE_HUD_X);
650 int prev_width = get_string_width_zoom((const unsigned char*)"<<", win->font_category, bit_small);
651 int next_width = get_string_width_zoom((const unsigned char*)">>", win->font_category, bit_small);
652 int button_height = (int)(0.5 + 2*very_small*BUTTONRADIUS);
653
654 width = 2*sep + get_string_width_zoom((const unsigned char*)win_design, win->font_category, bit_small);
655 min_width = max2i(min_width, width);
656
657 width = 5*sep + calc_button_width((const unsigned char*)male_str, win->font_category, very_small)
658 + calc_button_width((const unsigned char*)female_str, win->font_category, very_small);
659 min_width = max2i(min_width, width);
660
661 width = 4*sep + button_height
662 + calc_button_width((const unsigned char*)human_str, win->font_category, very_small);
663 min_width = max2i(min_width, 2*width);
664 width = 4*sep + button_height
665 + calc_button_width((const unsigned char*)elf_str, win->font_category, very_small);
666 min_width = max2i(min_width, 2*width);
667 width = 4*sep + button_height
668 + calc_button_width((const unsigned char*)dwarf_str, win->font_category, very_small);
669 min_width = max2i(min_width, 2*width);
670 width = 4*sep + button_height
671 + calc_button_width((const unsigned char*)gnome_str, win->font_category, very_small);
672 min_width = max2i(min_width, 2*width);
673 width = 4*sep + button_height
674 + calc_button_width((const unsigned char*)orchan_str, win->font_category, very_small);
675 min_width = max2i(min_width, 2*width);
676 width = 4*sep + button_height
677 + calc_button_width((const unsigned char*)draegoni_str, win->font_category, very_small);
678 min_width = max2i(min_width, 2*width);
679
680 width = 3*sep + prev_width + next_width
681 + get_string_width_zoom((const unsigned char*)head_str, win->font_category, bit_small);
682 min_width = max2i(min_width, 2*width);
683 width = 3*sep + prev_width + next_width
684 + get_string_width_zoom((const unsigned char*)shirt_str, win->font_category, bit_small);
685 min_width = max2i(min_width, 2*width);
686 width = 3*sep + prev_width + next_width
687 + get_string_width_zoom((const unsigned char*)skin_str, win->font_category, bit_small);
688 min_width = max2i(min_width, 2*width);
689 width = 3*sep + prev_width + next_width
690 + get_string_width_zoom((const unsigned char*)pants_str, win->font_category, bit_small);
691 min_width = max2i(min_width, 2*width);
692 width = 3*sep + prev_width + next_width
693 + get_string_width_zoom((const unsigned char*)hair_str, win->font_category, bit_small);
694 min_width = max2i(min_width, 2*width);
695 width = 3*sep + prev_width + next_width
696 + get_string_width_zoom((const unsigned char*)boots_str, win->font_category, bit_small);
697 min_width = max2i(min_width, 2*width);
698 width = 3*sep + prev_width + next_width
699 + get_string_width_zoom((const unsigned char*)eyes_str, win->font_category, bit_small);
700 min_width = max2i(min_width, 2*width);
701
702 width = 3*sep + calc_button_width((const unsigned char*)char_done, win->font_category, bit_small)
703 + calc_button_width((const unsigned char*)char_back, win->font_category, bit_small);
704
705 hud_x = min2i(min_width, win->len_x/2);
706 }
707
ui_scale_newchar_handler(window_info * win)708 static int ui_scale_newchar_handler(window_info *win)
709 {
710 set_hud_width(win);
711 resize_newchar_hud_window();
712 return 1;
713 }
714
ui_resize_newchar_handler(window_info * win)715 static int ui_resize_newchar_handler(window_info *win)
716 {
717 if (get_show_window(win->window_id))
718 {
719 init_hud_interface (HUD_INTERFACE_NEW_CHAR);
720 set_all_intersect_update_needed(main_bbox_tree); // redraw the scene
721 }
722 return 1;
723 }
724
change_newchar_font_handler(window_info * win,font_cat cat)725 static int change_newchar_font_handler(window_info *win, font_cat cat)
726 {
727 if (cat != win->font_category)
728 return 0;
729 ui_scale_newchar_handler(win);
730 return 1;
731 }
732
create_newchar_root_window(void)733 void create_newchar_root_window (void)
734 {
735 if (newchar_root_win < 0)
736 {
737 our_actor.race_id=RAND(0, 5);
738 our_actor.def=&races[our_actor.race_id];//6 "races" - counting women as their own race, of course ;-) We cannot include the new races in the random function since they are p2p
739 our_actor.skin = inc(our_actor.def->skin, SKIN_BROWN, RAND (SKIN_BROWN, SKIN_TAN));//Increment a random # of times.
740 our_actor.hair = inc(our_actor.def->hair, HAIR_BLACK, RAND (HAIR_BLACK, our_actor.def->type >= draegoni_female ? HAIR_PURPLE:HAIR_WHITE));
741 our_actor.eyes = inc(our_actor.def->eyes, EYES_BROWN, RAND (EYES_BROWN, EYES_GOLD));
742 our_actor.shirt = inc(our_actor.def->shirts, SHIRT_BLACK, RAND (SHIRT_BLACK, SHIRT_YELLOW));
743 our_actor.pants = inc(our_actor.def->pants, PANTS_BLACK, RAND (PANTS_BLACK, PANTS_WHITE));
744 our_actor.boots = inc(our_actor.def->boots, BOOTS_BLACK, RAND (BOOTS_BLACK, BOOTS_ORANGE));
745 our_actor.head = inc(our_actor.def->head, HEAD_1, RAND (HEAD_1, our_actor.def->type==human_female?HEAD_5:HEAD_4));
746 our_actor.race = our_actor.def->type;
747 our_actor.male = our_actor.race<gnome_female?our_actor.race%2:!(our_actor.race%2);
748
749 game_minute = 120; //Midday. So that it's bright and sunny.
750 real_game_minute = game_minute;
751
752 change_map ("./maps/newcharactermap.elm");
753
754 newchar_root_win = create_window (win_newchar, -1, -1, 0, 0, window_width, window_height, ELW_USE_UISCALE|ELW_TITLE_NONE|ELW_SHOW_LAST);
755
756 set_window_handler (newchar_root_win, ELW_HANDLER_DISPLAY, &display_newchar_handler);
757 set_window_handler (newchar_root_win, ELW_HANDLER_MOUSEOVER, &mouseover_newchar_handler);
758 set_window_handler (newchar_root_win, ELW_HANDLER_CLICK, &click_newchar_handler);
759 set_window_handler (newchar_root_win, ELW_HANDLER_KEYPRESS, (int (*)())&keypress_newchar_handler);
760 set_window_handler (newchar_root_win, ELW_HANDLER_SHOW, &show_newchar_handler);
761 set_window_handler (newchar_root_win, ELW_HANDLER_AFTER_SHOW, &update_have_display);
762 set_window_handler (newchar_root_win, ELW_HANDLER_HIDE, &update_have_display);
763 set_window_handler (newchar_root_win, ELW_HANDLER_UI_SCALE, &ui_scale_newchar_handler);
764 set_window_handler (newchar_root_win, ELW_HANDLER_RESIZE, &ui_resize_newchar_handler);
765 set_window_handler(newchar_root_win, ELW_HANDLER_FONT_CHANGE, &change_newchar_font_handler);
766
767 newchar_advice_win = create_window ("Advice", newchar_root_win, 0, 100, 10, 200, 100, ELW_USE_UISCALE|ELW_USE_BACKGROUND|ELW_USE_BORDER|ELW_SHOW|ELW_ALPHA_BORDER);
768 set_window_handler (newchar_advice_win, ELW_HANDLER_DISPLAY, &display_advice_handler);
769 set_window_handler (newchar_advice_win, ELW_HANDLER_UI_SCALE, &ui_scale_advice_handler);
770 set_window_handler (newchar_advice_win, ELW_HANDLER_FONT_CHANGE, &change_advice_font_handler);
771
772 if (newchar_root_win >= 0 && newchar_root_win < windows_list.num_windows)
773 ui_scale_newchar_handler(&windows_list.window[newchar_root_win]);
774
775 create_newchar_hud_window();
776
777 LOG_TO_CONSOLE(c_green1, char_help);
778 } else {
779 show_window(newchar_root_win);
780 show_window(newchar_advice_win);
781 show_window(newchar_hud_win);
782 show_window(color_race_win);
783 hide_window(namepass_win);
784 }
785 old_use_windowed_chat = use_windowed_chat;
786 use_windowed_chat = 0;
787 }
788
789 static int active=0;
790 static int hidden=0;
791 static int are_you_sure=1;
792 static int numbers_in_name=0;
793
get_pass_str(int l)794 static const unsigned char* get_pass_str(int l)
795 {
796 static unsigned char str[20];
797
798 memset(str, '*', l);
799 str[l]=0;
800
801 return str;
802 }
803
804 //Returns 1 if it's valid, 0 if invalid and -1 if there's too many numbers in the name
check_character(int type,char ch)805 static int check_character(int type, char ch)
806 {
807 int retval=0;
808
809 if(type==0){
810 //name
811 if(isdigit(ch)){
812 // no more then two digits in a name
813 if (numbers_in_name >= 2)
814 {
815 retval=-1;
816 } else {
817 numbers_in_name++;
818 retval=1;
819 }
820 } else if(isalnum(ch)||ch=='_'){
821 retval=1;
822 } else if ((ch>= 33 && ch<=47)||(ch>=58 && ch<=64)||(ch>=91&&ch<=96)||(ch>=122 && ch<=126)){
823 // not permitted in a name
824 retval=-2;
825 }
826 } else { // password
827 if (VALID_PASSWORD_CHAR(ch)) retval=1;
828 }
829
830 return retval;
831 }
832
add_text_to_buffer(int color,const char * text,int time_to_display)833 static void add_text_to_buffer(int color, const char * text, int time_to_display)
834 {
835 if (namepass_win < 0 || namepass_win >= windows_list.num_windows)
836 return;
837 put_small_colored_text_in_box_zoomed(color, (unsigned char*)text, strlen(text),
838 widget_get_width(namepass_win, error_widget_id), create_char_error_str, windows_list.window[namepass_win].current_scale);
839 display_time=cur_time+time_to_display;
840 }
841
create_character(void)842 static void create_character(void)
843 {
844 if(inputs[0].pos<3){
845 add_text_to_buffer(c_red2, error_username_length, DEF_MESSAGE_TIMEOUT);
846 return;
847 } else if(inputs[1].pos<4){
848 add_text_to_buffer(c_red2, error_password_length, DEF_MESSAGE_TIMEOUT);
849 return;
850 } else if(!strncasecmp(inputs[1].str, actors_list[0]->actor_name, strlen(actors_list[0]->actor_name))){
851 add_text_to_buffer(c_red2, error_bad_pass, DEF_MESSAGE_TIMEOUT);
852 return;
853 } else if(strcmp(inputs[1].str, inputs[2].str)){
854 add_text_to_buffer(c_red2, error_pass_no_match, DEF_MESSAGE_TIMEOUT);
855 return;
856 }
857
858 if(are_you_sure){
859 creating_char=0;
860 // Clear the error message, if necessary
861 create_char_error_str[0] = '\0';
862 send_new_char(inputs[0].str, inputs[1].str, our_actor.skin, our_actor.hair, our_actor.eyes, our_actor.shirt, our_actor.pants, our_actor.boots, our_actor.head, our_actor.race);
863 } else {
864 are_you_sure=1;
865
866 add_text_to_buffer(c_orange3, error_confirm_create_char, DEF_MESSAGE_TIMEOUT);
867 LOG_TO_CONSOLE(c_green2, "\n");
868 LOG_TO_CONSOLE(c_green2, remember_change_appearance);
869 }
870 }
871
login_from_new_char(void)872 void login_from_new_char(void)
873 {
874 set_username(inputs[0].str);
875 set_password(inputs[1].str);
876
877 // now destroy reference to ourself, otherwise we'll mess up the ID's
878 destroy_all_actors();
879 our_actor.our_model=NULL;
880
881 // close help and setting windows
882 hide_window_MW(MW_HELP);
883 hide_window_MW(MW_CONFIG);
884
885 //restore use_windowed_chat
886 use_windowed_chat = old_use_windowed_chat;
887 hide_window(newchar_hud_win);
888
889 //now send the log in info
890 send_login_info();
891 }
892
893 //The character design window
change_race(int new_race)894 static void change_race(int new_race)
895 {
896 if(our_actor.race_id==new_race)return;
897 destroy_all_actors();
898 our_actor.our_model = NULL;
899 our_actor.race_id=new_race;
900 our_actor.def=&races[new_race];
901 our_actor.skin = our_actor.def->skin[find_pos_in_enum(our_actor.def->skin, our_actor.skin)];//Increment a random # of times.
902 our_actor.hair = our_actor.def->hair[find_pos_in_enum(our_actor.def->hair, our_actor.hair)];
903 our_actor.eyes = our_actor.def->eyes[find_pos_in_enum(our_actor.def->eyes, our_actor.eyes)];
904 our_actor.shirt = our_actor.def->shirts[find_pos_in_enum(our_actor.def->shirts, our_actor.shirt)];
905 our_actor.pants = our_actor.def->pants[find_pos_in_enum(our_actor.def->pants, our_actor.pants)];
906 our_actor.boots = our_actor.def->boots[find_pos_in_enum(our_actor.def->boots, our_actor.boots)];
907 our_actor.head = our_actor.def->head[find_pos_in_enum(our_actor.def->head, our_actor.head)];
908 our_actor.race = our_actor.def->type;
909 our_actor.male = our_actor.race<gnome_female?our_actor.race%2:!(our_actor.race%2);
910
911 change_actor();
912 }
913
914 int book_human=200000;
915 int book_dwarf=200001;
916 int book_elf=200002;
917 int book_gnome=200003;
918 int book_orchan=200004;
919 int book_draegoni=200005;
920
toggle_book(int id)921 static void toggle_book(int id)
922 {
923 if (book_is_open(id))
924 close_book(id);
925 else
926 open_book(id);
927 }
928
929 static int newchar_mouseover = 0; //book id if mouse is over a book 1 if mouse is over p2p race
930 static int newchar_mouseover_time = 0;
931 static char* tooltip = NULL;
932 static int tooltip_x = 0;
933 static int tooltip_y = 0;
934
click_done_handler(widget_list * w,int mx,int my,Uint32 flags)935 static int click_done_handler(widget_list *w, int mx, int my, Uint32 flags)
936 {
937 if(w->window_id == color_race_win)
938 {
939 hide_window(color_race_win);
940 show_window(namepass_win);
941 }
942 else
943 {
944 if(w->Flags)
945 {
946 create_character();
947 }
948 else
949 {
950 w->Flags = BUTTON_ACTIVE;
951 add_text_to_buffer(c_orange3, error_confirm_create_char, DEF_MESSAGE_TIMEOUT);
952 }
953 }
954 return 1;
955 }
956
click_back_handler(widget_list * w,int mx,int my,Uint32 flags)957 static int click_back_handler(widget_list *w, int mx, int my, Uint32 flags)
958 {
959 if(w->window_id == color_race_win)
960 {
961 destroy_all_actors();
962 our_actor.our_model = NULL;
963 use_windowed_chat = old_use_windowed_chat; //Restore use_windowed_chat
964 hide_window(newchar_hud_win);
965 hide_window(newchar_root_win);
966 show_window(login_root_win);
967 hide_hud_windows();
968 }
969 else
970 {
971 hide_window(namepass_win);
972 show_window(color_race_win);
973 }
974 return 1;
975 }
976
click_namepass_field(widget_list * w,int mx,int my,Uint32 flags)977 static int click_namepass_field(widget_list *w, int mx, int my, Uint32 flags)
978 {
979 active = *(int*)w->spec;
980 return 1;
981 }
982
errorbox_draw(widget_list * w)983 static int errorbox_draw(widget_list *w)
984 {
985 if (w->window_id >= 0 && w->window_id < windows_list.num_windows)
986 draw_string_small_zoomed(w->pos_x, w->pos_y, create_char_error_str, 8, windows_list.window[w->window_id].current_scale);
987 return 1;
988 }
989
name_draw(widget_list * w)990 static int name_draw(widget_list *w)
991 {
992 draw_smooth_button((const unsigned char*)w->widget_info, w->fcat, w->size, w->pos_x, w->pos_y, w->len_x - 2*BUTTONRADIUS*w->size, 1,
993 w->r, w->g, w->b, active == *(int*)w->spec, gui_invert_color[0], gui_invert_color[1], gui_invert_color[2], 0.0f);
994 return 1;
995 }
996
password_draw(widget_list * w)997 static int password_draw(widget_list *w)
998 {
999 if(!hidden)
1000 {
1001 draw_smooth_button(get_pass_str(strlen((const char*)w->widget_info)), w->fcat, w->size, w->pos_x, w->pos_y, w->len_x - 2*BUTTONRADIUS*w->size, 1,
1002 w->r, w->g, w->b, active == *(int*)w->spec, gui_invert_color[0], gui_invert_color[1], gui_invert_color[2], 0.0f);
1003 }
1004 else
1005 {
1006 draw_smooth_button((const unsigned char*)w->widget_info, w->fcat, w->size, w->pos_x, w->pos_y, w->len_x - 2*BUTTONRADIUS*w->size, 1,
1007 w->r, w->g, w->b, active == *(int*)w->spec, gui_invert_color[0], gui_invert_color[1], gui_invert_color[2], 0.0f);
1008 }
1009 return 1;
1010 }
1011
keypress_namepass_handler(window_info * win,int mx,int my,SDL_Keycode key_code,Uint32 key_unicode,Uint16 key_mod)1012 static int keypress_namepass_handler (window_info *win, int mx, int my, SDL_Keycode key_code, Uint32 key_unicode, Uint16 key_mod)
1013 {
1014 Uint8 ch = key_to_char (key_unicode);
1015 int ret=0;
1016 struct input_text * t=&inputs[active];
1017
1018 if (clear_player_name)
1019 {
1020 clear_player_name = 0;
1021 inputs[0].pos = 0;
1022 inputs[0].str[0] = 0;
1023 }
1024
1025 if ((ret=check_character (active > 0, ch)))
1026 {
1027 if (ret==-1)
1028 {
1029 add_text_to_buffer (c_red2, error_max_digits, DEF_MESSAGE_TIMEOUT);
1030 }
1031 else if (ret==-2)
1032 {
1033 add_text_to_buffer (c_red2, error_illegal_character, DEF_MESSAGE_TIMEOUT);
1034 }
1035 else if (t->pos + 1 > MAX_USERNAME_LENGTH - 1) // MAX_USERNAME_LENGTH includes the null terminator and t->pos counts from 0
1036 {
1037 add_text_to_buffer (c_red2, error_length, DEF_MESSAGE_TIMEOUT);
1038 }
1039 else
1040 {
1041 // add the character to the buffer
1042 t->str[t->pos++]=ch;
1043 t->str[t->pos]=0;
1044 ret=1; //Reused to show that a letter has been added
1045 }
1046 }
1047 else if (key_code == SDLK_TAB || key_code == SDLK_RETURN || key_code == SDLK_KP_ENTER)
1048 {
1049 active++;
1050 if(active>2) active=0;
1051 }
1052 else if (key_code == SDLK_BACKSPACE)
1053 {
1054 if (t->pos>0)
1055 {
1056 t->pos--;
1057 if ((active == 0) && isdigit (t->str[t->pos]))
1058 numbers_in_name--;
1059 t->str[t->pos] = 0;
1060 ret = 1; // Reused to show that a letter has been removed
1061 }
1062 }
1063 else
1064 {
1065 //only send error messages on non-null characters
1066 if(ch != 0){
1067 add_text_to_buffer (c_red2, error_illegal_character, DEF_MESSAGE_TIMEOUT);
1068 }
1069 }
1070
1071 if(active>0){
1072 //Password/confirm
1073 if((inputs[1].pos > 0) && (inputs[2].pos > 0) && ret){
1074 if(!strncasecmp(inputs[1].str, actors_list[0]->actor_name, strlen(actors_list[0]->actor_name))){
1075 add_text_to_buffer(c_red2, error_bad_pass, DEF_MESSAGE_TIMEOUT);
1076 } else if(strcmp(inputs[1].str, inputs[2].str)){
1077 add_text_to_buffer(c_red2, error_pass_no_match, DEF_MESSAGE_TIMEOUT);
1078 } else {
1079 add_text_to_buffer(c_green1, passwords_match, DEF_MESSAGE_TIMEOUT);
1080 }
1081 }
1082 } else {
1083 safe_strncpy(actors_list[0]->actor_name, inputs[0].str,
1084 sizeof(actors_list[0]->actor_name));
1085 }
1086
1087 return ret;
1088 }
1089
1090 static const struct WIDGET_TYPE name_type = {NULL, &name_draw, &click_namepass_field, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //custom widget for the name button
1091 static const struct WIDGET_TYPE password_type = {NULL, &password_draw, &click_namepass_field, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //custom widget for the password buttons
1092 static const struct WIDGET_TYPE errorbox_type = {NULL, &errorbox_draw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //custom widget for displaying name/password errors
1093 static int specs[3] = {0, 1, 2};
1094
click_remember_details_handler(widget_list * widget,int mx,int my,Uint32 flags)1095 static int click_remember_details_handler(widget_list *widget, int mx, int my, Uint32 flags)
1096 {
1097 set_var_unsaved("passmngr_enabled", INI_FILE_VAR);
1098 return 1;
1099 }
1100
init_namepass_handler(window_info * win)1101 static int init_namepass_handler(window_info * win)
1102 {
1103 float very_small = win->current_scale_small; //font sizes
1104 float bit_small = 0.9f * win->current_scale;
1105 float normal = 1.0f * win->current_scale;
1106 int free_widget_id = 8;
1107 int widget_id;
1108 int sep = (int)(0.5 + win->current_scale * 5);
1109 int y = sep;
1110 int x_off = 3*sep;
1111 int size = (int)(0.5 + win->current_scale * 15);
1112 float input_size, label_size;
1113 int max_username_width;
1114 int input_len_x;
1115 int input_len_y = 2 * BUTTONRADIUS * very_small;
1116 int center = (input_len_y - get_line_height(win->font_category, normal)) / 2;
1117 int input_off, max_input_off = win->len_x / 3;
1118 int text_width, max_text_width = 0;
1119
1120 label_size = normal;
1121 text_width = get_string_width_zoom((const unsigned char*)login_username_str,
1122 win->font_category, label_size);
1123 max_text_width = max2i(text_width, max_text_width);
1124 text_width = get_string_width_zoom((const unsigned char*)login_password_str,
1125 win->font_category, label_size);
1126 max_text_width = max2i(text_width, max_text_width);
1127 text_width = get_string_width_zoom((const unsigned char*)confirm_password,
1128 win->font_category, label_size);
1129 max_text_width = max2i(text_width, max_text_width);
1130 input_off = x_off + sep + max_text_width;
1131
1132 if (input_off > max_input_off)
1133 {
1134 input_off -= x_off - sep;
1135 x_off = sep;
1136 if (input_off > max_input_off)
1137 {
1138 float scale = (float)(max_input_off - x_off - sep) / (input_off - x_off - sep);
1139 label_size *= min2f(scale, 0.9);
1140 input_off = max_input_off;
1141 }
1142 }
1143
1144 input_size = very_small;
1145 max_username_width = (MAX_USERNAME_LENGTH - 1)
1146 * get_max_char_width_zoom(win->font_category, input_size);
1147 input_len_x = max_username_width + 2 * BUTTONRADIUS * input_size;
1148 if (input_off + input_len_x + sep > win->len_x)
1149 {
1150 input_size *= (float)(win->len_x - sep - input_off) / input_len_x;
1151 input_len_x = win->len_x - sep - input_off;
1152 }
1153
1154 //Choose your name and password
1155 text_width = get_string_width_zoom((const unsigned char*)win_name_pass,
1156 win->font_category, bit_small);
1157 widget_id = label_add_extended(win->window_id, free_widget_id++, 0,
1158 (win->len_x - text_width)/2, y, 0, bit_small, (const char*)win_name_pass);
1159 y += widget_get_height(win->window_id, widget_id) + 2*sep;
1160 label_add_extended(win->window_id, free_widget_id++, 0, x_off, y + center, 0, label_size, (char*)login_username_str);
1161 widget_id = widget_add(win->window_id, free_widget_id++, 0, input_off, y, input_len_x, input_len_y, 0, input_size, &name_type, inputs[0].str, (void*)&specs[0]);
1162 y += input_len_y + 2*sep;
1163 label_add_extended(win->window_id, free_widget_id++, 0, x_off, y + center, 0, label_size, (char*)login_password_str);
1164 widget_id = widget_add(win->window_id, free_widget_id++, 0, input_off, y, input_len_x, input_len_y, 0, input_size, &password_type, inputs[1].str, (void*)&specs[1]);
1165 y += input_len_y + 2*sep;
1166 label_add_extended(win->window_id ,free_widget_id++, 0, x_off, y + center, 0, label_size, (char*)confirm_password);
1167 widget_id = widget_add(win->window_id, free_widget_id++, 0, input_off, y, input_len_x, input_len_y, 0, input_size, &password_type, inputs[2].str, (void*)&specs[2]);
1168 y += input_len_y + 2*sep;
1169
1170 // Show password checkbox
1171 text_width = get_string_width_zoom((const unsigned char*)show_password,
1172 win->font_category, bit_small);
1173 label_add_extended(win->window_id, free_widget_id++, 0,
1174 win->len_x - 4 * sep - size - text_width, y, 0, bit_small, show_password);
1175 widget_id = checkbox_add_extended(win->window_id, free_widget_id++, 0, win->len_x - 2 * sep - size, y, size, size, 0, bit_small, &hidden);
1176 y += sep + get_line_height(win->font_category, bit_small);
1177
1178 // Remember password checkbox
1179 text_width = get_string_width_zoom((const unsigned char*)remember_details_str,
1180 win->font_category, bit_small);
1181 label_add_extended(win->window_id, free_widget_id++, 0,
1182 win->len_x - 4 * sep - size - text_width, y, 0, bit_small, remember_details_str);
1183 widget_id = checkbox_add_extended(win->window_id, free_widget_id, 0, win->len_x - 2 * sep - size, y, size, size, 0, bit_small, &passmngr_enabled);
1184 y += sep + get_line_height(win->font_category, bit_small);
1185 widget_set_OnClick(win->window_id, free_widget_id, click_remember_details_handler);
1186 free_widget_id++;
1187
1188 // Error label
1189 error_widget_id = widget_add(win->window_id, free_widget_id++, 0, 2 * sep, y, win->len_x - 4 * sep, win->len_y - y, 0, very_small, &errorbox_type, NULL, NULL);
1190
1191 //Done and Back buttons
1192 widget_id = button_add_extended(win->window_id, free_widget_id++, 0, 0, 0, 0, 0, 0, very_small, char_done);
1193 widget_set_OnClick(win->window_id, widget_id, &click_done_handler);
1194 y = win->len_y - widget_get_height(win->window_id, widget_id) - sep;
1195 widget_move(win->window_id, widget_id, (win->len_x / 2 - widget_get_width(win->window_id, widget_id)) / 2, y);
1196 widget_id = button_add_extended(win->window_id, free_widget_id++, 0, 0, 0, 0, 0, 0, very_small, char_back);
1197 widget_set_OnClick(win->window_id, widget_id, &click_back_handler);
1198 widget_move(win->window_id, widget_id, win->len_x / 2 + (win->len_x / 2 - widget_get_width(win->window_id, widget_id)) / 2, y);
1199 return 1;
1200 }
1201
click_newchar_book_handler(widget_list * w,int mx,int my,Uint32 flags)1202 static int click_newchar_book_handler(widget_list *w, int mx, int my, Uint32 flags)
1203 {
1204 if ( (flags & ELW_MOUSE_BUTTON) == 0) return 0;
1205 image_set_uv(w->window_id, w->id, (float)32/256,1.0f-(float)64/256,(float)63/256,1.0f-(float)95/256);
1206 toggle_book(w->id);
1207 newchar_mouseover = w->id;
1208 return 1;
1209 }
1210
mouseover_newchar_book_handler(widget_list * w,int mx,int my)1211 static int mouseover_newchar_book_handler(widget_list *w, int mx, int my)
1212 {
1213 image_set_uv(w->window_id, w->id, (float)32/256,1.0f-(float)64/256,(float)63/256,1.0f-(float)95/256);
1214 newchar_mouseover = w->id;
1215 if( newchar_mouseover == book_human) tooltip = about_human;
1216 else if( newchar_mouseover == book_elf) tooltip = about_elves;
1217 else if( newchar_mouseover == book_dwarf) tooltip = about_dwarfs;
1218 else if( newchar_mouseover == book_gnome) tooltip = about_gnomes;
1219 else if( newchar_mouseover == book_orchan) tooltip = about_orchans;
1220 else if( newchar_mouseover == book_draegoni) tooltip = about_draegoni;
1221 else if( newchar_mouseover == book_human) tooltip = about_human;
1222 else return 1;
1223 newchar_mouseover_time = cur_time; //we are currently over something
1224 {
1225 window_info *win = &windows_list.window[w->window_id];
1226 int size = win->small_font_max_len_x
1227 + get_string_width_zoom((const unsigned char*)tooltip,
1228 win->font_category, win->current_scale_small);
1229 tooltip_x = (mx + size <= hud_x) ? mx : hud_x - size;
1230 tooltip_y = my + win->small_font_len_y;
1231 }
1232 return 1;
1233 }
1234
click_newchar_gender_handler(widget_list * w,int mx,int my,Uint32 flags)1235 static int click_newchar_gender_handler(widget_list *w, int mx, int my, Uint32 flags)
1236 {
1237 int i = multiselect_get_selected(w->window_id, w->id);
1238 switch(i)
1239 {
1240 case 0:
1241 change_race(our_actor.race_id + !our_actor.male);
1242 break;
1243 case 1:
1244 change_race(our_actor.race_id - our_actor.male);
1245 break;
1246 }
1247 return 1;
1248 }
1249
mouseover_p2p_race_handler(widget_list * w,int mx,int my)1250 static int mouseover_p2p_race_handler(widget_list *w, int mx, int my)
1251 {
1252 window_info *win = &windows_list.window[w->window_id];
1253 int size = win->small_font_max_len_x
1254 + get_string_width_zoom((const unsigned char*)p2p_race,
1255 win->font_category, win->current_scale_small);
1256 newchar_mouseover = 1; //we are over an p2p race
1257 newchar_mouseover_time = cur_time; //we are currently over something
1258 tooltip = p2p_race;
1259 tooltip_x = (mx + size <= hud_x) ? mx : hud_x - size;
1260 tooltip_y = my + win->small_font_len_y;
1261 return 1;
1262 }
1263
click_newchar_race_handler(widget_list * w,int mx,int my,Uint32 flags)1264 static int click_newchar_race_handler(widget_list *w, int mx, int my, Uint32 flags)
1265 {
1266 int i = multiselect_get_selected(w->window_id, w->id);
1267 switch(i)
1268 {
1269 case 0:
1270 change_race(human_female + our_actor.male);
1271 break;
1272 case 1:
1273 change_race(elf_female + our_actor.male);
1274 break;
1275 case 2:
1276 change_race(dwarf_female + our_actor.male);
1277 break;
1278 case 3:
1279 change_race(gnome_female - 31 + our_actor.male);
1280 break;
1281 case 4:
1282 change_race(orchan_female - 31 + our_actor.male);
1283 break;
1284 case 5:
1285 change_race(draegoni_female - 31 + our_actor.male);
1286 break;
1287 }
1288 return 0;
1289 }
1290
update_head(void)1291 static void update_head(void)
1292 {
1293 // Detach the old head, and reattach and save the new one.
1294 model_detach_mesh(our_actor.our_model,
1295 our_actor.our_model->body_parts->head_meshindex);
1296 model_attach_mesh(our_actor.our_model,
1297 actors_defs[our_actor.race].head[our_actor.head].mesh_index);
1298 our_actor.our_model->body_parts->head_meshindex =
1299 actors_defs[our_actor.race].head[our_actor.head].mesh_index;
1300 }
1301
update_skin(void)1302 static void update_skin(void)
1303 {
1304 // Copy the skin texture names.
1305 safe_strncpy(our_actor.our_model->body_parts->hands_tex,
1306 actors_defs[our_actor.race].skin[our_actor.skin].hands_name,
1307 sizeof(our_actor.our_model->body_parts->hands_tex));
1308 safe_strncpy(our_actor.our_model->body_parts->head_tex,
1309 actors_defs[our_actor.race].skin[our_actor.skin].head_name,
1310 sizeof(our_actor.our_model->body_parts->head_tex));
1311
1312 change_enhanced_actor(our_actor.our_model->texture_id,
1313 our_actor.our_model->body_parts);
1314 }
1315
update_hair(void)1316 static void update_hair(void)
1317 {
1318 // Copy the hair texture name.
1319 safe_strncpy(our_actor.our_model->body_parts->hair_tex,
1320 actors_defs[our_actor.race].hair[our_actor.hair].hair_name,
1321 sizeof(our_actor.our_model->body_parts->hair_tex));
1322
1323 change_enhanced_actor(our_actor.our_model->texture_id,
1324 our_actor.our_model->body_parts);
1325 }
1326
1327 #ifdef NEW_EYES
update_eyes()1328 static void update_eyes()
1329 {
1330 // Copy the eyes texture name.
1331 safe_strncpy(our_actor.our_model->body_parts->eyes_tex,
1332 actors_defs[our_actor.race].eyes[our_actor.eyes].eyes_name,
1333 sizeof(our_actor.our_model->body_parts->eyes_tex));
1334
1335 change_enhanced_actor(our_actor.our_model->texture_id,
1336 our_actor.our_model->body_parts);
1337 }
1338 #endif /* NEW_EYES */
1339
update_shirt()1340 static void update_shirt()
1341 {
1342 // Copy the shirt and arms texture names.
1343 safe_strncpy(our_actor.our_model->body_parts->arms_tex,
1344 actors_defs[our_actor.race].shirt[our_actor.shirt].arms_name,
1345 sizeof(our_actor.our_model->body_parts->arms_tex));
1346 safe_strncpy(our_actor.our_model->body_parts->torso_tex,
1347 actors_defs[our_actor.race].shirt[our_actor.shirt].torso_name,
1348 sizeof(our_actor.our_model->body_parts->torso_tex));
1349
1350 // If we need a new mesh, drop the old one and load it.
1351 if (actors_defs[our_actor.race].shirt[our_actor.shirt].mesh_index !=
1352 our_actor.our_model->body_parts->torso_meshindex)
1353 {
1354 model_detach_mesh(our_actor.our_model,
1355 our_actor.our_model->body_parts->torso_meshindex);
1356 model_attach_mesh(our_actor.our_model,
1357 actors_defs[our_actor.race].shirt[our_actor.shirt].mesh_index);
1358 our_actor.our_model->body_parts->torso_meshindex =
1359 actors_defs[our_actor.race].shirt[our_actor.shirt].mesh_index;
1360 }
1361
1362 change_enhanced_actor(our_actor.our_model->texture_id, our_actor.our_model->body_parts);
1363 }
1364
update_pants(void)1365 static void update_pants(void)
1366 {
1367 // Copy the pants texture name.
1368 safe_strncpy(our_actor.our_model->body_parts->pants_tex,
1369 actors_defs[our_actor.race].legs[our_actor.pants].legs_name,
1370 sizeof(our_actor.our_model->body_parts->pants_tex));
1371
1372 // If we need a new mesh, drop the old one and load it.
1373 if (actors_defs[our_actor.race].legs[our_actor.pants].mesh_index !=
1374 our_actor.our_model->body_parts->legs_meshindex)
1375 {
1376 model_detach_mesh(our_actor.our_model,
1377 our_actor.our_model->body_parts->legs_meshindex);
1378 model_attach_mesh(our_actor.our_model,
1379 actors_defs[our_actor.race].legs[our_actor.pants].mesh_index);
1380 our_actor.our_model->body_parts->legs_meshindex =
1381 actors_defs[our_actor.race].legs[our_actor.pants].mesh_index;
1382 }
1383
1384 change_enhanced_actor(our_actor.our_model->texture_id,
1385 our_actor.our_model->body_parts);
1386 }
1387
update_boots(void)1388 static void update_boots(void)
1389 {
1390 // Copy the new boots texture name.
1391 safe_strncpy(our_actor.our_model->body_parts->boots_tex,
1392 actors_defs[our_actor.race].boots[our_actor.boots].boots_name,
1393 sizeof(our_actor.our_model->body_parts->boots_tex));
1394
1395 // If we need a new mesh, drop the old one and load it.
1396 if (actors_defs[our_actor.race].boots[our_actor.boots].mesh_index !=
1397 our_actor.our_model->body_parts->boots_meshindex)
1398 {
1399 model_detach_mesh(our_actor.our_model,
1400 our_actor.our_model->body_parts->boots_meshindex);
1401 model_attach_mesh(our_actor.our_model,
1402 actors_defs[our_actor.race].boots[our_actor.boots].mesh_index);
1403 our_actor.our_model->body_parts->boots_meshindex =
1404 actors_defs[our_actor.race].boots[our_actor.boots].mesh_index;
1405 }
1406
1407 change_enhanced_actor(our_actor.our_model->texture_id,
1408 our_actor.our_model->body_parts);
1409 }
1410
head_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1411 static int head_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1412 {
1413 our_actor.head = dec(our_actor.def->head, our_actor.head, 1);
1414
1415 update_head();
1416
1417 return 1;
1418 }
1419
head_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1420 static int head_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1421 {
1422 our_actor.head = inc(our_actor.def->head, our_actor.head, 1);
1423
1424 update_head();
1425
1426 return 1;
1427 }
1428
skin_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1429 static int skin_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1430 {
1431 our_actor.skin = dec(our_actor.def->skin, our_actor.skin, 1);
1432
1433 update_skin();
1434
1435 return 1;
1436 }
1437
skin_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1438 static int skin_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1439 {
1440 our_actor.skin = inc(our_actor.def->skin, our_actor.skin, 1);
1441
1442 update_skin();
1443
1444 return 1;
1445 }
1446
hair_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1447 static int hair_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1448 {
1449 our_actor.hair = dec(our_actor.def->hair, our_actor.hair, 1);
1450
1451 update_hair();
1452
1453 return 1;
1454 }
1455
hair_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1456 static int hair_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1457 {
1458 our_actor.hair = inc(our_actor.def->hair, our_actor.hair, 1);
1459
1460 update_hair();
1461
1462 return 1;
1463 }
1464
eyes_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1465 static int eyes_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1466 {
1467 our_actor.eyes = dec(our_actor.def->eyes, our_actor.eyes, 1);
1468 #ifdef NEW_EYES
1469 update_eyes();
1470 #endif
1471 return 1;
1472 }
1473
eyes_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1474 static int eyes_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1475 {
1476 our_actor.eyes = inc(our_actor.def->eyes, our_actor.eyes, 1);
1477 #ifdef NEW_EYES
1478 update_eyes();
1479 #endif
1480 return 1;
1481 }
1482
shirt_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1483 static int shirt_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1484 {
1485 our_actor.shirt = dec(our_actor.def->shirts, our_actor.shirt, 1);
1486
1487 update_shirt();
1488
1489 return 1;
1490 }
1491
shirt_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1492 static int shirt_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1493 {
1494 our_actor.shirt = inc(our_actor.def->shirts, our_actor.shirt, 1);
1495
1496 update_shirt();
1497
1498 return 1;
1499 }
1500
pants_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1501 static int pants_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1502 {
1503 our_actor.pants=dec(our_actor.def->pants, our_actor.pants, 1);
1504
1505 update_pants();
1506
1507 return 1;
1508 }
1509
pants_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1510 static int pants_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1511 {
1512 our_actor.pants=inc(our_actor.def->pants, our_actor.pants, 1);
1513
1514 update_pants();
1515
1516 return 1;
1517 }
1518
boots_dec_handler(widget_list * w,int mx,int my,Uint32 flags)1519 static int boots_dec_handler(widget_list *w, int mx, int my, Uint32 flags)
1520 {
1521 our_actor.boots = dec(our_actor.def->boots, our_actor.boots, 1);
1522
1523 update_boots();
1524
1525 return 1;
1526 }
1527
boots_inc_handler(widget_list * w,int mx,int my,Uint32 flags)1528 static int boots_inc_handler(widget_list *w, int mx, int my, Uint32 flags)
1529 {
1530 our_actor.boots = inc(our_actor.def->boots, our_actor.boots, 1);
1531
1532 update_boots();
1533
1534 return 1;
1535 }
1536
mouseover_color_race_handler(window_info * win,int mx,int my)1537 static int mouseover_color_race_handler(window_info *win, int mx, int my)
1538 {
1539 if(!(newchar_mouseover == book_human)) image_set_uv(win->window_id, book_human, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1540 if(!(newchar_mouseover == book_elf)) image_set_uv(win->window_id, book_elf, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1541 if(!(newchar_mouseover == book_dwarf)) image_set_uv(win->window_id, book_dwarf, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1542 if(!(newchar_mouseover == book_gnome)) image_set_uv(win->window_id, book_gnome, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1543 if(!(newchar_mouseover == book_orchan)) image_set_uv(win->window_id, book_orchan, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1544 if(!(newchar_mouseover == book_draegoni)) image_set_uv(win->window_id, book_draegoni, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256);
1545 if(!newchar_mouseover)
1546 newchar_mouseover_time = 0; //reset timer
1547 newchar_mouseover = 0;
1548 return 1;
1549 }
1550
draw_box(const unsigned char * name,font_cat cat,int x,int y,int w,int h,float size,int rad)1551 static void draw_box(const unsigned char* name, font_cat cat, int x, int y, int w, int h,
1552 float size, int rad)
1553 {
1554 int l=0;
1555
1556 if (name)
1557 {
1558 int line_height = get_line_height(cat, size);
1559 l = (w-10-get_string_width_zoom(name, cat, size))/2.0f;
1560 draw_string_zoomed_centered(x + w/2, y-line_height/2, name, 1, size);
1561 }
1562
1563 glDisable(GL_TEXTURE_2D);
1564 if(l>0){
1565 glBegin(GL_LINE_STRIP);
1566 glVertex2i(x+l, y);
1567 draw_circle_ext(x, y, rad, 5, 90, 180);
1568 draw_circle_ext(x, y+h-2*rad, rad, 5, 180, 270);
1569 draw_circle_ext(x+w-2*rad, y+h-2*rad, rad, 5, 270, 360);
1570 draw_circle_ext(x+w-2*rad, y, rad, 5, 0, 90);
1571 glVertex2i(x+w-l, y);
1572 glEnd();
1573 } else if(l<0){
1574 glBegin(GL_LINE_STRIP);
1575 glVertex2i(x+l, y);
1576 draw_circle_ext(x+rad, y+h-rad, rad, 5, 180, 270);
1577 draw_circle_ext(x+w-2*rad, y+h-rad, rad, 5, 270, 360);
1578 glVertex2i(x+w-l, y);
1579 glEnd();
1580 } else {
1581 glBegin(GL_LINE_LOOP);
1582 draw_circle_ext(x+rad, y, rad, 5, 90, 180);
1583 draw_circle_ext(x+rad, y+h-rad, rad, 5, 180, 270);
1584 draw_circle_ext(x+w-2*rad, y+h-rad, rad, 5, 270, 360);
1585 draw_circle_ext(x+w-2*rad, y, rad, 5, 0, 90);
1586 glEnd();
1587 }
1588 glEnable(GL_TEXTURE_2D);
1589 #ifdef OPENGL_TRACE
1590 CHECK_GL_ERRORS();
1591 #endif //OPENGL_TRACE
1592 }
1593
box_draw(widget_list * w)1594 static int box_draw(widget_list *w)
1595 {
1596 glColor3f(w->r, w->g, w->b); //draw a box
1597 draw_box(w->widget_info, w->fcat, w->pos_x, w->pos_y, w->len_x, w->len_y, w->size, 0);
1598 #ifdef OPENGL_TRACE
1599 CHECK_GL_ERRORS();
1600 #endif //OPENGL_TRACE
1601 return 1;
1602 }
1603
1604 static const struct WIDGET_TYPE box_type = {NULL, &box_draw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //a custom box widget
1605
init_color_race_handler(window_info * win)1606 static int init_color_race_handler(window_info * win)
1607 {
1608 float r = gui_color[0], g = gui_color[1], b = gui_color[2]; //widget color
1609 float rh = gui_invert_color[0], gh = gui_invert_color[1], bh = gui_invert_color[2]; //highlighted color
1610 float very_small = win->current_scale_small; //font sizes
1611 float bit_small = 0.9f * win->current_scale;
1612 float normal = 1.0f * win->current_scale;
1613 int free_widget_id = 8; //next free widget id
1614 int widget_id;
1615 int sep = (int)(0.5 + win->current_scale * 5);
1616 int y = sep;
1617 int label_width;
1618
1619 //Design your character
1620 label_width = get_string_width_zoom((const unsigned char*)win_design,
1621 win->font_category, bit_small);
1622 widget_id = label_add_extended(win->window_id, free_widget_id++, 0,
1623 (win->len_x - label_width)/2, y, 0, bit_small, win_design);
1624 y += widget_get_height(win->window_id, widget_id);
1625
1626 //Gender selection
1627 {
1628 int box_label_height = get_line_height(win->font_category, very_small);
1629 int button_height = 2 * very_small * BUTTONRADIUS;
1630 int element_height = box_label_height + button_height;
1631 int button_width = (int)(0.5 + win->current_scale * 100);
1632 y += sep + box_label_height / 2;
1633 widget_add(win->window_id, free_widget_id++, 0, sep, y, win->len_x - 2 * sep, element_height, 0, very_small, &box_type, gender_str, NULL);
1634 widget_id = multiselect_add_extended(win->window_id, free_widget_id++, 0, 2 * sep, y + box_label_height / 2, win->len_x - 4 * sep, button_height, normal, r, g, b, rh, gh, bh, 2);
1635 multiselect_button_add_extended(win->window_id, widget_id, 0, 0, button_width, male_str, very_small, our_actor.male);
1636 multiselect_button_add_extended(win->window_id, widget_id, win->len_x - button_width - 4 * sep, 0, button_width, female_str, very_small, !our_actor.male);
1637 widget_set_OnClick(win->window_id, widget_id, &click_newchar_gender_handler);
1638 y += element_height;
1639 }
1640
1641 //Races
1642 {
1643 int book_ids[6] = {book_human, book_elf, book_dwarf, book_gnome, book_orchan, book_draegoni};
1644 int box_label_height = get_line_height(win->font_category, very_small);
1645 int button_height = 2 * very_small * BUTTONRADIUS;
1646 int button_y_off = box_label_height;
1647 int button_set_height = 3 * button_height + 2 * sep;
1648 int button_set_width = win->len_x - 4 * sep;
1649 int col_two_x_off = sep + button_set_width / 2;
1650 int button_width = col_two_x_off - 4*sep - button_height;
1651 int element_height = 2 * box_label_height + button_set_height;
1652 size_t i;
1653 y += sep + box_label_height / 2;
1654
1655 widget_add(win->window_id, free_widget_id++, 0, sep, y, win->len_x - 2 * sep, element_height, 0, very_small, &box_type, race_str, NULL);
1656
1657 widget_id = widget_add(win->window_id, free_widget_id++, 0, sep + col_two_x_off, y + box_label_height / 2 + 2,
1658 3 * sep + button_width + button_height, button_set_height + box_label_height / 2 + sep, 0, very_small, &box_type, "P2P", NULL);
1659 widget_set_color(win->window_id, widget_id, 1.0f, 0.0f, 0.0f);
1660 widget_set_OnMouseover(win->window_id, widget_id, &mouseover_p2p_race_handler);
1661
1662 widget_id = multiselect_add_extended(win->window_id, free_widget_id++, 0, 2 * sep, y + button_y_off , button_set_width, button_set_height, normal, r, g, b, rh, gh, bh, 6);
1663 multiselect_button_add_extended(win->window_id, widget_id, 0, 0, button_width, human_str, very_small, our_actor.race==human_female||our_actor.race==human_male);
1664 multiselect_button_add_extended(win->window_id, widget_id, 0, button_height + sep, button_width, elf_str, very_small, our_actor.race==elf_female||our_actor.race==elf_male);
1665 multiselect_button_add_extended(win->window_id, widget_id, 0, 2 * (button_height + sep), button_width, dwarf_str, very_small, our_actor.race==dwarf_female||our_actor.race==dwarf_male);
1666 multiselect_button_add_extended(win->window_id, widget_id, col_two_x_off, 0, button_width, gnome_str, very_small, our_actor.race==dwarf_female||our_actor.race==dwarf_male);
1667 multiselect_button_add_extended(win->window_id, widget_id, col_two_x_off, button_height + sep, button_width, orchan_str, very_small, our_actor.race==orchan_female||our_actor.race==orchan_male);
1668 multiselect_button_add_extended(win->window_id, widget_id, col_two_x_off, 2 * (button_height + sep), button_width, draegoni_str, very_small, our_actor.race==draegoni_female||our_actor.race==draegoni_male);
1669 widget_set_OnClick(win->window_id, widget_id, &click_newchar_race_handler);
1670
1671 for(i = 0; i < 3; i++)
1672 {
1673 widget_id = image_add_extended(win->window_id, book_ids[i], 0, 2 * sep + button_width + sep, y + button_y_off + (button_height + sep)*i, button_height, button_height, 0, 1.0f, icons_text, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256, -1);
1674 widget_set_color(win->window_id, widget_id, 1.0f, 1.0f, 1.0f);
1675 widget_set_OnClick(win->window_id, widget_id, &click_newchar_book_handler);
1676 widget_set_OnMouseover(win->window_id, widget_id, &mouseover_newchar_book_handler);
1677 }
1678 for(i = 0; i< 3; i++)
1679 {
1680 widget_id = image_add_extended(win->window_id, book_ids[i+3], 0, 3 * sep + col_two_x_off + button_width, y + button_y_off + (button_height + sep)*i, button_height, button_height, 0, 1.0f, icons_text, (float)0/256,1.0f-(float)64/256,(float)31/256,1.0f-(float)95/256, -1);
1681 widget_set_color(win->window_id, widget_id, 1.0f, 1.0f, 1.0f);
1682 widget_set_OnClick(win->window_id, widget_id, &click_newchar_book_handler);
1683 widget_set_OnMouseover(win->window_id, widget_id, &mouseover_newchar_book_handler);
1684 }
1685 y += element_height;
1686 }
1687
1688 // Appearence
1689 {
1690 char* body_part_strs[7] = {head_str, skin_str, hair_str, eyes_str, shirt_str, pants_str, boots_str};
1691 void* body_handlers_dec[7] = {&head_dec_handler, &skin_dec_handler, &hair_dec_handler, &eyes_dec_handler, &shirt_dec_handler, &pants_dec_handler, &boots_dec_handler};
1692 void* body_handlers_inc[7] = {&head_inc_handler, &skin_inc_handler, &hair_inc_handler, &eyes_inc_handler, &shirt_inc_handler, &pants_inc_handler, &boots_inc_handler};
1693 int box_label_height = get_line_height(win->font_category, very_small);
1694 int changer_height = get_line_height(win->font_category, bit_small);
1695 int element_height = box_label_height + 4 * changer_height + 3 * sep;
1696 int prev_width = get_string_width_zoom((const unsigned char*)"<<",
1697 win->font_category, bit_small);
1698 int next_width = get_string_width_zoom((const unsigned char*)">>",
1699 win->font_category, bit_small);
1700 int x;
1701 size_t i;
1702 int label_width;
1703 int line_height = get_line_height(win->font_category, bit_small);
1704
1705 y += sep + box_label_height / 2;
1706 widget_add(win->window_id, free_widget_id++, 0, sep, y, win->len_x - 2 * sep, element_height, 0, very_small, &box_type, appearance_str, NULL);
1707 y += box_label_height / 2;
1708 for(i = 0; i < 4; i++)//Head, Skin, Hair and Eyes
1709 {
1710 widget_id = label_add_extended(win->window_id, free_widget_id++, 0, 2 * sep, y+(line_height+sep)*i, 0, bit_small, "<<");
1711 widget_set_OnClick(win->window_id, widget_id, body_handlers_dec[i]);
1712 label_width = get_string_width_zoom((const unsigned char*)body_part_strs[i],
1713 win->font_category, bit_small);
1714 x = 2 * sep + prev_width
1715 + (win->len_x/2 - 3 * sep - prev_width - next_width - label_width)/2;
1716 label_add_extended(win->window_id, free_widget_id++, 0, x, y+(line_height+sep)*i, 0, bit_small, body_part_strs[i]);
1717 widget_id = label_add_extended(win->window_id, free_widget_id++, 0, win->len_x/2-sep-next_width, y+(line_height+sep)*i, 0, bit_small, ">>");
1718 widget_set_OnClick(win->window_id, widget_id, body_handlers_inc[i]);
1719 }
1720 for(i = 4; i < 7; i++)//Shirt, Pants and Boots
1721 {
1722 widget_id = label_add_extended(win->window_id, free_widget_id++, 0, win->len_x/2+sep, y+(line_height+sep)*(i-4), 0, bit_small, "<<");
1723 widget_set_OnClick(win->window_id, widget_id, body_handlers_dec[i]);
1724 label_width = get_string_width_zoom((const unsigned char*)body_part_strs[i],
1725 win->font_category, bit_small);
1726 x = win->len_x/2 + sep + prev_width
1727 + (win->len_x/2 - 3 * sep - prev_width - next_width - label_width)/2;
1728 label_add_extended(win->window_id, free_widget_id++, 0, x, y+(line_height+sep)*(i-4), 0, bit_small, (char*)body_part_strs[i]);
1729 widget_id = label_add_extended(win->window_id, free_widget_id++, 0, win->len_x-2 * sep-next_width, y+(line_height+sep)*(i-4), 0, bit_small, ">>");
1730 widget_set_OnClick(win->window_id, widget_id, body_handlers_inc[i]);
1731 }
1732 }
1733
1734 //Done and Back
1735 widget_id = button_add_extended(win->window_id, free_widget_id++, 0, 0, 0, 0, 0, 0, very_small, char_done);
1736 widget_set_OnClick(win->window_id, widget_id, &click_done_handler);
1737 y = win->len_y - widget_get_height(win->window_id, widget_id) - sep;
1738 widget_move(win->window_id, widget_id, (win->len_x / 2 - widget_get_width(win->window_id, widget_id)) / 2, y);
1739 widget_id = button_add_extended(win->window_id, free_widget_id++, 0, 0, 0, 0, 0, 0, very_small, char_back);
1740 widget_set_OnClick(win->window_id, widget_id, &click_back_handler);
1741 widget_move(win->window_id, widget_id, win->len_x / 2 + (win->len_x / 2 - widget_get_width(win->window_id, widget_id)) / 2, y);
1742
1743 return 1;
1744 }
1745
1746 static int tooltip_win;
1747
display_tooltip_handler(window_info * win)1748 static int display_tooltip_handler(window_info * win)
1749 {
1750 if(newchar_mouseover_time == cur_time) //draw a help text if currently over something
1751 show_help(tooltip, tooltip_x, tooltip_y, win->current_scale);
1752 return 1;
1753 }
1754
display_newchar_hud_handler(window_info * win)1755 static int display_newchar_hud_handler(window_info * win)
1756 {
1757 glColor3f(0.0f, 0.0f, 0.0f); //Draw a black background
1758 glBegin(GL_QUADS);
1759 glVertex2i(0, 0);
1760 glVertex2i(0, win->len_y);
1761 glVertex2i(win->len_x, win->len_y);
1762 glVertex2i(win->len_x, 0);
1763 glEnd();
1764 glColor3fv(gui_color);
1765 #ifdef OPENGL_TRACE
1766 CHECK_GL_ERRORS();
1767 #endif //OPENGL_TRACE
1768 return 1;
1769 }
1770
create_newchar_hud_window(void)1771 static void create_newchar_hud_window(void)
1772 {
1773 if(newchar_hud_win != -1) return;
1774
1775 newchar_hud_win = create_window("Newchar_Hud", newchar_root_win, 0, window_width - hud_x, 0, hud_x, window_height - hud_y, ELW_USE_UISCALE|ELW_USE_BORDER|ELW_SHOW|ELW_SHOW_LAST);
1776 set_window_handler(newchar_hud_win, ELW_HANDLER_DISPLAY, &display_newchar_hud_handler);
1777
1778 tooltip_win = create_window("Help Text", newchar_hud_win, 0, 0, 0, 0, 0, ELW_USE_UISCALE|ELW_SHOW);
1779 set_window_handler(tooltip_win, ELW_HANDLER_DISPLAY, &display_tooltip_handler);
1780
1781 color_race_win = create_window(win_design, newchar_hud_win, 0, 0, 0, hud_x, window_height - hud_y, ELW_USE_UISCALE|ELW_SHOW|ELW_SHOW_LAST); //Design your character
1782 set_window_handler(color_race_win, ELW_HANDLER_INIT, &init_color_race_handler);
1783 set_window_handler(color_race_win, ELW_HANDLER_MOUSEOVER, &mouseover_color_race_handler);
1784 init_window(color_race_win, newchar_hud_win, 0, 0, 0, hud_x, window_height - hud_y);
1785
1786 namepass_win = create_window(win_name_pass, newchar_hud_win, 0, 0, 0, hud_x, window_height - hud_y, ELW_USE_UISCALE|ELW_SHOW_LAST); //Choose name and password
1787 set_window_handler(namepass_win, ELW_HANDLER_INIT, &init_namepass_handler);
1788 set_window_handler(namepass_win, ELW_HANDLER_KEYPRESS, (int (*)())&keypress_namepass_handler);
1789 init_window(namepass_win, newchar_hud_win, 0, 0, 0, hud_x, window_height - hud_y);
1790 }
1791
resize_newchar_hud_window(void)1792 void resize_newchar_hud_window(void)
1793 {
1794 if(newchar_hud_win >= 0) //Simply destroy and recreate everything
1795 {
1796 destroy_window(color_race_win);
1797 destroy_window(namepass_win);
1798 destroy_window(newchar_hud_win);
1799 destroy_window(tooltip_win);
1800
1801 newchar_hud_win = -1;
1802 create_newchar_hud_window();
1803 }
1804 }
1805
destroy_new_character_interface(void)1806 void destroy_new_character_interface(void)
1807 {
1808 destroy_window(color_race_win);
1809 destroy_window(newchar_advice_win);
1810 destroy_window(namepass_win);
1811 destroy_window(newchar_hud_win);
1812 destroy_window(tooltip_win);
1813 destroy_window(newchar_root_win);
1814 color_race_win = newchar_advice_win = namepass_win = newchar_hud_win = tooltip_win = newchar_root_win = -1;
1815 }
1816