more work

This commit is contained in:
Metis
2024-09-13 01:50:58 -04:00
parent 8fd779ef02
commit 7b0780804f
320 changed files with 12185 additions and 161 deletions

View File

@@ -0,0 +1,6 @@
#define STARTING_PAYCHECK 50
//ID bank account support defines.
#define ID_NO_BANK_ACCOUNT 0
#define ID_FREE_BANK_ACCOUNT 1
#define ID_LOCKED_BANK_ACCOUNT 2

View File

@@ -0,0 +1 @@
GLOBAL_LIST_EMPTY(wendigo_soul_storages)

View File

@@ -0,0 +1,10 @@
SUBSYSTEM_DEF(economy)
name = "Economy"
wait = 5 MINUTES
init_order = INIT_ORDER_ECONOMY
runlevels = RUNLEVEL_GAME
flags = SS_NO_FIRE //Let's not forget this. This subsystem does not use fire and was needlessly using CPU.
var/roundstart_paychecks = 5
var/budget_pool = 35000
var/list/generated_accounts = list()
var/list/bank_accounts = list() //List of normal accounts (not department accounts)

View File

@@ -0,0 +1,67 @@
//Small Sprite for borgs --Cyanosis
//Basically the same as /small_sprite, but i'm screaming for modularization
/datum/action/cyborg_small_sprite
name = "Toggle Giant Sprite"
desc = "Others will continue to see you giant."
icon_icon = 'icons/obj/plushes.dmi'
button_icon_state = "securityk9"
background_icon_state = "bg_default_on" //looks techy enough
var/designated_module as text
var/small = FALSE
var/small_icon = null
var/small_icon_state = null
var/image/icon_image
var/i_am_wide = FALSE //transform stuff so we appear in the middle of a tile instead of between two WHEN PLUSHIE
/datum/action/cyborg_small_sprite/k9 //turns you into a marketable plushie
designated_module = "Security K-9 Unit"
small_icon = 'icons/obj/plushes.dmi'
small_icon_state = "securityk9"
i_am_wide = TRUE
/datum/action/cyborg_small_sprite/medihound
designated_module = "MediHound"
small_icon = 'icons/obj/plushes.dmi'
small_icon_state = "medihound"
i_am_wide = TRUE
/datum/action/cyborg_small_sprite/scrubpup
designated_module = "Scrub Pup"
small_icon = 'icons/obj/plushes.dmi'
small_icon_state = "scrubpuppy"
i_am_wide = TRUE
/datum/action/cyborg_small_sprite/Grant(mob/M)
..()
if(!owner)
return
update_image()
RegisterSignal(owner, COMSIG_CYBORG_MODULE_CHANGE,PROC_REF(update_image))
/datum/action/cyborg_small_sprite/Remove(mob/M)
UnregisterSignal(owner, COMSIG_CYBORG_MODULE_CHANGE)
..()
/datum/action/cyborg_small_sprite/Trigger()
if(!icon_image)
update_image()
if(!small)
owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic, "cyborg_smallsprite", icon_image)
else
owner.remove_alt_appearance("cyborg_smallsprite")
small = !small
return TRUE
/datum/action/cyborg_small_sprite/proc/update_image()
var/image/I
if(small_icon && small_icon_state)
I = image(icon=small_icon,icon_state=small_icon_state,loc=owner,layer=owner.layer,pixel_x=owner.pixel_x,pixel_y=owner.pixel_y)
else
I = image(icon=owner.icon,icon_state=owner.icon_state,loc=owner,layer=owner.layer,pixel_x=owner.pixel_x,pixel_y=owner.pixel_y)
I.overlays = owner.overlays
var/matrix/M = matrix() //I don't understand why, I don't want to know why, but this matrix is needed
M.Scale(0.5) //If you ever change the borg's size, be sure to change this too
M.Translate(8*i_am_wide, -8) //x position is for WIDE borgs. If they're not wide, this doesn't matter
I.transform = M //also why do images have transforms
I.override = TRUE
icon_image = I

View File

@@ -0,0 +1,105 @@
//Jay Sparrow
//The base for this datum is found in reagent.dm
/datum/bounty/lewd
var/required_volume = 10
var/shipped_volume = 0
var/datum/reagent/wanted_reagent
/datum/bounty/lewd/completion_string()
return {"[round(shipped_volume)]/[required_volume] Units"}
/datum/bounty/lewd/can_claim()
return ..() && shipped_volume >= required_volume
/datum/bounty/lewd/applies_to(obj/O)
if(!istype(O, /obj/item/reagent_containers))
return FALSE
if(!O.reagents || !O.reagents.has_reagent(wanted_reagent.type))
return FALSE
if(O.flags_1 & HOLOGRAM_1)
return FALSE
return shipped_volume < required_volume
/datum/bounty/lewd/ship(obj/O)
if(!applies_to(O))
return
shipped_volume += O.reagents.get_reagent_amount(wanted_reagent.type)
if(shipped_volume > required_volume)
shipped_volume = required_volume
/datum/bounty/lewd/compatible_with(other_bounty)
return TRUE //Not a lot of different reagents right now, so no sense in closing these off.
/datum/bounty/lewd/fluid
name = "Discretionary Bounty"
reward = 1500
datum/bounty/lewd/fluid/New() //GS13 made some edits here that changes stuff into fatty-related junk
var/reagent_type
switch(rand(1, 20)) //So we can set probabilities for each kind
if(1,2,3,4,5)//Nutriment bounty
required_volume = 200
reagent_type = /datum/reagent/consumable/nutriment
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "CentCom's food lab requires more nutriment to experiment with."
reward += rand(2, 7) * 500
if(6,7) //Big nutriment bounty
required_volume = 1000
reagent_type = /datum/reagent/consumable/nutriment
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "CentCom's food lab have requested vast amounts of nutriment for undisclosed purposes."
reward += rand(10, 17) * 500
if(8,9,10,11,12) //Milk
required_volume = 200
reagent_type = /datum/reagent/consumable/milk
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "CentCom's kitchen is low on dairy, and this station always seems to have plenty for some reason. Mind sending us some?"
reward += rand(2, 7) * 500
if(13,14) //Mega Milk
required_volume = 1000
reagent_type = /datum/reagent/consumable/milk
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "The GATO annual bake sale is soon, and all of our milk has expired. Help us out."
reward += rand(10, 17) * 500 //Milk is generally easier to get. Make the reward a little lower.
if(15,16) //A little romance
var/static/list/possible_reagents = list(\
/datum/reagent/drug/aphrodisiac,\
/datum/reagent/consumable/ethanol/between_the_sheets,\
/datum/reagent/drug/aphrodisiacplus,\
/datum/reagent/lube)
required_volume = 30
reagent_type = pick(possible_reagents)
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "A CentCom official wants something to spice up the bedroom. We told them this was a misuse of their power. It went through anyways."
reward += rand(0, 5) * 500
if(17,18,19,20) //Not as popular of a fluid, so we will leave it the lowest chance.
required_volume = 50
reagent_type = /datum/reagent/consumable/lipoifier
wanted_reagent = new reagent_type
name = wanted_reagent.name
description = "The quality of GATO's meat-related products have diminished. Send us some lipoifier to help with meat production."
reward += rand(2, 7) * 500
/* //Just not getting this to work.
//Freeform sales
/datum/export/lewd/reagent_container
cost = 0 //Base cost of canister. We only care about what's inside.
unit_name = "Fluid Container"
export_types = list(/obj/item/reagent_containers/)
/datum/export/lewd/reagent_containers/get_cost(obj/O)
var/obj/item/reagent_containers/C = O
var/worth = 0
var/fluids = C.reagents.reagent_list
worth += fluids[/datum/reagent/consumable/semen]*2
worth += fluids[/datum/reagent/consumable/milk]*2
worth += fluids[/datum/reagent/consumable/femcum]*5
return worth
*/

View File

@@ -0,0 +1,46 @@
/datum/crafting_recipe/milking_machine
name = "Milking Machine"
reqs = list(/obj/item/stack/cable_coil = 5, /obj/item/stack/rods = 2, /obj/item/stack/sheet/cardboard = 1, /obj/item/reagent_containers/glass/beaker = 2, /obj/item/stock_parts/manipulator = 1)
result = /obj/item/milking_machine
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
category = CAT_MISC
/datum/crafting_recipe/milking_machine/penis
name = "Penis Milking Machine"
reqs = list(/obj/item/stack/cable_coil = 5, /obj/item/stack/rods = 1, /obj/item/stack/sheet/cardboard = 1, /obj/item/reagent_containers/glass/beaker/large = 1, /obj/item/stock_parts/manipulator = 1)
result = /obj/item/milking_machine/penis
//to do: put carpentry in it's own crafting tab
/datum/crafting_recipe/weak_metal
name = "Heated Metal"
reqs = list(/obj/item/stack/sheet/metal = 5)
tools = list(TOOL_WELDER)
category = CAT_CARPENTRY
result = /obj/item/processed/metal
/datum/crafting_recipe/processed_wood
name = "Processable Wood"
reqs = list(/obj/item/stack/sheet/mineral/wood = 5)
tools = list(TOOL_WIRECUTTER, TOOL_WELDER)
category = CAT_CARPENTRY
result = /obj/item/processed/wood/plank
/datum/crafting_recipe/stool_base
name = "Stool Base"
reqs = list(/obj/item/processed/wood/seat = 1, /obj/item/processed/wood/gluepeg = 4)
category = CAT_CARPENTRY
result = /obj/item/processed/wood/stool1
/datum/crafting_recipe/clothcushion
name = "Cloth Cushion"
reqs = list(/obj/item/stack/sheet/cloth = 2, /obj/item/stack/sheet/cotton = 5)
tools = list(TOOL_WIRECUTTER)
category = CAT_CARPENTRY
result = /obj/item/cushion
/datum/crafting_recipe/silkcushion
name = "Silk Cushion"
reqs = list(/obj/item/stack/sheet/silk = 2, /obj/item/stack/sheet/cotton = 5)
tools = list(TOOL_WIRECUTTER)
category = CAT_CARPENTRY
result = /obj/item/cushion/silk

View File

@@ -0,0 +1,191 @@
/datum/element/mob_holder/micro
/datum/element/mob_holder/micro/Attach(datum/target, _worn_state, _alt_worn, _right_hand, _left_hand, _inv_slots = NONE, _proctype)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
worn_state = _worn_state
alt_worn = _alt_worn
right_hand = _right_hand
left_hand = _left_hand
inv_slots = _inv_slots
proctype = _proctype
RegisterSignal(target, COMSIG_CLICK_ALT,PROC_REF(mob_try_pickup_micro), override = TRUE)
RegisterSignal(target, COMSIG_PARENT_EXAMINE,PROC_REF(on_examine), override = TRUE)
RegisterSignal(target, COMSIG_MICRO_PICKUP_FEET,PROC_REF(mob_pickup_micro_feet))
/datum/element/mob_holder/micro/Detach(datum/source, force)
. = ..()
UnregisterSignal(source, COMSIG_CLICK_ALT)
UnregisterSignal(source, COMSIG_PARENT_EXAMINE)
UnregisterSignal(source, COMSIG_MICRO_PICKUP_FEET)
/datum/element/mob_holder/micro/proc/mob_pickup_micro(mob/living/source, mob/user)
var/obj/item/clothing/head/mob_holder/micro/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
if(!holder)
return
user.put_in_hands(holder)
return
//shoehorned (get it?) and lazy way to do instant foot pickups cause haha funny.
/datum/element/mob_holder/micro/proc/mob_pickup_micro_feet(mob/living/source, mob/user)
var/obj/item/clothing/head/mob_holder/micro/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
if(!holder)
return
user.equip_to_slot(holder,ITEM_SLOT_SHOES)
return
/datum/element/mob_holder/micro/proc/mob_try_pickup_micro(mob/living/source, mob/user)
if(!ishuman(user) || !user.Adjacent(source) || user.incapacitated())
return FALSE
if(abs(user.get_effective_size()/source.get_effective_size()) < 2.0 )
to_chat(user, "<span class='warning'>They're too big to pick up!</span>")
return FALSE
if(user.get_active_held_item())
to_chat(user, "<span class='warning'>Your hands are full!</span>")
return FALSE
if(source.buckled)
to_chat(user, "<span class='warning'>[source] is buckled to something!</span>")
return FALSE
if(source == user)
to_chat(user, "<span class='warning'>You can't pick yourself up.</span>")
return FALSE
source.visible_message("<span class='warning'>[user] starts picking up [source].</span>", \
"<span class='userdanger'>[user] starts picking you up!</span>")
var/p = abs(source.get_effective_size()/user.get_effective_size() * 40) //Scale how fast the pickup will be depending on size difference
if(!do_after(user, p, target = source))
return FALSE
if(user.get_active_held_item()||source.buckled)
return FALSE
source.visible_message("<span class='warning'>[user] picks up [source]!</span>", \
"<span class='userdanger'>[user] picks you up!</span>")
to_chat(user, "<span class='notice'>You pick [source] up.</span>")
source.drop_all_held_items()
mob_pickup_micro(source, user)
return TRUE
/obj/item/clothing/head/mob_holder/micro
name = "micro"
desc = "Another person, small enough to fit in your hand."
icon = null
icon_state = ""
slot_flags = ITEM_SLOT_FEET | ITEM_SLOT_HEAD | ITEM_SLOT_ID | ITEM_SLOT_BACK | ITEM_SLOT_NECK
w_class = null //handled by their size
can_head = TRUE
/obj/item/clothing/head/mob_holder/micro/Initialize(mapload, mob/living/M, _worn_state, alt_worn, lh_icon, rh_icon, _can_head_override = FALSE)
. = ..()
if(M)
M.setDir(SOUTH)
held_mob = M
M.forceMove(src)
appearance = M.appearance
name = M.name
desc = M.desc
assimilate(M)
if(_can_head_override)
can_head = _can_head_override
if(alt_worn)
alternate_worn_icon = alt_worn
if(_worn_state)
item_state = _worn_state
icon_state = _worn_state
if(lh_icon)
lefthand_file = lh_icon
if(rh_icon)
righthand_file = rh_icon
/obj/item/clothing/head/mob_holder/micro/Destroy()
if(held_mob)
release()
return ..()
/obj/item/clothing/head/mob_holder/micro/dropped()
..()
if(isturf(loc))//don't release on soft-drops
release()
/obj/item/clothing/head/mob_holder/micro/relaymove(mob/user)
return
//TODO: add a timer to escape someone's grip dependant on size diff
/obj/item/clothing/head/mob_holder/micro/container_resist(mob/living/user)
if(user.incapacitated())
to_chat(user, "<span class='warning'>You can't escape while you're restrained like this!</span>")
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
var/mob/living/L = loc
visible_message("<span class='warning'>[src] begins to squirm in [L]'s grasp!</span>")
if(!do_after(user, 100, target = src))
to_chat(loc, "<span class='warning'>[src] stops resisting.</span>")
return
visible_message("<span class='warning'>[src] escapes [L]!")
release()
/obj/item/clothing/head/mob_holder/micro/assume_air(datum/gas_mixture/env)
var/atom/location = loc
if(!loc)
return //null
var/turf/T = get_turf(loc)
while(location != T)
location = location.loc
if(ismob(location))
return location.loc.assume_air(env)
return location.assume_air(env)
/obj/item/clothing/head/mob_holder/micro/remove_air(amount)
var/atom/location = loc
if(!loc)
return //null
var/turf/T = get_turf(loc)
while(location != T)
location = location.loc
if(ismob(location))
return location.loc.remove_air(amount)
return location.remove_air(amount)
/obj/item/clothing/head/mob_holder/micro/examine(var/mob/user)
for(var/mob/living/M in contents)
M.examine(user)
/obj/item/clothing/head/mob_holder/micro/MouseDrop(mob/M as mob)
..()
if(M != usr) return
if(usr == src) return
if(!Adjacent(usr)) return
if(istype(M,/mob/living/silicon/ai)) return
for(var/mob/living/carbon/human/O in contents)
O.show_inv(usr)
/obj/item/clothing/head/mob_holder/micro/attack_self(var/mob/living/user)
if(cooldown < world.time)
for(var/mob/living/carbon/human/M in contents)
cooldown = world.time + 15
if(user.a_intent == "harm") //TO:DO, rework all of these interactions to be a lot more in depth
visible_message("<span class='danger'> [user] slams their fist down on [M]!</span>")
playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
M.adjustBruteLoss(5)
return
if(user.a_intent == "disarm")
visible_message("<span class='danger'> [user] pins [M] down with a finger!</span>")
playsound(loc, 'sound/effects/bodyfall1.ogg', 50, 1)
M.adjustStaminaLoss(10)
return
if(user.a_intent == "grab")
visible_message("<span class='danger'> [user] squeezes their fist around [M]!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1)
M.adjustOxyLoss(5)
return
M.help_shake_act(user)
/obj/item/clothing/head/mob_holder/micro/attacked_by(obj/item/I, mob/living/user)
for(var/mob/living/carbon/human/M in contents)
M.attacked_by(I, user)

View File

@@ -0,0 +1,96 @@
//This file contains everything to spawn ERT for cleaning up a nuclear reactor meltdown, if those things could actually explode
//ERT
/datum/ert/cleanup
rename_team = "Emergency Cleanup Crew"
code = "Blue" //CC probably wouldn't know if it was sabotage or not, but nuclear waste is a hazard to personnel
mission = "Remove all nuclear residue from X station"
enforce_human = FALSE
opendoors = FALSE
polldesc = "a Sanitation Expert in nuclear waste"
teamsize = 3 //2 is not enough for such a big area, 4 is too much
leader_role = /datum/antagonist/ert/cleanup
roles = list(/datum/antagonist/ert/cleanup)
/datum/ert/cleanup/New()
mission = "Remove all nuclear waste on [station_name()]."
//Antag mind & team (for objectives on what to do)
/datum/antagonist/ert/cleanup
name = "Nuclear Waste Expert"
role = "Nuclear Waste Expert"
ert_team = /datum/team/ert/cleanup
outfit = /datum/outfit/ert/cleanup
/datum/antagonist/ert/cleanup/greet()
//\an [name] because modularization is nice
to_chat(owner, "You are \an [name].\n\
Your job is to remove all nuclear waste and residue contaminants from [station_name()], \
under orders of GATO's Crew Health and Safety Division, as formerly as possible.\n\
You are not required to repair any construction damages, as you are not equipped for such.")
/datum/team/ert/cleanup
mission = "Remove all nuclear waste aboard the station."
objectives = list("Remove all nuclear waste aboard the station.")
//Outfit
/datum/outfit/ert/cleanup
name = "Emergency Cleanup Technician"
id = /obj/item/card/id/ert/Engineer/cleanup
uniform = /obj/item/clothing/under/rank/chief_engineer
suit = /obj/item/clothing/suit/space/hardsuit/rd/hev/no_sound/nuclear_sanitation
glasses = /obj/item/clothing/glasses/meson/engine
back = /obj/item/storage/backpack/industrial
gloves = /obj/item/clothing/gloves/color/yellow/nuclear_sanitation
shoes = /obj/item/clothing/shoes/jackboots/nuclear_sanitation
suit_store = /obj/item/tank/internals/emergency_oxygen/engi
belt = /obj/item/gun/energy/e_gun/advtaser
backpack_contents = list(/obj/item/storage/firstaid/radbgone=2,
/obj/item/storage/firstaid/toxin=1,
/obj/item/jawsoflife=1,
/obj/item/shovel=1,
/obj/item/geiger_counter=1)
/datum/outfit/ert/cleanup/New()
if(prob(30))
l_hand = /obj/item/inducer/sci/combat //A whole engine gets destroyed, so add a nice inducer to help charge areas back up
. = ..()
//Clothes
/obj/item/radio/headset/headset_cent/cleanup
icon_state = "rob_headset" //cause it looks fancy
keyslot = new /obj/item/encryptionkey/headset_eng
/obj/item/card/id/ert/Engineer/cleanup
registered_name = "Waste Expert"
assignment = "Emergency Cleanup Technician"
/obj/item/card/id/ert/Engineer/cleanup/Initialize(mapload)
access = get_ert_access("eng")+get_region_accesses(1)+get_region_accesses(5)+get_region_accesses(7) //CC eng, general, engineering, and command
/obj/item/clothing/gloves/color/yellow/nuclear_sanitation
name = "thick gloves"
desc = "A pair of yellow gloves. They help protect from radiation."
siemens_coefficient = 0.85
permeability_coefficient = 0.7
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 20, "rad" = 100, "fire" = 0, "acid" = 50)
item_color = "chief"
/obj/item/clothing/shoes/jackboots/nuclear_sanitation
desc = "A pair of jackboots, sewn with special material to help protect from radiation."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 5, "bomb" = 5, "bio" = 0, "rad" = 100, "fire" = 10, "acid" = 70)
item_color = "chief"
/obj/item/clothing/suit/space/hardsuit/rd/hev/no_sound/nuclear_sanitation
name = "improved radiation suit"
desc = "A radiation suit that's been manufactured for being a hardsuit. It provides complete protection from radiation and bio contaminants."
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/rd/hev/no_scanner/nuclear_sanitation
slowdown = 0.7 //removes 30% of the slowness. This is actually a considerable amount
/obj/item/clothing/head/helmet/space/hardsuit/rd/hev/no_scanner/nuclear_sanitation
name = "improved radiation hood"
desc = "It protects from radiation and bio contaminants."

View File

@@ -0,0 +1,29 @@
/datum/mood_event/heatneed
description = "<span class='warning'>I need someone to satisfy me, my heat is driving me crazy.</span>\n"
mood_change = -3
timeout = 2 MINUTES
/datum/mood_event/heat
description = "<span class='userlove'>I have satisfied my heat, and I'm filled with happiness!</span>\n"
mood_change = 3
timeout = 5 MINUTES
/datum/mood_event/kiss
description = "<span class='nicegreen'>Someone kissed me, I feel happy!</span>\n"
mood_change = 2
timeout = 3 MINUTES
/datum/mood_event/deathsaw
description = "<span class='boldwarning'>I saw someone die!</span>\n"
mood_change = -5
timeout = 20 MINUTES //May be fine tuned in the future.
/datum/mood_event/healsbadman
description = "<span class='warning'>I feel like I'm held together by flimsy string, and could fall apart at any moment!</span>\n"
mood_change = -4
timeout = 2 MINUTES
/datum/mood_event/copium
description = "<span class='nicegreen'>Things are going to be okay, right?</span>\n"
mood_change = 3
timeout = 3 MINUTES

View File

@@ -0,0 +1,8 @@
/datum/map_template/ruin/lavaland/duohermit
name = "Makeshift Big Shelter"
id = "duohermitcave"
description = "A place of shelter for a couple of stranded hermits, scraping by to live another day."
suffix = "lavaland_surface_duohermit.dmm"
allow_duplicates = FALSE
never_spawn_with = list(/datum/map_template/ruin/lavaland/hermit)
cost = 5

View File

@@ -0,0 +1,63 @@
/datum/quirk/narsianspeaker
name = "Nar-Sian speaker"
desc = "Obsessed with forbidden knowledge regarding the blood cult, you've learned how to speak their ancient language."
value = 1
category = CATEGORY_LANGUAGES
gain_text = "<span class='notice'>Your mind feels sensitive to the slurred, ancient language of Nar'Sian cultists.</span>"
lose_text = "<span class='notice'>You forget how to speak Nar'Sian!</span>"
/datum/quirk/narsianspeaker/add()
var/mob/living/M = quirk_holder
M.grant_language(/datum/language/narsie)
/datum/quirk/narsianspeaker/remove()
if(quirk_holder)
quirk_holder.remove_language(/datum/language/ratvar)
/datum/quirk/ratvarianspeaker
name = "Ratvarian speaker"
desc = "Obsessed with the inner workings of the clock cult, you've learned how to speak their language."
value = 1
category = CATEGORY_LANGUAGES
gain_text = "<span class='notice'>Your mind feels sensitive to the ancient language of Ratvarian cultists.</span>"
lose_text = "<span class='notice'>You forget how to speak Ratvarian!</span>"
/datum/quirk/ratvarianspeaker/add()
var/mob/living/M = quirk_holder
M.grant_language(/datum/language/ratvar)
/datum/quirk/ratvarianspeaker/remove()
if(quirk_holder)
quirk_holder.remove_language(/datum/language/ratvar)
/datum/quirk/encodedspeaker
name = "Encoded Audio speaker"
desc = "You've been augmented with language encoders, allowing you to understand encoded audio."
value = 1
category = CATEGORY_LANGUAGES
gain_text = "<span class='notice'>Your mouth feels a little weird for a moment as your language encoder kicks in.</span>"
lose_text = "<span class='notice'>You feel your encoded audio chip malfunction. You can no longer speak or understand the language of fax machines.</span>"
/datum/quirk/encodedspeaker/add()
var/mob/living/M = quirk_holder
M.grant_language(/datum/language/machine)
/datum/quirk/encodedspeaker/remove()
if(quirk_holder)
quirk_holder.remove_language(/datum/language/ratvar)
/datum/quirk/xenospeaker
name = "Xenocommon speaker"
desc = "Through time observing and interacting with xenos and xeno hybrids, you've learned the intricate hissing patterns of their language."
value = 1
category = CATEGORY_LANGUAGES
gain_text = "<span class='notice'>You feel that you are now able to hiss in the same way xenomorphs do.</span>"
lose_text = "<span class='notice'>You seem to no longer know how to speak xenocommon.</span>"
/datum/quirk/xenospeaker/add()
var/mob/living/M = quirk_holder
M.grant_language(/datum/language/xenocommon)
/datum/quirk/xenospeaker/remove()
if(quirk_holder)
quirk_holder.remove_language(/datum/language/ratvar)

View File

@@ -0,0 +1,47 @@
//Skyrat port start
/datum/quirk/alcohol_lightweight
name = "Alcoholic Lightweight"
desc = "Alcohol really goes straight to your head, gotta be careful with what you drink."
value = 0
category = CATEGORY_ALCOHOL
mob_trait = TRAIT_ALCOHOL_LIGHTWEIGHT
gain_text = "<span class='notice'>You feel woozy thinking of alcohol.</span>"
lose_text = "<span class='notice'>You regain your stomach for drinks.</span>"
//Skyrat port stop
/datum/quirk/cursed_blood
name = "Cursed Blood"
desc = "Your lineage is cursed with the paleblood curse. Best to stay away from holy water... Hell water, on the other hand..."
value = 0
category = CATEGORY_GAMEPLAY
mob_trait = TRAIT_CURSED_BLOOD
gain_text = "<span class='notice'>A curse from a land where men return as beasts runs deep in your blood. Best to stay away from holy water... Hell water, on the other hand...</span>"
lose_text = "<span class='notice'>You feel the weight of the curse in your blood finally gone.</span>"
medical_record_text = "Patient suffers from an unknown type of aversion to holy reagents. Keep them away from a chaplain."
/datum/quirk/inheat
name = "In Heat"
desc = "Your system burns with the desire to be bred, your body will betray you and alert others' to your desire when examining you. Satisfying your lust will make you happy, but ignoring it may cause you to become sad and needy."
value = 0
category = CATEGORY_SEXUAL
mob_trait = TRAIT_HEAT
gain_text = "<span class='notice'>You body burns with the desire to be bred.</span>"
lose_text = "<span class='notice'>You feel more in control of your body and thoughts.</span>"
/datum/quirk/macrophile
name = "Macrophile"
desc = "You are attracted to larger people, and being stepped on by them."
value = 0
category = CATEGORY_SEXUAL
mob_trait = TRAIT_MACROPHILE
gain_text = "<span class='notice'>You feel attracted to people larger than you."
lose_text = "<span class='notice'>You feel less attracted to people larger than you."
/datum/quirk/microphile
name = "Microphile"
desc = "You are attracted to smaller people, and stepping on them."
value = 0
category = CATEGORY_SEXUAL
mob_trait = TRAIT_MICROPHILE
gain_text = "<span class='notice'>You feel attracted to people smaller than you."
lose_text = "<span class='notice'>You feel less attracted to people smaller than you."

View File

@@ -0,0 +1,93 @@
//GS13 Edit
/*
/datum/weather/oxygen_rain
name = "oxygen rain"
desc = "The weather of Layenia can be quite unpredictable. Given the natural low temperature of Layenia, the formation of natural croxygenic liquid gases is possible."
telegraph_duration = 300
telegraph_message = "<span class='boldwarning'>Oxygen clouds condense above and around the station...</span>"
telegraph_overlay = "rain_med"
weather_message = "<span class='userdanger'><i>Liquid oxygen pours down around you! It's freezing!</i></span>"
weather_overlay = "rain_high"
weather_duration_lower = 1200
weather_duration_upper = 4000
end_duration = 300
end_message = "<span class='boldannounce'>The downpour gradually slows to a light shower before fading away...</span>"
end_overlay = "rain_low"
area_type = /area/layenia
target_trait = ZTRAIT_STATION
immunity_type = "storm" // temp
probability = 2 //The chances of this happening are very low after all. We'll rarely see it, but it's worth it.
barometer_predictable = TRUE
var/datum/looping_sound/weak_outside_oxygenrain/sound_wo = new(list(), FALSE, TRUE)
var/datum/looping_sound/weak_inside_oxygenrain/sound_wi = new(list(), FALSE, TRUE)
/datum/weather/oxygen_rain/telegraph()
. = ..()
priority_announce("[station_name()]: A large quantity of condensed low temperature oxygen clouds has been detected around and above the station. A liquid oxygen downpour is expected.",
sound = 'sound/misc/notice2.ogg',
sender_override = "GATO Meteorology Division")
for(var/V in GLOB.player_list)
var/mob/M = V
if((M.client?.prefs?.toggles & SOUND_MIDI) && is_station_level(M.z))
M.playsound_local(M, 'hyperstation/sound/ambience/embrace.ogg', 40, FALSE, pressure_affected = FALSE)
/*
"Sappheiros - Embrace" is under a Creative Commons license (CC BY 3.0)
https://www.youtube.com/channel/UCxLKyBhC6igFhLEb0gxvQNg
Music promoted by BreakingCopyright: https://youtu.be/DzYp5uqixz0
*/
var/list/inside_areas = list()
var/list/outside_areas = list()
var/list/eligible_areas = list()
for (var/z in impacted_z_levels)
eligible_areas += SSmapping.areas_in_z["[z]"]
for(var/i in 1 to eligible_areas.len)
var/area/place = eligible_areas[i]
if(place.outdoors)
outside_areas += place
else
inside_areas += place
CHECK_TICK
sound_wo.output_atoms = outside_areas
sound_wi.output_atoms = inside_areas
sound_wo.start()
sound_wi.start()
/datum/weather/oxygen_rain/end()
. = ..()
sound_wo.stop()
sound_wi.stop()
/datum/weather/oxygen_rain/weather_act(mob/living/L)
//This is liquid oxygen after all. (-180C give or take)
L.adjust_bodytemperature(-rand(5,10))
/datum/looping_sound/weak_outside_oxygenrain
mid_sounds = list(
'sound/weather/oxygenrain/outside/weak_mid1.ogg'=1,
'sound/weather/oxygenrain/outside/weak_mid2.ogg'=1
)
mid_length = 80
start_sound = 'sound/weather/oxygenrain/outside/weak_start.ogg'
start_length = 130
end_sound = 'sound/weather/oxygenrain/outside/weak_end.ogg'
volume = 50
/datum/looping_sound/weak_inside_oxygenrain
mid_sounds = list(
'sound/weather/oxygenrain/inside/weak_mid1.ogg'=1,
'sound/weather/oxygenrain/inside/weak_mid2.ogg'=1
)
mid_length = 80
start_sound = 'sound/weather/oxygenrain/inside/weak_start.ogg'
start_length = 130
end_sound = 'sound/weather/oxygenrain/inside/weak_end.ogg'
volume = 30
*/

View File

@@ -0,0 +1,18 @@
/obj/effect/light/
name = "bloom"
icon = 'hyperstation/icons/effects/lighting.dmi'
icon_state = "light"
plane = ABOVE_LIGHTING_PLANE
blend_mode = BLEND_ADD
mouse_opacity = 0
anchored = TRUE //no more flying around.
/obj/effect/light/medium
icon = 'hyperstation/icons/effects/lightingmed.dmi'
pixel_x = -16
pixel_y = -16
/obj/effect/light/large
icon = 'hyperstation/icons/effects/lightinglarge.dmi'
pixel_x = -48
pixel_y = -48

View File

@@ -0,0 +1,296 @@
GLOBAL_DATUM_INIT(lore_terminal_controller, /datum/lore_controller, new)
/obj/machinery/computer/lore_terminal
name = "Staff info-link terminal"
desc = "A small CRT display with an inbuilt microcomputer which is loaded with an extensive database. These terminals contain eveyrthing from information about historical events to instruction manuals for common ship appliances."
icon = 'nsv13/icons/obj/computers.dmi'
icon_state = "terminal"
pixel_y = 26 //So they snap to walls correctly
density = FALSE
anchored = TRUE
idle_power_usage = 15
var/access_tag = "kncommon" //Every subtype of this type will be readable by this console. Use this for away terms as seen here \/
var/list/entries = list() //Every entry that we've got.
var/in_use = FALSE //Stops sound spam
var/datum/looping_sound/computer_click/soundloop
/obj/machinery/computer/lore_terminal/command //Put sensitive information on this one
name = "Command info-link terminal"
access_tag = "kncommand"
req_access = list(ACCESS_HEADS)
/obj/machinery/computer/lore_terminal/security
name = "Security info-link terminal"
access_tag = "knsecurity"
req_access = list(ACCESS_SECURITY)
/obj/machinery/computer/lore_terminal/awaymission //Example for having a terminal preloaded with only a set list of files.
access_tag = "awaymission_default"
/obj/machinery/computer/lore_terminal/Initialize(mapload)
. = ..()
get_entries()
soundloop = new(list(src), FALSE)
/datum/looping_sound/computer_click
mid_sounds = list('nsv13/sound/effects/computer/scroll1.ogg','nsv13/sound/effects/computer/scroll2.ogg','nsv13/sound/effects/computer/scroll3.ogg','nsv13/sound/effects/computer/scroll5.ogg')
mid_length = 0.8 SECONDS
volume = 30
/obj/machinery/computer/lore_terminal/proc/get_entries()
for(var/X in GLOB.lore_terminal_controller.entries)
var/datum/lore_entry/instance = X
if(instance.access_tag == access_tag || instance.access_tag == "all")
entries += instance
/obj/machinery/computer/lore_terminal/attack_hand(mob/user)
. = ..()
if(!allowed(user))
var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg')
playsound(src, sound, 100, 1)
to_chat(user, "<span class='warning'>Access denied</span>")
return
playsound(src, 'nsv13/sound/effects/computer/scroll_start.ogg', 100, 1)
user.set_machine(src)
var/dat
if(!entries.len)
get_entries()
for(var/X in entries) //Allows you to remove things individually
var/datum/lore_entry/content = X
dat += "<a href='?src=[REF(src)];selectitem=\ref[content]'>[content.name]</a><br>"
var/datum/browser/popup = new(user, "cd C:/entries/local", name, 300, 500)
popup.set_content(dat)
popup.open()
/obj/machinery/computer/lore_terminal/Topic(href, href_list)
if(!in_range(src, usr))
return
if(in_use)
var/sound = 'nsv13/sound/effects/computer/buzz2.ogg'
playsound(src, sound, 100, 1)
to_chat(usr, "<span class='warning'>ERROR: I/O function busy. A file is still loading...</span>")
return
var/datum/lore_entry/content = locate(href_list["selectitem"])
if(!content || !content?.content)
return
var/clicks = length(content.content) //Split the content into characters. 1 character = 1 click
var/dat = "<!DOCTYPE html>\
<html>\
<body background='https://cdn.discordapp.com/attachments/573966558548721665/612306341612093489/static.png'>\
\
<body onload='typeWriter()'>\
\
<h4>ACCESS FILE: C:/entries/local/[content.name]</h4>\
<h3><i>Classification: [content.classified]</i></h3>\
<h6>- <20> Seegson systems inc, 2257</h6>\
<hr style='border-top: dotted 1px;' />\
<h2>[content.title]</h2>\
\
<p id='demo'></p>\
\
<script>\
var i = 0;\
var txt = \"[content.content]\";\
var speed = 10;\
\
function typeWriter() {\
if (i < txt.length) {\
var char = txt.charAt(i);\
if (char == '`') {\
document.getElementById('demo').innerHTML += '<br>';\
}\
else {\
document.getElementById('demo').innerHTML += txt.charAt(i);\
}\
i++;\
setTimeout(typeWriter, speed);\
}\
}\
</script>\
\
\
<style>\
body {\
background-color: black;\
background-image: radial-gradient(\
rgba(0, 20, 0, 0.75), black 120%\
);\
height: 100vh;\
margin: 0;\
overflow: hidden;\
padding: 2rem;\
color: #36f891;\
font: 1.3rem Lucida Console, monospace;\
text-shadow: 0 0 5px #355732;\
&::after {\
content: '';\
position: absolute;\
top: 0;\
left: 0;\
width: 100vw;\
height: 100vh;\
background: repeating-linear-gradient(\
0deg,\
rgba(black, 0.15),\
rgba(black, 0.15) 1px,\
transparent 1px,\
transparent 2px\
);\
pointer-events: none;\
}\
}\
::selection {\
background: #0080FF;\
text-shadow: none;\
}\
pre {\
margin: 0;\
}\
</style>\
</body>\
</html>"
usr << browse(dat, "window=lore_console[content.name];size=600x600")
playsound(src, pick('nsv13/sound/effects/computer/buzz.ogg','nsv13/sound/effects/computer/buzz2.ogg'), 100, TRUE)
in_use = TRUE //Stops you from crashing the server with infinite sounds
icon_state = "terminal_scroll"
clicks = clicks/3
var/loops = clicks/3 //Each click sound has 4 clicks in it, so we only need to click 1/4th of the time per character yeet.
addtimer(CALLBACK(src,PROC_REF(stop_clicking)), loops)
soundloop?.start()
/obj/machinery/computer/lore_terminal/proc/stop_clicking()
soundloop?.stop()
icon_state = "terminal"
in_use = FALSE
/datum/lore_controller
var/name = "Lore archive controller"
var/list/entries = list() //All the lore entries we have.
/datum/lore_controller/New()
. = ..()
instantiate_lore_entries()
/datum/lore_controller/proc/instantiate_lore_entries()
for(var/instance in subtypesof(/datum/lore_entry))
var/datum/lore_entry/S = new instance
entries += S
/datum/lore_entry
var/name = "Loredoc.txt" //"File display name" that the term shows (C://blah/yourfile.bmp)
var/title = null //What it's all about
var/classified = "Declassified" //Fluff, is this a restricted file or not?
var/content = null //You may choose to set this here, or via a .txt. file if it's long. Newlines / Enters will break it!
var/path = null //The location at which we're stored. If you don't have this, you don't get content
var/access_tag = "placeholder" //Set this to match the terminals that you want to be able to access it. EG "ntcommon" for declassified shit.
/datum/lore_entry/New()
. = ..()
if(path)
content = file2text("[path]")
/*
TO GET THE COOL TYPEWRITER EFFECT, I HAD TO STRIP OUT THE HTML FORMATTING STUFF.
SPECIAL KEYS RESPOND AS FOLLOWS:
` = newline (br) (AKA when you press enter)
~ = horizontal line (hr)
<EFBFBD> = bullet point //Bullet points are not working? - archie
*/
/datum/lore_entry/station
name = "new_employees_memo.mail"
title = "Intercepted message"
path = "lore_entries/welcome.txt"
access_tag = "kncommon"
/datum/lore_entry/all
name = "nuclear_authdisk_instructions.mail"
title = "Handling the Nuclear Authentication Disk and You!"
content = "SYSADMIN -> allcrew@seegnet.kin. RE: The Nuclear Authentication Disk. ` Greetings staff members! We're aware of the questions you have in regards to the Nuclear Authentication disk. The disk itself contains the codes needed to unlock nuclear devices used in a Nuclear Emergency and trigger a station self-destruction sequence. ` It is the duty of every member of this crew to take responsibility for the disk in the off chance that station command is currently absent. ` Even though Layenia itself is a mobile facility and prevents Disk Triangulation in most circumstances, it is still important to hold onto the disk even when not needed- it is a good formality and keeps things secure! ` If the disk location is unknown, look for a red pinpointer, the Head of Security and the Captain should always have one in their offices or lockers. These will help you locate the disk. ` If the disk is in enemy hands, call all hands on deck immediately and order a red alert. ` ` Protect the disk with your life, for the lives of the station's crew depend on it. Stay safe through vigilance."
access_tag = "all"
/datum/lore_entry/all/meltdown_proceedures
name = "meltdown_proceedures.mail"
title = "Emergency proceedures regarding nuclear meltdowns:"
path = "lore_entries/meltdowns.txt"
/datum/lore_entry/command
name = "command_memo.mail"
title = "Intercepted Message"
access_tag = "kncommand"
classified = "Restricted"
content = "SYSADMIN -> command@seegnet.kin. RE: Orientation. ` Greetings station command staff, congratulations on your placement! It is now company policy to attend all briefings as issued by centcom staff. Please speak to your centcom officer for clarification on the new procedures."
/datum/lore_entry/command/xeno
name = "outpost_27.mail"
title = "Investigation Closed"
classified = "Classified"
content = "SYSADMIN -> command@seegnet.kin. RE: Outpost 27 Investigation. ` Until further notice, all communications, visits and trade with Outpost 27 must be denied. It is recommended that the subject is avoided. Stay safe through vigilance."
/datum/lore_entry/away_example
title = "Intercepted log file"
access_tag = "awayexample"
/datum/lore_entry/away_example/pilot_log
name = "pilot_log.txt"
content = "They're coming in hot! Prepare for flip and bur']###<23>$55%%% -=File Access Terminated=-"
/datum/lore_entry/away_example/weapons_log
name = "weapon_systems_dump2259/11/25.txt"
content = "Life support systems terminated. Railgun system status: A6E3. Torpedo system status: ~@##6#6#^^6 -=File Access Terminated=-"
/datum/lore_entry/security
name = "usage_and_terms.memo"
title = "Usage and Terms"
access_tag = "knsecurity"
path = "lore_entries/security/usageandterms.txt"
/datum/lore_entry/security/introduction
name = "introduction.memo"
title = "Security Introduction"
path = "lore_entries/security/introduction.txt"
/datum/lore_entry/security/basicgearandyou
name = "gearbasics.memo"
title = "Basic Gear and You"
path = "lore_entries/security/basicgearandyou.txt"
/datum/lore_entry/security/advancedgearandyou
name = "gearadvanced.memo"
title = "Advanced Gear and You"
path = "lore_entries/security/advancedgearandyou.txt"
/datum/lore_entry/security/defensivegearandyou
name = "geardefensive.memo"
title = "Defensive Gear and You"
path = "lore_entries/security/defensivegearandyou.txt"
/datum/lore_entry/security/sop
name = "standard_operating_procedure.txt"
title = "Standard Operating Procedure"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/lowcrime
name = "low_infractions.txt"
title = "Minor Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/mediumcrime
name = "medium_infractions.txt"
title = "Medium-risk Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/highcrime
name = "high_infractions.txt"
title = "Dangerous Infractions"
path = "lore_entries/security/wip.txt"
/datum/lore_entry/security/deltacrime
name = "delta_infractions.txt"
title = "Zealot-class Notice and Warning"
path = "lore_entries/security/wip.txt"

View File

@@ -0,0 +1,77 @@
//hyperstation 13 nail polish
/obj/item/nailpolish
name = "nail polish"
desc = "Paint with a fine brush to do your nails, or someone elses."
icon = 'hyperstation/icons/obj/cosmetic.dmi'
icon_state = "nailcap"
item_state = "nailpolish"
w_class = WEIGHT_CLASS_SMALL
var/paint = "black"
price = 5
var/mutable_appearance/bottle //show the colour on the bottle.
/obj/item/nailpolish/red
name = "red nail polish"
paint = "red"
/obj/item/nailpolish/blue
name = "blue nail polish"
paint = "blue"
/obj/item/nailpolish/aqua
name = "cyan nail polish"
paint = "aqua"
/obj/item/nailpolish/black
name = "black nail polish"
paint = "black"
/obj/item/nailpolish/white
name = "white nail polish"
paint = "white"
/obj/item/nailpolish/navy
name = "navy nail polish"
paint = "navy"
/obj/item/nailpolish/yellow
name = "yellow nail polish"
paint = "yellow"
/obj/item/nailpolish/purple
name = "purple nail polish"
paint = "purple"
/obj/item/nailpolish/Initialize(mapload)
. = ..()
bottle = mutable_appearance('hyperstation/icons/obj/cosmetic.dmi', "nailpolish")
bottle.color = paint
add_overlay(bottle)
/obj/item/nailpolish/attack(mob/M, mob/user)
if(!ismob(M))
return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.nail_style) //to stop stacking bugs
to_chat(user, "<span class='warning'>Remove the old nail polish first!</span>")
if(H == user)
user.visible_message("<span class='notice'>[user] does [user.p_their()] nails with \the [src].</span>", \
"<span class='notice'>You take a moment to apply \the [src]. Perfect!</span>")
H.nail_style = "nails"
H.nail_color = paint
H.update_body()
else
user.visible_message("<span class='warning'>[user] begins to do [H]'s nails with \the [src].</span>", \
"<span class='notice'>You begin to apply \the [src] on [H]'s nails...</span>")
if(do_after(user, 20, target = H))
user.visible_message("[user] does [H]'s nails with \the [src].", \
"<span class='notice'>You apply \the [src] on [H]'s nails.</span>")
H.nail_style = "nails"
H.nail_color = paint
H.update_body()
else
to_chat(user, "<span class='warning'>Where are the nail on that?</span>")

View File

@@ -0,0 +1,44 @@
/obj/item/storage/backpack/gigantic
name = "enormous backpack"
desc = "An absolutely massive backpack for particularly large crewmen."
icon_state = "explorerpack"
item_state = "explorerpack"
/obj/item/storage/backpack/gigantic/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_big_nesting = TRUE
STR.max_combined_w_class = 35
STR.max_w_class = WEIGHT_CLASS_HUGE
/obj/item/storage/backpack/gigantic/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning, bypass_equip_delay_self)
if(!..())
return FALSE
if(M.size_multiplier >= 2.0)
return ..()
else
return FALSE
/obj/item/storage/backpack/gigantic/proc/fallOff(mob/living/wearer)
wearer.dropItemToGround(src, TRUE)
playsound(src.loc, 'sound/items/handling/cloth_drop.ogg', 50, TRUE)
playsound(src.loc, 'sound/items/handling/toolbelt_drop.ogg', 50, TRUE)
wearer.visible_message("<span class='warning'>The [src.name] slips off [wearer]'s now too-small body and falls to the ground!'</span>", "<span class='warning'>The [src.name] slips off your now too-small body and falls to the ground!'</span>")
/obj/item/storage/backpack/gigantic/equipped(mob/equipper, slot)
. = ..()
if(slot ==ITEM_SLOT_BACK)
RegisterSignal(equipper, COMSIG_MOBSIZE_CHANGED,PROC_REF(fallOff))
else
UnregisterSignal(equipper, COMSIG_MOBSIZE_CHANGED)
/obj/item/storage/backpack/gigantic/dropped(mob/user, silent)
UnregisterSignal(user, COMSIG_MOBSIZE_CHANGED)
/obj/item/storage/backpack/gigantic/satchel
name = "enormous satchel"
desc = "An absolutely massive satchel for particularly large crewmen."
icon_state = "satchel-explorer"
item_state = "securitypack"

View File

@@ -0,0 +1,162 @@
//ported from virgo
/obj/structure/railing
name = "railing"
desc = "A railing to stop people from falling"
icon = 'hyperstation/icons/obj/railings.dmi'
var/icon_modifier = "grey_"
icon_state = "grey_railing0"
density = FALSE
layer = 4
anchored = TRUE
flags_1 = ON_BORDER_1
max_integrity = 250
var/heat_resistance = 800
var/health = 70
var/maxhealth = 70
resistance_flags = ACID_PROOF
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
CanAtmosPass = ATMOS_PASS_PROC
var/real_explosion_block //ignore this, just use explosion_block
var/breaksound = "shatter"
var/hitsound = 'sound/effects/Glasshit.ogg'
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
var/check = 0
var/static/list/freepass = typecacheof(list(
/obj/singularity,
/obj/effect/projectile,
/obj/effect/portal,
/obj/effect/abstract,
/obj/effect/hotspot,
/obj/effect/landmark,
/obj/effect/temp_visual,
/obj/effect/light_emitter/tendril,
/obj/effect/collapse,
/obj/effect/particle_effect/ion_trails,
/obj/effect/dummy/phased_mob,
/obj/effect/immovablerod,
/obj/effect/crystalline_reentry
)) //Gotta make sure certain things can phase through it otherwise the railings also block them.
/obj/structure/railing/CanPass(atom/movable/mover, turf/target)
if(istype(mover) && (mover.pass_flags & PASSGLASS) || is_type_in_typecache(mover, freepass))
return TRUE
if(get_dir(loc, target) == dir)
return FALSE
return TRUE
/obj/structure/railing/CheckExit(atom/movable/O, turf/target)
if(istype(O) && (O.pass_flags & PASSGLASS) || is_type_in_typecache(O, freepass))
return TRUE
if(get_dir(O.loc, target) == dir)
return FALSE
return TRUE
/obj/structure/railing/Initialize(mapload)
. = ..()
if(src.anchored)
update_icon(0)
/obj/structure/railing/proc/NeighborsCheck(var/UpdateNeighbors = 1)
check = 0
//if (!anchored) return
var/Rturn = turn(src.dir, -90)
var/Lturn = turn(src.dir, 90)
for(var/obj/structure/railing/R in src.loc)
if ((R.dir == Lturn) && R.anchored)
check |= 32
if (UpdateNeighbors)
R.update_icon(0)
if ((R.dir == Rturn) && R.anchored)
check |= 2
if (UpdateNeighbors)
R.update_icon(0)
for (var/obj/structure/railing/R in get_step(src, Lturn))
if ((R.dir == src.dir) && R.anchored)
check |= 16
if (UpdateNeighbors)
R.update_icon(0)
for (var/obj/structure/railing/R in get_step(src, Rturn))
if ((R.dir == src.dir) && R.anchored)
check |= 1
if (UpdateNeighbors)
R.update_icon(0)
for (var/obj/structure/railing/R in get_step(src, (Lturn + src.dir)))
if ((R.dir == Rturn) && R.anchored)
check |= 64
if (UpdateNeighbors)
R.update_icon(0)
for (var/obj/structure/railing/R in get_step(src, (Rturn + src.dir)))
if ((R.dir == Lturn) && R.anchored)
check |= 4
if (UpdateNeighbors)
R.update_icon(0)
/obj/structure/railing/update_icon(var/UpdateNeighgors = 1)
NeighborsCheck(UpdateNeighgors)
overlays.Cut()
if (!check || !anchored)//|| !anchored
icon_state = "[icon_modifier]railing0"
else
icon_state = "[icon_modifier]railing1"
if (check & 32)
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]corneroverlay")
if ((check & 16) || !(check & 32) || (check & 64))
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]frontoverlay_l")
if (!(check & 2) || (check & 1) || (check & 4))
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]frontoverlay_r")
if(check & 4)
switch (src.dir)
if (NORTH)
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = 32)
if (SOUTH)
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]mcorneroverlay", pixel_x = -32)
if (EAST)
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = -32)
if (WEST)
overlays += image ('hyperstation/icons/obj/railings.dmi', src, "[icon_modifier]mcorneroverlay", pixel_y = 32)
/obj/structure/railing/examine(mob/user)
. = ..()
if(health < maxhealth)
switch(health / maxhealth)
if(0.0 to 0.5)
. += "<span class='warning'>It looks severely damaged!</span>"
if(0.25 to 0.5)
. += "<span class='warning'>It looks damaged!</span>"
if(0.5 to 1.0)
. += "<span class='notice'>It has a few scrapes and dents.</span>"
/obj/structure/railing/take_damage(amount)
health -= amount
if(health <= 0)
visible_message("<span class='warning'>\The [src] breaks down!</span>")
playsound(src, 'sound/effects/grillehit.ogg', 50, 1)
new /obj/item/stack/rods(get_turf(src))
qdel(src)
/obj/structure/railing/MouseDrop_T(mob/living/M, mob/living/user)
if(!istype(user))
return
if(!isliving(user))
return
usr.visible_message("<span class='warning'>[user] starts climbing onto \the [src]!</span>")
if(!do_after(user, 20))
return
if(get_turf(user) == get_turf(src))
usr.forceMove(get_step(src, src.dir))
else
usr.forceMove(get_turf(src))
usr.visible_message("<span class='warning'>[user] climbed over \the [src]!</span>")

View File

@@ -0,0 +1,11 @@
/obj/structure/chair/bench
name = "wooden bench"
icon_state = "bench_middle"
icon = 'hyperstation/icons/obj/bench.dmi'
buildstackamount = 1
buildstacktype = /obj/item/stack/sheet/mineral/wood
/obj/structure/chair/bench/left
icon_state = "bench_left"
/obj/structure/chair/bench/right
icon_state = "bench_right"

View File

@@ -0,0 +1,144 @@
//Duo malfunctioning cryostasis sleepers: Spawns in big makeshift shelters in lavaland.
/obj/effect/mob_spawn/human/duohermit
name = "malfunctioning cryostasis sleeper"
desc = "A humming sleeper with a silhouetted occupant inside. Its stasis function is broken and it's likely being used as a bed."
mob_name = "a stranded hermit"
job_description = "Lavaland Hermit"
icon = 'icons/obj/lavaland/spawners.dmi'
icon_state = "cryostasis_sleeper"
roundstart = FALSE
death = FALSE
random = TRUE
mob_species = /datum/species/human
short_desc = "You are lost."
flavour_text = "You and another have been stranded in this planet for quite some time now. Each day you barely scrape by, and between the terrible \
conditions of your makeshift shelter, the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \
the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you and your friend got here... "
assignedrole = "Hermit"
mirrorcanloadappearance = TRUE
/obj/effect/mob_spawn/human/duohermit/Initialize(mapload)
. = ..()
var/arrpee = rand(1,3)
switch(arrpee)
if(1)
flavour_text += "you were an intern at a rather odd deep space facility. You weren't quite sure how things worked or what they were doing there, but it was your first day on the \
job. A day that was abruptly interrupted by gunfire and alarms. Luckily enough, your handy crowbar skills managed to get you to an escape pod before it was too late.</b>"
outfit.uniform = /obj/item/clothing/under/assistantformal
outfit.shoes = /obj/item/clothing/shoes/sneakers/black
outfit.back = /obj/item/storage/backpack
if(2)
flavour_text += "you were a volunteer test subject for a state of the art deep space facility. You didn't care much about who you were working with, but in the end, the paycheck \
was really, really good. To this day, you're not quite sure which sort of prototype implants were used on you, as you seem to remember little but the headache that struck you once \
the escape pod finally hit the ground and your seatbelt failed to keep you buckled.</b>"
outfit.uniform = /obj/item/clothing/under/rank/scientist
outfit.suit = /obj/item/clothing/suit/toggle/labcoat
outfit.shoes = /obj/item/clothing/shoes/sneakers/black
outfit.back = /obj/item/storage/backpack
if(3)
flavour_text += "you were a doctor at a state of the art deep space facility. For who exactly you were conducting research for, not even you are quite sure. Only that the paycheck \
at the end of the month was good enough. In the end, when said facility was attacked by Nanotransen, you and another were the only ones to have made it out alive. Or so it seemed.</b>"
outfit.uniform = /obj/item/clothing/under/rank/medical
outfit.suit = /obj/item/clothing/suit/toggle/labcoat
outfit.back = /obj/item/storage/backpack/medic
outfit.shoes = /obj/item/clothing/shoes/sneakers/black
/obj/effect/mob_spawn/human/duohermit/Destroy()
new/obj/structure/fluff/empty_cryostasis_sleeper(get_turf(src))
return ..()
/obj/effect/mob_spawn/human/duohermit/special(mob/living/carbon/human/new_spawn)
ADD_TRAIT(new_spawn,TRAIT_EXEMPT_HEALTH_EVENTS,GHOSTROLE_TRAIT)
//Exiles: Stranded exiles that have been left in Snowdin. Can be easily adapted for other roles as well.
/obj/effect/mob_spawn/human/exiled
name = "used bed"
desc = "Still warm."
mob_name = "exiled"
job_description = "Exiles"
icon = 'icons/obj/objects.dmi'
icon_state = "bed"
roundstart = FALSE
death = FALSE
random = TRUE
mob_species = /datum/species/human
short_desc = "You've been left behind."
flavour_text = "As the last escape shuttle left the sector, you were left for dead, stranded in a cold hell where you make do, until hopefully someone finds you. \
Every day, you pause and recollect your memories from before it all happened... "
assignedrole = "Arctic Exile"
mirrorcanloadappearance = TRUE
/obj/effect/mob_spawn/human/exiled/Initialize(mapload)
. = ..()
var/arrpee = rand(1,1)
switch(arrpee)
if(1)
flavour_text += "You were a lowly engineer, hired by GATO to make sure the turbines from their mining operation remained functional. \
You remember the day the mining team descended for the very last time into the depths of the shafts, only to never return. \
The agonizing screams from whatever now haunts those mines still brings a shiver down your spine."
outfit.uniform = /obj/item/clothing/under/assistantformal
outfit.suit = /obj/item/clothing/suit/hooded/wintercoat
outfit.shoes = /obj/item/clothing/shoes/winterboots
outfit.back = /obj/item/storage/backpack
outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
/obj/effect/mob_spawn/human/exiled/Destroy()
new/obj/structure/bed(get_turf(src))
return ..()
/obj/effect/mob_spawn/human/exiled/special(mob/living/carbon/human/new_spawn)
ADD_TRAIT(new_spawn,TRAIT_EXEMPT_HEALTH_EVENTS,GHOSTROLE_TRAIT)
//Villagers: Once a group of servants that worshiped their 'Gods-Kings', but now finally free after their overlords have abandoned the planet.
/obj/effect/mob_spawn/human/villager
name = "used bed"
desc = "Still warm."
mob_name = "villager"
job_description = "Villagers"
icon = 'icons/obj/objects.dmi'
icon_state = "bed"
roundstart = FALSE
death = FALSE
mob_species = /datum/species/human
short_desc = "You're finally free."
flavour_text = "After the God-Kings have abandoned the land, your people are finally free from their oppression. \
Still, the reasons for their departure are a mystery, and now your people need to work together to survive in this world."
assignedrole = "Free villager"
mirrorcanloadappearance = TRUE
/obj/effect/mob_spawn/human/villager/Initialize(mapload)
. = ..()
var/arrpee = rand(1,3)
switch(arrpee)
if(1)
flavour_text += "You were a guard, serving your gods to keep control of you own people. \
Now that they left, you work to defend the village."
outfit.head = /obj/item/clothing/head/pharaoh
outfit.uniform = /obj/item/clothing/under/tunic
outfit.shoes = /obj/item/clothing/shoes/sandal
outfit.back = /obj/item/storage/backpack/satchel/leather
outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
if(2)
flavour_text += "You were a farmer, working extensively for years in the field to feed your people. \
The work hasn't changed much since the departure of the gods..."
outfit.head = /obj/item/clothing/head/rice_hat
outfit.uniform = /obj/item/clothing/under/tunic
outfit.shoes = /obj/item/clothing/shoes/sandal
outfit.back = /obj/item/storage/backpack/satchel/leather
outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
if(3)
flavour_text += "You were a servant, doing any necessary work that was thrown at you. \
At least it gave you experience in a bit of everything, which can be useful in these new times."
outfit.uniform = /obj/item/clothing/under/mummy
outfit.uniform = /obj/item/clothing/under/tunic
outfit.shoes = /obj/item/clothing/shoes/sandal
outfit.back = /obj/item/storage/backpack/satchel/leather
outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
/obj/effect/mob_spawn/human/villager/Destroy()
new/obj/structure/bed(get_turf(src))
return ..()
/obj/effect/mob_spawn/human/villager/special(mob/living/carbon/human/new_spawn)
ADD_TRAIT(new_spawn,TRAIT_EXEMPT_HEALTH_EVENTS,GHOSTROLE_TRAIT)

View File

@@ -0,0 +1,120 @@
#define SAUNA_H2O_TEMP T20C + 20
#define SAUNA_LOG_FUEL 150
#define SAUNA_PAPER_FUEL 5
#define SAUNA_MAXIMUM_FUEL 3000
#define SAUNA_WATER_PER_WATER_UNIT 5
/obj/structure/sauna_oven
name = "sauna oven"
desc = "A modest sauna oven with rocks. Add some fuel, pour some water and enjoy the moment."
icon = 'hyperstation/icons/obj/structures/sauna_oven.dmi'
icon_state = "sauna_oven"
density = TRUE
anchored = TRUE
resistance_flags = FIRE_PROOF
var/lit = FALSE
var/fuel_amount = 0
var/water_amount = 0
/obj/structure/sauna_oven/examine(mob/user)
. = ..()
. += "<span class='notice'>The rocks are [water_amount ? "moist" : "dry"].</span>"
. += "<span class='notice'>There's [fuel_amount ? "some fuel" : "no fuel"] in the oven.</span>"
/obj/structure/sauna_oven/Destroy()
if(lit)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/structure/sauna_oven/attack_hand(mob/user)
. = ..()
if(.)
return
if(lit)
lit = FALSE
STOP_PROCESSING(SSobj, src)
user.visible_message("<span class='notice'>[user] turns on [src].</span>", "<span class='notice'>You turn on [src].</span>")
else if (fuel_amount)
lit = TRUE
START_PROCESSING(SSobj, src)
user.visible_message("<span class='notice'>[user] turns off [src].</span>", "<span class='notice'>You turn off [src].</span>")
update_icon()
/obj/structure/sauna_oven/update_overlays()
. = ..()
if(lit)
. += "sauna_oven_on_overlay"
/obj/structure/sauna_oven/update_icon()
..()
icon_state = "[lit ? "sauna_oven_on" : initial(icon_state)]"
/obj/structure/sauna_oven/attackby(obj/item/T, mob/user)
if(T.tool_behaviour == TOOL_WRENCH)
to_chat(user, "<span class='notice'>You begin to deconstruct [src].</span>")
if(T.use_tool(src, user, 60, volume=50))
to_chat(user, "<span class='notice'>You successfully deconstructed [src].</span>")
new /obj/item/stack/sheet/mineral/wood(get_turf(src), 30)
qdel(src)
return TRUE
else if(istype(T, /obj/item/reagent_containers))
var/obj/item/reagent_containers/reagent_container = T
if(!reagent_container.is_open_container())
return ..()
if(reagent_container.reagents.has_reagent(/datum/reagent/water))
reagent_container.reagents.remove_reagent(/datum/reagent/water, 5)
user.visible_message("<span class='notice'>[user] pours some \
water into [src].</span>", "<span class='notice'>You pour \
some water to [src].</span>")
water_amount += 5 * SAUNA_WATER_PER_WATER_UNIT
return TRUE
else
to_chat(user, "<span class='warning'>There's no water in [reagent_container]</span>")
return FALSE
else if(istype(T, /obj/item/stack/sheet/mineral/wood))
var/obj/item/stack/sheet/mineral/wood/wood = T
if(fuel_amount > SAUNA_MAXIMUM_FUEL)
to_chat(user, "<span class='warning'>You can't fit any more of [T] in [src]!</span>")
return FALSE
fuel_amount += SAUNA_LOG_FUEL * wood.amount
wood.use(wood.amount)
user.visible_message("<span class='notice'>[user] tosses some \
wood into [src].</span>", "<span class='notice'>You add \
some fuel to [src].</span>")
return TRUE
else if(istype(T, /obj/item/paper_bin))
var/obj/item/paper_bin/paper_bin = T
user.visible_message("<span class='notice'>[user] throws [T] into \
[src].</span>", "<span class='notice'>You add [T] to [src].\
</span>")
fuel_amount += SAUNA_PAPER_FUEL * paper_bin.total_paper
qdel(paper_bin)
return TRUE
else if(istype(T, /obj/item/paper))
user.visible_message("<span class='notice'>[user] throws [T] into \
[src].</span>", "<span class='notice'>You throw [T] into [src].\
</span>")
fuel_amount += SAUNA_PAPER_FUEL
qdel(T)
return TRUE
return ..()
/obj/structure/sauna_oven/process()
if(water_amount)
water_amount--
var/turf/pos = get_turf(src)
if(pos)
pos.atmos_spawn_air("water_vapor=10;TEMP=[SAUNA_H2O_TEMP]")
fuel_amount--
if(fuel_amount <= 0)
lit = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
#undef SAUNA_H2O_TEMP
#undef SAUNA_LOG_FUEL
#undef SAUNA_PAPER_FUEL
#undef SAUNA_MAXIMUM_FUEL
#undef SAUNA_WATER_PER_WATER_UNIT

View File

@@ -0,0 +1,339 @@
//Jay Sparrow
/datum/game_mode
var/list/datum/mind/lewd = list()
/datum/mind/
var/sexed = FALSE //General flag for completion check
//TODO - Move this somewhere else
GLOBAL_LIST_INIT(hyper_special_roles, list(
ROLE_LEWD_TRAITOR = /datum/game_mode/traitor/lewd
))
/datum/game_mode/traitor/lewd
name = "lewd traitor"
config_tag = "lewd traitor"
antag_flag = ROLE_LEWD_TRAITOR
false_report_weight = 20 //Reports of traitors are pretty common.
restricted_jobs = list("Cyborg")
protected_jobs = list() //Anyone can be lewd op. Even heads.
required_players = 0
required_enemies = 0
announce_span = "danger"
announce_text = "There are lewd agents on the station!\n\
<span class='danger'>Traitors</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the traitors succeed!"
//var/list/datum/mind/lewd
traitors_possible = 10 //hard limit on traitors if scaling is turned off //Let it be high for now. Testing phase.
num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
antag_datum = /datum/antagonist/traitor/lewd //what type of antag to create
/datum/antagonist/traitor/lewd
name = "Lewd Traitor"
roundend_category = "traitors"
antagpanel_category = "Traitor"
job_rank = ROLE_LEWD_TRAITOR
//antag_moodlet = /datum/mood_event/focused //No special moodlet yet
special_role = ROLE_LEWD_TRAITOR
employer = "An interested voyeur"
give_objectives = TRUE
should_give_codewords = FALSE
should_equip = TRUE
traitor_kind = TRAITOR_HUMAN //Set on initial assignment
can_hijack = HIJACK_NEUTRAL
//Custom uplink list - aaaaaaaaaaaaaa
var/list/lewd_uplink_list = list()
var/list/lewd_uplink_list_raw = list(
/datum/uplink_item/bundles_TC/random,
/datum/uplink_item/bundles_TC/telecrystal,
/datum/uplink_item/bundles_TC/telecrystal/five,
/datum/uplink_item/bundles_TC/telecrystal/twenty,
/datum/uplink_item/dangerous/foamsmg,
/datum/uplink_item/dangerous/foammachinegun,
/datum/uplink_item/dangerous/foampistol,
/datum/uplink_item/dangerous/phantomthief,
/datum/uplink_item/stealthy_weapons/dart_pistol,
/datum/uplink_item/stealthy_weapons/crossbow,
/datum/uplink_item/stealthy_weapons/sleepy_pen,
/datum/uplink_item/stealthy_weapons/suppressor,
/datum/uplink_item/stealthy_weapons/soap,
/datum/uplink_item/stealthy_weapons/soap_clusterbang,
/datum/uplink_item/ammo/pistolzzz,
/datum/uplink_item/ammo/shotgun/stun,
/datum/uplink_item/ammo/toydarts,
/datum/uplink_item/stealthy_tools/ai_detector,
/datum/uplink_item/stealthy_tools/chameleon,
/datum/uplink_item/stealthy_tools/chameleon_proj,
/datum/uplink_item/stealthy_tools/emplight,
/datum/uplink_item/stealthy_tools/syndigaloshes,
/datum/uplink_item/stealthy_tools/jammer,
/datum/uplink_item/stealthy_tools/smugglersatchel,
/datum/uplink_item/device_tools/binary,
/datum/uplink_item/device_tools/compressionkit,
/datum/uplink_item/device_tools/briefcase_launchpad,
/datum/uplink_item/device_tools/camera_bug,
/datum/uplink_item/device_tools/military_belt,
/datum/uplink_item/device_tools/frame,
/datum/uplink_item/device_tools/toolbox,
/datum/uplink_item/device_tools/medkit,
/datum/uplink_item/device_tools/surgerybag,
/datum/uplink_item/device_tools/encryptionkey,
/datum/uplink_item/device_tools/thermal,
/datum/uplink_item/implants/radio,
/datum/uplink_item/implants/reviver,
/datum/uplink_item/implants/stealthimplant,
/datum/uplink_item/implants/thermals,
/datum/uplink_item/implants/uplink,
/datum/uplink_item/implants/xray,
/datum/uplink_item/role_restricted/goldenbox,
/datum/uplink_item/role_restricted/chemical_gun,
/datum/uplink_item/badass/syndiecash,
/datum/uplink_item/badass/phantomthief,
/datum/uplink_item/badass/syndiecards,
/datum/uplink_item/badass/syndiecigs)
/datum/game_mode/traitor/lewd/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
GATO employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
/datum/mind/proc/make_LewdTraitor()
if(!(has_antag_datum(/datum/antagonist/traitor/lewd)))
add_antag_datum(/datum/antagonist/traitor/lewd)
/datum/admins/proc/makeLewdtraitors()
to_chat(GLOB.admins, "makeLewd_traitors called")
var/datum/game_mode/traitor/lewd/temp = new
//if(CONFIG_GET(flag/protect_roles_from_antagonist))
//continue
//if(CONFIG_GET(flag/protect_assistant_from_antagonist))
//continue
var/list/mob/living/carbon/human/candidates = list()
var/mob/living/carbon/human/H = null
var/list/mob/living/carbon/human/targets = list()
//var/mob/living/carbon/human/T = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
if(isReadytoRumble(applicant, ROLE_LEWD_TRAITOR))
if(temp.age_check(applicant.client))
if(!(applicant.job in temp.restricted_jobs))
candidates += applicant
for(var/mob/living/carbon/human/target in GLOB.player_list)
if(target.client?.prefs?.noncon)
if(!(target.job in temp.restricted_jobs))
targets += target
if(candidates.len)
var/numTraitors = min(candidates.len, targets.len, 1) //This number affects the maximum number of traitors. We want 1 for right now.
if(numTraitors == 0)
to_chat(GLOB.admins, "No lewd traitors created. Are there any valid targets?")
return FALSE
for(var/i = 0, i<numTraitors, i++)
H = pick(candidates)
H.mind.make_LewdTraitor()
candidates.Remove(H)
return TRUE
return FALSE
/datum/antagonist/traitor/lewd/proc/forge_objectives()
forge_single_objective()
/datum/antagonist/traitor/lewd/forge_human_objectives()
forge_single_objective()
/datum/antagonist/traitor/lewd/forge_single_objective()
var/datum/objective/noncon/noncon_objective = new
noncon_objective.owner = owner
noncon_objective.target = noncon_objective.find_target()
add_objective(noncon_objective)
return
/datum/antagonist/traitor/lewd/greet()
to_chat(owner.current, "<span class='userlove'>You are the [owner.special_role].</span>")
owner.announce_objectives()
if(should_give_codewords)
give_codewords()
/datum/antagonist/traitor/lewd/on_gain()
if(owner.current && isAI(owner.current))
traitor_kind = TRAITOR_AI
SSticker.mode.traitors += owner
owner.special_role = special_role
if(give_objectives)
forge_objectives()
finalize_traitor()
/datum/antagonist/traitor/lewd/finalize_traitor()
switch(traitor_kind)
if(TRAITOR_AI)
add_law_zero()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
owner.current.grant_language(/datum/language/codespeak)
if(TRAITOR_HUMAN)
if(should_equip)
equip(silent)
for(var/obj/I in owner.current.GetAllContents())
var/datum/component/uplink/hidden_uplink = I.GetComponent(/datum/component/uplink)
if(hidden_uplink)
lewd_uplink_list = get_custom_uplink_items(lewd_uplink_list_raw, /datum/game_mode/traitor/lewd, TRUE, FALSE)
hidden_uplink.uplink_items = lewd_uplink_list
hidden_uplink.telecrystals = 12
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
greet()
/datum/objective/noncon/New(var/datum/mind/_owner)
GLOB.objectives += src // CITADEL EDIT FOR CRYOPODS
if(_owner)
owner = _owner
//GS13 - this shit's just fucking weird lol, gtfo
// /datum/objective/noncon/find_target()
// //..()
// //to_chat(world, "<span class='boldannounce'>TEST: noncon/find_target() called</span>")
// var/list/datum/mind/targets = list()
// var/list/datum/mind/owners = get_owners()
// for(var/datum/mind/candidate in SSticker.minds)
// if (!(candidate in owners) && ishuman(candidate.current) && (candidate.current.client))
// if(candidate.current.client?.prefs?.noncon == 1)
// targets += candidate
// if(targets.len > 0)
// target = pick(targets)
// else
// target = null
// update_explanation_text()
// return target
// /datum/objective/noncon/check_completion()
// if(!target)
// return TRUE
// else
// return target.sexed
// /datum/objective/noncon/update_explanation_text()
// if(target)
// explanation_text = "Locate [target.name], and sate your lust."
// else
// explanation_text = "Free Lewd Objective"
/datum/antagonist/traitor/lewd/roundend_report()
var/list/result = list()
var/traitorwin = TRUE
result += printplayer(owner)
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[owner.key]
if(H)
TC_uses = H.total_spent
uplink_true = TRUE
purchases += H.generate_render(FALSE)
var/objectives_text = ""
if(objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE
count++
if(uplink_true)
var/uplink_text = "(used [TC_uses] TC) [purchases]"
if(TC_uses==0 && traitorwin)
var/static/icon/badass = icon('icons/badass.dmi', "badass")
uplink_text += "<BIG>[icon2html(badass, world)]</BIG>"
result += uplink_text
result += objectives_text
var/special_role_text = lowertext(name)
if(traitorwin)
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
else
result += "<span class='redtext'>The [special_role_text] has failed!</span>"
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
return result.Join("<br>")
/proc/get_custom_uplink_items(var/list/custom_uplink_list = null, var/datum/game_mode/gamemode = null, allow_sales = TRUE, allow_restricted = TRUE)
var/list/filtered_uplink_items = list()
var/list/sale_items = list()
if(!custom_uplink_list)
for(var/path in GLOB.uplink_items)
custom_uplink_list += new path
for(var/path in custom_uplink_list)
var/datum/uplink_item/I = new path
if(!I.item)
continue
if(I.include_modes.len)
if(!gamemode && SSticker.mode && !(SSticker.mode.type in I.include_modes))
continue
if(gamemode && !(gamemode in I.include_modes))
continue
if(I.exclude_modes.len)
if(!gamemode && SSticker.mode && (SSticker.mode.type in I.exclude_modes))
continue
if(gamemode && (gamemode in I.exclude_modes))
continue
if(I.player_minimum && I.player_minimum > GLOB.joined_player_list.len)
continue
if (I.restricted && !allow_restricted)
continue
if(!filtered_uplink_items[I.category])
filtered_uplink_items[I.category] = list()
filtered_uplink_items[I.category][I.name] = I
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1)
sale_items += I
if(allow_sales)
for(var/i in 1 to 2) //Smaller list, fewer discounts
var/datum/uplink_item/I = pick_n_take(sale_items)
var/datum/uplink_item/A = new I.type
var/discount = A.get_discount()
var/list/disclaimer = list("Void where prohibited.", "Not recommended for children.", "Contains small parts.", "Check local laws for legality in region.", "Do not taunt.", "Not responsible for direct, indirect, incidental or consequential damages resulting from any defect, error or failure to perform.", "Keep away from fire or flames.", "Product is provided \"as is\" without any implied or expressed warranties.", "As seen on TV.", "For recreational use only.", "Use only as directed.", "16% sales tax will be charged for orders originating within Space Nebraska.")
A.limited_stock = 1
I.refundable = FALSE //THIS MAN USES ONE WEIRD TRICK TO GAIN FREE TC, CODERS HATES HIM!
A.refundable = FALSE
if(A.cost >= 20) //Tough love for nuke ops
discount *= 0.5
A.cost = max(round(A.cost * discount),1)
A.category = "Discounted Gear"
A.name += " ([round(((initial(A.cost)-A.cost)/initial(A.cost))*100)]% off!)"
A.desc += " Normally costs [initial(A.cost)] TC. All sales final. [pick(disclaimer)]"
A.item = I.item
if(!filtered_uplink_items[A.category])
filtered_uplink_items[A.category] = list()
filtered_uplink_items[A.category][A.name] = A
return filtered_uplink_items

View File

@@ -0,0 +1,84 @@
//Jay Sparrow
//A less murder traitor for low chaos dynamic rounds.
/datum/game_mode/traitor/thief
name = "thief traitor"
config_tag = "thief traitor"
antag_flag = ROLE_TRAITOR
false_report_weight = 20 //Reports of traitors are pretty common.
restricted_jobs = list("AI","Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 0
required_enemies = 0
announce_span = "danger"
announce_text = "There are enemy agents on the station!\n\
<span class='danger'>Traitors</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the traitors succeed!"
traitors_possible = 3 //hard limit on traitors if scaling is turned off //Let it be high for now. Testing phase.
num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
antag_datum = /datum/antagonist/traitor/thief //what type of antag to create
/datum/antagonist/traitor/thief
name = "Thief Traitor"
roundend_category = "traitors"
antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
antag_moodlet = /datum/mood_event/focused
special_role = ROLE_TRAITOR
employer = "The Syndicate"
give_objectives = TRUE
should_give_codewords = TRUE
should_equip = TRUE
traitor_kind = TRAITOR_HUMAN //Set on initial assignment
can_hijack = HIJACK_NEUTRAL
/datum/game_mode/traitor/thief/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
GATO employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
/datum/mind/proc/make_ThiefTraitor()
if(!(has_antag_datum(/datum/antagonist/traitor/thief)))
add_antag_datum(/datum/antagonist/traitor/thief)
/datum/antagonist/traitor/thief/proc/forge_objectives()
forge_single_objective()
forge_single_objective()
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
/datum/antagonist/traitor/thief/forge_human_objectives()
forge_single_objective()
forge_single_objective()
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
/datum/antagonist/traitor/thief/forge_single_objective()
if(prob(15) && !(locate(/datum/objective/download) in owner.objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
var/datum/objective/download/download_objective = new
download_objective.owner = owner
download_objective.gen_amount_goal()
add_objective(download_objective)
else
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
add_objective(steal_objective)
return
/datum/antagonist/traitor/thief/on_gain()
if(owner.current && isAI(owner.current))
traitor_kind = TRAITOR_AI
SSticker.mode.traitors += owner
owner.special_role = special_role
if(give_objectives)
forge_objectives()
finalize_traitor()

View File

@@ -0,0 +1,50 @@
//mob based off the game Carrion.
//replica sprite made by quotefox
/mob/living/simple_animal/hostile/carrion
name = "mass of red tentacles"
desc = "A creature composed of tentacles and teeth, you aren't sure where it starts and where it ends."
icon = 'hyperstation/icons/mobs/carrion.dmi'
icon_state = "c_idle"
icon_living = "c_idle"
icon_dead = "idle"
gender = NEUTER
speak_chance = 0
turns_per_move = 2
turns_per_move = 3
maxHealth = 300
health = 300
see_in_dark = 7
response_help = "pets"
response_disarm = "pushes aside"
response_harm = "attacks"
melee_damage_lower = 12
melee_damage_upper = 20
attacktext = "attacks"
attack_sound = 'sound/weapons/bite.ogg'
faction = list("hostile")
ranged = 1
harm_intent_damage = 5
obj_damage = 60
a_intent = INTENT_HARM
ventcrawler = 1
death_sound = 'sound/voice/ed209_20sec.ogg'
deathmessage = "lets out scream and its tentacles shrivel away..."
move_to_delay = 4
loot = list(/obj/effect/gibspawner/human)
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 150
maxbodytemp = 500
do_footstep = TRUE
/mob/living/simple_animal/hostile/carrion/OpenFire(atom/the_target)
var/dist = get_dist(src,the_target)
Beam(the_target, "tentacle", time=dist*2, maxdistance=dist, beam_sleep_time = 5)
the_target.attack_animal(src)
/mob/living/simple_animal/hostile/carrion/Initialize(mapload)
//Move the sprite into position, cant use Pixel_X and Y, causes issues with the tenticle sprite!
..()
var/matrix/M = src.transform
src.transform = M.Translate(-32,-32)

View File

@@ -0,0 +1,56 @@
/mob/living/dancercaptain
name = "Captain Beats"
desc = "A captain cursed to dance for all eternity!"
icon = 'hyperstation/icons/mobs/dancer/captain.dmi'
icon_state = "idle"
var/danceaction = 1
var/lastaction = 0 //when the last action was!
var/actiontime = 4
var/list/dancefloor_turfs
var/list/dancefloor_turfs_types
var/dancefloor_exists = FALSE
/mob/living/dancercaptain/Move(atom/newloc, direct)
if(!danceaction)
if(!(world.time > lastaction))
return // no move for you!
animate(src, pixel_x, pixel_y = pixel_y + 10, time = 0.7, 0)
. = ..()
danceaction = 0 //you did your move
lastaction = world.time+actiontime //next action time
sleep(1)
animate(src, pixel_x, pixel_y = pixel_y - 10, time = 0.7, 0)
sleep(1)
LAZYINITLIST(dancefloor_turfs)
LAZYINITLIST(dancefloor_turfs_types)
if(dancefloor_exists) //remove the old one!
dancefloor_exists = FALSE
for(var/i in 1 to dancefloor_turfs.len)
var/turf/T = dancefloor_turfs[i]
T.ChangeTurf(dancefloor_turfs_types[i])
var/list/funky_turfs = RANGE_TURFS(2, src)
dancefloor_exists = TRUE
var/i = 1
dancefloor_turfs.len = funky_turfs.len
dancefloor_turfs_types.len = funky_turfs.len
for(var/t in funky_turfs)
if(!(istype(t, /turf/closed))) //dont change walls
var/turf/T = t
dancefloor_turfs[i] = T
dancefloor_turfs_types[i] = T.type
T.ChangeTurf((i % 2 == 0) ? /turf/open/floor/light/colour_cycle/dancefloor_a : /turf/open/floor/light/colour_cycle/dancefloor_b)
i++
/mob/living/dancercaptain/Initialize(mapload)
. = ..()
lastaction = round(world.time) //round to the nearest second! to keep in beat!
/mob/living/dancercaptain/proc/mtimer()

View File

@@ -0,0 +1,33 @@
/datum/emote/living/chirp
key = "chirp"
key_third_person = "chirps!"
message = "chirps!"
emote_type = EMOTE_AUDIBLE
muzzle_ignore = FALSE
restraint_check = FALSE
mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai)
/datum/emote/living/chirp/run_emote(mob/living/user, params)
if(!(. = ..()))
return
if(user.nextsoundemote >= world.time)
return
user.nextsoundemote = world.time + 7
playsound(user, 'sound/voice/chirp.ogg', 50, 1, -1)
/datum/emote/living/caw
key = "caw"
key_third_person = "caws!"
message = "caws!"
emote_type = EMOTE_AUDIBLE
muzzle_ignore = FALSE
restraint_check = FALSE
mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai)
/datum/emote/living/caw/run_emote(mob/living/user, params)
if(!(. = ..()))
return
if(user.nextsoundemote >= world.time)
return
user.nextsoundemote = world.time + 7
playsound(user, 'sound/voice/caw.ogg', 50, 1, -1)

View File

@@ -0,0 +1,311 @@
//HUGBOT
//HUGBOT PATHFINDING
//HUGBOT ASSEMBLY
/mob/living/simple_animal/bot/hugbot
name = "\improper Hugbot"
desc = "A little cudly robot. He looks excited."
icon = 'hyperstation/icons/mobs/aibots.dmi'
icon_state = "hugbot0"
density = FALSE
anchored = FALSE
health = 20
maxHealth = 20
pass_flags = PASSMOB
status_flags = (CANPUSH | CANSTUN)
bot_type = HUG_BOT
model = "Hugbot"
bot_core_type = /obj/machinery/bot_core/hugbot
window_id = "autohug"
window_name = "Automatic Hugging Unit v1.0 Alpha"
path_image_color = "#FFDDDD"
base_speed = 4
var/stationary_mode = 0 //If enabled, the Hugbot will not move automatically.
var/mob/living/carbon/patient = null
var/mob/living/carbon/oldpatient = null
var/last_found = 0
/mob/living/simple_animal/bot/hugbot/update_icon()
cut_overlays()
if(!on)
icon_state = "hugbot0"
return
if(IsStun())
icon_state = "hugbota"
return
if(mode == BOT_HEALING)
icon_state = "hugbots[stationary_mode]"
return
else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
icon_state = "hugbot2"
else
icon_state = "hugbot1"
/mob/living/simple_animal/bot/medbot/Initialize(mapload, new_skin)
. = ..()
update_icon()
/mob/living/simple_animal/bot/hugbot/update_canmove()
. = ..()
update_icon()
/mob/living/simple_animal/bot/hugbot/bot_reset()
..()
update_icon()
/mob/living/simple_animal/bot/hugbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
path = list()
patient = null
mode = BOT_IDLE
last_found = world.time
update_icon()
/mob/living/simple_animal/bot/hugbot/set_custom_texts()
text_hack = "You bypass [name]'s manipulator pressure sensors."
text_dehack = "You rewire [name]'s manipulator pressure sensors."
text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
/mob/living/simple_animal/bot/hugbot/attack_paw(mob/user)
return attack_hand(user)
/mob/living/simple_animal/bot/hugbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += showpai(user)
dat += "<TT><B>Hugging Unit Controls v1.0 Alpha</B></TT><BR><BR>"
dat += "Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel panel is [open ? "opened" : "closed"]<BR>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
if(!locked || issilicon(user) || IsAdminGhost(user))
dat += "Patrol Station: <a href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "Yes" : "No"]</a><br>"
dat += "Stationary Mode: <a href='?src=[REF(src)];stationary=1'>[stationary_mode ? "Yes" : "No"]</a><br>"
return dat
/mob/living/simple_animal/bot/hugbot/Topic(href, href_list)
if(..())
return TRUE
update_controls()
return
/mob/living/simple_animal/bot/hugbot/attackby(obj/item/W as obj, mob/user as mob, params)
var/current_health = health
..()
if(health < current_health) //if medbot took some damage
step_to(src, (get_step_away(src,user)))
/mob/living/simple_animal/bot/hugbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, "<span class='notice'>You short out [src]'s manipulator pressure sensors.</span>")
audible_message("<span class='danger'>[src]'s arm twitches violently!</span>")
flick("medibot_spark", src)
playsound(src, "sparks", 75, 1)
/mob/living/simple_animal/bot/hugbot/proc/assess_patient(mob/living/carbon/C)
//Time to see if they need medical help!
if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
return FALSE //welp too late for them!
if(!(loc == C.loc) && !(isturf(C.loc) && isturf(loc)))
return FALSE
if(ishuman(C))
var/mob/living/carbon/human/H = C
var/datum/component/mood/mood = H.GetComponent(/datum/component/mood)
if(emagged != 2) // EVERYONE GETS HUGS!
for(var/datum/mood_event/i in mood.mood_events)
if (i.description == "<span class='nicegreen'>Hugs are nice.</span>\n" )
return FALSE
else if (C.IsKnockdown())
return FALSE
return TRUE
return FALSE
/mob/living/simple_animal/bot/hugbot/process_scan(mob/living/carbon/human/H)
if(H.stat == DEAD)
return
if((H == oldpatient) && (world.time < last_found + 200))
return
if(assess_patient(H))
last_found = world.time
return H
else
return
/mob/living/simple_animal/bot/hugbot/handle_automated_action()
if(!..())
return
if(mode == BOT_HEALING)
medicate_patient(patient)
return
if(IsStun())
oldpatient = patient
patient = null
mode = BOT_IDLE
update_icon()
return
if(frustration > 8)
oldpatient = patient
soft_reset()
if(QDELETED(patient))
var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
oldpatient = patient
if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
if(mode != BOT_HEALING)
mode = BOT_HEALING
update_icon()
frustration = 0
medicate_patient(patient)
return
//Patient has moved away from us!
else if(patient && path.len && (get_dist(patient,path[path.len]) > 2))
path = list()
mode = BOT_IDLE
last_found = world.time
else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another.
soft_reset()
return
if(patient && path.len == 0 && (get_dist(src,patient) > 1))
path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,id=access_card)
mode = BOT_MOVING
if(!path.len) //try to get closer if you can't reach the patient directly
path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,1,id=access_card)
if(!path.len) //Do not chase a patient we cannot reach.
soft_reset()
if(path.len > 0 && patient)
if(!bot_move(path[path.len]))
oldpatient = patient
soft_reset()
return
if(path.len > 8 && patient)
frustration++
if(auto_patrol && !stationary_mode && !patient)
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
start_patrol()
if(mode == BOT_PATROL)
bot_patrol()
return
/mob/living/simple_animal/bot/hugbot/UnarmedAttack(atom/A)
if(iscarbon(A))
var/mob/living/carbon/C = A
patient = C
mode = BOT_HEALING
update_icon()
medicate_patient(C)
update_icon()
else
..()
/mob/living/simple_animal/bot/hugbot/proc/medicate_patient(mob/living/carbon/C)
if(!on)
return
if(!istype(C))
oldpatient = patient
soft_reset()
return
if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
oldpatient = patient
soft_reset()
return
visible_message("<span class='notice'>[src] hugs [C] to make [C.p_them()] feel better!</span>", \
"<span class='notice'>You hug [C] to make [C.p_them()] feel better!</span>")
SEND_SIGNAL(C, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
if (emagged != 2)
C.AdjustStun(-60)
C.AdjustKnockdown(-60)
C.AdjustUnconscious(-60)
C.AdjustSleeping(-100)
if(recoveringstam)
C.adjustStaminaLoss(-15)
else if(resting)
C.resting = 0
C.update_canmove()
else
C.Knockdown(100)
C.Stun(100)
C.update_canmove()
playsound(C.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
oldpatient = patient
patient = null
mode = BOT_IDLE
update_icon()
return
/mob/living/simple_animal/bot/hugbot/explode()
on = FALSE
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
do_sparks(3, TRUE, src)
..()
/obj/machinery/bot_core/hugbot
req_one_access = list(ACCESS_ROBOTICS)
/obj/item/bot_assembly/hugbot
desc = "It's a box of hugs with an arm attached."
name = "incomplete hugbot assembly"
icon = 'hyperstation/icons/mobs/aibots.dmi'
icon_state = "hugbot_arm"
created_name = "Hugbot"
/obj/item/bot_assembly/hugbot/attackby(obj/item/W, mob/user, params)
..()
if(istype(W, /obj/item/assembly/prox_sensor))
if(!can_finish_build(W, user))
return
var/mob/living/simple_animal/bot/hugbot/A = new(drop_location())
A.name = created_name
A.robot_arm = W.type
to_chat(user, "<span class='notice'>You add [W] to [src]. Beep boop!</span>")
qdel(W)
qdel(src)
/obj/item/storage/box/hug/attackby(obj/item/I, mob/user, params)
if((istype(I, /obj/item/bodypart/l_arm/robot)) || (istype(I, /obj/item/bodypart/r_arm/robot)))
if(contents.len) //prevent accidently deleting contents
to_chat(user, "<span class='warning'>You need to empty [src] out first!</span>")
return
if(!user.temporarilyRemoveItemFromInventory(I))
return
qdel(I)
to_chat(user, "<span class='notice'>You add [I] to the [src]! You've got a hugbot assembly now!</span>")
var/obj/item/bot_assembly/hugbot/A = new
qdel(src)
user.put_in_hands(A)
else
return ..()

View File

@@ -0,0 +1,414 @@
/mob/living/simple_animal/hostile/hs13mimic
name = "Mimic"
icon = 'hyperstation/icons/mobs/mimic.dmi'
desc = "A writhing mass of black flesh, unlikely to be happy to see you."
icon_state = "mimic"
icon_living = "mimic"
icon_dead = "mimic_dead"
gender = NEUTER
speak_chance = 0
maxHealth = 35
health = 35
turns_per_move = 5
move_to_delay = 1
speed = 0
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
pass_flags = PASSTABLE
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 2)
response_help = "prods"
response_disarm = "pushes aside"
response_harm = "smacks"
melee_damage_lower = 8
melee_damage_upper = 12
attacktext = "stings"
attack_sound = 'hyperstation/sound/creatures/mimic/mimic_attack.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
ventcrawler = VENTCRAWLER_ALWAYS
blood_volume = 0
faction = list("mimic")
gold_core_spawnable = NO_SPAWN
vision_range = 1
aggro_vision_range = 9
wander = TRUE
minbodytemp = 250 //weak to cold
maxbodytemp = 1500
pressure_resistance = 1200
sight = SEE_MOBS
var/stealthed = TRUE
var/knockdown_people = 1
var/playerTransformCD = 50
var/playerTfTime
var/static/mimic_blacklisted_transform_items = typecacheof(list(
/obj/item/projectile,
/obj/item/radio/intercom,
/mob/living/simple_animal/bot))
var/transformsound = 'hyperstation/sound/creatures/mimic/mimic_transform.ogg'
var/playstyle_string = "<span class='boldannounce'>You are a mimic</span></b>, a tricky creature that can take the form of \
almost any item nearby by shift-clicking it. While morphed, you move slowly and do less damage. \
Finally, you can restore yourself to your original form while morphed by shift-clicking yourself. \
Attacking carbon lifeforms will heal you at the cost of destructuring their DNA. \
You can also change your form to that of simple animals, but be wary that anyone examining you can \
find out.</b>"
/mob/living/simple_animal/hostile/hs13mimic/Initialize(mapload)
. = ..()
trytftorandomobject() // When initialized, make sure they take the form of something.
/mob/living/simple_animal/hostile/hs13mimic/Login()
. = ..()
SEND_SOUND(src, sound('sound/ambience/antag/ling_aler.ogg'))
to_chat(src, src.playstyle_string)
/mob/living/simple_animal/hostile/hs13mimic/attack_hand(mob/living/carbon/human/M)
. = ..()
if(stealthed && stat == CONSCIOUS)
if(M.a_intent == INTENT_HELP)//They're trying to pick us up! We tricked them boys! *plays runescape sea shanty*
target = M
guaranteedknockdown(M)
trigger() // Bring our friends if any!
/mob/living/simple_animal/hostile/hs13mimic/AttackingTarget()
. = ..()
if(iscarbon(target))
var/mob/living/carbon/C = target
if(.)
if(stealthed && knockdown_people) //Guaranteed knockdown if we get the first hit while disguised. Typically, only players can do this since NPC mimics transform first before attacking.
restore()
C.Knockdown(40)
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
"<span class='userdanger'>\The [src] knocks you down!</span>")
else if(knockdown_people && prob(15))
C.Knockdown(40)
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
"<span class='userdanger'>\The [src] knocks you down!</span>")
if(C.nutrition >= 15)
C.nutrition -= (rand(7,15)) //They lose 7-15 nutrition
adjustBruteLoss(-3) //We heal 3 damage
C.adjustCloneLoss(rand(2,4)) //They also take a bit of cellular damage.
if(isanimal(target))
var/mob/living/simple_animal/A = target
if(.)
if(stealthed)
restore()
if(A.stat == CONSCIOUS)
adjustBruteLoss(-3) //We heal 3 damage
/mob/living/simple_animal/hostile/hs13mimic/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
trigger()
. = ..()
/mob/living/simple_animal/hostile/hs13mimic/FindTarget()
. = ..()
if(.)
trigger() //We have a target! Trigger!
else if(!target && !stealthed) //Has no target, isn't stealthed, let's search for an object to transform
trytftorandomobject()
/mob/living/simple_animal/hostile/hs13mimic/death(gibbed)
restore() //We died. Restore form.
. = ..()
/mob/living/simple_animal/hostile/hs13mimic/med_hud_set_health()
if(stealthed)
var/image/holder = hud_list[HEALTH_HUD]
holder.icon_state = null
return //we hide medical hud while morphed
..()
/mob/living/simple_animal/hostile/hs13mimic/med_hud_set_status()
if(stealthed)
var/image/holder = hud_list[STATUS_HUD]
holder.icon_state = null
return //we hide medical hud while morphed
..()
/mob/living/simple_animal/hostile/hs13mimic/proc/mimicTransformList() //The list of default things to transform needs to be bigger, consider this in the future.
var/transformitem = rand(1,100)
medhudupdate()
wander = FALSE
vision_range = initial(vision_range)
switch(transformitem)
if(1 to 10)
name = "drinking glass"
icon = 'icons/obj/drinks.dmi'
icon_state = "glass_empty"
desc = "Your standard drinking glass."
if(11 to 20)
name = "insulated gloves"
icon = 'icons/obj/clothing/gloves.dmi'
icon_state = "yellow"
desc = "These gloves will protect the wearer from electric shock."
if(21 to 30)
name = "stunbaton"
desc = "A stun baton for incapacitating people with."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "stunbaton"
if(31 to 40)
name = "pen"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "pen"
desc = "It's a black ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpads™!"
if(41 to 50)
name = "newspaper"
desc = "An issue of The Catpaw, the newspaper circulating aboard GATO stations."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "newspaper"
if(51 to 60)
name = "stechkin pistol" //greytider bait
desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
icon = 'icons/obj/guns/projectile.dmi'
icon_state = "pistol"
if(61 to 70)
name = "emergency oxygen tank"
desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it."
icon = 'icons/obj/tank.dmi'
icon_state = "emergency"
if(71 to 80)
name = "drinking glass"
icon = 'icons/obj/drinks.dmi'
icon_state = "glass_empty"
desc = "Your standard drinking glass."
if(81 to 90)
name = "fleshlight"
icon = 'hyperstation/icons/obj/fleshlight.dmi'
icon_state = "fleshlight_totallynotamimic"
desc = "A sex toy disguised as a flashlight, used to stimulate someones penis, complete with colour changing sleeve."
if(91 to 100)
icon = 'modular_citadel/icons/obj/genitals/dildo.dmi'
switch(rand(1,3)) //switch within a switch hmmmmmmmmmm
if(1)
icon_state = "dildo_knotted_2"
name = "small knotted dildo"
if(2)
icon_state = "dildo_flared_4"
name = "huge flared dildo"
if(3)
icon_state = "dildo_knotted_3"
name = "big knotted dildo"
desc = "Floppy!"
/mob/living/simple_animal/hostile/hs13mimic/proc/guaranteedknockdown(mob/living/carbon/human/M)
M.Knockdown(40)
M.visible_message("<span class='danger'>\The [src] knocks down \the [M]!</span>", \
"<span class='userdanger'>\The [src] tricks you, knocking you down!</span>")
/mob/living/simple_animal/hostile/hs13mimic/proc/medhudupdate()
med_hud_set_health()
med_hud_set_status()
/mob/living/simple_animal/hostile/hs13mimic/proc/restore()
//back to normal mimic sprite
stealthed = FALSE
medhudupdate()
name = initial(name)
icon = 'hyperstation/icons/mobs/mimic.dmi'
icon_state = "mimic"
desc = initial(desc)
speed = initial(speed)
wander = TRUE
vision_range = 9
/mob/living/simple_animal/hostile/hs13mimic/proc/trigger()
if(stealthed && stat == CONSCIOUS)
visible_message("<span class='danger'>The [src] Reveals itself to be a Mimic!</span>")
restore()
playsound(loc, transformsound, 75, TRUE)
triggerOthers(target) // Friends too!
/mob/living/simple_animal/hostile/hs13mimic/proc/triggerOthers(passtarget) //
for(var/mob/living/simple_animal/hostile/hs13mimic/C in oview(5, src.loc))
if(passtarget && C.target == null && !(isdead(target)))
C.target = passtarget
C.trigger()
/mob/living/simple_animal/hostile/hs13mimic/proc/trytftorandomobject()
stealthed = TRUE
medhudupdate()
var/list/obj/item/listItems = list()
for(var/obj/item/I in oview(9,src.loc))
if(allowed(I))
listItems += I
if(LAZYLEN(listItems))
var/obj/item/changedReference = pick(listItems)
wander = FALSE
vision_range = initial(vision_range)
name = changedReference.name
icon = changedReference.icon
icon_state = changedReference.icon_state
desc = changedReference.desc
else
mimicTransformList() //Couldn't find any valid items, let's go for the default list then.
/mob/living/simple_animal/hostile/hs13mimic/proc/allowed(atom/movable/A)
return !is_type_in_typecache(A, mimic_blacklisted_transform_items) && (isitem(A) || isanimal(A))
//One leader mimic spawns per mimic event spawn, they are able to consume and transform themselves into the station's dead pets. Buckle up.
/mob/living/simple_animal/hostile/hs13mimic/leader
var/mob/living/consumptionTarget = null
var/consuming = FALSE
health = 38 //They have a teeeny tiny more health.
maxHealth = 38
/mob/living/simple_animal/hostile/hs13mimic/leader/Life()
. = ..()
if(!consuming)
if(!consumptionTarget)
for(var/mob/living/simple_animal/pet/A in oview(5, src))
if(A.stat == DEAD)
consumptionTarget = A
break
if(!target && consumptionTarget) //Don't try to consume anything if we're currently attacking something.
var/target_distance = get_dist(targets_from, consumptionTarget)
if(target_distance > minimum_distance)
Goto(consumptionTarget,move_to_delay,minimum_distance)
else
tryConsume(consumptionTarget)
/mob/living/simple_animal/hostile/hs13mimic/leader/proc/tryConsume(var/mob/living/simple_animal/pet/A)
src.visible_message("<span class='warning'>[A] is being consumed...</span>",
"<span class='notice'>You start to consume the dead [A]...</span>", "You hear strange fleshy sounds.")
consuming = TRUE
if(do_after(src, 100, target = A))
stealthed = TRUE
speed = 5
wander = TRUE
name = A.name
desc = A.desc
icon = A.icon
icon_state = A.icon_living
desc += "<span class='warning'> But something about it seems wrong...</span>"
qdel(A)
consuming = FALSE
consumptionTarget = FALSE
return TRUE
consuming = FALSE
return FALSE
//Player control code
/mob/living/simple_animal/hostile/hs13mimic/ShiftClickOn(atom/movable/A)
if(playerTfTime <= world.time && stat == CONSCIOUS)
if(A == src)
restore()
playerTfTime = world.time + playerTransformCD
return
if(istype(A) && allowed(A))
stealthed = TRUE
SEND_SOUND(src, sound(transformsound,volume=50))
name = A.name
icon = A.icon
icon_state = A.icon_state
desc = A.desc
speed = 5
playerTfTime = world.time + playerTransformCD
if(isanimal(A))
var/mob/living/simple_animal/animal = A
icon_state = animal.icon_living
desc += "<span class='warning'> But something about it seems wrong...</span>"
else
to_chat(src, "<span class='warning'>You need to wait a little longer before you can shift into something else!</span>")
..()
//Event control
/datum/round_event_control/mimic_infestation
name = "Mimic Infestation"
typepath = /datum/round_event/mimic_infestation
weight = 5
max_occurrences = 1
min_players = 15
/datum/round_event/mimic_infestation
announceWhen = 200
var/static/list/mimic_station_areas_blacklist = typecacheof(/area/space,
/area/shuttle,
/area/mine,
/area/holodeck,
/area/ruin,
/area/hallway,
/area/hallway/primary,
/area/hallway/secondary,
/area/hallway/secondary/entry,
/area/engine/supermatter,
/area/engine/atmospherics_engine,
/area/engine/engineering/reactor_core,
/area/engine/engineering/reactor_control,
/area/ai_monitored/turret_protected,
/area/layenia/cloudlayer,
/area/asteroid/nearstation,
/area/science/server,
/area/science/explab,
/area/science/xenobiology,
/area/security/processing)
var/spawncount = 1
fakeable = FALSE
/datum/round_event/mimic_infestation/setup()
announceWhen = rand(announceWhen, announceWhen + 50)
spawncount = rand(4, 7)
/datum/round_event/mimic_infestation/announce(fake)
priority_announce("Unidentified lifesigns detected aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", 'sound/ai/aliens.ogg')
/datum/round_event/mimic_infestation/start()
var/list/area/stationAreas = list()
var/list/area/eligible_areas = list()
for(var/area/A in world) // Get the areas in the Z level
if(A.z == SSmapping.station_start)
stationAreas += A
for(var/area/place in stationAreas) // first we check if it's a valid area
if(place.outdoors)
continue
if(place.areasize < 16)
continue
if(is_type_in_typecache(place, mimic_station_areas_blacklist))
continue
eligible_areas += place
for(var/area/place in eligible_areas) // now we check if there are people in that area
var/numOfPeople
for(var/mob/living/carbon/H in place)
numOfPeople++
break
if(numOfPeople > 0)
eligible_areas -= place
var/validFound = FALSE
var/list/turf/validTurfs = list()
var/area/pickedArea
while(!validFound || !eligible_areas.len)
pickedArea = pick_n_take(eligible_areas)
var/list/turf/t = get_area_turfs(pickedArea, SSmapping.station_start)
for(var/turf/thisTurf in t) // now we check if it's a closed turf, cold turf or occupied turf and yeet it
if(isopenturf(thisTurf))
var/turf/open/tempGet = thisTurf
if(tempGet.air.temperature <= T0C)
t -= thisTurf
continue
if(isclosedturf(thisTurf))
t -= thisTurf
else
for(var/obj/O in thisTurf)
if(O.density && !(istype(O, /obj/structure/table)))
t -= thisTurf
break
if(t.len >= spawncount) //Is the number of available turfs equal or bigger than spawncount?
validFound = TRUE
validTurfs = t
if(!eligible_areas.len)
message_admins("No eligible areas for spawning mimics.")
return WAITING_FOR_SOMETHING
notify_ghosts("A group of mimics has spawned in [pickedArea]!", source=pickedArea, action=NOTIFY_ATTACK, flashwindow = FALSE)
while(spawncount > 0 && validTurfs.len)
spawncount--
var/turf/pickedTurf = pick_n_take(validTurfs)
if(spawncount != 0)
var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic
spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
else
var/spawn_type = /mob/living/simple_animal/hostile/hs13mimic/leader
spawn_atom_to_turf(spawn_type, pickedTurf, 1, FALSE)
return SUCCESSFUL_SPAWN

View File

@@ -0,0 +1,49 @@
/client/proc/spawn_floor_cluwne()
set category = "Fun"
set name = "Unleash Targeted Floor Cluwne"
set desc = "Pick a specific target. Be warned: spawning more than one may cause issues!"
var/target
if(!check_rights(R_FUN))
return
target = input("Any specific target in mind? Please note only live, non cluwned, human targets are valid.", "Target", target) as null|anything in GLOB.player_list
if(target && ishuman(target))
var/mob/living/carbon/human/H = target
var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(H.loc)
FC.forced = TRUE
FC.Acquire_Victim(H)
FC.target = H
FC.current_victim = H
log_admin("[key_name(usr)] spawned floor cluwne.")
message_admins("[key_name(usr)] spawned floor cluwne.")
deadchat_broadcast("<span class='deadsay'><b>Floor Cluwne</b> has just been spawned!</span>")
/client/proc/spawn_random_floor_cluwne()
set category = "Fun"
set name = "Unleash Random Floor Cluwne"
set desc = "Goes after a random player in your Z level. Be warned: spawning more than one may cause issues!"
if(!check_rights(R_FUN))
return
var/turf/T = get_turf(usr)
new /mob/living/simple_animal/hostile/floor_cluwne(T)
log_admin("[key_name(usr)] spawned a random target floor cluwne.")
message_admins("[key_name(usr)] spawned a random target floor cluwne.")
/client/proc/spawn_twitch_plays_clowncar()
set category = "Fun"
set name = "Spawn Twich Plays: Clown Car Edition"
set desc = "A clown car that weights the direction it goes based on the keys ghosts are pushing. Terrible idea? Maybe."
if(!check_rights(R_FUN))
return
var/turf/T = get_turf(usr)
var/obj/vehicle/sealed/car/clowncar/twitch_plays/G = new /obj/vehicle/sealed/car/clowncar/twitch_plays(T)
var/area/A = get_area(G)
log_admin("[key_name(usr)] spawned a twitch plays clown car.")
message_admins("[key_name(usr)] spawned a twitch plays clown car. Some soundtrack is likely recommended for the fuckshit that's about to unfold.")
notify_ghosts("A Ghost Controlled Clown Car has been spawned at \the [A.name]! Double click it to orbit and wrestle its direction with other ghosts!", 'yogstation/sound/misc/bikehorn_creepy.ogg', source = G, action = NOTIFY_JUMP, flashwindow = FALSE)

View File

@@ -0,0 +1,277 @@
/*
Holds things like antag datums, game modes, abilities, and everything
related to the antag that could be a datum
*/
//ANTAGONIST
/datum/antagonist/wendigo
name = "wendigo"
antagpanel_category = "Wendigo"
/datum/antagonist/wendigo/on_gain()
if(istype(owner.current, /mob/living/carbon/human))
var/mob/living/carbon/wendigo/new_owner = new/mob/living/carbon/wendigo(get_turf(owner.current))
var/mob/current_body = owner.current
current_body.transfer_ckey(new_owner)
current_body.Destroy()
owner = new_owner.mind
owner.current = new_owner
..()
//HUD
//Contents: Intentions, Hands, Dropping/Throwing/Pulling, Inventory Equip
// Health + Souls on the bottom of screen
//TODO: Health doll, Soul counter (not devil)
/datum/hud/wendigo/New(mob/living/carbon/wendigo/owner)
..()
var/obj/screen/using
var/obj/screen/inventory/inv_box
var/widescreenlayout = FALSE //adds support for different hud layouts depending on widescreen pref
if(owner.client && owner.client.prefs && owner.client?.prefs?.widescreenpref)
widescreenlayout = FALSE
//CRAFTING
using = new /obj/screen/craft
using.icon = ui_style
if(!widescreenlayout)
using.screen_loc = ui_boxcraft
static_inventory += using
//LANG MENU
using = new/obj/screen/language_menu
using.icon = ui_style
if(!widescreenlayout)
using.screen_loc = ui_boxlang
static_inventory += using
//AREA EDITOR
using = new /obj/screen/area_creator
using.icon = ui_style
if(!widescreenlayout)
using.screen_loc = ui_boxarea
static_inventory += using
using = new /obj/screen/voretoggle()
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.screen_loc = ui_voremode
if(!widescreenlayout)
using.screen_loc = ui_boxvore
static_inventory += using
//INTENTS & ACTIONS
action_intent = new /obj/screen/act_intent/segmented
action_intent.icon_state = mymob.a_intent
static_inventory += action_intent
using = new /obj/screen/human/equip()
using.icon = ui_style
using.screen_loc = ui_equip_position(mymob)
static_inventory += using
using = new /obj/screen/mov_intent
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
using.screen_loc = ui_movi
static_inventory += using
using = new /obj/screen/resist()
using.icon = ui_style
using.screen_loc = ui_overridden_resist
hotkeybuttons += using
using = new /obj/screen/restbutton()
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.screen_loc = ui_pull_resist
static_inventory += using
using = new /obj/screen/combattoggle()
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.screen_loc = ui_combat_toggle
static_inventory += using
using = new /obj/screen/drop()
using.icon = ui_style
using.screen_loc = ui_drop_throw
static_inventory += using
pull_icon = new /obj/screen/pull()
pull_icon.icon = ui_style
pull_icon.update_icon(mymob)
pull_icon.screen_loc = ui_pull_resist
static_inventory += pull_icon
throw_icon = new /obj/screen/throw_catch()
throw_icon.icon = ui_style
throw_icon.screen_loc = ui_drop_throw
hotkeybuttons += throw_icon
//////
//INVENTORY
//////
build_hand_slots()
using = new /obj/screen/human/toggle()
using.icon = ui_style
using.screen_loc = ui_inventory
static_inventory += using
using = new /obj/screen/swap_hand()
using.icon = ui_style
using.icon_state = "swap_1"
using.screen_loc = ui_swaphand_position(owner,1)
static_inventory += using
using = new /obj/screen/swap_hand()
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
static_inventory += using
inv_box = new /obj/screen/inventory()
inv_box.name = "neck"
inv_box.icon = ui_style
inv_box.icon_state = "neck"
inv_box.screen_loc = ui_neck
inv_box.slot_id =ITEM_SLOT_NECK
toggleable_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "back"
inv_box.icon = ui_style
inv_box.icon_state = "back"
inv_box.screen_loc = ui_back
inv_box.slot_id =ITEM_SLOT_BACK
static_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "gloves"
inv_box.icon = ui_style
inv_box.icon_state = "gloves"
inv_box.screen_loc = ui_gloves
inv_box.slot_id =ITEM_SLOT_GLOVES
toggleable_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "eyes"
inv_box.icon = ui_style
inv_box.icon_state = "glasses"
inv_box.screen_loc = ui_glasses
inv_box.slot_id =ITEM_SLOT_GLASSES
toggleable_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "ears"
inv_box.icon = ui_style
inv_box.icon_state = "ears"
inv_box.screen_loc = ui_ears
inv_box.slot_id =ITEM_SLOT_EARS
toggleable_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "head"
inv_box.icon = ui_style
inv_box.icon_state = "head"
inv_box.screen_loc = ui_head
inv_box.slot_id =ITEM_SLOT_HEAD
toggleable_inventory += inv_box
inv_box = new /obj/screen/inventory()
inv_box.name = "belt"
inv_box.icon = ui_style
inv_box.icon_state = "belt"
inv_box.screen_loc = ui_belt
inv_box.slot_id =ITEM_SLOT_BELT
static_inventory += inv_box
//INFO DISPLAY
internals = new /obj/screen/internals()
infodisplay += internals
healths = new /obj/screen/healths()
infodisplay += healths
healthdoll = new /obj/screen/healthdoll()
infodisplay += healthdoll
zone_select = new /obj/screen/zone_sel()
zone_select.icon = ui_style
zone_select.update_icon(mymob)
static_inventory += zone_select
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
inv.hud = src
inv_slots[inv.slot_id] = inv
inv.update_icon()
/datum/hud/wendigo/hidden_inventory_update(mob/viewer)
if(!mymob)
return
var/mob/living/carbon/wendigo/W = mymob
var/mob/screenmob = viewer || W
if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown)
if(W.gloves)
W.gloves.screen_loc = ui_gloves
screenmob.client.screen += W.gloves
if(W.ears)
W.ears.screen_loc = ui_ears
screenmob.client.screen += W.ears
if(W.glasses)
W.glasses.screen_loc = ui_glasses
screenmob.client.screen += W.glasses
if(W.wear_neck)
W.wear_neck.screen_loc = ui_neck
screenmob.client.screen += W.wear_neck
if(W.head)
W.head.screen_loc = ui_head
screenmob.client.screen += W.head
else
if(W.gloves) screenmob.client.screen -= W.gloves
if(W.ears) screenmob.client.screen -= W.ears
if(W.glasses) screenmob.client.screen -= W.glasses
if(W.wear_neck) screenmob.client.screen -= W.wear_neck
if(W.head) screenmob.client.screen -= W.head
/datum/hud/wendigo/persistent_inventory_update(mob/viewer)
if(!mymob)
return
..()
var/mob/living/carbon/wendigo/W = mymob
var/mob/screenmob = viewer || W
if(screenmob.hud_used)
if(screenmob.hud_used.hud_shown)
if(W.belt)
W.belt.screen_loc = ui_belt
screenmob.client.screen += W.belt
if(W.back)
W.back.screen_loc = ui_back
screenmob.client.screen += W.back
else
if(W.belt)
screenmob.client.screen -= W.belt
if(W.back)
screenmob.client.screen -= W.back
if(hud_version != HUD_STYLE_NOHUD)
for(var/obj/item/I in W.held_items)
I.screen_loc = ui_hand_position(W.get_held_index_of_item(I))
screenmob.client.screen += I
else
for(var/obj/item/I in W.held_items)
I.screen_loc = null
screenmob.client.screen -= I
/datum/hud/wendigo/show_hud(version = 0,mob/viewmob)
. = ..()
if(!.)
return
var/mob/screenmob = viewmob || mymob
hidden_inventory_update(screenmob)

View File

@@ -0,0 +1,14 @@
/obj/structure/soul_storage
name = "soul storage"
desc = "Stores souls!"
var/list/souls = list()
//This is a big WIP. I don't even want it having the name "soul storage" but it'll do for now
/obj/structure/soul_storage/Initialize(mapload)
. = ..()
GLOB.wendigo_soul_storages += src
/obj/structure/soul_storage/Destroy()
GLOB.wendigo_soul_storages -= src
return ..()

View File

@@ -0,0 +1,11 @@
/mob/living/carbon/wendigo/UnarmedAttack(atom/A, proximity)
A.attack_hand(src)
/mob/living/carbon/wendigo/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
if(incapacitated() || lying)
to_chat(src, "<span class='warning'>You can't do that right now!</span>")
return FALSE
if(be_close && !in_range(M, src))
to_chat(src, "<span class='warning'>You are too far away!</span>")
return FALSE
return TRUE

View File

@@ -0,0 +1,115 @@
#define DEFAULT_MOVESPEED 1.5
//The mob itself
/mob/living/carbon/wendigo
name = "wendigo"
gender = FEMALE
unique_name = FALSE
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD)
hud_type = /datum/hud/wendigo
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE
status_flags = CANSTUN //cant be knocked down, unconscious, or be pushed
maxHealth = 200
icon = 'hyperstation/icons/mobs/wendigo.dmi'
icon_state = "reference"
bodyparts = list(/obj/item/bodypart/chest/wendigo, /obj/item/bodypart/head/wendigo,
/obj/item/bodypart/l_arm/wendigo, /obj/item/bodypart/r_arm/wendigo,
/obj/item/bodypart/l_leg/wendigo, /obj/item/bodypart/r_leg/wendigo)
var/obj/item/belt = null
var/datum/physiology/physiology
var/obj/structure/soul_storage/connected_link
var/fake_breast_size = 5 //She doesn't actually have the organ, but we cache her breast size for rp reasons
var/fake_penis_size = 8
/mob/living/carbon/wendigo/Initialize(mapload)
. = ..()
/* //TODO: Uncomment when objectives + forest get finished
if(!connected_link)
if(!GLOB.wendigo_soul_storages.len)
connected_link = new /obj/structure/soul_storage(get_turf(src))
else
connected_link = pick(GLOB.wendigo_soul_storages)
gender = pick(FEMALE, MALE)
*/
if(gender == MALE)
fake_breast_size = 0
else
fake_penis_size = 0
real_name = name
//DAMAGE RESISTANCE
physiology = new()
physiology.brute_mod = 0.7
physiology.burn_mod = 1.25
physiology.tox_mod = -1
physiology.oxy_mod = 1
physiology.clone_mod = 0
physiology.stamina_mod = 0 //Running and attacking, prods
physiology.heat_mod = 2 //IM MELTIIINNNGGGG-!
physiology.cold_mod = 0
physiology.siemens_coeff = 0.2
physiology.stun_mod = 0 //prods n aggressive grab
//physiology.bleed_mod = 2
physiology.speed_mod = 0.9 //Should be faster than a normal person's walking speed
physiology.hunger_mod = 2 //We're gonna have a FEAST TONIGHT!
physiology.do_after_speed = 1
//Traits & Bodyparts
create_bodyparts()
create_internal_organs()
ADD_TRAIT(src, TRAIT_NOCLONE, "initialize")
add_verb(src, /mob/living/proc/mob_sleep)
add_verb(src, /mob/living/proc/lay_down)
add_movespeed_modifier("MOVESPEED_DEFAULT", multiplicative_slowdown=DEFAULT_MOVESPEED)
update_body_parts()
/mob/living/carbon/wendigo/Destroy()
QDEL_NULL(physiology)
return ..()
/mob/living/carbon/wendigo/update_body_parts()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
BP.update_limb()
/mob/living/carbon/wendigo/update_move_intent_slowdown()
var/mod = 0
if(m_intent == MOVE_INTENT_WALK)
mod = (CONFIG_GET(number/movedelay/walk_delay) / 2) //complete copy besides this part
else
mod = 1.30
if(!isnum(mod))
mod = 1
add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, override = TRUE, multiplicative_slowdown = mod)
/mob/living/carbon/wendigo/update_movespeed(resort=TRUE)
return (..() * physiology.speed_mod)
/mob/living/carbon/wendigo/can_hold_items()
return TRUE
/mob/living/carbon/wendigo/IsAdvancedToolUser()
return TRUE
/mob/living/carbon/wendigo/can_be_pulled()
return FALSE
/mob/living/carbon/wendigo/is_literate()
return TRUE
/mob/living/carbon/wendigo/canBeHandcuffed()
return TRUE
/mob/living/carbon/wendigo/update_inv_handcuffed()
return
/mob/living/carbon/wendigo/update_inv_legcuffed()
return
//
//ORGANS
//
/mob/living/carbon/wendigo/create_internal_organs()
internal_organs += new /obj/item/organ/eyes/wendigo
internal_organs += new /obj/item/organ/liver/wendigo
internal_organs += new /obj/item/organ/tongue
internal_organs += new /obj/item/organ/lungs
internal_organs += new /obj/item/organ/heart
internal_organs += new /obj/item/organ/stomach
internal_organs += new /obj/item/organ/ears
..()

View File

@@ -0,0 +1,86 @@
/mob/living/carbon/wendigo/examine(mob/user)
var/t_He = p_they(TRUE)
var/t_His = p_their(TRUE)
var/t_his = p_their()
var/t_him = p_them()
. = list("<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>!")
if(handcuffed)
. += "<span class='warning'>[t_He] is [icon2html(handcuffed, user)] handcuffed!</span>"
if(legcuffed)
. += "<span class='warning'>[t_He] has [icon2html(legcuffed, user)] leg cuffs!</span>"
if(head)
. += "[t_He] is wearing [head.get_examine_string(user)] on [t_his] head."
if(wear_neck)
. += "[t_He] is wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
. += "[t_He] is holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
if(back)
. += "[t_He] has [back.get_examine_string(user)] on [t_his] back."
if(stat == DEAD)
. += "<span class='deadsay'>[t_He] is limp and unresponsive, with no signs of life.</span>"
var/list/msg = ("<span class='warning'>")
var/temp_hp = getBruteLoss()
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY))
if(temp_hp)
if(temp_hp <= 25) msg += "[t_He] has minor bruising.\n"
else if(temp_hp <= 75) msg += "[t_He] has <B>moderate</B> bruising!\n"
else msg += "<B>[t_He] has severe bruising!</B>\n"
temp_hp = getFireLoss()
if(temp_hp)
if(temp_hp <= 25) msg += "[t_He] has minor burns.\n"
else if(temp_hp <= 50) msg += "[t_He] has <B>moderate</B> burns!\n"
else msg += "<B>[t_He] has severe burns!</B>\n"
if(fire_stacks > 0)
msg += "[t_He] is covered in something flammable.\n"
if(fire_stacks < 0)
msg += "[t_He] looks a little soaked.\n"
if(pulledby)
if(pulledby.grab_state)
msg += "[t_He] is restrained by [pulledby]'s grip.\n"
msg += "</span>"
. += msg
if(stat == UNCONSCIOUS)
. += "[t_He] isn't responding to anything around [t_him] and seems to be asleep."
else if(InCritical())
. += "[t_His] breathing is shallow and labored."
if(fake_breast_size < 16)
. += "You see a pair of breasts. You estimate them to be [ascii2text(round(fake_breast_size)+63)]-cups."
else if(!fake_breast_size && gender == FEMALE)
. += "You see a pair of breasts. They're small and flatchested, however."
else
. += "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(fake_breast_size)]cm in diameter."
if(fake_penis_size)
. += "You see a flaccid human penis. You estimate it's about [round(fake_penis_size, 0.25)] inch[round(fake_penis_size, 0.25) != 1 ? "es" : ""] long." //would put girth here but lazy
if(connected_link)
if(connected_link.souls.len > 5)
. += "<span class='warning'><B>[t_His] eyes are glowing a deadly red.</B></span>"
else
var/A = "<span class='deadsay'>"
switch(connected_link.souls.len)
if(0)
A += "[t_He] looks malnourished and weak."
if(1)
A += "[t_He] looks hungry."
if(2 to 4)
A += "[t_He] is salivating."
if(5)
A += "[t_His] eyes are glowing red."
. += "[A]</span>"
else
. += "<span class='deadsay'>[t_He] looks lost.</span>"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, .)
. += "*---------*</span>"

View File

@@ -0,0 +1,55 @@
//Snowflake metabolization with naughty organ manipulation
/mob/living/carbon/wendigo/proc/metabolize_hunger()
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
return
if(connected_link)
if(connected_link.souls.len > 3)
nutrition = min(800, nutrition + (HUNGER_FACTOR*connected_link.souls.len))
nutrition = max(0, nutrition - (HUNGER_FACTOR / (physiology.hunger_mod / (connected_link.souls.len + 1))))
else
nutrition = max(0, nutrition - (HUNGER_FACTOR / physiology.hunger_mod))
switch(nutrition)
if(NUTRITION_LEVEL_WELL_FED to INFINITY)
throw_alert("nutrition", /obj/screen/alert/full)
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
throw_alert("nutrition", /obj/screen/alert/sated)
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
throw_alert("nutrition", /obj/screen/alert/hungry)
if(0 to NUTRITION_LEVEL_STARVING)
throw_alert("nutrition", /obj/screen/alert/starving)
/mob/living/carbon/wendigo/reagent_check(datum/reagent/R)
if(istype(R, /datum/reagent/fermi))
var/had_changed = FALSE
if(R.type == /datum/reagent/fermi/penis_enlarger)
fake_penis_size += 0.25
had_changed = "penis_enlarger"
if(R.type == /datum/reagent/fermi/PEsmaller)
fake_penis_size = max(0, fake_penis_size - 0.25)
had_changed = "PEsmaller"
if(R.type == /datum/reagent/fermi/breast_enlarger)
fake_breast_size += 0.25
had_changed = "breast_enlarger"
if(R.type == /datum/reagent/fermi/BEsmaller)
fake_breast_size = max(0, fake_breast_size - 0.25)
had_changed = "BEsmaller"
if(had_changed)
R.volume -= R.metabolization_rate
if(round(fake_penis_size, 1) == fake_penis_size && fake_penis_size)
switch(had_changed)
if("penis_enlarger")
to_chat(src, "<span class='warning'>Your [pick(GLOB.gentlemans_organ_names)] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [fake_penis_size] inch penis.</b></span>")
if("PEsmaller")
if(fake_penis_size > 0)
to_chat(src, "<span class='warning'>Your [pick(GLOB.gentlemans_organ_names)] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [fake_penis_size] inch penis.</b></span>")
else if(round(fake_breast_size, 1) == fake_breast_size && fake_breast_size)
switch(had_changed)
if("breast_enlarger")
to_chat(src, "<span class='warning'>Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [ascii2text(round(fake_breast_size)+63)]-cup.</b></span>")
if("BEsmaller)")
if(fake_breast_size > 0)
to_chat(src, "<span class='warning'>Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [ascii2text(round(fake_breast_size)+63)]-cup.</b></span>")
return TRUE

View File

@@ -0,0 +1,125 @@
/mob/living/carbon/wendigo/handle_environment(datum/gas_mixture/environment)
if(!environment)
return
var/loc_temp = get_temperature(environment)
if(stat != DEAD)
adjust_bodytemperature(natural_bodytemperature_stabilization())
if(!on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases
if(loc_temp < bodytemperature)
adjust_bodytemperature(max((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX))
else
adjust_bodytemperature(min((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTHEAT))
switch(bodytemperature)
if(280 to 300)
throw_alert("temp", /obj/screen/alert/hot, 1)
apply_damage(HEAT_DAMAGE_LEVEL_1*physiology.heat_mod, BURN)
if(300 to 350)
throw_alert("temp", /obj/screen/alert/hot, 2)
apply_damage(HEAT_DAMAGE_LEVEL_2*physiology.heat_mod, BURN)
if(350 to INFINITY)
throw_alert("temp", /obj/screen/alert/hot, 3)
if(on_fire)
apply_damage(HEAT_DAMAGE_LEVEL_3*physiology.heat_mod, BURN)
else
apply_damage(HEAT_DAMAGE_LEVEL_2*physiology.heat_mod, BURN)
else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTCOLD))
if(!istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
switch(bodytemperature)
if(200 to 260)
throw_alert("temp", /obj/screen/alert/cold, 1)
apply_damage(COLD_DAMAGE_LEVEL_1*physiology.cold_mod, BURN)
if(0 to 120)
throw_alert("temp", /obj/screen/alert/cold, 2)
apply_damage(COLD_DAMAGE_LEVEL_2*physiology.cold_mod, BURN)
if(-INFINITY to 0)
throw_alert("temp", /obj/screen/alert/cold, 3)
apply_damage(COLD_DAMAGE_LEVEL_3*physiology.cold_mod, BURN)
else
clear_alert("temp")
else
clear_alert("temp")
//Account for massive pressure differences
var/pressure = environment.return_pressure()
var/adjusted_pressure = calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob.
switch(adjusted_pressure)
if(HAZARD_HIGH_PRESSURE to INFINITY)
adjustBruteLoss(min((((adjusted_pressure / HAZARD_HIGH_PRESSURE)-1)*PRESSURE_DAMAGE_COEFFICIENT)*physiology.pressure_mod, MAX_HIGH_PRESSURE_DAMAGE))
throw_alert("pressure", /obj/screen/alert/highpressure, 2)
if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE)
throw_alert("pressure", /obj/screen/alert/highpressure, 1)
if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE)
clear_alert("pressure")
if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE)
throw_alert("pressure", /obj/screen/alert/lowpressure, 1)
else
adjustBruteLoss( LOW_PRESSURE_DAMAGE*physiology.pressure_mod )
throw_alert("pressure", /obj/screen/alert/lowpressure, 2)
return
/mob/living/carbon/wendigo/handle_breath_temperature(datum/gas_mixture/breath)
if(abs(BODYTEMP_NORMAL - breath.temperature) > 50)
switch(breath.temperature)
if(-INFINITY to 0)
adjustFireLoss(3)
if(0 to 120) //We flourish in a cold environment
adjustFireLoss(1.5)
if(298 to 350) //But hoo boy do we not like the heat
adjustFireLoss(2)
if(350 to 800)
adjustFireLoss(3)
if(800 to INFINITY)
adjustFireLoss(8)
/mob/living/carbon/wendigo/handle_fire()
if(..())
return
adjust_bodytemperature(BODYTEMP_HEATING_MAX*physiology.heat_mod)
return
/mob/living/carbon/wendigo/adjustBruteLoss(amount, updating_health, forced)
return ..(amount*physiology.brute_mod, updating_health, forced)
/mob/living/carbon/wendigo/adjustFireLoss(amount, updating_health, forced)
return ..(amount*physiology.burn_mod, updating_health, forced)
/mob/living/carbon/wendigo/adjustToxLoss(amount, updating_health, forced)
return ..(amount*physiology.tox_mod, updating_health, forced)
/mob/living/carbon/wendigo/adjustOxyLoss(amount, updating_health, forced)
return ..(amount*physiology.oxy_mod, updating_health, forced)
/mob/living/carbon/wendigo/adjustCloneLoss(amount, updating_health, forced)
return ..(amount*physiology.clone_mod, updating_health, forced)
/mob/living/carbon/wendigo/adjustStaminaLoss(amount, updating_health, forced)
return ..(amount*physiology.stamina_mod, updating_health, forced)
/mob/living/carbon/wendigo/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
/mob/living/carbon/wendigo/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
return ..(shock_damage, source, physiology.siemens_coeff, safety, override, tesla_shock, illusion, stun)
/mob/living/carbon/wendigo/Stun(amount, updating, ignore_canstun)
return ..(amount*physiology.stun_mod, updating, ignore_canstun)
/mob/living/carbon/wendigo/Knockdown(amount, updating, ignore_canknockdown, override_hardstun, override_stamdmg)
return ..(amount*physiology.stun_mod, updating, ignore_canknockdown, override_hardstun, override_stamdmg)
/mob/living/carbon/wendigo/Unconscious(amount, updating, ignore_canunconscious)
return ..(amount*physiology.stun_mod, updating, ignore_canunconscious)
/mob/living/carbon/wendigo/bleed(amt)
return ..(amt*physiology.bleed_mod)

View File

@@ -0,0 +1,100 @@
/mob/living/carbon/wendigo/can_equip(obj/item/I, slot, disable_warning)
switch(slot)
if(SLOT_HANDS)
if(get_empty_held_indexes())
return TRUE
return FALSE
if(SLOT_GLASSES)
if(glasses)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EYES))
return FALSE
return TRUE
if(SLOT_NECK)
if(wear_neck)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_NECK))
return FALSE
return TRUE
if(SLOT_EARS)
if(ears)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EARS))
return FALSE
return TRUE
if(SLOT_GLOVES)
if(gloves)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_GLOVES))
return FALSE
return TRUE
if(SLOT_BACK)
if(back)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_BACK))
return FALSE
return TRUE
if(SLOT_IN_BACKPACK)
if(back)
if(SEND_SIGNAL(back, COMSIG_TRY_STORAGE_CAN_INSERT, I, src, TRUE))
return TRUE
return FALSE
if(SLOT_HEAD)
if(head)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_HEAD))
return FALSE
return TRUE
if(SLOT_BELT)
if(belt)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_BELT))
return FALSE
return TRUE
return FALSE
/mob/living/carbon/wendigo/equip_to_slot(obj/item/I, slot)
if(!..())
return
switch(slot)
if(SLOT_GLASSES)
glasses = I
update_inv_glasses()
if(SLOT_EARS)
ears = I
update_inv_ears()
if(SLOT_GLOVES)
gloves = I
update_inv_gloves()
return TRUE
/mob/living/carbon/wendigo/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
. = ..()
if(!. || !I)
return
else if(I == gloves)
gloves = null
if(!QDELETED(src))
update_inv_gloves()
else if(I == glasses)
glasses = null
var/obj/item/clothing/glasses/G = I
if(G.tint)
update_tint()
if(G.vision_correction)
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
adjust_eye_damage(0)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
update_sight()
if(!QDELETED(src))
update_inv_glasses()
else if(I == ears)
ears = null
if(!QDELETED(src))
update_inv_ears()
else if(I == belt)
belt = null
if(!QDELETED(src))
update_inv_belt()

View File

@@ -0,0 +1,58 @@
/obj/item/organ/liver/wendigo
name = "rotten liver"
desc = "A liver from a wendigo. It looks like a spoiled tomato."
decay_factor = 0
/obj/item/organ/liver/wendigo/on_life()
var/mob/living/carbon/C = owner
if(istype(C))
damage = initial(maxHealth)
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
//handle liver toxin filtration
for(var/datum/reagent/toxin/T in C.reagents.reagent_list)
var/thisamount = C.reagents.get_reagent_amount(T.type)
if (thisamount && thisamount <= toxTolerance)
C.reagents.remove_reagent(T.type, 1)
C.reagents.metabolize(C, can_overdose=FALSE)
if(istype(C, /mob/living/carbon/wendigo))
var/mob/living/carbon/wendigo/A = C
A.metabolize_hunger()
/obj/item/organ/eyes/wendigo
sight_flags = SEE_MOBS
/obj/item/bodypart/head/wendigo
dismemberable = FALSE
max_damage = INFINITY
animal_origin = WENDIGO_BODYPART
/obj/item/bodypart/chest/wendigo
dismemberable = FALSE
max_damage = INFINITY
animal_origin = WENDIGO_BODYPART
/obj/item/bodypart/l_arm/wendigo
dismemberable = FALSE
max_damage = INFINITY
attack_verb = list("slashed", "clawed", "mauled")
animal_origin = WENDIGO_BODYPART
/obj/item/bodypart/r_arm/wendigo
dismemberable = FALSE
max_damage = INFINITY
attack_verb = list("slashed", "clawed", "mauled")
animal_origin = WENDIGO_BODYPART
/obj/item/bodypart/l_leg/wendigo
dismemberable = FALSE
max_damage = INFINITY
attack_verb = list("pounded", "stomped", "stamped", "kicked")
animal_origin = WENDIGO_BODYPART
/obj/item/bodypart/r_leg/wendigo
dismemberable = FALSE
max_damage = INFINITY
attack_verb = list("pounded", "stomped", "stamped", "kicked")
animal_origin = WENDIGO_BODYPART

View File

@@ -0,0 +1,370 @@
#define HEAD_X_OFFSET_NORTH 2
#define HEAD_Y_OFFSET_NORTH 8
#define HEAD_X_OFFSET_EAST 2
#define HEAD_Y_OFFSET_EAST 8
#define HEAD_X_OFFSET_SOUTH 8
#define HEAD_Y_OFFSET_SOUTH 2
#define HEAD_X_OFFSET_WEST 8
#define HEAD_Y_OFFSET_WEST -2
#define LHAND_X_OFFSET_NORTH -5
#define LHAND_Y_OFFSET_NORTH 3
#define LHAND_X_OFFSET_EAST -2
#define LHAND_Y_OFFSET_EAST 3
#define LHAND_X_OFFSET_SOUTH 8
#define LHAND_Y_OFFSET_SOUTH 3
#define LHAND_X_OFFSET_WEST -2
#define LHAND_Y_OFFSET_WEST 3
#define RHAND_X_OFFSET_NORTH 8
#define RHAND_Y_OFFSET_NORTH 3
#define RHAND_X_OFFSET_EAST 2
#define RHAND_Y_OFFSET_EAST 3
#define RHAND_X_OFFSET_SOUTH -5
#define RHAND_Y_OFFSET_SOUTH 3
#define RHAND_X_OFFSET_WEST 2
#define RHAND_Y_OFFSET_WEST 3
#define EARS_X_OFFSET_NORTH 0
#define EARS_Y_OFFSET_NORTH 0
#define EARS_X_OFFSET_EAST 0
#define EARS_Y_OFFSET_EAST 0
#define EARS_X_OFFSET_SOUTH 0
#define EARS_Y_OFFSET_SOUTH 0
#define EARS_X_OFFSET_WEST 0
#define EARS_Y_OFFSET_WEST 0
#define GLASSES_X_OFFSET_NORTH 5
#define GLASSES_Y_OFFSET_NORTH 10
#define GLASSES_X_OFFSET_EAST 1
#define GLASSES_Y_OFFSET_EAST 10
#define GLASSES_X_OFFSET_SOUTH -2
#define GLASSES_Y_OFFSET_SOUTH 10
#define GLASSES_X_OFFSET_WEST -1
#define GLASSES_Y_OFFSET_WEST 10
#define BELT_X_OFFSET_NORTH 0
#define BELT_Y_OFFSET_NORTH 10
#define BELT_X_OFFSET_EAST 0
#define BELT_Y_OFFSET_EAST 0
#define BELT_X_OFFSET_SOUTH 0
#define BELT_Y_OFFSET_SOUTH 0
#define BELT_X_OFFSET_WEST 0
#define BELT_Y_OFFSET_WEST 0
#define BACK_X_OFFSET_NORTH 1
#define BACK_Y_OFFSET_NORTH 8
#define BACK_X_OFFSET_EAST 0
#define BACK_Y_OFFSET_EAST 8
#define BACK_X_OFFSET_SOUTH 1
#define BACK_Y_OFFSET_SOUTH 8
#define BACK_X_OFFSET_WEST 0
#define BACK_Y_OFFSET_WEST 8
#define NECK_X_OFFSET_NORTH 2
#define NECK_Y_OFFSET_NORTH 10
#define NECK_X_OFFSET_EAST 0
#define NECK_Y_OFFSET_EAST 10
#define NECK_X_OFFSET_SOUTH 2
#define NECK_Y_OFFSET_SOUTH 10
#define NECK_X_OFFSET_WEST 0
#define NECK_Y_OFFSET_WEST 10
/mob/living/carbon/wendigo/setDir(newdir, ismousemovement)
if(dir == newdir)
return //Don't spend time regenerating icons when we don't move
. = ..()
regenerate_icons()
/mob/living/carbon/wendigo/regenerate_icons()
if(!..())
update_inv_head()
update_inv_gloves()
update_inv_ears()
update_inv_glasses()
update_inv_belt()
update_inv_back()
update_inv_neck()
update_transform()
/mob/living/carbon/wendigo/update_inv_gloves()
if(gloves)
gloves.screen_loc = ui_gloves
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += gloves
//GLASSES
/mob/living/carbon/wendigo/update_inv_glasses()
if(glasses)
glasses.screen_loc = ui_glasses
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += glasses
//EARS
/mob/living/carbon/wendigo/update_inv_ears()
remove_overlay(EARS_LAYER)
if(ears)
if(client && hud_used)
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_EARS]
inv.update_icon()
ears.screen_loc = ui_ears //move the item to the appropriate screen loc
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += ears
overlays_standing[EARS_LAYER] = ears.build_worn_icon(state = ears.icon_state, default_layer = EARS_LAYER, default_icon_file = ((ears.alternate_worn_icon) ? ears.alternate_worn_icon : 'icons/mob/ears.dmi'))
var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER]
switch(dir)
if(NORTH)
ears_overlay.pixel_x += EARS_X_OFFSET_NORTH
ears_overlay.pixel_y += EARS_Y_OFFSET_NORTH
if(EAST)
ears_overlay.pixel_x += EARS_X_OFFSET_EAST
ears_overlay.pixel_y += EARS_Y_OFFSET_EAST
if(SOUTH)
ears_overlay.pixel_x += EARS_X_OFFSET_SOUTH
ears_overlay.pixel_y += EARS_Y_OFFSET_SOUTH
if(WEST)
ears_overlay.pixel_x += EARS_X_OFFSET_WEST
ears_overlay.pixel_y += EARS_Y_OFFSET_WEST
overlays_standing[EARS_LAYER] = ears_overlay
apply_overlay(EARS_LAYER)
//BELT
/mob/living/carbon/wendigo/update_inv_belt()
remove_overlay(BELT_LAYER)
if(belt)
belt.screen_loc = ui_belt
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += belt
var/t_state = belt.item_state
if(!t_state)
t_state = belt.icon_state
overlays_standing[BELT_LAYER] = belt.build_worn_icon(state = t_state, default_layer = BELT_LAYER, default_icon_file = ((belt.alternate_worn_icon) ? belt.alternate_worn_icon : 'icons/mob/belt.dmi'))
var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER]
switch(dir)
if(NORTH)
belt_overlay.pixel_x += BELT_X_OFFSET_NORTH
belt_overlay.pixel_y += BELT_Y_OFFSET_NORTH
if(EAST)
belt_overlay.pixel_x += BELT_X_OFFSET_EAST
belt_overlay.pixel_y += BELT_Y_OFFSET_EAST
if(SOUTH)
belt_overlay.pixel_x += BELT_X_OFFSET_SOUTH
belt_overlay.pixel_y += BELT_Y_OFFSET_SOUTH
if(WEST)
belt_overlay.pixel_x += BELT_X_OFFSET_WEST
belt_overlay.pixel_y += BELT_Y_OFFSET_WEST
overlays_standing[BELT_LAYER] = belt_overlay
apply_overlay(BELT_LAYER)
//BACK
/mob/living/carbon/wendigo/update_inv_back()
..()
if(back)
back.screen_loc = ui_back
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += back
var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER]
if(back_overlay)
remove_overlay(BACK_LAYER)
switch(dir)
if(NORTH)
back_overlay.pixel_x += BACK_X_OFFSET_NORTH
back_overlay.pixel_y += BACK_Y_OFFSET_NORTH
if(EAST)
back_overlay.pixel_x += BACK_X_OFFSET_EAST
back_overlay.pixel_y += BACK_Y_OFFSET_EAST
if(SOUTH)
back_overlay.pixel_x += BACK_X_OFFSET_SOUTH
back_overlay.pixel_y += BACK_Y_OFFSET_SOUTH
if(WEST)
back_overlay.pixel_x += BACK_X_OFFSET_WEST
back_overlay.pixel_y += BACK_Y_OFFSET_WEST
overlays_standing[BACK_LAYER] = back_overlay
apply_overlay(BACK_LAYER)
//NECK
/mob/living/carbon/wendigo/update_inv_neck()
..()
if(wear_neck)
wear_neck.screen_loc = ui_neck
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += wear_neck
var/mutable_appearance/neck_overlay = overlays_standing[NECK_LAYER]
if(neck_overlay)
remove_overlay(NECK_LAYER)
switch(dir)
if(NORTH)
neck_overlay.pixel_x += NECK_X_OFFSET_NORTH
neck_overlay.pixel_y += NECK_Y_OFFSET_NORTH
if(EAST)
neck_overlay.pixel_x += NECK_X_OFFSET_EAST
neck_overlay.pixel_y += NECK_Y_OFFSET_EAST
if(SOUTH)
neck_overlay.pixel_x += NECK_X_OFFSET_SOUTH
neck_overlay.pixel_y += NECK_Y_OFFSET_SOUTH
if(WEST)
neck_overlay.pixel_x += NECK_X_OFFSET_WEST
neck_overlay.pixel_y += NECK_Y_OFFSET_WEST
overlays_standing[NECK_LAYER] = neck_overlay
apply_overlay(NECK_LAYER)
//HANDS
/mob/living/carbon/wendigo/update_inv_hands()
remove_overlay(HANDS_LAYER)
if (handcuffed)
drop_all_held_items()
return
var/list/hands = list()
for(var/obj/item/I in held_items)
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
I.screen_loc = ui_hand_position(get_held_index_of_item(I))
client.screen += I
if(observers && observers.len)
for(var/M in observers)
var/mob/dead/observe = M
if(observe.client && observe.client.eye == src)
observe.client.screen += I
else
observers -= observe
if(!observers.len)
observers = null
break
var/t_state = I.item_state
if(!t_state)
t_state = I.icon_state
var/icon_file = I.lefthand_file
var/righthand = 0
if(get_held_index_of_item(I) % 2 == 0)
icon_file = I.righthand_file
righthand = 1
var/mutable_appearance/thing = I.build_worn_icon(state = t_state, default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
if(righthand)
switch(dir)
if(NORTH)
thing.pixel_x += RHAND_X_OFFSET_NORTH
thing.pixel_y += RHAND_Y_OFFSET_NORTH
if(EAST)
thing = null //ghetto
if(SOUTH)
thing.pixel_x += RHAND_X_OFFSET_SOUTH
thing.pixel_y += RHAND_Y_OFFSET_SOUTH
if(WEST)
thing.pixel_x += RHAND_X_OFFSET_WEST
thing.pixel_y += RHAND_Y_OFFSET_WEST
else
switch(dir)
if(NORTH)
thing.pixel_x += LHAND_X_OFFSET_NORTH
thing.pixel_y += LHAND_Y_OFFSET_NORTH
if(EAST)
thing.pixel_x += LHAND_X_OFFSET_EAST
thing.pixel_y += LHAND_Y_OFFSET_EAST
if(SOUTH)
thing.pixel_x += LHAND_X_OFFSET_SOUTH
thing.pixel_y += LHAND_Y_OFFSET_SOUTH
if(WEST)
thing = null //ghetto
hands += thing
overlays_standing[HANDS_LAYER] = hands
apply_overlay(HANDS_LAYER)
//HEAD
/mob/living/carbon/wendigo/update_inv_head()
remove_overlay(HEAD_LAYER)
if(head)
head.screen_loc = ui_head
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += head
var/mutable_appearance/head_icon = head.build_worn_icon(state = head.icon_state, default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/head.dmi')
switch(dir)
if(NORTH)
head_icon.pixel_x += HEAD_X_OFFSET_NORTH
head_icon.pixel_y += HEAD_Y_OFFSET_NORTH
if(EAST)
head_icon.pixel_x += HEAD_X_OFFSET_EAST
head_icon.pixel_y += HEAD_Y_OFFSET_EAST
if(SOUTH)
head_icon.pixel_x += HEAD_X_OFFSET_SOUTH
head_icon.pixel_y += HEAD_Y_OFFSET_SOUTH
if(WEST)
head_icon.pixel_x += HEAD_X_OFFSET_WEST
head_icon.pixel_y += HEAD_Y_OFFSET_WEST
overlays_standing[SLOT_HEAD] = head_icon
update_hud_head(head)
apply_overlay(HEAD_LAYER)
#undef LHAND_X_OFFSET_NORTH
#undef LHAND_Y_OFFSET_NORTH
#undef LHAND_X_OFFSET_EAST
#undef LHAND_Y_OFFSET_EAST
#undef LHAND_X_OFFSET_SOUTH
#undef LHAND_Y_OFFSET_SOUTH
#undef LHAND_X_OFFSET_WEST
#undef LHAND_Y_OFFSET_WEST
#undef RHAND_X_OFFSET_NORTH
#undef RHAND_Y_OFFSET_NORTH
#undef RHAND_X_OFFSET_EAST
#undef RHAND_Y_OFFSET_EAST
#undef RHAND_X_OFFSET_SOUTH
#undef RHAND_Y_OFFSET_SOUTH
#undef RHAND_X_OFFSET_WEST
#undef RHAND_Y_OFFSET_WEST
#undef EARS_X_OFFSET_NORTH
#undef EARS_Y_OFFSET_NORTH
#undef EARS_X_OFFSET_EAST
#undef EARS_Y_OFFSET_EAST
#undef EARS_X_OFFSET_SOUTH
#undef EARS_Y_OFFSET_SOUTH
#undef EARS_X_OFFSET_WEST
#undef EARS_Y_OFFSET_WEST
#undef GLASSES_X_OFFSET_NORTH
#undef GLASSES_Y_OFFSET_NORTH
#undef GLASSES_X_OFFSET_EAST
#undef GLASSES_Y_OFFSET_EAST
#undef GLASSES_X_OFFSET_SOUTH
#undef GLASSES_Y_OFFSET_SOUTH
#undef GLASSES_X_OFFSET_WEST
#undef GLASSES_Y_OFFSET_WEST
#undef BELT_X_OFFSET_NORTH
#undef BELT_Y_OFFSET_NORTH
#undef BELT_X_OFFSET_EAST
#undef BELT_Y_OFFSET_EAST
#undef BELT_X_OFFSET_SOUTH
#undef BELT_Y_OFFSET_SOUTH
#undef BELT_X_OFFSET_WEST
#undef BELT_Y_OFFSET_WEST
#undef BACK_X_OFFSET_NORTH
#undef BACK_Y_OFFSET_NORTH
#undef BACK_X_OFFSET_EAST
#undef BACK_Y_OFFSET_EAST
#undef BACK_X_OFFSET_SOUTH
#undef BACK_Y_OFFSET_SOUTH
#undef BACK_X_OFFSET_WEST
#undef BACK_Y_OFFSET_WEST
#undef NECK_X_OFFSET_NORTH
#undef NECK_Y_OFFSET_NORTH
#undef NECK_X_OFFSET_EAST
#undef NECK_Y_OFFSET_EAST
#undef NECK_X_OFFSET_SOUTH
#undef NECK_Y_OFFSET_SOUTH
#undef NECK_X_OFFSET_WEST
#undef NECK_Y_OFFSET_WEST

View File

@@ -0,0 +1,704 @@
//Hyperstation Arousal hud
//This needs alot of attention, im a bad coder. a shitty attempt at making a more user friendly/modern hud
//if you wanna use this on your own server go ahead, but alittle credit would always be nice! -quotefox
//This still uses alot of cits arousal system!
/obj/screen/arousal/ui_interact(mob/user)
. = ..()
var/dat = {"<B>Genitals</B><BR><HR>"}
var/mob/living/carbon/U = user
for(var/obj/item/organ/genital/G in U.internal_organs)
if(!G.nochange)
if(!G.dontlist)
// GS13: Fix spelling
dat += "<a href='byond://?src=[REF(src)];hide[G.name]=1'>[G.mode == "hidden" ? "[G.name] <font color='red'>(Hidden)</font>" : (G.mode == "clothes" ? "[G.name] <font color='yellow'>(Hidden by Clothes)</font>" : (G.mode == "visible" ? "[G.name] <font color='green'>(Visible)</font>" : "[G.name] <font color='green'>(Visible)</font>"))]</a><BR>"
dat += {"<BR><B>Contexual Options</B><BR><HR>"}
var/obj/item/organ/genital/penis/P = user.getorganslot("penis")
//Options
dat += "<a href='byond://?src=[REF(src)];masturbate=1'>Masturbate</A>"
dat += "(Stimulate a sexual organ with your hands.)<BR>"
dat += "<a href='byond://?src=[REF(src)];climax=1'>Climax</A>"
dat += "(Orgasm from a sexual organ.)<BR>"
dat += "<a href='byond://?src=[REF(src)];container=1'>Fill container</A>"
dat += "(Use a container in your hand to collect your seminal fluid.)<BR>"
var/mob/living/carbon/human/C = usr
if(C && C.w_uniform || C.wear_suit) //if they are wearing cloths
dat += "<a href='byond://?src=[REF(src)];clothesplosion=1'>Explode out of clothes</A>"
dat += "(Flex your body to cause your clothes to burst apart.)<BR>"
if(user.pulling)
dat += "<a href='byond://?src=[REF(src)];kiss=1'>Kiss [user.pulling]</A>"
dat += "(Kiss a partner, or object.)<BR>"
dat += "<a href='byond://?src=[REF(src)];feed=1'>Feed [user.pulling]</A>"
dat += "(Feed a partner.)<BR>"
dat += "<a href='byond://?src=[REF(src)];feedfrom=1'>Feed from [user.pulling]</A>"
dat += "(Feed a partner.)<BR>"
else
dat += "<span class='linkOff'>Kiss</span></A>"
dat += "(Requires a partner)<BR>"
dat += "<span class='linkOff'>Feed others</span></A>"
dat += "(Requires a partner)<BR>"
dat += "<span class='linkOff'>Feed from others</span></A>"
dat += "(Requires a partner)<BR>"
dat += "<a href='byond://?src=[REF(src)];feedyourself=1'>Feed yourself</A>"
dat += "(Feed yourself with your own genitals)<BR>"
var/obj/item/organ/genital/belly/Belly = user.getorganslot("belly")
if(Belly)
if(Belly.inflatable)
// GS13: Fix description
dat += "<a href='byond://?src=[REF(src)];shrink_belly=1'>Decrease belly size</A>"
dat += "(Shrink your belly down a size)<BR>"
dat += "<a href='byond://?src=[REF(src)];inflate_belly=1'>Increase belly size</A>"
dat += "(Bloat your belly up a size)<BR>"
if(user.pulling)
dat += "<a href='byond://?src=[REF(src)];climaxover=1'>Climax over [user.pulling]</A>" //you can cum on objects if you really want...
dat += "(Orgasm over a person or object.)<BR>"
if(isliving(user.pulling))
if(iscarbon(user.pulling))
dat += "<a href='byond://?src=[REF(src)];climaxwith=1'>Climax with [user.pulling]</A>"
dat += {"(Orgasm with another person.)<BR>"}
var/mob/living/carbon/human/H = user.pulling
if(H.breedable && P && H)
dat += "<a href='byond://?src=[REF(src)];impreg=1'>Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)</A>"
dat += "(Climax inside another person, and attempt to knock them up.)<BR>"
else
dat += "<span class='linkOff'>Climax over</span></A>"
dat += "(Requires a partner)<BR>"
dat += "<span class='linkOff'>Climax with</span></A>"
dat += "(Requires a partner)<BR>"
//old code needs to be cleaned
if(P)
if(P.condom == 1)
dat += "<a href='byond://?src=[REF(src)];removecondom=1'>Remove condom (penis)</A><BR>"
if(P.sounding == 1)
dat += "<a href='byond://?src=[REF(src)];removesound=1'>Remove sounding rod (penis)</A><BR>"
for(var/obj/item/organ/genital/G in U.internal_organs)
if(G.equipment) //they have equipment
dat += "<a href='byond://?src=[REF(src)];removeequipment[G.name]=1;'>Remove [G.equipment.name] ([G.name])</A><BR>"
dat += {"<HR>"}//Newline for the objects
//bottom options
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<a href='byond://?src=[REF(src)];omenu=1'>Old Menu</A>"
dat += "<a href='byond://?src=[REF(src)];underwear=1'>Toggle Undergarments </A>"
dat += "<BR>"
var/datum/browser/popup = new(user, "arousal", "Arousal Panel")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state), 500,600)
popup.open()
/obj/screen/arousal/Topic(href, href_list)
. = ..() //Sanity checks.
if(..())
return
var/mob/living/carbon/human/H = usr
if (!H)
return
if(usr.stat==1) //No sleep-masturbation, you're unconscious.
to_chat(usr, "<span class='warning'>You must be conscious to do that!</span>")
usr << browse(null, "window=arousal") //closes the window
return
if(usr.stat==3)
to_chat(usr, "<span class='warning'>You must be alive to do that!</span>")
usr << browse(null, "window=arousal") //closes the window
return
if(href_list["hidepenis"])
var/obj/item/organ/genital/penis/P = usr.getorganslot("penis")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
P.toggle_visibility(picked_visibility)
if(href_list["hidevagina"])
var/obj/item/organ/genital/vagina/V = usr.getorganslot("vagina")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
V.toggle_visibility(picked_visibility)
if(href_list["hidebreasts"])
var/obj/item/organ/genital/breasts/B = usr.getorganslot("breasts")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
B.toggle_visibility(picked_visibility)
if(href_list["hidebelly"])
var/obj/item/organ/genital/belly/E = usr.getorganslot("belly")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
E.toggle_visibility(picked_visibility)
if(href_list["hideanus"])
var/obj/item/organ/genital/anus/A = usr.getorganslot("anus")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
A.toggle_visibility(picked_visibility)
if(href_list["hidetesticles"])
var/obj/item/organ/genital/testicles/T = usr.getorganslot("testicles")
var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
T.toggle_visibility(picked_visibility)
if(href_list["masturbate"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.solomasturbate()
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["container"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.cumcontainer()
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["clothesplosion"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //Requires 33% arousal.
H.clothesplosion()
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["climax"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.climaxalone(FALSE)
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["climaxover"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.climaxover(usr.pulling)
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["climaxwith"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.climaxwith(usr.pulling)
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["impreg"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
H.impregwith(usr.pulling)
return
else
to_chat(usr, "<span class='warning'>You aren't aroused enough for that! </span>")
return
if(href_list["kiss"])
if(usr.pulling)
kiss()
else
to_chat(usr, "<span class='warning'>You cannot do this alone!</span>")
return
if(href_list["feed"])
if(usr.pulling)
feed()
else
to_chat(usr, "<span class='warning'>You cannot do this alone!</span>")
return
if(href_list["feedfrom"])
if(usr.pulling)
feedfrom()
else
to_chat(usr, "<span class='warning'>You cannot do this alone!</span>")
return
if(href_list["feedyourself"])
feedyourself()
return
if(href_list["shrink_belly"])
var/obj/item/organ/genital/belly/E = usr.getorganslot("belly")
if(E.size > 0)
to_chat(usr, "<span class='userlove'>You feel your belly diminish.</span>")
E.size -= 1
H.update_genitals()
else
to_chat(usr, "<span class='warning'>Your belly is already at the minimum size! </span>")
if(href_list["inflate_belly"])
var/obj/item/organ/genital/belly/E = usr.getorganslot("belly")
if(E.size < 11)
to_chat(usr, "<span class='userlove'>You feel your belly bloat out..</span>")
E.size += 1
H.update_genitals()
else
to_chat(usr, "<span class='warning'>Your belly is already at the maximum size! </span>")
if(href_list["removecondom"])
H.menuremovecondom()
if(href_list["removesound"])
H.menuremovesounding()
if(href_list["removeequipmentpenis"])
var/obj/item/organ/genital/penis/O = usr.getorganslot("penis")
var/obj/item/I = O.equipment
usr.put_in_hands(I)
O.equipment = null
if(href_list["removeequipmentbreasts"])
var/obj/item/organ/genital/breasts/O = usr.getorganslot("breasts")
var/obj/item/I = O.equipment
usr.put_in_hands(I)
O.equipment = null
if(href_list["removeequipmentvagina"])
var/obj/item/organ/genital/vagina/O = usr.getorganslot("vagina")
var/obj/item/I = O.equipment
usr.put_in_hands(I)
if(istype(I, /obj/item/portalpanties))
var/obj/item/portalpanties/P = I
P.remove()
O.equipment = null
if(href_list["removeequipmentbelly"])
var/obj/item/organ/genital/belly/O = usr.getorganslot("belly")
var/obj/item/I = O.equipment
usr.put_in_hands(I)
O.equipment = null
if(href_list["removeequipmentanus"])
var/obj/item/organ/genital/anus/O = usr.getorganslot("anus")
var/obj/item/I = O.equipment
usr.put_in_hands(I)
O.equipment = null
if(href_list["omenu"])
usr << browse(null, "window=arousal") //closes the window
H.mob_climax()
return
if(href_list["underwear"])
H.underwear_toggle()
return
src.ui_interact(usr)
obj/screen/arousal/proc/kiss()
if(usr.restrained(TRUE))
to_chat(usr, "<span class='warning'>You can't do that while restrained!</span>")
return
var/mob/living/carbon/human/H = usr
if (H)
H.kisstarget(H.pulling)
obj/screen/arousal/proc/feed()
if(usr.restrained(TRUE))
to_chat(usr, "<span class='warning'>You can't do that while restrained!</span>")
return
var/mob/living/carbon/human/H = usr
if (H)
H.genitalfeed(H.pulling)
obj/screen/arousal/proc/feedfrom()
if(usr.restrained(TRUE))
to_chat(usr, "<span class='warning'>You can't do that while restrained!</span>")
return
var/mob/living/carbon/human/H = usr
if (H)
H.genitalfeedfrom(H.pulling)
obj/screen/arousal/proc/feedyourself()
if(usr.restrained(TRUE))
to_chat(usr, "<span class='warning'>You can't do that while restrained!</span>")
return
var/mob/living/carbon/human/H = usr
if (H)
H.genitalfeedyourself()
/mob/living/carbon/human/proc/menuremovecondom()
if(restrained(TRUE))
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return
var/free_hands = get_num_arms()
if(!free_hands)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return
var/obj/item/organ/genital/penis/P = getorganslot("penis")
if(!P.condom)
to_chat(src, "<span class='warning'>You don't have a condom on!</span>")
return
if(P.condom)
to_chat(src, "<span class='warning'>You tug the condom off the end of your penis!</span>")
removecondom()
src.ui_interact(usr) //reopen dialog
return
return
/mob/living/carbon/human/proc/menuremovesounding()
if(restrained(TRUE))
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return
var/free_hands = get_num_arms()
if(!free_hands)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return
var/obj/item/organ/genital/penis/P = getorganslot("penis")
if(!P.sounding)
to_chat(src, "<span class='warning'>You don't have a rod inside!</span>")
return
if(P.sounding)
to_chat(src, "<span class='warning'>You pull the rod off from the tip of your penis!</span>")
removesounding()
src.ui_interact(usr) //reopen dialog
return
return
/mob/living/carbon/human/proc/solomasturbate()
if(restrained(TRUE))
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return
var/free_hands = get_num_arms()
if(!free_hands)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return
for(var/helditem in held_items)
if(isobj(helditem))
free_hands--
if(free_hands <= 0)
to_chat(src, "<span class='warning'>You're holding too many things.</span>")
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
picked_organ = pick_masturbate_genitals()
if(picked_organ)
src << browse(null, "window=arousal") //closes the window
mob_masturbate(picked_organ)
return
else //They either lack organs that can masturbate, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
//Kissing target proc
/mob/living/carbon/human/proc/kisstarget(mob/living/L)
src << browse(null, "window=arousal") //closes the arousal window, if its open, mainly to stop spam
if(isliving(L)) //is your target living? Living people can resist your advances if they want to via moving.
if(iscarbon(L))
src.visible_message("<span class='notice'>[src] is about to kiss [L]!</span>", \
"<span class='notice'>You're attempting to kiss [L]!</span>", \
"<span class='notice'>You're attempting to kiss with something!</span>")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "kissed", /datum/mood_event/kiss) //how cute, affection is nice.
//Well done you kissed it/them!
src.visible_message("<span class='notice'>[src] kisses [L]!</span>", \
"<span class='notice'>You kiss [L]!</span>", \
"<span class='notice'>You kiss something!</span>")
/mob/living/carbon/human/proc/climaxalone()
//we dont need hands to climax alone, its hands free!
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals()
if(picked_organ)
src << browse(null, "window=arousal") //closes the window
mob_climax_outside(picked_organ)
return
else //They either lack organs that can masturbate, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
/mob/living/carbon/human/proc/climaxwith(mob/living/T)
var/mob/living/carbon/human/L = pick_partner()
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals()
if(picked_organ)
var/mob/living/partner = L
if(partner)
src << browse(null, "window=arousal") //alls fine, we can close the window now.
var/obj/item/organ/genital/penis/P = picked_organ
var/spillage = "No" //default to no, just incase player has items on to prevent climax
if(!P.condom == 1&&!P.sounding == 1) //you cant climax with a condom on or sounding in.
spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No")
if(spillage == "Yes")
mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE)
else
mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //They either lack organs that can masturbate, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
/mob/living/carbon/human/proc/climaxover(mob/living/T)
var/mob/living/carbon/human/L = T
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals()
if(picked_organ)
src << browse(null, "window=arousal") //alls fine, we can close the window now.
var/mob/living/partner = L
if(partner)
var/obj/item/organ/genital/penis/P = picked_organ
if(P.condom == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a condom on.</span>")
return
if(P.sounding == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a sounding in.</span>")
return
mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //They either lack organs that can masturbate, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
/mob/living/carbon/human/proc/clothesplosion()
if(usr.restrained(TRUE))
to_chat(usr, "<span class='warning'>You can't do that while restrained!</span>")
return
var/mob/living/carbon/human/H = src
var/items = H.get_contents()
for(var/obj/item/W in items)
if(W == H.w_uniform || W == H.wear_suit)
H.dropItemToGround(W, TRUE)
playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1)
H.visible_message("<span class='boldnotice'>[H] explodes out of their clothes!'</span>")
/mob/living/carbon/human/proc/impregwith(mob/living/T)
var/mob/living/carbon/human/L = pick_partner()
var/obj/item/organ/genital/picked_organ
picked_organ = src.getorganslot("penis") //Impregnation must be done with a penis.
if(picked_organ)
var/mob/living/partner = L
if(partner)
if(!partner.breedable)//check if impregable.
to_chat(src, "<span class='warning'>Your partner cannot be impregnated.</span>")//some fuckary happening, you shouldnt even get to this point tbh.
return
var/obj/item/organ/genital/penis/P = picked_organ
//you cant impreg with a condom on or sounding in.
if(P.condom == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a condom on.</span>")
return
if(P.sounding == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a sounding in.</span>")
return
src << browse(null, "window=arousal") //alls fine, we can close the window now.
//Keeping this for messy fun
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No")
if(spillage == "Yes")
mob_climax_partner(picked_organ, partner, TRUE, TRUE, FALSE)
else
mob_climax_partner(picked_organ, partner, FALSE, TRUE, FALSE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //no penis :(
to_chat(src, "<span class='warning'>You cannot impregnate without a penis.</span>")
return
/mob/living/carbon/human/proc/cumcontainer(mob/living/T)
//We'll need hands and no restraints.
if(restrained(TRUE)) //TRUE ignores grabs
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return
var/free_hands = get_num_arms()
if(!free_hands)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return
for(var/helditem in held_items)//how many hands are free
if(isobj(helditem))
free_hands--
if(free_hands <= 0)
to_chat(src, "<span class='warning'>You're holding too many things.</span>")
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
src << browse(null, "window=arousal")
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
if(picked_organ)
//Good, got an organ, time to pick a container
var/obj/item/reagent_containers/fluid_container = pick_climax_container()
if(fluid_container)
mob_fill_container(picked_organ, fluid_container)
return
else
to_chat(src, "<span class='warning'>You cannot do this without anything to fill.</span>")
return
else //They either lack organs that can climax, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot fill anything without choosing genitals.</span>")
return
/atom/proc/add_cum_overlay() //This can go in a better spot, for now its here.
cum_splatter_icon = icon(initial(icon), initial(icon_state), , 1)
cum_splatter_icon.Blend("#fff", ICON_ADD)
cum_splatter_icon.Blend(icon('hyperstation/icons/effects/cumoverlay.dmi', "cum_obj"), ICON_MULTIPLY)
add_overlay(cum_splatter_icon)
/atom/proc/wash_cum()
cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_normal"))
cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_large"))
if(cum_splatter_icon)
cut_overlay(cum_splatter_icon)
return TRUE
/mob/living/carbon/human/proc/genitalfeed(mob/living/L, mb_time = 30)
if(isliving(L)) //is your target living? Living people can resist your advances if they want to via moving.
if(iscarbon(L))
var/obj/item/organ/genital/picked_organ
var/total_fluids = 0
var/datum/reagents/fluid_source = null
src << browse(null, "window=arousal")
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
if(picked_organ)
//Good, got an organ, time to pick a container
if(picked_organ.name == "penis")//if the select organ is a penis
var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
if(P.condom) //if the penis is condomed
to_chat(src, "<span class='warning'>You cannot feed someone when there is a condom over your [picked_organ.name].</span>")
return
if(P.sounding) //if the penis is sounded
to_chat(src, "<span class='warning'>You cannot feed someone when there is a rod inside your [picked_organ.name].</span>")
return
if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
fluid_source = picked_organ.reagents
else
if(!picked_organ.linked_organ)
to_chat(src, "<span class='warning'>Your [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
return
fluid_source = picked_organ.linked_organ.reagents
total_fluids = fluid_source.total_volume
src.visible_message("<span class='love'>[src] starts to feed [L.name] with their [picked_organ.name].</span>", \
"<span class='userlove'>You feed [L.name] with your [picked_organ.name].</span>")
if(do_after(src, mb_time, target = src) && in_range(src, L))
fluid_source.trans_to(L, total_fluids)
src.visible_message("<span class='love'>[src] uses [p_their()] [picked_organ.name] to feed [L.name]!</span>", \
"<span class='userlove'>You used your [picked_organ.name] to feed [L.name] a total of [total_fluids]u's.</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
if(picked_organ.can_climax)
setArousalLoss(min_arousal)
else //They either lack organs that can climax, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot fill anything without choosing exposed genitals.</span>")
return
/mob/living/carbon/human/proc/genitalfeedfrom(mob/living/target, mb_time = 30)
var/mob/living/carbon/human/L = target
var/obj/item/organ/genital/picked_organ
var/total_fluids = 0
var/datum/reagents/fluid_source = null
src << browse(null, "window=arousal")
var/list/genitals_list = list()
var/list/worn_stuff = L.get_equipped_items()
for(var/obj/item/organ/genital/G in L.internal_organs)
if(G.can_climax) //filter out what you can't masturbate with
if(G.is_exposed(worn_stuff)) //Nude or through_clothing
if(!G.dontlist)
genitals_list += G
if(genitals_list.len)
picked_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list
else
return
if(picked_organ)
//Good, got an organ, time to pick a container
if(picked_organ.name == "penis")//if the select organ is a penis
var/obj/item/organ/genital/penis/P = L.getorganslot("penis")
if(P.condom) //if the penis is condomed
to_chat(src, "<span class='warning'>You cannot feed from [picked_organ.name] when there is a condom over it.</span>")
return
if(P.sounding) //if the penis is sounded
to_chat(src, "<span class='warning'>You cannot feed from [picked_organ.name] when there is a rod inside it.</span>")
return
if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
fluid_source = picked_organ.reagents
else
if(!picked_organ.linked_organ)
to_chat(src, "<span class='warning'>The [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
return
fluid_source = picked_organ.linked_organ.reagents
total_fluids = fluid_source.total_volume
src.visible_message("<span class='love'>[src] starts to feed from [L.name]'s [picked_organ.name].</span>", \
"<span class='userlove'>You feed from [L.name]'s '[picked_organ.name].</span>")
if(do_after(src, mb_time, target = src) && in_range(src, L))
fluid_source.trans_to(src, total_fluids)
src.visible_message("<span class='love'>[src] feeds from [L.name]'s [picked_organ.name]!</span>", \
"<span class='userlove'>You used [L.name]'s [picked_organ.name] to feed with a total of [total_fluids]u's.</span>")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
if(picked_organ.can_climax)
L.setArousalLoss(min_arousal)
else //They either lack organs that can climax, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot fill anything without choosing exposed genitals.</span>")
return
/mob/living/carbon/human/proc/genitalfeedyourself(mb_time = 30)
var/obj/item/organ/genital/picked_organ
var/total_fluids = 0
var/datum/reagents/fluid_source = null
src << browse(null, "window=arousal")
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
if(picked_organ)
//Good, got an organ, time to pick a container
if(picked_organ.name == "penis")//if the select organ is a penis
var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
if(P.condom) //if the penis is condomed
to_chat(src, "<span class='warning'>You cannot feed yourself when there is a condom over your [picked_organ.name].</span>")
return
if(P.sounding) //if the penis is sounded
to_chat(src, "<span class='warning'>You cannot feed yourself when there is a rod inside your [picked_organ.name].</span>")
return
if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
fluid_source = picked_organ.reagents
else
if(!picked_organ.linked_organ)
to_chat(src, "<span class='warning'>Your [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
return
fluid_source = picked_organ.linked_organ.reagents
total_fluids = fluid_source.total_volume
src.visible_message("<span class='love'>[src] starts to feed themselves with their [picked_organ.name].</span>", \
"<span class='userlove'>You feed yourself with your [picked_organ.name].</span>")
if(do_after(src, mb_time))
fluid_source.trans_to(src, total_fluids)
src.visible_message("<span class='love'>[src] uses [p_their()] [picked_organ.name] to feed themselves!</span>", \
"<span class='userlove'>You used your [picked_organ.name] to feed yourself a total of [total_fluids]u's.</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
if(picked_organ.can_climax)
setArousalLoss(min_arousal)
else //They either lack organs that can climax, or they didn't pick one.
to_chat(src, "<span class='warning'>You cannot fill anything without choosing exposed genitals.</span>")
return

View File

@@ -0,0 +1,15 @@
/mob/living/carbon/human/handle_creampie()
if(NOBLOOD in dna.species.species_traits)
cumdrip_rate = 0
return
if(cumdrip_rate < 0)
cumdrip_rate = 0
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE)))
cumdrip_rate = cumdrip_rate - 1
cumdrip()
/mob/living/carbon/human/proc/cumdrip()
if(isturf(loc))
new/obj/effect/decal/cleanable/semendrip(get_turf(src))

View File

@@ -0,0 +1,4 @@
/datum/export/plutonium_rod
cost = 20000
unit_name = "Plutonium Rod"
export_types = list(/obj/item/twohanded/required/fuel_rod/plutonium)

View File

@@ -0,0 +1,24 @@
/datum/export/sweatshop/stool
cost = 850
unit_name = "custom stool"
export_types = list(/obj/item/processed/wood/stool)
/datum/export/sweatshop/cushion
cost = 300
unit_name = "cloth cushion"
export_types = list(/obj/item/cushion)
/datum/export/sweatshop/cushionsilk
cost = 500
unit_name = "silk cushion"
export_types = list(/obj/item/cushion)
/datum/export/sweatshop/stool/cushioncloth
cost = 1800
unit_name = "cushioned stool (cloth)"
export_types = list(/obj/item/processed/wood/stoolcloth)
/datum/export/sweatshop/stool/cushionsilk
cost = 2400
unit_name = "cushioned stool (cloth)"
export_types = list(/obj/item/processed/wood/stoolsilk)

View File

@@ -0,0 +1,7 @@
/datum/supply_pack/service/stripperpole
name = "Stripper Pole Crate"
desc = "No private bar is complete without a stripper pole, show off the goods! Comes with a ready-to-assemble stripper pole, and a complementary wrench to get things set up!"
cost = 3550
contains = list(/obj/item/polepack/,
/obj/item/wrench/)
crate_name = "stripper pole crate"

View File

@@ -0,0 +1,6 @@
/obj/item/processed/metal
name = "Heated Metal"
desc = "A malleable metal, able to be cut into nails."
icon = 'hyperstation/icons/obj/cargo/sweatshop/metal.dmi'
icon_state = "metal"
sharpness = TRUE

View File

@@ -0,0 +1,256 @@
//THE TOOLS
/obj/item/carpentry
name = "carpentry"
desc = "You shouldn't be seeing this!"
icon = 'hyperstation/icons/obj/cargo/sweatshop/sweatshop.dmi'
usesound = list('sound/effects/picaxe1.ogg', 'sound/effects/picaxe2.ogg', 'sound/effects/picaxe3.ogg')
/obj/item/carpentry/handsaw
name = "handsaw"
desc = "A shoddy tool used to process wood into smaller segments."
icon_state = "handsaw"
slot_flags = ITEM_SLOT_BACK
force = 8
sharpness = TRUE
w_class = WEIGHT_CLASS_HUGE
materials = list(MAT_METAL=50)
attack_verb = list("slashed", "sawed")
/obj/item/carpentry/hammer
name = "hammer"
desc = "A tool used to manually bash nails into place."
icon_state = "hammer"
slot_flags = ITEM_SLOT_BELT
force = 7
sharpness = FALSE
w_class = WEIGHT_CLASS_NORMAL
materials = list(MAT_METAL=100)
attack_verb = list("bonked", "nailed")
/obj/item/carpentry/glue
name = "glue"
desc = "Used to haphazardly stick things together; secured by the toughest Monkey Glue(TM)."
icon_state = "glue"
force = 0
sharpness = FALSE
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_PLASTIC=25)
attack_verb = list("glued", "coughed")
/obj/item/carpentry/borer
name = "manual borer"
desc = "An incredibly awful tool used to manually drill holes into something... Surely there's a better option."
icon_state = "borer"
force = 3
sharpness = TRUE
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=25)
attack_verb = list("bored", "drilled")
/obj/item/carpentry/sandpaper
name = "sandpaper strip"
desc = "A strip of sandpaper, commonly used for sanding down rough surfaces into a more smooth shape."
icon_state = "sandpaper"
force = 1
sharpness = FALSE
w_class = WEIGHT_CLASS_TINY
materials = list(MAT_GLASS=1) //lmao
attack_verb = list("sanded", "licked")
/obj/item/nails
name = "metal nails"
desc = "A bunch of nails, used for hammering into things."
icon = 'hyperstation/icons/obj/cargo/sweatshop/sweatshop.dmi'
icon_state = "nails"
force = 0
sharpness = TRUE
w_class = WEIGHT_CLASS_TINY
materials = list(MAT_METAL=10)
attack_verb = list("nailed", "screwed")
/obj/item/cushion
name = "basic cushion"
desc = "Beats sitting on the floor."
icon = 'hyperstation/icons/obj/cargo/sweatshop/cloth.dmi'
icon_state = "clothcushion"
force = 0
sharpness = FALSE
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("thomped", "thwacked")
/obj/item/cushion/silk
name = "silk cushion"
desc = "How'd it turn red?!"
icon_state = "silkcushion"
//BASIC RECIPES - To do, add sound. As well as refactor everything in a more smart way so we can add the possibility of multiple wood types in the future.
//saw a plank into two platforms
/obj/item/processed/wood/plank/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/handsaw))
to_chat(user,"<span class='notice'> You begin to saw [src] in half...</span>")
if(do_after(user, 40) && isturf(loc))
new src.sawobj(loc)
new src.sawobj(loc) //send help i dont know how to make two in the same line lmfao
to_chat(user, "<span class='notice'> You saw [src] in half.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to saw [src]!</span>")
else
..()
//saw a platform into four blocks
/obj/item/processed/wood/platform/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/handsaw))
to_chat(user,"<span class='notice'> You begin cut [src] into smaller pieces...</span>")
if(do_after(user, 20) && isturf(loc))
new src.sawobj(loc)
new src.sawobj(loc)
new src.sawobj(loc)
new src.sawobj(loc)
to_chat(user, "<span class='notice'> You cut [src] into four pieces.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to saw [src]!</span>")
else
..()
//sand a block into a peg
/obj/item/processed/wood/block/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/sandpaper))
to_chat(user,"<span class='notice'> You carefully begin to sand down [src]...</span>")
if(do_after(user, 50) && isturf(loc))
new src.sandobj(loc)
to_chat(user, "<span class='notice'> You smooth [src] into a peg.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to sand [src]!</span>")
else
..()
//cut heated metal into nails
/obj/item/processed/metal/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER)
to_chat(user,"<span class='notice'> You tediously begin to cut [src] into several nails...</span>")
if(do_after(user, 80) && isturf(loc))
new /obj/item/nails(loc)
new /obj/item/nails(loc)
to_chat(user, "<span class='notice'> You make some crude metal nails.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to process [src]!</span>")
else
..()
//Covered in glue
//cover a wooden block in glue
/obj/item/processed/wood/block/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/glue))
to_chat(user,"<span class='notice'> You begin to glue down one end of [src]...</span>")
if(do_after(user, 10) && isturf(loc))
new src.glueobj(loc)
to_chat(user, "<span class='notice'> You slap some glue onto [src].</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to glue [src]!</span>")
else
..()
//cover a wooden peg in glue
/obj/item/processed/wood/peg/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/glue))
to_chat(user,"<span class='notice'> You begin to glue down one end of the [src]...</span>")
if(do_after(user, 10) && isturf(loc))
new src.glueobj(loc)
to_chat(user, "<span class='notice'> You slap some glue onto [src].</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to glue [src]!</span>")
else
..()
//Seats
//bore a platform into a seat
/obj/item/processed/wood/platform/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/borer))
to_chat(user,"<span class='notice'> You begin to cut four holes into [src]...</span>")
if(do_after(user, 40) && isturf(loc))
new src.boreobj(loc)
to_chat(user, "<span class='notice'> You drill four holes into [src].</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to refine [src]!</span>")
else
..()
//Stools - Further crafting
/obj/item/processed/wood/stool1/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/nails))
to_chat(user,"<span class='notice'> You place nails into [src]...</span>")
if(do_after(user, 20) && isturf(loc))
new /obj/item/processed/wood/stool2(loc)
to_chat(user, "<span class='notice'> The nails are ready to be hammered.</span>")
qdel(src)
qdel(I)
else
to_chat(user, "<span class='warning'>You need to hold still to refine [src]!</span>")
else
..()
/obj/item/processed/wood/stool2/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/hammer))
to_chat(user,"<span class='notice'> You begin to hammer the [src]...</span>")
if(do_after(user, 30) && isturf(loc))
new /obj/item/processed/wood/stool3(loc)
to_chat(user, "<span class='notice'> The nails are hammered into place.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to refine [src]!</span>")
else
..()
/obj/item/processed/wood/stool3/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/carpentry/sandpaper))
to_chat(user,"<span class='notice'> You begin to sand the [src]...</span>")
if(do_after(user, 30) && isturf(loc))
new /obj/item/processed/wood/stool4(loc)
to_chat(user, "<span class='notice'> You sand down the [src].</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need to hold still to refine [src]!</span>")
else
..()
/obj/item/processed/wood/stool4/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/processed/wood/glueblock))
to_chat(user,"<span class='notice'> You add some finishing touches to the [src]...</span>")
if(do_after(user, 30) && isturf(loc))
new /obj/item/processed/wood/stool(loc)
to_chat(user, "<span class='notice'> You complete the [src].</span>")
qdel(src)
qdel(I)
else
to_chat(user, "<span class='warning'>You need to hold still to refine [src]!</span>")
else
..()
/obj/item/processed/wood/stool/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/cushion))
to_chat(user,"<span class='notice'> You secure a cloth cushion to [src]...</span>")
if(do_after(user, 30) && isturf(loc))
new /obj/item/processed/wood/stoolcloth(loc)
to_chat(user, "<span class='notice'> You add a cushion to [src].</span>")
qdel(src)
qdel(I)
else
to_chat(user, "<span class='warning'>You need to hold still to detail [src]!</span>")
else
..()
/obj/item/processed/wood/stool/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/cushion/silk))
to_chat(user,"<span class='notice'> You secure a silk cushion to [src]...</span>")
if(do_after(user, 30) && isturf(loc))
new /obj/item/processed/wood/stoolsilk(loc)
to_chat(user, "<span class='notice'> You add a cushion to [src].</span>")
qdel(src)
qdel(I)
else
to_chat(user, "<span class='warning'>You need to hold still to detail [src]!</span>")
else
..()

View File

@@ -0,0 +1,128 @@
//WOODEN COMPONENTS. honestly i need to move some shit around to allow for easier material swapping, but that's for a later date.
/obj/item/processed/wood
name = "Wooden Processed Item"
desc = "You shouldn't see this!"
icon = 'hyperstation/icons/obj/cargo/sweatshop/wooden.dmi'
sharpness = FALSE
attack_verb = list("slapped", "thunked")
var/sawobj = /obj/item/condom
var/glueobj = /obj/item/dildo
var/sandobj = /obj/item/carpentry/sandpaper
var/boreobj = /obj/item/carpentry/borer
/obj/item/processed/wood/plank
name = "processable wooden plank"
desc = "A somewhat sturdy refined plank. This can be used in various applications."
icon_state = "plank"
force = 3
w_class = WEIGHT_CLASS_HUGE
sawobj = /obj/item/processed/wood/platform
/obj/item/processed/wood/platform
name = "wood platform"
desc = "A somewhat sturdy cropping of a plank. This one is an alright foundation for chairs and stools."
icon_state = "platform"
force = 3
w_class = WEIGHT_CLASS_NORMAL
sawobj = /obj/item/processed/wood/block
boreobj = /obj/item/processed/wood/seat
/obj/item/processed/wood/block
name = "wood block"
desc = "A chopped platform into a wooden block. This one can be used for sanded into pegs, or used as a base on it's own."
icon_state = "block"
force = 2
w_class = WEIGHT_CLASS_SMALL
sandobj = /obj/item/processed/wood/peg
glueobj = /obj/item/processed/wood/glueblock
/obj/item/processed/wood/peg
name = "wood peg"
desc = "A wooden peg. Useful for fitting into holes."
icon_state = "peg"
force = 1
w_class = WEIGHT_CLASS_TINY
attack_verb = list("donked", "thunked")
glueobj = /obj/item/processed/wood/gluepeg
//glue
/obj/item/processed/wood/gluepeg
name = "glued wood peg"
desc = "A wooden peg. With a bunch of glue used for securing."
icon_state = "gluepeg"
force = 1
w_class = WEIGHT_CLASS_TINY
attack_verb = list("pegged", "thunked")
/obj/item/processed/wood/glueblock
name = "glued wood block"
desc = "A wooden block. With a bunch of glue used for securing."
icon_state = "glueblock"
force = 2
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("blocked", "thunked")
//seat
/obj/item/processed/wood/seat
name = "wood seat"
desc = "A baseline for crafting seats. Not exactly that comfortable to sit on..."
icon_state = "seat"
force = 2
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("slapped", "thunked")
//Stool steps. There's probably an easier way to do this, but I cannot be assed rn, I'll refine after PR
/obj/item/processed/wood/stool1
name = "stool base"
desc = "A haphazardly made base for a stool. It's not even secured with any nails."
icon_state = "stool1"
force = 4
w_class = WEIGHT_CLASS_BULKY
/obj/item/processed/wood/stool2
name = "nailed stool base"
desc = "Nails are in position"
icon_state = "stool2"
force = 4
w_class = WEIGHT_CLASS_BULKY
/obj/item/processed/wood/stool3
name = "hammered stool base"
desc = "A vaguely stool-shaped... Thing. Could use some sandpaper."
icon_state = "stool3"
force = 4
w_class = WEIGHT_CLASS_BULKY
/obj/item/processed/wood/stool4
name = "bland stool"
desc = "A rather bland stool."
icon_state = "stool4"
force = 4
w_class = WEIGHT_CLASS_BULKY
//The finished product
/obj/item/processed/wood/stool
name = "custom stool"
desc = "An intricite, custom stool."
icon_state = "stool"
force = 10
w_class = WEIGHT_CLASS_BULKY
//Let's make it soft and more expensive
/obj/item/processed/wood/stoolcloth
name = "cloth-cushioned stool"
desc = "A custom stool with a cloth cushion."
icon_state = "stoolcloth"
force = 10
w_class = WEIGHT_CLASS_BULKY
/obj/item/processed/wood/stoolsilk
name = "cloth-cushioned stool"
desc = "A custom stool with a silk cushion."
icon_state = "stoolsilk"
force = 11 //lol
w_class = WEIGHT_CLASS_BULKY

View File

@@ -0,0 +1,11 @@
/datum/gear/glasses/garb
name = "polychromic gar glasses"
category =ITEM_SLOT_GLASSES
path = /obj/item/clothing/glasses/polychromic/garpoly
cost = 2
/datum/gear/glasses/gigagarb
name = "polychromic giga gar glasses"
category =ITEM_SLOT_GLASSES
path = /obj/item/clothing/glasses/polychromic/supergarpoly
cost = 2

View File

@@ -0,0 +1,11 @@
/datum/gear/syntech/ring
name = "Normalizer Ring"
category =ITEM_SLOT_GLOVES
path = /obj/item/clothing/gloves/ring/syntech
cost = 6
/datum/gear/syntech/band
name = "Normalizer Band"
category =ITEM_SLOT_GLOVES
path = /obj/item/clothing/gloves/ring/syntech/band
cost = 6

View File

@@ -0,0 +1,17 @@
/datum/gear/syntech/pendant
name = "Normalizer Pendant"
category =ITEM_SLOT_NECK
path = /obj/item/clothing/neck/syntech
cost = 6
/datum/gear/syntech/choker
name = "Normalizer Choker"
category =ITEM_SLOT_NECK
path = /obj/item/clothing/neck/syntech/choker
cost = 6
/datum/gear/syntech/collar
name = "Normalizer Collar"
category =ITEM_SLOT_NECK
path = /obj/item/clothing/neck/syntech/collar
cost = 6

View File

@@ -0,0 +1,5 @@
/datum/gear/backpack/tablet
name = "Tablet Computer"
category =ITEM_SLOT_IN_BACKPACK
path = /obj/item/modular_computer/tablet/preset/cheap/
cost = 3

View File

@@ -0,0 +1,39 @@
/obj/item/clothing/glasses/polychromic
name = "polychromic glasses template"
desc = "You shouldn't be seeing this. Report it if you do."
icon = 'hyperstation/icons/obj/clothing/glasses.dmi'
icon_state = "polygar"
item_color = "polygar"
item_state = "polygar"
alternate_worn_icon = 'hyperstation/icons/mob/eyes.dmi' //Because, as it appears, the item itself is normally not directly aware of its worn overlays, so this is about the easiest way, without adding a new var.
hasprimary = TRUE
primary_color = "#0c0c0c"
vision_correction = 1
/obj/item/clothing/glasses/polychromic/worn_overlays(isinhands, icon_file) //this is where the main magic happens. Also mandates that ALL polychromic stuff MUST USE alternate_worn_icon
. = ..()
if(hasprimary | hassecondary | hastertiary)
if(!isinhands) //prevents the worn sprites from showing up if you're just holding them
if(hasprimary) //checks if overlays are enabled
var/mutable_appearance/primary_worn = mutable_appearance(alternate_worn_icon, "[item_color]-primary") //automagical sprite selection
primary_worn.color = primary_color //colors the overlay
. += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite.
if(hassecondary)
var/mutable_appearance/secondary_worn = mutable_appearance(alternate_worn_icon, "[item_color]-secondary")
secondary_worn.color = secondary_color
. += secondary_worn
if(hastertiary)
var/mutable_appearance/tertiary_worn = mutable_appearance(alternate_worn_icon, "[item_color]-tertiary")
tertiary_worn.color = tertiary_color
. += tertiary_worn
/obj/item/clothing/glasses/polychromic/garpoly
name = "polychromic gar glasses"
desc = "Go beyond impossible and kick reason to the curb! Doesn't seem to have flash protection and doesn't seem sharp either. It is made out of bluespace prescription glass though."
/obj/item/clothing/glasses/polychromic/supergarpoly
name = "polychromic giga gar glasses"
desc = "Believe in the you who believes in yourself. Also doesn't seem to have flash protection and doesn't seem sharp either. It is made out of bluespace prescription glass though."
icon_state = "polysupergar"
item_color = "polysupergar"
item_state = "polysupergar"

View File

@@ -0,0 +1,13 @@
/obj/item/clothing/gloves/guncaster
name = "fingerless leather gloves"
desc = "Sturdy leather gloves with no fingertips, buckled at the wrist."
icon_state = "guncaster"
item_state = "guncaster"
icon = 'hyperstation/icons/obj/clothing/gloves.dmi'
alternate_worn_icon = 'hyperstation/icons/mobs/gloves.dmi'
item_color = null //So they don't wash.
transfer_prints = TRUE
strip_delay = 40
equip_delay_other = 20
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT

View File

@@ -0,0 +1,8 @@
/obj/item/clothing/head/maidband
name = "maid head-band"
desc = "To complete the maid look."
icon_state = "maid_head"
item_state = "maid_head"
icon = 'hyperstation/icons/obj/clothing/head.dmi'
alternate_worn_icon = 'hyperstation/icons/mobs/head.dmi'
mutantrace_variation = NONE

View File

@@ -0,0 +1,116 @@
//Clothing vars and procs
/obj/item/clothing
var/normalize_size = RESIZE_NORMAL //This number is used as the "normal" height people will be given when wearing one of these accessories
var/natural_size = null //The value of the wearer's body_size var in prefs. Unused for now.
var/recorded_size = null //the user's height prior to equipping
//For applying a normalization
/obj/item/clothing/proc/normalize_mob_size(mob/living/carbon/human/H)
if(H.normalized) //First we make a check to see if they're already normalized, from wearing another article of SynTech jewelry
to_chat(H, "<span class='warning'>This accessory buzzes, being overwritten by another.</span>")
playsound(H, 'sound/machines/buzz-sigh.ogg', 50, 1)
return
recorded_size = H.get_effective_size() //If not, grab their current size
playsound(H, 'sound/effects/magic.ogg', 50, 1)
flash_lighting_fx(3, 3, LIGHT_COLOR_PURPLE)
H.visible_message("<span class='warning'>A flash of purple light engulfs [H], before they change to normal!</span>","<span class='notice'>You feel warm for a moment, before everything scales to your size...</span>")
H.resize(normalize_size) //Then apply the size
H.normalized = TRUE //And set normalization
//For removing a normalization, and reverting back to normal
/obj/item/clothing/proc/denormalize_mob_size(mob/living/carbon/human/H)
if(H.normalized) //sanity check
playsound(H,'sound/weapons/emitter2.ogg', 50, 1)
flash_lighting_fx(3, 3, LIGHT_COLOR_YELLOW)
H.visible_message("<span class='warning'>Golden light engulfs [H], and they shoot back to their default height!</span>","<span class='notice'>Energy rushes through your body, and you return to normal.</span>")
H.resize(recorded_size)
H.normalized = FALSE
//For storing normalization on mobs
/mob/living
var/normalized = FALSE
//normalized is a check for instances where more than one accessory of jewelry is worn. For all intensive purposes, only the first worn accessory stores the user's size.
//Anything else is just extra.
//Clothing below. Code could be compressed more, but until I make jewelry slots, this will do. -Dahl
//GLOVE SLOT ITEMS...
//SynTech ring
/obj/item/clothing/gloves/ring/syntech
name = "normalizer ring"
desc = "An expensive, shimmering SynTech ring gilded with golden GATO markings. It will 'normalize' the size of the user to a specified height approved for work-conditions, as long as it is equipped. The artificial violet gem inside twinkles ominously."
icon = 'hyperstation/icons/obj/clothing/sizeaccessories.dmi'
icon_state = "ring"
item_state = "sring" //No use in a unique sprite since it's just one pixel
w_class = WEIGHT_CLASS_TINY
body_parts_covered = 0
transfer_prints = TRUE
strip_delay = 40
//These are already defined under the parent ring, but I wanna leave em here for reference purposes
//For glove slots
/obj/item/clothing/gloves/ring/syntech/equipped(mob/living/user, slot)
if(ishuman(user))
var/mob/living/carbon/human/human_target = user
if(slot ==ITEM_SLOT_GLOVES)
if(human_target.custom_body_size)
normalize_mob_size(human_target)
/obj/item/clothing/gloves/ring/syntech/dropped(mob/living/user, slot)
if(ishuman(user))
var/mob/living/carbon/human/human_target = user
if(human_target.normalized)
denormalize_mob_size(human_target)
//SynTech Wristband
/obj/item/clothing/gloves/ring/syntech/band
name = "normalizer wristband"
desc = "An expensive technological wristband cast in SynTech purples with shimmering GATO hues. It will 'normalize' the size of the user to a specified height for approved work-conditions, as long as it is equipped. There is a small screen buzzing with information."
icon_state = "wristband"
item_state = "syntechband"
//NECK SLOT ITEMS...
//Syntech Pendant
/obj/item/clothing/neck/syntech
name = "normalizer pendant"
desc = "A vibrant violet jewel cast in silvery-gold metals, sporting the elegance of GATO with SynTech prowess. It will 'normalize' the size of the user to a specified height for approved work-conditions, as long as it is equipped. The artificial violet gem inside twinkles ominously."
icon = 'hyperstation/icons/obj/clothing/sizeaccessories.dmi'
icon_state = "pendant"
item_state = "pendant"
w_class = WEIGHT_CLASS_SMALL //Gainstation Edit: Small, not normal sized.
//For neck items
/obj/item/clothing/neck/syntech/equipped(mob/living/user, slot)
if(ishuman(user))
var/mob/living/carbon/human/human_target = user
if(slot ==ITEM_SLOT_NECK)
if(human_target.custom_body_size)
normalize_mob_size(human_target)
/obj/item/clothing/neck/syntech/dropped(mob/living/user, slot)
if(ishuman(user))
var/mob/living/carbon/human/human_target = user
if(human_target.normalized)
denormalize_mob_size(human_target)
//Syntech Choker
/obj/item/clothing/neck/syntech/choker
name = "normalizer choker"
desc = "A sleek, tight-fitting choker embezzled with silver to gold, adorned with vibrant purple studs; combined technology of GATO and SynTech. It will 'normalize' the size of the user to a specified height for approved work-conditions, as long as it is equipped. There is a small screen buzzing with information."
icon_state = "choker"
item_state = "collar"
//Syntech Collar
/obj/item/clothing/neck/syntech/collar
name = "normalizer collar"
desc = "A cute pet collar, technologically designed with vibrant purples and smooth silvers. There is a small gem bordered by gold at the front, reading 'SYNTECH' engraved within the metal. It will 'normalize' the size of the user to a specified height for approved work-conditions, as long as it is equipped. The artificial violet gem inside twinkles ominously."
icon_state = "collar"
item_state = "collar"

View File

@@ -0,0 +1,178 @@
/obj/item/clothing/head/helmet/space/hardsuit/rd/hev
name = "HEV Suit helmet"
desc = "A Hazardous Environment Helmet. It fits snug over the suit and has a heads-up display for researchers. The flashlight seems broken, fitting considering this was made before the start of the milennium."
icon_state = "hev"
item_state = "hev"
item_color = "rd"
resistance_flags = ACID_PROOF | FIRE_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
armor = list("melee" = 30, "bullet" = 10, "laser" = 10, "energy" = 5, "bomb" = 80, "bio" = 100, "rad" = 100, "fire" = 60, "acid" = 60)
actions_types = list(/datum/action/item_action/toggle_research_scanner)
/obj/item/clothing/head/helmet/space/hardsuit/rd/hev/no_scanner
actions_types = list()
/obj/item/clothing/suit/space/hardsuit/rd/hev
name = "HEV Suit"
desc = "The hazard suit. It was designed to protect scientists from the blunt trauma, radiation, energy discharge that hazardous materials might produce or entail. Fits you like a glove. The automatic medical system seems broken... They're waiting for you, Gordon. In the test chamberrrrrr."
icon_state = "hev"
item_state = "hev"
resistance_flags = ACID_PROOF | FIRE_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT //Same as an emergency firesuit. Not ideal for extended exposure.
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/gun/energy/wormhole_projector,
/obj/item/hand_tele, /obj/item/aicard)
armor = list("melee" = 30, "bullet" = 10, "laser" = 10, "energy" = 5, "bomb" = 80, "bio" = 100, "rad" = 100, "fire" = 60, "acid" = 60)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/rd/hev
tauric = FALSE //Citadel Add for tauric hardsuits
taurmode = NOT_TAURIC
var/firstpickup = TRUE
var/pickupsound = TRUE
/obj/item/clothing/suit/space/hardsuit/rd/hev/no_sound
pickupsound = FALSE
/obj/item/clothing/suit/space/hardsuit/rd/hev/equipped(mob/user, slot)
. = ..()
if(!pickupsound)
return
if(!ishuman(user))
return
if(slot ==ITEM_SLOT_WEAR_SUIT)
if(!firstpickup)
SEND_SOUND(user, sound('hyperstation/sound/halflife/hevsuit_pickup.ogg', volume = 50))
else
firstpickup = FALSE
SEND_SOUND(user, sound('hyperstation/sound/halflife/hevsuit_firstpickup.ogg', volume = 50))
SEND_SOUND(user, sound('hyperstation/sound/halflife/anomalous_materials.ogg', volume = 50))
return
/obj/item/clothing/suit/space/hardsuit/shielded/goldenpa
name = "GATO Power Armor"
desc = "An advanced armor with built in energy shielding, developed by GATO via unknown means. It belongs by only few exclusive members of the corporation."
icon_state = "golden_pa"
item_state = "golden_pa"
max_charges = 4
current_charges = 4
recharge_delay = 15
armor = list("melee" = 80, "bullet" = 80, "laser" = 50, "energy" = 50, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/goldenpa
slowdown = 0
tauric = TRUE //Citadel Add for tauric hardsuits
/obj/item/clothing/suit/space/hardsuit/shielded/goldenpa/Initialize(mapload)
jetpack = new /obj/item/tank/jetpack/suit(src)
. = ..()
/obj/item/clothing/head/helmet/space/hardsuit/shielded/goldenpa
name = "GATO Power Helmet"
desc = "An advanced armor helmet with built in energy shielding, developed by GATO via unknown means. It belongs by only few exclusive members of the corporation."
icon_state = "hardsuit0-goldenpa"
item_state = "hardsuit0-goldenpa"
item_color = "goldenpa"
armor = list("melee" = 80, "bullet" = 80, "laser" = 50, "energy" = 50, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/suit/space/hardsuit/teslapa
name = "Tesla Power Armor"
desc = "An advanced power armor, with built-in tesla technology. You're sure this will fry whoever dares attack in close quarters."
icon_state = "tesla_pa"
item_state = "tesla_pa"
item_color = "tesla_pa"
armor = list("melee" = 70, "bullet" = 70, "laser" = 90, "energy" = 90, "bomb" = 70, "bio" = 100, "rad" = 40, "fire" = 100, "acid" = 100)
strip_delay = 300
equip_delay_self = 300
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/teslapahelmet
slowdown = 1
siemens_coefficient = -1
blood_overlay_type = "armor"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
hit_reaction_chance = 50
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
var/teslapa_cooldown = 20
var/teslapa_cooldown_duration = 10
var/tesla_power = 20000
var/tesla_range = 4
var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE
var/legacy = FALSE
var/legacy_dmg = 35
/obj/item/clothing/suit/space/hardsuit/teslapa/Initialize(mapload)
jetpack = new /obj/item/tank/jetpack/suit(src)
. = ..()
/obj/item/clothing/suit/space/hardsuit/teslapa/dropped(mob/user)
..()
if(istype(user))
user.flags_1 &= ~TESLA_IGNORE_1
/obj/item/clothing/suit/space/hardsuit/teslapa/equipped(mob/user, slot)
..()
if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
user.flags_1 |= TESLA_IGNORE_1
/obj/item/clothing/suit/space/hardsuit/teslapa/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(prob(hit_reaction_chance))
if(world.time < teslapa_cooldown_duration)
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(1, 1, src)
sparks.start()
owner.visible_message("<span class='danger'>The tesla capacitors on [owner]'s Tesla Power Armor are still recharging! The armor merely emits some sparks.</span>")
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out arcs of lightning!</span>")
if(!legacy)
tesla_zap(owner, tesla_range, tesla_power, tesla_flags)
else
for(var/mob/living/M in view(2, owner))
if(M == owner)
continue
owner.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
M.adjustFireLoss(legacy_dmg)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
teslapa_cooldown = world.time + teslapa_cooldown_duration
return TRUE
/obj/item/clothing/head/helmet/space/hardsuit/teslapahelmet
name = "Tesla Power Armor Helmet"
desc = "An advanced power armor, with built-in tesla technology. You're sure this will fry whoever dares attack in close quarters."
icon_state = "teslaup"
item_state = "teslaup"
armor = list("melee" = 70, "bullet" = 70, "laser" = 90, "energy" = 90, "bomb" = 70, "bio" = 100, "rad" = 10, "fire" = 100, "acid" = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/suit/space/hardsuit/advancedpa
name = "Advanced Power Armor"
desc = "An advanced power armor. You're sure this is near to impossible to penetrate in close quarters."
icon_state = "advanced_pa"
item_state = "advanced_pa"
item_color = "advanced_pa"
armor = list("melee" = 95, "bullet" = 95, "laser" = 70, "energy" = 80, "bomb" = 70, "bio" = 100, "rad" = 40, "fire" = 100, "acid" = 100)
strip_delay = 300 //chonky armor means chonky strip
equip_delay_self = 300
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/advancedpahelmet
slowdown = 0
blood_overlay_type = "armor"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
/obj/item/clothing/suit/space/hardsuit/advancedpa/Initialize(mapload)
jetpack = new /obj/item/tank/jetpack/suit(src)
. = ..()
/obj/item/clothing/head/helmet/space/hardsuit/advancedpahelmet
name = "Advanced Power Armor Helmet"
desc = "An advanced power armor. You're sure this is almost impenetrable in close quarters."
icon_state = "adv_pa"
item_state = "adv_pa"
armor = list("melee" = 95, "bullet" = 90, "laser" = 70, "energy" = 80, "bomb" = 70, "bio" = 100, "rad" = 40, "fire" = 100, "acid" = 100)
strip_delay = 300
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT

View File

@@ -0,0 +1,24 @@
/obj/item/clothing/suit/kaminacape
name = "Kamina's Cape"
desc = "Don't believe in yourself, dumbass. Believe in me. Believe in the Kamina who believes in you."
icon_state = "kaminacape"
item_state = "kaminacape"
body_parts_covered = 0
icon = 'hyperstation/icons/obj/clothing/suits.dmi'
alternate_worn_icon = 'hyperstation/icons/mobs/suits.dmi'
mutantrace_variation = NONE
/obj/item/clothing/suit/gcvest
name = "\improper Guncaster's Vest"
desc = "An open leather vest with battlescarred metal shoulderpads, perfect for hunting interdimensional wazards. Smells of gunpowder and plasma."
icon_state = "guncaster"
item_state = "guncaster"
icon = 'hyperstation/icons/obj/clothing/suits.dmi'
alternate_worn_icon = 'hyperstation/icons/mobs/suits.dmi'
mutantrace_variation = NONE
/obj/item/clothing/suit/gcvest/alt
name = "\improper Hellraider's Vest"
desc = "An open leather vest with battlescarred metal shoulderpads, discovered in a dimensional anomaly. Smells of gunpowder and plasma."
icon_state = "guncaster_alt"
item_state = "guncaster_alt"

View File

@@ -0,0 +1,9 @@
/obj/item/clothing/under/lumberjack
name = "lumberjack outfit"
desc = "I am a lumberjack and I am ok, I sleep all night and I work all day."
icon = 'hyperstation/icons/obj/clothing/suits.dmi'
alternate_worn_icon = 'hyperstation/icons/mobs/suits.dmi'
icon_state = "lumberjack"
item_state = "lumberjack"
can_adjust = FALSE
mutantrace_variation = NONE

View File

@@ -0,0 +1,29 @@
#define DUMPTIME 3000
/datum/bank_account
var/account_holder = "Some pleb"
var/account_balance = 0
var/account_offstation_balance = 0
var/account_pin = 0
var/account_dna = ""
var/datum/job/account_job
var/list/bank_cards = list()
var/add_to_accounts = TRUE
var/transferable = TRUE
var/account_id
var/withdrawDelay = 0
/datum/bank_account/New(newname, job)
if(add_to_accounts)
if(!SSeconomy)
log_world("Wack")
SSeconomy.bank_accounts += src
account_holder = newname
account_job = job
account_id = rand(111111,999999)
/datum/bank_account/Destroy()
if(add_to_accounts)
SSeconomy.bank_accounts -= src
return ..()

View File

@@ -0,0 +1,309 @@
/datum/round_event_control/crystalline_reentry
name = "Crystalline Asteroid"
typepath = /datum/round_event/crystalline_reentry
min_players = 15
max_occurrences = 5
var/atom/special_target
/datum/round_event_control/crystalline_reentry/admin_setup()
if(!check_rights(R_FUN))
return
var/aimed = alert("Aimed at current location?","Snipe", "Yes", "No")
if(aimed == "Yes")
special_target = get_turf(usr)
/datum/round_event/crystalline_reentry
announceWhen = 0
startWhen = 10
fakeable = FALSE
/datum/round_event/crystalline_reentry/announce(fake)
priority_announce("A crystalline asteroid has suffered a violent atmospheric entry. Brace for possible impact.", "General Alert")
/datum/round_event/crystalline_reentry/start()
var/datum/round_event_control/crystalline_reentry/C = control
var/startside = pick(GLOB.cardinals)
var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION))
var/turf/startT = spaceDebrisStartLoc(startside, z)
var/turf/endT = spaceDebrisFinishLoc(startside, z)
new /obj/effect/crystalline_reentry(startT, endT, C.special_target)
/datum/round_event_control/crystalline_wave
name = "Catastrophic Crystalline Asteroid Wave"
typepath = /datum/round_event/crystalline_wave
min_players = 35
max_occurrences = 0 //This is only an admin spawn. Ergo, wrath of the gods.
var/atom/special_target
/datum/round_event_control/crystalline_wave/admin_setup()
if(!check_rights(R_FUN))
return
/* No special target for you
var/aimed = alert("Aimed at current location?","Snipe", "Yes", "No")
if(aimed == "Yes")
special_target = get_turf(usr)
*/
var/randselect = pick("https://youtu.be/S0HTqqwZq-o","https://youtu.be/Liv4CvpMdRA","https://youtu.be/9XZyQ12qt7w")
message_admins("A crystalline asteroid wave has been triggered. Maybe you should add some music for the players? Consider this random selection: [randselect]")
/datum/round_event/crystalline_wave
announceWhen = 0
startWhen = 15
endWhen = 60 //45 seconds of pain
fakeable = FALSE
/datum/round_event/crystalline_wave/announce(fake)
priority_announce("Several crystalline asteroids have been detected en route with the station. All hands, brace for impact. Organic signals have been detected contained within some of the asteroids.", title = "Priority Alert", sound = 'sound/misc/voyalert.ogg')
/datum/round_event/crystalline_wave/tick()
if(ISMULTIPLE(activeFor, 3))
spawn_asteroids(rand(4,5)) // A looooot of asteroids...
/datum/round_event/crystalline_wave/proc/spawn_asteroids(number = 5)
var/datum/round_event_control/crystalline_reentry/C = control
for(var/i = 0; i < number; i++)
var/startside = pick(GLOB.cardinals)
var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION))
var/turf/startT = spaceDebrisStartLoc(startside, z)
var/turf/endT = spaceDebrisFinishLoc(startside, z)
new /obj/effect/crystalline_reentry/notendrilalert(startT, endT, C.special_target)
/obj/effect/crystalline_reentry
name = "dense ice asteroid"
desc = "Oh shit."
icon = 'icons/obj/meteor.dmi'
icon_state = "ice"
throwforce = 100
move_force = INFINITY
move_resist = INFINITY
pull_force = INFINITY
density = TRUE
anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/asteroidhealth = 150
var/z_original = 0
var/destination
var/notify = TRUE
var/tendrilnotify = TRUE
var/atom/special_target
var/dropamt = 5
var/droptype = list(/obj/item/stack/ore/bluespace_crystal)
var/meteorsound = 'sound/effects/meteorimpact.ogg'
/obj/effect/crystalline_reentry/New(atom/start, atom/end, aimed_at)
..()
SSaugury.register_doom(src, 2000)
z_original = z
destination = end
special_target = aimed_at
asteroidhealth = rand(150,300)
if(notify)
notify_ghosts("\A [src] is inbound!",
enter_link="<a href=?src=[REF(src)];orbit=1>(Click to orbit)</a>",
source=src, action=NOTIFY_ORBIT)
GLOB.poi_list += src
var/special_target_valid = FALSE
if(special_target)
var/turf/T = get_turf(special_target)
if(T.z == z_original)
special_target_valid = TRUE
if(special_target_valid)
walk_towards(src, special_target, 1)
else if(end && end.z==z_original)
walk_towards(src, destination, 1)
/obj/effect/crystalline_reentry/Topic(href, href_list)
if(href_list["orbit"])
var/mob/dead/observer/ghost = usr
if(istype(ghost))
ghost.ManualFollow(src)
/obj/effect/crystalline_reentry/Destroy()
GLOB.poi_list -= src
. = ..()
/obj/effect/crystalline_reentry/Moved()
if((z != z_original) || (loc == destination))
qdel(src)
if(special_target && loc == get_turf(special_target))
complete_trajectory()
return ..()
/obj/effect/crystalline_reentry/proc/complete_trajectory()
//We hit what we wanted to hit, time to go boom!
collision_effect()
/obj/effect/crystalline_reentry/ex_act(severity, target)
return FALSE
/obj/effect/crystalline_reentry/singularity_act()
return
/obj/effect/crystalline_reentry/singularity_pull()
return
/obj/effect/crystalline_reentry/Bump(atom/clong)
if(!special_target)//If it has a special target, THERE ARE NO BRAKES ON THE ADMINBUS, BABY
asteroidhealth = asteroidhealth - rand(7,14)
if(prob(10))
playsound(src, 'sound/effects/bang.ogg', 50, 1)
audible_message("<span class='danger'>You hear a BONK!</span>")
if(clong && prob(25))
x = clong.x
y = clong.y
if(special_target && clong == special_target)
complete_trajectory()
if(isturf(clong) || isobj(clong))
if(clong.density)
clong.ex_act(EXPLODE_HEAVY)
else if(isliving(clong))
penetrate(clong)
else if(istype(clong, type))
var/obj/effect/crystalline_reentry/other = clong
visible_message("<span class='danger'>[src] collides with [other]!\
</span>")
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(2, get_turf(src))
smoke.start()
qdel(src)
qdel(other)
if(asteroidhealth <= 0)
collision_effect()
else
atmos_spawn_air("water_vapor=75;TEMP=0") //brr
/obj/effect/crystalline_reentry/proc/penetrate(mob/living/L)
L.visible_message("<span class='danger'>[L] is smashed by a crystalline asteroid!</span>" , "<span class='userdanger'>The crystalline asteroid smashes you!</span>" , "<span class ='danger'>You hear a BONK!</span>")
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.adjustBruteLoss(160)
if(special_target && loc == get_turf(special_target)) // just in case. Otherwise the asteroid can stop if it penetrates someone that is standing exactly on that spot and that is bad
complete_trajectory()
/obj/effect/crystalline_reentry/proc/make_debris()
for(var/throws = dropamt, throws > 0, throws--)
var/thing_to_spawn = pick(droptype)
new thing_to_spawn(get_turf(src))
/obj/effect/crystalline_reentry/proc/collision_effect()
make_debris()
explosion(src.loc, 0, 0, 5, 3, 1, 0, 0, 0, 0)
var/sound/meteor_sound = sound(meteorsound)
var/random_frequency = get_rand_frequency()
for(var/mob/M in GLOB.player_list)
if((M.orbiting) && (SSaugury.watchers[M]))
continue
var/turf/T = get_turf(M)
if(!T || T.z != src.z)
continue
var/dist = get_dist(M.loc, src.loc)
shake_camera(M, dist > 20 ? 2 : 4, dist > 20 ? 1 : 3)
M.playsound_local(src.loc, null, 50, 1, random_frequency, 10, S = meteor_sound)
atmos_spawn_air("water_vapor=1250;TEMP=0") //brr
switch(rand(1,100))
if(1 to 30)
var/obj/structure/spawner/crystalline/M = new(src.loc)
visible_message("<span class='danger'>A [M] emerges from the asteroid's rubble!</span>")
if(prob(50) && tendrilnotify)
priority_announce("Unknown organic entities have been detected in the vincinity of [station_name()]. General caution is advised.", "General Alert")
if(31 to 99)
visible_message("The asteroid collapses into nothing...")
if(100)
var/mob/living/simple_animal/bot/hugbot/M = new(src.loc)
visible_message("<span class='danger'>A [M] emerges from the asteroid's rubble! Wait... What?</span>")
qdel(src)
/obj/effect/crystalline_reentry/notendrilalert
tendrilnotify = FALSE
/mob/living/simple_animal/hostile/asteroid/basilisk/tendril
fromtendril = TRUE
//Crystalline Tendrils, which spawn crystalline monsters
/obj/structure/spawner/crystalline
name = "crystalline tendril"
desc = "A vile tendril of corruption, originating from gods know where. Terrible monsters are pouring out of it."
icon = 'icons/mob/nest.dmi'
icon_state = "tendril"
faction = list("mining")
max_mobs = 3
max_integrity = 9000 // Don't worry, the value is normalized within Initialize
obj_integrity = 9000 // Same as above
mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk/tendril)
move_resist = INFINITY // just killing it tears a massive hole in the ground, let's not move it
anchored = TRUE
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | LAVA_PROOF
var/gps = null
var/obj/effect/light_emitter/tendril/emitted_light
/obj/structure/spawner/crystalline/Initialize(mapload)
. = ..()
emitted_light = new(loc)
for(var/F in RANGE_TURFS(1, src))
if(iswallturf(F))
var/turf/closed/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
if(iscloudturf(F))
var/turf/open/chasm/cloud/M = F
M.TerraformTurf(/turf/open/floor/plating/asteroid/layenia, /turf/open/floor/plating/asteroid/layenia)
gps = new /obj/item/gps/internal(src)
addtimer(CALLBACK(src,PROC_REF(delayedInitialize)), 4 SECONDS)
/obj/structure/spawner/crystalline/deconstruct(disassembled)
new /obj/effect/cloud_collapse(loc)
new /obj/structure/closet/crate/necropolis/tendril(loc)
return ..()
/obj/structure/spawner/crystalline/Destroy()
QDEL_NULL(emitted_light)
QDEL_NULL(gps)
return ..()
/obj/structure/spawner/crystalline/proc/delayedInitialize()
//Why is this needed? Simple, because apparently explosion is so slow that it triggers after the spawner spawns and kills it on the spot. This just makes it killable.
resistance_flags = FIRE_PROOF | LAVA_PROOF
max_integrity = 225
obj_integrity = 225
/obj/effect/light_emitter/crystalline
set_luminosity = 4
set_cap = 2.5
light_color = LIGHT_COLOR_LIGHT_CYAN
/obj/effect/cloud_collapse
name = "collapsing crystalline tendril"
desc = "Get clear!"
layer = TABLE_LAYER
icon = 'icons/mob/nest.dmi'
icon_state = "tendril"
anchored = TRUE
density = TRUE
var/obj/effect/light_emitter/crystalline/emitted_light
/obj/effect/cloud_collapse/Initialize(mapload)
. = ..()
emitted_light = new(loc)
visible_message("<span class='boldannounce'>The tendril writhes in fury as the earth around it begins to crack and break apart! Get back!</span>")
visible_message("<span class='warning'>Something falls free of the tendril!</span>")
playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, 0, 50, 1, 1)
addtimer(CALLBACK(src,PROC_REF(collapse)), 50)
/obj/effect/cloud_collapse/Destroy()
QDEL_NULL(emitted_light)
return ..()
/obj/effect/cloud_collapse/proc/collapse()
for(var/mob/M in range(7,src))
shake_camera(M, 15, 1)
playsound(get_turf(src),'sound/effects/explosionfar.ogg', 200, 1)
visible_message("<span class='boldannounce'>The tendril falls into the clouds below!</span>")
for(var/turf/T in range(1,src))
if(!T.density)
T.TerraformTurf(/turf/open/chasm/cloud, /turf/open/chasm/cloud)
qdel(src)

View File

@@ -0,0 +1,5 @@
/datum/chemical_reaction/pilk
name = "Pilk"
id = /datum/reagent/consumable/pilk
results = list(/datum/reagent/consumable/pilk = 2)
required_reagents = list(/datum/reagent/consumable/milk = 1, /datum/reagent/consumable/space_cola = 1)

View File

@@ -0,0 +1,80 @@
/* Doesnt fucking work, dont know why, everything I add in this game has some kinda of issue.
/obj/item/integrated_circuit/input/gmeasurement
name = "body measurement"
desc = "Used to get a measurement of a refs genitals size and body size."
icon_state = "medscan"
complexity = 5
extended_desc = "Upon activation, the circuit will attempt to measure all body parts on the refs body within one tile away."
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"penis length" = IC_PINTYPE_NUMBER,
"breast size" = IC_PINTYPE_NUMBER,
"testicle size" = IC_PINTYPE_NUMBER,
"body size" = IC_PINTYPE_NUMBER
)
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 40
cooldown_per_use = 20
ext_cooldown = 25
/obj/item/integrated_circuit/input/gmeasurement/do_work()
var/mob/living/L = get_pin_data_as_type(IC_INPUT, 1, /mob/living)
if(!istype(L) || !L.Adjacent(get_turf(src)) ) //Invalid input
return
var/obj/item/organ/genital/penis/P = L.getorganslot("penis")
var/obj/item/organ/genital/breasts/B = L.getorganslot("breasts")
var/obj/item/organ/genital/testicles/T = L.getorganslot("testicles")
//reset data, just incase they dont have that genitle
set_pin_data(IC_OUTPUT, 1, 0)
set_pin_data(IC_OUTPUT, 2, 0)
set_pin_data(IC_OUTPUT, 3, 0)
set_pin_data(IC_OUTPUT, 4, 0)
//get sizes
set_pin_data(IC_OUTPUT, 1, P.length)
set_pin_data(IC_OUTPUT, 2, B.cached_size)
set_pin_data(IC_OUTPUT, 3, T.cached_size )
set_pin_data(IC_OUTPUT, 4, L.size_multiplier*100)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/pregtest
name = "pregnancy tester"
desc = "A circuit used to determine whether someone is pregnant or not and if they possess the ability to be impregnated."
icon_state = "medscan"
complexity = 5
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"is pregnant" = IC_PINTYPE_BOOLEAN,
"breedable" = IC_PINTYPE_BOOLEAN
)
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 40
cooldown_per_use = 20
ext_cooldown = 25
/obj/item/integrated_circuit/input/pregtest/do_work()
var/mob/living/L = get_pin_data_as_type(IC_INPUT, 1, /mob/living)
if(!istype(L) || !L.Adjacent(get_turf(src)) ) //Invalid input
return
var/obj/item/organ/genital/womb/W = L.getorganslot("womb")
set_pin_data(IC_OUTPUT, 1, null)
set_pin_data(IC_OUTPUT, 2, null)
set_pin_data(IC_OUTPUT, 1, W.pregnant)
set_pin_data(IC_OUTPUT, 2, L.breedable)
push_data()
activate_pin(2)
*/

View File

@@ -0,0 +1,13 @@
/*
Roleplay Jobs, Currently borked.
/datum/job/rpcentral
title = "Central Command Inspector"
faction = "Station"
total_positions = 1
spawn_positions = 1
minimal_player_age = 1
supervisors = "central command"
selection_color = "#ffeef0"
custom_spawn_text = "You are from central command doing a routine inspection of the station, please fill out the provided information and submit it to central command by the end of the shift."
*/

View File

@@ -0,0 +1,8 @@
// yes, I COULD make it a seperate object from the surv capsule but the code needed is indeticle soo...
/obj/item/survivalcapsule/reactor // the not-so-survival capsule
name = "RMBK Reactor Beacon"
desc = "A special bluespace beacon designed to implement a reactor into the hull of the ship or station that it is activated on."
icon = 'icons/obj/device.dmi'
icon_state = "beacon"
template_id = "reactor"

View File

@@ -0,0 +1,7 @@
// yes, I COULD make it a seperate object from the surv capsule but the code needed is indeticle soo...
/datum/map_template/shelter/reactor
name = "RBMK Reactor"
shelter_id = "reactor"
description = "A reactor core, coolant and moderator loop not included."
mappath = "_maps/templates/reactor_1.dmm"

View File

@@ -0,0 +1,163 @@
/*
COSMETIC PARTS
this system allows you to change the _base_ appearance of a limb independent
of species or markings. this, for example, allows us to create "hybrids" like a
mammal with avian legs.
keep in mind that this does not change the species of a leg! in the above example,
the mammal's bird-legs are still mammal legs. this matters in some places, like
body part transplants; mis-matched species will cause extra damage if the surgery
fails and the part is rejected. so you can't attach mammal-bird legs to avians
safely.
*/
/datum/cosmetic_part
/** A unique string that is used to identify this part for save files. Allows name changes without breaking saves */
var/id
/** The name of the cosmetic part. This shows up in the preferences dropdown. */
var/name
var/icon = 'hyperstation/icons/mob/char_parts.dmi'
var/icon_state
/** How colors are determined for this part. MUTCOLORS for base color, MATRIXED to allow multiple channels. */
var/color_src = MUTCOLORS
/** Whether or not this cosmetic part has an alternate form for digitigrade legs. */
var/support_digitigrade = TRUE
/**
WE
HATE
GENDER!!!!!!!!!!
*/
var/support_gender = null
/** Species IDs that support this cosmetic part. Bypassed with "show mismatched markings" option. */
var/list/supported_species
/datum/cosmetic_part/head
/datum/cosmetic_part/chest
/datum/cosmetic_part/arms
/datum/cosmetic_part/legs
// HEADS
// =========================================
/datum/cosmetic_part/head/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/head/ipc_round
id = "ipc_round"
name = "round ipc head"
icon_state = "ipc_round"
supported_species = list("ipc")
support_gender = FALSE
// CHESTS
// =========================================
/datum/cosmetic_part/chest/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/chest/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc chest"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
support_gender = FALSE
/datum/cosmetic_part/chest/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc chest"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
support_gender = FALSE
// ARMS
// =========================================
/datum/cosmetic_part/arms/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/arms/avian_alt
id = "avian_alt"
name = "avian claws"
icon_state = "avian_alt"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
/datum/cosmetic_part/arms/insect
id = "insect"
name = "insect arms"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "insect"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
/datum/cosmetic_part/arms/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc arms"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
/datum/cosmetic_part/arms/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc arms"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
// LEGS
// =========================================
/datum/cosmetic_part/legs/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/legs/avian
id = "avian"
name = "avian legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "avian"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = FALSE
/datum/cosmetic_part/legs/mammal
id = "mammal"
name = "mammal legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "mammal"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = TRUE
/datum/cosmetic_part/legs/insect
id = "insect"
name = "insect legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "insect"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = TRUE
/datum/cosmetic_part/legs/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc legs"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
support_digitigrade = FALSE
/datum/cosmetic_part/legs/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc legs"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
support_digitigrade = FALSE

View File

@@ -0,0 +1,575 @@
/*
from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
/datum/sprite_accessory
var/extra = FALSE
var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
var/extra2 = FALSE
var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
var/extra2_color_src = MUTCOLORS3
var/list/ckeys_allowed
we use the "citadel" versions of mutant/species parts, which usually (but not always)
begins with "mam_" somewhere. stuff that's built for only humans/lizards in other parts
of the code are from TG, don't use those.
keep everything in alphabetical order, please!
*/
// TODO: code it so that we don't have to type in "icon = 'hyperstation/icons/mob/etc'"
// manually for hyperstation parts
/*
SNOUTS
==========================================================
*/
/datum/sprite_accessory/mam_snouts/bigmandible // sarcoph @ hyperstation, march 2022
name = "Big Mandibles (Hyper)"
icon_state = "bigmandible"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/proboscis // sarcoph @ hyperstation, march 2022
name = "Proboscis (Hyper)"
icon_state = "proboscis"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/rhinobeetle // sarcoph @ hyperstation, march 2022
name = "Rhino Beetle (Hyper)"
icon_state = "rhinobeetle"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/scarab // sarcoph @ hyperstation, march 2022
name = "Scarab Beetle (Hyper)"
icon_state = "scarab"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/smallmandible // sarcoph @ hyperstation, march 2022
name = "Small Mandibles (Hyper)"
icon_state = "smallmandible"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/spider // sarcoph @ hyperstation, march 2022
name = "Spider (Hyper)"
icon_state = "spider"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/tarantula // sarcoph @ hyperstation, march 2022
name = "Tarantula (Hyper)"
icon_state = "tarantula"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_snouts/easterndragon
name = "Eastern Dragon (Hyper)"
icon_state = "easterndw"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/feasterndragon
name = "Eastern Dragon (Top) (Hyper)"
icon_state = "feasterndw"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/easterndragonnowhiskers
name = "Eastern Dragon - No Whiskers (Hyper)"
icon_state = "easterndnw"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/feasterndragonnowhiskers
name = "Eastern Dragon - No Whiskers (Top) (Hyper)"
icon_state = "feasterndnw"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/knshuttle // Dahlular and Arcstaisia @ hyperstation, april 2022. Feel free to remove comment. Just remember this is snowflakey Kinaris stuff.
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/fchemlight
name = "RadDog (Top) (Hyper)"
icon_state = "fchemlight"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/chemlight
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/pinata
name = "pinata (Hyper)"
icon_state = "pinata"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/datum/sprite_accessory/mam_snouts/pinatasmile
name = "pinata Smile (Hyper)"
icon_state = "pinatasmile"
icon = 'hyperstation/icons/mob/char_snouts.dmi'
/*
EARS
==========================================================
*/
/datum/sprite_accessory/mam_ears/faceant // sarcoph @ hyperstation, march 2022
name = "Face Antennae (Hyper)"
icon_state = "faceant"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/faceant2 // sarcoph @ hyperstation, march 2022
name = "Face Antennae 2 (Hyper)"
icon_state = "faceant2"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/moth
name = "Moth Antennae (Hyper)"
icon_state = "moth"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/plumeant // sarcoph @ hyperstation, march 2022
name = "Plume Antennae (Hyper)"
icon_state = "plumeant"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/roundant // sarcoph @ hyperstation, march 2022
name = "Round Antennae (Hyper)"
icon_state = "roundant"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/thinant // sarcoph @ hyperstation, march 2022
name = "Thin Antennae (Hyper)"
icon_state = "thinant"
icon = 'hyperstation/icons/mob/char_ears.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_ears/easterndragon
name = "Eastern Dragon (Hyper)"
icon_state = "easternd"
icon = 'hyperstation/icons/mob/char_ears.dmi'
/datum/sprite_accessory/mam_ears/knshuttle // Dahlular and Arcstaisia @ hyperstation, april 2022. Feel free to remove comment. Just remember this is snowflakey Kinaris stuff.
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_ears.dmi'
/datum/sprite_accessory/mam_ears/chemlight
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_ears.dmi'
/*
WINGS
==========================================================
*/
/datum/sprite_accessory/deco_wings/beetle // sarcoph @ hyperstation, march 2022
name = "Beetle (Hyper)"
icon_state = "beetle"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/moth_wings/beetle
name = "Beetle (Hyper)"
icon_state = "beetle"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/beetle2 // sarcoph @ hyperstation, march 2022
name = "Beetle - 2-toned (Hyper)"
icon_state = "beetle2"
icon = 'hyperstation/icons/mob/char_wings.dmi'
color_src = MATRIXED
/datum/sprite_accessory/moth_wings/beetle2
name = "Beetle - 2-toned (Hyper)"
icon_state = "beetle2"
icon = 'hyperstation/icons/mob/char_wings.dmi'
color_src = MATRIXED
/datum/sprite_accessory/deco_wings/insect // sarcoph @ hyperstation, march 2022
name = "Insect (Hyper)"
icon_state = "insect"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/moth_wings/insect
name = "Insect (Hyper)"
icon_state = "insect"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/knshuttle // Dahlular and Arcstaisia @ hyperstation, april 2022. Feel free to remove comment. Just remember this is snowflakey Kinaris stuff.
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_wings.dmi'
//recommended_species = list("synthliz") need to give synths a deco wing slot
color_src = MATRIXED
/datum/sprite_accessory/deco_wings/minibat // sarcoph @ hyperstation, march 2022
name = "Mini Bat (Hyper)"
icon_state = "minibat"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/minifeather // sarcoph @ hyperstation, march 2022
name = "Mini Feather (Hyper)"
icon_state = "minifeather"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/tinybat // sarcoph @ hyperstation, march 2022
name = "Tiny Bat (Hyper)"
icon_state = "tinybat"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/tinyfeather // sarcoph @ hyperstation, march 2022
name = "Tiny Feather (Hyper)"
icon_state = "tinyfeather"
icon = 'hyperstation/icons/mob/char_wings.dmi'
/datum/sprite_accessory/deco_wings/sylveon // Aphast @ hyperstation, november 2022
name = "Sylveon Ribbons"
icon_state = "sylveon_bow"
icon = 'hyperstation/icons/mob/char_wings.dmi'
color_src = MATRIXED
/datum/sprite_accessory/horns/sylveon // Aphast @ hyperstation, november 2022, best place to put this due to being a pair and no horn slots here
name = "Sylveon Bow"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "sylveon_bow"
color_src = MATRIXED
/*
TAILS + ANIMATED TAILS
==========================================================
*/
/datum/sprite_accessory/mam_tails/bee // sarcoph @ hyperstation, march 2022
name = "Bee (Hyper)"
icon_state = "bee"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails_animated/bee
name = "Bee (Hyper)"
icon_state = "bee"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails/bee2 // sarcoph @ hyperstation, march 2022
name = "Bee w/ Stinger (Hyper)"
icon_state = "bee2"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails_animated/bee2
name = "Bee w/ Stinger (Hyper)"
icon_state = "bee2"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
// "fan" bird tail, short
/datum/sprite_accessory/mam_tails/shorthawk // sarcoph @ hyperstation, jan 2022
name = "Hawk - Short (Hyper)"
icon_state = "shorthawk"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/shorthawk
name = "Hawk - Short (Hyper)"
icon_state = "shorthawk"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails/insect // sarcoph @ hyperstation, march 2022
name = "Insect (Hyper)"
icon_state = "insect"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails_animated/insect
name = "Insect (Hyper)"
icon_state = "insect"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails/bug2tone // sarcoph @ hyperstation, march 2022
name = "Insect - 2-tone (Hyper)"
icon_state = "bug2tone"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_tails_animated/bug2tone
name = "Insect - 2-tone (Hyper)"
icon_state = "bug2tone"
icon = 'hyperstation/icons/mob/char_tails.dmi'
recommended_species = list("insect")
// "narrow" bird tail, long
/datum/sprite_accessory/mam_tails/longpigeon // sarcoph @ hyperstation, jan 2022
name = "Pigeon - Long (Hyper)"
icon_state = "longpigeon"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/longpigeon
name = "Pigeon - Long (Hyper)"
icon_state = "longpigeon"
icon = 'hyperstation/icons/mob/char_tails.dmi'
// "narrow" bird tail, short
/datum/sprite_accessory/mam_tails/shortpigeon // sarcoph @ hyperstation, jan 2022
name = "Pigeon - Short (Hyper)"
icon_state = "shortpigeon"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/shortpigeon
name = "Pigeon - Short (Hyper)"
icon_state = "shortpigeon"
icon = 'hyperstation/icons/mob/char_tails.dmi'
// "forked" bird tail, long
/datum/sprite_accessory/mam_tails/swallow // sarcoph @ hyperstation, jan 2022
name = "Swallow (Hyper)"
icon_state = "swallow"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/swallow
name = "Swallow (Hyper)"
icon_state = "swallow"
icon = 'hyperstation/icons/mob/char_tails.dmi'
// forked bird tail, long; special stripe markings
/datum/sprite_accessory/mam_tails/swallowstriped // sarcoph @ hyperstation, jan 2022
name = "Swallow - Striped (Hyper)"
icon_state = "swallowstriped"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/swallowstriped
name = "Swallow - Striped (Hyper)"
icon_state = "swallowstriped"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails/easterndragon //Pulled base from Virgo, seriously love the server and love you guys, stay lovely.
name = "Eastern Dragon (Hyper)"
icon_state = "easternd"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/easterndragon
name = "Eastern Dragon (Hyper)"
icon_state = "easternd"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails/knshuttle // Dahlular and Arcstaisia @ hyperstation, april 2022. Feel free to remove comment. Just remember this is snowflakey Kinaris stuff.
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/knshuttle
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails/chemlight
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/chemlight
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_tails.dmi'
/*
BODY MARKINGS
==========================================================
*/
/*
from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
/datum/sprite_accessory/mam_body_markings
extra = FALSE
extra2 = FALSE
color_src = MATRIXED
gender_specific = 0
icon = 'modular_citadel/icons/mob/mam_markings.dmi'
recommended_species = list("mammal", "xeno", "slimeperson", "podweak", "avian", "aquatic")
*/
/datum/sprite_accessory/mam_body_markings/bee // sarcoph @ hyperstation, march 2022
name = "Bee (Hyper)"
icon_state = "bee"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_body_markings/bee_fluff // sarcoph @ hyperstation, march 2022
name = "Bee - Fluffy (Hyper)"
icon_state = "bee_fluff"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_body_markings/bug3tone // sarcoph @ hyperstation, march 2022
name = "Beetle - 3-tone (Hyper)"
icon_state = "bug3tone"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_body_markings/moth // sarcoph @ hyperstation, jan 2022
name = "Moth (Hyper)"
icon_state = "moth"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("insect")
/datum/sprite_accessory/mam_body_markings/empty
name = "None (Hyper)"
icon_state = "empty"
recommended_species = list("podweak", /*"mammal",*/ "avian", "aquatic", "insect", "xeno", "synthliz", "slimeperson")
// mammals are cursed to no empty markings until they get their heads fixed.
/datum/sprite_accessory/mam_body_markings/pigeon // sarcoph @ hyperstation, jan 2022
name = "Pigeon (Hyper)"
icon_state = "pigeon"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("avian")
/datum/sprite_accessory/mam_body_markings/shrike // sarcoph @ hyperstation, jan 2022
name = "Shrike (Hyper)"
icon_state = "shrike"
icon = 'hyperstation/icons/mob/char_markings.dmi'
recommended_species = list("avian")
/datum/sprite_accessory/mam_body_markings/easterndragon
name = "Eastern Dragon (Hyper)"
icon_state = "easternd"
icon = 'hyperstation/icons/mob/char_markings.dmi'
/datum/sprite_accessory/mam_body_markings/knshuttle // Dahlular and Arcstaisia @ hyperstation, april 2022. Feel free to remove comment. Just remember this is snowflakey Kinaris stuff.
name = "Kinaris - Shuttle (Hyper)"
icon_state = "knshuttle"
icon = 'hyperstation/icons/mob/char_markings.dmi'
//doged was here
/datum/sprite_accessory/mam_body_markings/chemlight
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_markings.dmi'
//racc do a code maybe it won't explode
/datum/sprite_accessory/mam_body_markings/raccalt
name = "RaccAlt (Hyper)"
icon_state = "raccalt"
icon = 'hyperstation/icons/mob/char_markings.dmi'
/datum/sprite_accessory/mam_body_markings/pinata
name = "pinata (Hyper)"
icon_state = "pinata"
icon = 'hyperstation/icons/mob/char_markings.dmi'
/*
TAUR BODIES
==========================================================
*/
/*
from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
/datum/sprite_accessory/taur
icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra = TRUE
extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra2 = TRUE
center = TRUE
dimension_x = 64
var/taur_mode = NOT_TAURIC
color_src = MATRIXED
recommended_species = list("human", "lizard", "insect", "mammal", "xeno", "jelly", "slimeperson", "podweak", "avian", "aquatic")
*/
/datum/sprite_accessory/taur/chemnaga //Chemlight experimental sprites for future spriting
name = "RadDog Naga (Hyper)"
icon_state = "chemnaga"
taur_mode = SNEK_TAURIC
ckeys_allowed = list("chemlight")
/datum/sprite_accessory/taur/chemlight
name = "RadDog Taur (Hyper)"
icon_state = "chemlight"
taur_mode = PAW_TAURIC
ckeys_allowed = list("chemlight")
/*
IPCS
==========================================================
*/
/*
from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
/datum/sprite_accessory/antenna
icon = 'modular_citadel/icons/mob/ipc_antennas.dmi'
color_src = MUTCOLORS3
recommended_species = list("ipc")
/datum/sprite_accessory/screen
icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
color_src = null
*/
/datum/sprite_accessory/antenna/idog_down
name = "Dog, down (Hyper)"
icon_state = "idog_down"
color_src = MATRIXED
/datum/sprite_accessory/antenna/idog_up
name = "Dog, up (Hyper)"
icon_state = "idog_up"
color_src = MATRIXED
/datum/sprite_accessory/antenna/headset
name = "Headphones (Hyper)"
icon_state = "headset"
color_src = MATRIXED
/datum/sprite_accessory/antenna/aquatic
name = "Fins (Hyper)"
icon_state = "aquatic"
color_src = MATRIXED
/datum/sprite_accessory/screen/ghost
name = "Ghost (Hyper)"
icon_state = "ghost"
/datum/sprite_accessory/screen/heartbeat
name = "Heartbeat (Hyper)"
icon_state = "heartbeat"
/datum/sprite_accessory/screen/ocean
name = "Ocean (Hyper)"
icon_state = "ocean"
/datum/sprite_accessory/antenna/catears
name = "Pointy Ears (Hyper)"
icon_state = "catears"
color_src = MATRIXED
/datum/sprite_accessory/screen/valley
name = "Valley (Hyper)"
icon_state = "valley"
/*
BEARDS
==========================================================
*/
/*
/datum/sprite_accessory/facial_hair
icon = 'icons/mob/human_face.dmi'
gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P)
*/
/datum/sprite_accessory/facial_hair/mane
name = "Neckfluff (Hyper)"
icon_state = "facial_neckfluff"

View File

@@ -0,0 +1,3 @@
//This file is empty right now, but leaves room for people to put shit here in the future for those who are lazy
/mob/living/silicon/robot
var/datum/action/cyborg_small_sprite/small_sprite_action //This gets replaced every time the cyborg changes modules --Cyanosis

View File

@@ -0,0 +1,18 @@
//This file is empty right now, but leaves room for people to put shit here in the future for those who are lazy
//This proc gets called whenever a new robot module is being applied --Cyanosis
/obj/item/robot_module/proc/handle_sprite_action(mob/living/silicon/robot/R, is_huge = FALSE)
ASSERT(istype(R))
if(R.small_sprite_action)
QDEL_NULL(R.small_sprite_action)
if(!is_huge) //only from the expander upgrade. The borg won't have an action if they don't have the expander upgrade
return
for(var/P in typesof(/datum/action/cyborg_small_sprite))
var/datum/action/cyborg_small_sprite/action = P
if(initial(action.designated_module) == name)
R.small_sprite_action = new action()
R.small_sprite_action.Grant(R)
break
if(!R.small_sprite_action)
R.small_sprite_action = new()
R.small_sprite_action.Grant(R)

View File

@@ -0,0 +1,51 @@
//Ported from virgo, with some touch ups to make it work with our code.
/mob/living
var/list/status_indicators = null // Will become a list as needed.
/mob/living/proc/add_status_indicator(mutable_appearance/thing)
if(get_status_indicator(thing))
return
if(!istype(thing, /mutable_appearance))
thing = mutable_appearance('hyperstation/icons/mob/status_indicators.dmi', icon_state = thing)
LAZYADD(status_indicators, thing)
handle_status_indicators()
/mob/living/proc/remove_status_indicator(mutable_appearance/thing)
thing = get_status_indicator(thing)
cut_overlay(thing)
LAZYREMOVE(status_indicators, thing)
handle_status_indicators()
/mob/living/proc/get_status_indicator(mutable_appearance/thing)
if(!istype(thing, /mutable_appearance))
for(var/mutable_appearance/I in status_indicators)
if(I.icon_state == thing)
return I
return LAZYACCESS(status_indicators, LAZYFIND(status_indicators, thing))
/mob/living/proc/handle_status_indicators()
// First, get rid of all the overlays.
for(var/thing in status_indicators)
cut_overlay(thing)
if(!LAZYLEN(status_indicators))
return
if(stat == DEAD)
return
// Now the indicator row can actually be built.
for(var/thing in status_indicators)
var/mutable_appearance/I = thing
I.appearance_flags = PIXEL_SCALE|KEEP_APART
I.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
I.plane = HUD_PLANE
I.layer = ABOVE_FLY_LAYER
I.pixel_y = 18
I.pixel_x = 18
add_overlay(I)

View File

@@ -0,0 +1,29 @@
mob/proc/checkloadappearance()
var/mob/living/carbon/human/H = src
//This will be where the person gets to select their appearance instead of the random character
if (world.time <= (H.time_initialized + 900) && H.mirrorcanloadappearance == TRUE)
SEND_SOUND(H, 'sound/misc/server-ready.ogg')
to_chat(H, "<span class='boldannounce'>This ghost role allows you to select your loaded character's appearance. Make sure you have your ID in your ID slot, if you have one.</span>")
if(alert(H, "Would you like to load your currently loaded character's appearance?", "This can only be done up until 90s after you spawn.", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900))
if(alert(H, "You should only load a character that has not currently died in the round. Do you accept this?", "Warning", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900))
H.client?.prefs?.copy_to(H)
if (H.custom_body_size) //Do they have a custom size set?
H.resize(H.custom_body_size * 0.01)
H.real_name = H.client?.prefs?.real_name
H.mind.name = H.real_name //Makes sure to change their mind name to their real name.
SSquirks.AssignQuirks(H, H.client, TRUE, FALSE, H.job, FALSE)//This Assigns the selected character's quirks
H.dna.update_dna_identity() //This makes sure their DNA is updated.
var/obj/item/card/id/idCard = H.get_idcard() //Time to change their ID card as well if they have one.
if (idCard != null)
idCard.update_label(H.real_name, idCard.assignment)
idCard.registered_name = H.real_name
H.mirrorcanloadappearance = FALSE //Prevents them from using the mirror again.
ADD_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS,GHOSTROLE_TRAIT) //Makes sure they are exempt from health events.
SEND_SOUND(H, 'sound/magic/charge.ogg') //Fluff
to_chat(H, "<span class='boldannounce'>Your head aches for a second. You feel like this is how things should have been.</span>")
log_game("[key_name(H)] has loaded their default appearance for a ghost role.")
message_admins("[ADMIN_LOOKUPFLW(H)] has loaded their default appearance for a ghost role.")
return
else
to_chat(H, "<span class='boldannounce'>You either took too long or chose not to change. Alrighty. Remember, you have 90 seconds from spawn to get to a mirror and still do it if you wish.</span>")
return

View File

@@ -0,0 +1,15 @@
#define PATREONFILE "[global.config.directory]/patreons.txt"
GLOBAL_LIST_EMPTY(patreons)
/proc/load_patreons()
GLOB.patreons = list()
for(var/line in world.file2list(PATREONFILE))
if(!line)
continue
GLOB.patreons += ckey(line)
/proc/check_patreons(var/ckey)
if(!GLOB.patreons)
return FALSE
. = (ckey in GLOB.patreons)

View File

@@ -0,0 +1,45 @@
/obj/item/pen/attack(mob/living/M, mob/user,stealth)
if(!istype(M))
return
if(!force)
if(M.can_inject(user, 1))
if(user.a_intent == "harm") //old poke requires harm intent.
to_chat(user, "<span class='warning'>You stab [M] with the pen.</span>")
if(!stealth)
to_chat(M, "<span class='danger'>You feel a tiny prick!</span>")
. = 1
else //writing time
var/mob/living/carbon/human/T = M
if(!T) //not human.
return
if(!T.is_chest_exposed())
to_chat(user, "<span class='warning'>You cannot write on someone with their clothes on.</span>")
return
var/writting = input(user, "Add writing, doesn't replace current text", "Writing on [T]") as text|null
if(!writting)
return
var/obj/item/bodypart/BP = T.get_bodypart(user.zone_selected)
if(!(user==T))
src.visible_message("<span class='notice'>[user] begins to write on [T]'s [BP.name].</span>")
else
to_chat(user, "<span class='notice'>You begin to write on your [BP.name].</span>")
if(do_mob(user, T, 4 SECONDS))
if((length(BP.writtentext))+(length(writting)) < 100) //100 character limmit to stop spamming.
BP.writtentext += html_encode(writting) //you can add to text, not remove it.
else
to_chat(user, "<span class='notice'>There isnt enough space to write that on [T]'s [BP.name].</span>")
return
if(!(user==T))
to_chat(user, "<span class='notice'>You write on [T]'s [BP.name].</span>")
else
to_chat(user, "<span class='notice'>You write on your [BP.name].</span>")
else
. = ..()

View File

@@ -0,0 +1,229 @@
/obj/item/twohanded/required/fuel_rod
var/rad_strength = 500
var/half_life = 2000 // how many depletion ticks are needed to half the fuel_power (1 tick = 1 second)
var/time_created = 0
var/og_fuel_power = 0.20 //the original fuel power value
var/process = FALSE
// The depletion where depletion_final() will be called (and does something)
var/depletion_threshold = 100
// How fast this rod will deplete
var/depletion_speed_modifier = 1
var/depleted_final = FALSE // depletion_final should run only once
var/depletion_conversion_type = "plutonium"
/obj/item/twohanded/required/fuel_rod/Initialize(mapload)
. = ..()
time_created = world.time
AddComponent(/datum/component/radioactive, rad_strength, src) // This should be temporary for it won't make rads go lower than 350
if(process)
START_PROCESSING(SSobj, src)
/obj/item/twohanded/required/fuel_rod/Destroy()
if(process)
STOP_PROCESSING(SSobj, src)
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/N = loc
if(istype(N))
N.fuel_rods -= src
. = ..()
// This proc will try to convert your fuel rod if you don't override this proc
// So, ideally, you should write an override of this for every fuel rod you want to create
/obj/item/twohanded/required/fuel_rod/proc/depletion_final(result_rod = "")
if(result_rod)
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/N = loc
// Rod conversion is moot when you can't find the reactor
if(istype(N))
var/obj/item/twohanded/required/fuel_rod/R
// You can add your own depletion scheme and not override this proc if you are going to convert a fuel rod into another type
switch(result_rod)
if("plutonium")
R = new /obj/item/twohanded/required/fuel_rod/plutonium(loc)
R.depletion = depletion
if("depleted")
if(fuel_power < 10)
fuel_power = 0
playsound(loc, 'sound/effects/supermatter.ogg', 100, TRUE)
R = new /obj/item/twohanded/required/fuel_rod/depleted(loc)
R.depletion = depletion
// Finalization of conversion
if(istype(R))
N.fuel_rods += R
qdel(src)
else
depleted_final = FALSE // Maybe try again later?
/obj/item/twohanded/required/fuel_rod/deplete(amount=0.035) // override for the one in rmbk.dm
depletion += amount * depletion_speed_modifier
if(depletion >= depletion_threshold && !depleted_final)
depleted_final = TRUE
depletion_final(depletion_conversion_type)
/obj/item/twohanded/required/fuel_rod/plutonium
fuel_power = 0.20
name = "Plutonium-239 Fuel Rod"
desc = "A highly energetic titanium sheathed rod containing a sizeable measure of weapons grade plutonium, it's highly efficient as nuclear fuel, but will cause the reaction to get out of control if not properly utilised."
icon_state = "inferior"
rad_strength = 1500
process = TRUE // for half life code
depletion_threshold = 300
depletion_conversion_type = "depleted"
/obj/item/twohanded/required/fuel_rod/plutonium/process()
fuel_power = og_fuel_power * 0.5**((world.time - time_created) / half_life SECONDS) // halves the fuel power every half life (33 minutes)
/obj/item/twohanded/required/fuel_rod/depleted
name = "Depleted Fuel Rod"
desc = "A highly radioactive fuel rod which has expended most of it's useful energy."
icon_state = "normal"
rad_strength = 6000 // smelly
depletion_conversion_type = "" // It means that it won't turn into anything
// Master type for material optional (or requiring, wyci) and/or producing rods
/obj/item/twohanded/required/fuel_rod/material
// Whether the rod has been harvested. Should be set in expend().
var/expended = FALSE
// The material that will be inserted and then multiplied (or not). Should be some sort of /obj/item/stack
var/material_type
// The name of material that'll be used for texts
var/material_name
var/material_name_singular
var/initial_amount = 0
// The maximum amount of material the rod can hold
var/max_initial_amount = 10
var/grown_amount = 0
// The multiplier for growth. 1 for the same 2 for double etc etc
var/multiplier = 2
// After this depletion, you won't be able to add new materials
var/material_input_deadline = 25
// Material fuel rods generally don't get converted into another fuel object
depletion_conversion_type = ""
// Called when the rod is fully harvested
/obj/item/twohanded/required/fuel_rod/material/proc/expend()
expended = TRUE
// Basic checks for material rods
/obj/item/twohanded/required/fuel_rod/material/proc/check_material_input(mob/user)
if(depletion >= material_input_deadline)
to_chat(user, "<span class='warning'>The sample slots have sealed themselves shut, it's too late to add [material_name] now!</span>") // no cheesing in crystals at 100%
return FALSE
if(expended)
to_chat(user, "<span class='warning'>\The [src]'s material slots have already been used.</span>")
return FALSE
return TRUE
// The actual growth
/obj/item/twohanded/required/fuel_rod/material/depletion_final(result_rod)
if(result_rod)
..() // So if you put anything into depletion_conversion_type then your fuel rod will be converted (or not) and *won't grow*
else
grown_amount = initial_amount * multiplier
/obj/item/twohanded/required/fuel_rod/material/attackby(obj/item/W, mob/user, params)
var/obj/item/stack/M = W
if(istype(M, material_type))
if(!check_material_input(user))
return
if(initial_amount < max_initial_amount)
var/adding = min((max_initial_amount - initial_amount), M.amount)
M.amount -= adding
initial_amount += adding
if (adding == 1)
to_chat(user, "<span class='notice'>You insert [adding] [material_name_singular] into \the [src].</span>")
else
to_chat(user, "<span class='notice'>You insert [adding] [material_name] into \the [src].</span>")
M.zero_amount()
else
to_chat(user, "<span class='warning'>\The [src]'s material slots are full!</span>")
return
else
return ..()
/obj/item/twohanded/required/fuel_rod/material/attack_self(mob/user)
if(expended)
to_chat(user, "<span class='notice'>You have already removed [material_name] from \the [src].</span>")
return
if(depleted_final)
new material_type(user.loc, grown_amount)
if (grown_amount == 1)
to_chat(user, "<span class='notice'>You harvest [grown_amount] [material_name_singular] from \the [src].</span>") // Unlikely
else
to_chat(user, "<span class='notice'>You harvest [grown_amount] [material_name] from \the [src].</span>")
grown_amount = 0
expend()
else if(depletion)
to_chat(user, "<span class='warning'>\The [src] has not fissiled enough to fully grow the sample. The progress bar shows it is [min(depletion/depletion_threshold*100,100)]% complete.</span>")
else if(initial_amount)
new material_type(user.loc, initial_amount)
if (initial_amount == 1)
to_chat(user, "<span class='notice'>You remove [initial_amount] [material_name_singular] from \the [src].</span>")
else
to_chat(user, "<span class='notice'>You remove [initial_amount] [material_name] from \the [src].</span>")
initial_amount = 0
/obj/item/twohanded/required/fuel_rod/material/examine(mob/user)
. = ..()
if(expended)
. += "<span class='warning'>The material slots have been slagged by the extreme heat, you can't grow [material_name] in this rod again...</span>"
return
else if(depleted_final)
if(grown_amount == 1)
. += "<span class='warning'>This fuel rod's [material_name] are now fully grown, and it currently bears [grown_amount] harvestable [material_name_singular].</span>"
else
. += "<span class='warning'>This fuel rod's [material_name] are now fully grown, and it currently bears [grown_amount] harvestable [material_name].</span>"
return
if(depletion)
. += "<span class='danger'>The sample is [min(depletion/depletion_threshold*100,100)]% fissiled.</span>"
. += "<span class='disarm'>[initial_amount]/[max_initial_amount] of the slots for [material_name] are full.</span>"
/obj/item/twohanded/required/fuel_rod/material/telecrystal
name = "Telecrystal Fuel Rod"
desc = "A disguised titanium sheathed rod containing several small slots infused with uranium dioxide. Permits the insertion of telecrystals to grow more. Fissiles much faster than its standard counterpart"
icon_state = "telecrystal"
fuel_power = 0.30 // twice as powerful as a normal rod, you're going to need some engineering autism if you plan to mass produce TC
depletion_speed_modifier = 3 // headstart, otherwise it takes two hours
rad_strength = 1500
max_initial_amount = 8
multiplier = 3
material_type = /obj/item/stack/telecrystal
material_name = "telecrystals"
material_name_singular = "telecrystal"
/obj/item/twohanded/required/fuel_rod/material/telecrystal/depletion_final(result_rod)
..()
if(!result_rod)
fuel_power = 0.60 // thrice as powerful as plutonium, you'll want to get this one out quick!
name = "Exhausted Telecrystal Fuel Rod"
desc = "A highly energetic, disguised titanium sheathed rod containing a number of slots filled with greatly expanded telecrystals which can be removed by hand. It's extremely efficient as nuclear fuel, but will cause the reaction to get out of control if not properly utilised."
icon_state = "telecrystal_used"
AddComponent(/datum/component/radioactive, 3000, src)
/obj/item/twohanded/required/fuel_rod/material/bananium
name = "Bananium Fuel Rod"
desc = "A hilarious heavy-duty fuel rod which fissiles a bit slower than its cowardly counterparts. However, its cutting-edge cosmic clown technology allows rooms for extraordinarily exhilarating extraterrestrial element called bananium to menacingly multiply."
icon_state = "bananium"
fuel_power = 0.15
depletion_speed_modifier = 3
rad_strength = 350
max_initial_amount = 10
multiplier = 3
material_type = /obj/item/stack/sheet/mineral/bananium
material_name = "sheets of bananium"
material_name_singular = "sheet of bananium"
/obj/item/twohanded/required/fuel_rod/material/bananium/deplete(amount=0.035)
..()
if(initial_amount == max_initial_amount && prob(10))
playsound(src, pick('sound/items/bikehorn.ogg', 'yogstation/sound/misc/bikehorn_creepy.ogg'), 50) // HONK
/obj/item/twohanded/required/fuel_rod/material/bananium/depletion_final(result_rod)
..()
if(!result_rod)
fuel_power = 0.3 // Be warned
name = "Fully Grown Bananium Fuel Rod"
desc = "A hilarious heavy-duty fuel rod which fissiles a bit slower than it cowardly counterparts. Its greatly grimacing grwoth stage is now over, and bananium outgrowth hums as if it's blatantly honking bike horns."
icon_state = "bananium_used"
AddComponent(/datum/component/radioactive, 1250, src)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
// modular shitcode but it works:tm:
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/multitool_act(mob/living/user, obj/item/multitool/I)
if(istype(I))
to_chat(user, "<span class='notice'>You add \the [src]'s ID into the multitool's buffer.</span>")
I.buffer = src.id
return TRUE
/obj/machinery/computer/reactor/multitool_act(mob/living/user, obj/item/multitool/I)
if(istype(I))
to_chat(user, "<span class='notice'>You add the reactor's ID to \the [src]>")
src.id = I.buffer
link_to_reactor()
return TRUE
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/cargo // easier on the brain
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/cargo/New()
. = ..()
id = rand(1, 9999999) // cmon, what are the chances? The chances are... Very low friend... But maybe we can make this a bit better.
// Cargo variants can be wrenched down and don't start linked to the default RMBK reactor
/obj/machinery/computer/reactor/control_rods/cargo
anchored = FALSE
id = null
/obj/machinery/computer/reactor/stats/cargo
anchored = FALSE
id = null
/obj/machinery/computer/reactor/fuel_rods/cargo
anchored = FALSE
id = null
/obj/item/paper/fluff/rbmkcargo
name = "Nuclear Reactor Instructions"
info = "Make sure a 5x5 area is completely clear of pipes, cables and machinery when using the beacon. Those will be provided automatically with the beacon's bluespace decompression. Use a multitool on the reactor then on the computers provided to link them together. Also make sure the reactor has a proper pipeline filled with cooling gas before inserting fuel rods. Good luck!"

View File

@@ -0,0 +1,23 @@
/datum/reagent/consumable/pilk
name = "Pilk"
description = "A forbidden mixture that dates back to the early days of space civilization, its creation is known to have caused at least one or two massacres."
color = "#cf9f6f"
taste_description = "heresy"
glass_icon_state = "whiskeycolaglass"
glass_name = "glass of Pilk"
glass_desc = "Why would you do this to yourself?"
hydration = 3
/datum/reagent/consumable/pilk/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(0,M.drowsyness-3)
M.adjust_bodytemperature(-3 * TEMPERATURE_DAMAGE_COEFFICIENT, BODYTEMP_NORMAL)
if(HAS_TRAIT(M, TRAIT_CALCIUM_HEALER))
M.heal_bodypart_damage(0.75,0, 0)
. = 1
else
if(M.getBruteLoss() && prob(20))
M.heal_bodypart_damage(0.5,0, 0)
. = 1
if(holder.has_reagent(/datum/reagent/consumable/capsaicin))
holder.remove_reagent(/datum/reagent/consumable/capsaicin, 1)
..()

View File

@@ -0,0 +1,8 @@
/datum/reagent/consumable/alienhoney //for players who want bee character bewbs that produce honey.
name = "alien honey"
description = "Sweet honey that came from a alien source. This honey doesn't possess the same healing or nutrition properties as earth-bound bee honey."
color = "#d3a308"
value = 3 //plentiful, so wouldnt be worth as much.
nutriment_factor = 5 * REAGENTS_METABOLISM
metabolization_rate = 1 * REAGENTS_METABOLISM
taste_description = "sweetness"

View File

@@ -0,0 +1,294 @@
/*
* If you ever decide to add more reactions, please remember to keep these
* in alphabetical order, according to reagent names and not their datums.
* It could be hard to find reactions when code diving.
* Due note, unlike before this change, that subtypes will apply to the tray the same as their parents
* -DT
*/
#define DEFAULT_ACT_MUTAGEN switch(rand(100)){\
if(91 to 100){\
T.adjustHealth(-10);\
to_chat(user, "<span class='warning'>The plant shrivels and burns.</span>");}\
if(81 to 90)\
T.mutatespecie();\
if(66 to 80)\
T.hardmutate();\
if(41 to 65)\
T.mutate();\
if(21 to 41)\
to_chat(user, "<span class='notice'>The plants don't seem to react...</span>");\
if(11 to 20)\
T.mutateweed();\
if(1 to 10)\
T.mutatepest(user);\
else\
to_chat(user, "<span class='notice'>Nothing happens...</span>");}
//Ammonia
/datum/reagent/ammonia/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustHealth(round(volume * 0.5))
T.adjustNutri(round(volume * 1))
if(..())
T.myseed.adjust_yield(round(volume * 0.01))
return TRUE
//Ash
/datum/reagent/ash/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// Ash is used IRL in gardening, as a fertilizer enhancer and weed killer
T.adjustHealth(round(volume * 0.25))
T.adjustNutri(round(volume * 0.5))
T.adjustWeeds(-round(volume / 10))
return TRUE
//Beer
/datum/reagent/consumable/ethanol/beer/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// Beer is a chemical composition of alcohol and various other things. It's a shitty nutrient but hey, it's still one. Also alcohol is bad, mmmkay?
T.adjustHealth(-round(volume * 0.05))
T.adjustNutri(round(volume * 0.25))
T.adjustWater(round(volume * 0.7))
return TRUE
//Blood
/datum/reagent/blood/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustNutri(round(volume * 0.6))
T.adjustHealth(-round(volume))
T.adjustPests(rand(2,4)) //they HUNGER
return TRUE
//Charcoal
/datum/reagent/medicine/charcoal/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustToxic(-round(volume * 2)) //Antitoxin binds shit pretty well. So the tox goes significantly down
return TRUE
//Chlorine
/datum/reagent/chlorine/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustHealth(-round(volume * 1))
T.adjustToxic(round(volume * 1.5))
T.adjustWater(-round(volume * 0.5))
T.adjustWeeds(-rand(1,volume * 0.125))
return TRUE
//Diethylamine
/datum/reagent/diethylamine/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
//Corrosive to pests, but not to plants
if(..())
T.myseed.adjust_yield(round(volume * 0.02))
T.adjustHealth(round(volume))
T.adjustNutri(round(volume * 2))
T.adjustPests(-rand(1,round(volume / 30)))
return TRUE
//Earthsblood
/datum/reagent/medicine/earthsblood/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.self_sufficiency_progress += volume
if(T.self_sufficiency_progress >= T.self_sufficiency_req)
T.become_self_sufficient()
else
to_chat(user, "<span class='notice'>[T] warms as it might on a spring day under a genuine Sun.</span>")
return TRUE
//Enduro-Grow
/datum/reagent/plantnutriment/endurogrow/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(!..())
return -1
T.myseed.adjust_potency(-round(volume / 10))
T.myseed.adjust_yield(-round(volume / 30))
T.myseed.adjust_endurance(round(volume / 30))
return TRUE
//E-Z Nutrient
/datum/reagent/plantnutriment/eznutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.yieldmod = 1
T.mutmod = 1
return ..()
//Flourine
/datum/reagent/fluorine/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// Fluorine one of the most corrosive and deadly gasses
T.adjustHealth(-round(volume * 2))
T.adjustToxic(round(volume * 2.5))
T.adjustWater(-round(volume * 0.5))
T.adjustWeeds(-rand(1, volume * 0.25))
return TRUE
//Fluorosulfuric acid
/datum/reagent/toxin/acid/fluacid/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustHealth(-round(volume * 2))
T.adjustToxic(round(volume * 3))
T.adjustWeeds(-rand(1,volume * 0.5))
return TRUE
//Holy Water
/datum/reagent/water/holywater/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
//Mostly the same as water, it also heals the plant a little with the power of the spirits~
T.adjustWater(round(volume))
T.adjustHealth(round(volume * 0.1))
return TRUE
//Left-4-Zed
/datum/reagent/plantnutriment/left4zednutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.yieldmod = 0
T.mutmod = 2
return ..()
//Liquid Earthquake
/datum/reagent/plantnutriment/liquidearthquake/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(!..())
return -1
T.myseed.adjust_weed_chance(round(volume / 10))
T.myseed.adjust_weed_rate(round(volume / 30))
T.myseed.adjust_production(-round(volume / 30))
return TRUE
//Milk
/datum/reagent/consumable/milk/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustNutri(round(volume * 0.2))
T.adjustWater(round(volume * 0.5))
if(..()) // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth.
if(!T.myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) //Not shrooms though
T.adjustHealth(-round(volume / 2))
return TRUE
//Napalm
/datum/reagent/napalm/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(..())
if(T.myseed.resistance_flags & FIRE_PROOF)
return TRUE
T.adjustHealth(-round(volume * 6))
T.adjustToxic(round(volume * 7))
T.adjustWeeds(-rand(5,9))
return TRUE
//Nutriment
/datum/reagent/consumable/nutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
//Compost, effectively
T.adjustHealth(round(volume * 0.5))
T.adjustNutri(round(volume))
return TRUE
//Pest Killer
/datum/reagent/toxin/pestkiller/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustToxic(round(volume * 0.5))
T.adjustPests(-rand(1,volume / 5))
return TRUE
//Phosphorus
/datum/reagent/phosphorus/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// White Phosphorous + water -> phosphoric acid. That's not a good thing really.
// Phosphoric salts are beneficial though. And even if the plant suffers, in the long run the tray gets some nutrients. The benefit isn't worth that much.
T.adjustHealth(-round(volume * 0.75))
T.adjustNutri(round(volume * 0.1))
T.adjustWater(-round(volume * 0.5))
T.adjustWeeds(-rand(1, volume * 0.1))
return TRUE
//Plant-B-Gone
/datum/reagent/toxin/plantbgone/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustHealth(-round(volume * 5))
T.adjustToxic(round(volume * 6))
T.adjustWeeds(-rand(4,8))
return TRUE
//Plant Base
//For subtypes of /datum/reagent/plantnutriment/
/datum/reagent/plantnutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustNutri(round(volume))
return ..()
//Radium
/datum/reagent/radium/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(volume >= 10)
DEFAULT_ACT_MUTAGEN
else if(volume >= 5)
T.hardmutate()
else if(volume >= 2)
T.mutate()
T.adjustHealth(-round(volume))
T.adjustToxic(round(volume * 3)) // Radium is harsher (OOC: also easier to produce)
return TRUE
//Robust Harvest
/datum/reagent/plantnutriment/robustharvestnutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.yieldmod = 1.3
T.mutmod = 0
return ..()
//Saltpetre
/datum/reagent/saltpetre/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// Saltpetre is used for gardening IRL. To simplify highly, it speeds up growth and strengthens plants
T.adjustHealth(round(volume * 0.25))
if (..())
T.myseed.adjust_production(-round(volume/100)-prob(volume%100))
T.myseed.adjust_potency(round(volume*0.5))
return TRUE
//Soda Water
/datum/reagent/consumable/sodawater/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
// A variety of nutrients are dissolved in club soda, without sugar.
// These nutrients include carbon, oxygen, hydrogen, phosphorous, potassium, sulfur and sodium, all of which are needed for healthy plant growth.
T.adjustWater(round(volume) * 0.9)
T.adjustHealth(round(volume * 0.1))
T.adjustNutri(round(volume * 0.1))
return TRUE
//Sugar
/datum/reagent/consumable/sugar/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustWeeds(round(rand(1, volume / 5)))
T.adjustPests(round(rand(1, volume / 5)))
return TRUE
//Sulphuric Acid
/datum/reagent/toxin/acid/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustHealth(-round(volume * 1))
T.adjustToxic(round(volume * 1.5))
T.adjustWeeds(-rand(1,volume * 0.25))
return TRUE
//Toxin
/datum/reagent/toxin/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustToxic(round(volume * 2))
return TRUE
//Unstable Mutagen
/datum/reagent/toxin/mutagen/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(volume >= 5)
DEFAULT_ACT_MUTAGEN
else if(volume >= 2)
T.hardmutate()
else if(volume >= 1)
T.mutate()
return TRUE
//Uranium
/datum/reagent/uranium/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
if(volume >= 10)
DEFAULT_ACT_MUTAGEN
else if(volume >= 5)
T.hardmutate()
else if(volume >= 2)
T.mutate()
T.adjustHealth(-round(volume))
T.adjustToxic(round(volume * 2))
return TRUE
//Virus Food
/datum/reagent/toxin/mutagen/mutagenvirusfood/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustNutri(round(volume * 0.5))
T.adjustHealth(-round(volume * 0.5))
return TRUE
//Water
/datum/reagent/water/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustWater(round(volume))
return TRUE
//Weed Killer
/datum/reagent/toxin/plantbgone/weedkiller/on_tray(obj/machinery/hydroponics/T, volume, mob/user)
T.adjustToxic(round(volume / 2))
T.adjustWeeds(-rand(1,volume / 5))
return TRUE
#undef DEFAULT_ACT_MUTAGEN

View File

@@ -0,0 +1,29 @@
/datum/reagent/medicine/copium
name = "copium"
description = "A heavy scented substance meant to help one deal with loss."
reagent_state = LIQUID
color = "#a8707e"
overdose_threshold = 21
metabolization_rate = 0.75 * REAGENTS_METABOLISM
pH = 4
/datum/reagent/medicine/copium/on_mob_life(mob/living/carbon/M)
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
if(mood.sanity <= SANITY_NEUTRAL && current_cycle >= 5)
mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL))
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "copium", /datum/mood_event/copium)
..()
/datum/reagent/medicine/copium/overdose_process(mob/living/carbon/M) //copious amounts of copium
M.blur_eyes(10)
if(prob(50))
M.adjustToxLoss(1, 0)
if(prob(5))
M.say(pick("That's okay. Things are going to be okay.", "This is fine.", "I'm okay with the events that are unfolding currently.", "World of Spacecraft is still a good game...", "I'm winning.", "Diesels are far more powerful."))
if(prob(5))
M.emote("me", 1, "seems to be crying.")
if(prob(4))
M.emote("me", 1, "falls over, crying.")
M.Knockdown(40)
//To-do: /datum/reagent/medicine/seethium

View File

@@ -0,0 +1,6 @@
/datum/chemical_reaction/copium
name = "copium"
id = /datum/reagent/medicine/copium
results = list(/datum/reagent/medicine/copium = 5)
required_reagents = list(/datum/reagent/medicine/mannitol = 2, /datum/reagent/water = 1, /datum/reagent/medicine/epinephrine = 1, /datum/reagent/consumable/sugar = 1)
required_temp = 266

View File

@@ -0,0 +1,34 @@
//This action is technically a duplicate of /action/small_sprite
//However, we do our own things...
/datum/action/sizecode_resize
name = "Toggle Giant Sprite"
desc = "Others will continue to see you giant."
icon_icon = 'icons/mob/screen_gen_old.dmi'
button_icon_state = "health1" //You can change this if you want
background_icon_state = "bg_alien" //But keep this as a distinct background
var/small = FALSE
var/image/small_icon
/datum/action/sizecode_resize/Grant(mob/M, safety=FALSE)
if(ishuman(M) && !safety) //this probably gets called before a person gets overlays on roundstart, so try again
if(!LAZYLEN(M.overlays))
addtimer(CALLBACK(src,PROC_REF(Grant), M, TRUE), 5) //https://www.youtube.com/watch?v=QQ-aYZzlDeo
return
..()
if(!owner)
return
var/image/I = image(icon=owner.icon,icon_state=owner.icon_state,loc=owner,layer=owner.layer,pixel_x=owner.pixel_x,pixel_y=owner.pixel_y)
I.overlays += owner.overlays
I.override = TRUE
small_icon = I
/datum/action/sizecode_resize/Trigger()
..()
if(!small)
owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic, "sizecode_smallsprite", small_icon)
else
owner.remove_alt_appearance("sizecode_smallsprite")
small = !small
return TRUE

View File

@@ -0,0 +1,271 @@
//I am not a coder. Please fucking tear apart my code, and insult me for how awful I am at coding. Please and thank you. -Dahlular
//alright bet -BoxBoy
#define RESIZE_MACRO 6
#define RESIZE_HUGE 4
#define RESIZE_BIG 2
#define RESIZE_NORMAL 1
#define RESIZE_SMALL 0.75
#define RESIZE_TINY 0.50
#define RESIZE_MICRO 0.25
//Moving these here - Jay
/mob/living
var/size_multiplier = 1 //multiplier for the mob's icon size atm
var/previous_size = 1
//Cyanosis - Action that resizes the sprite for the client but nobody else. Say goodbye to attacking yourself when someone's above you lmao
var/datum/action/sizecode_resize/small_sprite
#define MOVESPEED_ID_SIZE "SIZECODE"
#define MOVESPEED_ID_STOMP "STEPPY"
//averages
#define RESIZE_A_MACROHUGE (RESIZE_MACRO + RESIZE_HUGE) / 2
#define RESIZE_A_HUGEBIG (RESIZE_HUGE + RESIZE_BIG) / 2
#define RESIZE_A_BIGNORMAL (RESIZE_BIG + RESIZE_NORMAL) / 2
#define RESIZE_A_NORMALSMALL (RESIZE_NORMAL + RESIZE_SMALL) / 2
#define RESIZE_A_SMALLTINY (RESIZE_SMALL + RESIZE_TINY) / 2
#define RESIZE_A_TINYMICRO (RESIZE_TINY + RESIZE_MICRO) / 2
//Scale up a mob's icon by the size_multiplier
/mob/living/update_transform()
ASSERT(!iscarbon(src)) //the source isnt carbon should always be true
var/matrix/M = matrix() //matrix (M) variable
M.Scale(size_multiplier)
M.Translate(0, 16*(size_multiplier-1)) //translate by 16 * size_multiplier - 1 on Y axis
src.transform = M //the source of transform is M
/mob/proc/get_effective_size()
return 100000
/mob/living/get_effective_size()
return src.size_multiplier
/datum/movespeed_modifier/size
id = MOVESPEED_ID_SIZE
/mob/living/proc/resize(var/new_size, var/animate = TRUE)
size_multiplier = new_size //This will be passed into update_transform() and used to change health and speed.
if(size_multiplier == previous_size)
return TRUE
src.update_transform() //WORK DAMN YOU
src.update_mobsize()
//Going to change the health and speed values too
src.remove_movespeed_modifier(/datum/movespeed_modifier/size)
src.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/size, multiplicative_slowdown = (abs(size_multiplier - 1) * 0.3 )) //GS Change, reduces speed penalties for size from *.4 to *.3
var/healthmod_old = ((previous_size * 35) - 75) //Get the old value to see what we must change.
var/healthmod_new = ((size_multiplier * 35) - 75) //A size of one would be zero. Big boys get health, small ones lose health. //GS Change, reduces health penalties/buffs for size from *75 to *35
var/healthchange = healthmod_new - healthmod_old //Get ready to apply the new value, and subtract the old one. (Negative values become positive)
src.maxHealth += healthchange
src.health += healthchange
if(iscarbon(src))
var/mob/living/carbon/C = src
for(var/obj/item/organ/genital/G in C.internal_organs)
G.update_appearance()
//if(src.size_multiplier >= RESIZE_A_HUGEBIG || src.size_multiplier <= RESIZE_A_TINYMICRO) Will remove clothing when too big or small. Will do later.
previous_size = size_multiplier //And, change this now that we are finally done.
SEND_SIGNAL(src, COMSIG_MOBSIZE_CHANGED, src) //This SHOULD allow other shit to check when a mob changes size -Capn
//Now check if the mob can get the size action
if(!small_sprite)
small_sprite = new(src)
small_sprite.Remove(src)
if(size_multiplier >= 1.25) //Anything bigger will start to block things
small_sprite.Grant(src)
//handle the big steppy, except nice
/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob)
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(tmob.pulledby == H)
return FALSE
//Micro is on a table.
var/turf/steppyspot = tmob.loc
for(var/thing in steppyspot.contents)
if(istype(thing, /obj/structure/table))
return TRUE
//Both small.
if(H.get_effective_size() <= RESIZE_A_TINYMICRO && tmob.get_effective_size() <= RESIZE_A_TINYMICRO)
now_pushing = 0
H.forceMove(tmob.loc)
return TRUE
//Doing messages
if(abs(get_effective_size()/tmob.get_effective_size()) >= 2) //if the initiator is twice the size of the micro
now_pushing = 0
H.forceMove(tmob.loc)
//Smaller person being stepped on
if(get_effective_size() > tmob.get_effective_size() && iscarbon(src))
// GS13: Import Fat Naga & Alt Naga from VoreStation
if(istype(H) && H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle" || H.dna.features["taur"] == "Fat Naga" || H.dna.features["taur"] == "Alt Naga")
tmob.visible_message("<span class='notice'>[src] carefully slithers around [tmob].</span>", "<span class='notice'>[src]'s huge tail slithers besides you.</span>")
else
tmob.visible_message("<span class='notice'>[src] carefully steps over [tmob].</span>", "<span class='notice'>[src] steps over you carefully.</span>")
return TRUE
//Smaller person stepping under a larger person
if(abs(tmob.get_effective_size()/get_effective_size()) >= 2)
H.forceMove(tmob.loc)
now_pushing = 0
micro_step_under(tmob)
return TRUE
//Stepping on disarm intent -- TO DO, OPTIMIZE ALL OF THIS SHIT
/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob)
ASSERT(isliving(tmob))
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(tmob.pulledby == H)
return FALSE
//If on a table, don't
var/turf/steppyspot = tmob.loc
for(var/thing in steppyspot.contents)
if(istype(thing, /obj/structure/table))
return TRUE
//Both small
if(H.get_effective_size() <= RESIZE_A_TINYMICRO && tmob.get_effective_size() <= RESIZE_A_TINYMICRO)
now_pushing = 0
H.forceMove(tmob.loc)
return TRUE
if(abs(get_effective_size()/tmob.get_effective_size()) >= 2)
if(H.a_intent == "disarm" && H.canmove && !H.buckled)
now_pushing = 0
H.forceMove(tmob.loc)
sizediffStamLoss(tmob)
H.add_movespeed_modifier(MOVESPEED_ID_STOMP, multiplicative_slowdown = 10) //Full stop
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/, remove_movespeed_modifier), MOVESPEED_ID_STOMP), 3) //0.3 seconds
if(get_effective_size() > tmob.get_effective_size() && iscarbon(H))
if(istype(H) && H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle" || H.dna.features["taur"] == "Fat Naga" || H.dna.features["taur"] == "Alt Naga")
tmob.visible_message("<span class='danger'>[src] carefully rolls their tail over [tmob]!</span>", "<span class='danger'>[src]'s huge tail rolls over you!</span>")
else
tmob.visible_message("<span class='danger'>[src] carefully steps on [tmob]!</span>", "<span class='danger'>[src] steps onto you with force!</span>")
//horny traits
/*
if(HAS_TRAIT(src, TRAIT_MICROPHILE))
src.adjust_arousal(8)
if (src.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna())
src.mob_climax(forced_climax=TRUE)
if(HAS_TRAIT(tmob, TRAIT_MACROPHILE))
tmob.adjust_arousal(10)
if (tmob.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna())
tmob.mob_climax(forced_climax=TRUE)
return TRUE
* commenting out for now.*/
if(H.a_intent == "harm" && H.canmove && !H.buckled)
now_pushing = 0
H.forceMove(tmob.loc)
sizediffStamLoss(tmob)
sizediffBruteloss(tmob)
playsound(loc, 'sound/misc/splort.ogg', 50, 1)
H.add_movespeed_modifier(MOVESPEED_ID_STOMP, multiplicative_slowdown = 10)
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/, remove_movespeed_modifier), MOVESPEED_ID_STOMP), 10) //1 second
//H.Stun(20)
if(get_effective_size() > tmob.get_effective_size() && iscarbon(H))
if(istype(H) && H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle" || H.dna.features["taur"] == "Fat Naga" || H.dna.features["taur"] == "Alt Naga")
tmob.visible_message("<span class='danger'>[src] mows down [tmob] under their tail!</span>", "<span class='userdanger'>[src] plows their tail over you mercilessly!</span>")
else
tmob.visible_message("<span class='danger'>[src] slams their foot down on [tmob], crushing them!</span>", "<span class='userdanger'>[src] crushes you under their foot!</span>")
//horny traits
/*
if(HAS_TRAIT(src, TRAIT_MICROPHILE))
src.adjust_arousal((get_effective_size()/tmob.get_effective_size()*3))
if (src.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna())
src.mob_climax(forced_climax=TRUE)
if(HAS_TRAIT(tmob, TRAIT_MACROPHILE))
tmob.adjust_arousal((get_effective_size()/tmob.get_effective_size()*3))
if (tmob.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna())
tmob.mob_climax(forced_climax=TRUE)
commenting out for now */
return TRUE
// if(H.a_intent == "grab" && H.canmove && !H.buckled)
// now_pushing = 0
// H.forceMove(tmob.loc)
// sizediffStamLoss(tmob)
// sizediffStun(tmob)
// H.add_movespeed_modifier(MOVESPEED_ID_STOMP, multiplicative_slowdown = 10)
// addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/, remove_movespeed_modifier), MOVESPEED_ID_STOMP), 7)//About 3/4th a second
// if(get_effective_size() > tmob.get_effective_size() && iscarbon(H))
// var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
// if(feetCover)
// if(istype(H) && H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle" || H.dna.features["taur"] == "Fat Naga" || H.dna.features["taur"] == "Alt Naga")
// tmob.visible_message("<span class='danger'>[src] pins [tmob] under their tail!</span>", "<span class='danger'>[src] pins you beneath their tail!</span>")
// else
// tmob.visible_message("<span class='danger'>[src] pins [tmob] helplessly underfoot!</span>", "<span class='danger'>[src] pins you underfoot!</span>")
// return TRUE
// else
// if(istype(H) && H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle" || H.dna.features["taur"] == "Fat Naga" || H.dna.features["taur"] == "Alt Naga")
// tmob.visible_message("<span class='danger'>[src] snatches up [tmob] underneath their tail!</span>", "<span class='userdanger'>[src]'s tail winds around you and snatches you in its coils!</span>")
// //tmob.mob_pickup_micro_feet(H)
// SEND_SIGNAL(tmob, COMSIG_MICRO_PICKUP_FEET, H)
// else
// tmob.visible_message("<span class='danger'>[src] stomps down on [tmob], curling their toes and picking them up!</span>", "<span class='userdanger'>[src]'s toes pin you down and curl around you, picking you up!</span>")
// //tmob.mob_pickup_micro_feet(H)
// SEND_SIGNAL(tmob, COMSIG_MICRO_PICKUP_FEET, H)
// return TRUE
if(abs(tmob.get_effective_size()/get_effective_size()) >= 2)
H.forceMove(tmob.loc)
now_pushing = 0
micro_step_under(tmob)
return TRUE
//smaller person stepping under another person... TO DO, fix and allow special interactions with naga legs to be seen
/mob/living/proc/micro_step_under(var/mob/living/tmob)
if(istype(tmob) && istype(tmob, /datum/sprite_accessory/taur/naga))
src.visible_message("<span class='notice'>[src] bounds over [tmob]'s tail.</span>", "<span class='notice'>You jump over [tmob]'s thick tail.</span>")
else
src.visible_message("<span class='notice'>[src] runs between [tmob]'s legs.</span>", "<span class='notice'>You run between [tmob]'s legs.</span>")
//Proc for scaling stamina damage on size difference
/mob/living/proc/sizediffStamLoss(var/mob/living/tmob)
var/S = (get_effective_size()/tmob.get_effective_size()*25) //macro divided by micro, times 25
tmob.Knockdown(S) //final result in stamina knockdown
//Proc for scaling stuns on size difference (for grab intent)
/mob/living/proc/sizediffStun(var/mob/living/tmob)
var/T = (get_effective_size()/tmob.get_effective_size()*2) //Macro divided by micro, times 2
tmob.Stun(T)
//Proc for scaling brute damage on size difference
/mob/living/proc/sizediffBruteloss(var/mob/living/tmob)
var/B = (get_effective_size()/tmob.get_effective_size()*2) //macro divided by micro, times 3 //GS change, *2
tmob.adjustBruteLoss(B) //final result in brute loss
//Proc for changing mob_size to be grabbed for item weight classes
/mob/living/proc/update_mobsize(var/mob/living/tmob)
if(size_multiplier <= 0.50)
mob_size = 0
else if(size_multiplier < 1)
mob_size = 1
else if(size_multiplier <= 2)
mob_size = 2 //the default human size
else if(size_multiplier > 2)
mob_size = 3
//Proc for instantly grabbing valid size difference. Code optimizations soon(TM)
/*
/mob/living/proc/sizeinteractioncheck(var/mob/living/tmob)
if(abs(get_effective_size()/tmob.get_effective_size())>=2.0 && get_effective_size()>tmob.get_effective_size())
return FALSE
else
return TRUE
*/
//Clothes coming off at different sizes, and health/speed/stam changes as well

View File

@@ -0,0 +1,134 @@
//Size Chemicals, now with better and less cringy names.
//TO DO: USE BETTER FERMICHEM TO MAKE ALL OF THESE CHEMICALS MORE INTERACTIVE
//Sizechem reagent
/datum/reagent/sizechem
name = "Cell-Volume Altering Base"
description = "A stabilized compound liquid, used as a basis for increasing or decreasing the size of living matter with more recipes."
color = "#C900CC"
taste_description = "regret"
can_synth = FALSE
metabolization_rate = 0.25
//Sizechem reaction
/datum/chemical_reaction/sizechem
name = "Cell-Volume Altering Base"
id = /datum/reagent/sizechem
mix_message = "the reaction rapidly alters in size!"
required_reagents = list(/datum/reagent/growthserum = 0.15, /datum/reagent/medicine/clonexadone = 0.15, /datum/reagent/gold = 0.15, /datum/reagent/acetone = 0.15)
results = list(/datum/reagent/sizechem = 0.3)
required_temp = 1
//Fermichem vars
OptimalTempMin = 600 // Lower area of bell curve for determining heat based rate reactions
OptimalTempMax = 630 // Upper end for above
ExplodeTemp = 635 // Temperature at which reaction explodes
OptimalpHMin = 5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
OptimalpHMax = 5.5 // Higest value for above
ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
ThermicConstant = -10 // Temperature change per 1u produced
HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
FermiExplode = FALSE // If the chemical explodes in a special way
PurityMin = 0.2
//Growthchem reagent
/datum/reagent/growthchem
name = "Prospacillin"
description = "A stabilized altercation of size-altering liquids, this one appears to increase cell volume."
color = "#E70C0C"
taste_description = "a sharp, fiery and intoxicating flavour"
overdose_threshold = 10
metabolization_rate = 0.25
can_synth = FALSE //DO NOT MAKE THIS SNYTHESIZABLE, THESE CHEMS ARE SUPPOSED TO NOT BE USED COMMONLY
//Growthchem reaction
/datum/chemical_reaction/growthchem
name = "Prospacillin"
id = /datum/reagent/growthchem
mix_message = "the reaction appears to grow!"
required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/condensedcapsaicin = 0.15, /datum/reagent/drug/aphrodisiac = 0.30)
results = list(/datum/reagent/growthchem = 0.25)
required_temp = 1
OptimalTempMin = 700 // Lower area of bell curve for determining heat based rate reactions
OptimalTempMax = 730 // Upper end for above
ExplodeTemp = 735 // Temperature at which reaction explodes
OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
OptimalpHMax = 3.5 // Higest value for above
ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
ThermicConstant = -10 // Temperature change per 1u produced
HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
FermiExplode = FALSE // If the chemical explodes in a special way
PurityMin = 0.2
//Growthchem effects
/datum/reagent/growthchem/on_mob_add(mob/living/carbon/M)
. = ..()
if(ishuman(M))
log_game("SIZECODE: [M] ckey: [M.key] has ingested growthchem.")
/datum/reagent/growthchem/on_mob_life(mob/living/carbon/M)
if(!ishuman(M))
return..()
if(M.size_multiplier < RESIZE_MACRO)
M.resize(M.size_multiplier+0.025)
M.visible_message("<span class='danger'>[pick("[M] grows!", "[M] expands in size!", "[M] pushes outwards in stature!")]</span>", "<span class='danger'>[pick("You feel your body fighting for space and growing!", "The world contracts inwards in every direction!", "You feel your muscles expand, and your surroundings shrink!")]</span>")
..()
. = 1
//Shrinkchem reagent
/datum/reagent/shrinkchem
name = "Diminicillin"
description = "A stabilized altercation of size-altering liquids, this one appears to decrease cell volume."
color = "#0C26E7"
taste_description = "a pungent, acidic and jittery flavour"
overdose_threshold = 10
metabolization_rate = 0.50
can_synth = FALSE //SAME STORY AS ABOVE
//Shrinchem reaction
/datum/chemical_reaction/shrinkchem
name = "Diminicillin"
id = /datum/reagent/shrinkchem
mix_message = "the reaction appears to shrink!"
required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/frostoil = 0.15, /datum/reagent/drug/aphrodisiac = 0.30)
results = list(/datum/reagent/shrinkchem = 0.25)
required_temp = 1
OptimalTempMin = 100 // Lower area of bell curve for determining heat based rate reactions
OptimalTempMax = 150 // Upper end for above
ExplodeTemp = 350 // Temperature at which reaction explodes
OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
OptimalpHMax = 4.5 // Higest value for above
ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
ThermicConstant = -10 // Temperature change per 1u produced
HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
FermiExplode = FALSE // If the chemical explodes in a special way
PurityMin = 0.2
//Shrinkchem effects
/datum/reagent/shrinkchem/on_mob_add(mob/living/carbon/M)
. = ..()
if(ishuman(M))
log_game("SIZECODE: [M] ckey: [M.key] has ingested shrinkchem.")
/datum/reagent/shrinkchem/on_mob_life(mob/living/carbon/M)
if(!ishuman(M))
return..()
if(M.size_multiplier > RESIZE_MICRO)
M.resize(M.size_multiplier-0.025)
M.visible_message("<span class='danger'>[pick("[M] shrinks down!", "[M] dwindles in size!", "[M] compresses down!")]</span>", "<span class='danger'>[pick("You feel your body compressing in size!", "The world pushes outwards in every direction!", "You feel your muscles contract, and your surroundings grow!")]</span>")
..()
. = 1

View File

@@ -0,0 +1,88 @@
/obj/item/projectile/sizelaser
name = "sizeray laser"
icon_state = "omnilaser"
hitsound = null
damage = 5
damage_type = STAMINA
flag = "laser"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
//TO DO: make the size ray have a selection of a minimum size and maximum size, rather than two modes.
/obj/item/projectile/sizelaser/shrinkray
icon_state="bluelaser"
/obj/item/projectile/sizelaser/growthray
icon_state="laser"
/obj/item/projectile/sizelaser/shrinkray/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living/carbon/human))
var/mob/living/M = target
switch(M.size_multiplier)
if(RESIZE_MACRO to INFINITY)
M.resize(RESIZE_HUGE)
if(RESIZE_HUGE to RESIZE_MACRO)
M.resize(RESIZE_BIG)
if(RESIZE_BIG to RESIZE_HUGE)
M.resize(RESIZE_NORMAL)
if(RESIZE_NORMAL to RESIZE_BIG)
M.resize(RESIZE_SMALL)
if(RESIZE_SMALL to RESIZE_NORMAL)
M.resize(RESIZE_TINY)
if(RESIZE_TINY to RESIZE_SMALL)
M.resize(RESIZE_MICRO)
if((0 - INFINITY) to RESIZE_NORMAL)
M.resize(RESIZE_MICRO)
M.update_transform()
return TRUE
/obj/item/projectile/sizelaser/growthray/on_hit(var/atom/target, var/blocked = 0 )
if(istype(target, /mob/living/carbon/human))
var/mob/living/M = target
switch(M.size_multiplier)
if(RESIZE_HUGE to RESIZE_MACRO)
M.resize(RESIZE_MACRO)
if(RESIZE_BIG to RESIZE_HUGE)
M.resize(RESIZE_HUGE)
if(RESIZE_NORMAL to RESIZE_BIG)
M.resize(RESIZE_BIG)
if(RESIZE_SMALL to RESIZE_NORMAL)
M.resize(RESIZE_NORMAL)
if(RESIZE_TINY to RESIZE_SMALL)
M.resize(RESIZE_SMALL)
if(RESIZE_MICRO to RESIZE_TINY)
M.resize(RESIZE_TINY)
if((0 - INFINITY) to RESIZE_MICRO)
M.resize(RESIZE_MICRO)
M.update_transform()
return TRUE
/obj/item/ammo_casing/energy/laser/growthray
projectile_type = /obj/item/projectile/sizelaser/growthray
select_name = "Growth"
/obj/item/ammo_casing/energy/laser/shrinkray
projectile_type = /obj/item/projectile/sizelaser/shrinkray
select_name = "Shrink"
//Gun
/obj/item/gun/energy/laser/sizeray
name = "size ray"
icon = 'icons/obj/guns/energy.dmi'
icon_state = "sizeshrink"
desc = "An extremely-dangerous, almost-illegal size-altering device. You've either stolen this, or have the permits for it."
item_state = null
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
selfcharge = EGUN_SELFCHARGE
charge_delay = 5
ammo_x_offset = 2
clumsy_check = 1
attackby(obj/item/W, mob/user)
if(W==src)
if(icon_state=="sizeshrink")
icon_state="sizegrow"
ammo_type = list(/obj/item/ammo_casing/energy/laser/growthray)
else
icon_state="sizeshrink"
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray)
return ..()

View File

@@ -0,0 +1,25 @@
/obj/item/organ/cyberimp/arm/mblade
name = "arm-mounted scytheblade"
desc = "An extremely dangerous implant which can be used in a variety of ways. Mostly killing."
contents = newlist(/obj/item/melee/mblade)
/obj/item/organ/cyberimp/arm/mblade/l
zone = BODY_ZONE_L_ARM
/obj/item/melee/mblade
name = "mounted scytheblade"
desc = "An extremely dangerous implant which can be used in a variety of ways. Mostly killing."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "mblade"
item_state = "mblade"
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
force = 45
hitsound = 'sound/weapons/bladeslice.ogg'
throwforce = 45
block_chance = 70
armour_penetration = 80
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_BULKY
sharpness = IS_SHARP_ACCURATE
attack_verb = list("slashed", "cut")

View File

@@ -0,0 +1,34 @@
//Jay Sparrow
/datum/quirk/cum_plus
name = "Extra productive genitals"
desc = "Your lower bits produce more and hold more than normal."
value = 0
category = CATEGORY_SEXUAL
mob_trait = TRAIT_CUM_PLUS
gain_text = "<span class='notice'>You feel pressure in your groin.</span>"
lose_text = "<span class='notice'>You feel a weight lifted from your groin.</span>"
medical_record_text = "Patient has greatly increased production of sexual fluids"
/datum/quirk/cum_plus/add()
var/mob/living/carbon/M = quirk_holder
if(M?.getorganslot("testicles"))
var/obj/item/organ/genital/testicles/T = M?.getorganslot("testicles")
T?.fluid_mult = 1.5 //Base is 1
T?.fluid_max_volume = 5
/datum/quirk/cum_plus/remove()
var/mob/living/carbon/M = quirk_holder
if(quirk_holder.getorganslot("testicles"))
var/obj/item/organ/genital/testicles/T = M?.getorganslot("testicles")
T?.fluid_mult = 1 //Base is 1
T?.fluid_max_volume = 3 //Base is 3
/datum/quirk/cum_plus/on_process()
var/mob/living/carbon/M = quirk_holder //If you get balls later, then this will still proc
if(M.getorganslot("testicles"))
var/obj/item/organ/genital/testicles/T = M?.getorganslot("testicles")
if(T?.fluid_max_volume <= 5 || T?.fluid_mult <= 0.2) //INVALID EXPRESSION?
T?.fluid_mult = 1.5 //Base is 0.133
T?.fluid_max_volume = 5

View File

@@ -0,0 +1,8 @@
/datum/uplink_item/device_tools/tc_rod
name = "Telecrystal Fuel Rod"
desc = "This special fuel rod has eight material slots that can be inserted with telecrystals, \
once the rod has been fully depleted, you will be able to harvest the extra telecrystals. \
Please note: This Rod fissiles much faster than it's regular counterpart, it doesn't take \
much to overload the reactor with these..."
item = /obj/item/twohanded/required/fuel_rod/material/telecrystal
cost = 7

View File

@@ -0,0 +1,50 @@
/obj/item/clothing/head/zao
name = "zao police cap"
desc = "Zao Corps standard issue police force headwear, designed with the overcoat to help with the cold weather. The headwear also features a holographic projector, allowing itself to blend in with the user to create a better face to face interaction with civilians."
icon = 'hyperstation/icons/obj/clothing/head.dmi'
icon_state = "zaohat"
item_state = "helmet"
item_color = "zaohat"
alternate_worn_icon = 'hyperstation/icons/mobs/head.dmi'
armor = list("melee" = 40, "bullet" = 40, "laser" = 10,"energy" = 20, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 60)
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
strip_delay = 60
resistance_flags = FLAMMABLE
var/cloaked = 0
/obj/item/clothing/head/zao/dropped()
src.icon_state = "zaohat"
src.cloaked=0
..()
/obj/item/clothing/head/zao/verb/cloakcap()
set category = "Object"
set name = "Cloak hat"
cloak(usr)
/obj/item/clothing/head/zao/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
cloak(user)
return TRUE
/obj/item/clothing/head/zao/proc/cloak(mob/user)
if(!user.incapacitated())
src.cloaked = !src.cloaked
if(src.cloaked)
icon_state = "zaohat_active"
to_chat(user, "<span class='notice'>You toggle the hat\'s cloaking.</span>")
else
icon_state = "zaohat"
to_chat(user, "<span class='notice'>You reveal the hat again.</span>")
usr.update_inv_head() //so our mob-overlays update
/obj/item/clothing/head/zao/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-click the hat to toggle it\'s cloaking [cloaked ? "off" : "on"].</span>"

View File

@@ -0,0 +1,32 @@
/obj/item/clothing/suit/toggle/zao
name = "zao overcoat"
desc = "Zao Corps signature navy-blue overcoat with a golden highlight finish. Found among police forces as the suit was designed with riot control in mind, it also serves as modest winter coat insulated padding inside."
icon = 'hyperstation/icons/obj/clothing/suits.dmi'
icon_state = "zaocoat"
item_state = "zaocoat"
item_color = "zaocoat"
alternate_worn_icon = 'hyperstation/icons/mobs/suits.dmi'
togglename = "zipper"
body_parts_covered = CHEST|ARMS|LEGS
cold_protection = CHEST|GROIN|LEGS|ARMS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
strip_delay = 70
equip_delay_other = 40
max_integrity = 250
resistance_flags = FLAMMABLE
armor = list("melee" = 25, "bullet" = 25, "laser" = 5, "energy" = 15, "bomb" = 15, "bio" = 0, "rad" = 0, "fire" = 10, "acid" = 30)
// armor = list("melee" = 50, "bullet" = 50, "laser" = 10, "energy" = 30, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 60)
allowed = list(/obj/item/ammo_box,
/obj/item/ammo_casing,
/obj/item/flashlight,
/obj/item/storage/fancy/cigarettes,
/obj/item/gun/ballistic,
/obj/item/gun/energy,
/obj/item/lighter,
/obj/item/melee/baton,
/obj/item/melee/classic_baton/telescopic,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals/emergency_oxygen,
/obj/item/tank/internals/plasmaman,
/obj/item/toy) // Will be modifying/removing/adding more at a later date.

View File

@@ -0,0 +1,8 @@
/obj/item/clothing/under/rank/security/zao
name = "zao uniform"
desc = "The standard-issue police force uniform of Zao Corp. Made with a more formal approach to a dress shirt attire while retaining the protective fibers and identity with the blue arm bands. Waistcoat encouraged."
icon = 'hyperstation/icons/obj/clothing/uniforms.dmi'
icon_state = "zaounder"
item_state = "zaounder"
item_color = "zaounder"
alternate_worn_icon = 'hyperstation/icons/mobs/uniforms.dmi'

View File

@@ -0,0 +1,45 @@
/obj/item/clothing/glasses/hud/toggle/zao
name = "zao security visor"
desc = "A security visor from ZaoCorp designed to deploy and retract it's visor on a whim."
icon = 'hyperstation/icons/obj/clothing/glasses.dmi'
icon_state = "zaovisor"
item_state = "trayson-meson"
flash_protect = 1
tint = 1
flags_cover = GLASSESCOVERSEYES
visor_flags_cover = GLASSESCOVERSEYES
alternate_worn_icon = 'hyperstation/icons/mobs/eyes.dmi'
hud_type = DATA_HUD_SECURITY_ADVANCED
actions_types = list(/datum/action/item_action/switch_hud)
glass_colour_type = /datum/client_colour/glass_colour/lightyellow
/obj/item/clothing/glasses/hud/toggle/zao/attack_self(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/wearer = user
if (wearer.glasses != src)
return
if (hud_type)
var/datum/atom_hud/H = GLOB.huds[hud_type]
H.remove_hud_from(user)
if (hud_type == DATA_HUD_SECURITY_ADVANCED)
icon_state = "zaovisor_off"
item_state = "zaovisor_off"
hud_type = null
flash_protect = 0
tint = 0
change_glass_color(user, /datum/client_colour/glass_colour/white)
else
hud_type = DATA_HUD_SECURITY_ADVANCED
icon_state = "zaovisor"
item_state = "zaovisor"
flash_protect = 1
tint = 1
change_glass_color(user, /datum/client_colour/glass_colour/lightyellow)
if (hud_type)
var/datum/atom_hud/H = GLOB.huds[hud_type]
H.add_hud_to(user)
user.update_inv_glasses()

View File

@@ -0,0 +1,17 @@
/obj/item/ashtray
name = "ashtray"
icon = 'hyperstation/icons/obj/objects.dmi'
icon_state = "ashtray"
/obj/item/ashtray/attackby(obj/item/I, mob/user, params)
if (istype(I,/obj/item/clothing/mask/cigarette/))
var/obj/item/clothing/mask/cigarette/cig = I
if (cig.lit == 1)
src.visible_message("[user] crushes [cig] in \the [src], putting it out.")
else if (cig.lit == 0)
to_chat(user, "You place [cig] in [src].")
qdel(cig) //drop it in.
if (istype(I,/obj/item/cigbutt))
to_chat(user, "You place [I] in [src].")
qdel(I) //drop it in.

View File

@@ -0,0 +1,36 @@
//Jay Sparrow
#define ROOMY = "ROOMY"
//Sorry jay, I killed it.
/obj/item/bluespace_thread
name = "Bluespace Sewing Kit"
desc = "Thread infused with bluespace dust to make your clothes a little more roomy. Current sewing technology already incorporates this, so thankfully, the days of needing these are long gone. Good souvenir though."
icon = 'hyperstation/icons/obj/bluespace_thread.dmi'
icon_state = "thread"
item_state = "thread"
var/uses = 5 //Give it a few charges so it can last through the shift
w_class = WEIGHT_CLASS_TINY
/obj/item/bluespace_thread/attack_obj(obj/O, mob/living/user)
. = ..()
if(!istype(O, /obj/item/clothing))
user.show_message("<span class='notice'>You find yourself unable to stitch this.</span>", 1)
return
/obj/item/bluespace_thread/attack_self(mob/living/user)
user.show_message("<span class='notice'>The spool has [uses] uses remaining.</span>", 1)
//Let's add this to the loadout screen
/datum/gear/bluespace_thread
name = "Bluespace Sewing Kit"
category =ITEM_SLOT_IN_BACKPACK
path = /obj/item/bluespace_thread
//Crafting recipe
/datum/crafting_recipe/bluespace_thread
name = "Bluespace Sewing Kit"
result = /obj/item/bluespace_thread
time = 40
reqs = list(/obj/item/stack/ore/bluespace_crystal = 1,
/obj/item/stack/sheet/cloth = 3)
category = CAT_MISC

View File

@@ -0,0 +1,128 @@
//Made by quotefox
//Really needs some work, mainly because condoms should be a container for semen, but I dont know how that works yet. Feel free to improve upon.
/obj/item/condom
name = "condom"
desc = "Dont be silly, cover your willy!"
icon = 'hyperstation/icons/obj/condom.dmi'
throwforce = 0
icon_state = "b_condom_wrapped"
var/unwrapped = 0
w_class = WEIGHT_CLASS_TINY
price = 1
obj/item/condom/Initialize(mapload)
create_reagents(300, DRAWABLE|NO_REACT)
..()
obj/item/condom/update_icon()
switch(reagents.total_volume)
if(0 to 49)
icon_state = "b_condom_inflated"
if(50 to 100)
icon_state = "b_condom_inflated_med"
if(101 to 249)
icon_state = "b_condom_inflated_large"
if(250 to 300)
icon_state = "b_condom_inflated_huge"
..()
/obj/item/condom/attack_self(mob/user) //Unwrap The Condom in hands
if(!istype(user))
return
if(isliving(user))
if(unwrapped == 0)
icon_state = "b_condom"
unwrapped = 1
to_chat(user, "<span class='notice'>You unwrap the condom.</span>")
playsound(user, 'sound/items/poster_ripped.ogg', 50, 1, -1)
return
// if(unwrapped == 1)
// new /obj/item/clothing/head/condom(usr.loc)
// qdel(src)
// to_chat(user, "<span class='notice'>You roll the condom out.</span>")
// playsound(user, 'sound/lewd/latex.ogg', 50, 1, -1)
// return
/obj/item/condom/attack(mob/living/carbon/C, mob/living/user) //apply the johnny on another person or yourself
if(unwrapped == 0 )
to_chat(user, "<span class='notice'>You must remove the condom from the package first!</span>")
return
var/obj/item/organ/genital/penis/P = C.getorganslot("penis")
if(P&&P.is_exposed())
if(P.condom)
to_chat(user, "<span class='notice'>They already have a condom on!</span>")
return
if(isliving(C)&&isliving(user)&&unwrapped == 1)
C.visible_message("<span class='warning'>[user] is trying to put a condom on [C]!</span>",\
"<span class='warning'>[user] is trying to put a condom on you!</span>")
if(!do_mob(user, C, 4 SECONDS)) //if Failed to put the condom on
return
var/mob/living/carbon/human/L = C
playsound(C, 'sound/lewd/latex.ogg', 50, 1, -1)
P.condom = 1 //apply condom
P.colourtint = "87ceeb"
if(L)
L.update_genitals() // apply the colour!
to_chat(C, "<span class='userlove'>Your penis feels more safe!</span>")
qdel(src)
return
to_chat(user, "<span class='notice'>You can't find anywhere to put the condom on.</span>") //Trying to put it on something without/or with a hidden
/obj/item/clothing/head/condom //this is ss13, it would be a sin to not include this..
name = "condom"
icon = 'hyperstation/icons/obj/condom.dmi'
desc = "Looks like someone had abit of some fun!"
alternate_worn_icon = 'hyperstation/icons/obj/clothing/head.dmi'
icon_state = "b_condom_out"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 5, "rad" = 0, "fire" = 0, "acid" = 0)
/mob/living/carbon/human/proc/removecondom()
var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
if(P.condom)
new /obj/item/clothing/head/condom(usr.loc)
to_chat(src, "The condom slips off the end of your penis.")
P.condom = 0
P.colourtint = ""
src.update_genitals()
/obj/item/condom/filled
name = "filled condom"
icon_state = "b_condom_inflated"
unwrapped = 2
w_class = WEIGHT_CLASS_TINY
/obj/item/condom/filled/throw_impact(atom/hit_atom)
. = ..()
if(!.) //if we're not being caught
splat(hit_atom)
/obj/item/condom/filled/proc/splat(atom/movable/hit_atom)
if(isliving(loc))
return
var/turf/T = get_turf(hit_atom)
new/obj/effect/decal/cleanable/semen(T)
playsound(T, "sound/misc/splort", 50, TRUE)
qdel(src)
/mob/living/carbon/human/proc/condomclimax()
var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
if(!istype(P))
return
if(!P.condom)
return
var/obj/item/condom/filled/C = new
P.linked_organ.reagents.trans_to(C, P.linked_organ.reagents.total_volume)
C.loc = loc
P.condom = FALSE
P.colourtint = ""
update_genitals()
C.update_icon()
to_chat(src, "<span class='love'>The condom bubbles outwards and fills with your cum.</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
setArousalLoss(0)

View File

@@ -0,0 +1,233 @@
/obj/decal/stencil
name = "stencil"
desc = "A letter, one of many used to make words."
icon = 'hyperstation/icons/decals/decal_new.dmi'
icon_state = "a"
anchored = TRUE
layer = WALL_OBJ_LAYER
left
pixel_x = -3 //fine-tune from this offset
pixel_y = 8
alpha = 200
a
name = "a"
icon_state = "a"
b
name = "b"
icon_state = "b"
c
name = "c"
icon_state = "c"
d
name = "d"
icon_state = "d"
e
name = "e"
icon_state = "e"
f
name = "f"
icon_state = "f"
g
name = "g"
icon_state = "g"
h
name = "h"
icon_state = "h"
i
name = "i"
icon_state = "i"
j
name = "j"
icon_state = "j"
k
name = "k"
icon_state = "k"
l
name = "l"
icon_state = "l"
m
name = "m"
icon_state = "m"
n
name = "n"
icon_state = "n"
o
name = "o"
icon_state = "o"
p
name = "p"
icon_state = "p"
q
name = "q"
icon_state = "q"
r
name = "r"
icon_state = "r"
s
name = "s"
icon_state = "s"
t
name = "t"
icon_state = "t"
u
name = "u"
icon_state = "u"
v
name = "v"
icon_state = "v"
w
name = "w"
icon_state = "w"
x
name = "x"
icon_state = "x"
y
name = "y"
icon_state = "y"
z
name = "z"
icon_state = "z"
one
name = "one"
icon_state = "1"
two
name = "two"
icon_state = "2"
three
name = "three"
icon_state = "3"
four
name = "four"
icon_state = "4"
five
name = "five"
icon_state = "5"
six
name = "six"
icon_state = "6"
seven
name = "seven"
icon_state = "7"
eight
name = "eight"
icon_state = "8"
nine
name = "nine"
icon_state = "9"
zero
name = "zero"
icon_state = "0"
right
pixel_x = 13 // fine-tune from this offset
pixel_y = 8
alpha = 200
a
name = "a"
icon_state = "a"
b
name = "b"
icon_state = "b"
c
name = "c"
icon_state = "c"
d
name = "d"
icon_state = "d"
e
name = "e"
icon_state = "e"
f
name = "f"
icon_state = "f"
g
name = "g"
icon_state = "g"
h
name = "h"
icon_state = "h"
i
name = "i"
icon_state = "i"
j
name = "j"
icon_state = "j"
k
name = "k"
icon_state = "k"
l
name = "l"
icon_state = "l"
m
name = "m"
icon_state = "m"
n
name = "n"
icon_state = "n"
o
name = "o"
icon_state = "o"
p
name = "p"
icon_state = "p"
q
name = "q"
icon_state = "q"
r
name = "r"
icon_state = "r"
s
name = "s"
icon_state = "s"
t
name = "t"
icon_state = "t"
u
name = "u"
icon_state = "u"
v
name = "v"
icon_state = "v"
w
name = "w"
icon_state = "w"
x
name = "x"
icon_state = "x"
y
name = "y"
icon_state = "y"
z
name = "z"
icon_state = "z"
one
name = "one"
icon_state = "1"
two
name = "two"
icon_state = "2"
three
name = "three"
icon_state = "3"
four
name = "four"
icon_state = "4"
five
name = "five"
icon_state = "5"
six
name = "six"
icon_state = "6"
seven
name = "seven"
icon_state = "7"
eight
name = "eight"
icon_state = "8"
nine
name = "nine"
icon_state = "9"
zero
name = "zero"
icon_state = "0"

View File

@@ -0,0 +1,169 @@
//Hyper station economy. Because coding it yourself is easier than port sometimes.
/obj/machinery/atm
name = "automated teller machine"
desc = "a wall mounted electronic banking outlet for accessing your bank account."
icon = 'hyperstation/icons/obj/economy.dmi'
icon_state = "atm"
max_integrity = 250
integrity_failure = 100
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
use_power = IDLE_POWER_USE
idle_power_usage = 0
active_power_usage = 0
power_channel = ENVIRON
resistance_flags = FIRE_PROOF
var/obj/item/card/held_card
var/user = ""
light_power = 0
light_range = 7
light_color = "#ff3232"
var/pin = 0
/obj/machinery/atm/ui_interact(mob/user)
. = ..()
var/dat = {""}
dat += "<p>"
dat += "<center><span class = 'big'><p>ATM</span></span></h1>"
dat += "<b><p>Welcome to General Station 13's Automated Teller Service.</b>"
dat += "<p>"
if(!held_card)
dat += "<p>Welcome, please insert your ID to continue."
else
dat += "<p>Welcome user, <a href='byond://?src=[REF(src)];card=1'>[held_card ? user : "------"]</a><br><br>"
var/obj/item/card/id/idcard = held_card
if(idcard.registered_account)
dat += "<p>Account ID: <b>([idcard.registered_account.account_id])</b>"
else
dat += "<p>Error, this account number does not exsist, please contact your local administration.</b>"
if(idcard.registered_account)
if(!idcard.registered_account.account_pin || pin == idcard.registered_account.account_pin)
dat += "<p>Balance: <b>$[idcard.registered_account.account_balance]</b>"
//dat += "<p>Offstation Balance: <b()</b>"
dat += "<p>"
dat += "<a href='byond://?src=[REF(src)];withdraw=1'>Withdraw</A>"
dat += "<a href='byond://?src=[REF(src)];changepin=1'>Change Pin</A>"
//dat += "<a href='byond://?src=[REF(src)];settings=1'>Account Settings</A>"
dat += "<a href='byond://?src=[REF(src)];card=1'>Eject</A>"
else
dat += "<p>Please enter your bank pin to continue!"
dat += "<p>"
dat += "<a href='byond://?src=[REF(src)];pin=1'>[pin ? pin : "----"]</a><br><br>"
dat += "<p></center>"
dat += "<p>"
var/datum/browser/popup = new(user, "atm", "ATM")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state), 500,300)
popup.open()
/obj/machinery/atm/attackby(obj/item/I, mob/living/user)
if(istype(I, /obj/item/card)) //input id!
if(!held_card)
var/obj/item/card/id/idcard = I
if(!user.transferItemToLoc(I, src)) //check if you can put it in
return
held_card = idcard
user = idcard.registered_name
pin = ""
playsound(src, 'sound/machines/button.ogg', 50, FALSE)
src.ui_interact(usr)
if(istype(I, /obj/item/stack/credits)) //feed money back into the machine! dont need a pin to donate stuff.
if(held_card)
var/obj/item/stack/credits/cred = I
var/obj/item/card/id/idcard = held_card
idcard.registered_account.account_balance = (idcard.registered_account.account_balance+cred.amount)
to_chat(usr, "<span class='notice'>You insert [cred] into the ATM.</span>")
src.ui_interact(usr)
del(cred)
/obj/machinery/atm/Topic(href, href_list)
. = ..()
if(..())
return
if(href_list["card"])
if(held_card)
if(usr.CanReach(src))
playsound(src, 'sound/machines/button.ogg', 50, FALSE)
if(usr.put_in_hands(held_card))
to_chat(usr, "<span class='notice'>You take the ID out of the slot.</span>")
held_card = null
else
to_chat(usr, "<span class='warning'>The machine drops the ID onto the floor!</span>")
held_card = null
pin = ""
user = ""
if(href_list["pin"])
playsound(src, get_sfx("terminal_type"), 25, 1)
var/pininput = input(user, "Input pin", "Pin Number") as num|null
if(pininput)
if(pininput > 9999 || pininput < 1000)
to_chat(usr, "<span class='notice'>[src.name] buzzes, you must input a 4 digit number between 1000 and 9999.</span>")
return
pin = max(min( round(text2num(pininput)), 9999),1000) //4 numbers or less.
var/obj/item/card/id/idcard = held_card
if(pin == idcard.registered_account.account_pin)
to_chat(usr, "<span class='notice'>[src.name] beeps, accepting the pin.</span>")
else
to_chat(usr, "<span class='notice'>[src.name] buzzes, denying the pin.</span>")
if(href_list["changepin"])
playsound(src, get_sfx("terminal_type"), 25, 1)
var/pinchange = input(user, "Input pin", "Pin Number") as num|null
if(pinchange > 9999 || pinchange < 1000)
to_chat(usr, "<span class='warning'>[src.name], you must have a 4 digit number for a pin and be between 1000 and 9999.</span>")
return
if(pinchange)
var/pinchange2 = input(user, "Confirm pin", "Confirm pin") as num|null //time to confirm!
if(pinchange == pinchange2)
var/obj/item/card/id/idcard = held_card
idcard.registered_account.account_pin = pinchange
to_chat(usr, "<span class='notice'>[src.name] beeps, your pin has been changed to [pinchange]!.</span>")
else
to_chat(usr, "<span class='warning'>[src.name] buzzes, your pins did not match!</span>")
pin = ""
if(href_list["withdraw"])
playsound(src, get_sfx("terminal_type"), 25, 1)
if(held_card)
var/obj/item/card/id/idcard = held_card
if(idcard.registered_account)
var/amount = input(user, "Choose amount", "Withdraw") as num|null
if(amount>0)
amount = max(min( round(text2num(amount)), idcard.registered_account.account_balance),0) //make sure they aint taking out more then what they have
to_chat(usr, "<span class='notice'>The machine prints out [amount] credits.</span>")
idcard.registered_account.account_balance = (idcard.registered_account.account_balance-amount) //subtract the amount they took out.
var/obj/item/stack/credits/C = new /obj/item/stack/credits/(loc)
C.amount = amount
if(usr.put_in_hands(C))
to_chat(usr, "<span class='notice'>You take [C] out of the ATM.</span>")
src.ui_interact(usr)
//Money, Well, get back, I'm all right Jack, Keep your hands off of my stack.
//making our own currency, just to stop exploits (for now)
/obj/item/stack/credits
name = "credits"
singular_name = "credit"
desc = "Legal tender, a bundle of shiny metalic looking notes."
icon = 'hyperstation/icons/obj/economy.dmi'
icon_state = "cash"
amount = 1
max_amount = 99999999
throwforce = 0
throw_speed = 2
throw_range = 2
w_class = WEIGHT_CLASS_TINY
full_w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
var/value = 1

View File

@@ -0,0 +1,392 @@
//Hyperstation 13 fleshlight
//Humbley request this doesnt get ported to other code bases, we strive to make things unique on our server and we dont have alot of coders
//but if you absolutely must. please give us some credit~ <3
//made by quotefox
/obj/item/fleshlight
name = "fleshlight"
desc = "A sex toy disguised as a flashlight, used to stimulate someones penis, complete with colour changing sleeve."
icon = 'hyperstation/icons/obj/fleshlight.dmi'
icon_state = "fleshlight_base"
item_state = "fleshlight"
w_class = WEIGHT_CLASS_SMALL
var/sleevecolor = "#ffcbd4" //pink
price = 8
var/mutable_appearance/sleeve
var/inuse = 0
/obj/item/fleshlight/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-Click \the [src.name] to customize it.</span>"
/obj/item/fleshlight/Initialize(mapload)
. = ..()
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "vagina")
sleeve.color = sleevecolor
add_overlay(sleeve)
/obj/item/fleshlight/AltClick(mob/user)
. = ..()
var/style = input(usr, "Choose style", "Customize Fleshlight", "vagina") in list("vagina", "anus")
var/new_color = input(user, "Choose color.", "Customize Fleshlight", sleevecolor) as color|null
if(new_color)
cut_overlays()
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', style)
sleevecolor = new_color
sleeve.color = new_color
add_overlay(sleeve)
return TRUE
/obj/item/fleshlight/attack(mob/living/carbon/C, mob/living/user)
var/obj/item/organ/genital/penis/P = C.getorganslot("penis")
if(inuse == 1) //just to stop stacking and causing people to cum instantly
return
if(P&&P.is_exposed())
inuse = 1
if(!(C == user)) //if we are targeting someone else.
C.visible_message("<span class='userlove'>[user] is trying to use [src] on [C]'s penis.</span>", "<span class='userlove'>[user] is trying to use [src] on your penis.</span>")
if(!do_mob(user, C, 3 SECONDS)) //3 second delay
inuse = 0
return
//checked if not used on yourself, if not, carry on.
playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound
inuse = 0
if(!(C == user)) //lewd flavour text
C.visible_message("<span class='userlove'>[user] pumps [src] on [C]'s penis.</span>", "<span class='userlove'>[user] pumps [src] up and down on your penis.</span>")
else
user.visible_message("<span class='userlove'>[user] pumps [src] on their penis.</span>", "<span class='userlove'>You pump the fleshlight on your penis.</span>")
if(prob(30)) //30% chance to make them moan.
C.emote("moan")
C.do_jitter_animation()
C.adjust_arousal(20) //make the target more aroused.
if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna())
C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge.
return
else
to_chat(user, "<span class='notice'>You don't see anywhere to use this on.</span>")
inuse = 0
..()
//Hyperstation 13 portal fleshlight
//kinky!
/obj/item/portallight
name = "portal fleshlight"
desc = "A silver love(TM) fleshlight, used to stimulate someones penis, with bluespace tech that allows lovers to hump at a distance."
icon = 'hyperstation/icons/obj/fleshlight.dmi'
icon_state = "unpaired"
item_state = "fleshlight"
w_class = WEIGHT_CLASS_SMALL
var/partnercolor = "#ffcbd4"
var/partnerbase = "normal"
var/partnerorgan = "portal_vag"
price = 20
var/mutable_appearance/sleeve
var/mutable_appearance/organ
var/inuse = 0
var/paired = 0
var/obj/item/portalunderwear
var/useable = FALSE
var/option = ""
/obj/item/portallight/examine(mob/user)
. = ..()
if(!portalunderwear)
. += "<span class='notice'>The device is unpaired, to pair, swipe against a pair of portal panties. </span>"
else
. += "<span class='notice'>The device is paired, and awaiting input. </span>"
/obj/item/portallight/attack(mob/living/carbon/C, mob/living/user) //use portallight! nearly the same as the fleshlight apart from you have a buddy!
var/obj/item/organ/genital/penis/P = C.getorganslot("penis")
if(inuse) //just to stop stacking and causing people to cum instantly
return
if(!useable)
to_chat(user, "<span class='notice'>It seems the device has failed or your partner is not wearing their device.</span>")
if(C == user)//if your using it on yourself, more options! otherwise, just fuck.
option = input(usr, "Choose action", "Portal Fleshlight", "Fuck") in list("Fuck", "Lick", "Touch")
else
option = "Fuck"
var/obj/item/organ/genital/G
if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime error.
G = portalunderwear.loc
if(!G)
return
var/mob/living/carbon/human/M = G.owner
if(option == "Fuck"&&!P.is_exposed()) //we are trying to fuck with no penis!
to_chat(user, "<span class='notice'>You don't see anywhere to use this on.</span>")
return
else //other options dont need checks
inuse = 1
if(!(C == user)) //if we are targeting someone else.
C.visible_message("<span class='userlove'>[user] is trying to use [src] on [C]'s penis.</span>", "<span class='userlove'>[user] is trying to use [src] on your penis.</span>")
if(!do_mob(user, C, 3 SECONDS)) //3 second delay
inuse = 0
return
//checked if not used on yourself, if not, carry on.
if(option == "Fuck")
playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound for fuck.
inuse = 0
if(!(C == user))
C.visible_message("<span class='userlove'>[user] pumps [src] on [C]'s penis.</span>", "<span class='userlove'>[user] pumps [src] up and down on your penis.</span>")
else
if(option == "Fuck")
user.visible_message("<span class='userlove'>[user] pumps [src] on their penis.</span>", "<span class='userlove'>You pump the fleshlight on your penis.</span>")
if(option == "Lick")
user.visible_message("<span class='userlove'>[user] licks into [src].</span>", "<span class='userlove'>You lick into [src].</span>")
if(option == "Touch")
user.visible_message("<span class='userlove'>[user] touches softly against [src].</span>", "<span class='userlove'>You touch softly on [src].</span>")
if(prob(30)) //30% chance to make your partner moan.
M.emote("moan")
if(option == "Fuck")// normal fuck
to_chat(M, "<span class='love'>You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [G.name].</span>")//message your partner, and kinky!
if(prob(30)) //30% chance to make them moan.
C.emote("moan")
if(prob(30)) //30% chance to make your partner moan.
M.emote("moan")
C.adjust_arousal(20)
M.adjust_arousal(20)
M.do_jitter_animation() //make your partner shake too!
if (M.getArousalLoss() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~
if(G.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill
M.mob_climax_outside(G, spillage = TRUE)
else
M.mob_climax_outside(G, spillage = FALSE)
if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna())
var/mob/living/carbon/human/O = C
if( (P.condom == 1) || (P.sounding == 1)) //If coundomed and/or sounded, do not fire impreg chance
O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE)
else //Else, fire impreg chance
if(G.name == "vagina") //no more spontaneous impregnations through the butt!
O.mob_climax_partner(P, M, FALSE, TRUE, FALSE, TRUE)
else
O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE)
if(option == "Lick")
to_chat(M, "<span class='love'>You feel a tongue lick you through the portal against your [G.name].</span>")
M.adjust_arousal(10)
if(option == "Touch")
to_chat(M, "<span class='love'>You feel someone touching your [G.name] through the portal.</span>")
M.adjust_arousal(5)
return
..()
/obj/item/portallight/proc/updatesleeve()
//get their looks and vagina colour!
cut_overlays()//remove current overlays
var/obj/item/organ/genital/G
if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime.
G = portalunderwear.loc
if(!G)
useable = FALSE
return
var/mob/living/carbon/human/H = G.owner
if(H) //if the portal panties are on someone.
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_normal")
if(H.dna.species.name == "Lizardperson") // lizard nerd
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_lizard")
if(H.dna.species.name == "Slimeperson") // slime nerd
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_slime")
if(H.dna.species.name == "Avian") // bird nerd
sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_avian")
sleeve.color = "#" + H.dna.features["mcolor"]
add_overlay(sleeve)
if(G.name == "vagina")
organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag")
organ.color = portalunderwear.loc.color
if(G.name == "anus")
organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_anus")
organ.color = "#" + H.dna.features["mcolor"]
useable = TRUE
add_overlay(organ)
else
useable = FALSE
//Hyperstation 13 portal underwear
//can be attached to vagina or anus, just like the vibrator, still requires pairing with the portallight
/obj/item/portalpanties
name = "portal panties"
desc = "A silver love(TM) pair of portal underwear, with bluespace tech allows lovers to hump at a distance. Needs to be paired with a portal fleshlight before use."
icon = 'hyperstation/icons/obj/fleshlight.dmi'
icon_state = "portalpanties"
item_state = "fleshlight"
w_class = WEIGHT_CLASS_SMALL
var/obj/item/portallight
var/attached = FALSE
var/shapetype = "vagina"
/obj/item/portalpanties/examine(mob/user)
. = ..()
if(!portallight)
. += "<span class='notice'>The device is unpaired, to pair, swipe the fleshlight against this pair of portal panties(TM). </span>"
else
. += "<span class='notice'>The device is paired, and awaiting attachment. </span>"
/obj/item/portalpanties/attackby(obj/item/I, mob/living/user) //pairing
if(istype(I, /obj/item/portallight))
var/obj/item/portallight/P = I
if(!P.portalunderwear) //make sure it aint linked to someone else
portallight = P //pair the fleshlight
P.portalunderwear = src //pair the panties on the fleshlight.
P.icon_state = "paired" //we are paired!
playsound(src, 'sound/machines/ping.ogg', 50, FALSE)
to_chat(user, "<span class='notice'>[P] has been linked up successfully.</span>")
else
to_chat(user, "<span class='notice'>[P] has already been linked to another pair of underwear.</span>")
else
..() //just allows people to hit it with other objects, if they so wished.
/obj/item/portalpanties/attack(mob/living/carbon/C, mob/living/user)
if(!portallight) //we arent paired yet! noobie trap, let them know.
to_chat(user, "<span class='warning'>[src] can only be attached once paired with a portal fleshlight.</span>")
return
var/obj/item/organ/genital/picked_organ
var/mob/living/carbon/human/S = user
var/mob/living/carbon/human/T = C
picked_organ = S.target_genitals(T)
if(picked_organ)
C.visible_message("<span class='warning'>[user] is trying to attach [src] to [T]!</span>",\
"<span class='warning'>[user] is trying to put [src] on you!</span>")
if(!do_mob(user, C, 3 SECONDS))//warn them and have a delay of 5 seconds to apply.
return
if((picked_organ.name == "vagina")||(picked_organ.name == "anus")) //only fits on a vagina or anus
src.shapetype = picked_organ.name
if(!picked_organ.equipment)
to_chat(user, "<span class='love'>You wrap [src] around [T]'s [picked_organ.name].</span>")
else
to_chat(user, "<span class='notice'>They already have [picked_organ.equipment.name] there.</span>")
return
if(!user.transferItemToLoc(src, picked_organ)) //check if you can put it in
return
src.attached = TRUE
picked_organ.equipment = src
var/obj/item/portallight/P = portallight
//now we need to send what they look like, but saddly if the person changes colour for what ever reason, it wont update. but dont tell people shh.
if(P) //just to make sure
P.updatesleeve()
else
to_chat(user, "<span class='warning'>[src] can only be attached to a vagina or anus.</span>")
return
else
to_chat(user, "<span class='notice'>You don't see anywhere to attach this.</span>")
/obj/item/portalpanties/proc/remove() //if taken off update it.
if(portallight)
var/obj/item/portallight/P = portallight
P.updatesleeve()
/obj/item/storage/box/portallight
name = "Portal Fleshlight and Underwear"
icon = 'hyperstation/icons/obj/fleshlight.dmi'
desc = "A small silver box with Silver Love Co embossed."
icon_state = "box"
price = 15
// portal fleshlight box
/obj/item/storage/box/portallight/PopulateContents()
new /obj/item/portallight/(src)
new /obj/item/portalpanties/(src)
new /obj/item/paper/fluff/portallight(src)
/obj/item/paper/fluff/portallight
name = "Portal Fleshlight Instructions"
info = "Thank you for purchasing the Silver Love Portal Fleshlight!<BR>To use, simply register your new portal fleshlight with the provided underwear to link them together. The ask your lover to wear the underwear.<BR>Have fun lovers,<BR><BR>Wilhelmina Steiner."
//Happy Halloween!
//Can be crafted with a knife and a pumpkin in the crafting menu (misc category).
//I have no regrets.
// /obj/item/twohanded/required/cumpkin
// name = "Cumpkin"
// desc = "A carved pumpkin with a suspicious inviting hole behind it, maybe you could 'use' it for a while..."
// icon = 'hyperstation/icons/obj/fleshlight.dmi'
// icon_state = "cumpkin"
// item_state = "cumpkin"
// lefthand_file = 'hyperstation/icons/mob/item_lefthand.dmi'
// righthand_file = 'hyperstation/icons/mob/item_righthand.dmi'
// w_class = WEIGHT_CLASS_SMALL
// price = 10
// var/inuse = 0
// /obj/item/twohanded/required/cumpkin/attack(mob/living/carbon/C, mob/living/user)
// var/obj/item/organ/genital/penis/P = C.getorganslot("penis")
// if(inuse == 1) //just to stop stacking and causing people to cum instantly
// return
// if(P&&P.is_exposed())
// inuse = 1
// if(!(C == user)) //if we are targeting someone else.
// C.visible_message("<span class='userlove'>[user] is trying to use [src] on [C]'s penis.</span>", "<span class='userlove'>[user] is trying to use [src] on your penis.</span>")
// if(!do_mob(user, C, 3 SECONDS)) //3 second delay
// inuse = 0
// return
// //checked if not used on yourself, if not, carry on.
// playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound
// inuse = 0
// if(!(C == user)) //lewd flavour text
// C.visible_message("<span class='userlove'>[user] pumps [src] on [C]'s penis.</span>", "<span class='userlove'>[user] pumps [src] up and down on your penis.</span>")
// else
// user.visible_message("<span class='userlove'>[user] pumps [src] on their penis.</span>", "<span class='userlove'>You pump the cumpkin on your penis.</span>")
// if(prob(30)) //30% chance to make them moan.
// C.emote("moan")
// C.do_jitter_animation()
// C.adjust_arousal(20) //make the target more aroused.
// if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna())
// C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge.
// return
// else
// to_chat(user, "<span class='notice'>You don't see anywhere to use this on.</span>")
// inuse = 0
// ..()
// /datum/crafting_recipe/cumpkin
// name = "Cumpkin"
// time = 30
// reqs = list(/obj/item/reagent_containers/food/snacks/grown/pumpkin = 1)
// tools = list(/obj/item/kitchen/knife)
// result = /obj/item/twohanded/required/cumpkin
// category = CAT_MISC

View File

@@ -0,0 +1,17 @@
/obj/structure/medscreen/
name = "medical screen"
desc = "No peaking now!"
icon_state = "screen"
icon = 'hyperstation/icons/obj/medical.dmi'
anchored = TRUE
resistance_flags = FLAMMABLE
max_integrity = 100
integrity_failure = 30
var/buildstacktype = /obj/item/stack/sheet/metal
var/buildstackamount = 2
density = TRUE
/obj/structure/medscreen/Moved()
. = ..()
if(has_gravity())
playsound(src, 'sound/effects/roll.ogg', 100, 1)

Some files were not shown because too many files have changed in this diff Show More