1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "storage.h"
6 #include "asc.h"
7 #include "context_menu.h"
8 #include "dialogues.h"
9 #include "elloggingwrapper.h"
10 #include "elwindows.h"
11 #include "filter.h"
12 #include "gamewin.h"
13 #include "hud.h"
14 #include "init.h"
15 #include "items.h"
16 #include "item_info.h"
17 #include "item_lists.h"
18 #include "misc.h"
19 #include "multiplayer.h"
20 #include "named_colours.h"
21 #include "sound.h"
22 #include "textures.h"
23 #include "translate.h"
24 #include "widgets.h"
25 #ifdef OPENGL_TRACE
26 #include "gl_init.h"
27 #endif
28 
29 #define STORAGE_CATEGORIES_SIZE 50
30 #define STORAGE_SCROLLBAR_CATEGORIES 1200
31 #define STORAGE_SCROLLBAR_ITEMS 1201
32 
33 struct storage_category {
34 	char name[25];
35 	int id;
36 	int color;
37 } storage_categories[STORAGE_CATEGORIES_SIZE];
38 
39 int no_storage_categories=0;
40 int selected_category=-1;
41 int view_only_storage=0;
42 Uint32 drop_fail_time = 0;
43 int sort_storage_categories = 0;
44 int sort_storage_items = 0;
45 
46 int active_storage_item=-1;
47 
48 ground_item storage_items[STORAGE_ITEMS_SIZE]={{0,0,0,0}};
49 int no_storage;
50 
51 #define MAX_DESCR_LEN 202
52 static const int item_grid_size = 6;
53 char storage_text[MAX_DESCR_LEN]={0};
54 static char last_storage_text[MAX_DESCR_LEN]={0};
55 static unsigned char wrapped_storage_text[MAX_DESCR_LEN+10]={0};
56 
57 static struct { int quantity; int id; int image_id; } print_info[STORAGE_ITEMS_SIZE];
58 static int number_to_print = 0;
59 static int next_item_to_print = 0;
60 static int printing_category = -1;
61 static int mouse_over_titlebar = 0;
62 static int mouse_over_storage = 0;
63 
64 int disable_storage_filter = 0;
65 static char filter_item_text[40] = "";
66 static size_t filter_item_text_size = 0;
67 static Uint8 storage_items_filter[STORAGE_ITEMS_SIZE];
68 
69 //	Look though the category for the selected item, pick it up if found.
70 //
select_item(int image_id,Uint16 item_id)71 static void select_item(int image_id, Uint16 item_id)
72 {
73 	int i;
74 	int found_at = -1;
75 
76 	for (i=0; i<no_storage; i++)
77 	{
78 		if ((item_id != unset_item_uid) && (storage_items[i].id != unset_item_uid) && (storage_items[i].quantity > 0))
79 		{
80 			if (storage_items[i].id == item_id)
81 			{
82 				found_at = i;
83 				break;
84 			}
85 		}
86 		else
87 		if ((storage_items[i].image_id == image_id) && (storage_items[i].quantity > 0))
88 		{
89 			found_at = i;
90 			break;
91 		}
92 	}
93 
94 	if (found_at < 0)
95 	{
96 		do_alert1_sound();
97 		item_lists_reset_pickup_fail_time();
98 	}
99 	else
100 	{
101 		active_storage_item=storage_items[found_at].pos;
102 		if (!view_only_storage)
103 		{
104 			storage_item_dragged=found_at;
105 			do_drag_item_sound();
106 		}
107 		else
108 		{
109 			do_click_sound();
110 		}
111 	}
112 }
113 
114 
115 static int wanted_category = -1;
116 static Uint16 wanted_item_id = -1;
117 static int wanted_image_id = -1;
118 static void move_to_category(int cat);
119 static int find_category(int id);
120 static int storage_categories_display = 0;
121 
122 //	Called when the category is changed.
123 //	- Update the store of items/category.
124 //	- If in the process of picking up an item go for it if this is the category.
125 //
category_updated(void)126 static void category_updated(void)
127 {
128 	int i;
129 	for (i=0; i<no_storage; i++)
130 		update_category_maps(storage_items[i].image_id, storage_items[i].id, storage_categories[selected_category].id);
131 	if (selected_category == wanted_category)
132 	{
133 		select_item(wanted_image_id, wanted_item_id);
134 		wanted_category = -1;
135 	}
136 }
137 
138 
139 //	Start the process of picking up the specified item from a specified category.
140 //	If the category is already selected, try picking up the item now, otherwise
141 //	set the requird category, the pick will continue when the category is availble.
142 //
pickup_storage_item(int image_id,Uint16 item_id,int cat_id)143 void pickup_storage_item(int image_id, Uint16 item_id, int cat_id)
144 {
145 	if ((get_id_MW(MW_STORAGE) < 0) || (find_category(cat_id) == -1))
146 	{
147 		do_alert1_sound();
148 		item_lists_reset_pickup_fail_time();
149 		return;
150 	}
151 	wanted_category = find_category(cat_id);
152 	wanted_image_id = image_id;
153 	wanted_item_id = item_id;
154 	if (selected_category == wanted_category)
155 	{
156 		select_item(wanted_image_id, wanted_item_id);
157 		wanted_category = -1;
158 	}
159 	else
160 		move_to_category(wanted_category);
161 }
162 
163 
164 
get_storage_text(const Uint8 * in_data,int len)165 void get_storage_text (const Uint8 *in_data, int len)
166 {
167 	safe_snprintf(storage_text, sizeof(storage_text), "%.*s", len, in_data);
168 	if ((len > 0) && (printing_category > -1) && (next_item_to_print < number_to_print))
169 	{
170 		char the_text[MAX_DESCR_LEN+20];
171 		if (!next_item_to_print)
172 		{
173 			safe_snprintf(the_text, sizeof(the_text), "%s: [Quantity Description (Id/Image ID)]", &storage_categories[printing_category].name[1] );
174 			LOG_TO_CONSOLE(c_green2, the_text);
175 		}
176 		safe_snprintf(the_text, sizeof(the_text), "%d %s (%d/%d)", print_info[next_item_to_print].quantity,
177 			&storage_text[1], print_info[next_item_to_print].id, print_info[next_item_to_print].image_id );
178 		next_item_to_print++;
179 		LOG_TO_CONSOLE(c_grey1, the_text);
180 		storage_text[0] = '\0';
181 	}
182 }
183 
category_cmp(const void * a,const void * b)184 static int category_cmp(const void *a, const void *b)
185 {
186 	return strcmp(((const struct storage_category *)a)->name,
187 				((const struct storage_category *)b)->name);
188 }
189 
get_storage_categories(const char * in_data,int len)190 void get_storage_categories(const char *in_data, int len)
191 {
192 	int i, idx;
193 
194 	idx = 1;
195 	for (i = 0; i < in_data[0] && i < STORAGE_CATEGORIES_SIZE && idx < len; i++)
196 	{
197 		storage_categories[i].id = (Uint8)in_data[idx++];
198 		storage_categories[i].name[0] = to_color_char(c_orange1);
199 		safe_strncpy(storage_categories[i].name+1, in_data+idx,
200 			sizeof(storage_categories[i].name)-1);
201 		idx += strlen(in_data+idx) + 1;
202 	}
203 	if (sort_storage_categories)
204 		qsort(storage_categories, i, sizeof(*storage_categories), category_cmp);
205 	for (i = in_data[0]; i < STORAGE_CATEGORIES_SIZE; i++)
206 	{
207 		storage_categories[i].id = -1;
208 		storage_categories[i].name[0] = 0;
209 	}
210 
211 	no_storage_categories = in_data[0];
212 	if (get_id_MW(MW_STORAGE) > 0) vscrollbar_set_bar_len(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_CATEGORIES, ( no_storage_categories - storage_categories_display ) > 1 ? (no_storage_categories - storage_categories_display) : 1);
213 
214 	selected_category=-1;
215 	active_storage_item=-1;
216 
217 	display_storage_menu();
218 	if (!view_only_storage)
219 		display_items_menu();
220 }
221 
find_category(int id)222 int find_category(int id)
223 {
224 	int i;
225 
226 	for(i=0;i<no_storage_categories;i++){
227 		if(storage_categories[i].id==id) return i;
228 	}
229 
230 	return -1;
231 }
232 
set_window_name(char * extra_sep,char * extra_name)233 void set_window_name(char *extra_sep, char *extra_name)
234 {
235 	safe_snprintf(windows_list.window[get_id_MW(MW_STORAGE)].window_name,
236 		sizeof(windows_list.window[get_id_MW(MW_STORAGE)].window_name),
237 		"%s%s%s%s", win_storage, extra_sep, extra_name, ((view_only_storage) ?win_storage_vo:""));
238 }
239 
move_to_category(int cat)240 void move_to_category(int cat)
241 {
242 	Uint8 str[4];
243 
244 	if(cat<0||cat>=no_storage_categories) return;
245 	storage_categories[cat].name[0] = to_color_char (c_red3);
246 	if (selected_category!=-1 && cat!=selected_category)
247 		storage_categories[selected_category].name[0] = to_color_char (c_orange1);
248 	set_window_name(" - ", storage_categories[cat].name+1);
249 
250 	str[0]=GET_STORAGE_CATEGORY;
251 	*((Uint8 *)(str+1))=storage_categories[cat].id;
252 
253 	my_tcp_send(my_socket, str, 2);
254 }
255 
item_cmp(const void * a,const void * b)256 static int item_cmp(const void *a, const void *b)
257 {
258 	const ground_item *item_a = (const ground_item *)a;
259 	const ground_item *item_b = (const ground_item *)b;
260 	int a_count, b_count;
261 
262 	if ((item_a->quantity <= 0) && (item_b->quantity <= 0))
263 		return 0;
264 	if (item_a->quantity <= 0)
265 		return 1;
266 	if (item_b->quantity <= 0)
267 		return -1;
268 
269 	a_count = get_item_count(item_a->id, item_a->image_id);
270 	b_count = get_item_count(item_b->id, item_b->image_id);
271 
272 	if ((a_count != 1) && (b_count != 1))
273 		return 0;
274 	if (a_count != 1)
275 		return 1;
276 	if (b_count != 1)
277 		return -1;
278 
279 	return strcmp(get_basic_item_description(item_a->id, item_a->image_id),
280 		get_basic_item_description(item_b->id, item_b->image_id));
281 }
282 
update_items_in_category(void)283 static void update_items_in_category(void)
284 {
285 	// Make sure dragged storage items with zero quantity are no longer dragged
286 	if ((storage_item_dragged >=0) && (storage_item_dragged < STORAGE_ITEMS_SIZE) && (storage_items[storage_item_dragged].quantity <= 0))
287 		storage_item_dragged = -1;
288 
289 	// if enabled, sort the items alphabetically by description (if we have one)
290 	if ((no_storage > 0) && sort_storage_items)
291 		qsort(storage_items, STORAGE_ITEMS_SIZE, sizeof(ground_item), item_cmp);
292 
293 	// Update the filter
294 	if (!disable_storage_filter && (no_storage > 0) && (filter_item_text_size > 0))
295 		filter_items_by_description(storage_items_filter, storage_items, filter_item_text, no_storage);
296 	else
297 	{
298 		size_t i;
299 		for (i=0; i<STORAGE_ITEMS_SIZE; i++)
300 			storage_items_filter[i] = 0;
301 	}
302 
303 	// Calculate the last row containing items and set the scrollbar to scroll just enough.
304 	// If the last row is full, we set the bar to scroll to the next row so we can see empty space.
305 	{
306 		size_t i;
307 		int last_occupied_row = 0;
308 		for (i = 0; i < STORAGE_ITEMS_SIZE; i++)
309 			if (storage_items[i].quantity > 0)
310 			{
311 				last_occupied_row = i / item_grid_size;
312 				if ((i % item_grid_size) == (item_grid_size - 1))
313 					last_occupied_row += 1;
314 			}
315 		vscrollbar_set_bar_len(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_ITEMS,
316 			(last_occupied_row > (item_grid_size - 1)) ?last_occupied_row - (item_grid_size - 1) : 0);
317 	}
318 }
319 
get_storage_items(const Uint8 * in_data,int len)320 void get_storage_items (const Uint8 *in_data, int len)
321 {
322 	int i;
323 	int cat, pos;
324 	int idx;
325 	int plen;
326 	int min_len = 2;
327 
328 	if (len < min_len)
329 	{
330 		LOG_WARNING("Got incomplete storage items update from the server");
331 		return;
332 	}
333 
334 	if (item_uid_enabled)
335 		plen=10;
336 	else
337 		plen=8;
338 
339 	if (in_data[0] == 255)
340 	{
341 		// We expect a single full update packet
342 		min_len += plen;
343 		if (len < min_len)
344 		{
345 			LOG_WARNING("Got incomplete storage items update from the server");
346 			return;
347 		}
348 
349 		// It's just an update - make sure we're in the right category
350 		idx = 2;
351 		active_storage_item = SDL_SwapLE16(*((Uint16*)(&in_data[idx+6])));
352 
353 		for (i = 0; i < STORAGE_ITEMS_SIZE; i++)
354 		{
355 			if ((storage_items[i].pos == SDL_SwapLE16(*((Uint16*)(&in_data[idx+6])))) && (storage_items[i].quantity > 0))
356 			{
357 				storage_items[i].image_id = SDL_SwapLE16(*((Uint16*)(&in_data[idx])));
358 				storage_items[i].quantity = SDL_SwapLE32(*((Uint32*)(&in_data[idx+2])));
359 				if (item_uid_enabled)
360 					storage_items[i].id = SDL_SwapLE16(*((Uint16*)(&in_data[idx+8])));
361 				else
362 					storage_items[i].id = unset_item_uid;
363 				update_items_in_category();
364 				return;
365 			}
366 		}
367 
368 		for (i = 0; i < STORAGE_ITEMS_SIZE; i++)
369 		{
370 			if (storage_items[i].quantity == 0)
371 			{
372 				if (item_uid_enabled)
373 					storage_items[i].id = SDL_SwapLE16(*((Uint16*)(&in_data[idx+8])));
374 				else
375 					storage_items[i].id = unset_item_uid;
376 				storage_items[i].pos = SDL_SwapLE16(*((Uint16*)(&in_data[idx+6])));
377 				storage_items[i].image_id = SDL_SwapLE16(*((Uint16*)(&in_data[idx])));
378 				storage_items[i].quantity = SDL_SwapLE32(*((Uint32*)(&in_data[idx+2])));
379 				no_storage++;
380 				update_items_in_category();
381 				return;
382 			}
383 		}
384 	}
385 
386 	no_storage = (len - 2) / plen;
387 
388 	cat = find_category(in_data[1]);
389 	if (cat >= 0)
390 	{
391 		storage_categories[cat].name[0] = to_color_char (c_red3);
392 		if (selected_category != -1 && cat != selected_category)
393 			storage_categories[selected_category].name[0] = to_color_char (c_orange1);
394 		set_window_name(" - ", storage_categories[cat].name+1);
395 		selected_category = cat;
396 	}
397 
398 	idx = 2;
399 	for (i = 0; i < no_storage && i < STORAGE_ITEMS_SIZE; i++, idx += plen)
400 	{
401 		storage_items[i].image_id = SDL_SwapLE16(*((Uint16*)(&in_data[idx])));
402 		storage_items[i].quantity = SDL_SwapLE32(*((Uint32*)(&in_data[idx+2])));
403 		storage_items[i].pos = SDL_SwapLE16(*((Uint16*)(&in_data[idx+6])));
404 		if (item_uid_enabled)
405 			storage_items[i].id = SDL_SwapLE16(*((Uint16*)(&in_data[idx+8])));
406 		else
407 			storage_items[i].id = unset_item_uid;
408 	}
409 
410 	for ( ; i < STORAGE_ITEMS_SIZE; i++)
411 	{
412 		storage_items[i].quantity=0;
413 	}
414 
415 	vscrollbar_set_pos(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_ITEMS, 0);
416 	pos = vscrollbar_get_pos(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_CATEGORIES);
417 	if (cat < pos) {
418 		vscrollbar_set_pos(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_CATEGORIES, cat);
419 	} else	if (cat >= pos + storage_categories_display) {
420 		vscrollbar_set_pos(get_id_MW(MW_STORAGE), STORAGE_SCROLLBAR_CATEGORIES, cat - storage_categories_display + 1);
421 	}
422 
423 	update_items_in_category();
424 
425 	if (selected_category != -1)
426 		category_updated();
427 
428 }
429 
430 static int cat_scrollbar_id = 0;
431 static int items_scrollbar_id = 0;
432 
433 int storage_win_x_len = 0;
434 int storage_win_y_len = 0;
435 
436 /* scalable values */
437 static int cat_right_offset = 0;
438 static int item_left_offset = 0;
439 static int item_grid_left_offset = 0;
440 static int item_right_offset = 0;
441 static int border_size = 0;
442 static int bottom_offset = 0;
443 static int item_box_size = 0;
444 static int cat_string_left_offset = 0;
445 static int cat_string_top_offset = 0;
446 static int cat_name_separation = 0;
447 static int desc_string_left_offset = 0;
448 static int desc_string_top_offset = 0;
449 static int desc_box_top_offset = 0;
450 static int desc_box_right_offset = 0;
451 static int desc_box_bottom_offset = 0;
452 static int scrollbar_width = 0;
453 static int scrollbar_len = 0;
454 
get_max_cat_width(font_cat cat,float zoom)455 static int get_max_cat_width(font_cat cat, float zoom)
456 {
457 	int i, max_width = 0;
458 	for (i = 0; i < no_storage_categories; ++i)
459 	{
460 		int width = get_string_width_zoom((const unsigned char*)storage_categories[i].name,
461 			cat, zoom);
462 		max_width = max2i(max_width, width);
463 	}
464 	return max_width;
465 }
466 
467 /* called when the UI scale changes */
ui_scale_storage_handler(window_info * win)468 static int ui_scale_storage_handler(window_info *win)
469 {
470 	int max_cat_width = get_max_cat_width(win->font_category, win->current_scale_small);
471 
472 	// set the basic sizes
473 	border_size = (int)(0.5 + 10 * win->current_scale);
474 	item_box_size = (int)(0.5 + 32 * win->current_scale);
475 
476 	// the rest are derived, some of the ordering is important!
477 	bottom_offset = (int)(0.5 + border_size + item_grid_size * item_box_size);
478 	scrollbar_width = (int)(0.5 + win->box_size);
479 	scrollbar_len = (int)(0.5 + item_grid_size * item_box_size);
480 
481 	cat_string_left_offset = (int)(0.5 + 2 * border_size);
482 	cat_string_top_offset = (int)(0.5 + 2 * border_size);
483 	storage_categories_display = (scrollbar_len - 2*border_size) / win->small_font_len_y;
484 	cat_name_separation = (int)(0.5 + (scrollbar_len - 2*border_size) / storage_categories_display);
485 	cat_right_offset = (int)(0.5 + 3 * border_size + max_cat_width);
486 
487 	item_left_offset = (int)(0.5 + cat_right_offset + scrollbar_width);
488 	item_grid_left_offset = (int)(0.5 + item_left_offset + border_size);
489 	item_right_offset = (int)(0.5 + item_grid_left_offset + item_grid_size * item_box_size);
490 
491 	desc_box_top_offset = (int)(0.5 + 2 * border_size + item_grid_size * item_box_size);
492 	desc_box_bottom_offset = (int)(0.5 + desc_box_top_offset + 2 * border_size + 2 * win->small_font_len_y);
493 	desc_string_left_offset = (int)(0.5 + 2 * border_size);
494 	desc_string_top_offset = (int)(0.5 + desc_box_top_offset + border_size);
495 
496 	storage_win_x_len = (int)(0.5 + item_right_offset + scrollbar_width + border_size + win->box_size);
497 	storage_win_y_len = (int)(0.5 + desc_box_bottom_offset + border_size);
498 	desc_box_right_offset = (int)(0.5 + storage_win_x_len - border_size);
499 
500 	// resize the window and scrollbars and move the scrollbars to correct position
501 	resize_window(win->window_id, storage_win_x_len, storage_win_y_len);
502 	widget_move(win->window_id, cat_scrollbar_id, cat_right_offset, border_size);
503 	widget_resize(win->window_id, cat_scrollbar_id, scrollbar_width, scrollbar_len);
504 	widget_move(win->window_id, items_scrollbar_id, item_right_offset, border_size);
505 	widget_resize(win->window_id, items_scrollbar_id, scrollbar_width, scrollbar_len);
506 	vscrollbar_set_bar_len(win->window_id, STORAGE_SCROLLBAR_CATEGORIES,
507 		(no_storage_categories - storage_categories_display) > 1 ? (no_storage_categories - storage_categories_display) : 1);
508 
509 	return 0;
510 }
511 
change_storage_font_handler(window_info * win,font_cat cat)512 static int change_storage_font_handler(window_info *win, font_cat cat)
513 {
514 	if (cat != UI_FONT)
515 		return 0;
516 	ui_scale_storage_handler(win);
517 	return 1;
518 }
519 
520 int cur_item_over=-1;
521 int storage_item_dragged=-1;
522 
post_display_storage_handler(window_info * win)523 static int post_display_storage_handler(window_info * win)
524 {
525 	if ((cur_item_over !=- 1) && (mouse_in_window(win->window_id, mouse_x, mouse_y) == 1) &&
526 		(active_storage_item != storage_items[cur_item_over].pos)  && (storage_items[cur_item_over].quantity > 0))
527 	{
528 		float zoom = enlarge_text() ? win->current_scale : win->current_scale_small;
529 		float line_height = enlarge_text() ? win->default_font_len_y : win->small_font_len_y;
530 		unsigned char str[20];
531 		safe_snprintf((char*)str, sizeof(str), "%d",storage_items[cur_item_over].quantity);
532 		show_help_colored_scaled_centered(str, mouse_x - win->pos_x,
533 			mouse_y - win->pos_y - line_height, 1.0f, 1.0f, 1.0f, zoom);
534 	}
535 
536 	if(active_storage_item >= 0) {
537 		int i, pos;
538 		/* Draw the active item's quantity on top of everything else. */
539 		for(i = pos = item_grid_size * vscrollbar_get_pos(win->window_id, STORAGE_SCROLLBAR_ITEMS); i < pos + item_grid_size*item_grid_size && i < no_storage; i++) {
540 			if(storage_items[i].pos == active_storage_item) {
541 				if (storage_items[i].quantity) {
542 					char str[20];
543 					int x = (i%item_grid_size) * item_box_size + item_grid_left_offset + 1;
544 
545 					safe_snprintf(str, sizeof(str), "%d", storage_items[i].quantity);
546 					if(x > (item_right_offset + 1)) {
547 						x = item_right_offset - item_box_size + 1;
548 					}
549 					if ((mouse_in_window(win->window_id, mouse_x, mouse_y) == 1) && enlarge_text())
550 						show_help_big(str, x, ((i-pos)/item_grid_size) * item_box_size + border_size + (item_box_size - win->default_font_len_y)/2, win->current_scale);
551 					else
552 						show_help(str, x, ((i-pos)/item_grid_size) * item_box_size + border_size + (item_box_size - win->small_font_len_y)/2, win->current_scale);
553 				}
554 				break;
555 			}
556 		}
557 	}
558 	return 1;
559 }
560 
display_storage_handler(window_info * win)561 int display_storage_handler(window_info * win)
562 {
563 	int i;
564 	int n=0;
565 	int pos;
566 	int help_text_line = 0;
567 
568 	static int have_colours = 0;
569 	static size_t c_selected = ELGL_INVALID_COLOUR;
570 	static size_t c_highlighted = ELGL_INVALID_COLOUR;
571 
572 	if (!have_colours)
573 	{
574 		c_selected = elglGetColourId("global.mouseselected");
575 		c_highlighted = elglGetColourId("global.mousehighlight");
576 		have_colours = 1;
577 	}
578 
579 	have_storage_list = 0;	//We visited storage, so we may have changed something
580 
581 	glColor3fv(gui_color);
582 	glEnable(GL_TEXTURE_2D);
583 
584 	for(i=pos=vscrollbar_get_pos(win->window_id,STORAGE_SCROLLBAR_CATEGORIES); i<no_storage_categories && storage_categories[i].id!=-1 && i<pos+storage_categories_display; i++,n++){
585 		int the_colour = from_color_char(storage_categories[i].name[0]);
586 		size_t offset = 1;
587 		if (the_colour == c_red3)
588 			elglColourI(c_selected);
589 		else if (the_colour == c_green2)
590 			elglColourI(c_highlighted);
591 		else if (the_colour == c_orange1)
592 			glColor3fv(gui_bright_color);
593 		else
594 			offset = 0;
595 		draw_string_small_zoomed(cat_string_left_offset, cat_string_top_offset + n * cat_name_separation, (unsigned char*)&storage_categories[i].name[offset],1, win->current_scale);
596 	}
597 	glColor3fv(gui_color);
598 	if(storage_text[0]){
599 		if (strcmp(storage_text, last_storage_text) != 0) {
600 			safe_strncpy(last_storage_text, storage_text, sizeof(last_storage_text));
601 			put_small_text_in_box_zoomed((Uint8 *)storage_text, strlen(storage_text),
602 				win->len_x - 4 * border_size, wrapped_storage_text, win->current_scale);
603 		}
604 		draw_string_small_zoomed(desc_string_left_offset, desc_string_top_offset,
605 			wrapped_storage_text, 2, win->current_scale);
606 	}
607 
608 	glColor3f(1.0f,1.0f,1.0f);
609 	for(i = pos = item_grid_size * vscrollbar_get_pos(win->window_id, STORAGE_SCROLLBAR_ITEMS); i < pos + item_grid_size*item_grid_size && i < no_storage; i++){
610 		GLfloat u_start, v_start, u_end, v_end;
611 		int x_start, x_end, y_start, y_end;
612 		int cur_item;
613 		GLuint this_texture;
614 
615 		if(!storage_items[i].quantity)continue;
616 		cur_item=storage_items[i].image_id%25;
617 		get_item_uv(cur_item, &u_start, &v_start, &u_end, &v_end);
618 
619 		this_texture=get_items_texture(storage_items[i].image_id/25);
620 
621 		if (this_texture != -1)
622 		{
623 			bind_texture(this_texture);
624 		}
625 
626 		x_start = (i%item_grid_size) * item_box_size + item_grid_left_offset + 1;
627 		x_end = x_start + item_box_size - 1;
628 		y_start = ((i-pos)/item_grid_size) * item_box_size + border_size;
629 		y_end = y_start + item_box_size - 1;
630 
631 		glBegin(GL_QUADS);
632 		draw_2d_thing(u_start,v_start,u_end,v_end,x_start,y_start,x_end,y_end);
633 		glEnd();
634 
635 		if (!disable_storage_filter && filter_item_text_size && storage_items_filter[i])
636 			gray_out(x_start,y_start,item_box_size);
637 	}
638 
639 	if(cur_item_over!=-1 && mouse_in_window(win->window_id, mouse_x, mouse_y) == 1){
640 		Uint16 item_id = storage_items[cur_item_over].id;
641 		int image_id = storage_items[cur_item_over].image_id;
642 		if (show_item_desc_text && item_info_available() && (get_item_count(item_id, image_id) == 1))
643 			show_help(get_item_description(item_id, image_id), 0, win->len_y + 10 + (help_text_line++) * win->small_font_len_y, win->current_scale);
644 	}
645 
646 	// Render the grid *after* the images. It seems impossible to code
647 	// it such that images are rendered exactly within the boxes on all
648 	// cards
649 	glDisable(GL_TEXTURE_2D);
650 
651 	glColor3fv(gui_color);
652 
653 	glBegin(GL_LINE_LOOP);
654 		glVertex2i(border_size,  border_size);
655 		glVertex2i(border_size,  bottom_offset);
656 		glVertex2i(cat_right_offset, bottom_offset);
657 		glVertex2i(cat_right_offset, border_size);
658 	glEnd();
659 
660 	glBegin(GL_LINE_LOOP);
661 		glVertex2i(border_size, desc_box_top_offset);
662 		glVertex2i(border_size, desc_box_bottom_offset);
663 		glVertex2i(desc_box_right_offset, desc_box_bottom_offset);
664 		glVertex2i(desc_box_right_offset, desc_box_top_offset);
665 	glEnd();
666 
667 	if (view_only_storage)
668 	{
669 		Uint32 currentticktime = SDL_GetTicks();
670 		if (currentticktime < drop_fail_time)
671 			drop_fail_time = 0; 				/* trap wrap */
672 		if ((currentticktime - drop_fail_time) < 250)
673 			glColor3f(0.8f,0.2f,0.2f);			/* flash red if tried to drop into */
674 		else
675 			glColor3f(0.37f, 0.37f, 0.39f);		/* otherwise draw greyed out */
676 	}
677 
678 	rendergrid(item_grid_size, item_grid_size, item_grid_left_offset, border_size, item_box_size, item_box_size);
679 	glEnable(GL_TEXTURE_2D);
680 
681 	glColor3f(1.0f,1.0f,1.0f);
682 	if (!disable_storage_filter && !mouse_over_titlebar)
683 	{
684 		if(filter_item_text_size > 0)
685 		{
686 			static char tmp[50];
687 			safe_snprintf(tmp, sizeof(tmp), "%s[%s]", storage_filter_prompt_str, filter_item_text);
688 			show_help(tmp, 0, win->len_y + 10 + (help_text_line++) * win->small_font_len_y, win->current_scale);
689 		}
690 		else if (show_help_text && mouse_over_storage)
691 			show_help(storage_filter_help_str, 0, win->len_y + 10 + (help_text_line++) * win->small_font_len_y, win->current_scale);
692 	}
693 
694 	mouse_over_storage = mouse_over_titlebar = 0;
695 
696 #ifdef OPENGL_TRACE
697 CHECK_GL_ERRORS();
698 #endif //OPENGL_TRACE
699 
700 	return 1;
701 }
702 
click_storage_handler(window_info * win,int mx,int my,Uint32 flags)703 int click_storage_handler(window_info * win, int mx, int my, Uint32 flags)
704 {
705 	if(flags&ELW_WHEEL_UP) {
706 		if(mx>border_size && mx<cat_right_offset) {
707 			vscrollbar_scroll_up(win->window_id, STORAGE_SCROLLBAR_CATEGORIES);
708 		} else if(mx>item_left_offset && mx<item_right_offset){
709 			vscrollbar_scroll_up(win->window_id, STORAGE_SCROLLBAR_ITEMS);
710 		}
711 	} else if(flags&ELW_WHEEL_DOWN) {
712 		if(mx>border_size && mx<cat_right_offset) {
713 			vscrollbar_scroll_down(win->window_id, STORAGE_SCROLLBAR_CATEGORIES);
714 		} else if(mx>item_left_offset && mx<item_right_offset){
715 			vscrollbar_scroll_down(win->window_id, STORAGE_SCROLLBAR_ITEMS);
716 		}
717 	}
718 	else if ( (flags & ELW_MOUSE_BUTTON) == 0) {
719 		return 0;
720 	}
721 	else {
722 		if((my > cat_string_top_offset) && (my < (cat_string_top_offset + storage_categories_display * cat_name_separation))){
723 			if(mx>border_size && mx<cat_right_offset){
724 				int cat=-1;
725 				cat=(my - cat_string_left_offset) / cat_name_separation + vscrollbar_get_pos(win->window_id, STORAGE_SCROLLBAR_CATEGORIES);
726 				move_to_category(cat);
727 				do_click_sound();
728 			}
729 		}
730 		if ((my > border_size) && (my<bottom_offset) && (mx > item_grid_left_offset) && (mx < item_right_offset)) {
731 				if(view_only_storage && item_dragged!=-1 && left_click){
732 					drop_fail_time = SDL_GetTicks();
733 					do_alert1_sound();
734 				} else if(!view_only_storage && item_dragged!=-1 && left_click){
735 					Uint8 str[6];
736 
737 					str[0]=DEPOSITE_ITEM;
738 					str[1]=item_list[item_dragged].pos;
739 					*((Uint32*)(str+2))=SDL_SwapLE32(item_quantity);
740 
741 					my_tcp_send(my_socket, str, 6);
742 					do_drop_item_sound();
743 
744 					if(item_list[item_dragged].quantity<=item_quantity) item_dragged=-1;//Stop dragging this item...
745 				} else if(right_click || (view_only_storage && left_click)){
746 					storage_item_dragged=-1;
747 					item_dragged=-1;
748 
749 					if(cur_item_over!=-1) {
750 						Uint8 str[3];
751 
752 						str[0]=LOOK_AT_STORAGE_ITEM;
753 						*((Uint16*)(str+1))=SDL_SwapLE16(storage_items[cur_item_over].pos);
754 
755 						my_tcp_send(my_socket, str, 3);
756 
757 						active_storage_item=storage_items[cur_item_over].pos;
758 						do_click_sound();
759 					}
760 				} else if(!view_only_storage && cur_item_over!=-1){
761 					storage_item_dragged=cur_item_over;
762 					active_storage_item=storage_items[cur_item_over].pos;
763 					do_drag_item_sound();
764 				}
765 		}
766 	}
767 
768 	return 1;
769 }
770 
mouseover_storage_handler(window_info * win,int mx,int my)771 int mouseover_storage_handler(window_info *win, int mx, int my)
772 {
773 	static int last_pos;
774 	int last_category;
775 
776 	cur_item_over=-1;
777 
778 	if (my < 0)
779 		mouse_over_titlebar = 1;
780 	else
781 		mouse_over_storage = 1;
782 
783 	if((my > cat_string_top_offset) && (my < (cat_string_top_offset + storage_categories_display * cat_name_separation))){
784 		if(mx>border_size && mx<cat_right_offset){
785 			int i;
786 			int pos=last_pos=(my - cat_string_top_offset) / cat_name_separation;
787 			int p;
788 
789 			for(i=p=vscrollbar_get_pos(win->window_id, STORAGE_SCROLLBAR_CATEGORIES);i<no_storage_categories;i++){
790 				if(i==selected_category) {
791 				} else if(i!=p+pos) {
792 					storage_categories[i].name[0]  = to_color_char (c_orange1);
793 				} else {
794 					storage_categories[i].name[0] = to_color_char (c_green2);
795 				}
796 			}
797 
798 			return 0;
799 		}
800 	}
801 	if ((my > border_size) && (my<bottom_offset) && (mx > item_grid_left_offset) && (mx < item_right_offset)) {
802 		cur_item_over = get_mouse_pos_in_grid(mx, my, item_grid_size, item_grid_size, item_grid_left_offset, border_size, item_box_size, item_box_size)+vscrollbar_get_pos(win->window_id, STORAGE_SCROLLBAR_ITEMS)*item_grid_size;
803 		if(cur_item_over>=no_storage||cur_item_over<0||!storage_items[cur_item_over].quantity) cur_item_over=-1;
804 	}
805 
806 	last_category = last_pos+vscrollbar_get_pos(win->window_id,STORAGE_SCROLLBAR_CATEGORIES);
807 	if(last_pos>=0 && last_pos<storage_categories_display && last_category != selected_category) {
808 		storage_categories[last_category].name[0] = to_color_char (c_orange1);
809 		last_pos=-1;
810 	}
811 
812 	return 0;
813 }
814 
815 
keypress_storage_handler(window_info * win,int mx,int my,SDL_Keycode key_code,Uint32 key_unicode,Uint16 key_mod)816 static int keypress_storage_handler(window_info *win, int mx, int my, SDL_Keycode key_code, Uint32 key_unicode, Uint16 key_mod)
817 {
818 	if (disable_storage_filter || (key_unicode == '`') || (key_mod & KMOD_CTRL) || (key_mod & KMOD_ALT))
819 		return 0;
820 	if (key_code == SDLK_ESCAPE)
821 	{
822 		filter_item_text[0] = '\0';
823 		filter_item_text_size = 0;
824 		return 1;
825 	}
826 	item_info_help_if_needed();
827 	if (string_input(filter_item_text, sizeof(filter_item_text), key_code, key_unicode, key_mod))
828 	{
829 		filter_item_text_size = strlen(filter_item_text);
830 		if (filter_item_text_size > 0)
831 			filter_items_by_description(storage_items_filter, storage_items, filter_item_text, no_storage);
832 		return 1;
833 	}
834 	return 0;
835 }
836 
print_items(void)837 void print_items(void)
838 {
839 	int i;
840 	actor *me;
841 
842 	me = get_our_actor();
843 	if (me)
844 		if(me->fighting)
845 		{
846 			LOG_TO_CONSOLE(c_red1, "You can't do this during combat!");
847 			return;
848 		}
849 
850 	/* request the description for each item */
851 	number_to_print = next_item_to_print = 0;
852 	printing_category = selected_category;
853 	for (i = 0; i < no_storage && i < STORAGE_ITEMS_SIZE; i++)
854 	{
855 		if (storage_items[i].quantity)
856 		{
857 			Uint8 str[3];
858 			print_info[number_to_print].quantity = storage_items[i].quantity;
859 			print_info[number_to_print].id = storage_items[i].id;
860 			print_info[number_to_print].image_id = storage_items[i].image_id;
861 			number_to_print++;
862 			str[0]=LOOK_AT_STORAGE_ITEM;
863 			*((Uint16*)(str+1))=SDL_SwapLE16(storage_items[i].pos);
864 			my_tcp_send(my_socket, str, 3);
865 		}
866 	}
867 }
868 
context_storage_handler(window_info * win,int widget_id,int mx,int my,int option)869 static int context_storage_handler(window_info *win, int widget_id, int mx, int my, int option)
870 {
871 	if (option<ELW_CM_MENU_LEN)
872 		return cm_title_handler(win, widget_id, mx, my, option);
873 	switch (option)
874 	{
875 		case ELW_CM_MENU_LEN+1: print_items(); break;
876 		case ELW_CM_MENU_LEN+2: safe_strncpy(storage_text, reopen_storage_str, MAX_DESCR_LEN) ; break;
877 		case ELW_CM_MENU_LEN+3: move_to_category(selected_category); break;
878 	}
879 	return 1;
880 }
881 
display_storage_menu()882 void display_storage_menu()
883 {
884 	int storage_win = get_id_MW(MW_STORAGE);
885 	int i;
886 
887 	/* Entropy suggested hack to determine if this is the view only "#sto" opened storage */
888 	view_only_storage = 0;
889 	for (i = 0; i < no_storage_categories; i++)
890 	{
891 		if ((storage_categories[i].id != -1) && (strcmp(&storage_categories[i].name[1], "Quest") == 0))
892 		{
893 			view_only_storage = 1;
894 			break;
895 		}
896 	}
897 
898 	if(storage_win<=0){
899 		storage_win = create_window(win_storage, (not_on_top_now(MW_STORAGE) ?game_root_win : -1), 0,
900 			get_pos_x_MW(MW_STORAGE), get_pos_y_MW(MW_STORAGE), 0, 0, ELW_USE_UISCALE|ELW_WIN_DEFAULT|ELW_TITLE_NAME);
901 		set_id_MW(MW_STORAGE, storage_win);
902 		set_window_custom_scale(storage_win, MW_STORAGE);
903 		set_window_handler(storage_win, ELW_HANDLER_DISPLAY, &display_storage_handler);
904 		set_window_handler(storage_win, ELW_HANDLER_POST_DISPLAY, &post_display_storage_handler);
905 		set_window_handler(storage_win, ELW_HANDLER_CLICK, &click_storage_handler);
906 		set_window_handler(storage_win, ELW_HANDLER_MOUSEOVER, &mouseover_storage_handler);
907 		set_window_handler(storage_win, ELW_HANDLER_KEYPRESS, (int (*)())&keypress_storage_handler );
908 		set_window_handler(storage_win, ELW_HANDLER_UI_SCALE, &ui_scale_storage_handler );
909 		set_window_handler(storage_win, ELW_HANDLER_FONT_CHANGE, &change_storage_font_handler);
910 
911 		cat_scrollbar_id = vscrollbar_add_extended(storage_win, STORAGE_SCROLLBAR_CATEGORIES, NULL, 0, 0, 0, 0, 0, 1.0, 0, 1,
912 				max2i(no_storage_categories - storage_categories_display, 0));
913 		items_scrollbar_id = vscrollbar_add_extended(storage_win, STORAGE_SCROLLBAR_ITEMS, NULL, 0, 0, 0, 0, 0, 1.0, 0, 1, 0);
914 
915 		cm_add(windows_list.window[storage_win].cm_id, cm_storage_menu_str, context_storage_handler);
916 		cm_add(windows_list.window[storage_win].cm_id, cm_dialog_options_str, context_storage_handler);
917 		cm_bool_line(windows_list.window[storage_win].cm_id, ELW_CM_MENU_LEN+2, &sort_storage_categories, NULL);
918 		cm_bool_line(windows_list.window[storage_win].cm_id, ELW_CM_MENU_LEN+3, &sort_storage_items, NULL);
919 		cm_bool_line(windows_list.window[storage_win].cm_id, ELW_CM_MENU_LEN+4, &disable_storage_filter, NULL);
920 		cm_bool_line(windows_list.window[storage_win].cm_id, ELW_CM_MENU_LEN+5, &autoclose_storage_dialogue, NULL);
921 		cm_bool_line(windows_list.window[storage_win].cm_id, ELW_CM_MENU_LEN+6, &auto_select_storage_option, NULL);
922 	} else {
923 		no_storage=0;
924 
925 		for(i = 0; i < no_storage_categories; i++)
926 			storage_categories[i].name[0] = to_color_char (c_orange1);
927 
928 		show_window(storage_win);
929 		select_window(storage_win);
930 
931 		vscrollbar_set_pos(storage_win, STORAGE_SCROLLBAR_CATEGORIES, 0);
932 		vscrollbar_set_pos(storage_win, STORAGE_SCROLLBAR_ITEMS, 0);
933 	}
934 
935 	cur_item_over = -1;
936 	storage_text[0] = '\0';
937 	set_window_name("", "");
938 
939 	ui_scale_storage_handler(&windows_list.window[storage_win]);
940 	check_proportional_move(MW_STORAGE);
941 }
942 
close_storagewin()943 void close_storagewin()
944 {
945 	if(!view_only_storage)
946 		hide_window_MW(MW_STORAGE);
947 }
948