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