Adds six new strange object powers! (#84775)

## About The Pull Request

DESIGN CONCEPT: Strange Devices are at their best when they're odd tools
which can help a department out, with some strange drawbacks that make
them interesting and unique. Foam for the Janitor, Flashbang for
Security, Teleporter for tiders, Corgimaker for the chef. They're also
ambiguous enough that they can really be used by anyone for silly
hijinks.

Drink Dispenser: Creates a glass, then fills it up with a random drink.

Bioscrambler: After a noticeable warning, bioscrambles people nearby.
33% chance to be used up on use.

Recharger: Shocks you, but recharges one random item to max battery.

Hugger: Hugs everyone in range as if you had the friendly trait.

DImensional: Converts the surroundings to a random material-theme. Each
use increases cooldown by two seconds.

Disguiser: Drops your clothing to the ground and replaces it with a
delete-on-drop costume and a randomly assigned cardboard ID.

Removed an unused and unusable shock flag.

Removed an unused dumb ghost item.

Added a proc that returns a hex color with the # attached.

## Why It's Good For The Game

> DESIGN CONCEPT: Strange Devices are at their best when they're odd
tools which can help a department out, with some strange drawbacks that
make them interesting and unique. Foam for the Janitor, Flashbang for
Security, Teleporter for tiders, Corgimaker for the chef. They're also
ambiguous enough that they can really be used by anyone for silly
hijinks.

Request by ArcaneMusic! He wanted new abilities to go along with the new
sprites, and approved these.

> Removed an unused dumb ghost item.

please stop using costume subtypes for OP items. whats the damn point of
the subtype if youre just going to screw with it

> Added a proc that returns a hex color with the # attached.

idk why it didnt have this tbh

## Changelog

🆑
add: Adds six new strange object powers! Drink dispenser, bioscrambler,
recharger, hugger, dimensional, disguiser.
code: Removed some unused code and items, and added a proc that returns
a random #colorstring.
/🆑
This commit is contained in:
carlarctg
2024-07-10 22:05:00 -04:00
committed by GitHub
parent 128d4dea6e
commit 63b94cd307
7 changed files with 196 additions and 5 deletions
+10
View File
@@ -190,6 +190,16 @@
var/picked_reagent = pick(random_reagents)
return picked_reagent
///Returns a random reagent consumable ethanol object minus blacklisted reagents
/proc/get_random_drink_id()
var/static/list/random_drinks = list()
if(!random_drinks.len)
for(var/datum/reagent/drink_path as anything in subtypesof(/datum/reagent/consumable/ethanol))
if(initial(drink_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED)
random_drinks += drink_path
var/picked_drink = pick(random_drinks)
return picked_drink
///Returns reagent datum from reagent name string
/proc/get_chem_id(chem_name)
for(var/X in GLOB.chemical_reagents_list)
+3
View File
@@ -463,6 +463,9 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
/proc/random_color()
return random_string(6, GLOB.hex_characters)
/proc/ready_random_color()
return "#" + random_string(6, GLOB.hex_characters)
//merges non-null characters (3rd argument) from "from" into "into". Returns result
//e.g. into = "Hello World"
// from = "Seeya______"
@@ -88,11 +88,15 @@
pixel_y = -16
duration = 0.5 SECONDS
color = COLOR_LIME
var/max_alpha = 255
/obj/effect/temp_visual/bioscrambler_wave/Initialize(mapload)
transform = matrix().Scale(0.1)
animate(src, transform = matrix().Scale(2), time = duration, flags = ANIMATION_PARALLEL)
animate(src, alpha = 255, time = duration * 0.6, flags = ANIMATION_PARALLEL)
animate(src, alpha = max_alpha, time = duration * 0.6, flags = ANIMATION_PARALLEL)
animate(alpha = 0, time = duration * 0.4)
apply_wibbly_filters(src)
return ..()
/obj/effect/temp_visual/bioscrambler_wave/light
max_alpha = 128
+11 -1
View File
@@ -22,8 +22,18 @@
if(!isinhands && check_holidays(HALLOWEEN))
. += emissive_appearance('icons/mob/simple/mob.dmi', "ghost", offset_spokesman = src, alpha = src.alpha)
/obj/item/clothing/suit/costume/ghost_sheet/spooky
/obj/item/clothing/suit/spooky_ghost_sheet
name = "spooky ghost"
desc = "This is obviously just a bedsheet, but maybe try it on?"
icon = 'icons/obj/clothing/suits/costume.dmi'
worn_icon = 'icons/mob/clothing/suits/costume.dmi'
user_vars_to_edit = list("name" = "Spooky Ghost", "real_name" = "Spooky Ghost" , "incorporeal_move" = INCORPOREAL_MOVE_BASIC, "appearance_flags" = KEEP_TOGETHER|TILE_BOUND, "alpha" = 150)
inhand_icon_state = null
throwforce = 0
throw_speed = 1
throw_range = 2
w_class = WEIGHT_CLASS_TINY
flags_inv = HIDEGLOVES|HIDEEARS|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
species_exception = list(/datum/species/golem)
supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON
alternate_worn_layer = ABOVE_BODY_FRONT_LAYER //so the bedsheet goes over everything but fire
@@ -283,7 +283,7 @@
else
Knockdown(stun_duration)
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper)
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper, force_friendly)
if(on_fire)
to_chat(helper, span_warning("You can't put [p_them()] out with just your bare hands!"))
return
@@ -374,7 +374,7 @@
else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
to_chat(helper, span_warning("It feels like [src] is freezing as you hug [p_them()]."))
if(HAS_TRAIT(helper, TRAIT_FRIENDLY))
if(HAS_TRAIT(helper, TRAIT_FRIENDLY) || force_friendly)
if (helper.mob_mood.sanity >= SANITY_GREAT)
new /obj/effect/temp_visual/heart(loc)
add_mood_event("friendly_hug", /datum/mood_event/besthug, helper)
@@ -551,7 +551,7 @@
. = rand(-1000, 1000)
..() //Called afterwards because getting the mind after getting gibbed is sketchy
/mob/living/carbon/human/help_shake_act(mob/living/carbon/helper)
/mob/living/carbon/human/help_shake_act(mob/living/carbon/helper, force_friendly)
if(!istype(helper))
return
+164
View File
@@ -617,6 +617,12 @@
PROC_REF(uncontrolled_teleport),
PROC_REF(heat_and_explode),
PROC_REF(rapid_self_dupe),
PROC_REF(drink_dispenser),
PROC_REF(tummy_ache),
PROC_REF(charger),
PROC_REF(hugger),
PROC_REF(dimensional_shift),
PROC_REF(disguiser),
)
/obj/item/relic/attack_self(mob/user)
@@ -722,6 +728,164 @@
throw_smoke(get_turf(user))
warn_admins(user, "Teleport", 0)
// Creates a glass and fills it up with a drink.
/obj/item/relic/proc/drink_dispenser(mob/user)
var/obj/item/reagent_containers/cup/glass/drinkingglass/freebie = new(get_step_rand(user))
playsound(freebie, 'sound/effects/phasein.ogg', rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
addtimer(CALLBACK(src, PROC_REF(dispense_drink), freebie), 0.5 SECONDS)
/obj/item/relic/proc/dispense_drink(obj/item/reagent_containers/cup/glass/glasser)
glasser.reagents.add_reagent(get_random_drink_id(), rand(glasser.volume * 0.3, glasser.volume))
playsound(glasser, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
throw_smoke(get_turf(glasser))
// Scrambles your organs. 33% chance to delete after use.
/obj/item/relic/proc/tummy_ache(mob/user)
new /obj/effect/temp_visual/bioscrambler_wave/light(get_turf(src))
to_chat(user, span_notice("Your stomach starts growling..."))
addtimer(CALLBACK(src, PROC_REF(scrambliticus), user), rand(1 SECONDS, 3 SECONDS)) // throw it away!
/obj/item/relic/proc/scrambliticus(mob/user)
new /obj/effect/temp_visual/bioscrambler_wave(get_turf(src))
playsound(src, 'sound/magic/cosmic_energy.ogg', vol = 50, vary = TRUE)
for(var/mob/living/carbon/nearby in hearers(2, src))
nearby.bioscramble(name)
playsound(nearby, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
throw_smoke(get_turf(nearby))
to_chat(nearby, span_notice("You feel weird."))
if(prob(33))
qdel(src)
// Charges an item or two in your inventory. Also yourself.
/obj/item/relic/proc/charger(mob/living/user)
to_chat(user, span_danger("You're recharged!"))
var/stunner = 1.25 SECONDS
if(iscarbon(user))
var/mob/living/carbon/carboner = user
carboner.electrocute_act(15, src, flags = SHOCK_NOGLOVES, stun_duration = stunner)
else
user.electrocute_act(15, src, flags = SHOCK_NOGLOVES)
playsound(user, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
var/list/chargeable_batteries = list()
for(var/obj/item/stock_parts/power_store/C in user.get_all_contents())
if(C.charge < (C.maxcharge * 0.95)) // otherwise the PDA always gets recharged
chargeable_batteries |= C
lightning_fx(user, stunner)
var/recharges = rand(1, 2)
if(!length(chargeable_batteries))
to_chat(user, span_notice("You have a strange feeling for a moment, but then it passes."))
return
for(var/obj/item/stock_parts/power_store/to_charge as anything in recharges)
to_charge = pick(chargeable_batteries)
to_charge.charge = to_charge.maxcharge
// The device powered by the cell is assumed to be its location.
var/obj/device = to_charge.loc
// If it's not an object, or the loc's assigned power_store isn't the cell, undo.
if(!istype(device) || (device.get_cell() != to_charge))
device = to_charge
device.update_appearance(UPDATE_ICON|UPDATE_OVERLAYS)
to_chat(user, span_notice("[device] feels energized!"))
lightning_fx(device, 0.8 SECONDS)
/obj/item/relic/proc/lightning_fx(atom/shocker, time)
var/lightning = mutable_appearance('icons/effects/effects.dmi', "electricity3", layer = ABOVE_MOB_LAYER)
shocker.add_overlay(lightning)
addtimer(CALLBACK(src, PROC_REF(cut_the_overlay), shocker, lightning), time)
/obj/item/relic/proc/cut_the_overlay(atom/shocker, lightning)
shocker.cut_overlay(lightning)
// Hugs/shakes everyone in range!
/obj/item/relic/proc/hugger(mob/user)
var/list/mob/living/carbon/huggeds = oviewers(3, user)
for(var/mob/living/carbon/victim in huggeds)
victim.help_shake_act(user, force_friendly = TRUE)
new /obj/effect/temp_visual/heart(victim.loc)
if(length(huggeds))
to_chat(user, span_nicegreen("You feel friendly!"))
else
to_chat(user, pick(span_notice("You hug yourself, for some reason."), span_notice("You have a strange feeling for a moment, but then it passes.")))
// Converts a 3x3 area into a random dimensional theme.
/obj/item/relic/proc/dimensional_shift(mob/user)
var/new_theme_path = pick(subtypesof(/datum/dimension_theme))
var/datum/dimension_theme/shifter = SSmaterials.dimensional_themes[new_theme_path]
for(var/turf/shiftee in range(1, user))
shifter.apply_theme(shiftee, show_effect = TRUE)
qdel(shifter)
// prevent *total* spam conversion
min_cooldown += 2 SECONDS
max_cooldown += 2 SECONDS
// Replaces your clothing with a random costume, and your ID with a cardboard one.
// TODO: make them part of the same kit (lobster hat, lobster suit)
/obj/item/relic/proc/disguiser(mob/user)
if(!iscarbon(user))
to_chat(user, span_notice("You have a strange feeling for a moment, but then it passes."))
return
if(prob(80)) // >:)
ADD_TRAIT(user, TRAIT_NO_JUMPSUIT, REF(src)) // prevent dropping pockets & belt
// magic trick!
playsound(user, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
throw_smoke(user)
// carbons always get a hat at least
var/mob/living/carbon/carbonius = user
//hat
var/obj/item/clothing/head/costume/disguise_hat = roll_costume(/obj/item/clothing/head/costume, HIDEMASK)
carbonius.dropItemToGround(carbonius.head)
carbonius.equip_to_slot_or_del(disguise_hat, ITEM_SLOT_HEAD)
if(!ishuman(carbonius))
to_chat(user, span_notice("You have a peculiar feeling for a moment, but then it passes."))
return
var/mob/living/carbon/human/humerus = carbonius
// uniform
var/obj/item/clothing/under/costume/disguise_uniform = roll_costume(/obj/item/clothing/under/costume)
humerus.dropItemToGround(humerus.w_uniform)
humerus.equip_to_slot_or_del(disguise_uniform, ITEM_SLOT_ICLOTHING)
// suit
var/obj/item/clothing/suit/costume/disguise_suit = roll_costume(/obj/item/clothing/suit/costume)
humerus.dropItemToGround(humerus.wear_suit)
humerus.equip_to_slot_or_del(disguise_suit, ITEM_SLOT_OCLOTHING)
// id
var/obj/item/card/cardboard/card_id = new()
humerus.dropItemToGround(humerus.wear_id)
humerus.equip_to_slot_or_del(card_id, ITEM_SLOT_ID)
// edit the card to a random job & name
if(!card_id)
return
card_id.scribbled_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]"
card_id.update_name()
card_id.details_colors = list(ready_random_color(), ready_random_color(), ready_random_color())
card_id.item_flags |= DROPDEL
var/datum/id_trim/random_trim = pick(subtypesof(/datum/id_trim)) // this can pick silly things
random_trim = new random_trim()
if(random_trim.trim_state && random_trim.assignment)
card_id.scribbled_trim = replacetext(random_trim.trim_state, "trim_", "cardboard_")
card_id.scribbled_assignment = random_trim.assignment
card_id.update_overlays()
REMOVE_TRAIT(user, TRAIT_NO_JUMPSUIT, REF(src))
/obj/item/relic/proc/roll_costume(type, flagcheck)
var/list/candidates = list()
for(var/obj/item/thingy as anything in subtypesof(type))
if(flagcheck && !(initial(thingy.flags_inv) & flagcheck))
continue
if(isnull(initial(thingy.icon_state)))
continue
candidates |= thingy
var/obj/item/new_costume = pick(candidates)
new_costume = new new_costume()
new_costume.item_flags |= DROPDEL
return new_costume
//Admin Warning proc for relics
/obj/item/relic/proc/warn_admins(mob/user, relic_type, priority = 1)
var/turf/location = get_turf(src)