3 * Purpose: Item destruction
5 * Copyright (c) 2007 David T. Blackston, Iain McFall, DarkGod, Jeff Greene,
6 * David Vestal, Pete Mack, Andrew Sidwell.
8 * This work is free software; you can redistribute it and/or modify it
9 * under the terms of either:
11 * a) the GNU General Public License as published by the Free Software
12 * Foundation, version 2, or
14 * b) the "Angband licence":
15 * This software may be copied and distributed for educational, research,
16 * and not for profit purposes provided that this copyright and statement
17 * are included in all such copies. Other copyrights may also apply.
24 * The squelch code has a long history. Originally it started out as a simple
25 * sval-dependent item destroyer, but then ego-item and quality squelch was
26 * added too, and then squelched items on the dungeon floor were marked by
27 * purple dots, and by this time the code was quite unmaintainable and pretty
28 * much impossible to work with.
30 * Luckily, though, it's been cleaned up. There is now only sval-dependent
31 * squelch and quality-based squelch, and the two don't interact -- quality-based
32 * is for items that get pseudo-id'd and sval-dependent is for potions and the
35 * The squelch code figures most things out itself. Simply do:
36 * p_ptr->notice |= PN_SQUELCH;
37 * whenever you want to make the game check for squelched items.
39 * The quality-dependent squelch is much reduced in scope from how it used to
40 * be. If less "general" settings are desired, they can be added easily enough
41 * by changing entries in type_tvals[][], adding more TYPE_* constants, and
42 * updating type_names. Savefile compatibility is automatically ensured.
45 * The UI code is much cleaner than it was before, but the interface itself
46 * still needs some design. XXX
51 * List of kinds of item, for pseudo-id squelch.
66 * Names of categories.
68 static const char *type_names
[TYPE_MAX
] =
78 /* Mapping of tval -> type */
79 static int type_tvals
[][2] =
81 { TYPE_WEAPON
, TV_SWORD
},
82 { TYPE_WEAPON
, TV_POLEARM
},
83 { TYPE_WEAPON
, TV_HAFTED
},
84 { TYPE_SHOOTER
, TV_BOW
},
85 { TYPE_MISSILE
, TV_ARROW
},
86 { TYPE_MISSILE
, TV_BOLT
},
87 { TYPE_MISSILE
, TV_SHOT
},
88 { TYPE_ARMOR
, TV_SHIELD
},
89 { TYPE_ARMOR
, TV_HELM
},
90 { TYPE_ARMOR
, TV_GLOVES
},
91 { TYPE_ARMOR
, TV_BOOTS
},
92 { TYPE_ARMOR
, TV_HARD_ARMOR
},
93 { TYPE_ARMOR
, TV_SOFT_ARMOR
},
94 { TYPE_ARMOR
, TV_CLOAK
},
95 { TYPE_ARMOR
, TV_CROWN
},
96 { TYPE_JEWELRY
, TV_RING
},
97 { TYPE_JEWELRY
, TV_AMULET
},
98 { TYPE_DIGGER
, TV_DIGGING
},
101 byte squelch_level
[TYPE_MAX
];
102 size_t squelch_size
= TYPE_MAX
;
106 * The different kinds of quality squelch
121 * The names for the various kinds of quality
123 static const char *quality_names
[SQUELCH_MAX
] =
125 "none", /* SQUELCH_NONE */
126 "cursed", /* SQUELCH_CURSED */
127 "average", /* SQUELCH_AVERAGE */
128 "good (strong pseudo-ID)", /* SQUELCH_GOOD_STRONG */
129 "good (weak pseudo-ID)", /* SQUELCH_GOOD_WEAK */
130 "everything except artifacts", /* SQUELCH_ALL */
134 /* Structure to describe tval/description pairings. */
141 /* Categories for sval-dependent squelch. */
142 static tval_desc sval_dependent
[] =
144 { TV_STAFF
, "Staffs" },
145 { TV_WAND
, "Wands" },
147 { TV_SCROLL
, "Scrolls" },
148 { TV_POTION
, "Potions" },
149 { TV_RING
, "Rings" },
150 { TV_AMULET
, "Amulets" },
152 { TV_MAGIC_BOOK
, "Magic books" },
153 { TV_PRAYER_BOOK
, "Prayer books" },
154 { TV_SPIKE
, "Spikes" },
155 { TV_LITE
, "Lights" },
156 { TV_FLASK
, "Flasks of oil" },
157 { TV_DRAG_ARMOR
, "Dragon mail armor" },
161 /*** Autoinscription stuff ***/
164 * This code needs documenting.
166 int get_autoinscription_index(s16b k_idx
)
170 for (i
= 0; i
< inscriptions_count
; i
++)
172 if (k_idx
== inscriptions
[i
].kind_idx
)
182 const char *get_autoinscription(s16b kind_idx
)
186 for (i
= 0; i
< inscriptions_count
; i
++)
188 if (kind_idx
== inscriptions
[i
].kind_idx
)
189 return quark_str(inscriptions
[i
].inscription_idx
);
195 /* Put the autoinscription on an object */
196 int apply_autoinscription(object_type
*o_ptr
)
199 cptr note
= get_autoinscription(o_ptr
->k_idx
);
200 cptr existing_inscription
= quark_str(o_ptr
->note
);
202 /* Don't inscribe unaware objects */
203 if (!note
|| !object_aware_p(o_ptr
))
206 /* Don't re-inscribe if it's already correctly inscribed */
207 if (existing_inscription
&& streq(note
, existing_inscription
))
210 /* Get an object description */
211 object_desc(o_name
, sizeof(o_name
), o_ptr
, TRUE
, 3);
214 o_ptr
->note
= quark_add(note
);
218 msg_format("You autoinscribe %s.", o_name
);
224 int remove_autoinscription(s16b kind
)
226 int i
= get_autoinscription_index(kind
);
229 if (i
== -1) return 0;
231 while (i
< inscriptions_count
- 1)
233 inscriptions
[i
] = inscriptions
[i
+1];
237 inscriptions_count
--;
243 int add_autoinscription(s16b kind
, cptr inscription
)
248 if (kind
== 0) return 0;
250 /* If there's no inscription, remove it */
251 if (!inscription
|| (inscription
[0] == 0))
252 return remove_autoinscription(kind
);
254 index
= get_autoinscription_index(kind
);
257 index
= inscriptions_count
;
259 if (index
>= AUTOINSCRIPTIONS_MAX
)
261 msg_format("This inscription (%s) cannot be added because the inscription array is full!", inscription
);
265 inscriptions
[index
].kind_idx
= kind
;
266 inscriptions
[index
].inscription_idx
= quark_add(inscription
);
268 /* Only increment count if inscription added to end of array */
269 if (index
== inscriptions_count
)
270 inscriptions_count
++;
276 void autoinscribe_ground(void)
280 s16b this_o_idx
, next_o_idx
= 0;
282 /* Scan the pile of objects */
283 for (this_o_idx
= cave_o_idx
[py
][px
]; this_o_idx
; this_o_idx
= next_o_idx
)
285 /* Get the next object */
286 next_o_idx
= o_list
[this_o_idx
].next_o_idx
;
288 /* Apply an autoinscription */
289 apply_autoinscription(&o_list
[this_o_idx
]);
293 void autoinscribe_pack(void)
297 /* Cycle through the inventory */
298 for (i
= INVEN_PACK
; i
> 0; i
--)
300 /* Skip empty items */
301 if (!inventory
[i
].k_idx
) continue;
303 /* Apply the inscription */
304 apply_autoinscription(&inventory
[i
]);
313 /*** Squelch code ***/
316 * Determines whether a tval is eligable for sval-squelch.
318 bool squelch_tval(int tval
)
322 /* Only squelch if the tval's allowed */
323 for (i
= 0; i
< N_ELEMENTS(sval_dependent
); i
++)
325 if (tval
== sval_dependent
[i
].tval
)
334 * Determines if an object is eligable for squelching.
336 bool squelch_item_ok(const object_type
*o_ptr
)
341 object_kind
*k_ptr
= &k_info
[o_ptr
->k_idx
];
342 bool fullid
= object_known_p(o_ptr
);
343 bool sensed
= (o_ptr
->ident
& IDENT_SENSE
) || fullid
;
344 byte feel
= fullid
? value_check_aux1(o_ptr
) : o_ptr
->pseudo
;
347 /* Don't squelch artifacts */
348 if (artifact_p(o_ptr
)) return FALSE
;
350 /* Don't squelch stuff inscribed not to be destroyed (!k) */
351 if (check_for_inscrip(o_ptr
, "!k") || check_for_inscrip(o_ptr
, "!*"))
356 /* Auto-squelch dead chests */
357 if (o_ptr
->tval
== TV_CHEST
&& o_ptr
->pval
== 0)
360 /* Do squelching by sval, if we 'know' the flavour. */
361 if (k_ptr
->squelch
&& (k_ptr
->flavor
== 0 || k_ptr
->aware
))
363 if (squelch_tval(k_info
[o_ptr
->k_idx
].tval
))
368 /* Don't check pseudo-ID for nonsensed things */
369 if (!sensed
) return FALSE
;
373 /* Find the appropriate squelch group */
374 for (i
= 0; i
< N_ELEMENTS(type_tvals
); i
++)
376 if (type_tvals
[i
][1] == o_ptr
->tval
)
378 num
= type_tvals
[i
][0];
383 /* Never squelched */
388 /* Get result based on the feeling and the squelch_level */
389 switch (squelch_level
[num
])
393 if ((feel
== INSCRIP_BROKEN
) || (feel
== INSCRIP_TERRIBLE
) ||
394 (feel
== INSCRIP_WORTHLESS
) || (feel
== INSCRIP_CURSED
))
402 case SQUELCH_AVERAGE
:
404 if ((feel
== INSCRIP_BROKEN
) || (feel
== INSCRIP_TERRIBLE
) ||
405 (feel
== INSCRIP_WORTHLESS
) || (feel
== INSCRIP_CURSED
) ||
406 (feel
== INSCRIP_AVERAGE
))
414 case SQUELCH_GOOD_WEAK
:
416 if ((feel
== INSCRIP_BROKEN
) || (feel
== INSCRIP_TERRIBLE
) ||
417 (feel
== INSCRIP_WORTHLESS
) || (feel
== INSCRIP_CURSED
) ||
418 (feel
== INSCRIP_AVERAGE
) || (feel
== INSCRIP_GOOD
))
426 case SQUELCH_GOOD_STRONG
:
428 if ((feel
== INSCRIP_BROKEN
) || (feel
== INSCRIP_TERRIBLE
) ||
429 (feel
== INSCRIP_WORTHLESS
) || (feel
== INSCRIP_CURSED
) ||
430 (feel
== INSCRIP_AVERAGE
) ||
431 ((feel
== INSCRIP_GOOD
) &&
432 ((fullid
) || (cp_ptr
->flags
& CF_PSEUDO_ID_HEAVY
))))
453 * Returns TRUE if an item should be hidden due to the player's
456 bool squelch_hide_item(object_type
*o_ptr
)
458 return (hide_squelchable
? squelch_item_ok(o_ptr
) : FALSE
);
463 * Destroy all {squelch}able items.
465 * Imported, with thanks, from Ey... much cleaner than the original.
467 void squelch_items(void)
469 int floor_list
[MAX_FLOOR_STACK
];
475 /* Set the hook and scan the floor */
476 item_tester_hook
= squelch_item_ok
;
477 (void)scan_floor(floor_list
, &floor_num
, p_ptr
->py
, p_ptr
->px
, 0x01);
481 for (n
= 0; n
< floor_num
; n
++)
483 o_ptr
= &o_list
[floor_list
[n
]];
485 /* Avoid artifacts */
486 if (artifact_p(o_ptr
)) continue;
488 if (item_tester_okay(o_ptr
))
491 floor_item_increase(floor_list
[n
], -o_ptr
->number
);
492 floor_item_optimize(floor_list
[n
]);
498 /* Scan through the slots backwards */
499 for (n
= INVEN_PACK
- 1; n
>= 0; n
--)
501 o_ptr
= &inventory
[n
];
503 /* Skip non-objects and artifacts */
504 if (!o_ptr
->k_idx
) continue;
505 if (artifact_p(o_ptr
)) continue;
507 if (item_tester_okay(o_ptr
))
510 inven_item_increase(n
, -o_ptr
->number
);
511 inven_item_optimize(n
);
516 item_tester_hook
= NULL
;
518 /* Mention casualties */
521 message_format(MSG_DESTROY
, 0, "%d item%s squelched.",
522 count
, ((count
> 1) ? "s" : ""));
524 /* Combine/reorder the pack */
525 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
531 * Drop all {squelch}able items.
533 void squelch_drop(void)
537 /* Scan through the slots backwards */
538 for (n
= INVEN_PACK
- 1; n
>= 0; n
--)
540 object_type
*o_ptr
= &inventory
[n
];
542 /* Skip non-objects and unsquelchable objects */
543 if (!o_ptr
->k_idx
) continue;
544 if (!squelch_item_ok(o_ptr
)) continue;
546 /* Check for !d (no drop) inscription */
547 if (!check_for_inscrip(o_ptr
, "!d") && !check_for_inscrip(o_ptr
, "!*"))
549 /* We're allowed to drop it. */
550 inven_drop(n
, o_ptr
->number
);
554 /* Combine/reorder the pack */
555 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
560 /*** Quality-squelch menu ***/
563 * Display an entry in the menu.
565 static void quality_display(menu_type
*menu
, int oid
, bool cursor
, int row
, int col
, int width
)
567 const char *name
= type_names
[oid
];
569 byte level
= squelch_level
[oid
];
570 const char *level_name
= quality_names
[level
];
572 byte attr
= (cursor
? TERM_L_BLUE
: TERM_WHITE
);
575 c_put_str(attr
, format("%-20s : %s", name
, level_name
), row
, col
);
580 * Display the quality squelch subtypes.
582 static void quality_subdisplay(menu_type
*menu
, int oid
, bool cursor
, int row
, int col
, int width
)
584 const char *name
= quality_names
[oid
];
585 byte attr
= (cursor
? TERM_L_BLUE
: TERM_WHITE
);
587 c_put_str(attr
, name
, row
, col
);
593 static bool quality_subaction(char cmd
, void *db
, int oid
)
602 static bool quality_action(char cmd
, void *db
, int oid
)
605 menu_iter menu_f
= { 0, 0, 0, quality_subdisplay
, quality_subaction
};
606 region area
= { 24, 5, 26, SQUELCH_MAX
};
610 /* Display at the right point */
612 cursor
= squelch_level
[oid
];
619 menu
.cmd_keys
= "\n\r";
620 menu
.count
= SQUELCH_MAX
;
621 if (oid
== TYPE_JEWELRY
)
622 menu
.count
= area
.page_rows
= SQUELCH_CURSED
+ 1;
624 menu_init2(&menu
, find_menu_skin(MN_SCROLL
), &menu_f
, &area
);
625 window_make(area
.col
- 2, area
.row
- 1, area
.col
+ area
.width
+ 2, area
.row
+ area
.page_rows
);
627 evt
= menu_select(&menu
, &cursor
, 0);
629 /* Set the new value appropriately */
630 if (evt
.key
!= ESCAPE
&& evt
.type
!= EVT_BACK
)
631 squelch_level
[oid
] = cursor
;
633 /* Load and finish */
639 * Display quality squelch menu.
641 static void quality_menu(void *unused
, const char *also_unused
)
644 menu_iter menu_f
= { 0, 0, 0, quality_display
, quality_action
};
645 region area
= { 1, 5, -1, -1 };
646 event_type evt
= EVENT_EMPTY
;
654 prt("Quality squelch menu", 0, 0);
657 text_out_to_screen(TERM_L_RED
, "Use the movement keys to navigate, and Enter to change settings.");
659 /* Set up the menu */
661 menu
.cmd_keys
= " \n\r";
662 menu
.count
= TYPE_MAX
;
663 menu_init2(&menu
, find_menu_skin(MN_SCROLL
), &menu_f
, &area
);
665 /* Select an entry */
666 while (evt
.key
!= ESCAPE
)
667 evt
= menu_select(&menu
, &cursor
, 0);
676 /*** Sval-dependent menu ***/
679 * Display an entry on the sval menu
681 static void sval_display(menu_type
*menu
, int oid
, bool cursor
, int row
, int col
, int width
)
684 const u16b
*choice
= menu
->menu_data
;
685 int idx
= choice
[oid
];
687 byte attr
= (cursor
? TERM_L_BLUE
: TERM_WHITE
);
690 /* Acquire the "name" of object "i" */
691 object_kind_name(buf
, sizeof(buf
), idx
, TRUE
);
694 c_put_str(attr
, format("[ ] %s", buf
), row
, col
);
695 if (k_info
[idx
].squelch
)
696 c_put_str(TERM_L_RED
, "*", row
, col
+ 1);
700 * Deal with events on the sval menu
702 static bool sval_action(char cmd
, void *db
, int oid
)
707 if (cmd
== '\n' || cmd
== '\r')
709 int idx
= choice
[oid
];
710 k_info
[idx
].squelch
= !k_info
[idx
].squelch
;
720 * Display list of svals to be squelched.
722 static bool sval_menu(int tval
, const char *desc
)
725 menu_iter menu_f
= { 0, 0, 0, sval_display
, sval_action
};
726 region area
= { 1, 5, -1, -1 };
727 event_type evt
= { EVT_NONE
, 0, 0, 0, 0 };
736 /* Create the array */
737 C_MAKE(choice
, z_info
->k_max
, u16b
);
739 /* Iterate over all possible object kinds, finding ones which can be squelched */
740 for (i
= 1; i
< z_info
->k_max
; i
++)
742 object_kind
*k_ptr
= &k_info
[i
];
744 /* Skip empty objects, unseen objects, and incorrect tvals */
745 if (!k_ptr
->name
) continue;
746 if (!k_ptr
->everseen
) continue;
747 if (k_ptr
->tval
!= tval
) continue;
749 /* Add this item to our possibles list */
753 /* Return here if there are no objects */
761 /* Save the screen and clear it */
767 /* Output to the screen */
768 text_out_hook
= text_out_to_screen
;
775 /* Display some helpful information */
776 text_out("Use the ");
777 text_out_c(TERM_L_GREEN
, "movement keys");
778 text_out(" to scroll the list or ");
779 text_out_c(TERM_L_GREEN
, "ESC");
780 text_out(" to return to the previous menu. ");
781 text_out_c(TERM_L_BLUE
, "Enter");
782 text_out(" toggles the current setting.");
786 /* Set up the menu */
788 menu
.cmd_keys
= " \n\r";
790 menu
.menu_data
= choice
;
791 menu_init2(&menu
, find_menu_skin(MN_SCROLL
), &menu_f
, &area
);
793 /* Select an entry */
794 while (evt
.key
!= ESCAPE
)
795 evt
= menu_select(&menu
, &cursor
, 0);
806 /* Returns TRUE if there's anything to display a menu of */
807 static bool seen_tval(int tval
)
811 for (i
= 1; i
< z_info
->k_max
; i
++)
813 object_kind
*k_ptr
= &k_info
[i
];
815 /* Skip empty objects, unseen objects, and incorrect tvals */
816 if (!k_ptr
->name
) continue;
817 if (!k_ptr
->everseen
) continue;
818 if (k_ptr
->tval
!= tval
) continue;
828 /* Extra options on the "item options" menu */
833 void (*action
)(void *unused
, const char *also_unused
);
834 } extra_item_options
[] =
836 { 'Q', "Quality squelching options", quality_menu
},
837 { '{', "Autoinscription setup", do_cmd_knowledge_objects
},
840 static char tag_options_item(menu_type
*menu
, int oid
)
842 size_t line
= (size_t) oid
;
844 if (line
< N_ELEMENTS(sval_dependent
))
847 /* Separator - blank line. */
848 if (line
== N_ELEMENTS(sval_dependent
))
851 line
= line
- N_ELEMENTS(sval_dependent
) - 1;
853 if (line
< N_ELEMENTS(extra_item_options
))
854 return extra_item_options
[line
].tag
;
859 static int valid_options_item(menu_type
*menu
, int oid
)
861 size_t line
= (size_t) oid
;
863 if (line
< N_ELEMENTS(sval_dependent
))
866 /* Separator - blank line. */
867 if (line
== N_ELEMENTS(sval_dependent
))
870 line
= line
- N_ELEMENTS(sval_dependent
) - 1;
872 if (line
< N_ELEMENTS(extra_item_options
))
878 static void display_options_item(menu_type
*menu
, int oid
, bool cursor
, int row
, int col
, int width
)
880 size_t line
= (size_t) oid
;
882 /* First section of menu - the svals */
883 if (line
< N_ELEMENTS(sval_dependent
))
885 bool known
= seen_tval(sval_dependent
[line
].tval
);
886 byte attr
= curs_attrs
[known
? CURS_KNOWN
: CURS_UNKNOWN
][(int)cursor
];
888 c_prt(attr
, sval_dependent
[line
].desc
, row
, col
);
890 /* Second section - the "extra options" */
893 byte attr
= curs_attrs
[CURS_KNOWN
][(int)cursor
];
895 line
= line
- N_ELEMENTS(sval_dependent
) - 1;
897 if (line
< N_ELEMENTS(extra_item_options
))
898 c_prt(attr
, extra_item_options
[line
].name
, row
, col
);
903 static const menu_iter options_item_iter
=
908 display_options_item
,
914 * Display and handle the main squelching menu.
916 void do_cmd_options_item(void *unused
, cptr title
)
919 event_type c
= EVENT_EMPTY
;
920 const char cmd_keys
[] = { ARROW_LEFT
, ARROW_RIGHT
, '\0' };
924 WIPE(&menu
, menu_type
);
926 menu
.cmd_keys
= cmd_keys
;
927 menu
.count
= N_ELEMENTS(sval_dependent
) + N_ELEMENTS(extra_item_options
) + 1;
928 menu_init2(&menu
, find_menu_skin(MN_SCROLL
), &options_item_iter
, &SCREEN_REGION
);
930 menu_layout(&menu
, &SCREEN_REGION
);
932 /* Save and clear screen */
936 while (c
.key
!= ESCAPE
)
939 c
= menu_select(&menu
, &cursor
, 0);
941 if (c
.type
== EVT_SELECT
)
943 if ((size_t) cursor
< N_ELEMENTS(sval_dependent
))
945 sval_menu(sval_dependent
[cursor
].tval
, sval_dependent
[cursor
].desc
);
949 cursor
= cursor
- N_ELEMENTS(sval_dependent
) - 1;
950 if ((size_t) cursor
< N_ELEMENTS(extra_item_options
))
951 extra_item_options
[cursor
].action(NULL
, NULL
);
956 /* Load screen and finish */