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
@@ -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>- 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)
= 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']###$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"
@@ -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>")
@@ -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"
+162
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>")
@@ -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"
@@ -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)
@@ -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