Adds pen clicking, changes most pen typechecks into writing implement checks (#84186)

## About The Pull Request

Fixes #84170 
Adds pen clicking and changes some of edagger and pendriver code to use
it instead.
Also replaces most pen typechecks to writing implement checks where it
makes sense, so now you can rename things with everything you can write
with (crayons)


![3d6NwcATNp](https://github.com/tgstation/tgstation/assets/44720187/f6b3ba2f-f3de-4e40-827f-2bad153a92f4)

Twisting pen caps (for traitor uplinks) has been moved to ctrl + click
instead.
This commit is contained in:
SmArtKar
2024-06-25 00:08:37 +03:00
committed by GitHub
parent e17dd9dcb9
commit 4ac4375faf
31 changed files with 84 additions and 49 deletions
+2
View File
@@ -16,3 +16,5 @@
#define BARCODE_SCANNER_CHECKIN "check_in"
#define BARCODE_SCANNER_INVENTORY "inventory"
#define IS_WRITING_UTENSIL(thing) (thing?.get_writing_implement_details()?["interaction_mode"] == MODE_WRITING)
+1 -1
View File
@@ -55,7 +55,7 @@
/obj/item/newspaper/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(held_item)
if(istype(held_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Scribble"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.get_temperature())
@@ -181,7 +181,7 @@
build_step = PTURRET_CLOSED
return
if(istype(used, /obj/item/pen)) //you can rename turrets like bots!
if(used.get_writing_implement_details()?["interaction_mode"] == MODE_WRITING) //you can rename turrets like bots!
var/choice = tgui_input_text(user, "Enter a new turret name", "Turret Classification", finish_name, MAX_NAME_LEN)
if(!choice)
return
+1 -1
View File
@@ -699,7 +699,7 @@
else
balloon_alert(user, "set to [choice]")
else if(!state_open && istype(weapon, /obj/item/pen))
else if(!state_open && IS_WRITING_UTENSIL(weapon))
if(locked)
balloon_alert(user, "unlock first!")
return
+1 -1
View File
@@ -48,7 +48,7 @@
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/beacon/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/pen)) // needed for things that use custom names like the locator
if(IS_WRITING_UTENSIL(W)) // needed for things that use custom names like the locator
var/new_name = tgui_input_text(user, "What would you like the name to be?", "Beacon", max_length = MAX_NAME_LEN)
if(!user.can_perform_action(src))
return
@@ -36,7 +36,7 @@
return ..()
/obj/item/implantcase/attackby(obj/item/used_item, mob/living/user, params)
if(istype(used_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(used_item))
if(!user.can_write(used_item))
return
var/new_name = tgui_input_text(user, "What would you like the label to be?", name, max_length = MAX_NAME_LEN)
@@ -45,7 +45,7 @@
to_chat(user, span_warning("[src] fails to implant [target]."))
/obj/item/implanter/attackby(obj/item/I, mob/living/user, params)
if(!istype(I, /obj/item/pen))
if(IS_WRITING_UTENSIL(I))
return ..()
if(!user.can_write(I))
return
+1 -1
View File
@@ -376,7 +376,7 @@
if(!locomotion)
O.set_lockcharge(TRUE)
else if(istype(W, /obj/item/pen))
else if(IS_WRITING_UTENSIL(W))
to_chat(user, span_warning("You need to use a multitool to name [src]!"))
else
return ..()
+1 -1
View File
@@ -30,7 +30,7 @@
desc = "It reads: [label]"
/obj/item/picket_sign/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen) || istype(W, /obj/item/toy/crayon))
if(IS_WRITING_UTENSIL(W))
retext(user, W)
else
return ..()
@@ -95,7 +95,7 @@
return ..()
/obj/item/storage/box/papersack/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
if(istype(inserted, /obj/item/pen))
if(IS_WRITING_UTENSIL(inserted))
var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, PROC_REF(check_menu), user, inserted), radius = 36, require_near = TRUE)
if(!choice || choice == design_choice)
return FALSE
@@ -399,7 +399,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
screentip_change = TRUE
if(!locked && !opened)
if(id_card && istype(held_item, /obj/item/pen))
if(id_card && IS_WRITING_UTENSIL(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Rename"
screentip_change = TRUE
if(secure && card_reader_installed && !broken)
@@ -817,7 +817,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
else
balloon_alert(user, "set to [choice]")
else if(!opened && istype(weapon, /obj/item/pen))
else if(!opened && IS_WRITING_UTENSIL(weapon))
if(locked)
balloon_alert(user, "unlock first!")
return
@@ -47,7 +47,7 @@
return ..()
/obj/structure/closet/body_bag/attackby(obj/item/interact_tool, mob/user, params)
if (istype(interact_tool, /obj/item/pen) || istype(interact_tool, /obj/item/toy/crayon))
if (IS_WRITING_UTENSIL(interact_tool))
if(!user.can_write(interact_tool))
return
var/t = tgui_input_text(user, "What would you like the label to be?", name, max_length = 53)
@@ -82,7 +82,7 @@
. += span_notice("There is a small <i>paper</i> placard on the assembly, written on it is '[created_name]'.")
/obj/structure/door_assembly/attackby(obj/item/W, mob/living/user, params)
if(istype(W, /obj/item/pen) && !user.combat_mode)
if(IS_WRITING_UTENSIL(W) && !user.combat_mode)
var/t = tgui_input_text(user, "Enter the name for the door", "Airlock Renaming", created_name, MAX_NAME_LEN)
if(!t)
return
+3 -3
View File
@@ -85,7 +85,7 @@
return TRUE
/obj/structure/sign/attackby(obj/item/I, mob/user, params)
if(is_editable && istype(I, /obj/item/pen))
if(is_editable && IS_WRITING_UTENSIL(I))
if(!length(GLOB.editable_sign_types))
CRASH("GLOB.editable_sign_types failed to populate")
var/choice = tgui_input_list(user, "Select a sign type", "Sign Customization", GLOB.editable_sign_types)
@@ -187,12 +187,12 @@
/obj/item/sign/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(is_editable && istype(held_item, /obj/item/pen))
if(is_editable && IS_WRITING_UTENSIL(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Change design"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/sign/attackby(obj/item/I, mob/user, params)
if(is_editable && istype(I, /obj/item/pen))
if(is_editable && IS_WRITING_UTENSIL(I))
if(!length(GLOB.editable_sign_types))
CRASH("GLOB.editable_sign_types failed to populate")
var/choice = tgui_input_list(user, "Select a sign type", "Sign Customization", GLOB.editable_sign_types)
@@ -246,7 +246,7 @@
electronics = null
ae.forceMove(drop_location())
else if(istype(W, /obj/item/pen))
else if(IS_WRITING_UTENSIL(W))
var/t = tgui_input_text(user, "Enter the name for the door", "Windoor Renaming", created_name, MAX_NAME_LEN)
if(!t)
return
+1 -1
View File
@@ -95,7 +95,7 @@
context[SCREENTIP_CONTEXT_LMB] = "Combine cards"
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item, /obj/item/toy/crayon) || istype(held_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(held_item))
context[SCREENTIP_CONTEXT_LMB] = blank ? "Write on card" : "Mark card"
return CONTEXTUAL_SCREENTIP_SET
+1 -1
View File
@@ -103,7 +103,7 @@
return CLICK_ACTION_SUCCESS
/obj/item/supplypod_beacon/attackby(obj/item/W, mob/user)
if(!istype(W, /obj/item/pen)) //give a tag that is visible from the linked express console
if(IS_WRITING_UTENSIL(W)) //give a tag that is visible from the linked express console
return ..()
var/new_beacon_name = tgui_input_text(user, "What would you like the tag to be?", "Beacon Tag", max_length = MAX_NAME_LEN)
if(isnull(new_beacon_name))
+1 -1
View File
@@ -228,7 +228,7 @@
return
else if(bomb)
balloon_alert(user, "already rigged!")
else if(istype(I, /obj/item/pen))
else if(IS_WRITING_UTENSIL(I))
if(!open)
if(!user.can_write(I))
return
+1 -1
View File
@@ -462,7 +462,7 @@
return
/obj/item/seeds/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/pen))
if(IS_WRITING_UTENSIL(O))
var/choice = tgui_input_list(usr, "What would you like to change?", "Seed Alteration", list("Plant Name", "Seed Description", "Product Description"))
if(isnull(choice))
return
+1 -1
View File
@@ -101,7 +101,7 @@
if(burn_paper_product_attackby_check(attacking_item, user))
return
if(istype(attacking_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(attacking_item))
if(!user.can_perform_action(src) || !user.can_write(attacking_item))
return
if(user.is_blind())
+1 -1
View File
@@ -130,7 +130,7 @@
atom_storage.attempt_remove(T, src)
to_chat(user, span_notice("You empty \the [I] into \the [src]."))
update_appearance()
else if(istype(I, /obj/item/pen))
else if(IS_WRITING_UTENSIL(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
var/newname = tgui_input_text(user, "What would you like to title this bookshelf?", "Bookshelf Renaming", max_length = MAX_NAME_LEN)
@@ -12,7 +12,7 @@
/obj/item/bot_assembly/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/pen))
if(IS_WRITING_UTENSIL(I))
rename_bot()
return
+1 -1
View File
@@ -77,7 +77,7 @@
return
to_chat(user, span_notice("You put [weapon] into [src]."))
update_appearance()
else if(istype(weapon, /obj/item/pen))
else if(IS_WRITING_UTENSIL(weapon))
rename(user, weapon)
/obj/item/folder/attack_self(mob/user)
+1 -1
View File
@@ -78,7 +78,7 @@
/obj/item/paperplane/attackby(obj/item/attacking_item, mob/user, params)
if(burn_paper_product_attackby_check(attacking_item, user))
return
if(istype(attacking_item, /obj/item/pen) || istype(attacking_item, /obj/item/toy/crayon))
if(IS_WRITING_UTENSIL(attacking_item))
to_chat(user, span_warning("You should unfold [src] before changing it!"))
return
else if(istype(attacking_item, /obj/item/stamp)) //we don't randomize stamps on a paperplane
+50 -17
View File
@@ -34,6 +34,8 @@
var/dart_insert_icon = 'icons/obj/weapons/guns/toy.dmi'
var/dart_insert_casing_icon_state = "overlay_pen"
var/dart_insert_projectile_icon_state = "overlay_pen_proj"
/// If this pen can be clicked in order to retract it
var/can_click = TRUE
/obj/item/pen/Initialize(mapload)
. = ..()
@@ -47,6 +49,34 @@
AddElement(/datum/element/tool_renaming)
RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart))
RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart))
if (!can_click)
return
create_transform_component()
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/// Proc that child classes can override to have custom transforms, like edaggers or pendrivers
/obj/item/pen/proc/create_transform_component()
AddComponent( \
/datum/component/transforming, \
sharpness_on = NONE, \
inhand_icon_change = FALSE, \
)
/*
* Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM].
*
* Clicks the pen to make an annoying sound. Clickity clickery click!
*/
/obj/item/pen/proc/on_transform(obj/item/source, mob/user, active)
SIGNAL_HANDLER
if(user)
balloon_alert(user, "clicked")
playsound(src, 'sound/machines/click.ogg', 30, TRUE, -3)
icon_state = initial(icon_state) + (active ? "_retracted" : "")
update_appearance(UPDATE_ICON)
return COMPONENT_NO_DEFAULT_MESSAGE
/obj/item/pen/proc/on_inserted_into_dart(datum/source, obj/projectile/dart, mob/user, embedded = FALSE)
SIGNAL_HANDLER
@@ -90,6 +120,7 @@
name = "four-color pen"
icon_state = "pen_4color"
colour = COLOR_BLACK
can_click = FALSE
/obj/item/pen/fourcolor/attack_self(mob/living/carbon/user)
. = ..()
@@ -110,6 +141,8 @@
colour = COLOR_BLACK
to_chat(user, span_notice("\The [src] will now write in [chosen_color]."))
desc = "It's a fancy four-color ink pen, set to [chosen_color]."
balloon_alert(user, "clicked")
playsound(src, 'sound/machines/click.ogg', 30, TRUE, -3)
/obj/item/pen/fountain
name = "fountain pen"
@@ -119,6 +152,7 @@
requires_gravity = FALSE // fancy spess pens
dart_insert_casing_icon_state = "overlay_fountainpen"
dart_insert_projectile_icon_state = "overlay_fountainpen_proj"
can_click = FALSE
/obj/item/pen/charcoal
name = "charcoal stylus"
@@ -129,6 +163,7 @@
custom_materials = null
grind_results = list(/datum/reagent/ash = 5, /datum/reagent/cellulose = 10)
requires_gravity = FALSE // this is technically a pencil
can_click = FALSE
/datum/crafting_recipe/charcoal_stylus
name = "Charcoal Stylus"
@@ -187,19 +222,17 @@
insert_comp.casing_overlay_icon_state = overlay_reskin[current_skin]
insert_comp.projectile_overlay_icon_state = "[overlay_reskin[current_skin]]_proj"
/obj/item/pen/attack_self(mob/living/carbon/user)
. = ..()
if(.)
return
/obj/item/pen/item_ctrl_click(mob/living/carbon/user)
if(loc != user)
to_chat(user, span_warning("You must be holding the pen to continue!"))
return
return CLICK_ACTION_BLOCKING
var/deg = tgui_input_number(user, "What angle would you like to rotate the pen head to? (0-360)", "Rotate Pen Head", max_value = 360)
if(isnull(deg) || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user)
return
return CLICK_ACTION_BLOCKING
degrees = deg
to_chat(user, span_notice("You rotate the top of the pen to [deg] degrees."))
SEND_SIGNAL(src, COMSIG_PEN_ROTATED, deg, user)
return CLICK_ACTION_SUCCESS
/obj/item/pen/attack(mob/living/M, mob/user, params)
if(force) // If the pen has a force value, call the normal attack procs. Used for e-daggers and captain's pen mostly.
@@ -212,6 +245,8 @@
return TRUE
/obj/item/pen/get_writing_implement_details()
if (HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
return null
return list(
interaction_mode = MODE_WRITING,
font = font,
@@ -287,6 +322,9 @@
speed = 6 SECONDS, \
butcher_sound = 'sound/weapons/blade1.ogg', \
)
RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan))
/obj/item/pen/edagger/create_transform_component()
AddComponent( \
/datum/component/transforming, \
force_on = 18, \
@@ -296,8 +334,6 @@
w_class_on = WEIGHT_CLASS_NORMAL, \
inhand_icon_change = FALSE, \
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan))
/obj/item/pen/edagger/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user)
. = ..()
@@ -369,9 +405,7 @@
* Handles swapping their icon files to edagger related icon files -
* as they're supposed to look like a normal pen.
*/
/obj/item/pen/edagger/proc/on_transform(obj/item/source, mob/user, active)
SIGNAL_HANDLER
/obj/item/pen/edagger/on_transform(obj/item/source, mob/user, active)
if(active)
name = hidden_name
desc = hidden_desc
@@ -418,6 +452,7 @@
colour = COLOR_BLUE
dart_insert_casing_icon_state = "overlay_survivalpen"
dart_insert_projectile_icon_state = "overlay_survivalpen_proj"
can_click = FALSE
/obj/item/pen/survival/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user)
. = ..()
@@ -456,6 +491,9 @@
/obj/item/pen/screwdriver/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/pen/screwdriver/create_transform_component()
AddComponent( \
/datum/component/transforming, \
throwforce_on = 5, \
@@ -464,12 +502,7 @@
inhand_icon_change = FALSE, \
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(toggle_screwdriver))
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/pen/screwdriver/proc/toggle_screwdriver(obj/item/source, mob/user, active)
SIGNAL_HANDLER
/obj/item/pen/screwdriver/on_transform(obj/item/source, mob/user, active)
if(user)
balloon_alert(user, active ? "extended" : "retracted")
playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE)
+1 -1
View File
@@ -68,7 +68,7 @@
/obj/item/photo/attackby(obj/item/P, mob/user, params)
if(burn_paper_product_attackby_check(P, user))
return
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
if(IS_WRITING_UTENSIL(P))
if(!user.can_write(P))
return
var/txt = tgui_input_text(user, "What would you like to write on the back?", "Photo Writing", max_length = 128)
@@ -74,7 +74,7 @@
/obj/item/reagent_containers/blood/snail
blood_type = "S"
unique_blood = /datum/reagent/lube
/obj/item/reagent_containers/blood/snail/examine()
. = ..()
. += span_notice("It's a bit slimy... The label indicates that this is meant for snails.")
@@ -100,7 +100,7 @@
blood_type = "U"
/obj/item/reagent_containers/blood/attackby(obj/item/tool, mob/user, params)
if (istype(tool, /obj/item/pen) || istype(tool, /obj/item/toy/crayon))
if (IS_WRITING_UTENSIL(tool))
if(!user.can_write(tool))
return
var/custom_label = tgui_input_text(user, "What would you like to label the blood pack?", "Blood Pack", name, MAX_NAME_LEN)
@@ -510,7 +510,7 @@
balloon_alert(user, "transferred [transfer_amount] unit\s")
flick("syrup_anim",src)
if(istype(attacking_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(attacking_item))
rename(user, attacking_item)
attacking_item.update_appearance()
+1 -1
View File
@@ -113,7 +113,7 @@
sort_tag = dest_tagger.currTag
playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE)
update_appearance()
else if(istype(item, /obj/item/pen))
else if(IS_WRITING_UTENSIL(item))
if(!user.can_write(item))
return
var/str = tgui_input_text(user, "Label text?", "Set label", max_length = MAX_NAME_LEN)
+1 -1
View File
@@ -1778,7 +1778,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
speak("\The [src] has been linked to [card_used].")
if(compartmentLoadAccessCheck(user))
if(istype(attack_item, /obj/item/pen))
if(IS_WRITING_UTENSIL(attack_item))
name = tgui_input_text(user, "Set name", "Name", name, 20)
desc = tgui_input_text(user, "Set description", "Description", desc, 60)
slogan_list += tgui_input_text(user, "Set slogan", "Slogan", "Epic", 60)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 27 KiB