From f13c34f8e2d252fd714b742a26229062c832bd27 Mon Sep 17 00:00:00 2001
From: SatinIsle <98125273+SatinIsle@users.noreply.github.com>
Date: Thu, 9 May 2024 01:08:30 +0100
Subject: [PATCH] Generic Machines Part 2 - Items and Effects (#15969)
Added a Generic Item and associated Eventkit verb Spawn Generic Item. Much like the Generic structure but is designed for hand held devices that can be picked up.
To both of the item and structure, added a bunch of options for effects: Sparks, Flash, Flicker Lights and Spawn Item.
Added the ability to upload custom sprites to both verbs, by selecting "Upload Own Sprite" from the list of sprites, along with some warnings that non 32x sprites will need to have their positions adjusted.
---
code/modules/admin/admin_verb_lists_vr.dm | 3 +-
.../eventkit/generic_objects/generic_item.dm | 241 ++++++++++++++++++
.../generic_objects/generic_structure.dm | 102 +++++++-
icons/obj/props/items.dmi | Bin 0 -> 8709 bytes
vorestation.dme | 1 +
5 files changed, 342 insertions(+), 5 deletions(-)
create mode 100644 code/modules/eventkit/generic_objects/generic_item.dm
create mode 100644 icons/obj/props/items.dmi
diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm
index e104916d2d..aad0440423 100644
--- a/code/modules/admin/admin_verb_lists_vr.dm
+++ b/code/modules/admin/admin_verb_lists_vr.dm
@@ -194,7 +194,8 @@ var/list/admin_verbs_spawn = list(
/client/proc/map_template_upload,
/client/proc/map_template_load_on_new_z,
/client/proc/eventkit_open_mob_spawner,
- /client/proc/generic_structure //VOREStation Add
+ /client/proc/generic_structure, //VOREStation Add
+ /client/proc/generic_item //VOREStation Add
)
var/list/admin_verbs_server = list(
diff --git a/code/modules/eventkit/generic_objects/generic_item.dm b/code/modules/eventkit/generic_objects/generic_item.dm
new file mode 100644
index 0000000000..aba094ce3c
--- /dev/null
+++ b/code/modules/eventkit/generic_objects/generic_item.dm
@@ -0,0 +1,241 @@
+/obj/item/generic_item
+ name = "unusual object"
+ desc = "An unusual object of some sort."
+ icon = 'icons/obj/props/items.dmi'
+ icon_state = "old_handheld"
+ var/on = 0
+ var/icon_state_off = "old_handheld"
+ var/icon_state_on = "old_handheld_on"
+ var/activatable_hand = 1
+ var/togglable = 1
+ var/text_activated = "The item turns on."
+ var/text_deactivated = "The item turns off."
+ var/effect = 0
+ var/object = 0
+ var/sound_activated = 0
+ var/delay_time = 0
+ var/icon_off = 0
+ var/icon_on = 0
+
+/obj/item/generic_item/attack_self(mob/user)
+ if(activatable_hand)
+ if(!on)
+ if(delay_time)
+ if(!do_after(user, delay_time, src, exclusive = TASK_USER_EXCLUSIVE))
+ return 0
+ on = 1
+ if(icon_on)
+ icon = icon_on
+ else
+ icon = 'icons/obj/props/items.dmi'
+ icon_state = icon_state_on
+ src.visible_message("[text_activated]")
+ update_icon()
+ if(effect == 1)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ if(effect == 2)
+ for(var/obj/machinery/light/L in machines)
+ if(L.z != user.z || get_dist(user,L) > 10)
+ continue
+ else
+ L.flicker(10)
+ if(effect == 3)
+ for (var/mob/O in viewers(user, null))
+ if(get_dist(user, O) > 3)
+ continue
+
+ var/flash_time = 10
+ if(istype(O, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = O
+ //VOREStation Edit Start
+ if(H.nif && H.nif.flag_check(NIF_V_FLASHPROT,NIF_FLAGS_VISION))
+ H.nif.notify("High intensity light detected, and blocked!",TRUE)
+ continue
+ //VOREStation Edit End
+ if(!H.eyecheck() <= 0)
+ continue
+ flash_time *= H.species.flash_mod
+ var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES]
+ if(!E)
+ return
+ if(E.is_bruised() && prob(E.damage + 50))
+ H.flash_eyes()
+ E.damage += rand(1, 5)
+ else
+ if(!O.blinded && isliving(O))
+ var/mob/living/L = O
+ L.flash_eyes()
+ O.Weaken(flash_time)
+ if(effect == 4)
+ var/atom/o = new object(get_turf(user))
+ src.visible_message("[src] has produced [o]!")
+ if(sound_activated)
+ playsound(src, sound_activated, 50, 1)
+ else if(togglable)
+ if(delay_time)
+ if(!do_after(user, delay_time, src, exclusive = TASK_USER_EXCLUSIVE))
+ return 0
+ on = 0
+ icon_state = icon_state_off
+ if(icon_off)
+ icon = icon_off
+ else
+ icon = 'icons/obj/props/items.dmi'
+ src.visible_message("[text_deactivated]")
+ update_icon()
+ return ..()
+
+/client/proc/generic_item()
+ set category = "EventKit"
+ set name = "Spawn Generic Item"
+ set desc = "Spawn a customisable item with a range of different options."
+
+ var/s_activatable = 0
+ var/s_togglable = 0
+ var/s_icon_state_on = 0
+ var/s_icon = 0
+ var/s_icon2 = 0
+ var/s_delay = 0
+ var/s_text_activated = 0
+ var/s_text_deactivated = 0
+ var/s_effect = 0
+ var/s_sound = 0
+ var/s_object = 0
+ var/list/icon_state_options = list("old_handheld",
+ "old_handheld_on",
+ "switch",
+ "switch_on",
+ "chalice",
+ "staffofnothing",
+ "staffofchange",
+ "staffofanimation",
+ "staffofchaos",
+ "scroll_rolledup",
+ "scroll_blank",
+ "scroll_text",
+ "scroll_textseal",
+ "scroll_rolledupseal",
+ "revolver",
+ "universal_id",
+ "universal_id_glow",
+ "partypopper",
+ "partypopper_e",
+ "screwdriver",
+ "screwdriver_glow",
+ "crystal",
+ "crystal_red",
+ "old_phone",
+ "old_phone_on",
+ "flash",
+ "flash_red",
+ "flash_burnt",
+ "techball_green",
+ "techball_yellow",
+ "techball_red",
+ "techball_blue",
+ "fleshorb",
+ "fleshorb_moving",
+ "Upload Own Sprite")
+ var/list/sound_options = list('sound/effects/alert.ogg',
+ 'sound/effects/bamf.ogg',
+ 'sound/effects/bang.ogg',
+ 'sound/effects/blobattack.ogg',
+ 'sound/effects/cascade.ogg',
+ 'sound/effects/clockcult_gateway_disrupted.ogg',
+ 'sound/effects/closet_close.ogg',
+ 'sound/effects/confetti_ball.ogg',
+ 'sound/effects/deskbell.ogg',
+ 'sound/effects/EMPulse.ogg',
+ 'sound/effects/Explosion1.ogg',
+ 'sound/effects/ghost.ogg',
+ 'sound/effects/Glassbr1.ogg',
+ 'sound/effects/lightningshock.ogg',
+ 'sound/effects/lighton.ogg',
+ 'sound/effects/magnetclamp.ogg',
+ 'sound/effects/pai_boot.ogg',
+ 'sound/effects/pai_login.ogg',
+ 'sound/effects/pai-restore.ogg',
+ 'sound/effects/radio_common.ogg',
+ 'sound/effects/refill.ogg',
+ 'sound/effects/siren.ogg',
+ 'sound/effects/smoke.ogg',
+ 'sound/effects/sparks1.ogg',
+ 'sound/effects/spray.ogg',
+ 'sound/effects/squelch1.ogg',
+ 'sound/effects/supermatter.ogg',
+ 'sound/effects/Whipcrack.ogg',
+ 'sound/effects/woodcutting.ogg')
+
+ var/check_togglable
+
+
+ if(!holder)
+ return
+
+ var/s_name = tgui_input_text(src, "Item Name:", "Name")
+ var/s_desc = tgui_input_text(src, "Item Description:", "Description")
+ var/s_icon_state_off = tgui_input_list(src, "Choose starting icon state:", "icon_state_off", icon_state_options)
+ if(s_icon_state_off == "Upload Own Sprite")
+ s_icon = input(usr, "Choose an image file to upload. Images that are not 32x32 will need to have their positions offset.","Upload Icon") as null|file
+ var/check_activatable = tgui_alert(src, "Allow it to be turned on?", "activatable", list("Yes", "No", "Cancel"))
+ if(check_activatable == "Cancel")
+ return
+ if(check_activatable == "No")
+ s_activatable = 0
+ if(check_activatable == "Yes")
+ s_activatable = 1
+ s_text_activated = tgui_input_text(src, "Activation text:", "Activation Text")
+ check_togglable = tgui_alert(src, "Allow it to be turned back off again?", "togglable", list("Yes", "No", "Cancel"))
+ if(check_togglable == "Cancel")
+ return
+ if(check_togglable == "No")
+ s_togglable = 0
+ if(check_togglable == "Yes")
+ s_text_deactivated = tgui_input_text(src, "Deactivation text:", "Deactivation Text")
+ s_togglable = 1
+ s_icon_state_on = tgui_input_list(src, "Choose activated icon state:", "icon_state_on", icon_state_options)
+ if(s_icon_state_on == "Upload Own Sprite")
+ s_icon2 = input(usr, "Choose an image file to upload. Images that are not 32x32 will need to have their positions offset.","Upload Icon") as null|file
+ s_delay = tgui_input_number(src, "Do you want it to take time to put turn on? Choose a number of deciseconds to activate, or 0 for instant.", "Delay")
+ var/check_effect = tgui_alert(src, "Produce an effect on activation?", "Effect?", list("No", "Spark", "Flicker Lights", "Flash", "Spawn Item", "Cancel"))
+ if(check_effect == "Cancel")
+ return
+ if(check_effect == "No")
+ s_effect = 0
+ if(check_effect == "Spark")
+ s_effect = 1
+ if(check_effect == "Flicker Lights")
+ s_effect = 2
+ if(check_effect == "Flash")
+ s_effect = 3
+ if(check_effect == "Spawn Item")
+ s_effect = 4
+ s_object = get_path_from_partial_text()
+ var/check_sound = tgui_alert(src, "Play a sound when turning on?", "Sound", list("Yes", "No", "Cancel"))
+ if(check_sound == "Cancel")
+ return
+ if(check_sound == "Yes")
+ s_sound = tgui_input_list(src, "Choose a sound to play on activation:", "Sound", sound_options)
+
+ var/spawnloc = get_turf(src.mob)
+ var/obj/item/generic_item/P = new(spawnloc)
+ P.name = s_name
+ P.desc = s_desc
+ P.icon_state_off = s_icon_state_off
+ P.icon_state_on = s_icon_state_on
+ P.activatable_hand = s_activatable
+ P.togglable = s_togglable
+ P.text_activated = s_text_activated
+ P.text_deactivated = s_text_deactivated
+ P.effect = s_effect
+ P.sound_activated = s_sound
+ P.delay_time = s_delay
+ P.object = s_object
+ P.icon_state = s_icon_state_off
+ P.icon_off = s_icon
+ P.icon_on = s_icon2
+ if(s_icon)
+ P.icon = s_icon
+ P.update_icon()
diff --git a/code/modules/eventkit/generic_objects/generic_structure.dm b/code/modules/eventkit/generic_objects/generic_structure.dm
index d7be876bdb..5334111cc3 100644
--- a/code/modules/eventkit/generic_objects/generic_structure.dm
+++ b/code/modules/eventkit/generic_objects/generic_structure.dm
@@ -16,8 +16,11 @@
var/text_activated = "The strucutre turns on."
var/text_deactivated = "The structure turns off."
var/effect = 0
+ var/object = 0
var/sound_activated = 0
var/delay_time = 0
+ var/icon_on = 0
+ var/icon_off = 0
/obj/structure/generic_structure/attack_hand(mob/user)
if(activatable_hand)
@@ -27,12 +30,53 @@
return 0
on = 1
icon_state = icon_state_on
+ if(icon_on)
+ icon = icon_on
+ else
+ icon = 'icons/obj/props/decor.dmi'
+ icon_state = icon_state_on
src.visible_message("[text_activated]")
update_icon()
- if(effect)
+ if(effect == 1)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
+ if(effect == 2)
+ for(var/obj/machinery/light/L in machines)
+ if(L.z != src.z || get_dist(src,L) > 10)
+ continue
+ else
+ L.flicker(10)
+ if(effect == 3)
+ for (var/mob/O in viewers(src, null))
+ if(get_dist(src, O) > 3)
+ continue
+
+ var/flash_time = 10
+ if(istype(O, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = O
+ //VOREStation Edit Start
+ if(H.nif && H.nif.flag_check(NIF_V_FLASHPROT,NIF_FLAGS_VISION))
+ H.nif.notify("High intensity light detected, and blocked!",TRUE)
+ continue
+ //VOREStation Edit End
+ if(!H.eyecheck() <= 0)
+ continue
+ flash_time *= H.species.flash_mod
+ var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES]
+ if(!E)
+ return
+ if(E.is_bruised() && prob(E.damage + 50))
+ H.flash_eyes()
+ E.damage += rand(1, 5)
+ else
+ if(!O.blinded && isliving(O))
+ var/mob/living/L = O
+ L.flash_eyes()
+ O.Weaken(flash_time)
+ if(effect == 4)
+ var/atom/o = new object(get_turf(src))
+ src.visible_message("[src] has produced [o]!")
if(sound_activated)
playsound(src, sound_activated, 50, 1)
else if(togglable)
@@ -41,6 +85,10 @@
return 0
on = 0
icon_state = icon_state_off
+ if(icon_off)
+ icon = icon_off
+ else
+ icon = 'icons/obj/props/decor.dmi'
src.visible_message("[text_deactivated]")
update_icon()
return ..()
@@ -67,6 +115,9 @@
var/s_text_deactivated = 0
var/s_effect = 0
var/s_sound = 0
+ var/s_object = 0
+ var/s_icon = 0
+ var/s_icon2 = 0
var/list/icon_state_options = list("bsb_off",
"bsb_on",
"bsc",
@@ -133,7 +184,8 @@
"ob_warhead_2",
"ob_warhead_3",
"ob_warhead_4",
- "angel")
+ "angel",
+ "Upload Own Sprite")
var/list/sound_options = list('sound/effects/alert.ogg',
'sound/effects/bamf.ogg',
'sound/effects/bang.ogg',
@@ -194,6 +246,8 @@
if(check_wrenchable == "Yes")
s_wrenchable = 1
var/s_icon_state_off = tgui_input_list(src, "Choose starting icon state:", "icon_state_off", icon_state_options)
+ if(s_icon_state_off == "Upload Own Sprite")
+ s_icon = input(usr, "Choose an image file to upload. Images that are not 32x32 will need to have their positions offset.","Upload Icon") as null|file
var/check_activatable = tgui_alert(src, "Allow it to be turned on?", "activatable", list("Yes", "No", "Cancel"))
if(check_activatable == "Cancel")
return
@@ -211,14 +265,23 @@
s_text_deactivated = tgui_input_text(src, "Deactivation text:", "Deactivation Text")
s_togglable = 1
s_icon_state_on = tgui_input_list(src, "Choose activated icon state:", "icon_state_on", icon_state_options)
+ if(s_icon_state_on == "Upload Own Sprite")
+ s_icon2 = input(usr, "Choose an image file to upload. Images that are not 32x32 will need to have their positions offset.","Upload Icon") as null|file
s_delay = tgui_input_number(src, "Do you want it to take time to put turn on? Choose a number of deciseconds to activate, or 0 for instant.", "Delay")
- var/check_effect = tgui_alert(src, "Spark when turning on?", "Spark?", list("Yes", "No", "Cancel"))
+ var/check_effect = tgui_alert(src, "Produce an effect on activation?", "Effect?", list("No", "Spark", "Flicker Lights", "Flash", "Spawn Item", "Cancel"))
if(check_effect == "Cancel")
return
if(check_effect == "No")
s_effect = 0
- if(check_effect == "Yes")
+ if(check_effect == "Spark")
s_effect = 1
+ if(check_effect == "Flicker Lights")
+ s_effect = 2
+ if(check_effect == "Flash")
+ s_effect = 3
+ if(check_effect == "Spawn Item")
+ s_effect = 4
+ s_object = get_path_from_partial_text()
var/check_sound = tgui_alert(src, "Play a sound when turning on?", "Sound", list("Yes", "No", "Cancel"))
if(check_sound == "Cancel")
return
@@ -241,5 +304,36 @@
P.effect = s_effect
P.sound_activated = s_sound
P.delay_time = s_delay
+ P.object = s_object
+ P.icon_state = s_icon_state_off
+ P.icon_off = s_icon
+ P.icon_on = s_icon2
+ if(s_icon)
+ P.icon = s_icon
P.update_icon()
+/client/proc/get_path_from_partial_text(default_path)
+ var/desired_path = tgui_input_text(usr, "Enter full or partial typepath.","Typepath","[default_path]")
+
+ if(!desired_path) //VOREStation Add - If you don't give it anything it builds a list of every possible thing in the game and crashes your client.
+ return //VOREStation Add - And the main way for it to do that is to push the cancel button, which should just do nothing. :U
+
+ var/list/types = typesof(/atom)
+ var/list/matches = list()
+
+ for(var/path in types)
+ if(findtext("[path]", desired_path))
+ matches += path
+
+ if(matches.len==0)
+ tgui_alert_async(usr, "No results found. Sorry.")
+ return
+
+ var/result = null
+
+ if(matches.len==1)
+ result = matches[1]
+ else
+ result = tgui_input_list(usr, "Select an atom type", "Spawn Atom", matches, strict_modern = TRUE)
+ return result
+
diff --git a/icons/obj/props/items.dmi b/icons/obj/props/items.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..98a5538c7902a801192c685503d1f33ee2c9636e
GIT binary patch
literal 8709
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
JT3zRu{|Dqa0+Ij#
literal 0
HcmV?d00001
diff --git a/vorestation.dme b/vorestation.dme
index 6ebe54698e..cd057eceee 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -2266,6 +2266,7 @@
#include "code\modules\error_handler\error_viewer.dm"
#include "code\modules\error_handler\~defines.dm"
#include "code\modules\eventkit\event_machinery.dm"
+#include "code\modules\eventkit\generic_objects\generic_item.dm"
#include "code\modules\eventkit\generic_objects\generic_structure.dm"
#include "code\modules\eventkit\gm_interfaces\fake_pda_conversations.dm"
#include "code\modules\eventkit\gm_interfaces\mob_spawner.dm"