Skip to content

Commit

Permalink
Detective hat improvements regex, for real this time. (tgstation#83033)
Browse files Browse the repository at this point in the history
Fun fact: This PR has been made a total of three (3) times because I
keep forgetting about it.

## About The Pull Request

The inspector's Fedora now uses regex. When saying commands, it is much
more generous on picking up trigger words, as it is now case insensitive
and ignores punctuation at the middle end as well as extra words.

For example, if the prefix is "go go gadget" and the prefix is "batong",
it will trigger with these phrases:
- Go go gadget... batong (Ignores punctuation after the prefix)
- Go go gadget batong! (Ignores punctuation at the end)
- Go go gadget batong bitch! (Ignores extra words at the end)
- Go go GADGET, BATONG (Ignores case)

Multiple items can also be deployed at once, if it is possible to put an
item in your hand. For example, you can assign two items to the same
word, and the first item will be put in your active hand and the second
would be put in your off hand.

## Why It's Good For The Game

Regex good. Removes infuriating situations where the entire phrase is
ignored because you didn't say it exactly, such as adding extra
punctuation or typing in all caps.

I tested this pretty extensively(tm) so it does work, and I tested some
dumb possible exploits as well and couldn't do them. Works with latest
version of /tg/.

## Changelog

:cl: BurgerBB
qol: The inspector's Fedora now uses regex. When saying commands, it is
much more generous on picking up trigger word.
/:cl:

---------

Co-authored-by: san7890 <[email protected]>
  • Loading branch information
BurgerLUA and san7890 authored May 7, 2024
1 parent eb9383f commit 6a3ad66
Showing 1 changed file with 76 additions and 42 deletions.
118 changes: 76 additions & 42 deletions code/modules/clothing/head/jobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,10 @@
interaction_flags_click = FORBID_TELEKINESIS_REACH|ALLOW_RESTING
///prefix our phrases must begin with
var/prefix = "go go gadget"
///an assoc list of phrase = item (like gun = revolver)
var/list/items_by_phrase = list()
///an assoc list of regex = item (like regex datum = revolver item)
var/list/items_by_regex = list()
///A an assoc list of regex = phrase (like regex datum = gun text)
var/list/phrases_by_regex = list()
///how many gadgets can we hold
var/max_items = 4
///items above this weight cannot be put in the hat
Expand All @@ -258,36 +260,58 @@
become_hearing_sensitive(ROUNDSTART_TRAIT)
QDEL_NULL(atom_storage)

/obj/item/clothing/head/fedora/inspector_hat/proc/set_prefix(desired_prefix)

prefix = desired_prefix

// Regenerated the phrases here.
for(var/old_regex in phrases_by_regex)
var/old_phrase = phrases_by_regex[old_regex]
var/obj/item/old_item = items_by_regex[old_regex]
items_by_regex -= old_regex
phrases_by_regex -= old_regex
set_phrase(old_phrase,old_item)

return TRUE

/obj/item/clothing/head/fedora/inspector_hat/proc/set_phrase(desired_phrase,obj/item/associated_item)

var/regex/phrase_regex = regex("[prefix]\[\\s\\W\]+[desired_phrase]","i")

phrases_by_regex[phrase_regex] = desired_phrase
items_by_regex[phrase_regex] = associated_item

return TRUE

/obj/item/clothing/head/fedora/inspector_hat/examine(mob/user)
. = ..()
. += span_notice("You can put items inside, and get them out by saying a phrase, or using it in-hand!")
. += span_notice("The prefix is <b>[prefix]</b>, and you can change it with alt-click!\n")
for(var/phrase in items_by_phrase)
var/obj/item/item = items_by_phrase[phrase]
. += span_notice("[icon2html(item, user)] You can remove [item] by saying <b>\"[prefix] [phrase]\"</b>!")
for(var/found_regex in phrases_by_regex)
var/found_phrase = phrases_by_regex[found_regex]
var/obj/item/found_item = items_by_regex[found_regex]
. += span_notice("[icon2html(found_item, user)] You can remove [found_item] by saying <b>\"[prefix] [found_phrase]\"</b>!")

/obj/item/clothing/head/fedora/inspector_hat/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range)
. = ..()
var/mob/living/carbon/wearer = loc
if(!istype(wearer) || speaker != wearer) //if we are worn
return FALSE
return

raw_message = htmlrendertext(raw_message)
var/prefix_index = findtext(raw_message, prefix)
if(prefix_index != 1)
return FALSE

var/the_phrase = trim_left(replacetext(raw_message, prefix, ""))
var/obj/item/result = items_by_phrase[the_phrase]
if(!result)
return FALSE

if(wearer.put_in_active_hand(result))
wearer.visible_message(span_warning("[src] drops [result] into the hands of [wearer]!"))
else
balloon_alert(wearer, "cant put in hands!")

return TRUE
for(var/regex/found_regex as anything in phrases_by_regex)
if(!found_regex.Find(raw_message))
continue
var/obj/item/found_item = items_by_regex[found_regex]
if(wearer.put_in_hands(found_item))
wearer.visible_message(span_warning("[src] drops [found_item] into the hands of [wearer]!"))
. = TRUE
else
balloon_alert(wearer, "can't put in hands!")
break

return .

/obj/item/clothing/head/fedora/inspector_hat/attackby(obj/item/item, mob/user, params)
. = ..()
Expand All @@ -299,51 +323,61 @@
balloon_alert(user, "too big!")
return

var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26)
if(!input || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(input in items_by_phrase)
balloon_alert(user, "already used!")
var/desired_phrase = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26)
if(!desired_phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return

if(item.loc != user || !user.transferItemToLoc(item, src))
return

to_chat(user, span_notice("You install [item] into the [thtotext(contents.len)] slot in [src]."))
to_chat(user, span_notice("You install [item] into the [thtotext(contents.len)] slot of [src]."))
playsound(src, 'sound/machines/click.ogg', 30, TRUE)
items_by_phrase[input] = item
set_phrase(desired_phrase,item)

return TRUE

/obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user)
. = ..()
var/phrase = tgui_input_list(user, "What item do you want to remove by phrase?", "Item Removal", items_by_phrase)
if(!phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
user.put_in_inactive_hand(items_by_phrase[phrase])
if(!length(items_by_regex))
return CLICK_ACTION_BLOCKING
var/list/found_items = list()
for(var/found_regex in items_by_regex)
found_items += items_by_regex[found_regex]
var/obj/found_item = tgui_input_list(user, "What item do you want to remove?", "Item Removal", found_items)
if(!found_item || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return CLICK_ACTION_BLOCKING
user.put_in_inactive_hand(found_item)

/obj/item/clothing/head/fedora/inspector_hat/click_alt(mob/user)
var/new_prefix = tgui_input_text(user, "What should be the new prefix?", "Activation prefix", prefix, max_length = 24)
if(!new_prefix || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return CLICK_ACTION_BLOCKING
prefix = new_prefix
set_prefix(new_prefix)
return CLICK_ACTION_SUCCESS

/obj/item/clothing/head/fedora/inspector_hat/Exited(atom/movable/gone, direction)
. = ..()
for(var/phrase in items_by_phrase)
var/obj/item/result = items_by_phrase[phrase]
if(gone == result)
items_by_phrase -= phrase
return
for(var/found_regex in items_by_regex)
var/obj/item/found_item = items_by_regex[found_regex]
if(gone != found_item)
continue
items_by_regex -= found_regex
phrases_by_regex -= found_regex
break

/obj/item/clothing/head/fedora/inspector_hat/atom_destruction(damage_flag)
for(var/phrase in items_by_phrase)
var/obj/item/result = items_by_phrase[phrase]
result.forceMove(drop_location())
items_by_phrase = null

var/atom/atom_location = drop_location()
for(var/found_regex in items_by_regex)
var/obj/item/result = items_by_regex[found_regex]
result.forceMove(atom_location)
items_by_regex -= found_regex
phrases_by_regex -= found_regex

return ..()

/obj/item/clothing/head/fedora/inspector_hat/Destroy()
QDEL_LIST_ASSOC(items_by_phrase)
QDEL_LIST_ASSOC(items_by_regex) //Anything that failed to drop gets deleted.
return ..()

//Mime
Expand Down

0 comments on commit 6a3ad66

Please sign in to comment.