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