1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "bags.h"
5 #include "3d_objects.h"
6 #include "asc.h"
7 #include "cursors.h"
8 #include "elconfig.h"
9 #include "elwindows.h"
10 #include "errors.h"
11 #include "gamewin.h"
12 #include "hud.h"
13 #ifdef OPENGL_TRACE
14 #include "gl_init.h"
15 #endif
16 #include "init.h"
17 #include "interface.h"
18 #include "items.h"
19 #include "item_info.h"
20 #include "md5.h"
21 #include "multiplayer.h"
22 #include "particles.h"
23 #include "textures.h"
24 #include "eye_candy_wrapper.h"
25 #include "sound.h"
26
27 #define NUM_BAGS 200
28 #define ITEMS_PER_BAG 50
29
30 typedef struct
31 {
32 int x;
33 int y;
34 int obj_3d_id;
35 #ifdef ONGOING_BAG_EFFECT
36 ec_reference ongoing_bag_effect_reference;
37 #endif // ONGOING_BAG_EFFECT
38 } bag;
39
40 int ground_items_visible_grid_rows = 10;
41 int ground_items_visible_grid_cols = 5;
42 int items_auto_get_all = 0;
43 int view_ground_items=0;
44
45 static ground_item ground_item_list[ITEMS_PER_BAG];
46 static bag bag_list[NUM_BAGS];
47 static int GRIDSIZE = 33;
48 static int ground_items_grid_rows = 10;
49 static int ground_items_grid_cols = 5;
50 static int grid_sep_x = 0;
51 static int grid_sep_y = 0;
52 static const int min_grid_rows = 4;
53 static const int min_grid_cols = 2;
54 static const char *item_desc_str = NULL;
55 static int mouseover_ground_item_pos = -1;
56 static Uint32 ground_items_empty_next_bag=0;
57
58
59 // forward declarations
60 static void draw_pick_up_menu(void);
61 // float get_bag_offset_x(float pos_x, float pos_y, int bag_id, int map_x, int map_y);
62 // float get_bag_offset_y(float pos_x, float pos_y, int bag_id, int map_x, int map_y);
63 static float get_bag_rotation(float pos_x, float pos_y, int bag_id, int map_x, int map_y);
64 static float get_bag_tilt(float pos_x, float pos_y, int bag_id, int map_x, int map_y);
65
strap_word(char * in,char * out)66 void strap_word(char * in, char * out)
67 {
68 int i = 3;
69 while(i--) *out++=*in++;
70 while(*in==' ')in++;
71 *out++='\n';
72 i=3;
73 while(i--) *out++=*in++;
74 *out=0;
75 }
76
77 /*float get_bag_offset_x(float pos_x, float pos_y, int bag_id, int map_x, int map_y)
78 {
79 char str[64];
80 MD5 md5;
81 Uint8 digest[16];
82 memset(digest, 0, 16);
83 safe_snprintf(str, 40, "%f%f%f%f%f", pos_x, pos_y, (float) bag_id,
84 (float) map_x, (float) map_y);
85 MD5Open(&md5);
86 MD5Digest(&md5, str, strlen(str));
87 MD5Close(&md5, digest);
88 // the sum of 5 sin/cos operations can be between -5 and +5
89 // normalize them to -1 ... +1
90 // then divide by 16 to normalize the return value to -0.0625 ... + 0.0625
91 // (a tile is 0.5 wide)
92 return (sinf(powf(digest[0], 2.0f)) + sinf(powf(digest[1], 2.0f)) + sinf(
93 sqrtf(abs((float) digest[2]))) + cosf((float) digest[3]) + sinf(
94 (float) digest[4])) / 80.0f * ((((int) abs(digest[5])) % 3 == 0) ? 1.0f : -1.0f);
95 }*/
96
97 /*float get_bag_offset_y(float pos_x, float pos_y, int bag_id, int map_x, int map_y)
98 {
99 char str[64];
100 MD5 md5;
101 Uint8 digest[16];
102 memset(digest, 0, 16);
103 safe_snprintf(str, 40, "%f%f%f%f%f", pos_x, pos_y, (float) bag_id,
104 (float) map_x, (float) map_y);
105 MD5Open(&md5);
106 MD5Digest(&md5, str, strlen(str));
107 MD5Close(&md5, digest);
108 // the sum of 5 sin/cos operations can be between -5 and +5
109 // normalize them to -1 ... +1
110 // then divide by 16 to normalize the return value to -0.0625 ... + 0.0625
111 // (a tile is 0.5 wide)
112 return (cosf(powf(digest[1], 2.0f)) + cosf(powf(digest[2], 2.0f)) + cosf(
113 sqrtf(abs((float) digest[3]))) + sinf((float) digest[4]) + cosf(
114 (float) digest[5])) / 80.0f * ((((int) abs(digest[6])) % 3 == 0) ? 1.0f : -1.0f);
115 }*/
116
get_bag_rotation(float pos_x,float pos_y,int bag_id,int map_x,int map_y)117 static float get_bag_rotation(float pos_x, float pos_y, int bag_id, int map_x, int map_y)
118 {
119 char str[64];
120 MD5 md5;
121 Uint8 digest[16];
122 memset(digest, 0, 16);
123 safe_snprintf(str, 40, "%f%f%f%f%f", pos_x, pos_y, (float) bag_id,
124 (float) map_x, (float) map_y);
125 MD5Open(&md5);
126 MD5Digest(&md5, str, strlen(str));
127 MD5Close(&md5, digest);
128 // the sum of 5 sin operations can be between -5 and +5
129 // normalize them to -0.5 ... +0.5
130 // multiply with 360 (-180.0 ... +180.0 degrees)
131 return ((sinf(digest[2]) + sinf(digest[3]) + sinf(digest[4]) + sinf(
132 digest[5]) + sinf(digest[6])) / 10.0f) * 360;
133 }
134
get_bag_tilt(float pos_x,float pos_y,int bag_id,int map_x,int map_y)135 static float get_bag_tilt(float pos_x, float pos_y, int bag_id, int map_x, int map_y)
136 {
137 char str[64];
138 MD5 md5;
139 Uint8 digest[16];
140 memset(digest, 0, 16);
141 safe_snprintf(str, 40, "%f%f%f%f%f", pos_x, pos_y, (float) bag_id,
142 (float) map_x, (float) map_y);
143 MD5Open(&md5);
144 MD5Digest(&md5, str, strlen(str));
145 MD5Close(&md5, digest);
146 // the sum of 5 cos operations can be between -5 and +5
147 // normalize them to -1.0 ... +1.0
148 // multiply with 15 (-15.0 ... +15.0 degrees)
149 return ((cosf(digest[3]) + cosf(digest[4]) + cosf(digest[5]) + cosf(
150 digest[6]) + cosf(digest[7])) / 5.0f) * 30;
151 }
152
put_bag_on_ground(int bag_x,int bag_y,int bag_id)153 void put_bag_on_ground(int bag_x,int bag_y,int bag_id)
154 {
155 float x,y,z;
156 int obj_3d_id;
157 #ifdef NEW_SOUND
158 int snd;
159 #endif // NEW_SOUND
160
161 //now, get the Z position
162 if (!get_tile_valid(bag_x, bag_y))
163 {
164 //Warn about this error:
165 LOG_WARNING("A bag was placed OUTSIDE the map!\n");
166 return;
167 }
168
169 z = get_tile_height(bag_x, bag_y);
170 //convert from height values to meters
171 x=(float)bag_x/2;
172 y=(float)bag_y/2;
173 //center the object (slightly randomized)
174 x = x + 0.25f; // + get_bag_offset_x(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y);
175 y = y + 0.25f; // + get_bag_offset_y(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y);
176
177 // DEBUG
178 // printf("bag <%i> (%f,%f) rot %f tilt %f\n", bag_id, x, y,
179 // get_bag_rotation(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y),
180 // get_bag_tilt(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y));
181
182 //Launch the animation
183 if (use_eye_candy) {
184 ec_create_bag_drop(x, y, z, (poor_man ? 6 : 10));
185 #ifdef ONGOING_BAG_EFFECT
186 // start an ongoing effect until the ongoing bag effect is coded
187 bag_list[bag_id].ongoing_bag_effect_reference = ec_create_lamp(x, y, z, 0.0, 1.0, 0.75, (poor_man ? 6 : 10));
188 #endif // ONGOING_BAG_EFFECT
189 }
190 else
191 add_particle_sys_at_tile("./particles/bag_in.part", bag_x, bag_y, 1);
192 #ifdef NEW_SOUND
193 if (your_actor && bag_x == your_actor->x_pos * 2 && bag_y == your_actor->y_pos * 2)
194 {
195 snd = get_sound_index_for_particle_file_name("./particles/bag_in.part");
196 if (snd >= 0)
197 {
198 add_sound_object (snd, bag_x, bag_y, 0);
199 }
200 }
201 #endif // NEW_SOUND
202
203 obj_3d_id=add_e3d("./3dobjects/bag1.e3d", x, y, z,
204 get_bag_tilt(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y), 0,
205 get_bag_rotation(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y),
206 1 ,0 ,1.0f ,1.0f, 1.0f, 1);
207
208 //now, find a place into the bags list, so we can destroy the bag properly
209 bag_list[bag_id].x=bag_x;
210 bag_list[bag_id].y=bag_y;
211 bag_list[bag_id].obj_3d_id=obj_3d_id;
212 }
213
add_bags_from_list(const Uint8 * data)214 void add_bags_from_list (const Uint8 *data)
215 {
216 Uint16 bags_no;
217 int i;
218 int bag_x,bag_y,my_offset; //bag_type unused?
219 float x,y,z;
220 int obj_3d_id, bag_id;
221
222 bags_no=data[0];
223
224 if(bags_no > NUM_BAGS) {
225 return;//something nasty happened
226 }
227
228 for(i=0;i<bags_no;i++) {
229 my_offset=i*5+1;
230 bag_x=SDL_SwapLE16(*((Uint16 *)(data+my_offset)));
231 bag_y=SDL_SwapLE16(*((Uint16 *)(data+my_offset+2)));
232 bag_id=*((Uint8 *)(data+my_offset+4));
233 if(bag_id >= NUM_BAGS) {
234 continue;
235 }
236 //now, get the Z position
237 if (!get_tile_valid(bag_x, bag_y))
238 {
239 //Warn about this error!
240 LOG_WARNING("A bag was located OUTSIDE the map!\n");
241 continue;
242 }
243
244 z = get_tile_height(bag_x, bag_y);
245 //convert from height values to meters
246 x=(float)bag_x/2;
247 y=(float)bag_y/2;
248 //center the object (slightly randomized)
249 x = x + 0.25f; // + get_bag_offset_x(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y);
250 y = y + 0.25f; // + get_bag_offset_y(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y);
251
252 // DEBUG
253 LOG_DEBUG_VERBOSE("bag <%i> (%f,%f) rot %f tilt %f\n", bag_id, x, y,
254 get_bag_rotation(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y),
255 get_bag_tilt(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y));
256
257 if (use_eye_candy) {
258 #ifdef ONGOING_BAG_EFFECT
259 // start an ongoing effect until the ongoing bag effect is coded
260 bag_list[bag_id].ongoing_bag_effect_reference = ec_create_lamp(x, y, z, 0.0, 1.0, 0.75, (poor_man ? 6 : 10));
261 #endif // ONGOING_BAG_EFFECT
262 }
263
264 // Now, find a place into the bags list, so we can destroy the bag properly
265 if (bag_list[bag_id].obj_3d_id != -1) {
266 char buf[256];
267 // oops, slot already taken!
268 safe_snprintf(buf, sizeof(buf), "Oops, trying to add an existing bag! id=%d\n", bag_id);
269 LOG_ERROR(buf);
270 return;
271 }
272
273 obj_3d_id = add_e3d("./3dobjects/bag1.e3d", x, y, z,
274 get_bag_tilt(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y), 0,
275 get_bag_rotation(bag_x, bag_y, bag_id, tile_map_size_x, tile_map_size_y),
276 1, 0, 1.0f, 1.0f, 1.0f, 1);
277 bag_list[bag_id].x=bag_x;
278 bag_list[bag_id].y=bag_y;
279 bag_list[bag_id].obj_3d_id=obj_3d_id;
280 }
281 }
282
remove_item_from_ground(Uint8 pos)283 void remove_item_from_ground(Uint8 pos)
284 {
285 if (pos < ITEMS_PER_BAG)
286 ground_item_list[pos].quantity= 0;
287 }
288
remove_bag(int bag_id)289 void remove_bag(int bag_id)
290 {
291 #ifdef NEW_SOUND
292 int snd;
293 #endif // NEW_SOUND
294
295 if (bag_id >= NUM_BAGS) return;
296
297 if (bag_list[bag_id].obj_3d_id == -1) {
298 // oops, no bag in that slot!
299 LOG_ERROR("Oops, double-removal of bag!\n");
300 return;
301 }
302
303 if (use_eye_candy) {
304 ec_create_bag_pickup(objects_list[bag_list[bag_id].obj_3d_id]->x_pos, objects_list[bag_list[bag_id].obj_3d_id]->y_pos, objects_list[bag_list[bag_id].obj_3d_id]->z_pos, (poor_man ? 6 : 10));
305 #ifdef ONGOING_BAG_EFFECT
306 if (bag_list[bag_id].ongoing_bag_effect_reference != NULL) {
307 ec_recall_effect(bag_list[bag_id].ongoing_bag_effect_reference);
308 bag_list[bag_id].ongoing_bag_effect_reference = NULL;
309 }
310 #endif // ONGOING_BAG_EFFECT
311 }
312 else
313 add_particle_sys_at_tile ("./particles/bag_out.part", bag_list[bag_id].x, bag_list[bag_id].y, 1);
314 #ifdef NEW_SOUND
315 if (your_actor && bag_list[bag_id].x == your_actor->x_pos * 2 && bag_list[bag_id].y == your_actor->y_pos * 2)
316 {
317 snd = get_sound_index_for_particle_file_name("./particles/bag_out.part");
318 if (snd >= 0)
319 {
320 add_sound_object (snd, bag_list[bag_id].x, bag_list[bag_id].y, 0);
321 }
322 }
323 #endif // NEW_SOUND
324
325 destroy_3d_object(bag_list[bag_id].obj_3d_id);
326 bag_list[bag_id].obj_3d_id=-1;
327 }
328
remove_all_bags(void)329 void remove_all_bags(void){
330 int i;
331
332 for(i=0; i<NUM_BAGS; i++){ // clear bags list!!!!
333 bag_list[i].obj_3d_id= -1;
334 }
335 }
336
337
clear_groundlist(void)338 static int clear_groundlist(void)
339 {
340 int i;
341 for(i = 0; i < ITEMS_PER_BAG; i++) {
342 ground_item_list[i].quantity = 0;
343 }
344 return 1;
345 }
346
find_and_open_closest_bag(int tile_x,int tile_y,float max_distance)347 int find_and_open_closest_bag(int tile_x, int tile_y, float max_distance)
348 {
349 int i;
350 int found_bag = -1;
351 float x = tile_x;
352 float y = tile_y;
353
354 float distance;
355 float min_distance_found = 50;
356
357 for(i=0; i<NUM_BAGS; i++)
358 if(bag_list[i].obj_3d_id != -1)
359 {
360 distance = sqrt(((float)bag_list[i].x - x) * ((float)bag_list[i].x - x) + ((float)bag_list[i].y - y) * ((float)bag_list[i].y - y));
361 if (distance < max_distance)
362 if (distance < min_distance_found)
363 {
364 found_bag = i;
365 min_distance_found = distance;
366 }
367 }
368
369 if (found_bag != -1)
370 {
371 Uint8 str[4];
372 str[0]= INSPECT_BAG;
373 str[1]= found_bag;
374 my_tcp_send(my_socket,str, 2);
375 return 1;
376 }
377
378 return 0;
379 }
380
open_bag(int object_id)381 void open_bag(int object_id)
382 {
383 int i;
384 Uint8 str[4];
385 for(i=0;i<NUM_BAGS;i++){
386 if(bag_list[i].obj_3d_id==object_id){
387 str[0]= INSPECT_BAG;
388 str[1]= i;
389 my_tcp_send(my_socket,str,2);
390 return;
391 }
392 }
393 }
394
395 //do the flags later on
get_bag_item(const Uint8 * data)396 void get_bag_item (const Uint8 *data)
397 {
398 int pos;
399 pos= data[6];
400
401 if (pos >= ITEMS_PER_BAG) return;
402
403 ground_item_list[pos].image_id= SDL_SwapLE16(*((Uint16 *)(data)));
404 ground_item_list[pos].quantity= SDL_SwapLE32(*((Uint32 *)(data+2)));
405 ground_item_list[pos].id= unset_item_uid;
406 ground_item_list[pos].pos= pos;
407 }
408
409
pick_up_all_items(void)410 static void pick_up_all_items(void)
411 {
412 Uint8 str[20];
413 int itempos;
414 for(itempos = 0; itempos < ITEMS_PER_BAG; itempos++){
415 if(ground_item_list[itempos].quantity){
416 str[0]=PICK_UP_ITEM;
417 str[1]=itempos;
418 *((Uint32 *)(str+2))=SDL_SwapLE32(ground_item_list[itempos].quantity);
419 my_tcp_send(my_socket,str,6);
420 }
421 }
422 }
423
items_get_bag(int x,int y)424 void items_get_bag(int x, int y)
425 {
426 int pos;
427 for(pos=0;pos<NUM_BAGS;pos++)
428 {
429 if(bag_list[pos].x != 0 && bag_list[pos].y != 0 &&
430 bag_list[pos].x == x && bag_list[pos].y == y)
431 {
432 if(get_show_window_MW(MW_BAGS))
433 pick_up_all_items();
434 else
435 {
436 // if auto empty bags enable, set the open timer
437 if (items_auto_get_all)
438 ground_items_empty_next_bag = SDL_GetTicks();
439 else
440 ground_items_empty_next_bag = 0;
441 open_bag(bag_list[pos].obj_3d_id);
442 }
443 break; //we should only stand on one bag
444 }
445 }
446 }
447
448 //put the flags later on
get_bags_items_list(const Uint8 * data)449 void get_bags_items_list (const Uint8 *data)
450 {
451 Uint16 items_no;
452 int i;
453 int pos;
454 int my_offset;
455
456 view_ground_items=1;
457 //clear the list
458 clear_groundlist();
459
460 items_no = data[0];
461 if(items_no > ITEMS_PER_BAG) {
462 return;
463 }
464
465 for(i=0;i<items_no;i++) {
466 my_offset= i*7+1;
467 pos= data[my_offset+6];
468 ground_item_list[pos].image_id= SDL_SwapLE16(*((Uint16 *)(data+my_offset)));
469 ground_item_list[pos].quantity= SDL_SwapLE32(*((Uint32 *)(data+my_offset+2)));
470 ground_item_list[pos].id= unset_item_uid;
471 ground_item_list[pos].pos= pos;
472 }
473
474 // If we have auto bag empting set, only do so within 1 second of pressing getall
475 if (ground_items_empty_next_bag) {
476 if ((SDL_GetTicks() - ground_items_empty_next_bag) < 1000)
477 pick_up_all_items();
478 ground_items_empty_next_bag = 0;
479 }
480
481 // Open and display the bag even if we have sent the server messages to
482 // empty. Because if we can't carry the load the window needs to be shown.
483
484 draw_pick_up_menu();
485 if(item_window_on_drop) {
486 display_items_menu();
487 }
488 }
489
pre_display_ground_items_handler(window_info * win)490 static int pre_display_ground_items_handler(window_info *win)
491 {
492 glEnable(GL_TEXTURE_2D);
493 if (item_desc_str != NULL)
494 {
495 show_help(item_desc_str, 0, win->len_y+10, win->current_scale);
496 item_desc_str = NULL;
497 }
498 return 1;
499 }
500
display_ground_items_handler(window_info * win)501 static int display_ground_items_handler(window_info *win)
502 {
503 char str[80];
504 char my_str[10];
505 int i;
506 static Uint8 resizing = 0;
507 int yoffset = get_window_scroll_pos(win->window_id);
508 int but_text_y;
509
510 /* if resizing wait until we stop */
511 if (win->resized)
512 resizing = 1;
513 /* once we stop, snap the window to the new grid size */
514 else if (resizing)
515 {
516 int new_width = grid_sep_x + (ground_items_grid_cols + 1) * GRIDSIZE;
517 int new_rows = (win->len_y - 2 * grid_sep_y + GRIDSIZE / 2) / GRIDSIZE;
518 int max_rows = (ITEMS_PER_BAG + ground_items_grid_cols - 1) / ground_items_grid_cols;
519 resizing = 0;
520 resize_window (win->window_id, new_width, 2 * grid_sep_y + ((new_rows > max_rows) ?max_rows :new_rows) * GRIDSIZE);
521 yoffset = get_window_scroll_pos(win->window_id);
522 }
523
524 glEnable(GL_TEXTURE_2D);
525
526 // write "get all" in the "get all" box :)
527 strap_word(get_all_str,my_str);
528 glColor3fv(gui_color);
529 but_text_y = (int)(0.5 + ((GRIDSIZE - (float)(2 * win->small_font_len_y)) / 2.0));
530 draw_string_small_zoomed_centered(win->len_x-GRIDSIZE/2, win->box_size+but_text_y+yoffset, (unsigned char*)my_str, 2, win->current_scale);
531
532 glColor3f(1.0f,1.0f,1.0f);
533 //ok, now let's draw the objects...
534 for(i=ITEMS_PER_BAG-1; i>=0; --i) {
535 if(ground_item_list[i].quantity > 0) {
536 float u_start,v_start,u_end,v_end;
537 int this_texture,cur_item,cur_pos;
538 int x_start,x_end,y_start,y_end;
539 int use_large = (mouseover_ground_item_pos == i) && enlarge_text();
540
541 //get the UV coordinates.
542 cur_item=ground_item_list[i].image_id%25;
543 get_item_uv(cur_item, &u_start, &v_start, &u_end, &v_end);
544
545 //get the x and y
546 cur_pos=i;
547 x_start = grid_sep_x + GRIDSIZE * (cur_pos % ground_items_grid_cols) + 1;
548 x_end=x_start+GRIDSIZE-1;
549 y_start = grid_sep_y + + GRIDSIZE * (cur_pos / ground_items_grid_cols);
550 y_end=y_start+GRIDSIZE-1;
551
552 //get the texture this item belongs to
553 this_texture=get_items_texture(ground_item_list[i].image_id/25);
554 bind_texture(this_texture);
555
556 glBegin(GL_QUADS);
557 draw_2d_thing(u_start,v_start,u_end,v_end,x_start,y_start,x_end,y_end);
558 glEnd();
559
560 safe_snprintf(str,sizeof(str),"%i",ground_item_list[i].quantity);
561 y_end -= ((i & 1) ?GRIDSIZE-1 : ((use_large) ?win->default_font_len_y :win->small_font_len_y));
562 if (use_large)
563 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);
564 else
565 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);
566 }
567 }
568 mouseover_ground_item_pos = -1;
569
570 // Render the grid *after* the images. It seems impossible to code
571 // it such that images are rendered exactly within the boxes on all
572 // cards
573 glDisable(GL_TEXTURE_2D);
574
575 glColor3fv(gui_color);
576 /* if a full grid render in one go */
577 if (ground_items_grid_cols*ground_items_grid_rows == ITEMS_PER_BAG)
578 rendergrid(ground_items_grid_cols, ground_items_grid_rows, grid_sep_x, grid_sep_y, GRIDSIZE, GRIDSIZE);
579 /* otherwise don't render the extra slots */
580 else
581 {
582 int remainder = ITEMS_PER_BAG - (ground_items_grid_cols*(ground_items_grid_rows-1));
583 rendergrid(ground_items_grid_cols, ground_items_grid_rows - 1, grid_sep_x, grid_sep_y, GRIDSIZE, GRIDSIZE);
584 rendergrid(remainder, 1, grid_sep_x, grid_sep_y + GRIDSIZE*(ground_items_grid_rows-1), GRIDSIZE, GRIDSIZE);
585 }
586
587 glBegin(GL_LINE_LOOP);
588
589 // draw the "get all" box
590 glVertex2i(win->len_x, win->box_size + yoffset);
591 glVertex2i(win->len_x - GRIDSIZE, win->box_size + yoffset);
592 glVertex2i(win->len_x - GRIDSIZE, win->box_size + GRIDSIZE + yoffset);
593 glVertex2i(win->len_x, win->box_size + GRIDSIZE + yoffset);
594
595 glEnd();
596 glEnable(GL_TEXTURE_2D);
597 #ifdef OPENGL_TRACE
598 CHECK_GL_ERRORS();
599 #endif //OPENGL_TRACE
600 return 1;
601 }
602
603
click_ground_items_handler(window_info * win,int mx,int my,Uint32 flags)604 static int click_ground_items_handler(window_info *win, int mx, int my, Uint32 flags)
605 {
606 int pos;
607 Uint8 str[10];
608 int right_click = flags & ELW_RIGHT_MOUSE;
609 int ctrl_on = flags & KMOD_CTRL;
610 int yoffset = get_window_scroll_pos(win->window_id);
611
612 // only handle mouse button clicks, not scroll wheels moves
613 if ( (flags & ELW_MOUSE_BUTTON) == 0) {
614 return 0;
615 }
616
617 if(right_click) {
618 if(item_dragged != -1) {
619 item_dragged = -1;
620 return 1;
621 } else if(is_gamewin_look_action()) {
622 clear_gamewin_look_action();
623 return 1;
624 }
625 }
626
627 // see if we clicked on the "Get All" box
628 if(mx>(win->len_x-GRIDSIZE) && mx<win->len_x && my>win->box_size && my<GRIDSIZE+win->box_size){
629 pick_up_all_items();
630 do_get_item_sound();
631 return 1;
632 }
633
634 pos = (my<0) ?-1 :get_mouse_pos_in_grid(mx, my + yoffset + 1,
635 ground_items_grid_cols, ground_items_grid_rows, grid_sep_x, grid_sep_y, GRIDSIZE, GRIDSIZE);
636
637 if(pos==-1 || pos>=ITEMS_PER_BAG){
638 } else
639 if(!ground_item_list[pos].quantity) {
640 if (item_dragged != -1){
641 str[0] = DROP_ITEM;
642 str[1] = item_dragged;
643 *((Uint32 *) (str + 2)) = SDL_SwapLE32(item_quantity);
644 my_tcp_send(my_socket, str, 6);
645 do_drop_item_sound();
646 }
647 } else if(right_click || is_gamewin_look_action()) {
648 str[0]= LOOK_AT_GROUND_ITEM;
649 str[1]= ground_item_list[pos].pos;
650 my_tcp_send(my_socket,str,2);
651 } else {
652 int quantity;
653 quantity= ground_item_list[pos].quantity;
654 if(quantity > item_quantity && !ctrl_on) quantity= item_quantity;
655
656 str[0]= PICK_UP_ITEM;
657 str[1]= ground_item_list[pos].pos;
658 *((Uint32 *)(str+2))= SDL_SwapLE32(quantity);
659 my_tcp_send(my_socket,str,6);
660 do_get_item_sound();
661 }
662
663 return 1;
664 }
665
666
mouseover_ground_items_handler(window_info * win,int mx,int my)667 static int mouseover_ground_items_handler(window_info *win, int mx, int my) {
668 int yoffset = get_window_scroll_pos(win->window_id);
669 int pos = (yoffset>my) ?-1 :get_mouse_pos_in_grid(mx, my + 1, ground_items_grid_cols,
670 ground_items_grid_rows, grid_sep_x, grid_sep_y, GRIDSIZE, GRIDSIZE);
671
672 if(pos!=-1 && pos<ITEMS_PER_BAG && ground_item_list[pos].quantity) {
673 Uint16 item_id = ground_item_list[pos].id;
674 int image_id = ground_item_list[pos].image_id;
675 if (show_item_desc_text && item_info_available() && (get_item_count(item_id, image_id) == 1))
676 item_desc_str = get_item_description(item_id, image_id);
677 if(is_gamewin_look_action()) {
678 elwin_mouse=CURSOR_EYE;
679 } else {
680 elwin_mouse=CURSOR_PICK;
681 }
682 mouseover_ground_item_pos = pos;
683 return 1;
684 }
685
686 return 0;
687 }
688
689 /* dynamically adjust the grid and the scroll bar when the window resizes */
resize_ground_items_handler(window_info * win,int width,int height)690 static int resize_ground_items_handler(window_info *win, int width, int height)
691 {
692 ground_items_visible_grid_cols = ((win->len_x - grid_sep_x) / GRIDSIZE) - 1;
693 ground_items_visible_grid_rows = ((win->len_y - 2 * grid_sep_y) / GRIDSIZE);
694
695 /* let the width lead */
696 ground_items_grid_cols = ground_items_visible_grid_cols;
697 if (ground_items_grid_cols < min_grid_cols)
698 ground_items_grid_cols = min_grid_cols;
699
700 /* but maintain a minimum height */
701 ground_items_grid_rows = (ITEMS_PER_BAG + ground_items_grid_cols - 1) / ground_items_grid_cols;
702 if (ground_items_grid_rows <= min_grid_rows)
703 {
704 ground_items_grid_rows = min_grid_rows;
705 ground_items_grid_cols = min_grid_cols;
706 while (ground_items_grid_cols*ground_items_grid_rows < ITEMS_PER_BAG)
707 ground_items_grid_cols++;
708 }
709
710 set_window_scroll_len(win->window_id, ground_items_grid_rows * GRIDSIZE + 2 * grid_sep_y - win->len_y);
711 return 0;
712 }
713
ui_scale_ground_items_handler(window_info * win)714 static int ui_scale_ground_items_handler(window_info * win)
715 {
716 int current_scroll_pos = get_window_scroll_pos(win->window_id) / (GRIDSIZE/3);
717 if (ground_items_visible_grid_cols < min_grid_cols || ground_items_visible_grid_cols >= ITEMS_PER_BAG ||
718 ground_items_visible_grid_rows < min_grid_rows || ground_items_visible_grid_rows >= ITEMS_PER_BAG)
719 {
720 ground_items_visible_grid_cols = 5;
721 ground_items_visible_grid_rows = 10;
722 }
723 GRIDSIZE = (int)(0.5 + 33 * win->current_scale);
724 grid_sep_x = (int)(0.5 + 2 * win->current_scale);
725 grid_sep_y = (int)(0.5 + 2 * win->current_scale);
726 set_window_min_size(win->window_id, grid_sep_x + (min_grid_cols + 1) * GRIDSIZE, 2 * grid_sep_y + min_grid_rows * GRIDSIZE);
727 set_window_scroll_inc(win->window_id, GRIDSIZE/3);
728 set_window_scroll_yoffset(win->window_id, GRIDSIZE);
729 set_window_scroll_pos(win->window_id, current_scroll_pos * GRIDSIZE/3);
730 resize_window(win->window_id, grid_sep_x + (ground_items_visible_grid_cols + 1) * GRIDSIZE,
731 2 * grid_sep_y + ground_items_visible_grid_rows * GRIDSIZE);
732 return 1;
733 }
734
server_close_bag(void)735 void server_close_bag(void)
736 {
737 hide_window_MW(MW_BAGS);
738 clear_groundlist();
739 clear_was_open_MW(MW_BAGS);
740 }
741
client_close_bag(void)742 void client_close_bag(void)
743 {
744 const unsigned char protocol_close_bag = S_CLOSE_BAG;
745 my_tcp_send(my_socket, &protocol_close_bag, 1);
746 server_close_bag();
747 }
748
close_handler(window_info * win)749 static int close_handler(window_info *win)
750 {
751 client_close_bag();
752 return 1;
753 }
754
draw_pick_up_menu(void)755 static void draw_pick_up_menu(void)
756 {
757 int ground_items_win = get_id_MW(MW_BAGS);
758
759 if(ground_items_win < 0){
760 ground_items_win = create_window(win_bag, (not_on_top_now(MW_BAGS) ?game_root_win : -1), 0, get_pos_x_MW(MW_BAGS), get_pos_y_MW(MW_BAGS),
761 0, 0, ELW_USE_UISCALE|ELW_SCROLLABLE|ELW_RESIZEABLE|ELW_WIN_DEFAULT);
762 set_id_MW(MW_BAGS, ground_items_win);
763
764 set_window_custom_scale(ground_items_win, MW_BAGS);
765 set_window_handler(ground_items_win, ELW_HANDLER_DISPLAY, &display_ground_items_handler );
766 set_window_handler(ground_items_win, ELW_HANDLER_PRE_DISPLAY, &pre_display_ground_items_handler );
767 set_window_handler(ground_items_win, ELW_HANDLER_CLICK, &click_ground_items_handler );
768 set_window_handler(ground_items_win, ELW_HANDLER_MOUSEOVER, &mouseover_ground_items_handler );
769 set_window_handler(ground_items_win, ELW_HANDLER_RESIZE, &resize_ground_items_handler );
770 set_window_handler(ground_items_win, ELW_HANDLER_CLOSE, &close_handler );
771 set_window_handler(ground_items_win, ELW_HANDLER_UI_SCALE, &ui_scale_ground_items_handler );
772
773 if (ground_items_win >=0 && ground_items_win < windows_list.num_windows)
774 ui_scale_ground_items_handler(&windows_list.window[ground_items_win]);
775 else
776 return;
777 check_proportional_move(MW_BAGS);
778
779 } else {
780 show_window(ground_items_win);
781 select_window(ground_items_win);
782 }
783 set_window_scroll_pos(ground_items_win, 0);
784 }
785