1 #include <stdlib.h>
2 #include <string.h>
3 #include <math.h>
4 #include <limits.h>
5 #include "items.h"
6 #include "asc.h"
7 #include "colors.h"
8 #include "client_serv.h"
9 #include "cursors.h"
10 #include "context_menu.h"
11 #include "text.h"
12 #include "elconfig.h"
13 #include "elwindows.h"
14 #include "errors.h"
15 #include "gamewin.h"
16 #include "gl_init.h"
17 #include "hud.h"
18 #include "init.h"
19 #include "interface.h"
20 #include "item_info.h"
21 #include "item_lists.h"
22 #include "manufacture.h"
23 #include "misc.h"
24 #include "multiplayer.h"
25 #include "platform.h"
26 #include "sound.h"
27 #include "storage.h"
28 #include "textures.h"
29 #include "translate.h"
30 #include "counters.h"
31 #include "widgets.h"
32 #include "spells.h"
33
34 item item_list[ITEM_NUM_ITEMS];
35 item_extra item_list_extra[ITEM_NUM_ITEMS];
36
37 struct quantities quantities = {
38 0,
39 {
40 {1, 1, "1"},
41 {5, 1, "5"},
42 {10, 2, "10"},
43 {20, 2, "20"},
44 {50, 2, "50"},
45 {100, 3, "100"},
46 {1, 1, "1"}, // item list preview quantity - not editable or displayed with others
47 }
48 };
49 int edit_quantity=-1;
50
51 static int item_action_mode = ACTION_WALK;
52
53 int item_dragged=-1;
54 int item_quantity=1;
55 int use_item=-1;
56 int item_uid_enabled = 0;
57 const Uint16 unset_item_uid = (Uint16)-1;
58 int items_text[MAX_ITEMS_TEXTURES];
59 int independant_inventory_action_modes = 0;
60
61 /* title menu options */
62 int allow_equip_swap=0;
63 int use_small_items_window = 0;
64 int manual_size_items_window = 0;
65 int items_mod_click_any_cursor = 1;
66 int items_disable_text_block = 0;
67 int items_buttons_on_left = 0;
68 int items_equip_grid_on_left = 0;
69
70 /* button options */
71 int items_mix_but_all = 0;
72 int items_stoall_nofirstrow = 0;
73 int items_stoall_nolastrow = 0;
74 int items_dropall_nofirstrow = 0;
75 int items_dropall_nolastrow = 0;
76 int items_list_on_left = 0;
77
78 /* use standard way to size and position the window components */
79 struct win_component {int pos_x; int pos_y; int len_x; int len_y; int mouse_over; int rows; int cols; int width; int height; };
80 static struct win_component items_grid = {0,0,0,0,-1,0,0,0,0};
81 static struct win_component equip_grid = {0,0,0,0,-1,0,0,0,0};
82 static struct win_component buttons_grid = {0,0,0,0,-1,0,0,0,0};
83 static struct win_component text_arrow = {0,0,0,0,-1,0,0,0,0};
84 static struct win_component unequip_arrow = {0,0,0,0,-1,0,0,0,0};
85 static struct win_component message_box = {0,0,0,0,-1,0,0,0,0};
86 static struct win_component labels_box = {0,0,0,0,-1,0,0,0,0};
87 static struct win_component quantity_grid = {0,0,0,0,-1,0,0,0,0};
88
89 static char items_string[350] = {0};
90 static size_t last_items_string_id = 0;
91 static const char *item_help_str = NULL;
92 static const char *item_desc_str = NULL;
93 static float button_text_zoom = 0.0f;
94
95 #define NUMBUT 5
96 static size_t buttons_cm_id[NUMBUT] = {CM_INIT_VALUE, CM_INIT_VALUE, CM_INIT_VALUE, CM_INIT_VALUE, CM_INIT_VALUE};
97 enum { BUT_STORE, BUT_GET, BUT_DROP, BUT_MIX, BUT_ITEM_LIST };
98
99 /* variables to enable enhanced equipment swapping */
100 static struct { int last_dest; int move_to; int move_from; size_t string_id; Uint32 start_time; } swap_complete = {-1, -1, -1, 0, 0};
101
102 static int show_items_handler(window_info * win);
103 static void drop_all_handler(void);
104
105 // Limit external setting of the action mode: Called due to an action keypress or action icon in the icon window.
set_items_action_mode(int new_mode)106 void set_items_action_mode(int new_mode)
107 {
108 // Only change the action mode if is one used by the window.
109 if (!independant_inventory_action_modes && ((new_mode == ACTION_WALK) || (new_mode == ACTION_LOOK) || (new_mode == ACTION_USE) || (new_mode == ACTION_USE_WITEM)))
110 item_action_mode = new_mode;
111 }
112
set_shown_string(char colour_code,const char * the_text)113 void set_shown_string(char colour_code, const char *the_text)
114 {
115 if (strlen(the_text) == 0)
116 {
117 inventory_item_string[0] = '\0';
118 inventory_item_string_id++;
119 return;
120 }
121 inventory_item_string[0] = to_color_char(colour_code);
122 safe_strncpy2(inventory_item_string+1, the_text, sizeof(inventory_item_string)-2, strlen(the_text));
123 inventory_item_string[sizeof(inventory_item_string)-1] = 0;
124 inventory_item_string_id++;
125 }
126
127
128 /* return index of button or -1 if mouse not over a button */
over_button(window_info * win,int mx,int my)129 static int over_button(window_info *win, int mx, int my)
130 {
131 if ((mx > buttons_grid.pos_x) && (mx < buttons_grid.pos_x + buttons_grid.len_x) &&
132 (my > buttons_grid.pos_y) && (my < buttons_grid.pos_y + buttons_grid.len_y)) {
133 return (my - buttons_grid.pos_y) / buttons_grid.height;
134 }
135 return -1;
136 }
137
138
gray_out(int x_start,int y_start,int gridsize)139 void gray_out(int x_start, int y_start, int gridsize){
140
141 glDisable(GL_TEXTURE_2D);
142 glEnable(GL_BLEND);
143 //glBlendFunc(GL_DST_COLOR, GL_ONE); //this brightens up
144 glBlendFunc(GL_ZERO, GL_SRC_COLOR); //this brightens down
145 glColor3f(0.4f, 0.2f, 0.2f);
146 glBegin(GL_QUADS);
147 glVertex3i(x_start,y_start,0);
148 glVertex3i(x_start+gridsize,y_start,0);
149 glVertex3i(x_start+gridsize,y_start+gridsize,0);
150 glVertex3i(x_start,y_start+gridsize,0);
151 glEnd();
152 glDisable(GL_BLEND);
153 glEnable(GL_TEXTURE_2D);
154 glColor3f(1.0f, 1.0f, 1.0f);
155 }
156
157
rendergrid(int columns,int rows,int left,int top,int width,int height)158 void rendergrid(int columns, int rows, int left, int top, int width, int height)
159 {
160 int x, y;
161 int temp;
162
163 glBegin(GL_LINES);
164
165 for(y=0; y<=rows; y++){
166 temp = top + y * height;
167 glVertex2i(left, temp);
168 glVertex2i(left + width*columns, temp);
169 }
170
171 for(x=0; x<columns+1; x++){
172 temp = left + x * width;
173 glVertex2i(temp, top);
174 glVertex2i(temp, top + height*rows);
175 }
176
177 glEnd();
178 }
179
get_mouse_pos_in_grid(int mx,int my,int columns,int rows,int left,int top,int width,int height)180 int get_mouse_pos_in_grid(int mx, int my, int columns, int rows, int left, int top, int width, int height)
181 {
182 int x, y, i;
183
184 mx -= left;
185 my -= top;
186
187 i = 0;
188 for (y = 0; y < rows; y++)
189 {
190 for (x = 0; x < columns; x++, i++)
191 {
192 if (mx >= x*width && mx <= (x+1)*width && my >= y*height && my <= (y+1)*height)
193 return i;
194 }
195 }
196
197 return -1;
198 }
199
reset_quantity(int pos)200 void reset_quantity (int pos)
201 {
202 int val;
203
204 switch(pos)
205 {
206 case 0:
207 val = 1;
208 break;
209 case 1:
210 val = 5;
211 break;
212 case 2:
213 val = 10;
214 break;
215 case 3:
216 val = 20;
217 break;
218 case 4:
219 val = 50;
220 break;
221 case 5:
222 val = 100;
223 break;
224 default:
225 LOG_ERROR ("Trying to reset invalid element of quantities, pos = %d", pos);
226 return;
227 }
228
229 safe_snprintf (quantities.quantity[pos].str, sizeof(quantities.quantity[pos].str), "%d", val);
230 quantities.quantity[pos].len = strlen (quantities.quantity[pos].str);
231 quantities.quantity[pos].val = val;
232 }
233
get_item_uv(const Uint32 item,float * u_start,float * v_start,float * u_end,float * v_end)234 void get_item_uv(const Uint32 item, float* u_start, float* v_start,
235 float* u_end, float* v_end)
236 {
237 *u_start = (50.0f/256.0f) * (item % 5) + 0.5f / 256.0f;
238 *u_end = *u_start + (50.0f/256.0f);
239 *v_start = (50.0f/256.0f) * (item / 5) + 0.5f / 256.0f;
240 *v_end = *v_start + (50.0f/256.0f);
241 }
242
drag_item(int item,int storage,int mini)243 void drag_item(int item, int storage, int mini)
244 {
245 float u_start,v_start,u_end,v_end;
246 int cur_item,this_texture;
247 int cur_item_img;
248 int my_items_grid_size = (int)(0.5 + get_global_scale() * ((use_small_items_window) ?33: 50));
249 int offset = (mini) ? my_items_grid_size/3 : my_items_grid_size/2;
250
251 int quantity=item_quantity;
252
253 if(storage) {
254 if (item < 0 || item >= STORAGE_ITEMS_SIZE)
255 // oops
256 return;
257
258 cur_item=storage_items[item].image_id;
259 if(!storage_items[item].quantity) {
260 use_item = storage_item_dragged=-1;
261 return;
262 }
263 if (quantity > storage_items[item].quantity)
264 quantity = storage_items[item].quantity;
265 } else {
266 if (item < 0 || item >= ITEM_NUM_ITEMS)
267 // oops
268 return;
269
270 cur_item=item_list[item].image_id;
271 if(!item_list[item].quantity) {
272 use_item = item_dragged=-1;
273 return;
274 }
275 if (item >= ITEM_WEAR_START) {
276 quantity = -1;
277 } else if (item_list[item].is_stackable) {
278 if(quantity > item_list[item].quantity)
279 quantity = item_list[item].quantity;
280 // The quantity for non-stackable items is misleading so don't show it unless we can reliably count how many we have.
281 } else if (item_list[item].id == unset_item_uid) {
282 quantity = -1;
283 } else {
284 size_t i;
285 int count = 0;
286 for (i = 0; i < ITEM_WEAR_START; i++)
287 if((item_list[i].quantity > 0) && (item_list[item].image_id == item_list[i].image_id) && (item_list[item].id == item_list[i].id))
288 count++;
289 if (quantity > count)
290 quantity = count;
291 }
292 }
293
294 cur_item_img=cur_item%25;
295 get_item_uv(cur_item_img, &u_start, &v_start, &u_end, &v_end);
296
297 //get the texture this item belongs to
298 this_texture=get_items_texture(cur_item/25);
299
300 bind_texture(this_texture);
301 glBegin(GL_QUADS);
302 draw_2d_thing(u_start, v_start, u_end, v_end, mouse_x - offset, mouse_y - offset, mouse_x + offset, mouse_y + offset);
303 glEnd();
304
305 if (!mini && quantity != -1)
306 {
307 int text_height = get_line_height(UI_FONT, get_global_scale() * DEFAULT_SMALL_RATIO);
308 unsigned char str[20];
309 safe_snprintf((char*)str, sizeof(str), "%d", quantity);
310 draw_string_small_zoomed_centered(mouse_x, mouse_y - offset - text_height,
311 str, 1, get_global_scale());
312 }
313 }
314
get_your_items(const Uint8 * data)315 void get_your_items (const Uint8 *data)
316 {
317 int i,total_items,pos,len;
318 Uint8 flags;
319
320 if (item_uid_enabled)
321 len=10;
322 else
323 len=8;
324
325 //data[0] -> num_items
326 //data[1] -> image_id
327 //data[3] -> quantity
328 //data[7] -> pos
329 //data[8] -> flags
330 //data[9] -> id
331
332
333 total_items=data[0];
334
335 //clear the items first
336 for(i=0;i<ITEM_NUM_ITEMS;i++){
337 item_list[i].quantity=0;
338 item_list_extra[i].slot_busy_start = 0;
339 }
340
341 for(i=0;i<total_items;i++){
342 pos=data[i*len+1+6];
343 // try not to wipe out cooldown information if no real change
344 if(item_list[pos].image_id != SDL_SwapLE16(*((Uint16 *)(data+i*len+1))) ){
345 item_list[pos].cooldown_time = 0;
346 item_list[pos].cooldown_rate = 1;
347 }
348 item_list[pos].image_id=SDL_SwapLE16(*((Uint16 *)(data+i*len+1)));
349 item_list[pos].quantity=SDL_SwapLE32(*((Uint32 *)(data+i*len+1+2)));
350 item_list[pos].pos=pos;
351 #ifdef NEW_SOUND
352 item_list[pos].action = ITEM_NO_ACTION;
353 item_list[pos].action_time = 0;
354 #endif // NEW_SOUND
355 flags=data[i*len+1+7];
356 if (item_uid_enabled)
357 item_list[pos].id=SDL_SwapLE16(*((Uint16 *)(data+i*len+1+8)));
358 else
359 item_list[pos].id=unset_item_uid;
360 item_list[pos].is_resource=((flags&ITEM_RESOURCE)>0);
361 item_list[pos].is_reagent=((flags&ITEM_REAGENT)>0);
362 item_list[pos].use_with_inventory=((flags&ITEM_INVENTORY_USABLE)>0);
363 item_list[pos].is_stackable=((flags&ITEM_STACKABLE)>0);
364 }
365
366 build_manufacture_list();
367 check_castability();
368 }
369
370 #ifdef NEW_SOUND
check_for_item_sound(int pos)371 void check_for_item_sound(int pos)
372 {
373 int i, snd = -1;
374
375 #ifdef _EXTRA_SOUND_DEBUG
376 // printf("Used item: %d, Image ID: %d, Action: %d\n", pos, item_list[pos].image_id, item_list[pos].action);
377 #endif // _EXTRA_SOUND_DEBUG
378 if (item_list[pos].action != ITEM_NO_ACTION)
379 {
380 // Play the sound that goes with this action
381 switch (item_list[pos].action)
382 {
383 case USE_INVENTORY_ITEM:
384 snd = get_index_for_inv_use_item_sound(item_list[pos].image_id);
385 break;
386 case ITEM_ON_ITEM:
387 // Find the second item (being used with)
388 for (i = 0; i < ITEM_NUM_ITEMS; i++)
389 {
390 if (i != pos && item_list[i].action == ITEM_ON_ITEM)
391 {
392 snd = get_index_for_inv_usewith_item_sound(item_list[pos].image_id, item_list[i].action);
393 break;
394 }
395 }
396 break;
397 }
398 if (snd > -1)
399 add_sound_object(snd, 0, 0, 1);
400 // Reset the action
401 item_list[pos].action = ITEM_NO_ACTION;
402 item_list[pos].action_time = 0;
403 }
404 }
405
update_item_sound(int interval)406 void update_item_sound(int interval)
407 {
408 int i;
409 // Iterate through the list of items, checking for out of date item actions (> 2 sec old)
410 for (i = 0; i < ITEM_NUM_ITEMS; i++)
411 {
412 if (item_list[i].action != ITEM_NO_ACTION)
413 {
414 item_list[i].action_time += interval;
415 if (item_list[i].action_time >= 2000)
416 {
417 // Item action state is out of date so reset it
418 item_list[i].action = ITEM_NO_ACTION;
419 item_list[i].action_time = 0;
420 }
421 }
422 }
423 }
424 #endif // NEW_SOUND
425
426 static int used_item_counter_initialised = 0;
427 static int used_item_counter_queue[ITEM_NUM_ITEMS];
428 static Uint32 used_item_counter_queue_time[ITEM_NUM_ITEMS];
429
used_item_counter_init(void)430 void used_item_counter_init(void)
431 {
432 size_t i;
433 for (i=0; i<ITEM_NUM_ITEMS; i++)
434 {
435 used_item_counter_queue[i] = 0;
436 used_item_counter_queue_time[i] = 0;
437 }
438 used_item_counter_initialised = 1;
439 //printf("Used item counter code initialised\n");
440 }
441
used_item_counter_timer(void)442 void used_item_counter_timer(void)
443 {
444 if (!used_item_counter_initialised)
445 used_item_counter_init();
446 else
447 {
448 size_t i;
449 for (i=0; i<ITEM_NUM_ITEMS; i++)
450 {
451 /* The timeout value is need in the absence of a server change that would give feedback to
452 use actions. Too short, and we will miss a valid counter event due to server lag. Too
453 long, and we will interpret a single dropped item as use of an item that has actually
454 failed. Hopefully, the server lag will not be as high as the timeout, and a player will
455 not switch from failed ACTION_USE to dropping an item in less than the timeout. */
456 if (used_item_counter_queue_time[i] && (SDL_GetTicks() - used_item_counter_queue_time[i]) > 1000u)
457 {
458 used_item_counter_queue[i] = 0;
459 used_item_counter_queue_time[i] = 0;
460 //printf("Used item counter pos %lu, confirmation timed out\n", i);
461 }
462 }
463 }
464 }
465
used_item_counter_action_use(int pos)466 void used_item_counter_action_use(int pos)
467 {
468 if (!used_item_counter_initialised)
469 used_item_counter_init();
470 if ((pos < 0) || !(pos < ITEM_NUM_ITEMS))
471 return;
472 used_item_counter_queue[pos]++;
473 used_item_counter_queue_time[pos] = SDL_GetTicks();
474 //printf("Used item counter pos %d, waiting for confirmation pending %d\n", pos, used_item_counter_queue[pos]);
475 }
476
477
used_item_counter_check_confirmation(int pos,int new_quanity)478 static void used_item_counter_check_confirmation(int pos, int new_quanity)
479 {
480 if (!used_item_counter_initialised)
481 used_item_counter_init();
482 if ((pos < 0) || !(pos < ITEM_NUM_ITEMS))
483 return;
484 if (used_item_counter_queue[pos])
485 {
486 if ((item_list[pos].quantity > 0) && (new_quanity < item_list[pos].quantity))
487 {
488 static int sent_unique_message = 0;
489 static int sent_get_failed_message = 0;
490 int item_count = get_item_count(item_list[pos].id, item_list[pos].image_id);
491 used_item_counter_queue[pos]--;
492 if (!used_item_counter_queue[pos])
493 used_item_counter_queue_time[pos] = 0;
494 if (item_count == 1)
495 increment_used_item_counter(get_basic_item_description(item_list[pos].id, item_list[pos].image_id), item_list[pos].quantity - new_quanity);
496 else if ((item_count > 1) && !sent_unique_message)
497 {
498 LOG_TO_CONSOLE(c_red1, item_use_not_unique_str);
499 LOG_TO_CONSOLE(c_red1, item_uid_help_str);
500 sent_unique_message = 1;
501 }
502 else if ((item_count < 1) && !sent_get_failed_message)
503 {
504 char str[256];
505 safe_snprintf(str, sizeof(str), "%s id=%d image_id=%d", item_use_get_failed_str, item_list[pos].id, item_list[pos].image_id);
506 LOG_TO_CONSOLE(c_red1, str);
507 sent_get_failed_message = 1;
508 }
509 //printf("Used item counter confirmed pos %d - item removed [%s] quanity %d\n", pos, get_item_description(item_list[pos].id, item_list[pos].image_id), item_list[pos].quantity - new_quanity);
510 }
511 //else
512 // printf("Used item counter pos %d issue with quanity\n", pos);
513 }
514 //else
515 // printf("Used item counter pos %d - not due to use action\n", pos);
516 }
517
remove_item_from_inventory(int pos)518 void remove_item_from_inventory(int pos)
519 {
520 used_item_counter_check_confirmation(pos, 0);
521 item_list[pos].quantity=0;
522
523 if (pos == swap_complete.move_from)
524 swap_complete.move_to = swap_complete.move_from = -1;
525
526 #ifdef NEW_SOUND
527 check_for_item_sound(pos);
528 #endif // NEW_SOUND
529
530 build_manufacture_list();
531 check_castability();
532 }
533
get_new_inventory_item(const Uint8 * data)534 void get_new_inventory_item (const Uint8 *data)
535 {
536 int pos;
537 Uint8 flags;
538 int quantity;
539 int image_id;
540 Uint16 id;
541
542 if (item_uid_enabled)
543 id=SDL_SwapLE16(*((Uint16 *)(data+8)));
544 else
545 id=unset_item_uid;
546
547 pos= data[6];
548 flags= data[7];
549 image_id=SDL_SwapLE16(*((Uint16 *)(data)));
550 quantity=SDL_SwapLE32(*((Uint32 *)(data+2)));
551
552 used_item_counter_check_confirmation(pos, quantity);
553 if (now_harvesting() && (quantity >= item_list[pos].quantity) ) { //some harvests, eg hydrogenium and wolfram, also decrease an item number. only count what goes up
554 increment_harvest_counter(item_list[pos].quantity > 0 ? quantity - item_list[pos].quantity : quantity);
555 }
556
557 // don't touch cool down when it's already active
558 if(item_list[pos].quantity == 0 || item_list[pos].image_id != image_id){
559 item_list[pos].cooldown_time = 0;
560 item_list[pos].cooldown_rate = 1;
561 }
562 item_list[pos].quantity=quantity;
563 item_list[pos].image_id=image_id;
564 item_list[pos].pos=pos;
565 item_list[pos].id=id;
566 item_list[pos].is_resource=((flags&ITEM_RESOURCE)>0);
567 item_list[pos].is_reagent=((flags&ITEM_REAGENT)>0);
568 item_list[pos].use_with_inventory=((flags&ITEM_INVENTORY_USABLE)>0);
569 item_list[pos].is_stackable=((flags&ITEM_STACKABLE)>0);
570
571 #ifdef NEW_SOUND
572 check_for_item_sound(pos);
573 #endif // NEW_SOUND
574
575 build_manufacture_list();
576 check_castability();
577
578 // if we can, complete a swap of equipment by moving the removed item to the slot left by the new
579 if (pos == swap_complete.move_to)
580 {
581 if (item_list[swap_complete.move_from].quantity)
582 {
583 if (!move_item(swap_complete.move_from, swap_complete.move_to, -1))
584 swap_complete.move_from = swap_complete.move_to = -1;
585 }
586 else
587 swap_complete.move_from = swap_complete.move_to = -1;
588 }
589 }
590
591
592
draw_item(int id,int x_start,int y_start,int gridsize)593 void draw_item(int id, int x_start, int y_start, int gridsize){
594 float u_start,v_start,u_end,v_end;
595 int cur_item;
596 int this_texture;
597
598 //get the UV coordinates.
599 cur_item=id%25;
600 get_item_uv(cur_item, &u_start, &v_start, &u_end, &v_end);
601
602 //get the texture this item belongs to
603 this_texture=get_items_texture(id/25);
604
605 bind_texture(this_texture);
606 glBegin(GL_QUADS);
607 draw_2d_thing(u_start,v_start,u_end,v_end,x_start,y_start,x_start+gridsize-1,y_start+gridsize-1);
608 glEnd();
609 }
610
display_items_handler(window_info * win)611 static int display_items_handler(window_info *win)
612 {
613 char str[80];
614 char my_str[10];
615 int x,y,i;
616 int item_is_weared=0;
617 Uint32 _cur_time = SDL_GetTicks(); /* grab a snapshot of current time */
618 char *but_labels[NUMBUT] = { sto_all_str, get_all_str, drp_all_str, NULL, itm_lst_str };
619
620 glEnable(GL_TEXTURE_2D);
621
622 check_for_swap_completion();
623
624 /*
625 * Labrat: I never realised that a store all patch had been posted to Berlios by Awn in February '07
626 * Thanks to Awn for his earlier efforts (but this is not a derivative of his earlier work)
627 *
628 *My next step will be to code an #ifdef STORE_ALL section to save the 0-35 loop in the click handler for future proofing
629 * ready for server side implementation
630 */
631 // draw the button labels
632 but_labels[BUT_MIX] = (items_mix_but_all) ?mix_all_str :mix_one_str;
633 for (i=0; i<NUMBUT; i++) {
634 strap_word(but_labels[i],my_str);
635 glColor3fv(gui_color);
636 draw_text(buttons_grid.pos_x + buttons_grid.width/2,
637 buttons_grid.pos_y + buttons_grid.height * i + buttons_grid.height/2,
638 (const unsigned char*)my_str, strlen(my_str), win->font_category,
639 TDO_ZOOM, button_text_zoom, TDO_ALIGNMENT, CENTER, TDO_VERTICAL_ALIGNMENT, CENTER_LINE,
640 TDO_END);
641 }
642
643 x = quantity_grid.pos_x + quantity_grid.width / 2;
644 y = quantity_grid.pos_y + quantity_grid.height / 2;
645 for(i = 0; i < ITEM_EDIT_QUANT; x += quantity_grid.width, ++i){
646 if(i==edit_quantity){
647 glColor3f(1.0f, 0.0f, 0.3f);
648 } else if(i==quantities.selected){
649 glColor3f(0.0f, 1.0f, 0.3f);
650 } else {
651 glColor3f(0.3f,0.5f,1.0f);
652 }
653 draw_text(x, y, (const unsigned char*)quantities.quantity[i].str,
654 strlen(quantities.quantity[i].str), win->font_category, TDO_ZOOM, win->current_scale_small,
655 TDO_ALIGNMENT, CENTER, TDO_VERTICAL_ALIGNMENT, CENTER_DIGITS, TDO_END);
656 }
657 glColor3f(0.3f,0.5f,1.0f);
658 draw_string_small_zoomed_right(labels_box.pos_x + labels_box.len_x, labels_box.pos_y,
659 (const unsigned char*)quantity_str, 1, win->current_scale);
660
661 glColor3f(0.57f,0.67f,0.49f);
662 draw_text(equip_grid.pos_x + equip_grid.len_x / 2, equip_grid.pos_y, (const unsigned char*)equip_str,
663 strlen(equip_str), win->font_category, TDO_MAX_WIDTH, equip_grid.len_x,
664 TDO_ZOOM, win->current_scale_small, TDO_SHRINK_TO_FIT, 1, TDO_ALIGNMENT, CENTER,
665 TDO_VERTICAL_ALIGNMENT, BOTTOM_LINE, TDO_END);
666
667 glColor3f(1.0f,1.0f,1.0f);
668 //ok, now let's draw the objects...
669 for(i=ITEM_NUM_ITEMS-1;i>=0;i--){
670 if(item_list[i].quantity){
671 int cur_pos;
672 int x_start,x_end,y_start,y_end;
673
674 // don't display an item that is in the proces of being moved after equipment swap
675 if (item_swap_in_progress(i))
676 continue;
677
678 //get the x and y
679 cur_pos=i;
680 if(cur_pos>=ITEM_WEAR_START){//the items we 'wear' are smaller
681 cur_pos-=ITEM_WEAR_START;
682 item_is_weared=1;
683 x_start = equip_grid.pos_x + equip_grid.width * (cur_pos % equip_grid.cols) + 1;
684 x_end = x_start + equip_grid.width - 1;
685 y_start = equip_grid.pos_y + equip_grid.height * (cur_pos / equip_grid.cols);
686 y_end = y_start + equip_grid.height - 1;
687 draw_item(item_list[i].image_id, x_start, y_start, equip_grid.width - 1);
688 } else {
689 item_is_weared=0;
690 x_start = items_grid.pos_x + items_grid.width * (cur_pos % items_grid.cols) +1;
691 x_end = x_start + items_grid.width - 1;
692 y_start = items_grid.pos_y + items_grid.height * (cur_pos / items_grid.cols);
693 y_end = y_start + items_grid.height - 1;
694 draw_item(item_list[i].image_id, x_start, y_start, items_grid.width - 1);
695 }
696 if ((_cur_time - item_list_extra[i].slot_busy_start) < 250)
697 gray_out(x_start, y_start, items_grid.width);
698
699 if (item_list[i].cooldown_time > _cur_time)
700 {
701 float cooldown = ((float)(item_list[i].cooldown_time - _cur_time)) / ((float)item_list[i].cooldown_rate);
702 float x_center = (x_start + x_end)*0.5f;
703 float y_center = (y_start + y_end)*0.5f;
704 float flash_effect_offset = 0.0f;
705
706 if (cooldown < 0.0f)
707 cooldown = 0.0f;
708 else if (cooldown > 1.0f)
709 cooldown = 1.0f;
710
711 glDisable(GL_TEXTURE_2D);
712 glEnable(GL_BLEND);
713
714 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
715 glBegin(GL_TRIANGLE_FAN);
716 if (cooldown < 1.0f)
717 flash_effect_offset = sin(pow(1.0f - cooldown, 4.0f) * 2.0f * M_PI * 30.0);
718 glColor4f(0.14f - flash_effect_offset / 20.0f, 0.35f - flash_effect_offset / 20.0f, 0.82f + flash_effect_offset / 8.0f, 0.48f + flash_effect_offset / 15.0f);
719
720 glVertex2f(x_center, y_center);
721
722 if (cooldown >= 0.875f) {
723 float t = tan(2.0f*M_PI*(1.0f - cooldown));
724 glVertex2f(t*x_end + (1.0f - t)*x_center, y_start);
725 glVertex2f(x_end, y_start);
726 glVertex2f(x_end, y_end);
727 glVertex2f(x_start, y_end);
728 glVertex2f(x_start, y_start);
729 } else if (cooldown >= 0.625f) {
730 float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.75f - cooldown));
731 glVertex2f(x_end, t*y_end + (1.0f - t)*y_start);
732 glVertex2f(x_end, y_end);
733 glVertex2f(x_start, y_end);
734 glVertex2f(x_start, y_start);
735 } else if (cooldown >= 0.375f) {
736 float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.5f - cooldown));
737 glVertex2f(t*x_start + (1.0f - t)*x_end, y_end);
738 glVertex2f(x_start, y_end);
739 glVertex2f(x_start, y_start);
740 } else if (cooldown >= 0.125f) {
741 float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.25f - cooldown));
742 glVertex2f(x_start, t*y_start + (1.0f - t)*y_end);
743 glVertex2f(x_start, y_start);
744 } else {
745 float t = tan(2.0f*M_PI*(cooldown));
746 glVertex2f(t*x_start + (1.0f - t)*x_center, y_start);
747 }
748
749 glVertex2f(x_center, y_start);
750 glEnd();
751
752 glDisable(GL_BLEND);
753 glEnable(GL_TEXTURE_2D);
754 }
755
756 if(!item_is_weared){
757 int use_large = (items_grid.mouse_over == i) && enlarge_text();
758 safe_snprintf(str, sizeof(str), "%i", item_list[i].quantity);
759 y_end -= (i & 1) ?items_grid.height - 1 : ((use_large) ?win->default_font_len_y :win->small_font_len_y);
760 if (use_large)
761 draw_string_shadowed_zoomed(x_start, y_end, (unsigned char*)str, 1,1.0f,1.0f,1.0f, 0.0f, 0.0f, 0.0f, win->current_scale);
762 else
763 draw_string_small_shadowed_zoomed(x_start, y_end, (unsigned char*)str, 1,1.0f,1.0f,1.0f, 0.0f, 0.0f, 0.0f, win->current_scale);
764 }
765 }
766 }
767 items_grid.mouse_over = -1;
768
769 glColor3f(1.0f,1.0f,1.0f);
770
771 //draw the load string
772 safe_snprintf(str, sizeof(str), "%s: %i/%i", attributes.carry_capacity.shortname, your_info.carry_capacity.cur, your_info.carry_capacity.base);
773 draw_string_small_zoomed(labels_box.pos_x, labels_box.pos_y, (unsigned char*)str, 1, win->current_scale);
774
775 //now, draw the inventory text, if any.
776 if (!items_disable_text_block)
777 {
778 if (last_items_string_id != inventory_item_string_id)
779 {
780 put_small_text_in_box_zoomed((const unsigned char*)inventory_item_string, strlen(inventory_item_string), message_box.len_x,
781 (unsigned char*)items_string, win->current_scale);
782 last_items_string_id = inventory_item_string_id;
783 }
784 draw_string_small_zoomed(message_box.pos_x, message_box.pos_y, (unsigned char*)items_string, message_box.rows, win->current_scale);
785 }
786
787 glDisable(GL_TEXTURE_2D);
788
789 if (text_arrow.mouse_over != -1)
790 glColor3fv(gui_bright_color);
791 else
792 glColor3fv(gui_color);
793 text_arrow.mouse_over = -1;
794 if (items_disable_text_block)
795 {
796 glBegin(GL_LINES); /* Dn arrow */
797 glVertex3i(text_arrow.pos_x, text_arrow.pos_y - text_arrow.len_y, 0);
798 glVertex3i(text_arrow.pos_x + text_arrow.len_x/2, text_arrow.pos_y, 0);
799 glVertex3i(text_arrow.pos_x + text_arrow.len_x/2, text_arrow.pos_y, 0);
800 glVertex3i(text_arrow.pos_x + text_arrow.len_x, text_arrow.pos_y - text_arrow.len_y, 0);
801 glEnd();
802 // if we have a coloured message, draw a small dot at the top of the arrow to indicate so, using the colour of the message
803 if ((strlen(inventory_item_string) > 0) && is_color(inventory_item_string[0]))
804 {
805 int colour = from_color_char (inventory_item_string[0]);
806 if ((colour >= c_lbound) && (colour <= c_ubound))
807 {
808 glColor4f((float) colors_list[colour].r1 / 255.0f, (float) colors_list[colour].g1 / 255.0f, (float) colors_list[colour].b1 / 255.0f, 1.0f);
809 glEnable( GL_POINT_SMOOTH );
810 glEnable( GL_BLEND );
811 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
812 glPointSize(text_arrow.len_x/3);
813 glBegin(GL_POINTS);
814 glVertex2f(text_arrow.pos_x + text_arrow.len_x/2, text_arrow.pos_y - text_arrow.len_y + text_arrow.len_y/6);
815 glEnd();
816 glDisable(GL_BLEND);
817 glDisable(GL_POINT_SMOOTH);
818 }
819 }
820 }
821 else
822 {
823 glBegin(GL_LINES); /* Up arrow */
824 glVertex3i(text_arrow.pos_x, text_arrow.pos_y, 0);
825 glVertex3i(text_arrow.pos_x + text_arrow.len_x/2, text_arrow.pos_y - text_arrow.len_y, 0);
826 glVertex3i(text_arrow.pos_x + text_arrow.len_x/2, text_arrow.pos_y - text_arrow.len_y, 0);
827 glVertex3i(text_arrow.pos_x + text_arrow.len_x, text_arrow.pos_y, 0);
828 glEnd();
829 }
830
831 if (unequip_arrow.mouse_over != -1)
832 glColor3fv(gui_bright_color);
833 else
834 glColor3fv(gui_color);
835 unequip_arrow.mouse_over = -1;
836 if (items_equip_grid_on_left)
837 {
838 int arrow_width = (disable_double_click) ?unequip_arrow.len_x : unequip_arrow.len_x/2;
839 glBegin(GL_LINES); /* right arrow */
840 glVertex3i(unequip_arrow.pos_x, unequip_arrow.pos_y, 0);
841 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
842 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
843 glVertex3i(unequip_arrow.pos_x, unequip_arrow.pos_y + unequip_arrow.len_y, 0);
844 if (!disable_double_click)
845 {
846 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y, 0);
847 glVertex3i(unequip_arrow.pos_x + unequip_arrow.len_x, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
848 glVertex3i(unequip_arrow.pos_x + unequip_arrow.len_x, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
849 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y, 0);
850 }
851 glEnd();
852 }
853 else
854 {
855 int arrow_width = (disable_double_click) ?unequip_arrow.len_x : unequip_arrow.len_x/2;
856 glBegin(GL_LINES); /* left arrow */
857 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y, 0);
858 glVertex3i(unequip_arrow.pos_x, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
859 glVertex3i(unequip_arrow.pos_x, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
860 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y, 0);
861 if (!disable_double_click)
862 {
863 glVertex3i(unequip_arrow.pos_x + unequip_arrow.len_x, unequip_arrow.pos_y, 0);
864 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
865 glVertex3i(unequip_arrow.pos_x + arrow_width, unequip_arrow.pos_y + unequip_arrow.len_y/2, 0);
866 glVertex3i(unequip_arrow.pos_x + unequip_arrow.len_x, unequip_arrow.pos_y + unequip_arrow.len_y, 0);
867 }
868 glEnd();
869 }
870
871 // Render the grid *after* the images. It seems impossible to code
872 // it such that images are rendered exactly within the boxes on all
873 // cards
874 glColor3fv(gui_color);
875
876 //draw the grids
877 rendergrid(items_grid.cols, items_grid.rows, items_grid.pos_x, items_grid.pos_y, items_grid.width, items_grid.height);
878
879 glColor3f(0.57f,0.67f,0.49f);
880 rendergrid(equip_grid.cols, equip_grid.rows, equip_grid.pos_x, equip_grid.pos_y, equip_grid.width, equip_grid.height);
881
882 // draw the button boxes
883 glColor3fv(gui_color);
884 for (i=0; i<NUMBUT; i++) {
885 glBegin(GL_LINE_LOOP);
886 glVertex3i(buttons_grid.pos_x + buttons_grid.width, buttons_grid.pos_y + buttons_grid.height * i, 0);
887 glVertex3i(buttons_grid.pos_x, buttons_grid.pos_y + buttons_grid.height * i, 0);
888 glVertex3i(buttons_grid.pos_x, buttons_grid.pos_y + buttons_grid.height * i + buttons_grid.height, 0);
889 glVertex3i(buttons_grid.pos_x + buttons_grid.width, buttons_grid.pos_y + buttons_grid.height * i + buttons_grid.height, 0);
890 glEnd();
891 }
892
893 // highlight a button with the mouse over
894 if (buttons_grid.mouse_over != -1)
895 {
896 glColor3fv(gui_bright_color);
897 glBegin(GL_LINE_LOOP);
898 glVertex3i(buttons_grid.pos_x + buttons_grid.width + 1, buttons_grid.pos_y + buttons_grid.height * buttons_grid.mouse_over - 1, 0);
899 glVertex3i(buttons_grid.pos_x - 1, buttons_grid.pos_y + buttons_grid.height * buttons_grid.mouse_over - 1, 0);
900 glVertex3i(buttons_grid.pos_x - 1, buttons_grid.pos_y + buttons_grid.height * buttons_grid.mouse_over + buttons_grid.height + 1, 0);
901 glVertex3i(buttons_grid.pos_x + buttons_grid.width + 1, buttons_grid.pos_y + buttons_grid.height * buttons_grid.mouse_over + buttons_grid.height + 1, 0);
902 glEnd();
903 }
904
905 //now, draw the quantity boxes
906 glColor3f(0.3f,0.5f,1.0f);
907 rendergrid(quantity_grid.cols, quantity_grid.rows, quantity_grid.pos_x, quantity_grid.pos_y, quantity_grid.width, quantity_grid.height);
908
909 glEnable(GL_TEXTURE_2D);
910
911 // display help text for button if mouse over one
912 if ((buttons_grid.mouse_over != -1) && show_help_text) {
913 char *helpstr[NUMBUT] = { stoall_help_str, getall_help_str, ((disable_double_click) ?drpall_help_str :dcdrpall_help_str), mixoneall_help_str, itmlst_help_str };
914 show_help(helpstr[buttons_grid.mouse_over], 0, win->len_y+10, win->current_scale);
915 show_help(cm_help_options_str, 0, win->len_y+10+win->small_font_len_y, win->current_scale);
916 }
917 // show help set in the mouse_over handler
918 else {
919 int offset = 10;
920 if (show_help_text && (item_help_str != NULL)) {
921 show_help(item_help_str, 0, win->len_y+offset, win->current_scale);
922 offset += win->small_font_len_y;
923 }
924 if (item_desc_str != NULL)
925 show_help(item_desc_str, 0, win->len_y+offset, win->current_scale);
926 item_help_str = NULL;
927 item_desc_str = NULL;
928 }
929
930 buttons_grid.mouse_over = -1;
931
932 #ifdef OPENGL_TRACE
933 CHECK_GL_ERRORS();
934 #endif //OPENGL_TRACE
935
936 return 1;
937 }
938
939
940 /* return 1 if sent the move command */
move_item(int item_pos_to_mov,int destination_pos,int avoid_pos)941 int move_item(int item_pos_to_mov, int destination_pos, int avoid_pos)
942 {
943 int drop_on_stack = 0;
944 swap_complete.last_dest = -1;
945 /* if the dragged item is equipped and the destintion is occupied, try to find another slot */
946 if ((item_pos_to_mov >= ITEM_WEAR_START) && (item_list[destination_pos].quantity)){
947 int i;
948 int have_free_pos = 0;
949 /* find first free slot, use a free slot in preference to a stack as the server does the stacking */
950 for (i = 0; i < ITEM_WEAR_START; i++){
951 if (!item_list[i].quantity && i != avoid_pos){
952 destination_pos = i;
953 have_free_pos = 1;
954 break;
955 }
956 }
957 /* if no free slot, try to find an existing stack. But be careful of dupe image ids */
958 if (!have_free_pos && item_list[item_pos_to_mov].is_stackable){
959 int num_stacks_found = 0;
960 int proposed_slot = -1;
961 for (i = 0; i < ITEM_WEAR_START; i++){
962 if (item_list[i].is_stackable && (item_list[i].image_id == item_list[item_pos_to_mov].image_id)){
963 num_stacks_found++;
964 proposed_slot = i;
965 }
966 }
967 /* only use the stack if we're sure there are no other possibilities */
968 if (num_stacks_found == 1){
969 destination_pos = proposed_slot;
970 drop_on_stack = 1;
971 }
972 else
973 set_shown_string(c_red2, items_stack_str);
974 /* This still leaves one possibility for the dreaded server accusation.
975 If we have no free inventory slots, one or more stackable items
976 unequipped, and a single, different equipped item with the same id as
977 the aforementioned stack. When we try to unequip the single item, the
978 client tries to place it on that stack. This may mean we have to
979 abandon this feature; i.e. allowing a stackable item to be unequipping
980 when there are no free slots. (pjbroad/bluap) */
981 }
982 }
983 /* move item */
984 if(drop_on_stack || !item_list[destination_pos].quantity){
985 Uint8 str[20];
986 //send the drop info to the server
987 str[0]=MOVE_INVENTORY_ITEM;
988 str[1]=item_list[item_pos_to_mov].pos;
989 str[2]=destination_pos;
990 my_tcp_send(my_socket,str,3);
991 swap_complete.last_dest = destination_pos;
992 return 1;
993 }
994 else
995 return 0;
996 }
997
equip_item(int item_pos_to_equip,int destination_pos)998 static void equip_item(int item_pos_to_equip, int destination_pos)
999 {
1000 Uint8 str[20];
1001 //send the drop info to the server
1002 str[0]=MOVE_INVENTORY_ITEM;
1003 str[1]=item_list[item_pos_to_equip].pos;
1004 str[2]=destination_pos;
1005 my_tcp_send(my_socket,str,3);
1006 }
1007
prep_move_to_vacated_slot(int destination)1008 static void prep_move_to_vacated_slot(int destination)
1009 {
1010 swap_complete.move_from = swap_complete.last_dest;
1011 swap_complete.move_to = destination;
1012 swap_complete.string_id = inventory_item_string_id;
1013 swap_complete.start_time = SDL_GetTicks();
1014 }
1015
1016 // stop expecting swap completion if we get a message, or we timeout (catch all)
check_for_swap_completion(void)1017 void check_for_swap_completion(void)
1018 {
1019 if (swap_complete.move_from != -1)
1020 {
1021 if (swap_complete.string_id != inventory_item_string_id)
1022 swap_complete.move_from = swap_complete.move_to = -1;
1023 if (SDL_GetTicks() > swap_complete.start_time + 2000)
1024 swap_complete.move_from = swap_complete.move_to = -1;
1025 }
1026 }
1027
item_swap_in_progress(int item_pos)1028 int item_swap_in_progress(int item_pos)
1029 {
1030 return (item_pos == swap_complete.move_from) ?1: 0;
1031 }
1032
1033 // If we double-click an equipable item, and one of that type is already equipped, swap them.
1034 //
swap_equivalent_equipped_item(int from_pos)1035 static int swap_equivalent_equipped_item(int from_pos)
1036 {
1037 size_t i;
1038 enum EQUIP_TYPE from_equip_type = get_item_equip_type(item_list[from_pos].id, item_list[from_pos].image_id);
1039 int same_pos = -1, left_hand_pos = -1, right_hand_pos = -1, both_hands_pos = -1;
1040 int item_to_swap = -1, extra_item = -1;
1041
1042 // stop now if we don't know about the item type
1043 if (from_equip_type == EQUIP_NONE)
1044 return 0;
1045
1046 // clear any previous "avoid destination" there may have been
1047 swap_complete.last_dest = -1;
1048
1049 // there are several rules about swapping left and right handed items with both handed items
1050 // find each of the types
1051 for(i = ITEM_WEAR_START; i<ITEM_WEAR_START + ITEM_NUM_WEAR; i++)
1052 if (item_list[i].quantity > 0)
1053 {
1054 enum EQUIP_TYPE the_type = get_item_equip_type(item_list[i].id, item_list[i].image_id);
1055 if (the_type == from_equip_type)
1056 same_pos = i;
1057 else if (the_type == EQUIP_LEFT_HAND)
1058 left_hand_pos = i;
1059 else if (the_type == EQUIP_RIGHT_HAND)
1060 right_hand_pos = i;
1061 else if (the_type == EQUIP_BOTH_HANDS)
1062 both_hands_pos = i;
1063 }
1064
1065 // if a simple, same item type swap
1066 if (same_pos != -1)
1067 item_to_swap = same_pos;
1068 // if equipping a both hands item, swap a right hand item first, any left hand as the extra
1069 else if (from_equip_type == EQUIP_BOTH_HANDS && right_hand_pos != -1)
1070 {
1071 item_to_swap = right_hand_pos;
1072 if (left_hand_pos != -1)
1073 extra_item = left_hand_pos;
1074 }
1075 // equipping a both hands item, no right hand but swap any left hand item
1076 else if (from_equip_type == EQUIP_BOTH_HANDS && left_hand_pos != -1)
1077 item_to_swap = left_hand_pos;
1078 // if theres an equipped both hands item, allow a right or left hand item to be swapped with it
1079 else if (both_hands_pos != -1 && (from_equip_type == EQUIP_RIGHT_HAND || from_equip_type == EQUIP_LEFT_HAND))
1080 item_to_swap = both_hands_pos;
1081
1082 // remove any extra item, swap_complete.last_dest will be set the the new slot for the remove item
1083 if ((extra_item != -1) && !move_item(extra_item, 0, -1))
1084 {
1085 do_alert1_sound();
1086 set_shown_string(c_red2, items_cannot_equip_str);
1087 return 1;
1088 }
1089
1090 // do the swap if any
1091 if (item_to_swap != -1)
1092 {
1093 // avoid moving to where we put any removed extra item
1094 if (move_item(item_to_swap, 0, swap_complete.last_dest))
1095 {
1096 equip_item(from_pos, item_to_swap);
1097 prep_move_to_vacated_slot(from_pos);
1098 do_get_item_sound();
1099 item_dragged = -1;
1100 }
1101 else
1102 {
1103 do_alert1_sound();
1104 set_shown_string(c_red2, items_cannot_equip_str);
1105 }
1106 return 1; // there was something to swap, and we tried, don't try other stuff
1107 }
1108
1109 return 0; // there was nothing to swap, try other stuff
1110 }
1111
1112 // common function for aut equip used by inventory and quickbar
try_auto_equip(int from_item)1113 void try_auto_equip(int from_item)
1114 {
1115 if (allow_equip_swap && swap_equivalent_equipped_item(from_item)) {
1116 // all done, don't try direct equip
1117 } else {
1118 size_t i;
1119 for(i = ITEM_WEAR_START; i < ITEM_WEAR_START + ITEM_NUM_WEAR; i++) {
1120 if(item_list[i].quantity<1) {
1121 if (!move_item(from_item, i, -1))
1122 {
1123 do_alert1_sound();
1124 set_shown_string(c_red2, items_cannot_equip_str);
1125 }
1126 item_dragged=-1;
1127 break;
1128 }
1129 }
1130 }
1131 }
1132
click_items_handler(window_info * win,int mx,int my,Uint32 flags)1133 static int click_items_handler(window_info *win, int mx, int my, Uint32 flags)
1134 {
1135 Uint8 str[100];
1136 int right_click = flags & ELW_RIGHT_MOUSE;
1137 int ctrl_on = flags & KMOD_CTRL;
1138 int shift_on = flags & KMOD_SHIFT;
1139 int alt_on = flags & KMOD_ALT;
1140 int pos;
1141 actor *me;
1142
1143 // only handle mouse button clicks, not scroll wheels moves (unless its the mix button)
1144 if (((flags & ELW_MOUSE_BUTTON) == 0) && (over_button(win, mx, my) != BUT_MIX)) return 0;
1145
1146 // ignore middle mouse button presses
1147 if ((flags & ELW_MID_MOUSE) != 0) return 0;
1148
1149 if (!right_click && over_button(win, mx, my) != -1)
1150 do_click_sound();
1151
1152 if ((flags & ELW_LEFT_MOUSE) && (mx > text_arrow.pos_x) && (mx < text_arrow.pos_x + text_arrow.len_x) &&
1153 (my < text_arrow.pos_y) && (my > text_arrow.pos_y - text_arrow.len_y))
1154 {
1155 items_disable_text_block ^= 1;
1156 show_items_handler(win);
1157 do_click_sound();
1158 return 1;
1159 }
1160
1161 if ((flags & ELW_LEFT_MOUSE) && (mx > unequip_arrow.pos_x) && (mx < unequip_arrow.pos_x + unequip_arrow.len_x) &&
1162 (my > unequip_arrow.pos_y) && (my < unequip_arrow.pos_y + unequip_arrow.len_y))
1163 {
1164 size_t i;
1165 int last_pos = 0;
1166 int success = 1;
1167 static Uint32 last_click = 0;
1168 if (!safe_button_click(&last_click))
1169 return 1;
1170 for(i = ITEM_WEAR_START; i < ITEM_WEAR_START + ITEM_NUM_WEAR; i++)
1171 {
1172 if(item_list[i].quantity>0)
1173 {
1174 size_t j;
1175 int found_slot = 0;
1176 if (item_list[i].is_stackable)
1177 {
1178 for (j=0; j<ITEM_WEAR_START; j++)
1179 if ((item_list[j].quantity>0) && (item_list[i].id == item_list[j].id) && (item_list[i].image_id == item_list[j].image_id))
1180 {
1181 if (move_item(i, j, -1))
1182 found_slot = 1;
1183 break;
1184 }
1185 }
1186 if (!found_slot)
1187 for (j=last_pos; j<ITEM_WEAR_START; j++)
1188 {
1189 if (item_list[j].quantity<1)
1190 {
1191 if (move_item(i, j, -1))
1192 found_slot = 1;
1193 last_pos = j + 1;
1194 break;
1195 }
1196 }
1197 if (!found_slot)
1198 success = 0;
1199 }
1200 }
1201 if (success)
1202 do_get_item_sound();
1203 else
1204 do_alert1_sound();
1205 item_dragged=-1;
1206 return 1;
1207 }
1208
1209 if(right_click) {
1210 if(item_dragged!=-1 || use_item!=-1 || storage_item_dragged!=-1){
1211 use_item=-1;
1212 item_dragged=-1;
1213 storage_item_dragged=-1;
1214 item_action_mode=ACTION_WALK;
1215 return 1;
1216 }
1217
1218 if((mx >= equip_grid.pos_x) && (mx < equip_grid.pos_x + equip_grid.len_x) &&
1219 (my >= equip_grid.pos_y) && (my < equip_grid.pos_y + equip_grid.len_y + 1)) {
1220 switch(item_action_mode){
1221 case ACTION_WALK:
1222 item_action_mode=ACTION_LOOK;
1223 break;
1224 case ACTION_LOOK:
1225 default:
1226 item_action_mode=ACTION_WALK;
1227 }
1228 return 1;
1229 } else if((mx >= quantity_grid.pos_x) && (mx < quantity_grid.pos_x + quantity_grid.len_x) &&
1230 (my >= quantity_grid.pos_y) && (my < quantity_grid.pos_y + + quantity_grid.len_y)){
1231 //fall through...
1232 } else {
1233 switch(item_action_mode) {
1234 case ACTION_WALK:
1235 item_action_mode=ACTION_LOOK;
1236 break;
1237 case ACTION_LOOK:
1238 item_action_mode=ACTION_USE;
1239 break;
1240 case ACTION_USE:
1241 item_action_mode=ACTION_USE_WITEM;
1242 break;
1243 case ACTION_USE_WITEM:
1244 item_action_mode=ACTION_WALK;
1245 break;
1246 default:
1247 item_action_mode=ACTION_WALK;
1248 }
1249 return 1;
1250 }
1251 }
1252
1253 if (item_action_mode == ACTION_USE_WITEM)
1254 set_gamewin_usewith_action();
1255
1256 //see if we changed the quantity
1257 if((mx >= quantity_grid.pos_x) && (mx < quantity_grid.pos_x + quantity_grid.len_x) &&
1258 (my >= quantity_grid.pos_y) && (my < quantity_grid.pos_y + quantity_grid.len_y)) {
1259 int pos = get_mouse_pos_in_grid(mx, my, quantity_grid.cols, quantity_grid.rows, quantity_grid.pos_x, quantity_grid.pos_y, quantity_grid.width, quantity_grid.height);
1260
1261 if(pos==-1){
1262 } else if(flags & ELW_LEFT_MOUSE){
1263 if(edit_quantity!=-1){
1264 if(!quantities.quantity[edit_quantity].len){
1265 //Reset the quantity
1266 reset_quantity(edit_quantity);
1267 }
1268 edit_quantity=-1;
1269 }
1270
1271 item_quantity=quantities.quantity[pos].val;
1272 quantities.selected=pos;
1273 } else if(right_click){
1274 //Edit the given quantity
1275 edit_quantity=pos;
1276 }
1277
1278 return 1;
1279 }
1280
1281 if(edit_quantity!=-1){
1282 if(!quantities.quantity[edit_quantity].len)reset_quantity(edit_quantity);
1283 item_quantity=quantities.quantity[edit_quantity].val;
1284 quantities.selected=edit_quantity;
1285 edit_quantity=-1;
1286 }
1287
1288 //see if we clicked on any item in the main category
1289 else if(mx>items_grid.pos_x && (mx < items_grid.pos_x + items_grid.len_x) &&
1290 my>0 && my < items_grid.len_y) {
1291 int pos=get_mouse_pos_in_grid(mx, my, items_grid.cols, items_grid.rows, items_grid.pos_x, items_grid.pos_y, items_grid.width, items_grid.height);
1292
1293 #ifdef NEW_SOUND
1294 if(pos>-1) {
1295 item_list[pos].action = ITEM_NO_ACTION;
1296 item_list[pos].action_time = 0;
1297 }
1298 #endif // NEW_SOUND
1299 if(pos==-1) {
1300 } else if(item_dragged!=-1){
1301 if(item_dragged == pos){
1302 try_auto_equip(item_dragged);
1303 } else {
1304 if (move_item(item_dragged, pos, -1)){
1305 do_drop_item_sound();
1306 }
1307 else {
1308 do_alert1_sound();
1309 }
1310 item_dragged=-1;
1311 }
1312
1313 }
1314 else if(storage_item_dragged!=-1){
1315 str[0]=WITHDRAW_ITEM;
1316 *((Uint16*)(str+1))=SDL_SwapLE16(storage_items[storage_item_dragged].pos);
1317 *((Uint32*)(str+3))=SDL_SwapLE32(item_quantity);
1318 my_tcp_send(my_socket, str, 6);
1319 do_drop_item_sound();
1320 if(storage_items[storage_item_dragged].quantity<=item_quantity) storage_item_dragged=-1;
1321 }
1322 else if(item_list[pos].quantity){
1323 if (ctrl_on && (items_mod_click_any_cursor || (item_action_mode==ACTION_WALK))) {
1324 str[0]=DROP_ITEM;
1325 str[1]=item_list[pos].pos;
1326 if(item_list[pos].is_stackable)
1327 *((Uint32 *)(str+2))=SDL_SwapLE32(item_list[pos].quantity);
1328 else
1329 *((Uint32 *)(str+2))=SDL_SwapLE32(36);//Drop all
1330 my_tcp_send(my_socket, str, 6);
1331 do_drop_item_sound();
1332 } else if (alt_on && (items_mod_click_any_cursor || (item_action_mode==ACTION_WALK))) {
1333 if ((get_id_MW(MW_STORAGE) >= 0) && (get_show_window_MW(MW_STORAGE)) && (view_only_storage == 0)) {
1334 str[0]=DEPOSITE_ITEM;
1335 str[1]=item_list[pos].pos;
1336 *((Uint32*)(str+2))=SDL_SwapLE32(INT_MAX);
1337 my_tcp_send(my_socket, str, 6);
1338 do_drop_item_sound();
1339 } else {
1340 drop_fail_time = SDL_GetTicks();
1341 do_alert1_sound();
1342 }
1343 } else if(item_action_mode==ACTION_LOOK) {
1344 click_time=cur_time;
1345 str[0]=LOOK_AT_INVENTORY_ITEM;
1346 str[1]=item_list[pos].pos;
1347 my_tcp_send(my_socket,str,2);
1348 } else if(item_action_mode==ACTION_USE) {
1349 if(item_list[pos].use_with_inventory){
1350 str[0]=USE_INVENTORY_ITEM;
1351 str[1]=item_list[pos].pos;
1352 my_tcp_send(my_socket,str,2);
1353 used_item_counter_action_use(pos);
1354 #ifdef NEW_SOUND
1355 item_list[pos].action = USE_INVENTORY_ITEM;
1356 #ifdef _EXTRA_SOUND_DEBUG
1357 // printf("Using item: %d, inv pos: %d, Image ID: %d\n", item_list[pos].pos, pos, item_list[pos].image_id);
1358 #endif // _EXTRA_SOUND_DEBUG
1359 #endif // NEW_SOUND
1360 }
1361 } else if(item_action_mode==ACTION_USE_WITEM) {
1362 if(use_item!=-1) {
1363 str[0]=ITEM_ON_ITEM;
1364 str[1]=item_list[use_item].pos;
1365 str[2]=item_list[pos].pos;
1366 my_tcp_send(my_socket,str,3);
1367 used_item_counter_action_use(use_item);
1368 #ifdef NEW_SOUND
1369 item_list[use_item].action = ITEM_ON_ITEM;
1370 item_list[pos].action = ITEM_ON_ITEM;
1371 #ifdef _EXTRA_SOUND_DEBUG
1372 // printf("Using item: %d on item: %d, Image ID: %d\n", pos, use_item, item_list[pos].image_id);
1373 #endif // _EXTRA_SOUND_DEBUG
1374 #endif // NEW_SOUND
1375 if (!shift_on)
1376 use_item=-1;
1377 } else {
1378 use_item=pos;
1379 }
1380 } else {
1381 item_dragged=pos;
1382 do_drag_item_sound();
1383 }
1384 }
1385 }
1386
1387 // Get All button
1388 else if(over_button(win, mx, my)==BUT_GET){
1389 int x,y;
1390 me = get_our_actor ();
1391 if(!me)return(1);
1392 x=me->x_tile_pos;
1393 y=me->y_tile_pos;
1394 items_get_bag(x,y);
1395 }
1396
1397 // Sto All button
1398 else if(over_button(win, mx, my)==BUT_STORE && get_id_MW(MW_STORAGE) >= 0 && view_only_storage == 0 && get_show_window_MW(MW_STORAGE) /*thanks alberich*/){
1399 #ifdef STORE_ALL
1400 /*
1401 * Future code to save server load by having one byte to represent the 36 slot inventory loop. Will need server support.
1402 */
1403 str[0]=DEPOSITE_ITEM;
1404 str[1]=STORE_ALL;
1405 my_tcp_send(my_socket, str, 2);
1406 #else
1407 for(pos=((items_stoall_nofirstrow)?6:0);pos<((items_stoall_nolastrow)?30:36);pos++){
1408 if(item_list[pos].quantity>0){
1409 str[0]=DEPOSITE_ITEM;
1410 str[1]=item_list[pos].pos;
1411 *((Uint32*)(str+2))=SDL_SwapLE32(item_list[pos].quantity);
1412 my_tcp_send(my_socket, str, 6);
1413 }
1414 }
1415 #endif
1416 }
1417
1418 // Drop All button
1419 else if(over_button(win, mx, my)==BUT_DROP){
1420 drop_all_handler();
1421 }
1422
1423 // Mix One/All button
1424 else if(over_button(win, mx, my)==BUT_MIX){
1425 if (items_mix_but_all)
1426 mix_handler(255, mixbut_empty_str);
1427 else
1428 mix_handler(1, mixbut_empty_str);
1429 }
1430
1431 // Item List button
1432 else if (over_button(win, mx, my)==BUT_ITEM_LIST)
1433 toggle_items_list_window(win);
1434
1435 //see if we clicked on any item in the wear category
1436 else if((mx > equip_grid.pos_x) && (mx < equip_grid.pos_x + equip_grid.len_x) &&
1437 (my > equip_grid.pos_y) && (my < equip_grid.pos_y + equip_grid.len_y)){
1438 int pos = ITEM_WEAR_START + get_mouse_pos_in_grid(mx, my, equip_grid.cols, equip_grid.rows, equip_grid.pos_x, equip_grid.pos_y, equip_grid.width, equip_grid.height);
1439
1440 if(pos < ITEM_WEAR_START) {
1441 } else if(item_list[pos].quantity){
1442 if(item_action_mode == ACTION_LOOK) {
1443 str[0]=LOOK_AT_INVENTORY_ITEM;
1444 str[1]=item_list[pos].pos;
1445 my_tcp_send(my_socket, str, 2);
1446 } else if(item_dragged==-1 && left_click) {
1447 item_dragged=pos;
1448 do_drag_item_sound();
1449 }
1450 else if(item_dragged!=-1 && left_click) {
1451 int can_move = (item_dragged == pos) || allow_equip_swap;
1452 if (can_move && move_item(pos, 0, -1)) {
1453 equip_item(item_dragged, pos);
1454 if (item_dragged != pos)
1455 prep_move_to_vacated_slot(item_dragged);
1456 do_get_item_sound();
1457 }
1458 else {
1459 do_alert1_sound();
1460 set_shown_string(c_red2, items_cannot_equip_str);
1461 }
1462 item_dragged=-1;
1463 }
1464 } else if(item_dragged!=-1){
1465 equip_item(item_dragged, pos);
1466 item_dragged=-1;
1467 do_drop_item_sound();
1468 }
1469 }
1470
1471 // clear the message area if double-clicked
1472 else if (!items_disable_text_block && (mx > message_box.pos_x) && (mx < message_box.pos_x + message_box.len_x) &&
1473 (my > message_box.pos_y) && (my < message_box.pos_y + message_box.len_y)) {
1474 static Uint32 last_click = 0;
1475 if (safe_button_click(&last_click)) {
1476 set_shown_string(0,"");
1477 return 1;
1478 }
1479 }
1480
1481 return 1;
1482 }
1483
set_description_help(int pos)1484 static void set_description_help(int pos)
1485 {
1486 Uint16 item_id = item_list[pos].id;
1487 int image_id = item_list[pos].image_id;
1488 if (show_item_desc_text && item_info_available() && (get_item_count(item_id, image_id) == 1))
1489 item_desc_str = get_item_description(item_id, image_id);
1490 }
1491
mouseover_items_handler(window_info * win,int mx,int my)1492 static int mouseover_items_handler(window_info *win, int mx, int my) {
1493 int pos;
1494
1495 // check and record if mouse if over a button
1496 if ((buttons_grid.mouse_over = over_button(win, mx, my)) != -1)
1497 return 0; // keep standard cursor
1498
1499 if ((mx > text_arrow.pos_x) && (mx < text_arrow.pos_x + text_arrow.len_x) &&
1500 (my < text_arrow.pos_y) && (my > text_arrow.pos_y - text_arrow.len_y))
1501 {
1502 item_help_str = items_text_toggle_help_str;
1503 text_arrow.mouse_over = 1;
1504 return 0;
1505 }
1506
1507 if ((mx > unequip_arrow.pos_x) && (mx < unequip_arrow.pos_x + unequip_arrow.len_x) &&
1508 (my > unequip_arrow.pos_y) && (my < unequip_arrow.pos_y + unequip_arrow.len_y))
1509 {
1510 item_help_str = (disable_double_click) ?items_unequip_all_help_str :items_doubleclick_unequip_all_help_str;
1511 unequip_arrow.mouse_over = 1;
1512 return 0;
1513 }
1514
1515 if((mx > items_grid.pos_x) && (mx < items_grid.pos_x + items_grid.len_x) && (my > 0) && (my < items_grid.len_y)) {
1516 pos = get_mouse_pos_in_grid(mx, my, items_grid.cols, items_grid.rows, items_grid.pos_x, items_grid.pos_y, items_grid.width, items_grid.height);
1517
1518 if(pos==-1) {
1519 } else if(item_list[pos].quantity){
1520 set_description_help(pos);
1521 if ((item_dragged == -1) && (items_mod_click_any_cursor || (item_action_mode==ACTION_WALK)))
1522 item_help_str = mod_click_item_help_str;
1523 if(item_action_mode==ACTION_LOOK) {
1524 elwin_mouse=CURSOR_EYE;
1525 } else if(item_action_mode==ACTION_USE) {
1526 elwin_mouse=CURSOR_USE;
1527 } else if(item_action_mode==ACTION_USE_WITEM) {
1528 elwin_mouse=CURSOR_USE_WITEM;
1529 if (use_item!=-1)
1530 item_help_str = multiuse_item_help_str;
1531 } else {
1532 elwin_mouse=CURSOR_PICK;
1533 }
1534 items_grid.mouse_over = pos;
1535
1536 return 1;
1537 }
1538 } else if((mx > equip_grid.pos_x) && (mx < equip_grid.pos_x + equip_grid.len_x) &&
1539 (my > equip_grid.pos_y) && (my < equip_grid.pos_y + equip_grid.len_y)) {
1540 pos = ITEM_WEAR_START + get_mouse_pos_in_grid(mx, my, equip_grid.cols, equip_grid.rows, equip_grid.pos_x, equip_grid.pos_y, equip_grid.width, equip_grid.height);
1541 item_help_str = equip_here_str;
1542 if(pos==-1) {
1543 } else if(item_list[pos].quantity){
1544 set_description_help(pos);
1545 if(item_action_mode==ACTION_LOOK) {
1546 elwin_mouse=CURSOR_EYE;
1547 } else if(item_action_mode==ACTION_USE) {
1548 elwin_mouse=CURSOR_USE;
1549 } else if(item_action_mode==ACTION_USE_WITEM) {
1550 elwin_mouse=CURSOR_USE_WITEM;
1551 } else {
1552 elwin_mouse=CURSOR_PICK;
1553 }
1554 return 1;
1555 }
1556 } else if(show_help_text && (mx > quantity_grid.pos_x) && (mx < quantity_grid.pos_x + quantity_grid.len_x) &&
1557 (my > quantity_grid.pos_y) && (my < quantity_grid.pos_y + quantity_grid.len_y)){
1558 item_help_str = quantity_edit_str;
1559 } else if (show_help_text && *inventory_item_string && !items_disable_text_block &&
1560 (mx > message_box.pos_x) && (mx < message_box.pos_x + message_box.len_x) &&
1561 (my > message_box.pos_y) && (my < message_box.pos_y + message_box.len_y)) {
1562 item_help_str = (disable_double_click)?click_clear_str :double_click_clear_str;
1563 }
1564
1565 return 0;
1566 }
1567
keypress_items_handler(window_info * win,int x,int y,SDL_Keycode key_code,Uint32 key_unicode,Uint16 key_mod)1568 static int keypress_items_handler(window_info * win, int x, int y, SDL_Keycode key_code, Uint32 key_unicode, Uint16 key_mod)
1569 {
1570 if(edit_quantity!=-1){
1571 char * str=quantities.quantity[edit_quantity].str;
1572 int * len=&quantities.quantity[edit_quantity].len;
1573 int * val=&quantities.quantity[edit_quantity].val;
1574
1575 if(key_code == SDLK_DELETE){
1576 reset_quantity(edit_quantity);
1577 edit_quantity=-1;
1578 return 1;
1579 } else if(key_code == SDLK_BACKSPACE){
1580 if(*len>0){
1581 (*len)--;
1582 str[*len]=0;
1583 *val=atoi(str);
1584 }
1585 return 1;
1586 } else if(key_code == SDLK_RETURN || key_code == SDLK_KP_ENTER){
1587 if(!*val){
1588 reset_quantity(edit_quantity);
1589 }
1590 item_quantity=*val;
1591 quantities.selected=edit_quantity;
1592 edit_quantity=-1;
1593 return 1;
1594 } else if(key_code == SDLK_ESCAPE){
1595 reset_quantity(edit_quantity);
1596 edit_quantity=-1;
1597 return 1;
1598 } else if(key_unicode >= '0' && key_unicode <= '9'){
1599 if (*len<5)
1600 {
1601 str[*len]=key_unicode;
1602 (*len)++;
1603 str[*len]=0;
1604 *val=atoi(str);
1605 }
1606 return 1;
1607 }
1608 }
1609
1610 return 0;
1611 }
1612
drop_all_handler(void)1613 static void drop_all_handler (void)
1614 {
1615 Uint8 str[6] = {0};
1616 int i;
1617 int dropped_something = 0;
1618 static Uint32 last_click = 0;
1619
1620 /* provide some protection for inadvertent pressing (double click that can be disabled) */
1621 if (safe_button_click(&last_click))
1622 {
1623 for(i = 0; i < ITEM_NUM_ITEMS; i++)
1624 {
1625 if (item_list[i].quantity != 0 && // only drop stuff that we're not wearing or not excluded
1626 item_list[i].pos >= ((items_dropall_nofirstrow)?6:0) &&
1627 item_list[i].pos < ((items_dropall_nolastrow)?30:ITEM_WEAR_START))
1628 {
1629 str[0] = DROP_ITEM;
1630 str[1] = item_list[i].pos;
1631 *((Uint32 *)(str+2)) = SDL_SwapLE32(item_list[i].quantity);
1632 my_tcp_send (my_socket, str, 6);
1633 dropped_something = 1;
1634 }
1635 }
1636 if (dropped_something)
1637 do_drop_item_sound();
1638 }
1639 }
1640
get_max_but_label_len(window_info * win)1641 static int get_max_but_label_len(window_info * win)
1642 {
1643 char const *but_labels[] = { sto_all_str, get_all_str, drp_all_str, mix_all_str, mix_one_str, itm_lst_str };
1644 int max_width = 0;
1645 char *buf = NULL;
1646 size_t i;
1647 if (win == NULL)
1648 return 0;
1649 max_width = win->box_size;
1650 for (i = 0; i < sizeof(but_labels) / sizeof(char *); i++)
1651 {
1652 char *saveptr = NULL;
1653 char *next = NULL;
1654 buf = realloc(buf, strlen(but_labels[i]) + 1);
1655 strcpy((char *)buf, but_labels[i]);
1656 next = strtok_r(buf, " ", &saveptr);
1657 while (next != NULL)
1658 {
1659 max_width = max2i(max_width, get_buf_width_zoom((unsigned char *)next, strlen(next), win->font_category, button_text_zoom));
1660 next = strtok_r(NULL, " ", &saveptr);
1661 }
1662 }
1663 free(buf);
1664 return max_width;
1665 }
1666
show_items_handler(window_info * win)1667 static int show_items_handler(window_info * win)
1668 {
1669 int i, win_x_len, win_y_len;
1670 int seperator = (int)(0.5 + win->current_scale * 5);
1671
1672 if (!manual_size_items_window)
1673 use_small_items_window = ((window_height<=600) || (window_width<=800));
1674
1675 items_grid.cols = 6;
1676 items_grid.rows = 6;
1677 items_grid.width = (int)(0.5 + win->current_scale * ((use_small_items_window) ?33: 50));
1678 items_grid.height = (int)(0.5 + win->current_scale * ((use_small_items_window) ?33: 50));
1679 items_grid.len_x = items_grid.width * items_grid.cols;
1680 items_grid.len_y = items_grid.height * items_grid.rows;
1681
1682 equip_grid.cols = 2;
1683 equip_grid.rows = 4;
1684 equip_grid.width = (int)(0.5 + win->current_scale * 33);
1685 equip_grid.height = (int)(0.5 + win->current_scale * 33);
1686 equip_grid.len_x = equip_grid.width * equip_grid.cols;
1687 equip_grid.len_y = equip_grid.height * equip_grid.rows;;
1688
1689 /* the buttons */
1690 button_text_zoom = win->current_scale_small
1691 * min2f(1.0, 0.5 * equip_grid.height / win->small_font_len_y);
1692 buttons_grid.cols = 1;
1693 buttons_grid.rows = NUMBUT;
1694 buttons_grid.width = get_max_but_label_len(win) + (int)(0.5 + 6 * button_text_zoom);
1695 buttons_grid.height = equip_grid.height;
1696 buttons_grid.len_x = buttons_grid.width * buttons_grid.cols;
1697 buttons_grid.len_y = buttons_grid.height * buttons_grid.rows;
1698
1699 /* we can have the eqipment grid and or the button bar on the left of right */
1700 if (items_buttons_on_left)
1701 {
1702 buttons_grid.pos_x = 0;
1703 if (items_equip_grid_on_left)
1704 {
1705 equip_grid.pos_x = buttons_grid.pos_x + buttons_grid.len_x + seperator;
1706 items_grid.pos_x = equip_grid.pos_x + equip_grid.len_x + seperator;
1707 }
1708 else
1709 {
1710 items_grid.pos_x = buttons_grid.pos_x + buttons_grid.len_x + seperator;
1711 equip_grid.pos_x = items_grid.pos_x + items_grid.len_x + seperator;
1712 }
1713 buttons_grid.pos_y = items_grid.height;
1714 items_grid.pos_y = 0;
1715 equip_grid.pos_y = items_grid.height;
1716 }
1717 else
1718 {
1719 if (items_equip_grid_on_left)
1720 {
1721 equip_grid.pos_x = 0;
1722 items_grid.pos_x = equip_grid.pos_x + equip_grid.len_x + seperator;
1723 buttons_grid.pos_x = items_grid.pos_x + items_grid.len_x + seperator;
1724 }
1725 else
1726 {
1727 items_grid.pos_x = 0;
1728 equip_grid.pos_x = items_grid.pos_x + items_grid.len_x + seperator;
1729 buttons_grid.pos_x = equip_grid.pos_x + equip_grid.len_x + seperator;
1730 }
1731 items_grid.pos_y = 0;
1732 equip_grid.pos_y = items_grid.height;
1733 buttons_grid.pos_y = items_grid.height;
1734 }
1735
1736 text_arrow.len_x = unequip_arrow.len_x = equip_grid.width * 0.4;
1737 text_arrow.len_y = unequip_arrow.len_y = equip_grid.height * 0.4;
1738 unequip_arrow.pos_x = equip_grid.pos_x + ((items_equip_grid_on_left) ?equip_grid.width :0) + (equip_grid.width - unequip_arrow.len_x) / 2;
1739 unequip_arrow.pos_y = equip_grid.pos_y + equip_grid.len_y + (equip_grid.height - unequip_arrow.len_y) / 2;
1740
1741 /* we can finally calculate the maximum y value so far .... */
1742 win_y_len = ((items_grid.pos_y + items_grid.len_y) > (equip_grid.pos_y + equip_grid.len_y + text_arrow.len_y + seperator)) ?(items_grid.pos_y + items_grid.len_y) : (equip_grid.pos_y + equip_grid.len_y + text_arrow.len_y + seperator);
1743 win_y_len = ((buttons_grid.pos_y + buttons_grid.len_y) > win_y_len) ?(buttons_grid.pos_y + buttons_grid.len_y) :win_y_len;
1744
1745 /* then we can finally poistion the message box arrow */
1746 text_arrow.pos_x = equip_grid.pos_x + ((items_equip_grid_on_left) ?0 :equip_grid.width) + (equip_grid.width - text_arrow.len_x) / 2;
1747 text_arrow.pos_y = win_y_len;
1748
1749 /* calculate the window width needed for all the components */
1750 win_x_len = items_grid.len_x + equip_grid.len_x + buttons_grid.len_x + 2 * seperator + ((items_buttons_on_left && items_equip_grid_on_left) ?win->box_size :0);
1751
1752 /* the text message box */
1753 message_box.rows = 4;
1754 message_box.cols = 1;
1755 message_box.len_x = win_x_len - 8;
1756 message_box.len_y = win->small_font_len_y * message_box.rows;
1757 message_box.pos_x = 4;
1758 if (items_disable_text_block)
1759 message_box.pos_y = 0;
1760 else
1761 {
1762 message_box.pos_y = win_y_len + seperator;
1763 win_y_len += message_box.len_y;
1764 }
1765
1766 /* the load and quanity labels */
1767 win_y_len += seperator;
1768 labels_box.rows = 1;
1769 labels_box.cols = 1;
1770 labels_box.len_x = win_x_len - 8;
1771 labels_box.len_y = win->small_font_len_y * labels_box.rows;
1772 labels_box.pos_x = 4;
1773 labels_box.pos_y = win_y_len;
1774 win_y_len += labels_box.len_y;
1775
1776 /* the quanity numbers */
1777 item_quantity = quantities.quantity[quantities.selected].val;
1778 quantity_grid.cols = ITEM_EDIT_QUANT;
1779 quantity_grid.rows = 1;
1780 quantity_grid.width = (int)((float)win_x_len / (float)quantity_grid.cols);
1781 quantity_grid.height = win->small_font_len_y + seperator;
1782 quantity_grid.len_x = quantity_grid.width * quantity_grid.cols;
1783 quantity_grid.len_y = quantity_grid.height * quantity_grid.rows;
1784 quantity_grid.pos_x = (win_x_len - quantity_grid.len_x) / 2;
1785 quantity_grid.pos_y = win_y_len;
1786 win_y_len += quantity_grid.height;
1787
1788 resize_window(win->window_id, win_x_len, win_y_len);
1789
1790 cm_remove_regions(win->window_id);
1791 for (i=0; i<NUMBUT; i++)
1792 cm_add_region(buttons_cm_id[i], win->window_id, buttons_grid.pos_x, buttons_grid.pos_y + buttons_grid.height * i, buttons_grid.width, buttons_grid.height);
1793
1794 /* make sure we redraw any string */
1795 last_items_string_id = 0;
1796
1797 return 1;
1798 }
1799
context_items_handler(window_info * win,int widget_id,int mx,int my,int option)1800 static int context_items_handler(window_info *win, int widget_id, int mx, int my, int option)
1801 {
1802 if (option<ELW_CM_MENU_LEN)
1803 return cm_title_handler(win, widget_id, mx, my, option);
1804 switch (option)
1805 {
1806 case ELW_CM_MENU_LEN+1: manual_size_items_window = 1; show_items_handler(win); break;
1807 case ELW_CM_MENU_LEN+2: case ELW_CM_MENU_LEN+6: case ELW_CM_MENU_LEN+7: show_items_handler(win); break;
1808 case ELW_CM_MENU_LEN+9: send_input_text_line("#sto", 4); break;
1809 }
1810 return 1;
1811 }
1812
display_items_menu()1813 void display_items_menu()
1814 {
1815 int items_win = get_id_MW(MW_ITEMS);
1816 if(items_win < 0){
1817 items_win = create_window(win_inventory, (not_on_top_now(MW_ITEMS) ?game_root_win : -1), 0, get_pos_x_MW(MW_ITEMS), get_pos_y_MW(MW_ITEMS),
1818 0, 0, ELW_USE_UISCALE|ELW_WIN_DEFAULT);
1819 set_id_MW(MW_ITEMS, items_win);
1820
1821 set_window_custom_scale(items_win, MW_ITEMS);
1822 set_window_handler(items_win, ELW_HANDLER_DISPLAY, &display_items_handler );
1823 set_window_handler(items_win, ELW_HANDLER_CLICK, &click_items_handler );
1824 set_window_handler(items_win, ELW_HANDLER_MOUSEOVER, &mouseover_items_handler );
1825 set_window_handler(items_win, ELW_HANDLER_KEYPRESS, (int (*)())&keypress_items_handler );
1826 set_window_handler(items_win, ELW_HANDLER_SHOW, &show_items_handler );
1827 set_window_handler(items_win, ELW_HANDLER_UI_SCALE, &show_items_handler );
1828 set_window_handler(items_win, ELW_HANDLER_FONT_CHANGE, &show_items_handler);
1829
1830 cm_add(windows_list.window[items_win].cm_id, cm_items_menu_str, context_items_handler);
1831 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+1, &use_small_items_window, NULL);
1832 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+2, &manual_size_items_window, NULL);
1833 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+3, &item_window_on_drop, "item_window_on_drop");
1834 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+4, &allow_equip_swap, NULL);
1835 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+5, &items_mod_click_any_cursor, NULL);
1836 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+6, &items_buttons_on_left, NULL);
1837 cm_bool_line(windows_list.window[items_win].cm_id, ELW_CM_MENU_LEN+7, &items_equip_grid_on_left, NULL);
1838
1839 buttons_cm_id[BUT_STORE] = cm_create(inv_keeprow_str, NULL);
1840 cm_bool_line(buttons_cm_id[BUT_STORE], 0, &items_stoall_nofirstrow, NULL);
1841 cm_bool_line(buttons_cm_id[BUT_STORE], 1, &items_stoall_nolastrow, NULL);
1842
1843 buttons_cm_id[BUT_DROP] = cm_create(inv_keeprow_str, NULL);
1844 cm_bool_line(buttons_cm_id[BUT_DROP], 0, &items_dropall_nofirstrow, NULL);
1845 cm_bool_line(buttons_cm_id[BUT_DROP], 1, &items_dropall_nolastrow, NULL);
1846
1847 buttons_cm_id[BUT_MIX] = cm_create(mix_all_str, NULL);
1848 cm_bool_line(buttons_cm_id[BUT_MIX], 0, &items_mix_but_all, NULL);
1849
1850 buttons_cm_id[BUT_GET] = cm_create(auto_get_all_str, NULL);
1851 cm_bool_line(buttons_cm_id[BUT_GET], 0, &items_auto_get_all, NULL);
1852
1853 buttons_cm_id[BUT_ITEM_LIST] = cm_create(item_list_but_str, NULL);
1854 cm_bool_line(buttons_cm_id[BUT_ITEM_LIST], 0, &items_list_on_left, NULL);
1855
1856 show_items_handler(&windows_list.window[items_win]);
1857 check_proportional_move(MW_ITEMS);
1858
1859 } else {
1860 show_window(items_win);
1861 select_window(items_win);
1862 }
1863 }
1864
get_items_cooldown(const Uint8 * data,int len)1865 void get_items_cooldown (const Uint8 *data, int len)
1866 {
1867 int iitem, nitems, ibyte, pos;
1868 Uint8 cooldown, max_cooldown;
1869
1870 // reset old cooldown values
1871 for (iitem = 0; iitem < ITEM_NUM_ITEMS; iitem++)
1872 {
1873 item_list[iitem].cooldown_time = 0;
1874 item_list[iitem].cooldown_rate = 1;
1875 }
1876
1877 nitems = len / 5;
1878 if (nitems <= 0) return;
1879
1880 ibyte = 0;
1881 for (iitem = 0; iitem < nitems; iitem++)
1882 {
1883 pos = data[ibyte];
1884 max_cooldown = SDL_SwapLE16 (*((Uint16*)(&data[ibyte+1])));
1885 cooldown = SDL_SwapLE16 (*((Uint16*)(&data[ibyte+3])));
1886 ibyte += 5;
1887
1888 item_list[pos].cooldown_rate = 1000 * (Uint32)max_cooldown;
1889 item_list[pos].cooldown_time = cur_time + 1000 * (Uint32)cooldown;
1890 }
1891 }
1892