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