Atrinik Client  4.0
inventory.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/string.h>
34 
39 
44  "applied", "container", "magical", "cursed", "unidentified", "unapplied",
45  "locked"
46 };
47 
55 static int inventory_matches_filter(object *op)
56 {
57  /* No filtering of objects in the below inventory or in a sack. */
58  if (op->env == cpl.below || op->env == cpl.sack) {
59  return 1;
60  }
61 
62  /* Never show spell/skill/force objects in the inventory. */
63  if (op->itype == TYPE_SPELL || op->itype == TYPE_SKILL ||
64  op->itype == TYPE_FORCE || op->itype == TYPE_POISONING ||
65  op->itype == TYPE_REGION_MAP) {
66  return 0;
67  }
68 
70  return 1;
71  }
72 
74  op->flags & CS_FLAG_APPLIED) {
75  return 1;
76  }
77 
79  op->itype == TYPE_CONTAINER) {
80  return 1;
81  }
82 
84  op->flags & CS_FLAG_IS_MAGICAL) {
85  return 1;
86  }
87 
89  op->flags & (CS_FLAG_CURSED | CS_FLAG_DAMNED)) {
90  return 1;
91  }
92 
94  op->item_qua == 255) {
95  return 1;
96  }
97 
99  !(op->flags & CS_FLAG_APPLIED)) {
100  return 1;
101  }
102 
104  op->flags & CS_FLAG_LOCKED) {
105  return 1;
106  }
107 
108  return 0;
109 }
110 
116 void inventory_filter_set(uint64_t filter)
117 {
118  widgetdata *widget = widget_find(NULL, INVENTORY_ID, "main", NULL);
119  SOFT_ASSERT(widget != NULL, "Could not find widget");
120 
121  inventory_filter = filter;
122  widget_inventory_handle_arrow_key(widget, SDLK_UNKNOWN);
123  widget->redraw = 1;
124  draw_info(COLOR_GREEN, "Inventory filter changed.");
125 }
126 
132 void inventory_filter_toggle(uint64_t filter)
133 {
134  widgetdata *widget = widget_find(NULL, INVENTORY_ID, "main", NULL);
135  SOFT_ASSERT(widget != NULL, "Could not find widget");
136 
137  if (inventory_filter & filter) {
138  inventory_filter &= ~filter;
139  } else {
140  inventory_filter |= filter;
141  }
142 
143  widget_inventory_handle_arrow_key(widget, SDLK_UNKNOWN);
144  widget->redraw = 1;
145  draw_info(COLOR_GREEN, "Inventory filter changed.");
146 }
147 
153 void inventory_filter_set_names(const char *filter)
154 {
155  widgetdata *widget = widget_find(NULL, INVENTORY_ID, "main", NULL);
156  SOFT_ASSERT(widget != NULL, "Could not find widget");
157 
159 
160  char word[MAX_BUF];
161  size_t pos = 0;
162  while (string_get_word(filter, &pos, ' ', word, sizeof(word), 0)) {
163  for (size_t i = 0; i < INVENTORY_FILTER_MAX; i++) {
164  if (strcmp(inventory_filter_names[i], word) == 0) {
165  inventory_filter |= 1 << i;
166  break;
167  }
168  }
169  }
170 
171  widget_inventory_handle_arrow_key(widget, SDLK_UNKNOWN);
172  widget->redraw = 1;
173  draw_info(COLOR_GREEN, "Inventory filter changed.");
174 }
175 
196 static int inventory_render_object(widgetdata *widget, object *ob, uint32_t i,
197  uint32_t *r, int mx, int my)
198 {
199  inventory_struct *inventory;
200  uint32_t row, r_row, r_col;
201  int x, y;
202  char buf[HUGE_BUF];
203  SDL_Rect box;
204 
205  inventory = INVENTORY(widget);
206  row = i / INVENTORY_COLS(inventory);
207 
208  if (mx != -1 && my != -1) {
209  mx -= widget->x;
210  my -= widget->y;
211  }
212 
213  /* Check if this object should be visible. */
214  if (row < inventory->scrollbar_info.scroll_offset ||
215  row >= inventory->scrollbar_info.scroll_offset +
216  INVENTORY_ROWS(inventory)) {
217  return 0;
218  }
219 
220  /* Calculate the row and column to render on. */
221  r_row = *r / INVENTORY_COLS(inventory);
222  r_col = *r % INVENTORY_COLS(inventory);
223 
224  /* Calculate the X/Y positions. */
225  x = inventory->x + r_col * INVENTORY_ICON_SIZE;
226  y = inventory->y + r_row * INVENTORY_ICON_SIZE;
227 
228  /* Increase the rendering index. */
229  *r += 1;
230 
231  /* If 'mx' and 'my' are not -1, do not render, just check if the
232  * provided coordinates are over the object. */
233  if (mx != -1 && my != -1) {
234  if (mx >= x && mx < x + INVENTORY_ICON_SIZE &&
235  my >= y && my < y + INVENTORY_ICON_SIZE) {
236  return 1;
237  } else {
238  return 0;
239  }
240  }
241 
242  object_show_inventory(widget->surface, ob, x, y);
243 
244  /* If this object is selected, show the selected graphic. */
245  if (i == inventory->selected) {
246  surface_show(widget->surface, x, y, NULL, TEXTURE_CLIENT(
247  cpl.inventory_focus == widget ? "invslot" : "invslot_u"));
248  }
249 
250  /* If the object is marked, show that. */
251  if (ob->tag != 0 && ob->tag == cpl.mark_count) {
252  surface_show(widget->surface, x, y, NULL,
253  TEXTURE_CLIENT("invslot_marked"));
254  }
255 
256  /* If it's the currently open container, add the 'container
257  * start' graphic. */
258  if (ob == cpl.sack) {
259  surface_show(widget->surface, x, y, NULL,
260  TEXTURE_CLIENT("cmark_start"));
261  } else if (ob->env == cpl.sack) {
262  /* Object inside the open container... */
263 
264  /* If there is still something more in the container, show the
265  * 'object in the middle of container' graphic. */
266  if (ob->next) {
267  surface_show(widget->surface, x, y, NULL,
268  TEXTURE_CLIENT("cmark_middle"));
269  } else {
270  /* The end, show the 'end of container' graphic instead. */
271  surface_show(widget->surface, x, y, NULL,
272  TEXTURE_CLIENT("cmark_end"));
273  }
274  }
275 
276  /* Only show extra information for the selected object. */
277  if (i != inventory->selected) {
278  return 1;
279  }
280 
281  int alpha = 255;
282  if (cpl.inventory_focus != widget) {
283  alpha /= 2;
284  }
285  snprintf(VS(buf), "[alpha=%d][center]", alpha);
286 
287  /* Construct the name */
288  if (ob->nrof > 1) {
289  snprintfcat(VS(buf), "%" PRIu32 " %s", ob->nrof, ob->s_name);
290  } else {
291  snprintfcat(VS(buf), "%s", ob->s_name);
292  }
293 
294  snprintfcat(VS(buf), "[/center]\n");
295 
296  /* Extra information for items in the player's inventory */
297  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
298  char filter[MAX_BUF];
299 
300  /* Item quality of 255 marks unidentified items */
301  if (ob->item_qua == 255) {
302  snprintfcat(VS(buf), "[red]not identified[/red]");
303  } else {
304  snprintfcat(VS(buf), "Con: %d/%d", ob->item_con, ob->item_qua);
305 
306  /* Show item's level and required skill */
307  if (ob->item_level) {
308  object *skill;
309  size_t skill_id;
310  int level;
311  char buf2[MAX_BUF];
312 
313  if (ob->item_skill_tag &&
314  (skill = object_find(ob->item_skill_tag)) &&
315  skill_find_object(skill, &skill_id)) {
316  level = skill_get(skill_id)->level;
317  snprintf(VS(buf2), "level %d %s", ob->item_level,
318  skill->s_name);
319  } else {
320  level = cpl.stats.level;
321  snprintf(VS(buf2), "level %d", ob->item_level);
322  }
323 
324  /* If the player or the player's skill level is too low,
325  * show the required level in red to indicate that. */
326  if (ob->item_level > level) {
327  snprintfcat(VS(buf), " [red]%s[/red]", buf2);
328  } else {
329  snprintfcat(VS(buf), " %s", buf2);
330  }
331  }
332  }
333 
334  /* Item's weight */
335  snprintfcat(VS(buf), " [right]%4.3f kg[/right]\n",
336  ob->weight * (double) ob->nrof);
337 
338  /* No active filter, show "all". */
340  snprintf(filter, sizeof(filter), "all");
341  } else {
342  size_t filter_num;
343 
344  *filter = '\0';
345 
346  /* Construct a string of active filters. Only the first active
347  * filter will be shown, and if there are any more active filters,
348  * ellipsis will be appended. */
349  for (filter_num = 0; filter_num < INVENTORY_FILTER_MAX;
350  filter_num++) {
351  if (inventory_filter & (1 << filter_num)) {
352  if (*filter == '\0') {
353  snprintf(filter, sizeof(filter), "%s",
354  inventory_filter_names[filter_num]);
355  } else {
356  snprintfcat(filter, sizeof(filter), ", ...");
357  break;
358  }
359  }
360  }
361  }
362 
363  /* Append the active filter(s) and carrying capacity of the player */
364  snprintfcat(VS(buf),
365  "Showing: %s [right]Carrying: %4.3f/%4.3f kg[/right]", filter,
367  }
368 
369  snprintfcat(VS(buf), "\n[/alpha]");
370 
371  box.w = widget->w - 4 * 2;
372  box.h = widget->h - inventory->h - 2 * 2;
373 
374  text_show(widget->surface, FONT_ARIAL11, buf, 4, 2, COLOR_HGOLD,
375  TEXT_MARKUP, &box);
376 
377  return 1;
378 }
379 
381 static void event_drag_cb(void)
382 {
383  object *dragging;
384 
385  dragging = object_find(cpl.dragging_tag);
386  SOFT_ASSERT(dragging != NULL, "Not dragging anything!");
387 
388  if (dragging->env == cpl.ob || (cpl.sack != NULL &&
389  cpl.sack->env == cpl.ob)) {
390  widgetdata *widget = widget_find(NULL, INVENTORY_ID, "main", NULL);
391  SOFT_ASSERT(widget != NULL, "Could not find widget");
392  menu_inventory_drop(widget, NULL, NULL);
393  } else {
394  widgetdata *widget = widget_find(NULL, INVENTORY_ID, "below", NULL);
395  SOFT_ASSERT(widget != NULL, "Could not find widget");
396  menu_inventory_get(widget, NULL, NULL);
397  }
398 }
399 
401 static void widget_draw(widgetdata *widget)
402 {
403  inventory_struct *inventory;
404  int w, h;
405  object *tmp, *tmp2;
406  uint32_t i, r;
407 
408  if (!widget->redraw) {
409  return;
410  }
411 
412  inventory = INVENTORY(widget);
413 
414  if (inventory->display == INVENTORY_DISPLAY_NONE) {
415  if (strcmp(widget->id, "main") == 0) {
416  inventory->display = INVENTORY_DISPLAY_MAIN;
417  inventory->x = 3;
418  inventory->y = 44;
419  } else if (strcmp(widget->id, "below") == 0) {
420  inventory->display = INVENTORY_DISPLAY_BELOW;
421  inventory->x = 5;
422  inventory->y = 19;
423  }
424  }
425 
426  w = MAX(widget->w - inventory->x * 2 - 9, INVENTORY_ICON_SIZE);
427  h = MAX(widget->h - inventory->y - inventory->x, INVENTORY_ICON_SIZE);
428 
429  if (inventory->w != w || inventory->h != h) {
430  char buf[MAX_BUF];
431 
432  inventory->w = w;
433  inventory->h = h;
434 
435  scrollbar_create(&inventory->scrollbar, 9, inventory->h,
436  &inventory->scrollbar_info.scroll_offset,
437  &inventory->scrollbar_info.num_lines,
438  INVENTORY_ROWS(inventory));
439  inventory->scrollbar.redraw = &inventory->scrollbar_info.redraw;
440 
441  texture_delete(inventory->texture);
442  snprintf(buf, sizeof(buf),
443  "rectangle:%d,%d;[bar=inventory_bg][border=widget_border]",
444  inventory->w + 1 * 2 + inventory->scrollbar.background.w,
445  inventory->h + 1 * 2);
446  inventory->texture = texture_get(TEXTURE_TYPE_SOFTWARE, buf);
447  }
448 
449  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
450  /* Recalculate the weight, as it may have changed. */
451  cpl.real_weight = 0.0;
452 
453  for (tmp = INVENTORY_WHERE(inventory)->inv; tmp; tmp = tmp->next) {
454  if (!inventory_matches_filter(tmp)) {
455  continue;
456  }
457 
458  cpl.real_weight += tmp->weight * (double) tmp->nrof;
459  }
460 
461  surface_show(widget->surface, inventory->x - 1, inventory->y - 1, NULL,
462  texture_surface(inventory->texture));
463  } else if (inventory->display == INVENTORY_DISPLAY_BELOW) {
464  surface_show(widget->surface, inventory->x - 1, inventory->y - 1, NULL,
465  texture_surface(inventory->texture));
466  }
467 
468  widget_inventory_handle_arrow_key(widget, SDLK_UNKNOWN);
469 
470  for (i = 0, r = 0, tmp = INVENTORY_WHERE(inventory)->inv; tmp;
471  tmp = tmp->next) {
472  if (!inventory_matches_filter(tmp)) {
473  continue;
474  }
475 
476  inventory_render_object(widget, tmp, i, &r, -1, -1);
477  i++;
478 
479  if (cpl.sack == tmp) {
480  for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->next) {
481  if (!inventory_matches_filter(tmp2)) {
482  continue;
483  }
484 
485  inventory_render_object(widget, tmp2, i, &r, -1, -1);
486  i++;
487  }
488  }
489  }
490 
491  inventory->scrollbar.px = widget->x;
492  inventory->scrollbar.py = widget->y;
493  scrollbar_show(&inventory->scrollbar, widget->surface,
494  inventory->x + inventory->w, inventory->y);
495 }
496 
498 static int widget_event(widgetdata *widget, SDL_Event *event)
499 {
500  inventory_struct *inventory;
501 
502  inventory = INVENTORY(widget);
503 
504  if (scrollbar_event(&inventory->scrollbar, event)) {
505  widget->redraw = 1;
506 
507  if (inventory->scrollbar_info.redraw) {
508  inventory->selected = *inventory->scrollbar.scroll_offset *
509  INVENTORY_COLS(inventory);
510  inventory->scrollbar_info.redraw = 0;
511  }
512 
513  return 1;
514  }
515 
516  if (event->type == SDL_MOUSEBUTTONDOWN) {
517  if (event->button.button == SDL_BUTTON_WHEELUP) {
518  widget_inventory_handle_arrow_key(widget, SDLK_UP);
519  return 1;
520  } else if (event->button.button == SDL_BUTTON_WHEELDOWN) {
521  widget_inventory_handle_arrow_key(widget, SDLK_DOWN);
522  return 1;
523  }
524  }
525 
526  if ((event->type == SDL_MOUSEBUTTONDOWN ||
527  event->type == SDL_MOUSEBUTTONUP) &&
528  (event->button.button == SDL_BUTTON_LEFT ||
529  event->button.button == SDL_BUTTON_RIGHT)) {
530  uint32_t i, r;
531  object *tmp, *tmp2, *found;
532 
533  if (event_dragging_check()) {
534  object *dragging, *target_env;
535 
536  dragging = object_find(cpl.dragging_tag);
537 
538  if (inventory->display == INVENTORY_DISPLAY_BELOW) {
539  target_env = cpl.below;
540  } else {
541  target_env = cpl.ob;
542  }
543 
544  if (cpl.sack != NULL && dragging != cpl.sack &&
545  (dragging->env == cpl.sack ||
546  dragging->env == cpl.sack->env)) {
547  if (cpl.sack->env == cpl.ob && target_env == cpl.below) {
548  widgetdata *inv = widget_find(NULL, INVENTORY_ID, "main",
549  NULL);
550  SOFT_ASSERT_RC(inv != NULL, 0, "Could not find widget");
551  menu_inventory_drop(inv, NULL, NULL);
552  } else {
553  const char *id = cpl.sack->env == cpl.below ? "below" :
554  "main";
555  widgetdata *inv = widget_find(NULL, INVENTORY_ID, id, NULL);
556  SOFT_ASSERT_RC(inv != NULL, 0, "Could not find widget");
557  menu_inventory_get(inv, NULL, NULL);
558  }
559  } else if (dragging->env == target_env) {
560  if (target_env == cpl.below) {
561  widgetdata *inv = widget_find(NULL, INVENTORY_ID, "below",
562  NULL);
563  SOFT_ASSERT_RC(inv != NULL, 0, "Could not find widget");
564  menu_inventory_get(inv, NULL, NULL);
565  }
566  } else if (target_env == cpl.below) {
567  widgetdata *inv = widget_find(NULL, INVENTORY_ID, "main", NULL);
568  SOFT_ASSERT_RC(inv != NULL, 0, "Could not find widget");
569  menu_inventory_drop(inv, NULL, NULL);
570  } else if (target_env == cpl.ob) {
571  widgetdata *inv = widget_find(NULL, INVENTORY_ID, "below",
572  NULL);
573  SOFT_ASSERT_RC(inv != NULL, 0, "Could not find widget");
574  menu_inventory_get(inv, NULL, NULL);
575  }
576 
577  event_dragging_stop();
578 
579  return 1;
580  }
581 
582  for (found = NULL, i = 0, r = 0, tmp = INVENTORY_WHERE(inventory)->inv;
583  tmp && found == NULL; tmp = tmp->next) {
584  if (!inventory_matches_filter(tmp)) {
585  continue;
586  }
587 
588  if (inventory_render_object(widget, tmp, i, &r,
589  event->motion.x, event->motion.y)) {
590  found = tmp;
591  break;
592  }
593 
594  i++;
595 
596  if (cpl.sack == tmp) {
597  for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->next) {
598  if (!inventory_matches_filter(tmp2)) {
599  continue;
600  }
601 
602  if (inventory_render_object(widget, tmp2, i, &r,
603  event->motion.x, event->motion.y)) {
604  found = tmp2;
605  break;
606  }
607 
608  i++;
609  }
610  }
611  }
612 
613  if (found != NULL) {
614  if (event->type == SDL_MOUSEBUTTONDOWN) {
615  if (event->button.button == SDL_BUTTON_LEFT) {
616  event_dragging_start(found->tag, event->motion.x,
617  event->motion.y);
618  event_dragging_set_callback(event_drag_cb);
619  }
620  } else {
621  if (SDL_GetTicks() - inventory->last_clicked <
624  inventory->last_clicked = 0;
625  } else {
626  inventory->last_clicked = SDL_GetTicks();
627  }
628  }
629 
630  if (inventory->selected != i) {
631  inventory->selected = i;
632  inventory->last_clicked = 0;
633  }
634 
635  widget->redraw = 1;
636 
637  return 1;
638  }
639  }
640 
641  return 0;
642 }
643 
645 static int widget_menu_handle(widgetdata *widget, SDL_Event *event)
646 {
647  inventory_struct *inventory = INVENTORY(widget);
648  widgetdata *menu = create_menu(event->motion.x, event->motion.y, widget);
649 
650  if (INVENTORY_MOUSE_INSIDE(widget, event->motion.x, event->motion.y)) {
651  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
652  add_menuitem(menu, "Drop", &menu_inventory_drop, MENU_NORMAL, 0);
653  }
654 
655  add_menuitem(menu, "Get", &menu_inventory_get, MENU_NORMAL, 0);
656 
657  if (inventory->display == INVENTORY_DISPLAY_BELOW) {
658  add_menuitem(menu, "Get all", &menu_inventory_getall, MENU_NORMAL,
659  0);
660  }
661 
662  add_menuitem(menu, "Examine", &menu_inventory_examine, MENU_NORMAL, 0);
663 
665  add_menuitem(menu, "Patch", &menu_inventory_patch, MENU_NORMAL, 0);
666  add_menuitem(menu, "Load to console", &menu_inventory_loadtoconsole,
667  MENU_NORMAL, 0);
668  }
669 
670  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
671  add_menuitem(menu, "More >", &menu_inventory_submenu_more,
672  MENU_SUBMENU, 0);
673  }
674 
675  /* Process the right click event so the correct item is
676  * selected. */
677  widget->event_func(widget, event);
678  } else {
679  widget_menu_standard_items(widget, menu);
680 
681  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
682  add_menuitem(menu, "Inventory Filters >", &menu_inv_filter_submenu,
683  MENU_SUBMENU, 0);
684  }
685  }
686 
687  menu_finalize(menu);
688 
689  return 1;
690 }
691 
696 {
697  inventory_struct *inventory = ecalloc(1, sizeof(*inventory));
699 
700  widget->draw_func = widget_draw;
701  widget->event_func = widget_event;
702  widget->menu_handle_func = widget_menu_handle;
703  widget->subwidget = inventory;
704 }
705 
714 {
715  HARD_ASSERT(widget != NULL);
716 
717  inventory_struct *inventory = widget->subwidget;
718  uint32_t i = 0;
719 
720  for (object *tmp = INVENTORY_WHERE(inventory)->inv; tmp != NULL;
721  tmp = tmp->next) {
722  if (!inventory_matches_filter(tmp)) {
723  continue;
724  }
725 
726  i++;
727 
728  if (cpl.sack == tmp) {
729  for (object *tmp2 = tmp->inv; tmp2 != NULL;
730  tmp2 = tmp2->next) {
731  if (!inventory_matches_filter(tmp2)) {
732  continue;
733  }
734 
735  i++;
736  }
737  }
738  }
739 
740  return i;
741 }
742 
751 {
752  HARD_ASSERT(widget != NULL);
753 
754  inventory_struct *inventory = widget->subwidget;
755  uint32_t i = 0;
756 
757  for (object *tmp = INVENTORY_WHERE(inventory)->inv; tmp != NULL;
758  tmp = tmp->next) {
759  if (!inventory_matches_filter(tmp)) {
760  continue;
761  }
762 
763  if (i == inventory->selected) {
764  return tmp;
765  }
766 
767  i++;
768 
769  if (cpl.sack == tmp) {
770  for (object *tmp2 = tmp->inv; tmp2 != NULL;
771  tmp2 = tmp2->next) {
772  if (!inventory_matches_filter(tmp2)) {
773  continue;
774  }
775 
776  if (i == inventory->selected) {
777  return tmp2;
778  }
779 
780  i++;
781  }
782  }
783  }
784 
785  return NULL;
786 }
787 
796 {
797  inventory_struct *inventory = INVENTORY(widget);
798 
799  if (INVENTORY_COLS(inventory) == 0) {
800  return;
801  }
802 
803  int selected = inventory->selected;
804  switch (key) {
805  case SDLK_UP:
806  selected -= INVENTORY_COLS(inventory);
807  break;
808 
809  case SDLK_DOWN:
810  selected += INVENTORY_COLS(inventory);
811  break;
812 
813  case SDLK_LEFT:
814  selected -= 1;
815  break;
816 
817  case SDLK_RIGHT:
818  selected += 1;
819  break;
820 
821  default:
822  break;
823  }
824 
825  /* Calculate maximum number of inventory items. */
826  int num = widget_inventory_num_items(widget);
827 
828  /* Make sure the selected value does not overflow. */
829  if (selected < 0) {
830  selected = 0;
831  } else if (selected > num - 1) {
832  selected = num - 1;
833  }
834 
835  if (inventory->selected != (uint32_t) selected) {
836  inventory->selected = selected;
837  widget->redraw = 1;
838  }
839 
840  uint32_t offset = MAX(0, selected / INVENTORY_COLS(inventory));
841 
842  if (inventory->scrollbar_info.scroll_offset > offset) {
843  inventory->scrollbar_info.scroll_offset = offset;
844  } else if (offset >= inventory->scrollbar.max_lines +
845  inventory->scrollbar_info.scroll_offset) {
846  inventory->scrollbar_info.scroll_offset = offset -
847  inventory->scrollbar.max_lines + 1;
848  }
849 
850  int cols = INVENTORY_COLS(inventory);
851  inventory->scrollbar_info.num_lines = (num + cols - 1) / cols;
852  /* Makes sure the scroll offset doesn't overflow. */
853  scrollbar_scroll_adjust(&inventory->scrollbar, 0);
854  inventory->scrollbar_info.redraw = 0;
855 }
856 
870 void object_show_inventory(SDL_Surface *surface, object *tmp, int x, int y)
871 {
872  SDL_Surface *icon;
873 
874  object_show_centered(surface, tmp, x, y, INVENTORY_ICON_SIZE,
875  INVENTORY_ICON_SIZE, false);
876 
877  if (tmp->nrof > 1) {
878  char buf[64];
879  SDL_Rect box;
880 
881  if (tmp->nrof > 9999) {
882  snprintf(buf, sizeof(buf), "many");
883  } else {
884  snprintf(buf, sizeof(buf), "%" PRIu32, tmp->nrof);
885  }
886 
887  box.w = INVENTORY_ICON_SIZE;
888  box.h = 0;
889  text_show(surface, FONT_ARIAL10, buf, x, y + 18, COLOR_WHITE,
891  }
892 
893  if (tmp->flags & CS_FLAG_APPLIED) {
894  surface_show(surface, x, y, NULL, TEXTURE_CLIENT("apply"));
895  } else if (tmp->flags & CS_FLAG_UNPAID) {
896  surface_show(surface, x, y, NULL, TEXTURE_CLIENT("unpaid"));
897  }
898 
899  if (tmp->flags & CS_FLAG_LOCKED) {
900  icon = TEXTURE_CLIENT("lock");
901  surface_show(surface, x, y + INVENTORY_ICON_SIZE - icon->w - 2, NULL,
902  icon);
903  }
904 
905  if (tmp->flags & CS_FLAG_IS_MAGICAL) {
906  icon = TEXTURE_CLIENT("magic");
907  surface_show(surface, x + INVENTORY_ICON_SIZE - icon->w - 2,
908  y + INVENTORY_ICON_SIZE - icon->h - 2, NULL, icon);
909  }
910 
911  if (tmp->flags & (CS_FLAG_CURSED | CS_FLAG_DAMNED)) {
912  if (tmp->flags & CS_FLAG_DAMNED) {
913  icon = TEXTURE_CLIENT("damned");
914  } else {
915  icon = TEXTURE_CLIENT("cursed");
916  }
917 
918  surface_show(surface, x + INVENTORY_ICON_SIZE - icon->w - 2, y, NULL,
919  icon);
920  }
921 
922  if (tmp->flags & CS_FLAG_IS_TRAPPED) {
923  icon = TEXTURE_CLIENT("trapped");
924  surface_show(surface, x + INVENTORY_ICON_SIZE / 2 - icon->w / 2,
925  y + INVENTORY_ICON_SIZE / 2 - icon->h / 2, NULL, icon);
926  }
927 }
928 
938 void menu_inventory_drop(widgetdata *widget, widgetdata *menuitem,
939  SDL_Event *event)
940 {
941  HARD_ASSERT(widget != NULL);
942 
943  inventory_struct *inventory = INVENTORY(widget);
944  if (inventory->display != INVENTORY_DISPLAY_MAIN) {
945  return;
946  }
947 
948  object *ob = widget_inventory_get_selected(widget);
949  if (ob == NULL) {
950  return;
951  }
952 
953  if (ob->flags & CS_FLAG_LOCKED) {
954  draw_info(COLOR_DGOLD, "That item is locked.");
955  return;
956  }
957 
958  uint32_t loc;
959 
960  if (cpl.sack != NULL && cpl.sack->env == cpl.below) {
961  loc = cpl.sack->tag;
962  } else {
963  loc = cpl.below->tag;
964  }
965 
966  uint32_t nrof = ob->nrof;
967 
968  if (nrof == 1) {
969  nrof = 0;
970  } else if (!(setting_get_int(OPT_CAT_GENERAL, OPT_COLLECT_MODE) & 2)) {
971  widget_input_struct *input;
972  char buf[MAX_BUF];
973 
974  WIDGET_SHOW(cur_widget[INPUT_ID]);
975  SetPriorityWidget(cur_widget[INPUT_ID]);
976  input = cur_widget[INPUT_ID]->subwidget;
977 
978  snprintf(input->title_text, sizeof(input->title_text),
979  "Drop how many from %" PRIu32 " %s?", nrof, ob->s_name);
980  snprintf(input->prepend_text, sizeof(input->prepend_text),
981  "/droptag %" PRIu32 " %" PRIu32 " ", loc, ob->tag);
982  snprintf(VS(buf), "%" PRIu32, nrof);
983  text_input_set(&input->text_input, buf);
984  input->text_input.character_check_func =
985  text_input_number_character_check;
986  text_input_set_history(&input->text_input, NULL);
987  return;
988  }
989 
990  draw_info_format(COLOR_DGOLD, "drop %s", ob->s_name);
991  client_send_move(loc, ob->tag, nrof);
992  sound_play_effect("drop.ogg", 100);
993 }
994 
1005  SDL_Event *event)
1006 {
1007  send_command_check("/drop all");
1008 }
1009 
1019 void menu_inventory_get(widgetdata *widget, widgetdata *menuitem,
1020  SDL_Event *event)
1021 {
1022  HARD_ASSERT(widget != NULL);
1023  SOFT_ASSERT(widget->type == INVENTORY_ID,
1024  "Called for wrong widget type: %d", widget->type);
1025 
1026  object *ob = widget_inventory_get_selected(widget);
1027  if (ob == NULL) {
1028  return;
1029  }
1030 
1031  inventory_struct *inventory = INVENTORY(widget);
1032  tag_t loc;
1033 
1034  if (inventory->display == INVENTORY_DISPLAY_MAIN) {
1035  /* Need to have an open container to do 'get' in main inventory... */
1036  if (cpl.sack == NULL) {
1037  draw_info(COLOR_DGOLD, "You have no open container to put it in.");
1038  return;
1039  } else {
1040  if (cpl.sack->env != cpl.ob) {
1041  /* Open container not in main inventory... */
1042  draw_info(COLOR_DGOLD, "You already have it.");
1043  return;
1044  } else if (ob->env == cpl.sack) {
1045  /* If the object is already in the open container, take it
1046  * out. */
1047  loc = cpl.ob->tag;
1048  } else {
1049  /* Put the object into the open container. */
1050  loc = cpl.sack->tag;
1051  }
1052  }
1053  } else {
1054  if (cpl.sack != NULL && cpl.sack->env == cpl.below &&
1055  cpl.sack->tag != ob->tag && ob->env != cpl.sack) {
1056  /* If there is an open container on the ground and the item to
1057  * 'get' is not the container and it's not inside the container,
1058  * put it into the container. */
1059  loc = cpl.sack->tag;
1060  } else {
1061  /* Otherwise pick it up into the player's inventory. */
1062  loc = cpl.ob->tag;
1063  }
1064  }
1065 
1066  uint32_t nrof = ob->nrof;
1067 
1068  if (nrof == 1) {
1069  nrof = 0;
1070  } else if (!(setting_get_int(OPT_CAT_GENERAL, OPT_COLLECT_MODE) & 1)) {
1071  widget_input_struct *input;
1072  char buf[MAX_BUF];
1073 
1074  WIDGET_SHOW(cur_widget[INPUT_ID]);
1075  SetPriorityWidget(cur_widget[INPUT_ID]);
1076  input = cur_widget[INPUT_ID]->subwidget;
1077 
1078  snprintf(input->title_text, sizeof(input->title_text),
1079  "Take how many from %" PRIu32 " %s?", nrof, ob->s_name);
1080  snprintf(input->prepend_text, sizeof(input->prepend_text),
1081  "/gettag %" PRIu32 " %" PRIu32 " ", loc, ob->tag);
1082  snprintf(VS(buf), "%" PRIu32, nrof);
1083  text_input_set(&input->text_input, buf);
1084  input->text_input.character_check_func =
1085  text_input_number_character_check;
1086  text_input_set_history(&input->text_input, NULL);
1087  return;
1088  }
1089 
1090  draw_info_format(COLOR_DGOLD, "get %s", ob->s_name);
1091  client_send_move(loc, ob->tag, nrof);
1092  sound_play_effect("get.ogg", 100);
1093 }
1094 
1105  SDL_Event *event)
1106 {
1107  send_command_check("/take all");
1108 }
1109 
1120  SDL_Event *event)
1121 {
1122  object *ob;
1123 
1124  ob = widget_inventory_get_selected(widget);
1125 
1126  if (ob == NULL) {
1127  return;
1128  }
1129 
1130  draw_info_format(COLOR_DGOLD, "examine %s", ob->s_name);
1131  client_send_examine(ob->tag);
1132 }
1133 
1144  SDL_Event *event)
1145 {
1146  object *ob;
1147  char buf[HUGE_BUF];
1148 
1149  ob = widget_inventory_get_selected(widget);
1150 
1151  if (ob == NULL) {
1152  return;
1153  }
1154 
1155  snprintf(buf, sizeof(buf), "/console noinf::obj = find_obj(me, count = %d)",
1156  ob->tag);
1157  send_command(buf);
1158 }
1159 
1170  SDL_Event *event)
1171 {
1172  object *ob;
1173  char buf[HUGE_BUF];
1174 
1175  ob = widget_inventory_get_selected(widget);
1176 
1177  if (ob == NULL) {
1178  return;
1179  }
1180 
1181  snprintf(buf, sizeof(buf), "/patch #%d ", ob->tag);
1182  widget_textwin_handle_console(buf);
1183 }
1184 
1195  SDL_Event *event)
1196 {
1197  object *ob;
1198 
1199  ob = widget_inventory_get_selected(widget);
1200 
1201  if (ob == NULL) {
1202  return;
1203  }
1204 
1205  if (ob->tag == cpl.mark_count) {
1206  draw_info_format(COLOR_DGOLD, "unmark %s", ob->s_name);
1207  } else {
1208  draw_info_format(COLOR_DGOLD, "mark %s", ob->s_name);
1209  }
1210 
1211  object_send_mark(ob);
1212 }
1213 
1224  SDL_Event *event)
1225 {
1226  object *ob;
1227 
1228  ob = widget_inventory_get_selected(widget);
1229 
1230  if (ob == NULL) {
1231  return;
1232  }
1233 
1234  if (ob->flags & CS_FLAG_LOCKED) {
1235  draw_info_format(COLOR_DGOLD, "unlock %s", ob->s_name);
1236  } else {
1237  draw_info_format(COLOR_DGOLD, "lock %s", ob->s_name);
1238  }
1239 
1240  toggle_locked(ob);
1241 }
1242 
1253  SDL_Event *event)
1254 {
1255  object *ob;
1256 
1257  ob = widget_inventory_get_selected(widget);
1258 
1259  if (ob == NULL) {
1260  return;
1261  }
1262 
1263  cpl.dragging_tag = ob->tag;
1264  cpl.dragging_startx = event->motion.x;
1265  cpl.dragging_starty = event->motion.y;
1266 }
1267 
1274 {
1275  object *ob;
1276 
1277  ob = widget_inventory_get_selected(widget);
1278 
1279  if (!ob) {
1280  return;
1281  }
1282 
1283  draw_info_format(COLOR_DGOLD, "apply %s", ob->s_name);
1284  client_send_apply(ob);
1285 }
1286 
1296 void menu_inv_filter(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
1297 {
1298  widgetdata *tmp;
1299  _widget_label *label;
1300  size_t i;
1301 
1302  for (tmp = menuitem->inv; tmp; tmp = tmp->next) {
1303  if (tmp->type == LABEL_ID) {
1304  label = LABEL(menuitem->inv);
1305 
1306  if (strcasecmp(label->text, "all") == 0) {
1308  return;
1309  }
1310 
1311  for (i = 0; i < INVENTORY_FILTER_MAX; i++) {
1312  if (strcasecmp(label->text, inventory_filter_names[i]) == 0) {
1313  inventory_filter_toggle(1 << i);
1314  return;
1315  }
1316  }
1317 
1318  break;
1319  }
1320  }
1321 }
1322 
1333  SDL_Event *event)
1334 {
1335  widgetdata *submenu;
1336  size_t i;
1337  char buf[MAX_BUF];
1338 
1339  submenu = MENU(menuitem->env)->submenu;
1340 
1341  add_menuitem(submenu, "All", &menu_inv_filter, MENU_CHECKBOX,
1343 
1344  for (i = 0; i < INVENTORY_FILTER_MAX; i++) {
1345  snprintf(buf, sizeof(buf), "%s", inventory_filter_names[i]);
1346  string_capitalize(buf);
1347 
1348  add_menuitem(submenu, buf, &menu_inv_filter, MENU_CHECKBOX,
1349  inventory_filter & (1 << i));
1350  }
1351 }
1352 
1363  SDL_Event *event)
1364 {
1365  widgetdata *submenu;
1366 
1367  submenu = MENU(menuitem->env)->submenu;
1368  add_menuitem(submenu, "Drop all", &menu_inventory_dropall, MENU_NORMAL, 0);
1369  add_menuitem(submenu, "Mark", &menu_inventory_mark, MENU_NORMAL, 0);
1370  add_menuitem(submenu, "Lock", &menu_inventory_lock, MENU_NORMAL, 0);
1371  add_menuitem(submenu, "Drag", &menu_inventory_drag, MENU_NORMAL, 0);
1372 }
uint32_t item_skill_tag
Definition: item.h:100
object * below
Definition: player.h:114
int type
Definition: widget.h:118
struct widgetdata * env
Definition: widget.h:98
uint64_t inventory_filter
Definition: inventory.c:38
static int inventory_render_object(widgetdata *widget, object *ob, uint32_t i, uint32_t *r, int mx, int my)
Definition: inventory.c:196
void menu_inventory_lock(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1223
void object_show_inventory(SDL_Surface *surface, object *tmp, int x, int y)
Definition: inventory.c:870
char s_name[NAME_LEN]
Definition: item.h:60
static int inventory_matches_filter(object *op)
Definition: inventory.c:55
void widget_inventory_init(widgetdata *widget)
Definition: inventory.c:695
void draw_info(const char *color, const char *str)
Definition: textwin.c:448
void * subwidget
Definition: widget.h:107
void menu_inventory_drop(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:938
SDL_Surface * texture_surface(texture_struct *texture)
Definition: texture.c:303
uint8_t item_level
Definition: item.h:103
void sound_play_effect(const char *filename, int volume)
Definition: sound.c:367
void menu_inventory_drag(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1252
uint32_t nrof
Definition: item.h:66
void menu_inventory_loadtoconsole(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1143
SDL_Surface * surface
Definition: widget.h:110
#define INVENTORY_FILTER_ALL
Definition: inventory.h:38
uint8_t item_qua
Definition: item.h:94
#define INVENTORY_FILTER_MAX
Definition: inventory.h:56
object * widget_inventory_get_selected(widgetdata *widget)
Definition: inventory.c:750
void menu_inv_filter_submenu(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1332
void text_show(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:1983
uint32_t last_clicked
Definition: inventory.h:115
scrollbar_info_struct scrollbar_info
Definition: inventory.h:109
#define INVENTORY_WHERE(_inventory)
Definition: inventory.h:69
void menu_inventory_dropall(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1004
Stats stats
Definition: player.h:167
void menu_inventory_getall(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1104
#define INVENTORY_COLS(_inventory)
Definition: inventory.h:63
#define COLOR_HGOLD
Definition: text.h:319
void menu_finalize(widgetdata *widget)
Definition: widget.c:2524
void inventory_filter_set(uint64_t filter)
Definition: inventory.c:116
void menu_inventory_patch(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1169
#define INVENTORY_FILTER_MAGICAL
Definition: inventory.h:44
texture_struct * texture_get(texture_type_t type, const char *name)
Definition: texture.c:279
#define INVENTORY_FILTER_CONTAINER
Definition: inventory.h:42
struct widgetdata * next
Definition: widget.h:86
skill_entry_struct * skill_get(size_t id)
Definition: skills.c:246
#define INVENTORY_FILTER_APPLIED
Definition: inventory.h:40
void menu_inventory_get(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1019
#define TEXT_MARKUP
Definition: text.h:224
uint32_t max_lines
Definition: scrollbar.h:77
void send_command(const char *command)
Definition: player.c:175
struct widgetdata * inv
Definition: widget.h:92
uint32_t selected
Definition: inventory.h:88
static int widget_menu_handle(widgetdata *widget, SDL_Event *event)
Definition: inventory.c:645
#define INVENTORY_FILTER_LOCKED
Definition: inventory.h:52
#define TEXT_ALIGN_CENTER
Definition: text.h:230
object * sack
Definition: player.h:117
uint32_t tag
Definition: item.h:63
char * id
Definition: widget.h:42
double weight
Definition: item.h:69
scrollbar_struct scrollbar
Definition: inventory.h:106
void scrollbar_show(scrollbar_struct *scrollbar, SDL_Surface *surface, int x, int y)
Definition: scrollbar.c:443
void toggle_locked(object *op)
Definition: item.c:347
scrollbar_element background
Definition: scrollbar.h:117
#define COLOR_GREEN
Definition: text.h:297
widgetdata * widget_find(widgetdata *where, int type, const char *id, SDL_Surface *surface)
Definition: widget.c:2091
void object_send_mark(object *op)
Definition: item.c:366
uint32_t widget_inventory_num_items(widgetdata *widget)
Definition: inventory.c:713
#define INVENTORY_FILTER_UNAPPLIED
Definition: inventory.h:50
tag_t dragging_tag
Definition: player.h:187
tag_t mark_count
Definition: player.h:143
Client_Player cpl
Definition: client.c:50
#define INVENTORY_MOUSE_INSIDE(_widget, _mx, _my)
Definition: inventory.h:72
void scrollbar_info_create(scrollbar_info_struct *info)
Definition: scrollbar.c:382
struct obj * env
Definition: item.h:54
#define INVENTORY_ROWS(_inventory)
Definition: inventory.h:65
void menu_inventory_mark(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1194
void texture_delete(texture_struct *texture)
Definition: texture.c:208
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
uint32_t * scroll_offset
Definition: scrollbar.h:71
widgetdata * cur_widget[TOTAL_SUBWIDGETS]
Definition: widget.c:75
uint8_t redraw
Definition: widget.h:72
void menu_inv_filter(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1296
void client_send_examine(tag_t tag)
Definition: player.c:138
void widget_inventory_handle_apply(widgetdata *widget)
Definition: inventory.c:1273
const char * inventory_filter_names[INVENTORY_FILTER_MAX]
Definition: inventory.c:43
void menu_inventory_examine(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1119
texture_struct * texture
Definition: inventory.h:112
int dragging_startx
Definition: player.h:192
uint8_t item_con
Definition: item.h:97
int x
Definition: widget.h:48
void inventory_filter_toggle(uint64_t filter)
Definition: inventory.c:132
static void event_drag_cb(void)
Definition: inventory.c:381
void scrollbar_scroll_adjust(scrollbar_struct *scrollbar, int adjust)
Definition: scrollbar.c:427
void scrollbar_create(scrollbar_struct *scrollbar, int w, int h, uint32_t *scroll_offset, uint32_t *num_lines, uint32_t max_lines)
Definition: scrollbar.c:350
static void widget_draw(widgetdata *widget)
Definition: inventory.c:401
Display player's inventory.
Definition: inventory.h:79
static int widget_event(widgetdata *widget, SDL_Event *event)
Definition: inventory.c:498
#define TEXT_OUTLINE
Definition: text.h:255
struct obj * next
Definition: item.h:45
void inventory_filter_set_names(const char *filter)
Definition: inventory.c:153
#define INVENTORY_ICON_SIZE
Definition: inventory.h:60
widgetdata * create_menu(int x, int y, widgetdata *owner)
Definition: widget.c:2428
#define DOUBLE_CLICK_DELAY
Definition: list.h:289
int w
Definition: widget.h:54
uint8_t * redraw
Definition: scrollbar.h:87
void client_send_move(tag_t loc, tag_t tag, uint32_t nrof)
Definition: player.c:156
int h
Definition: widget.h:57
object * object_find(tag_t tag)
Definition: item.c:139
uint32_t level
Definition: player.h:63
inventory_display_t display
Definition: inventory.h:103
void menu_inventory_submenu_more(widgetdata *widget, widgetdata *menuitem, SDL_Event *event)
Definition: inventory.c:1362
int send_command_check(const char *cmd)
Definition: menu.c:376
uint8_t itype
Definition: item.h:90
Display below inventory.
Definition: inventory.h:80
void surface_show(SDL_Surface *surface, int x, int y, SDL_Rect *srcrect, SDL_Surface *src)
Definition: sprite.c:761
int scrollbar_event(scrollbar_struct *scrollbar, SDL_Event *event)
Definition: scrollbar.c:529
float weight_limit
Definition: player.h:126
widgetdata * inventory_focus
Definition: player.h:200
#define INVENTORY_FILTER_CURSED
Definition: inventory.h:46
struct obj * inv
Definition: item.h:57
static scrollbar_info_struct scrollbar_info
Definition: region_map.c:130
#define INVENTORY_FILTER_UNIDENTIFIED
Definition: inventory.h:48
uint32_t flags
Definition: item.h:87
void SetPriorityWidget(widgetdata *node)
Definition: widget.c:1788
void client_send_apply(object *op)
Definition: player.c:119
void draw_info_format(const char *color, const char *format,...)
Definition: textwin.c:429
int dragging_starty
Definition: player.h:197
void object_show_centered(SDL_Surface *surface, object *tmp, int x, int y, int w, int h, bool fit)
Definition: item.c:545
void widget_inventory_handle_arrow_key(widgetdata *widget, SDLKey key)
Definition: inventory.c:795
float real_weight
Definition: player.h:161
void add_menuitem(widgetdata *menu, const char *text, void(*menu_func_ptr)(widgetdata *, widgetdata *, SDL_Event *event), int menu_type, int val)
Definition: widget.c:2451
#define COLOR_DGOLD
Definition: text.h:321
uint32_t scroll_offset
Definition: scrollbar.h:135
object * ob
Definition: player.h:111
#define COLOR_WHITE
Definition: text.h:289
int y
Definition: widget.h:51
char * text
Definition: widget.h:210