[user] stops feeding \the [O] into \the [src]!/span>")
+
+ else ..()
+
+/obj/item/toy/toy_xeno
+ icon = 'icons/obj/toy_vr.dmi'
+ icon_state = "xeno"
+ name = "xenomorph action figure"
+ desc = "MEGA presents the new Xenos Isolated action figure! Comes complete with realistic sounds! Pull back string to use."
+ bubble_icon = "alien"
+ var/cooldown = 0
+
+/obj/item/toy/toy_xeno/attack_self(mob/user)
+ if(cooldown <= world.time)
+ cooldown = (world.time + 50) //5 second cooldown
+ user.visible_message("[user] pulls back the string on [src].")
+ icon_state = "[initial(icon_state)]cool"
+ sleep(5)
+ atom_say("Hiss!")
+ var/list/possible_sounds = list('sound/voice/hiss1.ogg', 'sound/voice/hiss2.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss4.ogg')
+ playsound(get_turf(src), pick(possible_sounds), 50, 1)
+ spawn(45)
+ if(src)
+ icon_state = "[initial(icon_state)]"
+ else
+ to_chat(user, "The string on [src] hasn't rewound all the way!")
+ return
+
+/obj/item/toy/russian_revolver
+ name = "russian revolver"
+ desc = "For fun and games!"
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "detective"
+ item_state = "gun"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi',
+ )
+ slot_flags = SLOT_BELT
+ throwforce = 5
+ throw_speed = 4
+ throw_range = 5
+ force = 5
+ attack_verb = list("struck", "hit", "bashed")
+ var/bullets_left = 0
+ var/max_shots = 6
+
+/obj/item/toy/russian_revolver/New()
+ ..()
+ spin_cylinder()
+
+/obj/item/toy/russian_revolver/attack_self(mob/user)
+ if(!bullets_left)
+ user.visible_message("[user] loads a bullet into [src]'s cylinder before spinning it.")
+ spin_cylinder()
+ else
+ user.visible_message("[user] spins the cylinder on [src]!")
+ playsound(src, 'sound/weapons/revolver_spin.ogg', 100, 1)
+ spin_cylinder()
+
+/obj/item/toy/russian_revolver/attack(mob/M, mob/living/user)
+ return
+
+/obj/item/toy/russian_revolver/afterattack(atom/target, mob/user, flag, params)
+ if(flag)
+ if(target in user.contents)
+ return
+ if(!ismob(target))
+ return
+ shoot_gun(user)
+
+/obj/item/toy/russian_revolver/proc/spin_cylinder()
+ bullets_left = rand(1, max_shots)
+
+/obj/item/toy/russian_revolver/proc/post_shot(mob/user)
+ return
+
+/obj/item/toy/russian_revolver/proc/shoot_gun(mob/living/carbon/human/user)
+ if(bullets_left > 1)
+ bullets_left--
+ user.visible_message("*click*")
+ playsound(src, 'sound/weapons/empty.ogg', 50, 1)
+ return FALSE
+ if(bullets_left == 1)
+ bullets_left = 0
+ var/zone = "head"
+ if(!(user.has_organ(zone))) // If they somehow don't have a head.
+ zone = "chest"
+ playsound(src, 'sound/effects/snap.ogg', 50, 1)
+ user.visible_message("[src] goes off!")
+ shake_camera(user, 2, 1)
+ user.Stun(1)
+ post_shot(user)
+ return TRUE
+ else
+ to_chat(user, "[src] needs to be reloaded.")
+ return FALSE
+
+/obj/item/toy/russian_revolver/trick_revolver
+ name = "\improper .357 revolver"
+ desc = "A suspicious revolver. Uses .357 ammo."
+ icon = 'icons/obj/toy_vr.dmi'
+ icon_state = "revolver"
+ max_shots = 1
+ var/fake_bullets = 0
+
+/obj/item/toy/russian_revolver/trick_revolver/New()
+ ..()
+ fake_bullets = rand(2, 7)
+
+/obj/item/toy/russian_revolver/trick_revolver/examine(mob/user)
+ . = ..()
+ . += "Has [fake_bullets] round\s remaining."
+ . += "[fake_bullets] of those are live rounds."
+
+/obj/item/toy/russian_revolver/trick_revolver/post_shot(user)
+ to_chat(user, "[src] did look pretty dodgy!")
+ playsound(src, 'sound/items/confetti.ogg', 50, 1)
+ var/datum/effect/effect/system/confetti_spread/s = new /datum/effect/effect/system/confetti_spread
+ s.set_up(5, 1, src)
+ s.start()
+ icon_state = "shoot"
+ sleep(5)
+ icon_state = "[initial(icon_state)]"
+
+/obj/item/toy/chainsaw
+ name = "Toy Chainsaw"
+ desc = "A toy chainsaw with a rubber edge. Ages 8 and up"
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "chainsaw0"
+ force = 0
+ throwforce = 0
+ throw_speed = 4
+ throw_range = 20
+ attack_verb = list("sawed", "cut", "hacked", "carved", "cleaved", "butchered", "felled", "timbered")
+ var/cooldown = 0
+
+/obj/item/toy/chainsaw/attack_self(mob/user as mob)
+ if(!cooldown)
+ playsound(user, 'sound/weapons/chainsaw_startup.ogg', 10, 0)
+ cooldown = 1
+ addtimer(CALLBACK(src, .proc/cooldownreset), 50)
+ return ..()
+
+/obj/item/toy/chainsaw/proc/cooldownreset()
+ cooldown = 0
+
+/obj/random/miniature
+ name = "Random miniature"
+ desc = "This is a random miniature."
+ icon = 'icons/obj/toy.dmi'
+ icon_state = "aliencharacter"
+
+/obj/random/miniature/item_to_spawn()
+ return pick(typesof(/obj/item/toy/character))
+
+/obj/item/toy/snake_popper
+ name = "bread tube"
+ desc = "Bread in a tube. Chewy...and surprisingly tasty."
+ description_fluff = "This is the product that brought Centauri Provisions into the limelight. A product of the earliest extrasolar colony of Heaven, the Bread Tube, while bland, contains all the nutrients a spacer needs to get through the day and is decidedly edible when compared to some of its competitors. Due to the high-fructose corn syrup content of NanoTrasen's own-brand bread tubes, many jurisdictions classify them as a confectionary."
+ icon = 'icons/obj/toy_vr.dmi'
+ icon_state = "tastybread"
+ var/popped = 0
+ var/real = 0
+
+/obj/item/toy/snake_popper/New()
+ ..()
+ if(prob(0.1))
+ real = 1
+
+/obj/item/toy/snake_popper/attack_self(mob/user as mob)
+ if(!popped)
+ to_chat(user, "A snake popped out of [src]!")
+ if(real == 0)
+ var/obj/item/toy/C = new /obj/item/toy/plushie/snakeplushie(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ if(real == 1)
+ var/mob/living/simple_mob/C = new /mob/living/simple_mob/animal/passive/snake(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ if(real == 2)
+ var/mob/living/simple_mob/C = new /mob/living/simple_mob/vore/aggressive/giant_snake(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ playsound(src, 'sound/items/confetti.ogg', 50, 0)
+ icon_state = "tastybread_popped"
+ popped = 1
+ user.Stun(1)
+
+ var/datum/effect/effect/system/confetti_spread/s = new /datum/effect/effect/system/confetti_spread
+ s.set_up(5, 1, src)
+ s.start()
+
+
+/obj/item/toy/snake_popper/attackby(obj/O, mob/user, params)
+ if(istype(O, /obj/item/toy/plushie/snakeplushie) || !real)
+ if(popped && !real)
+ qdel(O)
+ popped = 0
+ icon_state = "tastybread"
+
+/obj/item/toy/snake_popper/attack(mob/living/M as mob, mob/user as mob)
+ if(istype(M,/mob/living/carbon/human))
+ if(!popped)
+ to_chat(user, "A snake popped out of [src]!")
+ if(real == 0)
+ var/obj/item/toy/C = new /obj/item/toy/plushie/snakeplushie(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ if(real == 1)
+ var/mob/living/simple_mob/C = new /mob/living/simple_mob/animal/passive/snake(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ if(real == 2)
+ var/mob/living/simple_mob/C = new /mob/living/simple_mob/vore/aggressive/giant_snake(get_turf(loc))
+ C.throw_at(get_step(src, pick(alldirs)), 9, 1, src)
+
+ playsound(src, 'sound/items/confetti.ogg', 50, 0)
+ icon_state = "tastybread_popped"
+ popped = 1
+ user.Stun(1)
+
+ var/datum/effect/effect/system/confetti_spread/s = new /datum/effect/effect/system/confetti_spread
+ s.set_up(5, 1, src)
+ s.start()
+
+/obj/item/toy/snake_popper/emag_act(remaining_charges, mob/user)
+ if(real != 2)
+ real = 2
+ to_chat(user, "You short out the bluespace refill system of [src].")
+
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/ships.dm b/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
index dd37bc2519e..7f423165a75 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
@@ -6,7 +6,7 @@
name = T_BOARD("point defense battery")
board_type = new /datum/frame/frame_types/machine
desc = "Control systems for a Kuiper pattern point defense battery. Aim away from vessel."
- build_path = /obj/machinery/pointdefense
+ build_path = /obj/machinery/power/pointdefense
origin_tech = list(TECH_ENGINEERING = 3, TECH_COMBAT = 2)
req_components = list(
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser = 1,
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index 0f7405096dc..1dca4b4caf6 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -176,17 +176,6 @@ var/last_chew = 0
/obj/item/weapon/handcuffs/cable/white
color = "#FFFFFF"
-/obj/item/weapon/handcuffs/cable/attackby(var/obj/item/I, mob/user as mob)
- ..()
- if(istype(I, /obj/item/stack/rods))
- var/obj/item/stack/rods/R = I
- if (R.use(1))
- var/obj/item/weapon/material/wirerod/W = new(get_turf(user))
- user.put_in_hands(W)
- to_chat(user, "You wrap the cable restraint around the top of the rod.")
- qdel(src)
- update_icon(user)
-
/obj/item/weapon/handcuffs/cyborg
dispenser = 1
diff --git a/code/game/objects/items/weapons/improvised_components.dm b/code/game/objects/items/weapons/improvised_components.dm
index bfd059f74d6..928a7c1a5d2 100644
--- a/code/game/objects/items/weapons/improvised_components.dm
+++ b/code/game/objects/items/weapons/improvised_components.dm
@@ -38,33 +38,3 @@
qdel(W)
qdel(src)
return
-
-/obj/item/weapon/material/wirerod
- name = "wired rod"
- desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit."
- icon_state = "wiredrod"
- item_state = "rods"
- force = 8
- throwforce = 10
- w_class = ITEMSIZE_NORMAL
- attack_verb = list("hit", "bludgeoned", "whacked", "bonked")
- force_divisor = 0.1
- thrown_force_divisor = 0.1
-
-/obj/item/weapon/material/wirerod/attackby(var/obj/item/I, mob/user as mob)
- ..()
- var/obj/item/finished
- if(istype(I, /obj/item/weapon/material/shard) || istype(I, /obj/item/weapon/material/butterflyblade))
- var/obj/item/weapon/material/tmp_shard = I
- finished = new /obj/item/weapon/material/twohanded/spear(get_turf(user), tmp_shard.material.name)
- to_chat(user, "You fasten \the [I] to the top of the rod with the cable.")
- else if(I.is_wirecutter())
- finished = new /obj/item/weapon/melee/baton/cattleprod(get_turf(user))
- to_chat(user, "You fasten the wirecutters to the top of the rod with the cable, prongs outward.")
- if(finished)
- user.drop_from_inventory(src)
- user.drop_from_inventory(I)
- qdel(I)
- qdel(src)
- user.put_in_hands(finished)
- update_icon(user)
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm
index bfa8b616805..7dbb927f853 100644
--- a/code/game/objects/items/weapons/material/misc.dm
+++ b/code/game/objects/items/weapons/material/misc.dm
@@ -74,14 +74,12 @@
/obj/item/weapon/material/snow/snowball/attack_self(mob/user as mob)
if(user.a_intent == I_HURT)
- //visible_message("[user] has smashed the snowball in their hand!", "You smash the snowball in your hand.")
- to_chat(user, "You smash the snowball in your hand.")
+ to_chat(user, SPAN_NOTICE("You smash the snowball in your hand."))
var/atom/S = new /obj/item/stack/material/snow(user.loc)
qdel(src)
user.put_in_hands(S)
else
- //visible_message("[user] starts compacting the snowball.", "You start compacting the snowball.")
- to_chat(user, "You start compacting the snowball.")
+ to_chat(user, SPAN_NOTICE("You start compacting the snowball."))
if(do_after(user, 2 SECONDS))
var/atom/S = new /obj/item/weapon/material/snow/snowball/reinforced(user.loc)
qdel(src)
diff --git a/code/game/objects/items/weapons/melee/misc_vr.dm b/code/game/objects/items/weapons/melee/misc_vr.dm
new file mode 100644
index 00000000000..fd228ba9c42
--- /dev/null
+++ b/code/game/objects/items/weapons/melee/misc_vr.dm
@@ -0,0 +1,16 @@
+/obj/item/weapon/melee/rapier
+ name = "rapier"
+ desc = "A gleaming steel blade with a gold handguard and inlayed with an outstanding red gem."
+ icon = 'icons/obj/weapons_vr.dmi'
+ icon_state = "rapier"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi',
+ )
+ force = 15
+ throwforce = 10
+ w_class = ITEMSIZE_NORMAL
+ sharp = 1
+ edge = 0
+ attack_verb = list("stabbed", "lunged at", "dextrously struck", "sliced", "lacerated", "impaled", "diced", "charioted")
+ hitsound = 'sound/weapons/bladeslice.ogg'
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index 5dc7f83da8b..116d57fd2ed 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -71,6 +71,8 @@
/obj/item/weapon/tape_roll,
/obj/item/device/integrated_electronics/wirer,
/obj/item/device/integrated_electronics/debugger, //Vorestation edit adding debugger to toolbelt can hold list
+ /obj/item/weapon/shovel/spade, //VOREStation edit. If it can hold minihoes and hatchers, why not the gardening spade?
+ /obj/item/stack/nanopaste //VOREStation edit. Think of it as a tube of superglue. Belts hold that all the time.
)
/obj/item/weapon/storage/belt/utility/full
@@ -349,7 +351,8 @@
/obj/item/device/megaphone,
/obj/item/taperoll,
/obj/item/weapon/reagent_containers/spray,
- /obj/item/weapon/soap
+ /obj/item/weapon/soap,
+ /obj/item/device/lightreplacer //VOREStation edit
)
/obj/item/weapon/storage/belt/archaeology
diff --git a/code/game/objects/items/weapons/tools/crowbar.dm b/code/game/objects/items/weapons/tools/crowbar.dm
index f1ff2dd642f..de84168ddf7 100644
--- a/code/game/objects/items/weapons/tools/crowbar.dm
+++ b/code/game/objects/items/weapons/tools/crowbar.dm
@@ -20,9 +20,7 @@
drop_sound = 'sound/items/drop/crowbar.ogg'
pickup_sound = 'sound/items/pickup/crowbar.ogg'
toolspeed = 1
-
-/obj/item/weapon/tool/crowbar/is_crowbar()
- return TRUE
+ tool_qualities = list(TOOL_CROWBAR)
/obj/item/weapon/tool/crowbar/red
icon = 'icons/obj/tools.dmi'
diff --git a/code/game/objects/items/weapons/tools/screwdriver.dm b/code/game/objects/items/weapons/tools/screwdriver.dm
index 6ea222b6ac5..5252aa63ba1 100644
--- a/code/game/objects/items/weapons/tools/screwdriver.dm
+++ b/code/game/objects/items/weapons/tools/screwdriver.dm
@@ -21,6 +21,7 @@
attack_verb = list("stabbed")
sharp = 1
toolspeed = 1
+ tool_qualities = list(TOOL_SCREWDRIVER)
var/random_color = TRUE
/obj/item/weapon/tool/screwdriver/suicide_act(mob/user)
@@ -67,10 +68,6 @@
M = user
return eyestab(M,user)
-/obj/item/weapon/tool/screwdriver/is_screwdriver()
- return TRUE
-
-
/datum/category_item/catalogue/anomalous/precursor_a/alien_screwdriver
name = "Precursor Alpha Object - Hard Light Torgue Tool"
desc = "This appears to be a tool, with a solid handle, and a thin hard light \
diff --git a/code/game/objects/items/weapons/tools/weldingtool.dm b/code/game/objects/items/weapons/tools/weldingtool.dm
index bd5b5a57c34..af92a574545 100644
--- a/code/game/objects/items/weapons/tools/weldingtool.dm
+++ b/code/game/objects/items/weapons/tools/weldingtool.dm
@@ -21,6 +21,8 @@
//R&D tech level
origin_tech = list(TECH_ENGINEERING = 1)
+
+ tool_qualities = list(TOOL_WELDER)
//Welding tool specific stuff
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
diff --git a/code/game/objects/items/weapons/tools/wirecutters.dm b/code/game/objects/items/weapons/tools/wirecutters.dm
index 1ef130e13f8..36459852ef2 100644
--- a/code/game/objects/items/weapons/tools/wirecutters.dm
+++ b/code/game/objects/items/weapons/tools/wirecutters.dm
@@ -22,6 +22,7 @@
sharp = 1
edge = 1
toolspeed = 1
+ tool_qualities = list(TOOL_WIRECUTTER)
var/random_color = TRUE
/obj/item/weapon/tool/wirecutters/New()
@@ -43,10 +44,6 @@
else
..()
-/obj/item/weapon/tool/wirecutters/is_wirecutter()
- return TRUE
-
-
/datum/category_item/catalogue/anomalous/precursor_a/alien_wirecutters
name = "Precursor Alpha Object - Wire Seperator"
desc = "An object appearing to have a tool shape. It has two handles, and two \
diff --git a/code/game/objects/items/weapons/tools/wrench.dm b/code/game/objects/items/weapons/tools/wrench.dm
index 300a3c8c6b8..220ddb667da 100644
--- a/code/game/objects/items/weapons/tools/wrench.dm
+++ b/code/game/objects/items/weapons/tools/wrench.dm
@@ -17,9 +17,7 @@
toolspeed = 1
drop_sound = 'sound/items/drop/wrench.ogg'
pickup_sound = 'sound/items/pickup/wrench.ogg'
-
-/obj/item/weapon/tool/wrench/is_wrench()
- return TRUE
+ tool_qualities = list(TOOL_WRENCH)
/obj/item/weapon/tool/wrench/cyborg
name = "automatic wrench"
diff --git a/code/game/objects/random/_random.dm b/code/game/objects/random/_random.dm
index 7b9cc60617f..e9beda6de10 100644
--- a/code/game/objects/random/_random.dm
+++ b/code/game/objects/random/_random.dm
@@ -9,25 +9,36 @@
// creates a new object and deletes itself
/obj/random/Initialize()
..()
- if (!prob(spawn_nothing_percentage))
- spawn_item()
+ if(!prob(spawn_nothing_percentage))
+ try_spawn_item()
return INITIALIZE_HINT_QDEL
+/obj/random/proc/try_spawn_item()
+ var/atom/result = spawn_item()
+ if(istype(result) && !QDELETED(result))
+ apply_adjustments(result)
+ else if(islist(result))
+ for(var/atom/A in result)
+ if(!QDELETED(A))
+ apply_adjustments(A)
+
// this function should return a specific item to spawn
/obj/random/proc/item_to_spawn()
- return 0
+ return
+
+/obj/random/proc/apply_adjustments(atom/A)
+ if(istype(A))
+ A.pixel_x = pixel_x
+ A.pixel_y = pixel_y
+ A.set_dir(dir)
/obj/random/drop_location()
- return drop_get_turf? get_turf(src) : ..()
+ return drop_get_turf ? get_turf(src) : ..()
// creates the random item
/obj/random/proc/spawn_item()
var/build_path = item_to_spawn()
-
- var/atom/A = new build_path(drop_location())
- if(pixel_x || pixel_y)
- A.pixel_x = pixel_x
- A.pixel_y = pixel_y
+ return new build_path(drop_location())
var/list/random_junk_
var/list/random_useful_
@@ -82,7 +93,7 @@ var/list/random_useful_
/obj/random/multiple/spawn_item()
var/list/things_to_make = item_to_spawn()
for(var/new_type in things_to_make)
- new new_type(src.loc)
+ LAZYADD(., new new_type(src.loc))
/*
// Multi Point Spawn
diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm
index f7a3b499331..5b160c1b905 100644
--- a/code/game/objects/random/misc.dm
+++ b/code/game/objects/random/misc.dm
@@ -266,7 +266,6 @@
prob(4);/obj/item/weapon/material/butterfly,
prob(6);/obj/item/weapon/material/butterflyblade,
prob(6);/obj/item/weapon/material/butterflyhandle,
- prob(6);/obj/item/weapon/material/wirerod,
prob(2);/obj/item/weapon/material/butterfly/switchblade,
prob(2);/obj/item/clothing/gloves/knuckledusters,
prob(1);/obj/item/weapon/material/knife/tacknife,
diff --git a/code/game/objects/random/mob_vr.dm b/code/game/objects/random/mob_vr.dm
index 3db11f0626e..fdb41ada596 100644
--- a/code/game/objects/random/mob_vr.dm
+++ b/code/game/objects/random/mob_vr.dm
@@ -145,7 +145,6 @@
/obj/random/cargopod/item_to_spawn()
return pick(prob(10);/obj/item/weapon/contraband/poster,\
prob(8);/obj/item/weapon/haircomb,\
- prob(6);/obj/item/weapon/material/wirerod,\
prob(6);/obj/item/weapon/storage/pill_bottle/paracetamol,\
prob(6);/obj/item/weapon/material/butterflyblade,\
prob(6);/obj/item/weapon/material/butterflyhandle,\
diff --git a/code/game/objects/structures/crates_lockers/closets/misc_vr.dm b/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
index aa7a55dff6f..6be3942fd7e 100644
--- a/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
+++ b/code/game/objects/structures/crates_lockers/closets/misc_vr.dm
@@ -124,7 +124,7 @@
/obj/item/weapon/storage/backpack/parachute,
/obj/item/weapon/material/knife/tacknife/survival,
/obj/item/weapon/gun/energy/locked/frontier/holdout,
- /obj/item/clothing/head/pilot,
+ /obj/item/clothing/head/ompilot,
/obj/item/clothing/under/rank/pilot1,
/obj/item/clothing/suit/storage/toggle/bomber/pilot,
/obj/item/clothing/shoes/boots/winter/explorer,
@@ -176,7 +176,6 @@
/obj/item/stack/marker_beacon/thirty,
/obj/item/weapon/material/knife/tacknife/survival,
/obj/item/weapon/material/knife/machete/deluxe,
- /obj/item/weapon/gun/energy/locked/frontier/carbine,
/obj/item/clothing/accessory/holster/machete,
/obj/random/explorer_shield,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood,
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security_vr.dm b/code/game/objects/structures/crates_lockers/closets/secure/security_vr.dm
index af14ca3e30c..3d7e899dc22 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security_vr.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security_vr.dm
@@ -178,3 +178,19 @@
if(prob(75))
new /obj/item/weapon/storage/backpack/dufflebag/sec(src)
return ..()
+
+/obj/structure/closet/secure_closet/captains
+ starts_with = list(
+ /obj/item/weapon/storage/backpack/dufflebag/captain,
+ /obj/item/clothing/head/helmet,
+ /obj/item/clothing/suit/storage/vest,
+ /obj/item/weapon/cartridge/captain,
+ /obj/item/weapon/storage/lockbox/medal,
+ /obj/item/device/radio/headset/heads/captain,
+ /obj/item/device/radio/headset/heads/captain/alt,
+ /obj/item/weapon/gun/energy/gun,
+ /obj/item/weapon/melee/telebaton,
+ /obj/item/device/flash,
+ /obj/item/weapon/storage/box/ids,
+ /obj/item/weapon/melee/rapier,
+ /obj/item/clothing/accessory/holster/machete/rapier)
\ No newline at end of file
diff --git a/code/game/objects/structures/ghost_pods/event_vr.dm b/code/game/objects/structures/ghost_pods/event_vr.dm
index 4fface95d1b..7a04e0ea2ce 100644
--- a/code/game/objects/structures/ghost_pods/event_vr.dm
+++ b/code/game/objects/structures/ghost_pods/event_vr.dm
@@ -10,19 +10,37 @@
invisibility = INVISIBILITY_OBSERVER
spawn_active = TRUE
var/announce_prob = 35
- var/list/possible_mobs = list("Space Bumblebee" = /mob/living/simple_mob/vore/bee,
- "Voracious Lizard" = /mob/living/simple_mob/vore/aggressive/dino,
- "Giant Frog" = /mob/living/simple_mob/vore/aggressive/frog,
- "Giant Rat" = /mob/living/simple_mob/vore/aggressive/rat,
- "Juvenile Solargrub" = /mob/living/simple_mob/vore/solargrub,
+ var/list/possible_mobs = list("Rabbit" = /mob/living/simple_mob/vore/rabbit,
"Red Panda" = /mob/living/simple_mob/vore/redpanda,
"Fennec" = /mob/living/simple_mob/vore/fennec,
"Fennix" = /mob/living/simple_mob/vore/fennix,
+ "Space Bumblebee" = /mob/living/simple_mob/vore/bee,
+ "Space Bear" = /mob/living/simple_mob/animal/space/bear,
+ "Voracious Lizard" = /mob/living/simple_mob/vore/aggressive/dino,
+ "Giant Frog" = /mob/living/simple_mob/vore/aggressive/frog,
+ "Giant Rat" = /mob/living/simple_mob/vore/aggressive/rat,
"Jelly Blob" = /mob/living/simple_mob/animal/space/jelly,
"Wolf" = /mob/living/simple_mob/animal/wolf,
+ "Juvenile Solargrub" = /mob/living/simple_mob/vore/solargrub,
"Sect Queen" = /mob/living/simple_mob/vore/sect_queen,
"Sect Drone" = /mob/living/simple_mob/vore/sect_drone,
"Defanged Xenomorph" = /mob/living/simple_mob/vore/xeno_defanged,
+ "Panther" = /mob/living/simple_mob/vore/aggressive/panther,
+ "Giant Snake" = /mob/living/simple_mob/vore/aggressive/giant_snake,
+ "Deathclaw" = /mob/living/simple_mob/vore/aggressive/deathclaw,
+ "Otie" = /mob/living/simple_mob/otie,
+ "Mutated Otie" =/mob/living/simple_mob/otie/feral,
+ "Red Otie" = /mob/living/simple_mob/otie/red,
+ "Corrupt Hound" = /mob/living/simple_mob/vore/aggressive/corrupthound,
+ "Corrupt Corrupt Hound" = /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi,
+ "Hunter Giant Spider" = /mob/living/simple_mob/animal/giant_spider/hunter,
+ "Lurker Giant Spider" = /mob/living/simple_mob/animal/giant_spider/lurker,
+ "Pepper Giant Spider" = /mob/living/simple_mob/animal/giant_spider/pepper,
+ "Thermic Giant Spider" = /mob/living/simple_mob/animal/giant_spider/thermic,
+ "Webslinger Giant Spider" = /mob/living/simple_mob/animal/giant_spider/webslinger,
+ "Frost Giant Spider" = /mob/living/simple_mob/animal/giant_spider/frost,
+ "Nurse Giant Spider" = /mob/living/simple_mob/animal/giant_spider/nurse/eggless,
+ "Giant Spider Queen" = /mob/living/simple_mob/animal/giant_spider/nurse/queen/eggless
)
/obj/structure/ghost_pod/ghost_activated/maintpred/create_occupant(var/mob/M)
diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm
index 01069b8e234..55ebb62b1ad 100644
--- a/code/game/objects/structures/loot_piles.dm
+++ b/code/game/objects/structures/loot_piles.dm
@@ -255,7 +255,6 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/stack/material/cardboard{amount = 5},
/obj/item/weapon/contraband/poster,
/obj/item/weapon/contraband/poster/custom,
- /obj/item/weapon/material/wirerod,
/obj/item/weapon/newspaper,
/obj/item/weapon/paper/crumpled,
/obj/item/weapon/paper/crumpled/bloody
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 282a10f9e08..6b95d902111 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -222,7 +222,7 @@
M.touching.remove_any(remove_amount)
M.clean_blood()
-
+
if(isturf(loc))
var/turf/tile = loc
for(var/obj/effect/E in tile)
@@ -272,6 +272,7 @@
desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl
icon = 'icons/obj/watercloset.dmi'
icon_state = "rubberducky"
+ honk_sound = 'sound/voice/quack.ogg' //VOREStation edit
/obj/structure/sink
name = "sink"
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index b655d8b5e75..b70af8354d5 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -229,8 +229,17 @@ proc/admin_notice(var/message, var/rights)
return
PlayerNotesPage(1)
-/datum/admins/proc/PlayerNotesPage(page)
- var/dat = "Player notes
"
+/datum/admins/proc/PlayerNotesFilter()
+ if (!istype(src,/datum/admins))
+ src = usr.client.holder
+ if (!istype(src,/datum/admins))
+ to_chat(usr, "Error: you are not an admin!")
+ return
+ var/filter = input(usr, "Filter string (case-insensitive regex)", "Player notes filter") as text|null
+ PlayerNotesPage(1, filter)
+
+/datum/admins/proc/PlayerNotesPage(page, filter)
+ var/dat = "Player notes - Apply Filter
"
var/savefile/S=new("data/player_notes.sav")
var/list/note_keys
S >> note_keys
@@ -240,29 +249,38 @@ proc/admin_notice(var/message, var/rights)
dat += ""
note_keys = sortList(note_keys)
+ if(filter)
+ var/list/results = list()
+ var/regex/needle = regex(filter, "i")
+ for(var/haystack in note_keys)
+ if(needle.Find(haystack))
+ results += haystack
+ note_keys = results
+
// Display the notes on the current page
var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE
// Emulate CEILING(why does BYOND not have ceil, 1)
if(number_pages != round(number_pages))
number_pages = round(number_pages) + 1
var/page_index = page - 1
+
if(page_index < 0 || page_index >= number_pages)
- return
+ dat += "| No keys found. |
"
+ else
+ var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1
+ var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE
+ upper_bound = min(upper_bound, note_keys.len)
+ for(var/index = lower_bound, index <= upper_bound, index++)
+ var/t = note_keys[index]
+ dat += "| [t] |
"
- var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1
- var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE
- upper_bound = min(upper_bound, note_keys.len)
- for(var/index = lower_bound, index <= upper_bound, index++)
- var/t = note_keys[index]
- dat += "| [t] |
"
-
- dat += "
"
+ dat += "
"
// Display a footer to select different pages
for(var/index = 1, index <= number_pages, index++)
if(index == page)
dat += ""
- dat += "[index] "
+ dat += "[index] "
if(index == page)
dat += ""
diff --git a/code/modules/admin/admin_vr.dm b/code/modules/admin/admin_vr.dm
index 356d69a3761..e40db3f525a 100644
--- a/code/modules/admin/admin_vr.dm
+++ b/code/modules/admin/admin_vr.dm
@@ -8,5 +8,7 @@
traitors.spawn_uplink(H)
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
H.mind.accept_tcrystals = 1
+ var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
+ message_admins(msg)
else
to_chat(usr, "You do not have access to this command.")
\ No newline at end of file
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 2c80b58274e..44b3c9e16bd 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1971,7 +1971,12 @@
if("show")
show_player_info(ckey)
if("list")
- PlayerNotesPage(text2num(href_list["index"]))
+ var/filter
+ if(href_list["filter"] && href_list["filter"] != "0")
+ filter = url_decode(href_list["filter"])
+ PlayerNotesPage(text2num(href_list["index"]), filter)
+ if("filter")
+ PlayerNotesFilter()
return
mob/living/proc/can_centcom_reply()
diff --git a/code/modules/blob2/core_chunk.dm b/code/modules/blob2/core_chunk.dm
index 4abc06843eb..15db91e89ec 100644
--- a/code/modules/blob2/core_chunk.dm
+++ b/code/modules/blob2/core_chunk.dm
@@ -118,19 +118,19 @@
return FALSE
-/datum/chemical_reaction/blob_reconstitution
+/decl/chemical_reaction/instant/blob_reconstitution
name = "Hostile Blob Revival"
id = "blob_revival"
result = null
required_reagents = list("phoron" = 60)
result_amount = 1
-/datum/chemical_reaction/blob_reconstitution/can_happen(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/can_happen(var/datum/reagents/holder)
if(holder.my_atom && istype(holder.my_atom, /obj/item/weapon/blobcore_chunk))
return ..()
return FALSE
-/datum/chemical_reaction/blob_reconstitution/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/on_reaction(var/datum/reagents/holder)
var/obj/item/weapon/blobcore_chunk/chunk = holder.my_atom
if(chunk.can_genesis && chunk.regen())
chunk.visible_message("[chunk] bubbles, surrounding itself with a rapidly expanding mass of [chunk.blob_type.name]!")
@@ -138,14 +138,14 @@
else
chunk.visible_message("[chunk] shifts strangely, but falls still.")
-/datum/chemical_reaction/blob_reconstitution/domination
+/decl/chemical_reaction/instant/blob_reconstitution/domination
name = "Allied Blob Revival"
id = "blob_friend"
result = null
required_reagents = list("hydrophoron" = 40, "peridaxon" = 20, "mutagen" = 20)
result_amount = 1
-/datum/chemical_reaction/blob_reconstitution/domination/on_reaction(var/datum/reagents/holder)
+/decl/chemical_reaction/instant/blob_reconstitution/domination/on_reaction(var/datum/reagents/holder)
var/obj/item/weapon/blobcore_chunk/chunk = holder.my_atom
if(chunk.can_genesis && chunk.regen("neutral"))
chunk.visible_message("[chunk] bubbles, surrounding itself with a rapidly expanding mass of [chunk.blob_type.name]!")
diff --git a/code/modules/catalogue/catalogue_data_vr.dm b/code/modules/catalogue/catalogue_data_vr.dm
index 4ac6a0b0696..06c3f9c51a7 100644
--- a/code/modules/catalogue/catalogue_data_vr.dm
+++ b/code/modules/catalogue/catalogue_data_vr.dm
@@ -5,63 +5,124 @@
/datum/category_item/catalogue/fauna/akula
name = "Sapients - Akula"
- desc = ""
+ desc = "A pelagic species hailing from the Barkalis System originally\
+ the Akula have been incidentally uplifted by free Kosaky \
+ sharing much of their more modern culture with interstellar\
+ Humanity. Many of them have spread among the stars, either\
+ in the nomad fleets or joining colonies as capable hard labour."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/sergal
name = "Sapients - Sergal"
- desc = ""
+ desc = "The dominant species in the Vilous System, the Sergal are a\
+ strange mammalian clade which shares similarities with \
+ masurpials, pelagic creatures and wolves. Collectivist and\
+ organising themselves in tribes and city states, they have\
+ eclipsed the private colony venture trying to hold them \
+ economically beholden and now have joined the sapient \
+ diaspora on more equal terms."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/nevrean
name = "Sapients - Nevrean"
- desc = ""
+ desc = "A co-sapient species from Vilous, the Nevrean have found their\
+ ecological niche as nomadic traders and craftsmen, \
+ developing a rich oral tradition, that is being slowly \
+ codified by the Sergals in an efforts to culturally export \
+ it through the stars. The modern Nevrean co-inhabits most \
+ places the Sergals do as comrades and historical allies."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/rapala
name = "Sapients - Rapala"
- desc = ""
+ desc = "The Rapala, formally “Rapala-Unathi†are a vassal species of the Unathi \
+ in form of winged Humanoids. While they share a similar outwards appearance with humans, \
+ they have a much more complex system of sexual genetics, as well superior 3D awareness. \
+ The Rapala act as emissaries, diplomats and spies for their overlords, although it is an open \
+ secret that they work for more autonomy and self-governance."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/xenochimera
name = "Sapients - Xenochimera"
- desc = ""
+ desc = "ERROR : DNA corruption detected. The likely outcome of this is this specimen being \
+ a Xenochimera. Xenochimeras are the end stage of “Roanoke Syndromeâ€, a microbial infection \
+ that infiltrates the immune system of a host species by mimicking cells. Upon expiration of \
+ the host (preventable by medical attention), the cells cannibalize and take over the body, \
+ creating a xenochimera. If the body has been capable of sapient thought, the resultant morph \
+ is also capable of thought. \
+
\
+ Contrary to popular belief, Roanoke Syndrome colonies do not seek out sapient life. Any exposure \
+ is incidental and not part of a plot – xenochimera without sapient thought are simply wild animals or disease vectors."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/vulpkanin
name = "Sapients - Vulpkanin"
- desc = ""
+ desc = "The Vulpkanin are the remnants of an ancient precursor which resided in the Coreward Periphery \
+ 3000 to 4000 years ago, residing on a planet called “Altamâ€. Vulpkanin diverged from the precursors due \
+ to heavy isolation after the fall, presumably due to being a freshly found colony. A lack of material support \
+ regressed their technology to pre-industrial standards until being found again by Humanity. At this point \
+ they have formed an early spacefaring society and accession into the Diaspora went over relatively smoothly. \
+ Vulpkanin are the closest successor to the precursors, genetically, although genelocked devices still do not \
+ recognize them due to genetic drift."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/alraune
name = "Sapients - Alraune"
- desc = ""
+ desc = "Alraune are enigmatic, strange creatures from the Elysian Colonies. While their main culture is still \
+ in the early neolithic, a large diaspora has formed from previous abductions and trade with these creatures, who \
+ seem to mimic many cultivars throughout space through yet an unknown mechanism. Alraune are pleasant, but \
+ predatory who autocannibalize their own products as a form of nutriment transfer and storage."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/vasilissan
name = "Sapients - Vasilissan"
- desc = ""
+ desc = "Vasilissans are an arachnid species uplifted by NT due to their propensity for architectural feats for \
+ surface-to-orbit buildings with relatively primitive materials. Exploited for a while, they have managed to \
+ connect to the greater commerce of the Diaspora, making them less dependent of our favourite TSCs, sadly. \
+ Vasilissans are happily adopted into Coreward Periphery colonies, valued for their infrastructural acumen \
+ and their craftsmanship with their natural silk."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/zorren
name = "Sapients - Zorren"
- desc = ""
+ desc = "The Zorren are the remnants of an ancient precursor which resided in the Coreward Periphery 3000 to 4000 \
+ years ago, residing on a planet called “Menhirâ€, which we call Virgo 4. Zorren organise themselves through various \
+ feudal-styled kingdoms and monarchies, of which the most prominent is the Kingdom of An-Tahk-Et. They are obsessed \
+ over their ancient heritage and the power of the noble houses comes through the control and excavation of old technology \
+ of their precursors, leading to a massive divide between commoners, who live as serfs and the nobility, who live in \
+ comparable conditions as wealthy members of the Diaspora."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/shadekin
name = "Sapients - Shadekin"
- desc = ""
+ desc = "ERROR : No DNA found. ERROR : Ambient energy signature detected. Likely origin from attempt of scanning \
+ Specimen NT-495. \
+
\
+ NT-495, also colloquial known as “Shadekinâ€, “Deep Peopleâ€, “Mar Beastâ€, “Shadow creature†are an enigmatic species \
+ capable of localized bluespace events (although the credibility of them actually manipulating bluespace effects \
+ still is in question), allowing them to “shift†through phases of existence without assistance of machines. \
+ Observation of NT-495 is notoriously difficult, as they do not exhibit these traits when in direct view unless \
+ they seem to feel threatened. \
+
\
+ Their definite sapience has been proven as several NT-495 sightings supports them to be capable of galactic common, \
+ especially under the variant that does not seem to possess the innate ability to phase – in fact, NT has recently \
+ started to hire those for closer observation."
value = CATALOGUER_REWARD_EASY
/datum/category_item/catalogue/fauna/custom_species
name = "Sapients - Other"
- desc = "Remote frontiers require people of all sorts of life...\
- Sometimes species one would never see anywhere close to core worlds can be met here."
+ desc = "ERROR : DNA scan inconclusive. Please interview subject to catalogue them manually. \
+ We apologise for the inconvenience. \
+
\
+ Likely reasons for failure : Genetic Engineering, Hybridization, minor species of Orion Spur Diaspora."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/technology/resleeving
name = "Resleeving"
- desc = ""
+ desc = "The premier technology of the early 2280s, Resleeving is a direct upgrade to the antiquated flash \
+ cloning by creating near perfect copies of a body within the database, capable of uploading a consciousness \
+ in the dormant brain via direct electro-uploading. However, this technology is not perfect and small, but \
+ non-zero error margins exist. Handle with care! Or don't. Stress testing this stuff makes a lucrative market."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/information/organization/khi
diff --git a/code/modules/catalogue/cataloguer_vr.dm b/code/modules/catalogue/cataloguer_vr.dm
index 8a8322c5815..6759cca6510 100644
--- a/code/modules/catalogue/cataloguer_vr.dm
+++ b/code/modules/catalogue/cataloguer_vr.dm
@@ -3,8 +3,10 @@
/obj/item/device/cataloguer/compact
name = "compact cataloguer"
- icon = 'icons/vore/custom_items_vr.dmi'
- icon_state = "tricorder"
+ desc = "A compact hand-held device, used for compiling information about an object by scanning it. \
+ Alt+click to highlight scannable objects around you."
+ icon = 'icons/obj/device_vr.dmi'
+ icon_state = "compact"
action_button_name = "Toggle Cataloguer"
var/deployed = TRUE
scan_range = 1
@@ -30,7 +32,7 @@
if(deployed)
w_class = ITEMSIZE_NORMAL
icon_state = "[initial(icon_state)]"
- to_chat(usr, span("notice", "You flip open \the [src]."))
+ to_chat(usr, span("notice", "You flick open \the [src]."))
else
w_class = ITEMSIZE_SMALL
icon_state = "[initial(icon_state)]_closed"
@@ -54,6 +56,15 @@
/obj/item/device/cataloguer/compact/pathfinder
name = "pathfinder's cataloguer"
- icon_state = "tricorder_med"
+ desc = "A compact hand-held device, used for compiling information about an object by scanning it. \
+ Alt+click to highlight scannable objects around you."
+ icon = 'icons/obj/device_vr.dmi'
+ icon_state = "pathcat"
scan_range = 3
toolspeed = 1
+
+/obj/item/device/cataloguer
+ desc = "A hand-held device, used for compiling information about an object by scanning it. \
+ Alt+click to highlight scannable objects around you."
+ icon = 'icons/obj/device_vr.dmi'
+ icon_state = "cataloguer"
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm
index 673e273af0b..fc21c743c09 100644
--- a/code/modules/client/preference_setup/general/02_language.dm
+++ b/code/modules/client/preference_setup/general/02_language.dm
@@ -15,8 +15,18 @@
if(!islist(pref.alternate_languages)) pref.alternate_languages = list()
if(pref.species)
var/datum/species/S = GLOB.all_species[pref.species]
- if(S && pref.alternate_languages.len > S.num_alternate_languages)
+ if(!istype(S))
+ return
+
+ if(pref.alternate_languages.len > S.num_alternate_languages)
pref.alternate_languages.len = S.num_alternate_languages // Truncate to allowed length
+
+ // Sanitize illegal languages
+ for(var/language in pref.alternate_languages)
+ var/datum/language/L = GLOB.all_languages[language]
+ if(!istype(L) || (L.flags & RESTRICTED) || (!(language in S.secondary_langs) && !is_lang_whitelisted(pref.client, L)))
+ pref.alternate_languages -= language
+
if(isnull(pref.language_prefixes) || !pref.language_prefixes.len)
pref.language_prefixes = config.language_prefixes.Copy()
for(var/prefix in pref.language_prefixes)
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 949d613b6b5..15f079d31cb 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -37,6 +37,43 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
var/g_wing3 = 30 // Wing tertiary color
var/b_wing3 = 30 // Wing tertiary color
+// Sanitize ear/wing/tail styles
+/datum/preferences/proc/sanitize_body_styles()
+
+ // Grandfather in anyone loading paths from a save.
+ if(ispath(ear_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.ear_styles_list[ear_style]
+ if(istype(instance))
+ ear_style = instance.name
+ if(ispath(wing_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.wing_styles_list[wing_style]
+ if(istype(instance))
+ wing_style = instance.name
+ if(ispath(tail_style, /datum/sprite_accessory))
+ var/datum/sprite_accessory/instance = global.tail_styles_list[tail_style]
+ if(istype(instance))
+ tail_style = instance.name
+
+ // Sanitize for non-existent keys.
+ if(ear_style && !(ear_style in get_available_styles(global.ear_styles_list)))
+ ear_style = null
+ if(wing_style && !(wing_style in get_available_styles(global.wing_styles_list)))
+ wing_style = null
+ if(tail_style && !(tail_style in get_available_styles(global.tail_styles_list)))
+ tail_style = null
+
+/datum/preferences/proc/get_available_styles(var/style_list)
+ . = list("Normal" = null)
+ for(var/path in style_list)
+ var/datum/sprite_accessory/instance = style_list[path]
+ if(!istype(instance))
+ continue
+ if(instance.ckeys_allowed && (!client || !(client.ckey in instance.ckeys_allowed)))
+ continue
+ if(instance.species_allowed && (!species || !(species in instance.species_allowed)) && (!client || !check_rights(R_ADMIN | R_EVENT | R_FUN, 0, client)))
+ continue
+ .[instance.name] = instance
+
/datum/category_item/player_setup_item/general/body
name = "Body"
sort_order = 3
@@ -228,21 +265,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.r_wing3 = sanitize_integer(pref.r_wing3, 0, 255, initial(pref.r_wing3))
pref.g_wing3 = sanitize_integer(pref.g_wing3, 0, 255, initial(pref.g_wing3))
pref.b_wing3 = sanitize_integer(pref.b_wing3, 0, 255, initial(pref.b_wing3))
- if(pref.ear_style)
- pref.ear_style = sanitize_inlist(pref.ear_style, ear_styles_list, initial(pref.ear_style))
- var/datum/sprite_accessory/temp_ear_style = ear_styles_list[pref.ear_style]
- if(temp_ear_style.apply_restrictions && (!(pref.species in temp_ear_style.species_allowed)))
- pref.ear_style = initial(pref.ear_style)
- if(pref.tail_style)
- pref.tail_style = sanitize_inlist(pref.tail_style, tail_styles_list, initial(pref.tail_style))
- var/datum/sprite_accessory/temp_tail_style = tail_styles_list[pref.tail_style]
- if(temp_tail_style.apply_restrictions && (!(pref.species in temp_tail_style.species_allowed)))
- pref.tail_style = initial(pref.tail_style)
- if(pref.wing_style)
- pref.wing_style = sanitize_inlist(pref.wing_style, wing_styles_list, initial(pref.wing_style))
- var/datum/sprite_accessory/temp_wing_style = wing_styles_list[pref.wing_style]
- if(temp_wing_style.apply_restrictions && (!(pref.species in temp_wing_style.species_allowed)))
- pref.wing_style = initial(pref.wing_style)
+
+ pref.sanitize_body_styles()
// Moved from /datum/preferences/proc/copy_to()
/datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character)
@@ -274,37 +298,44 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
character.g_synth = pref.g_synth
character.b_synth = pref.b_synth
character.synth_markings = pref.synth_markings
- character.ear_style = ear_styles_list[pref.ear_style]
- character.r_ears = pref.r_ears
- character.b_ears = pref.b_ears
- character.g_ears = pref.g_ears
- character.r_ears2 = pref.r_ears2
- character.b_ears2 = pref.b_ears2
- character.g_ears2 = pref.g_ears2
- character.r_ears3 = pref.r_ears3
- character.b_ears3 = pref.b_ears3
- character.g_ears3 = pref.g_ears3
- character.tail_style = tail_styles_list[pref.tail_style]
- character.r_tail = pref.r_tail
- character.b_tail = pref.b_tail
- character.g_tail = pref.g_tail
- character.r_tail2 = pref.r_tail2
- character.b_tail2 = pref.b_tail2
- character.g_tail2 = pref.g_tail2
- character.r_tail3 = pref.r_tail3
- character.b_tail3 = pref.b_tail3
- character.g_tail3 = pref.g_tail3
- character.wing_style = wing_styles_list[pref.wing_style]
- character.r_wing = pref.r_wing
- character.b_wing = pref.b_wing
- character.g_wing = pref.g_wing
- character.r_wing2 = pref.r_wing2
- character.b_wing2 = pref.b_wing2
- character.g_wing2 = pref.g_wing2
- character.r_wing3 = pref.r_wing3
- character.b_wing3 = pref.b_wing3
- character.g_wing3 = pref.g_wing3
- character.set_gender( pref.biological_gender)
+
+ var/list/ear_styles = pref.get_available_styles(global.ear_styles_list)
+ character.ear_style = ear_styles[pref.ear_style]
+ character.r_ears = pref.r_ears
+ character.b_ears = pref.b_ears
+ character.g_ears = pref.g_ears
+ character.r_ears2 = pref.r_ears2
+ character.b_ears2 = pref.b_ears2
+ character.g_ears2 = pref.g_ears2
+ character.r_ears3 = pref.r_ears3
+ character.b_ears3 = pref.b_ears3
+ character.g_ears3 = pref.g_ears3
+
+ var/list/tail_styles = pref.get_available_styles(global.tail_styles_list)
+ character.tail_style = tail_styles[pref.tail_style]
+ character.r_tail = pref.r_tail
+ character.b_tail = pref.b_tail
+ character.g_tail = pref.g_tail
+ character.r_tail2 = pref.r_tail2
+ character.b_tail2 = pref.b_tail2
+ character.g_tail2 = pref.g_tail2
+ character.r_tail3 = pref.r_tail3
+ character.b_tail3 = pref.b_tail3
+ character.g_tail3 = pref.g_tail3
+
+ var/list/wing_styles = pref.get_available_styles(global.wing_styles_list)
+ character.wing_style = wing_styles[pref.wing_style]
+ character.r_wing = pref.r_wing
+ character.b_wing = pref.b_wing
+ character.g_wing = pref.g_wing
+ character.r_wing2 = pref.r_wing2
+ character.b_wing2 = pref.b_wing2
+ character.g_wing2 = pref.g_wing2
+ character.r_wing3 = pref.r_wing3
+ character.b_wing3 = pref.b_wing3
+ character.g_wing3 = pref.g_wing3
+
+ character.set_gender(pref.biological_gender)
// Destroy/cyborgize organs and limbs.
for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO))
@@ -519,59 +550,47 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
. += "Genetics Settings
"
- var/ear_display = "Normal"
- if(pref.ear_style && (pref.ear_style in ear_styles_list))
- var/datum/sprite_accessory/ears/instance = ear_styles_list[pref.ear_style]
- ear_display = instance.name
-
- else if(pref.ear_style)
- ear_display = "REQUIRES UPDATE"
+ var/list/ear_styles = pref.get_available_styles(global.ear_styles_list)
+ var/datum/sprite_accessory/ears/ear = ear_styles[pref.ear_style]
. += "Ears
"
- . += " Style: [ear_display]
"
- if(ear_styles_list[pref.ear_style])
- var/datum/sprite_accessory/ears/ear = ear_styles_list[pref.ear_style]
+ if(istype(ear))
+ . += " Style: [ear.name]
"
if(ear.do_colouration)
. += "Change Color [color_square(pref.r_ears, pref.g_ears, pref.b_ears)]
"
if(ear.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_ears2, pref.g_ears2, pref.b_ears2)]
"
if(ear.extra_overlay2)
. += "Change Tertiary Color [color_square(pref.r_ears3, pref.g_ears3, pref.b_ears3)]
"
+ else
+ . += " Style: Select
"
- var/tail_display = "Normal"
- if(pref.tail_style && (pref.tail_style in tail_styles_list))
- var/datum/sprite_accessory/tail/instance = tail_styles_list[pref.tail_style]
- tail_display = instance.name
- else if(pref.tail_style)
- tail_display = "REQUIRES UPDATE"
+ var/list/tail_styles = pref.get_available_styles(global.tail_styles_list)
+ var/datum/sprite_accessory/tail/tail = tail_styles[pref.tail_style]
. += "Tail
"
- . += " Style: [tail_display]
"
-
- if(tail_styles_list[pref.tail_style])
- var/datum/sprite_accessory/tail/T = tail_styles_list[pref.tail_style]
- if(T.do_colouration)
+ if(istype(tail))
+ . += " Style: [tail.name]
"
+ if(tail.do_colouration)
. += "Change Color [color_square(pref.r_tail, pref.g_tail, pref.b_tail)]
"
- if(T.extra_overlay)
+ if(tail.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_tail2, pref.g_tail2, pref.b_tail2)]
"
- if(T.extra_overlay2)
+ if(tail.extra_overlay2)
. += "Change Tertiary Color [color_square(pref.r_tail3, pref.g_tail3, pref.b_tail3)]
"
+ else
+ . += " Style: Select
"
- var/wing_display = "Normal"
- if(pref.wing_style && (pref.wing_style in wing_styles_list))
- var/datum/sprite_accessory/wing/instance = wing_styles_list[pref.wing_style]
- wing_display = instance.name
- else if(pref.wing_style)
- wing_display = "REQUIRES UPDATE"
+ var/list/wing_styles = pref.get_available_styles(global.wing_styles_list)
+ var/datum/sprite_accessory/wing/wings = wing_styles[pref.wing_style]
. += "Wing
"
- . += " Style: [wing_display]
"
-
- if(wing_styles_list[pref.wing_style])
- var/datum/sprite_accessory/wing/W = wing_styles_list[pref.wing_style]
- if(W.do_colouration)
+ if(istype(wings))
+ . += " Style: [wings.name]
"
+ if(wings.do_colouration)
. += "Change Color [color_square(pref.r_wing, pref.g_wing, pref.b_wing)]
"
- if(W.extra_overlay)
+ if(wings.extra_overlay)
. += "Change Secondary Color [color_square(pref.r_wing2, pref.g_wing2, pref.b_wing2)]
"
- if(W.extra_overlay2)
+ if(wings.extra_overlay2)
. += "Change Secondary Color [color_square(pref.r_wing3, pref.g_wing3, pref.b_wing3)]
"
+ else
+ . += " Style: Select
"
. += "
Body Markings +
"
. += ""
@@ -669,7 +688,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case.
pref.body_markings.Cut() // Basically same as above.
-
+
+ pref.sanitize_body_styles()
+
var/min_age = get_min_age()
var/max_age = get_max_age()
pref.age = max(min(pref.age, max_age), min_age)
@@ -1085,17 +1106,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["ear_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_ear_styles = list("Normal" = null)
- for(var/path in ear_styles_list)
- var/datum/sprite_accessory/ears/instance = ear_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_ear_styles[instance.name] = path
-
- // Present choice to user
- var/new_ear_style = input(user, "Pick ears", "Character Preference", pref.ear_style) as null|anything in pretty_ear_styles
+ var/new_ear_style = input(user, "Select an ear style for this character:", "Character Preference", pref.ear_style) as null|anything in pref.get_available_styles(global.ear_styles_list)
if(new_ear_style)
- pref.ear_style = pretty_ear_styles[new_ear_style]
+ pref.ear_style = new_ear_style
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -1127,18 +1140,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_tail_styles = list("Normal" = null)
- for(var/path in tail_styles_list)
- var/datum/sprite_accessory/tail/instance = tail_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_tail_styles[instance.name] = path
-
- // Present choice to user
- var/new_tail_style = input(user, "Pick tails", "Character Preference", pref.tail_style) as null|anything in pretty_tail_styles
+ var/new_tail_style = input(user, "Select a tail style for this character:", "Character Preference", pref.tail_style) as null|anything in pref.get_available_styles(global.tail_styles_list)
if(new_tail_style)
- pref.tail_style = pretty_tail_styles[new_tail_style]
-
+ pref.tail_style = new_tail_style
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_color"])
@@ -1169,17 +1173,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["wing_style"])
- // Construct the list of names allowed for this user.
- var/list/pretty_wing_styles = list("Normal" = null)
- for(var/path in wing_styles_list)
- var/datum/sprite_accessory/wing/instance = wing_styles_list[path]
- if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit
- pretty_wing_styles[instance.name] = path
-
- // Present choice to user
- var/new_wing_style = input(user, "Pick wings", "Character Preference", pref.wing_style) as null|anything in pretty_wing_styles
+ var/new_wing_style = input(user, "Select a wing style for this character:", "Character Preference", pref.wing_style) as null|anything in pref.get_available_styles(global.wing_styles_list)
if(new_wing_style)
- pref.wing_style = pretty_wing_styles[new_wing_style]
+ pref.wing_style = new_wing_style
return TOPIC_REFRESH_UPDATE_PREVIEW
diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm
index c91b2314c89..e5822353990 100644
--- a/code/modules/client/preference_setup/loadout/loadout.dm
+++ b/code/modules/client/preference_setup/loadout/loadout.dm
@@ -62,12 +62,15 @@ var/list/gear_datums = list()
/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost)
. = list()
- var/mob/preference_mob = preference_mob()
+ var/mob/preference_mob = preference_mob() //VOREStation Add
for(var/gear_name in gear_datums)
var/datum/gear/G = gear_datums[gear_name]
- if(G.whitelisted && !is_alien_whitelisted(preference_mob, GLOB.all_species[G.whitelisted]))
- continue
+ if(G.whitelisted && config.loadout_whitelist != LOADOUT_WHITELIST_OFF)
+ if(config.loadout_whitelist == LOADOUT_WHITELIST_STRICT && G.whitelisted != pref.species)
+ continue
+ if(config.loadout_whitelist == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob(), GLOB.all_species[G.whitelisted]))
+ continue
if(max_cost && G.cost > max_cost)
continue
//VOREStation Edit Start
diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
index 17656aae896..52666a24190 100644
--- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
@@ -60,6 +60,12 @@
ckeywhitelist = list("aegisoa")
character_name = list("Xander Bevin")
+/datum/gear/fluff/charlotte_cigarettes
+ path = /obj/item/weapon/storage/fancy/fluff/charlotte
+ display_name = "Charlotte's cigarette case"
+ ckeywhitelist = list("alfalah")
+ character_name = list("Charlotte Graves")
+
/datum/gear/fluff/lynn_penlight
path = /obj/item/device/flashlight/pen/fluff/lynn
display_name = "Lynn's Penlight"
@@ -89,11 +95,23 @@
character_name = list("Aronai Sieyes")
/datum/gear/fluff/astra_ritualknife
- path = /obj/item/weapon/material/knife/ritual/fluff/astra
- display_name = "Polished Ritual Knife"
- description = "A well kept strange ritual knife, There is a small tag with the name 'Astra Ether' on it. They are probably looking for this."
- ckeywhitelist = list("astraether")
- character_name = list("Astra Ether")
+ path = /obj/item/weapon/material/knife/ritual/fluff/astra
+ display_name = "Polished Ritual Knife"
+ description = "A well kept strange ritual knife, There is a small tag with the name 'Astra Ether' on it. They are probably looking for this."
+ ckeywhitelist = list("astraether")
+ character_name = list("Astra Ether")
+
+/datum/gear/fluff/astra_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Astra's Conduct Medal"
+ ckeywhitelist = list("astraether")
+ character_name = list("Astra Ether")
+
+/datum/gear/fluff/astra_medal_2
+ path = /obj/item/clothing/accessory/medal/silver/unity
+ display_name = "Astra's Unity Medal"
+ ckeywhitelist = list("astraether")
+ character_name = list("Astra Ether")
/datum/gear/fluff/collar/azura
path = /obj/item/clothing/accessory/collar/azura
@@ -149,6 +167,12 @@
ckeywhitelist = list("blakeryan")
character_name = list("Nolan Conaway")
+/datum/gear/fluff/amber_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Amber's Conduct Medal"
+ ckeywhitelist = list("bluewolf128")
+ character_name = list("Amber Wresspenn")
+
/datum/gear/fluff/charles_hat
path = /obj/item/clothing/head/that/fluff/gettler
display_name = "Charles' Top-Hat"
@@ -189,6 +213,12 @@
ckeywhitelist = list("bacon12366")
character_name = list("Elly Brown")
+/datum/gear/fluff/alibig_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Ali Big's Conduct Medal"
+ ckeywhitelist = list("bigbababooey")
+ character_name = list("Ali Big")
+
// C CKEYS
/datum/gear/fluff/cappy_watch
path = /obj/item/clothing/accessory/watch
@@ -260,6 +290,18 @@
ckeywhitelist = list("dickfreedomjohnson")
character_name = list("Elliot Richards")
+/datum/gear/fluff/donald_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Donald's Conduct Medal"
+ ckeywhitelist = list("drainquake")
+ character_name = list("Donald Weinbeck")
+
+/datum/gear/fluff/donald_medal_2
+ path = /obj/item/clothing/accessory/medal/bronze_heart
+ display_name = "Donald's Heart Medal"
+ ckeywhitelist = list("drainquake")
+ character_name = list("Donald Weinbeck")
+
/datum/gear/fluff/drake_box
path = /obj/item/weapon/storage/box/fluff/drake
display_name = "Drake's Box"
@@ -570,6 +612,12 @@
character_name = list("Ashley Kifer")
// L CKEYS
+/datum/gear/fluff/kenzie_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Kenzie's Conduct Medal"
+ ckeywhitelist = list("lm40")
+ character_name = list("Kenzie Houser")
+
/datum/gear/fluff/kenzie_hypospray
path = /obj/item/weapon/reagent_containers/hypospray/vial/kenzie
display_name = "Kenzie's Hypospray"
@@ -584,6 +632,12 @@
ckeywhitelist = list("luminescentring")
character_name = list("Briana Moore")
+/datum/gear/fluff/entchtut_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Entchtut's Conduct Medal"
+ ckeywhitelist = list("littlebigkid2000")
+ character_name = list("Entchtut Cenein")
+
// M CKEYS
/datum/gear/fluff/phi_box
path = /obj/item/weapon/storage/box/fluff/phi
@@ -736,7 +790,7 @@
character_name = list("Scylla Casmus")
/datum/gear/fluff/kiyoshi_cloak
- path = /obj/item/clothing/accessory/poncho/fluff/cloakglowing
+ path = /obj/item/clothing/accessory/poncho/roles/cloak/fluff/cloakglowing
display_name = "glowing cloak"
ckeywhitelist = list("pastelprincedan")
character_name = list("Kiyoshi Maki", "Masumi Maki")
@@ -758,6 +812,18 @@
character_name = list("Clara Mali")
cost = 1
+/datum/gear/fluff/luna_sci_medal
+ path = /obj/item/clothing/accessory/medal/nobel_science
+ display_name = "LUNA's Nobel Science Award"
+ ckeywhitelist = list("residentcody")
+ character_name = list("LUNA")
+
+/datum/gear/fluff/luna_conduct_medal
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "LUNA's Distinguished Conduct Medal"
+ ckeywhitelist = list("residentcody")
+ character_name = list("LUNA")
+
/datum/gear/fluff/nikki_dorky_outfit
path = /obj/item/weapon/storage/box/fluff
display_name = "Nikki's Witchy Outfit"
@@ -777,6 +843,18 @@
ckeywhitelist = list("sageofaether12")
character_name = list("Brynhild Vandradottir")
+/datum/gear/fluff/brynhild_medal_3
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Brynhild's Conduct Medal"
+ ckeywhitelist = list("sageofaether12")
+ character_name = list("Brynhild Vandradottir")
+
+/datum/gear/fluff/brynhild_medal_4
+ path = /obj/item/clothing/accessory/medal/bronze_heart
+ display_name = "Brynhild's Heart Medal"
+ ckeywhitelist = list("sageofaether12")
+ character_name = list("Brynhild Vandradottir")
+
/datum/gear/fluff/kateryna_voidsuit
path = /obj/item/clothing/suit/space/void/engineering/kate
display_name = "Kateryna's Voidsuit"
@@ -912,6 +990,12 @@
ckeywhitelist = list("tabiranth")
character_name = list("Ascian")
+/datum/gear/fluff/ascian_medal_3
+ path = /obj/item/clothing/accessory/medal/conduct
+ display_name = "Ascian's Conduct Medal"
+ ckeywhitelist = list("tabiranth")
+ character_name = list("Ascian")
+
/datum/gear/fluff/ascian_spiritspawner
path = /obj/item/weapon/grenade/spawnergrenade/spirit
display_name = "The Best Kitten"
diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm
index 542348fec4d..719eb6fcfc1 100644
--- a/code/modules/client/preference_setup/loadout/loadout_general.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_general.dm
@@ -76,6 +76,7 @@
description = "Choose from a number of toys."
path = /obj/item/toy/
+/* VOREStation removal
/datum/gear/toy/New()
..()
var/toytype = list()
@@ -86,7 +87,7 @@
toytype["Magic 8 Ball"] = /obj/item/toy/eight_ball
toytype["Magic Conch shell"] = /obj/item/toy/eight_ball/conch
gear_tweaks += new/datum/gear_tweak/path(toytype)
-
+*/
/datum/gear/flask
display_name = "flask"
diff --git a/code/modules/client/preference_setup/loadout/loadout_general_vr.dm b/code/modules/client/preference_setup/loadout/loadout_general_vr.dm
index 09093b65673..8f11a56b372 100644
--- a/code/modules/client/preference_setup/loadout/loadout_general_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_general_vr.dm
@@ -9,4 +9,83 @@
for(var/ball in typesof(/obj/item/toy/tennis/))
var/obj/item/toy/tennis/ball_type = ball
balls[initial(ball_type.name)] = ball_type
- gear_tweaks += new/datum/gear_tweak/path(sortAssoc(balls))
\ No newline at end of file
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(balls))
+
+/datum/gear/character/
+ display_name = "miniature selection"
+ description = "Choose from a number of miniatures. From Battlemace 40 million to Grottos and Ghouls."
+ path = /obj/item/toy/character/alien
+
+/datum/gear/character/New()
+ ..()
+ var/list/characters = list()
+ for(var/character in typesof(/obj/item/toy/character/) - /obj/item/toy/character)
+ var/obj/item/toy/character/character_type = character
+ characters[initial(character_type.name)] = character_type
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(characters))
+
+/datum/gear/mechtoy/
+ display_name = "mecha toy selection"
+ description = "Choose from a number of mech toys."
+ path = /obj/item/toy/mecha/ripley
+
+/datum/gear/mechtoy/New()
+ ..()
+ var/list/mechs = list()
+ for(var/mech in typesof(/obj/item/toy/mecha/) - /obj/item/toy/mecha/)
+ var/obj/item/toy/mecha/mech_type = mech
+ mechs[initial(mech_type.name)] = mech_type
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(mechs))
+
+/datum/gear/toy/New()
+ ..()
+ var/toytype = list()
+ toytype["Blink toy"] = /obj/item/toy/blink
+ toytype["Foam dart crossbow"] = /obj/item/toy/blink
+ toytype["Toy sword"] = /obj/item/toy/sword
+ toytype["Toy katana"] = /obj/item/toy/katana
+ toytype["Snap pops"] = /obj/item/weapon/storage/box/snappops
+ toytype["Plastic flowers"] = /obj/item/toy/bouquet/fake
+ toytype["Stick horse"] = /obj/item/toy/stickhorse
+ toytype["Toy X-mas tree"] = /obj/item/toy/xmastree
+ toytype["Fake handcuff kit"] = /obj/item/weapon/storage/box/handcuffs/fake
+ toytype["Gravitational singularity"] = /obj/item/toy/spinningtoy
+ toytype["Water flower"] = /obj/item/weapon/reagent_containers/spray/waterflower
+ toytype["Bosun's whistle"] = /obj/item/toy/bosunwhistle
+ toytype["Magic 8 Ball"] = /obj/item/toy/eight_ball
+ toytype["Magic Conch shell"] = /obj/item/toy/eight_ball/conch
+ toytype["Pet rock"] = /obj/item/toy/rock
+ toytype["Toy flash"] = /obj/item/toy/flash
+ toytype["Big Red Button"] = /obj/item/toy/redbutton
+ toytype["Garden gnome"] = /obj/item/toy/gnome
+ toytype["Toy AI"] = /obj/item/toy/AI
+ toytype["Hand buzzer"] = /obj/item/clothing/gloves/ring/buzzer/toy
+ toytype["Toy nuke"] = /obj/item/toy/nuke
+ toytype["Toy gibber"] = /obj/item/toy/minigibber
+ toytype["Toy xeno"] = /obj/item/toy/toy_xeno
+ gear_tweaks += new/datum/gear_tweak/path(toytype)
+
+/datum/gear/chewtoy
+ display_name = "animal toy selection"
+ path = /obj/item/toy/chewtoy
+
+/datum/gear/chewtoy/New()
+ ..()
+ var/toytype = list()
+ toytype["Bone"] = /obj/item/toy/chewtoy
+ toytype["Classic"] = /obj/item/toy/chewtoy/tall
+ toytype["Mouse"] = /obj/item/toy/cat_toy
+ toytype["Feather rod"] = /obj/item/toy/cat_toy/rod
+ gear_tweaks += new/datum/gear_tweak/path(toytype)
+
+/datum/gear/chewtoy_poly
+ display_name = "animal toy selection, colorable"
+ path = /obj/item/toy/chewtoy/poly
+
+/datum/gear/chewtoy_poly/New()
+ ..()
+ var/toytype = list()
+ toytype["Bone"] = /obj/item/toy/chewtoy/poly
+ toytype["Classic"] = /obj/item/toy/chewtoy/tall/poly
+ gear_tweaks += new/datum/gear_tweak/path(toytype)
+ gear_tweaks += gear_tweak_free_color_choice
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index aaec0a08401..f607b9945ff 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -129,6 +129,7 @@
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_character(S)
+
/datum/category_group/player_setup_category/proc/save_character(var/savefile/S)
// Sanitize all data, then save it
for(var/datum/category_item/player_setup_item/PI in items)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0c32155812c..a98e0898510 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -169,8 +169,8 @@ datum/preferences
if(!IsGuestKey(C.key))
load_path(C.ckey)
if(load_preferences())
- if(load_character())
- return
+ load_character()
+
/datum/preferences/Destroy()
. = ..()
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index cb25e733967..cb2b3cf0b34 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -82,10 +82,8 @@
player_setup.load_character(S)
S.cd = "/character[default_slot]"
player_setup.save_character(S)
- sanitize_preferences()
- player_setup.load_character(S)
- clear_character_previews() // Recalculate them on next show
+ clear_character_previews() // VOREStation Edit
return 1
/datum/preferences/proc/save_character()
diff --git a/code/modules/clothing/head/pilot_helmet_vr.dm b/code/modules/clothing/head/pilot_helmet_vr.dm
new file mode 100644
index 00000000000..acf700f81f7
--- /dev/null
+++ b/code/modules/clothing/head/pilot_helmet_vr.dm
@@ -0,0 +1,33 @@
+//Overmap pilots. Same gear, without the dumb interface.
+
+/obj/item/clothing/head/ompilot
+ name = "pilot helmet"
+ desc = "Standard pilot gear. Protects the head from impacts."
+ icon_state = "pilot_helmet1"
+ item_icons = list(slot_head_str = 'icons/mob/pilot_helmet.dmi')
+ sprite_sheets = list(
+ SPECIES_TESHARI = 'icons/mob/species/teshari/pilot_helmet.dmi'
+ )
+ flags = THICKMATERIAL
+ armor = list(melee = 20, bullet = 10, laser = 10, energy = 5, bomb = 10, bio = 0, rad = 0)
+ flags_inv = HIDEEARS
+ cold_protection = HEAD
+ min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE
+ heat_protection = HEAD
+ max_heat_protection_temperature = HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
+ w_class = ITEMSIZE_NORMAL
+
+/obj/item/clothing/head/ompilot/alt
+ name = "pilot helmet"
+ desc = "Standard pilot gear. Protects the head from impacts. This one has a retractable visor"
+ icon_state = "pilot_helmet2"
+ action_button_name = "Toggle Visor"
+
+/obj/item/clothing/head/ompilot/alt/attack_self(mob/user as mob)
+ if(src.icon_state == initial(icon_state))
+ src.icon_state = "[icon_state]up"
+ to_chat(user, "You raise the visor on the pilot helmet.")
+ else
+ src.icon_state = initial(icon_state)
+ to_chat(user, "You lower the visor on the pilot helmet.")
+ update_clothing_icon() //so our mob-overlays update
\ No newline at end of file
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 0ecbe0390d6..0dde614e048 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -78,7 +78,7 @@
* Radiation protection
*/
/obj/item/clothing/head/radiation
- name = "Radiation Hood"
+ name = "Radiation hood"
icon_state = "rad"
desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation"
flags_inv = BLOCKHAIR
@@ -98,4 +98,20 @@
slowdown = 1.5
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
- item_flags = THICKMATERIAL
\ No newline at end of file
+ item_flags = THICKMATERIAL
+
+/obj/item/clothing/suit/radiation/teshari
+ name = "Small radiation suit"
+ desc = "A specialist suit that protects against radiation, designed specifically for use by Teshari. Made to order by Aether."
+ icon = 'icons/obj/clothing/species/teshari/suits.dmi'
+ icon_override = 'icons/mob/species/teshari/suit.dmi'
+ icon_state = "rad_fitted"
+ species_restricted = list(SPECIES_TESHARI)
+
+/obj/item/clothing/head/radiation/teshari
+ name = "Small radiation hood"
+ desc = "A specialist hood with radiation protective properties, designed specifically for use by Teshari. Made to order by Aether."
+ icon = 'icons/obj/clothing/species/teshari/hats.dmi'
+ icon_override = 'icons/mob/species/teshari/head.dmi'
+ icon_state = "rad_fitted"
+ species_restricted = list(SPECIES_TESHARI)
\ No newline at end of file
diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm
index 85c28047585..5422e294b4e 100644
--- a/code/modules/clothing/under/accessories/accessory_vr.dm
+++ b/code/modules/clothing/under/accessories/accessory_vr.dm
@@ -365,4 +365,4 @@
icon_state = "silverthree"
item_state = "silverthree"
overlay_state = "silverthree"
- desc = "A silver medal awarded to a group which has demonstrated exceptional teamwork to achieve a notable feat. This one has two bronze service stars, denoting that it has been awarded three times."
+ desc = "A silver medal awarded to a group which has demonstrated exceptional teamwork to achieve a notable feat. This one has three bronze service stars, denoting that it has been awarded four times."
diff --git a/code/modules/clothing/under/accessories/holster_vr.dm b/code/modules/clothing/under/accessories/holster_vr.dm
index 75cb4ccc9e7..f99e798faa8 100644
--- a/code/modules/clothing/under/accessories/holster_vr.dm
+++ b/code/modules/clothing/under/accessories/holster_vr.dm
@@ -1,4 +1,53 @@
/obj/item/clothing/accessory/holster/waist/kinetic_accelerator
name = "KA holster"
desc = "A specialized holster, made specifically for Kinetic Accelerator."
- can_hold = list(/obj/item/weapon/gun/energy/kinetic_accelerator)
\ No newline at end of file
+ can_hold = list(/obj/item/weapon/gun/energy/kinetic_accelerator)
+
+/obj/item/clothing/accessory/holster/machete/rapier
+ name = "rapier sheath"
+ desc = "A beautiful red sheath, probably for a beautiful blade."
+ icon = 'icons/obj/clothing/ties_vr.dmi'
+ icon_state = "sheath"
+ slot_flags = SLOT_BELT|ACCESSORY_SLOT_WEAPON
+ var/has_full_icon = 1
+ icon_override = 'icons/mob/ties_vr.dmi'
+ overlay_state = "sheath"
+ can_hold = list(/obj/item/weapon/melee/rapier)
+
+/obj/item/clothing/accessory/holster/machete/rapier/swords
+ name = "sword sheath"
+ desc = "A beautiful red sheath, probably for a beautiful blade."
+ can_hold = list(
+ /obj/item/weapon/melee/rapier,
+ /obj/item/weapon/material/sword/katana,
+ /obj/item/toy/cultsword,
+ /obj/item/weapon/material/sword,
+ /obj/item/weapon/melee/cursedblade,
+ /obj/item/weapon/melee/cultblade
+ )
+
+/obj/item/clothing/accessory/holster/machete/rapier/proc/occupied()
+ if(!has_full_icon)
+ return
+ if(contents.len)
+ overlay_state = "[initial(overlay_state)]-rapier"
+ else
+ overlay_state = initial(overlay_state)
+
+/obj/item/clothing/accessory/holster/machete/rapier/swords/occupied()
+ if(!has_full_icon)
+ return
+ if(contents.len)
+ overlay_state = "[initial(overlay_state)]-secondary"
+ else
+ overlay_state = initial(overlay_state)
+
+/obj/item/clothing/accessory/holster/machete/rapier/holster(var/obj/item/I, var/mob/living/user)
+ ..()
+ occupied()
+ has_suit.update_clothing_icon()
+
+/obj/item/clothing/accessory/holster/machete/rapier/unholster(var/obj/item/I, var/mob/living/user)
+ ..()
+ occupied()
+ has_suit.update_clothing_icon()
diff --git a/code/modules/mining/coins.dm b/code/modules/economy/coins.dm
similarity index 100%
rename from code/modules/mining/coins.dm
rename to code/modules/economy/coins.dm
diff --git a/code/modules/mining/mint.dm b/code/modules/economy/mint.dm
similarity index 100%
rename from code/modules/mining/mint.dm
rename to code/modules/economy/mint.dm
diff --git a/code/modules/mining/money_bag.dm b/code/modules/economy/money_bag.dm
similarity index 95%
rename from code/modules/mining/money_bag.dm
rename to code/modules/economy/money_bag.dm
index fd1cb561b0e..3e85d62e460 100644
--- a/code/modules/mining/money_bag.dm
+++ b/code/modules/economy/money_bag.dm
@@ -1,98 +1,98 @@
-/*****************************Money bag********************************/
-
-/obj/item/weapon/moneybag
- icon = 'icons/obj/storage.dmi'
- name = "Money bag"
- icon_state = "moneybag"
- force = 10.0
- throwforce = 2.0
- w_class = ITEMSIZE_LARGE
-
-/obj/item/weapon/moneybag/attack_hand(user as mob)
- var/amt_gold = 0
- var/amt_silver = 0
- var/amt_diamond = 0
- var/amt_iron = 0
- var/amt_phoron = 0
- var/amt_uranium = 0
-
- for (var/obj/item/weapon/coin/C in contents)
- if (istype(C,/obj/item/weapon/coin/diamond))
- amt_diamond++;
- if (istype(C,/obj/item/weapon/coin/phoron))
- amt_phoron++;
- if (istype(C,/obj/item/weapon/coin/iron))
- amt_iron++;
- if (istype(C,/obj/item/weapon/coin/silver))
- amt_silver++;
- if (istype(C,/obj/item/weapon/coin/gold))
- amt_gold++;
- if (istype(C,/obj/item/weapon/coin/uranium))
- amt_uranium++;
-
- var/dat = text("The contents of the moneybag reveal...
")
- if (amt_gold)
- dat += text("Gold coins: [amt_gold] Remove one
")
- if (amt_silver)
- dat += text("Silver coins: [amt_silver] Remove one
")
- if (amt_iron)
- dat += text("Metal coins: [amt_iron] Remove one
")
- if (amt_diamond)
- dat += text("Diamond coins: [amt_diamond] Remove one
")
- if (amt_phoron)
- dat += text("Phoron coins: [amt_phoron] Remove one
")
- if (amt_uranium)
- dat += text("Uranium coins: [amt_uranium] Remove one
")
- user << browse("[dat]", "window=moneybag")
-
-/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob)
- ..()
- if (istype(W, /obj/item/weapon/coin))
- var/obj/item/weapon/coin/C = W
- to_chat(user, "You add the [C.name] into the bag.")
- usr.drop_item()
- contents += C
- if (istype(W, /obj/item/weapon/moneybag))
- var/obj/item/weapon/moneybag/C = W
- for (var/obj/O in C.contents)
- contents += O;
- to_chat(user, "You empty the [C.name] into the bag.")
- return
-
-/obj/item/weapon/moneybag/Topic(href, href_list)
- if(..())
- return 1
- usr.set_machine(src)
- src.add_fingerprint(usr)
- if(href_list["remove"])
- var/obj/item/weapon/coin/COIN
- switch(href_list["remove"])
- if("gold")
- COIN = locate(/obj/item/weapon/coin/gold,src.contents)
- if("silver")
- COIN = locate(/obj/item/weapon/coin/silver,src.contents)
- if("iron")
- COIN = locate(/obj/item/weapon/coin/iron,src.contents)
- if("diamond")
- COIN = locate(/obj/item/weapon/coin/diamond,src.contents)
- if("phoron")
- COIN = locate(/obj/item/weapon/coin/phoron,src.contents)
- if("uranium")
- COIN = locate(/obj/item/weapon/coin/uranium,src.contents)
- if(!COIN)
- return
- COIN.loc = src.loc
- return
-
-
-
-/obj/item/weapon/moneybag/vault
-
-/obj/item/weapon/moneybag/vault/New()
- ..()
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/silver(src)
- new /obj/item/weapon/coin/gold(src)
+/*****************************Money bag********************************/
+
+/obj/item/weapon/moneybag
+ icon = 'icons/obj/storage.dmi'
+ name = "Money bag"
+ icon_state = "moneybag"
+ force = 10.0
+ throwforce = 2.0
+ w_class = ITEMSIZE_LARGE
+
+/obj/item/weapon/moneybag/attack_hand(user as mob)
+ var/amt_gold = 0
+ var/amt_silver = 0
+ var/amt_diamond = 0
+ var/amt_iron = 0
+ var/amt_phoron = 0
+ var/amt_uranium = 0
+
+ for (var/obj/item/weapon/coin/C in contents)
+ if (istype(C,/obj/item/weapon/coin/diamond))
+ amt_diamond++;
+ if (istype(C,/obj/item/weapon/coin/phoron))
+ amt_phoron++;
+ if (istype(C,/obj/item/weapon/coin/iron))
+ amt_iron++;
+ if (istype(C,/obj/item/weapon/coin/silver))
+ amt_silver++;
+ if (istype(C,/obj/item/weapon/coin/gold))
+ amt_gold++;
+ if (istype(C,/obj/item/weapon/coin/uranium))
+ amt_uranium++;
+
+ var/dat = text("The contents of the moneybag reveal...
")
+ if (amt_gold)
+ dat += text("Gold coins: [amt_gold] Remove one
")
+ if (amt_silver)
+ dat += text("Silver coins: [amt_silver] Remove one
")
+ if (amt_iron)
+ dat += text("Metal coins: [amt_iron] Remove one
")
+ if (amt_diamond)
+ dat += text("Diamond coins: [amt_diamond] Remove one
")
+ if (amt_phoron)
+ dat += text("Phoron coins: [amt_phoron] Remove one
")
+ if (amt_uranium)
+ dat += text("Uranium coins: [amt_uranium] Remove one
")
+ user << browse("[dat]", "window=moneybag")
+
+/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ ..()
+ if (istype(W, /obj/item/weapon/coin))
+ var/obj/item/weapon/coin/C = W
+ to_chat(user, "You add the [C.name] into the bag.")
+ usr.drop_item()
+ contents += C
+ if (istype(W, /obj/item/weapon/moneybag))
+ var/obj/item/weapon/moneybag/C = W
+ for (var/obj/O in C.contents)
+ contents += O;
+ to_chat(user, "You empty the [C.name] into the bag.")
+ return
+
+/obj/item/weapon/moneybag/Topic(href, href_list)
+ if(..())
+ return 1
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+ if(href_list["remove"])
+ var/obj/item/weapon/coin/COIN
+ switch(href_list["remove"])
+ if("gold")
+ COIN = locate(/obj/item/weapon/coin/gold,src.contents)
+ if("silver")
+ COIN = locate(/obj/item/weapon/coin/silver,src.contents)
+ if("iron")
+ COIN = locate(/obj/item/weapon/coin/iron,src.contents)
+ if("diamond")
+ COIN = locate(/obj/item/weapon/coin/diamond,src.contents)
+ if("phoron")
+ COIN = locate(/obj/item/weapon/coin/phoron,src.contents)
+ if("uranium")
+ COIN = locate(/obj/item/weapon/coin/uranium,src.contents)
+ if(!COIN)
+ return
+ COIN.loc = src.loc
+ return
+
+
+
+/obj/item/weapon/moneybag/vault
+
+/obj/item/weapon/moneybag/vault/New()
+ ..()
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/silver(src)
+ new /obj/item/weapon/coin/gold(src)
new /obj/item/weapon/coin/gold(src)
\ No newline at end of file
diff --git a/code/modules/economy/price_list.dm b/code/modules/economy/price_list.dm
index 9e3fb438d82..839148ebaf2 100644
--- a/code/modules/economy/price_list.dm
+++ b/code/modules/economy/price_list.dm
@@ -13,7 +13,7 @@
//---Beverages---//
//***************//
-/datum/reagent/var/price_tag = null
+/datum/reagent/var/price_tag = 0
// Juices, soda and similar //
diff --git a/code/game/machinery/vending.dm b/code/modules/economy/vending.dm
similarity index 96%
rename from code/game/machinery/vending.dm
rename to code/modules/economy/vending.dm
index 58107d9d0b4..36adfb63921 100644
--- a/code/game/machinery/vending.dm
+++ b/code/modules/economy/vending.dm
@@ -1,720 +1,723 @@
-///
-/// A vending machine
-///
-
-//
-// ALL THE VENDING MACHINES ARE IN vending_machines.dm now!
-//
-
-/obj/machinery/vending
- name = "Vendomat"
- desc = "A generic vending machine."
- icon = 'icons/obj/vending.dmi'
- icon_state = "generic"
- anchored = 1
- density = 1
- clicksound = "button"
-
- // Power
- use_power = USE_POWER_IDLE
- idle_power_usage = 10
- var/vend_power_usage = 150 //actuators and stuff
-
- // Vending-related
- var/active = 1 //No sales pitches if off!
- var/vend_ready = 1 //Are we ready to vend?? Is it time??
- var/vend_delay = 10 //How long does it take to vend?
- var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
- var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
- var/vending_sound = "machines/vending/vending_drop.ogg"
-
- /*
- Variables used to initialize the product list
- These are used for initialization only, and so are optional if
- product_records is specified
- */
- var/list/products = list() // For each, use the following pattern:
- var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2)
- var/list/premium = list() // No specified amount = only one in stock
- var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price.
-
- // List of vending_product items available.
- var/list/product_records = list()
-
-
- // Variables used to initialize advertising
- var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons
- var/product_ads = "" //String of small ad messages in the vending screen
-
- var/list/ads_list = list()
-
- // Stuff relating vocalizations
- var/list/slogan_list = list()
- var/shut_up = 1 //Stop spouting those godawful pitches!
- var/vend_reply //Thank you for shopping!
- var/last_reply = 0
- var/last_slogan = 0 //When did we last pitch?
- var/slogan_delay = 6000 //How long until we can pitch again?
-
- // Things that can go wrong
- emagged = 0 //Ignores if somebody doesn't have card access to that machine.
- var/seconds_electrified = 0 //Shock customers like an airlock.
- var/shoot_inventory = 0 //Fire items at customers! We're broken!
-
- var/scan_id = 1
- var/obj/item/weapon/coin/coin
- var/datum/wires/vending/wires = null
-
- var/list/log = list()
- var/req_log_access = access_cargo //default access for checking logs is cargo
- var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs
- var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals.
-
-
-/obj/machinery/vending/Initialize()
- . = ..()
- wires = new(src)
- if(product_slogans)
- slogan_list += splittext(product_slogans, ";")
-
- // So not all machines speak at the exact same time.
- // The first time this machine says something will be at slogantime + this random value,
- // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated.
- last_slogan = world.time + rand(0, slogan_delay)
-
- if(product_ads)
- ads_list += splittext(product_ads, ";")
-
- build_inventory()
- power_change()
-
-GLOBAL_LIST_EMPTY(vending_products)
-/**
- * Build produdct_records from the products lists
- *
- * products, contraband, premium, and prices allow specifying
- * products that the vending machine is to carry without manually populating
- * product_records.
- */
-/obj/machinery/vending/proc/build_inventory()
- var/list/all_products = list(
- list(products, CAT_NORMAL),
- list(contraband, CAT_HIDDEN),
- list(premium, CAT_COIN))
-
- for(var/current_list in all_products)
- var/category = current_list[2]
-
- for(var/entry in current_list[1])
- var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry)
-
- product.price = (entry in prices) ? prices[entry] : 0
- product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1
- product.category = category
-
- product_records.Add(product)
- GLOB.vending_products[entry] = 1
-
-/obj/machinery/vending/Destroy()
- qdel(wires)
- wires = null
- qdel(coin)
- coin = null
- for(var/datum/stored_item/vending_product/R in product_records)
- qdel(R)
- product_records = null
- return ..()
-
-/obj/machinery/vending/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if(prob(50))
- qdel(src)
- return
- if(3.0)
- if(prob(25))
- spawn(0)
- malfunction()
- return
- return
- else
- return
-
-/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user)
- if(!emagged)
- emagged = 1
- to_chat(user, "You short out \the [src]'s product lock.")
- return 1
-
-/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
- var/obj/item/weapon/card/id/I = W.GetID()
-
- if(I || istype(W, /obj/item/weapon/spacecash))
- attack_hand(user)
- return
- else if(W.is_screwdriver())
- panel_open = !panel_open
- to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
- playsound(src, W.usesound, 50, 1)
- if(panel_open)
- wires.Interact(user)
- add_overlay("[initial(icon_state)]-panel")
- else
- cut_overlay("[initial(icon_state)]-panel")
-
- SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI
- return
- else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter())
- if(panel_open)
- attack_hand(user)
- return
- else if(istype(W, /obj/item/weapon/coin) && premium.len > 0)
- user.drop_item()
- W.forceMove(src)
- coin = W
- categories |= CAT_COIN
- to_chat(user, "You insert \the [W] into \the [src].")
- SStgui.update_uis(src)
- return
- else if(W.is_wrench())
- playsound(src, W.usesound, 100, 1)
- if(anchored)
- user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
- else
- user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
-
- if(do_after(user, 20 * W.toolspeed))
- if(!src) return
- to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
- anchored = !anchored
- return
- else
-
- for(var/datum/stored_item/vending_product/R in product_records)
- if(istype(W, R.item_path) && (W.name == R.item_name))
- stock(W, R, user)
- return
- ..()
-
-/**
- * Receive payment with cashmoney.
- *
- * usr is the mob who gets the change.
- */
-/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user)
- if(currently_vending.price > cashmoney.worth)
-
- // This is not a status display message, since it's something the character
- // themselves is meant to see BEFORE putting the money in
- to_chat(usr, "[bicon(cashmoney)] That is not enough money.")
- return 0
-
- if(istype(cashmoney, /obj/item/weapon/spacecash))
-
- visible_message("\The [usr] inserts some cash into \the [src].")
- cashmoney.worth -= currently_vending.price
-
- if(cashmoney.worth <= 0)
- usr.drop_from_inventory(cashmoney)
- qdel(cashmoney)
- else
- cashmoney.update_icon()
-
- // Vending machines have no idea who paid with cash
- credit_purchase("(cash)")
- return 1
-
-/**
- * Scan a chargecard and deduct payment from it.
- *
- * Takes payment for whatever is the currently_vending item. Returns 1 if
- * successful, 0 if failed.
- */
-/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet)
- visible_message("\The [usr] swipes \the [wallet] through \the [src].")
- playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
- if(currently_vending.price > wallet.worth)
- to_chat(usr, "Insufficient funds on chargecard.")
- return 0
- else
- wallet.worth -= currently_vending.price
- credit_purchase("[wallet.owner_name] (chargecard)")
- return 1
-
-/**
- * Scan a card and attempt to transfer payment from associated account.
- *
- * Takes payment for whatever is the currently_vending item. Returns 1 if
- * successful, 0 if failed
- */
-/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
- visible_message("[M] swipes a card through [src].")
- playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
-
- var/datum/money_account/customer_account = get_account(I.associated_account_number)
- if(!customer_account)
- to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.")
- return FALSE
-
- if(customer_account.suspended)
- to_chat(M, "Unable to access account: account suspended.")
- return FALSE
-
- // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
- // empty at high security levels
- if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
- var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
- customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
-
- if(!customer_account)
- to_chat(M, "Unable to access account: incorrect credentials.")
- return FALSE
-
- if(currently_vending.price > customer_account.money)
- to_chat(M, "Insufficient funds in account.")
- return FALSE
-
- // Okay to move the money at this point
-
- // debit money from the purchaser's account
- customer_account.money -= currently_vending.price
-
- // create entry in the purchaser's account log
- var/datum/transaction/T = new()
- T.target_name = "[vendor_account.owner_name] (via [name])"
- T.purpose = "Purchase of [currently_vending.item_name]"
- if(currently_vending.price > 0)
- T.amount = "([currently_vending.price])"
- else
- T.amount = "[currently_vending.price]"
- T.source_terminal = name
- T.date = current_date_string
- T.time = stationtime2text()
- customer_account.transaction_log.Add(T)
-
- // Give the vendor the money. We use the account owner name, which means
- // that purchases made with stolen/borrowed card will look like the card
- // owner made them
- credit_purchase(customer_account.owner_name)
- return 1
-
-/**
- * Add money for current purchase to the vendor account.
- *
- * Called after the money has already been taken from the customer.
- */
-/obj/machinery/vending/proc/credit_purchase(var/target as text)
- vendor_account.money += currently_vending.price
-
- var/datum/transaction/T = new()
- T.target_name = target
- T.purpose = "Purchase of [currently_vending.item_name]"
- T.amount = "[currently_vending.price]"
- T.source_terminal = name
- T.date = current_date_string
- T.time = stationtime2text()
- vendor_account.transaction_log.Add(T)
-
-/obj/machinery/vending/attack_ghost(mob/user)
- return attack_hand(user)
-
-/obj/machinery/vending/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/vending/attack_hand(mob/user as mob)
- if(stat & (BROKEN|NOPOWER))
- return
-
- if(seconds_electrified != 0)
- if(shock(user, 100))
- return
-
- wires.Interact(user)
- tgui_interact(user)
-
-/obj/machinery/vending/ui_assets(mob/user)
- return list(
- get_asset_datum(/datum/asset/spritesheet/vending),
- )
-
-/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "Vending", name)
- ui.open()
-
-/obj/machinery/vending/tgui_data(mob/user)
- var/list/data = list()
- var/list/listed_products = list()
-
- data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
- for(var/key = 1 to product_records.len)
- var/datum/stored_item/vending_product/I = product_records[key]
-
- if(!(I.category & categories))
- continue
-
- listed_products.Add(list(list(
- "key" = key,
- "name" = I.item_name,
- "price" = I.price,
- "color" = I.display_color,
- "isatom" = ispath(I.item_path, /atom),
- "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
- "amount" = I.get_amount()
- )))
-
- data["products"] = listed_products
-
- if(coin)
- data["coin"] = coin.name
- else
- data["coin"] = FALSE
-
- if(currently_vending)
- data["actively_vending"] = currently_vending.item_name
- else
- data["actively_vending"] = null
-
- if(panel_open)
- data["panel"] = 1
- data["speaker"] = shut_up ? 0 : 1
- else
- data["panel"] = 0
-
- var/mob/living/carbon/human/H
- var/obj/item/weapon/card/id/C
-
- data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
- data["userMoney"] = 0
- data["user"] = null
- if(ishuman(user))
- H = user
- C = H.GetIdCard()
- var/obj/item/weapon/spacecash/S = H.get_active_hand()
- if(istype(S))
- data["userMoney"] = S.worth
- data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]â‚®."
- else if(istype(C))
- var/datum/money_account/A = get_account(C.associated_account_number)
- if(istype(A))
- data["user"] = list()
- data["user"]["name"] = A.owner_name
- data["userMoney"] = A.money
- data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
- else
- data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
-
- return data
-
-/obj/machinery/vending/tgui_act(action, params)
- if(stat & (BROKEN|NOPOWER))
- return
- if(usr.stat || usr.restrained())
- return
- if(..())
- return TRUE
-
- . = TRUE
- switch(action)
- if("remove_coin")
- if(issilicon(usr))
- return FALSE
-
- if(!coin)
- to_chat(usr, "There is no coin in this machine.")
- return
-
- coin.forceMove(src.loc)
- if(!usr.get_active_hand())
- usr.put_in_hands(coin)
-
- to_chat(usr, "You remove \the [coin] from \the [src].")
- coin = null
- categories &= ~CAT_COIN
- return TRUE
- if("vend")
- if(!vend_ready)
- to_chat(usr, "[src] is busy!")
- return
- if(!allowed(usr) && !emagged && scan_id)
- to_chat(usr, "Access denied.") //Unless emagged of course
- flick("[icon_state]-deny",src)
- playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
- return
- if(panel_open)
- to_chat(usr, "[src] cannot dispense products while its service panel is open!")
- return
-
- var/key = text2num(params["vend"])
- var/datum/stored_item/vending_product/R = product_records[key]
-
- // This should not happen unless the request from NanoUI was bad
- if(!(R.category & categories))
- return
-
- if(!can_buy(R, usr))
- return
- if(R.price <= 0)
- vend(R, usr)
- add_fingerprint(usr)
- return TRUE
-
- if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
- to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.")
- return
- if(!ishuman(usr))
- return
-
-
- vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
-
- var/mob/living/carbon/human/H = usr
- var/obj/item/weapon/card/id/C = H.GetIdCard()
-
- if(!vendor_account || vendor_account.suspended)
- to_chat(usr, "Vendor account offline. Unable to process transaction.")
- flick("[icon_state]-deny",src)
- vend_ready = TRUE
- return
-
- currently_vending = R
-
- var/paid = FALSE
-
- if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
- var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
- paid = pay_with_cash(cash, usr)
- else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
- var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
- paid = pay_with_ewallet(wallet)
- else if(istype(C, /obj/item/weapon/card))
- paid = pay_with_card(C, usr)
- /*else if(usr.can_advanced_admin_interact())
- to_chat(usr, "Vending object due to admin interaction.")
- paid = TRUE*/
- else
- to_chat(usr, "Payment failure: you have no ID or other method of payment.")
- vend_ready = TRUE
- flick("[icon_state]-deny",src)
- return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
- if(paid)
- vend(currently_vending, usr) // vend will handle vend_ready
- . = TRUE
- else
- to_chat(usr, "Payment failure: unable to process payment.")
- vend_ready = TRUE
-
- if("togglevoice")
- if(!panel_open)
- return FALSE
- shut_up = !shut_up
-
-/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
- if(!allowed(user) && !emagged && scan_id)
- to_chat(user, "Access denied.") //Unless emagged of course
- flick("[icon_state]-deny",src)
- playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
- return FALSE
- return TRUE
-
-/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
- if(!can_buy(R, user))
- return
-
- if(!R.amount)
- to_chat(user, "[src] has ran out of that product.")
- vend_ready = TRUE
- return
-
- vend_ready = FALSE //One thing at a time!!
- SStgui.update_uis(src)
-
- if(R.category & CAT_COIN)
- if(!coin)
- to_chat(user, "You need to insert a coin to get this item.")
- return
- if(coin.string_attached)
- if(prob(50))
- to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.")
- else
- to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.")
- qdel(coin)
- coin = null
- categories &= ~CAT_COIN
- else
- qdel(coin)
- coin = null
- categories &= ~CAT_COIN
-
- if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply)
- spawn(0)
- speak(vend_reply)
- last_reply = world.time
-
- use_power(vend_power_usage) //actuators and stuff
- flick("[icon_state]-vend",src)
- addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
-
-/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
- R.get_product(get_turf(src))
- if(has_logs)
- do_logging(R, user, 1)
- if(prob(1))
- sleep(3)
- if(R.get_product(get_turf(src)))
- visible_message("\The [src] clunks as it vends an additional item.")
- playsound(src, "sound/[vending_sound]", 100, 1, 1)
-
- vend_ready = 1
- currently_vending = null
- SStgui.update_uis(src)
- GLOB.items_sold_shift_roundstat++
-
-/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
- if(user.GetIdCard())
- var/obj/item/weapon/card/id/tempid = user.GetIdCard()
- var/list/list_item = list()
- if(vending)
- list_item += "vend"
- else
- list_item += "stock"
- list_item += tempid.registered_name
- list_item += stationtime2text()
- list_item += R.item_name
- log[++log.len] = list_item
-
-/obj/machinery/vending/proc/show_log(mob/user as mob)
- if(user.GetIdCard())
- var/obj/item/weapon/card/id/tempid = user.GetIdCard()
- if(req_log_access in tempid.GetAccess())
- var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500)
- var/dat = ""
- dat += "[name] Vending Log"
- dat += "Welcome [user.name]!
"
- dat += "Below are the recent vending logs for your vending machine.
"
- for(var/i in log)
- dat += json_encode(i)
- dat += ";
"
- popup.set_content(dat)
- popup.open()
- else
- to_chat(user,"You do not have the required access to view the vending logs for this machine.")
-
-
-/obj/machinery/vending/verb/rotate_clockwise()
- set name = "Rotate Vending Machine Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.can_rotate == 0)
- to_chat(usr, "\The [src] cannot be rotated.")
- return 0
-
- if (src.anchored || usr:stat)
- to_chat(usr, "It is bolted down!")
- return 0
- src.set_dir(turn(src.dir, 270))
- return 1
-
-/obj/machinery/vending/verb/check_logs()
- set name = "Check Vending Logs"
- set category = "Object"
- set src in oview(1)
-
- show_log(usr)
-
-/**
- * Add item to the machine
- *
- * Checks if item is vendable in this machine should be performed before
- * calling. W is the item being inserted, R is the associated vending_product entry.
- */
-/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user)
- if(!user.unEquip(W))
- return
-
- to_chat(user, "You insert \the [W] in the product receptor.")
- R.add_product(W)
- if(has_logs)
- do_logging(R, user)
-
- SStgui.update_uis(src)
-
-/obj/machinery/vending/process()
- if(stat & (BROKEN|NOPOWER))
- return
-
- if(!active)
- return
-
- if(seconds_electrified > 0)
- seconds_electrified--
-
- //Pitch to the people! Really sell it!
- if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5))
- var/slogan = pick(slogan_list)
- speak(slogan)
- last_slogan = world.time
-
- if(shoot_inventory && prob(2))
- throw_item()
-
- return
-
-/obj/machinery/vending/proc/speak(var/message)
- if(stat & NOPOWER)
- return
-
- if(!message)
- return
-
- for(var/mob/O in hearers(src, null))
- O.show_message("\The [src] beeps, \"[message]\"",2)
- return
-
-/obj/machinery/vending/power_change()
- ..()
- if(stat & BROKEN)
- icon_state = "[initial(icon_state)]-broken"
- else
- if(!(stat & NOPOWER))
- icon_state = initial(icon_state)
- else
- spawn(rand(0, 15))
- icon_state = "[initial(icon_state)]-off"
-
-//Oh no we're malfunctioning! Dump out some product and break.
-/obj/machinery/vending/proc/malfunction()
- for(var/datum/stored_item/vending_product/R in product_records)
- while(R.get_amount()>0)
- R.get_product(loc)
- break
-
- stat |= BROKEN
- icon_state = "[initial(icon_state)]-broken"
- return
-
-//Somebody cut an important wire and now we're following a new definition of "pitch."
-/obj/machinery/vending/proc/throw_item()
- var/obj/throw_item = null
- var/mob/living/target = locate() in view(7,src)
- if(!target)
- return 0
-
- for(var/datum/stored_item/vending_product/R in product_records)
- throw_item = R.get_product(loc)
- if(!throw_item)
- continue
- break
- if(!throw_item)
- return 0
- spawn(0)
- throw_item.throw_at(target, 16, 3, src)
- visible_message("\The [src] launches \a [throw_item] at \the [target]!")
- return 1
-
-//Actual machines are in vending_machines.dm
+///
+/// A vending machine
+///
+
+//
+// ALL THE VENDING MACHINES ARE IN vending_machines.dm now!
+//
+
+/obj/machinery/vending
+ name = "Vendomat"
+ desc = "A generic vending machine."
+ icon = 'icons/obj/vending.dmi'
+ icon_state = "generic"
+ anchored = 1
+ density = 1
+ clicksound = "button"
+
+ // Power
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 10
+ var/vend_power_usage = 150 //actuators and stuff
+
+ // Vending-related
+ var/active = 1 //No sales pitches if off!
+ var/vend_ready = 1 //Are we ready to vend?? Is it time??
+ var/vend_delay = 10 //How long does it take to vend?
+ var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
+ var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
+ var/vending_sound = "machines/vending/vending_drop.ogg"
+
+ /*
+ Variables used to initialize the product list
+ These are used for initialization only, and so are optional if
+ product_records is specified
+ */
+ var/list/products = list() // For each, use the following pattern:
+ var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2)
+ var/list/premium = list() // No specified amount = only one in stock
+ var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price.
+
+ // List of vending_product items available.
+ var/list/product_records = list()
+
+
+ // Variables used to initialize advertising
+ var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons
+ var/product_ads = "" //String of small ad messages in the vending screen
+
+ var/list/ads_list = list()
+
+ // Stuff relating vocalizations
+ var/list/slogan_list = list()
+ var/shut_up = 1 //Stop spouting those godawful pitches!
+ var/vend_reply //Thank you for shopping!
+ var/last_reply = 0
+ var/last_slogan = 0 //When did we last pitch?
+ var/slogan_delay = 6000 //How long until we can pitch again?
+
+ // Things that can go wrong
+ emagged = 0 //Ignores if somebody doesn't have card access to that machine.
+ var/seconds_electrified = 0 //Shock customers like an airlock.
+ var/shoot_inventory = 0 //Fire items at customers! We're broken!
+
+ var/scan_id = 1
+ var/obj/item/weapon/coin/coin
+ var/datum/wires/vending/wires = null
+
+ var/list/log = list()
+ var/req_log_access = access_cargo //default access for checking logs is cargo
+ var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs
+ var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals.
+
+
+/obj/machinery/vending/Initialize()
+ . = ..()
+ wires = new(src)
+ if(product_slogans)
+ slogan_list += splittext(product_slogans, ";")
+
+ // So not all machines speak at the exact same time.
+ // The first time this machine says something will be at slogantime + this random value,
+ // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated.
+ last_slogan = world.time + rand(0, slogan_delay)
+
+ if(product_ads)
+ ads_list += splittext(product_ads, ";")
+
+ build_inventory()
+ power_change()
+
+GLOBAL_LIST_EMPTY(vending_products)
+/**
+ * Build produdct_records from the products lists
+ *
+ * products, contraband, premium, and prices allow specifying
+ * products that the vending machine is to carry without manually populating
+ * product_records.
+ */
+/obj/machinery/vending/proc/build_inventory()
+ var/list/all_products = list(
+ list(products, CAT_NORMAL),
+ list(contraband, CAT_HIDDEN),
+ list(premium, CAT_COIN))
+
+ for(var/current_list in all_products)
+ var/category = current_list[2]
+
+ for(var/entry in current_list[1])
+ var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry)
+
+ product.price = (entry in prices) ? prices[entry] : 0
+ product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1
+ product.category = category
+
+ product_records.Add(product)
+ GLOB.vending_products[entry] = 1
+
+/obj/machinery/vending/Destroy()
+ qdel(wires)
+ wires = null
+ qdel(coin)
+ coin = null
+ for(var/datum/stored_item/vending_product/R in product_records)
+ qdel(R)
+ product_records = null
+ return ..()
+
+/obj/machinery/vending/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if(prob(50))
+ qdel(src)
+ return
+ if(3.0)
+ if(prob(25))
+ spawn(0)
+ malfunction()
+ return
+ return
+ else
+ return
+
+/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user)
+ if(!emagged)
+ emagged = 1
+ to_chat(user, "You short out \the [src]'s product lock.")
+ return 1
+
+/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ var/obj/item/weapon/card/id/I = W.GetID()
+
+ if(I || istype(W, /obj/item/weapon/spacecash))
+ attack_hand(user)
+ return
+ else if(W.is_screwdriver())
+ panel_open = !panel_open
+ to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
+ playsound(src, W.usesound, 50, 1)
+ if(panel_open)
+ wires.Interact(user)
+ add_overlay("[initial(icon_state)]-panel")
+ else
+ cut_overlay("[initial(icon_state)]-panel")
+
+ SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI
+ return
+ else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter())
+ if(panel_open)
+ attack_hand(user)
+ return
+ else if(istype(W, /obj/item/weapon/coin) && premium.len > 0)
+ user.drop_item()
+ W.forceMove(src)
+ coin = W
+ categories |= CAT_COIN
+ to_chat(user, "You insert \the [W] into \the [src].")
+ SStgui.update_uis(src)
+ return
+ else if(W.is_wrench())
+ playsound(src, W.usesound, 100, 1)
+ if(anchored)
+ user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
+ else
+ user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
+
+ if(do_after(user, 20 * W.toolspeed))
+ if(!src) return
+ to_chat(user, "You [anchored? "un" : ""]secured \the [src]!")
+ anchored = !anchored
+ return
+ else
+
+ for(var/datum/stored_item/vending_product/R in product_records)
+ if(istype(W, R.item_path) && (W.name == R.item_name))
+ stock(W, R, user)
+ return
+ ..()
+
+/**
+ * Receive payment with cashmoney.
+ *
+ * usr is the mob who gets the change.
+ */
+/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user)
+ if(currently_vending.price > cashmoney.worth)
+
+ // This is not a status display message, since it's something the character
+ // themselves is meant to see BEFORE putting the money in
+ to_chat(usr, "[bicon(cashmoney)] That is not enough money.")
+ return 0
+
+ if(istype(cashmoney, /obj/item/weapon/spacecash))
+
+ visible_message("\The [usr] inserts some cash into \the [src].")
+ cashmoney.worth -= currently_vending.price
+
+ if(cashmoney.worth <= 0)
+ usr.drop_from_inventory(cashmoney)
+ qdel(cashmoney)
+ else
+ cashmoney.update_icon()
+
+ // Vending machines have no idea who paid with cash
+ credit_purchase("(cash)")
+ return 1
+
+/**
+ * Scan a chargecard and deduct payment from it.
+ *
+ * Takes payment for whatever is the currently_vending item. Returns 1 if
+ * successful, 0 if failed.
+ */
+/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet)
+ visible_message("\The [usr] swipes \the [wallet] through \the [src].")
+ playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
+ if(currently_vending.price > wallet.worth)
+ to_chat(usr, "Insufficient funds on chargecard.")
+ return 0
+ else
+ wallet.worth -= currently_vending.price
+ credit_purchase("[wallet.owner_name] (chargecard)")
+ return 1
+
+/**
+ * Scan a card and attempt to transfer payment from associated account.
+ *
+ * Takes payment for whatever is the currently_vending item. Returns 1 if
+ * successful, 0 if failed
+ */
+/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
+ visible_message("[M] swipes a card through [src].")
+ playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
+
+ var/datum/money_account/customer_account = get_account(I.associated_account_number)
+ if(!customer_account)
+ to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.")
+ return FALSE
+
+ if(customer_account.suspended)
+ to_chat(M, "Unable to access account: account suspended.")
+ return FALSE
+
+ // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
+ // empty at high security levels
+ if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
+ var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
+ customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
+
+ if(!customer_account)
+ to_chat(M, "Unable to access account: incorrect credentials.")
+ return FALSE
+
+ if(currently_vending.price > customer_account.money)
+ to_chat(M, "Insufficient funds in account.")
+ return FALSE
+
+ // Okay to move the money at this point
+
+ // debit money from the purchaser's account
+ customer_account.money -= currently_vending.price
+
+ // create entry in the purchaser's account log
+ var/datum/transaction/T = new()
+ T.target_name = "[vendor_account.owner_name] (via [name])"
+ T.purpose = "Purchase of [currently_vending.item_name]"
+ if(currently_vending.price > 0)
+ T.amount = "([currently_vending.price])"
+ else
+ T.amount = "[currently_vending.price]"
+ T.source_terminal = name
+ T.date = current_date_string
+ T.time = stationtime2text()
+ customer_account.transaction_log.Add(T)
+
+ // Give the vendor the money. We use the account owner name, which means
+ // that purchases made with stolen/borrowed card will look like the card
+ // owner made them
+ credit_purchase(customer_account.owner_name)
+ return 1
+
+/**
+ * Add money for current purchase to the vendor account.
+ *
+ * Called after the money has already been taken from the customer.
+ */
+/obj/machinery/vending/proc/credit_purchase(var/target as text)
+ vendor_account.money += currently_vending.price
+
+ var/datum/transaction/T = new()
+ T.target_name = target
+ T.purpose = "Purchase of [currently_vending.item_name]"
+ T.amount = "[currently_vending.price]"
+ T.source_terminal = name
+ T.date = current_date_string
+ T.time = stationtime2text()
+ vendor_account.transaction_log.Add(T)
+
+/obj/machinery/vending/attack_ghost(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/vending/attack_ai(mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/vending/attack_hand(mob/user as mob)
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ if(seconds_electrified != 0)
+ if(shock(user, 100))
+ return
+
+ wires.Interact(user)
+ tgui_interact(user)
+
+/obj/machinery/vending/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/vending),
+ )
+
+/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Vending", name)
+ ui.open()
+
+/obj/machinery/vending/tgui_data(mob/user)
+ var/list/data = list()
+ var/list/listed_products = list()
+
+ data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
+ for(var/key = 1 to product_records.len)
+ var/datum/stored_item/vending_product/I = product_records[key]
+
+ if(!(I.category & categories))
+ continue
+
+ listed_products.Add(list(list(
+ "key" = key,
+ "name" = I.item_name,
+ "desc" = I.item_desc,
+ "price" = I.price,
+ "color" = I.display_color,
+ "isatom" = ispath(I.item_path, /atom),
+ "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
+ "amount" = I.get_amount()
+ )))
+
+ data["products"] = listed_products
+
+ if(coin)
+ data["coin"] = coin.name
+ else
+ data["coin"] = FALSE
+
+ if(currently_vending)
+ data["actively_vending"] = currently_vending.item_name
+ else
+ data["actively_vending"] = null
+
+ if(panel_open)
+ data["panel"] = 1
+ data["speaker"] = shut_up ? 0 : 1
+ else
+ data["panel"] = 0
+
+ var/mob/living/carbon/human/H
+ var/obj/item/weapon/card/id/C
+
+ data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
+ data["userMoney"] = 0
+ data["user"] = null
+ if(ishuman(user))
+ H = user
+ C = H.GetIdCard()
+ var/obj/item/weapon/spacecash/S = H.get_active_hand()
+ if(istype(S))
+ data["userMoney"] = S.worth
+ data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]â‚®."
+ else if(istype(C))
+ var/datum/money_account/A = get_account(C.associated_account_number)
+ if(istype(A))
+ data["user"] = list()
+ data["user"]["name"] = A.owner_name
+ data["userMoney"] = A.money
+ data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
+ else
+ data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
+
+ return data
+
+/obj/machinery/vending/tgui_act(action, params)
+ if(stat & (BROKEN|NOPOWER))
+ return
+ if(usr.stat || usr.restrained())
+ return
+ if(..())
+ return TRUE
+
+ . = TRUE
+ switch(action)
+ if("remove_coin")
+ if(issilicon(usr))
+ return FALSE
+
+ if(!coin)
+ to_chat(usr, "There is no coin in this machine.")
+ return
+
+ coin.forceMove(src.loc)
+ if(!usr.get_active_hand())
+ usr.put_in_hands(coin)
+
+ to_chat(usr, "You remove \the [coin] from \the [src].")
+ coin = null
+ categories &= ~CAT_COIN
+ return TRUE
+ if("vend")
+ if(!vend_ready)
+ to_chat(usr, "[src] is busy!")
+ return
+ if(!allowed(usr) && !emagged && scan_id)
+ to_chat(usr, "Access denied.") //Unless emagged of course
+ flick("[icon_state]-deny",src)
+ playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
+ return
+ if(panel_open)
+ to_chat(usr, "[src] cannot dispense products while its service panel is open!")
+ return
+
+ var/key = text2num(params["vend"])
+ var/datum/stored_item/vending_product/R = product_records[key]
+
+ // This should not happen unless the request from NanoUI was bad
+ if(!(R.category & categories))
+ return
+
+ if(!can_buy(R, usr))
+ return
+
+ if(R.price <= 0)
+ vend(R, usr)
+ add_fingerprint(usr)
+ return TRUE
+
+ if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
+ to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.")
+ return
+ if(!ishuman(usr))
+ return
+
+ vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
+
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/weapon/card/id/C = H.GetIdCard()
+
+ if(!vendor_account || vendor_account.suspended)
+ to_chat(usr, "Vendor account offline. Unable to process transaction.")
+ flick("[icon_state]-deny",src)
+ vend_ready = TRUE
+ return
+
+ currently_vending = R
+
+ var/paid = FALSE
+
+ if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
+ var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
+ paid = pay_with_cash(cash, usr)
+ else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
+ var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
+ paid = pay_with_ewallet(wallet)
+ else if(istype(C, /obj/item/weapon/card))
+ paid = pay_with_card(C, usr)
+ /*else if(usr.can_advanced_admin_interact())
+ to_chat(usr, "Vending object due to admin interaction.")
+ paid = TRUE*/
+ else
+ to_chat(usr, "Payment failure: you have no ID or other method of payment.")
+ vend_ready = TRUE
+ flick("[icon_state]-deny",src)
+ return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
+ if(paid)
+ vend(currently_vending, usr) // vend will handle vend_ready
+ . = TRUE
+ else
+ to_chat(usr, "Payment failure: unable to process payment.")
+ vend_ready = TRUE
+
+ if("togglevoice")
+ if(!panel_open)
+ return FALSE
+ shut_up = !shut_up
+
+/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
+ if(!allowed(user) && !emagged && scan_id)
+ to_chat(user, "Access denied.") //Unless emagged of course
+ flick("[icon_state]-deny",src)
+ playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
+ return FALSE
+ return TRUE
+
+/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
+ if(!can_buy(R, user))
+ return
+
+ if(!R.amount)
+ to_chat(user, "[src] has ran out of that product.")
+ vend_ready = TRUE
+ return
+
+ vend_ready = FALSE //One thing at a time!!
+ SStgui.update_uis(src)
+
+ if(R.category & CAT_COIN)
+ if(!coin)
+ to_chat(user, "You need to insert a coin to get this item.")
+ return
+ if(coin.string_attached)
+ if(prob(50))
+ to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.")
+ else
+ to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.")
+ qdel(coin)
+ coin = null
+ categories &= ~CAT_COIN
+ else
+ qdel(coin)
+ coin = null
+ categories &= ~CAT_COIN
+
+ if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply)
+ spawn(0)
+ speak(vend_reply)
+ last_reply = world.time
+
+ use_power(vend_power_usage) //actuators and stuff
+ flick("[icon_state]-vend",src)
+ addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
+
+/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
+ R.get_product(get_turf(src))
+ if(has_logs)
+ do_logging(R, user, 1)
+ if(prob(1))
+ sleep(3)
+ if(R.get_product(get_turf(src)))
+ visible_message("\The [src] clunks as it vends an additional item.")
+ playsound(src, "sound/[vending_sound]", 100, 1, 1)
+
+ GLOB.items_sold_shift_roundstat++
+
+ vend_ready = 1
+ currently_vending = null
+ SStgui.update_uis(src)
+
+
+/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ var/list/list_item = list()
+ if(vending)
+ list_item += "vend"
+ else
+ list_item += "stock"
+ list_item += tempid.registered_name
+ list_item += stationtime2text()
+ list_item += R.item_name
+ log[++log.len] = list_item
+
+/obj/machinery/vending/proc/show_log(mob/user as mob)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ if(req_log_access in tempid.GetAccess())
+ var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500)
+ var/dat = ""
+ dat += "[name] Vending Log"
+ dat += "Welcome [user.name]!
"
+ dat += "Below are the recent vending logs for your vending machine.
"
+ for(var/i in log)
+ dat += json_encode(i)
+ dat += ";
"
+ popup.set_content(dat)
+ popup.open()
+ else
+ to_chat(user,"You do not have the required access to view the vending logs for this machine.")
+
+
+/obj/machinery/vending/verb/rotate_clockwise()
+ set name = "Rotate Vending Machine Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.can_rotate == 0)
+ to_chat(usr, "\The [src] cannot be rotated.")
+ return 0
+
+ if (src.anchored || usr:stat)
+ to_chat(usr, "It is bolted down!")
+ return 0
+ src.set_dir(turn(src.dir, 270))
+ return 1
+
+/obj/machinery/vending/verb/check_logs()
+ set name = "Check Vending Logs"
+ set category = "Object"
+ set src in oview(1)
+
+ show_log(usr)
+
+/**
+ * Add item to the machine
+ *
+ * Checks if item is vendable in this machine should be performed before
+ * calling. W is the item being inserted, R is the associated vending_product entry.
+ */
+/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user)
+ if(!user.unEquip(W))
+ return
+
+ to_chat(user, "You insert \the [W] in the product receptor.")
+ R.add_product(W)
+ if(has_logs)
+ do_logging(R, user)
+
+ SStgui.update_uis(src)
+
+/obj/machinery/vending/process()
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ if(!active)
+ return
+
+ if(seconds_electrified > 0)
+ seconds_electrified--
+
+ //Pitch to the people! Really sell it!
+ if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5))
+ var/slogan = pick(slogan_list)
+ speak(slogan)
+ last_slogan = world.time
+
+ if(shoot_inventory && prob(2))
+ throw_item()
+
+ return
+
+/obj/machinery/vending/proc/speak(var/message)
+ if(stat & NOPOWER)
+ return
+
+ if(!message)
+ return
+
+ for(var/mob/O in hearers(src, null))
+ O.show_message("\The [src] beeps, \"[message]\"",2)
+ return
+
+/obj/machinery/vending/power_change()
+ ..()
+ if(stat & BROKEN)
+ icon_state = "[initial(icon_state)]-broken"
+ else
+ if(!(stat & NOPOWER))
+ icon_state = initial(icon_state)
+ else
+ spawn(rand(0, 15))
+ icon_state = "[initial(icon_state)]-off"
+
+//Oh no we're malfunctioning! Dump out some product and break.
+/obj/machinery/vending/proc/malfunction()
+ for(var/datum/stored_item/vending_product/R in product_records)
+ while(R.get_amount()>0)
+ R.get_product(loc)
+ break
+
+ stat |= BROKEN
+ icon_state = "[initial(icon_state)]-broken"
+ return
+
+//Somebody cut an important wire and now we're following a new definition of "pitch."
+/obj/machinery/vending/proc/throw_item()
+ var/obj/throw_item = null
+ var/mob/living/target = locate() in view(7,src)
+ if(!target)
+ return 0
+
+ for(var/datum/stored_item/vending_product/R in product_records)
+ throw_item = R.get_product(loc)
+ if(!throw_item)
+ continue
+ break
+ if(!throw_item)
+ return 0
+ spawn(0)
+ throw_item.throw_at(target, 16, 3, src)
+ visible_message("\The [src] launches \a [throw_item] at \the [target]!")
+ return 1
+
+//Actual machines are in vending_machines.dm
diff --git a/code/game/machinery/vending_machines.dm b/code/modules/economy/vending_machines.dm
similarity index 100%
rename from code/game/machinery/vending_machines.dm
rename to code/modules/economy/vending_machines.dm
diff --git a/code/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm
new file mode 100644
index 00000000000..8c10b4cde2f
--- /dev/null
+++ b/code/modules/emotes/definitions/_mob.dm
@@ -0,0 +1,41 @@
+var/list/_default_mob_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+)
+
+/mob
+ var/list/usable_emotes
+
+/mob/proc/update_emotes(var/skip_sort)
+ usable_emotes = list()
+ for(var/emote in get_default_emotes())
+ var/decl/emote/emote_datum = decls_repository.get_decl(emote)
+ if(emote_datum.check_user(src))
+ usable_emotes[emote_datum.key] = emote_datum
+ if(!skip_sort)
+ usable_emotes = sortAssoc(usable_emotes)
+
+/mob/proc/get_default_emotes()
+ return global._default_mob_emotes
diff --git a/code/modules/emotes/definitions/_species.dm b/code/modules/emotes/definitions/_species.dm
new file mode 100644
index 00000000000..ff15df2fae5
--- /dev/null
+++ b/code/modules/emotes/definitions/_species.dm
@@ -0,0 +1,11 @@
+/datum/species
+ var/list/default_emotes = list()
+
+/mob/living/carbon/update_emotes(var/skip_sort)
+ . = ..(skip_sort = TRUE)
+ if(species)
+ for(var/emote in species.default_emotes)
+ var/decl/emote/emote_datum = decls_repository.get_decl(emote)
+ if(emote_datum.check_user(src))
+ usable_emotes[emote_datum.key] = emote_datum
+ usable_emotes = sortAssoc(usable_emotes)
diff --git a/code/modules/emotes/definitions/audible.dm b/code/modules/emotes/definitions/audible.dm
new file mode 100644
index 00000000000..15f547b9e85
--- /dev/null
+++ b/code/modules/emotes/definitions/audible.dm
@@ -0,0 +1,229 @@
+/decl/emote/audible
+ key = "burp"
+ emote_message_3p = "burps."
+ message_type = AUDIBLE_MESSAGE
+
+/decl/emote/audible/New()
+ . = ..()
+ // Snips the 'USER' from 3p emote messages for radio.
+ if(!emote_message_radio && emote_message_3p)
+ emote_message_radio = emote_message_3p
+ if(!emote_message_radio_synthetic && emote_message_synthetic_3p)
+ emote_message_radio_synthetic = emote_message_synthetic_3p
+
+/decl/emote/audible/deathgasp_alien
+ key = "deathgasp"
+ emote_message_3p = "lets out a waning guttural screech, green blood bubbling from its maw."
+
+/decl/emote/audible/whimper
+ key = "whimper"
+ emote_message_3p = "whimpers."
+
+/decl/emote/audible/gasp
+ key = "gasp"
+ emote_message_3p = "gasps."
+ conscious = FALSE
+
+/decl/emote/audible/scretch
+ key = "scretch"
+ emote_message_3p = "scretches."
+
+/decl/emote/audible/choke
+ key ="choke"
+ emote_message_3p = "chokes."
+ conscious = FALSE
+
+/decl/emote/audible/gnarl
+ key = "gnarl"
+ emote_message_3p = "gnarls and shows USER_THEIR teeth."
+
+/decl/emote/audible/multichirp
+ key = "mchirp"
+ emote_message_3p = "chirps a chorus of notes!"
+ emote_sound = 'sound/voice/multichirp.ogg'
+
+/decl/emote/audible/alarm
+ key = "alarm"
+ emote_message_1p = "You sound an alarm."
+ emote_message_3p = "sounds an alarm."
+
+/decl/emote/audible/alert
+ key = "alert"
+ emote_message_1p = "You let out a distressed noise."
+ emote_message_3p = "lets out a distressed noise."
+
+/decl/emote/audible/notice
+ key = "notice"
+ emote_message_1p = "You play a loud tone."
+ emote_message_3p = "plays a loud tone."
+
+/decl/emote/audible/boop
+ key = "boop"
+ emote_message_1p = "You boop."
+ emote_message_3p = "boops."
+
+/decl/emote/audible/beep
+ key = "beep"
+ emote_message_3p = "You beep."
+ emote_message_3p = "beeps."
+ emote_sound = 'sound/machines/twobeep.ogg'
+
+/decl/emote/audible/sniff
+ key = "sniff"
+ emote_message_3p = "sniffs."
+
+/decl/emote/audible/snore
+ key = "snore"
+ emote_message_3p = "snores."
+ conscious = FALSE
+
+/decl/emote/audible/whimper
+ key = "whimper"
+ emote_message_3p = "whimpers."
+
+/decl/emote/audible/yawn
+ key = "yawn"
+ emote_message_3p = "yawns."
+
+/decl/emote/audible/clap
+ key = "clap"
+ emote_message_3p = "claps."
+
+/decl/emote/audible/chuckle
+ key = "chuckle"
+ emote_message_3p = "chuckles."
+
+/decl/emote/audible/cry
+ key = "cry"
+ emote_message_3p = "cries."
+
+/decl/emote/audible/sigh
+ key = "sigh"
+ emote_message_3p = "sighs."
+
+/decl/emote/audible/laugh
+ key = "laugh"
+ emote_message_3p_target = "laughs at TARGET."
+ emote_message_3p = "laughs."
+
+/decl/emote/audible/mumble
+ key = "mumble"
+ emote_message_3p = "mumbles!"
+
+/decl/emote/audible/grumble
+ key = "grumble"
+ emote_message_3p = "grumbles!"
+
+/decl/emote/audible/groan
+ key = "groan"
+ emote_message_3p = "groans!"
+ conscious = FALSE
+
+/decl/emote/audible/moan
+ key = "moan"
+ emote_message_3p = "moans!"
+ conscious = FALSE
+
+/decl/emote/audible/giggle
+ key = "giggle"
+ emote_message_3p = "giggles."
+
+/decl/emote/audible/grunt
+ key = "grunt"
+ emote_message_3p = "grunts."
+
+/decl/emote/audible/bug_hiss
+ key ="hiss"
+ emote_message_3p_target = "hisses at TARGET."
+ emote_message_3p = "hisses."
+ emote_sound = 'sound/voice/BugHiss.ogg'
+
+/decl/emote/audible/bug_buzz
+ key ="buzz"
+ emote_message_3p = "buzzes its wings."
+ emote_sound = 'sound/voice/BugBuzz.ogg'
+
+/decl/emote/audible/bug_chitter
+ key ="chitter"
+ emote_message_3p = "chitters."
+ emote_sound = 'sound/voice/Bug.ogg'
+
+/decl/emote/audible/roar
+ key = "roar"
+ emote_message_3p = "roars!"
+
+/decl/emote/audible/bellow
+ key = "bellow"
+ emote_message_3p = "bellows!"
+
+/decl/emote/audible/howl
+ key = "howl"
+ emote_message_3p = "howls!"
+
+/decl/emote/audible/wheeze
+ key = "wheeze"
+ emote_message_3p = "wheezes."
+
+/decl/emote/audible/hiss
+ key = "hiss"
+ emote_message_3p_target = "hisses softly at TARGET."
+ emote_message_3p = "hisses softly."
+
+/decl/emote/audible/chirp
+ key = "chirp"
+ emote_message_3p = "chirps!"
+ emote_sound = 'sound/misc/nymphchirp.ogg'
+
+/decl/emote/audible/crack
+ key = "crack"
+ emote_message_3p = "cracks USER_THEIR knuckles."
+ emote_sound = 'sound/voice/knuckles.ogg'
+
+/decl/emote/audible/squish
+ key = "squish"
+ emote_sound = 'sound/effects/slime_squish.ogg' //Credit to DrMinky (freesound.org) for the sound.
+ emote_message_3p = "squishes."
+
+/decl/emote/audible/warble
+ key = "warble"
+ emote_sound = 'sound/effects/warble.ogg' // Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
+ emote_message_3p = "warbles."
+
+/decl/emote/audible/vox_shriek
+ key = "shriek"
+ emote_message_3p = "SHRIEKS!"
+ emote_sound = 'sound/voice/shriek1.ogg'
+
+/decl/emote/audible/purr
+ key = "purr"
+ emote_message_3p = "purrs."
+ emote_sound = 'sound/voice/cat_purr.ogg'
+
+/decl/emote/audible/purrlong
+ key = "purrl"
+ emote_message_3p = "purrs."
+ emote_sound = 'sound/voice/cat_purr_long.ogg'
+
+/decl/emote/audible/teshsqueak
+ key = "surprised"
+ emote_message_1p = "You chirp in surprise!"
+ emote_message_3p = "chirps in surprise!"
+ emote_message_1p_target = "You chirp in surprise at TARGET!"
+ emote_message_3p_target = "chirps in surprise at TARGET!"
+ emote_sound = 'sound/voice/teshsqueak.ogg' // Copyright CC BY 3.0 InspectorJ (freesound.org) for the source audio.
+
+/decl/emote/audible/teshchirp
+ key = "chirp"
+ emote_message_1p = "You chirp!"
+ emote_message_3p = "chirps!"
+ emote_message_1p_target = "You chirp at TARGET!"
+ emote_message_3p_target = "chirps at TARGET!"
+ emote_sound = 'sound/voice/teshchirp.ogg' // Copyright Sampling+ 1.0 Incarnidine (freesound.org) for the source audio.
+
+/decl/emote/audible/teshtrill
+ key = "trill"
+ emote_message_1p = "You trill."
+ emote_message_3p = "trills."
+ emote_message_1p_target = "You trill at TARGET."
+ emote_message_3p_target = "trills at TARGET."
+ emote_sound = 'sound/voice/teshtrill.ogg' // Copyright CC BY-NC 3.0 Arnaud Coutancier (freesound.org) for the source audio.
diff --git a/code/modules/emotes/definitions/audible_cough.dm b/code/modules/emotes/definitions/audible_cough.dm
new file mode 100644
index 00000000000..4e28d1db918
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_cough.dm
@@ -0,0 +1,52 @@
+/decl/emote/audible/cough
+ key = "cough"
+ emote_message_1p = "You cough!"
+ emote_message_1p_target = "You cough on TARGET!"
+ emote_message_3p = "coughs!"
+ emote_message_3p_target = "coughs on TARGET!"
+ emote_message_synthetic_1p_target = "You emit a robotic cough towards TARGET."
+ emote_message_synthetic_1p = "You emit a robotic cough."
+ emote_message_synthetic_3p_target = "emits a robotic cough towards TARGET."
+ emote_message_synthetic_3p = "emits a robotic cough."
+ emote_volume = 120
+ emote_volume_synthetic = 50
+
+ conscious = FALSE
+ emote_sound_synthetic = list(
+ FEMALE = list(
+ 'sound/effects/mob_effects/f_machine_cougha.ogg',
+ 'sound/effects/mob_effects/f_machine_coughb.ogg'
+ ),
+ MALE = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ ),
+ NEUTER = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ ),
+ PLURAL = list(
+ 'sound/effects/mob_effects/m_machine_cougha.ogg',
+ 'sound/effects/mob_effects/m_machine_coughb.ogg',
+ 'sound/effects/mob_effects/m_machine_coughc.ogg'
+ )
+ )
+
+/decl/emote/audible/cough/get_emote_sound(var/atom/user)
+ if(ishuman(user) && !check_synthetic(user))
+ var/mob/living/carbon/human/H = user
+ if(H.get_gender() == FEMALE)
+ if(length(H.species.female_cough_sounds))
+ return list(
+ "sound" = H.species.female_cough_sounds,
+ "vol" = emote_volume
+ )
+ else
+ if(length(H.species.male_cough_sounds))
+ return list(
+ "sound" = H.species.male_cough_sounds,
+ "vol" = emote_volume
+ )
+ return ..()
diff --git a/code/modules/emotes/definitions/audible_furry_vr.dm b/code/modules/emotes/definitions/audible_furry_vr.dm
new file mode 100644
index 00000000000..681e9101a29
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_furry_vr.dm
@@ -0,0 +1,129 @@
+/decl/emote/audible/awoo
+ key = "awoo"
+ emote_message_3p = "lets out an awoo."
+ emote_sound = 'sound/voice/awoo.ogg'
+/decl/emote/audible/awoo2
+ key = "awoo2"
+ emote_message_3p = "lets out an awoo."
+ emote_sound = 'sound/voice/long_awoo.ogg'
+/decl/emote/audible/growl
+ key = "growl"
+ emote_message_3p = "lets out a growl."
+ emote_sound = 'sound/voice/growl.ogg'
+/decl/emote/audible/woof
+ key = "woof"
+ emote_message_3p = "lets out a woof."
+ emote_sound = 'sound/voice/woof.ogg'
+/decl/emote/audible/woof2
+ key = "woof2"
+ emote_message_3p = "lets out a woof."
+ emote_sound = 'sound/voice/woof2.ogg'
+/decl/emote/audible/nya
+ key = "nya"
+ emote_message_3p = "lets out a nya."
+ emote_sound = 'sound/voice/nya.ogg'
+/decl/emote/audible/mrowl
+ key = "mrowl"
+ emote_message_3p = "mrowls."
+ emote_sound = 'sound/voice/mrow.ogg'
+/decl/emote/audible/peep
+ key = "peep"
+ emote_message_3p = "peeps like a bird."
+ emote_sound = 'sound/voice/peep.ogg'
+/decl/emote/audible/chirp
+ key = "chirp"
+ emote_message_3p = "chirps!"
+ emote_sound = 'sound/misc/nymphchirp.ogg'
+/decl/emote/audible/hoot
+ key = "hoot"
+ emote_message_3p = "hoots!"
+ emote_sound = 'sound/voice/hoot.ogg'
+/decl/emote/audible/weh
+ key = "weh"
+ emote_message_3p = "lets out a weh."
+ emote_sound = 'sound/voice/weh.ogg'
+/decl/emote/audible/merp
+ key = "merp"
+ emote_message_3p = "lets out a merp."
+ emote_sound = 'sound/voice/merp.ogg'
+/decl/emote/audible/myarp
+ key = "myarp"
+ emote_message_3p = "lets out a myarp."
+ emote_sound = 'sound/voice/myarp.ogg'
+/decl/emote/audible/bark
+ key = "bark"
+ emote_message_3p = "lets out a bark."
+ emote_sound = 'sound/voice/bark2.ogg'
+/decl/emote/audible/bork
+ key = "bork"
+ emote_message_3p = "lets out a bork."
+ emote_sound = 'sound/voice/bork.ogg'
+/decl/emote/audible/mrow
+ emote_message_3p = "lets out a mrow."
+ emote_sound = 'sound/voice/mrow.ogg'
+/decl/emote/audible/hypno
+ emote_message_3p = "lets out a mystifying tone."
+ emote_sound = 'sound/voice/hypno.ogg'
+/decl/emote/audible/hiss
+ key = "hiss"
+ emote_message_3p = "lets out a hiss."
+ emote_sound = 'sound/voice/hiss.ogg'
+/decl/emote/audible/rattle
+ key = "rattle"
+ emote_message_3p = "rattles!"
+ emote_sound = 'sound/voice/rattle.ogg'
+/decl/emote/audible/squeak
+ key = "squeak"
+ emote_message_3p = "lets out a squeak."
+ emote_sound = 'sound/effects/mouse_squeak.ogg'
+/decl/emote/audible/geck
+ key = "geck"
+ emote_message_3p = "geckers!"
+ emote_sound = 'sound/voice/geck.ogg'
+/decl/emote/audible/baa
+ key = "baa"
+ emote_message_3p = "lets out a baa."
+ emote_sound = 'sound/voice/baa.ogg'
+/decl/emote/audible/baa2
+ key = "baa2"
+ emote_message_3p = "bleats."
+ emote_sound = 'sound/voice/baa2.ogg'
+/*
+/decl/emote/audible/deathgasp2
+ key = "deathgasp2"
+ emote_message_3p = "[species.get_death_message()]"
+ m_type = 1
+ emote_sound = 'sound/voice/deathgasp2.ogg'
+*/
+/decl/emote/audible/mar
+ key = "mar"
+ emote_message_3p = "lets out a mar."
+ emote_sound = 'sound/voice/mar.ogg'
+/decl/emote/audible/wurble
+ key = "wurble"
+ emote_message_3p = "lets out a wurble."
+ emote_sound = 'sound/voice/wurble.ogg'
+/decl/emote/audible/snort
+ key = "snort"
+ emote_message_3p = "snorts!"
+ emote_sound = 'sound/voice/Snort.ogg'
+/decl/emote/audible/meow
+ key = "meow"
+ emote_message_3p = "gently meows!"
+ emote_sound = 'sound/voice/Meow.ogg'
+/decl/emote/audible/moo
+ key = "moo"
+ emote_message_3p = "takes a breath and lets out a moo."
+ emote_sound = 'sound/voice/Moo.ogg'
+/decl/emote/audible/croak
+ key = "croak"
+ emote_message_3p = "rumbles their throat, puffs their cheeks and croaks."
+ emote_sound = 'sound/voice/Croak.ogg'
+/decl/emote/audible/gao
+ key = "gao"
+ emote_message_3p = "lets out a gao."
+ emote_sound = 'sound/voice/gao.ogg'
+/decl/emote/audible/cackle
+ key = "cackle"
+ emote_message_3p = "cackles hysterically!"
+ emote_sound = 'sound/voice/YeenCackle.ogg'
diff --git a/code/modules/emotes/definitions/audible_scream.dm b/code/modules/emotes/definitions/audible_scream.dm
new file mode 100644
index 00000000000..00ed9c29fc3
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_scream.dm
@@ -0,0 +1,16 @@
+/decl/emote/audible/scream
+ key = "scream"
+ emote_message_1p = "You scream!"
+ emote_message_3p = "screams!"
+
+/decl/emote/audible/scream/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ return "You [H.species.scream_verb_1p]!"
+ . = ..()
+
+/decl/emote/audible/cough/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ return "[H.species.scream_verb_3p]!"
+ . = ..()
diff --git a/code/modules/emotes/definitions/audible_slap.dm b/code/modules/emotes/definitions/audible_slap.dm
new file mode 100644
index 00000000000..d0b5466c30c
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_slap.dm
@@ -0,0 +1,24 @@
+/decl/emote/audible/slap
+ key = "slap"
+ emote_message_1p_target = "You slap TARGET across the face. Ouch!"
+ emote_message_1p = "You slap yourself across the face!"
+ emote_message_3p_target = "slaps TARGET across the face. Ouch!"
+ emote_message_3p = "slaps USER_SELF across the face!"
+ emote_sound = 'sound/effects/snap.ogg'
+ check_restraints = TRUE
+ check_range = 1
+
+/decl/emote/audible/slap/New()
+ ..()
+ emote_message_1p_target = SPAN_DANGER(emote_message_1p_target)
+ emote_message_1p = SPAN_DANGER(emote_message_1p)
+ emote_message_3p_target = SPAN_DANGER(emote_message_3p_target)
+ emote_message_3p = SPAN_DANGER(emote_message_3p)
+
+/decl/emote/audible/slap/do_extra(var/atom/user, var/atom/target)
+ . = ..()
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ var/obj/item/clothing/mask/smokable/mask = H.wear_mask
+ if(istype(mask) && H.unEquip(mask))
+ mask.forceMove(get_turf(H))
diff --git a/code/modules/emotes/definitions/audible_snap.dm b/code/modules/emotes/definitions/audible_snap.dm
new file mode 100644
index 00000000000..d098839f5b8
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_snap.dm
@@ -0,0 +1,22 @@
+/decl/emote/audible/snap
+ key = "snap"
+ emote_message_1p = "You snap your fingers."
+ emote_message_3p = "snaps USER_THEIR fingers."
+ emote_message_1p_target = "You snap your fingers at TARGET."
+ emote_message_3p_target = "snaps USER_THEIR fingers at TARGET."
+ emote_sound = 'sound/effects/fingersnap.ogg'
+
+/decl/emote/audible/snap/proc/can_snap(var/atom/user)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ for(var/limb in list(BP_L_HAND, BP_R_HAND))
+ var/obj/item/organ/external/L = H.get_organ(limb)
+ if(istype(L) && L.is_usable() && !L.splinted)
+ return TRUE
+ return FALSE
+
+/decl/emote/audible/snap/do_emote(var/atom/user, var/extra_params)
+ if(!can_snap(user))
+ to_chat(user, SPAN_WARNING("You need at least one working hand to snap your fingers."))
+ return FALSE
+ . = ..()
diff --git a/code/modules/emotes/definitions/audible_sneeze.dm b/code/modules/emotes/definitions/audible_sneeze.dm
new file mode 100644
index 00000000000..a15cbaf46db
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_sneeze.dm
@@ -0,0 +1,29 @@
+/decl/emote/audible/sneeze
+ key = "sneeze"
+ emote_message_1p = "You sneeze."
+ emote_message_3p = "sneezes."
+ emote_sound_synthetic = list(
+ FEMALE = 'sound/effects/mob_effects/machine_sneeze.ogg',
+ MALE = 'sound/effects/mob_effects/f_machine_sneeze.ogg',
+ NEUTER = 'sound/effects/mob_effects/f_machine_sneeze.ogg',
+ PLURAL = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
+ )
+ emote_message_synthetic_1p = "You emit a robotic sneeze."
+ emote_message_synthetic_1p_target = "You emit a robotic sneeze towards TARGET."
+ emote_message_synthetic_3p = "emits a robotic sneeze."
+ emote_message_synthetic_3p_target = "emits a robotic sneeze towards TARGET."
+
+/decl/emote/audible/sneeze/get_emote_sound(var/atom/user)
+ if(ishuman(user) && !check_synthetic(user))
+ var/mob/living/carbon/human/H = user
+ if(H.get_gender() == FEMALE)
+ return list(
+ "sound" = H.species.female_sneeze_sound,
+ "vol" = emote_volume
+ )
+ else
+ return list(
+ "sound" = H.species.male_sneeze_sound,
+ "vol" = emote_volume
+ )
+ return ..()
diff --git a/code/modules/emotes/definitions/audible_whistle.dm b/code/modules/emotes/definitions/audible_whistle.dm
new file mode 100644
index 00000000000..dabd64af59d
--- /dev/null
+++ b/code/modules/emotes/definitions/audible_whistle.dm
@@ -0,0 +1,36 @@
+/decl/emote/audible/whistle
+ key = "whistle"
+ emote_message_1p = "You whistle a tune."
+ emote_message_3p = "whistles a tune."
+ emote_sound = 'sound/voice/longwhistle.ogg'
+ emote_message_muffled = "makes a light spitting noise, a poor attempt at a whistle."
+ emote_sound_synthetic = 'sound/voice/longwhistle_robot.ogg'
+ emote_message_synthetic_1p = "You whistle a robotic tune."
+ emote_message_synthetic_3p = "whistles a robotic tune."
+
+/decl/emote/audible/whistle/quiet
+ key = "qwhistle"
+ emote_message_1p = "You whistle quietly."
+ emote_message_3p = "whistles quietly."
+ emote_sound = 'sound/voice/shortwhistle.ogg'
+ emote_message_synthetic_1p = "You whistle robotically."
+ emote_message_synthetic_3p = "whistles robotically."
+ emote_sound_synthetic = 'sound/voice/shortwhistle_robot.ogg'
+
+/decl/emote/audible/whistle/wolf
+ key = "wwhistle"
+ emote_message_1p = "You whistle inappropriately."
+ emote_message_3p = "whistles inappropriately."
+ emote_sound = 'sound/voice/wolfwhistle.ogg'
+ emote_message_synthetic_1p = "You beep inappropriately."
+ emote_message_synthetic_3p = "beeps inappropriately."
+ emote_sound_synthetic = 'sound/voice/wolfwhistle_robot.ogg'
+
+/decl/emote/audible/whistle/summon
+ key = "swhistle"
+ emote_message_1p = "You whistle a tune."
+ emote_message_3p = "whistles a tune."
+ emote_sound = 'sound/voice/summon_whistle.ogg'
+ emote_message_synthetic_1p = "You whistle a robotic tune."
+ emote_message_synthetic_3p = "whistles a robotic tune."
+ emote_sound_synthetic = 'sound/voice/summon_whistle_robot.ogg'
diff --git a/code/modules/emotes/definitions/exertion.dm b/code/modules/emotes/definitions/exertion.dm
new file mode 100644
index 00000000000..ac0061cca32
--- /dev/null
+++ b/code/modules/emotes/definitions/exertion.dm
@@ -0,0 +1,40 @@
+/decl/emote/exertion/biological
+ key = "esweat"
+ emote_range = 4
+ emote_message_1p = "You are sweating heavily."
+ emote_message_3p = "is sweating heavily."
+
+/decl/emote/exertion/biological/check_user(mob/living/user)
+ if(istype(user) && !user.isSynthetic())
+ return ..()
+ return FALSE
+
+/decl/emote/exertion/biological/breath
+ key = "ebreath"
+ emote_message_1p = "You feel out of breath."
+ emote_message_3p = "looks out of breath."
+
+/decl/emote/exertion/biological/pant
+ key = "epant"
+ emote_range = 3
+ message_type = AUDIBLE_MESSAGE
+ emote_message_1p = "You pant to catch your breath."
+ emote_message_3p = "pants for air."
+ emote_message_impaired = "You can see USER breathing heavily."
+
+/decl/emote/exertion/synthetic
+ key = "ewhine"
+ emote_range = 3
+ message_type = AUDIBLE_MESSAGE
+ emote_message_1p = "You overstress your actuators."
+ emote_message_3p = "USER's actuators whine with strain."
+
+/decl/emote/exertion/synthetic/check_user(mob/living/user)
+ if(istype(user) && user.isSynthetic())
+ return ..()
+ return FALSE
+
+/decl/emote/exertion/synthetic/creak
+ key = "ecreak"
+ emote_message_1p = "Your chassis stress indicators spike."
+ emote_message_3p = "USER's joints creak with stress."
diff --git a/code/modules/emotes/definitions/helpers_vr.dm b/code/modules/emotes/definitions/helpers_vr.dm
new file mode 100644
index 00000000000..6dc3a79bddc
--- /dev/null
+++ b/code/modules/emotes/definitions/helpers_vr.dm
@@ -0,0 +1,33 @@
+// Not specifically /human type because those won't allow FBPs to use them
+/decl/emote/helper/vwag
+ key = "vwag"
+ emote_message_3p = ""
+
+/decl/emote/helper/vwag/check_user(mob/living/carbon/human/user)
+ if(!istype(user) || (!user.tail_style || !user.tail_style.ani_state))
+ return FALSE
+ return ..()
+
+/decl/emote/helper/vwag/do_emote(var/mob/living/carbon/human/user, var/extra_params)
+ if(user.toggle_tail(message = 1))
+ return ..()
+
+/decl/emote/helper/vwag/get_emote_message_3p(var/mob/living/carbon/human/user, var/atom/target, var/extra_params)
+ return "[user.wagging ? "starts" : "stops"] wagging USER_THEIR tail."
+
+
+/decl/emote/helper/vflap
+ key = "vflap"
+ emote_message_3p = ""
+
+/decl/emote/helper/vflap/check_user(mob/living/carbon/human/user)
+ if(!istype(user) || (!user.wing_style || !user.wing_style.ani_state))
+ return FALSE
+ return ..()
+
+/decl/emote/helper/vflap/do_emote(var/mob/living/carbon/human/user, var/extra_params)
+ if(user.toggle_wing(message = 1))
+ return ..()
+
+/decl/emote/helper/vflap/get_emote_message_3p(var/mob/living/carbon/human/user, var/atom/target, var/extra_params)
+ return "[user.flapping ? "starts" : "stops"] flapping USER_THEIR wings."
diff --git a/code/modules/emotes/definitions/human.dm b/code/modules/emotes/definitions/human.dm
new file mode 100644
index 00000000000..982e472c5f2
--- /dev/null
+++ b/code/modules/emotes/definitions/human.dm
@@ -0,0 +1,62 @@
+/decl/emote/human
+ key = "vomit"
+
+/decl/emote/human/check_user(var/mob/living/carbon/human/user)
+ return (istype(user))//VOREStation Edit - What does a mouth have to do with wagging?? && user.check_has_mouth() && !user.isSynthetic())
+
+/decl/emote/human/do_emote(var/mob/living/carbon/human/user)
+ user.vomit()
+
+/decl/emote/human/deathgasp
+ key = "deathgasp"
+
+/decl/emote/human/deathgasp/do_emote(mob/living/carbon/human/user)
+ if(istype(user) && user.species.get_death_message(user) == DEATHGASP_NO_MESSAGE)
+ to_chat(user, SPAN_WARNING("Your species has no deathgasp."))
+ return
+ . = ..()
+
+/decl/emote/human/deathgasp/get_emote_message_3p(var/mob/living/carbon/human/user)
+ return "USER [user.species.get_death_message(user)]"
+
+/decl/emote/human/swish
+ key = "swish"
+
+/decl/emote/human/swish/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_once()
+
+/decl/emote/human/wag
+ key = "wag"
+
+/decl/emote/human/wag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_start()
+
+/decl/emote/human/sway
+ key = "sway"
+
+/decl/emote/human/sway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_start()
+
+/decl/emote/human/qwag
+ key = "qwag"
+
+/decl/emote/human/qwag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_fast()
+
+/decl/emote/human/fastsway
+ key = "fastsway"
+
+/decl/emote/human/fastsway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_fast()
+
+/decl/emote/human/swag
+ key = "swag"
+
+/decl/emote/human/swag/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_stop()
+
+/decl/emote/human/stopsway
+ key = "stopsway"
+
+/decl/emote/human/stopsway/do_emote(var/mob/living/carbon/human/user)
+ user.animate_tail_stop()
diff --git a/code/modules/emotes/definitions/slimes.dm b/code/modules/emotes/definitions/slimes.dm
new file mode 100644
index 00000000000..877422825ba
--- /dev/null
+++ b/code/modules/emotes/definitions/slimes.dm
@@ -0,0 +1,32 @@
+/decl/emote/slime
+ key = "nomood"
+ var/mood
+
+/decl/emote/slime/do_extra(var/mob/living/simple_mob/slime/user)
+ . = ..()
+ if(istype(user))
+ user.mood = mood
+ user.update_icon()
+
+/decl/emote/slime/check_user(var/atom/user)
+ return isslime(user)
+
+/decl/emote/slime/pout
+ key = "pout"
+ mood = "pout"
+
+/decl/emote/slime/sad
+ key = "sad"
+ mood = "sad"
+
+/decl/emote/slime/angry
+ key = "angry"
+ mood = "angry"
+
+/decl/emote/slime/frown
+ key = "frown"
+ mood = "mischevous"
+
+/decl/emote/slime/smile
+ key = "smile"
+ mood = ":3"
diff --git a/code/modules/emotes/definitions/synthetics.dm b/code/modules/emotes/definitions/synthetics.dm
new file mode 100644
index 00000000000..2e31a07f8fd
--- /dev/null
+++ b/code/modules/emotes/definitions/synthetics.dm
@@ -0,0 +1,51 @@
+/decl/emote/audible/synth
+ key = "beep"
+ emote_message_3p = "beeps."
+ emote_sound = 'sound/machines/twobeep.ogg'
+
+/decl/emote/audible/synth/check_user(var/mob/living/user)
+ if(istype(user) && user.isSynthetic())
+ return ..()
+ return FALSE
+
+/decl/emote/audible/synth/ping
+ key = "ping"
+ emote_message_3p = "pings."
+ emote_sound = 'sound/machines/ping.ogg'
+
+/decl/emote/audible/synth/buzz
+ key = "buzz"
+ emote_message_3p = "buzzes."
+ emote_sound = 'sound/machines/buzz-sigh.ogg'
+
+/decl/emote/audible/synth/confirm
+ key = "confirm"
+ emote_message_3p = "emits an affirmative blip."
+ emote_sound = 'sound/machines/synth_yes.ogg'
+
+/decl/emote/audible/synth/deny
+ key = "deny"
+ emote_message_3p = "emits a negative blip."
+ emote_sound = 'sound/machines/synth_no.ogg'
+
+/decl/emote/audible/synth/security
+ key = "law"
+ emote_message_3p = "shows USER_THEIR legal authorization barcode."
+ emote_message_3p_target = "shows TARGET USER_THEIR legal authorization barcode."
+ emote_sound = 'sound/voice/biamthelaw.ogg'
+
+/decl/emote/audible/synth/security/check_user(var/mob/living/silicon/robot/user)
+ return (istype(user) && (istype(user.module, /obj/item/weapon/robot_module/robot/security) || istype(user.module, /obj/item/weapon/robot_module/robot/knine))) //VOREStation Add - knine module
+
+/decl/emote/audible/synth/security/halt
+ key = "halt"
+ emote_message_3p = "USER's speakers skreech, \"Halt! Security!\"."
+ emote_sound = 'sound/voice/halt.ogg'
+
+/decl/emote/audible/synth/dwoop
+ key = "dwoop"
+ emote_message_1p_target = "You chirp happily at TARGET!"
+ emote_message_1p = "You chirp happily."
+ emote_message_3p_target = "chirps happily at TARGET!"
+ emote_message_3p = "chirps happily."
+ emote_sound = 'sound/machines/dwoop.ogg'
diff --git a/code/modules/emotes/definitions/visible.dm b/code/modules/emotes/definitions/visible.dm
new file mode 100644
index 00000000000..986839fff1a
--- /dev/null
+++ b/code/modules/emotes/definitions/visible.dm
@@ -0,0 +1,336 @@
+/decl/emote/visible
+ key ="tail"
+ emote_message_3p = "waves USER_THEIR tail."
+ message_type = VISIBLE_MESSAGE
+
+/decl/emote/visible/scratch
+ key = "scratch"
+ check_restraints = TRUE
+ emote_message_3p = "scratches."
+
+/decl/emote/visible/drool
+ key ="drool"
+ emote_message_3p = "drools."
+ conscious = FALSE
+
+/decl/emote/visible/nod
+ key ="nod"
+ emote_message_3p_target = "nods USER_THEIR head at TARGET."
+ emote_message_3p = "nods USER_THEIR head."
+
+/decl/emote/visible/sway
+ key ="sway"
+ emote_message_3p = "sways around dizzily."
+
+/decl/emote/visible/sulk
+ key ="sulk"
+ emote_message_3p = "sulks down sadly."
+
+/decl/emote/visible/dance
+ key ="dance"
+ check_restraints = TRUE
+ emote_message_3p = "dances around happily."
+
+/decl/emote/visible/roll
+ key ="roll"
+ check_restraints = TRUE
+ emote_message_3p = "rolls."
+
+/decl/emote/visible/shake
+ key ="shake"
+ emote_message_3p = "shakes USER_THEIR head."
+
+/decl/emote/visible/jump
+ key ="jump"
+ emote_message_3p = "jumps!"
+
+/decl/emote/visible/shiver
+ key ="shiver"
+ emote_message_3p = "shivers."
+ conscious = FALSE
+
+/decl/emote/visible/collapse
+ key ="collapse"
+ emote_message_3p = "collapses!"
+
+/decl/emote/visible/collapse/do_extra(var/mob/user)
+ ..()
+ if(istype(user))
+ user.Paralyse(2)
+
+/decl/emote/visible/flash
+ key = "flash"
+ emote_message_3p = "flash USER_THEIR lights quickly."
+
+/decl/emote/visible/blink
+ key = "blink"
+ emote_message_3p = "blinks."
+
+/decl/emote/visible/airguitar
+ key = "airguitar"
+ check_restraints = TRUE
+ emote_message_3p = "is strumming the air and headbanging like a safari chimp."
+
+/decl/emote/visible/blink_r
+ key = "blink_r"
+ emote_message_3p = "blinks rapidly."
+
+/decl/emote/visible/bow
+ key = "bow"
+ emote_message_3p_target = "bows to TARGET."
+ emote_message_3p = "bows."
+
+/decl/emote/visible/salute
+ key = "salute"
+ emote_message_3p_target = "salutes TARGET."
+ emote_message_3p = "salutes."
+ check_restraints = TRUE
+
+/decl/emote/visible/flap
+ key = "flap"
+ check_restraints = TRUE
+ emote_message_3p = "flaps USER_THEIR wings."
+
+/decl/emote/visible/aflap
+ key = "aflap"
+ check_restraints = TRUE
+ emote_message_3p = "flaps USER_THEIR wings ANGRILY!"
+
+/decl/emote/visible/eyebrow
+ key = "eyebrow"
+ emote_message_3p = "raises an eyebrow."
+
+/decl/emote/visible/twitch
+ key = "twitch"
+ emote_message_3p = "twitches."
+ conscious = FALSE
+
+/decl/emote/visible/twitch_v
+ key = "twitch_v"
+ emote_message_3p = "twitches violently."
+ conscious = FALSE
+
+/decl/emote/visible/faint
+ key = "faint"
+ emote_message_3p = "faints."
+
+/decl/emote/visible/faint/do_extra(var/mob/user)
+ . = ..()
+ if(istype(user) && !user.sleeping)
+ user.Sleeping(10)
+
+/decl/emote/visible/frown
+ key = "frown"
+ emote_message_3p = "frowns."
+
+/decl/emote/visible/blush
+ key = "blush"
+ emote_message_3p = "blushes."
+
+/decl/emote/visible/wave
+ key = "wave"
+ emote_message_3p_target = "waves at TARGET."
+ emote_message_3p = "waves."
+ check_restraints = TRUE
+
+/decl/emote/visible/glare
+ key = "glare"
+ emote_message_3p_target = "glares at TARGET."
+ emote_message_3p = "glares."
+
+/decl/emote/visible/stare
+ key = "stare"
+ emote_message_3p_target = "stares at TARGET."
+ emote_message_3p = "stares."
+
+/decl/emote/visible/look
+ key = "look"
+ emote_message_3p_target = "looks at TARGET."
+ emote_message_3p = "looks."
+
+/decl/emote/visible/point
+ key = "point"
+ check_restraints = TRUE
+ emote_message_3p_target = "points to TARGET."
+ emote_message_3p = "points."
+
+/decl/emote/visible/raise
+ key = "raise"
+ check_restraints = TRUE
+ emote_message_3p = "raises a hand."
+
+/decl/emote/visible/grin
+ key = "grin"
+ emote_message_3p_target = "grins at TARGET."
+ emote_message_3p = "grins."
+
+/decl/emote/visible/shrug
+ key = "shrug"
+ emote_message_3p = "shrugs."
+
+/decl/emote/visible/smile
+ key = "smile"
+ emote_message_3p_target = "smiles at TARGET."
+ emote_message_3p = "smiles."
+
+/decl/emote/visible/pale
+ key = "pale"
+ emote_message_3p = "goes pale for a second."
+
+/decl/emote/visible/tremble
+ key = "tremble"
+ emote_message_3p = "trembles in fear!"
+
+/decl/emote/visible/wink
+ key = "wink"
+ emote_message_3p_target = "winks at TARGET."
+ emote_message_3p = "winks."
+
+/decl/emote/visible/hug
+ key = "hug"
+ check_restraints = TRUE
+ emote_message_3p_target = "hugs TARGET."
+ emote_message_3p = "hugs USER_SELF."
+ check_range = 1
+
+/decl/emote/visible/dap
+ key = "dap"
+ check_restraints = TRUE
+ emote_message_3p_target = "gives daps to TARGET."
+ emote_message_3p = "sadly can't find anybody to give daps to, and daps USER_SELF."
+
+/decl/emote/visible/bounce
+ key = "bounce"
+ emote_message_3p = "bounces in place."
+
+/decl/emote/visible/jiggle
+ key = "jiggle"
+ emote_message_3p = "jiggles!"
+
+/decl/emote/visible/lightup
+ key = "light"
+ emote_message_3p = "lights up for a bit, then stops."
+
+/decl/emote/visible/vibrate
+ key = "vibrate"
+ emote_message_3p = "vibrates!"
+
+/decl/emote/visible/deathgasp_robot
+ key = "deathgasp"
+ emote_message_3p = "shudders violently for a moment, then becomes motionless, USER_THEIR eyes slowly darkening."
+
+/decl/emote/visible/handshake
+ key = "handshake"
+ check_restraints = TRUE
+ emote_message_3p_target = "shakes hands with TARGET."
+ emote_message_3p = "shakes hands with USER_SELF."
+ check_range = 1
+
+/decl/emote/visible/handshake/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
+ if(target && !user.Adjacent(target))
+ return "holds out USER_THEIR hand out to TARGET."
+ return ..()
+
+/decl/emote/visible/signal
+ key = "signal"
+ emote_message_3p_target = "signals at TARGET."
+ emote_message_3p = "signals."
+ check_restraints = TRUE
+
+/decl/emote/visible/signal/check_user(atom/user)
+ return ismob(user)
+
+/decl/emote/visible/signal/get_emote_message_3p(var/mob/living/user, var/atom/target, var/extra_params)
+ if(istype(user) && (!user.get_active_hand() || !user.get_inactive_hand()))
+ var/t1 = round(text2num(extra_params))
+ if(isnum(t1) && t1 <= 5)
+ return "raises [t1] finger\s."
+ return .. ()
+
+/decl/emote/visible/afold
+ key = "afold"
+ check_restraints = TRUE
+ emote_message_3p = "folds USER_THEIR arms."
+
+/decl/emote/visible/alook
+ key = "alook"
+ emote_message_3p = "looks away."
+
+/decl/emote/visible/hbow
+ key = "hbow"
+ emote_message_3p = "bows USER_THEIR head."
+
+/decl/emote/visible/hip
+ key = "hip"
+ check_restraints = TRUE
+ emote_message_3p = "puts USER_THEIR hands on USER_THEIR hips."
+
+/decl/emote/visible/holdup
+ key = "holdup"
+ check_restraints = TRUE
+ emote_message_3p = "holds up USER_THEIR palms."
+
+/decl/emote/visible/hshrug
+ key = "hshrug"
+ emote_message_3p = "gives a half shrug."
+
+/decl/emote/visible/crub
+ key = "crub"
+ check_restraints = TRUE
+ emote_message_3p = "rubs USER_THEIR chin."
+
+/decl/emote/visible/eroll
+ key = "eroll"
+ emote_message_3p = "rolls USER_THEIR eyes."
+ emote_message_3p_target = "rolls USER_THEIR eyes at TARGET."
+
+/decl/emote/visible/erub
+ key = "erub"
+ check_restraints = TRUE
+ emote_message_3p = "rubs USER_THEIR eyes."
+
+/decl/emote/visible/fslap
+ key = "fslap"
+ check_restraints = TRUE
+ emote_message_3p = "slaps USER_THEIR forehead."
+
+/decl/emote/visible/ftap
+ key = "ftap"
+ emote_message_3p = "taps USER_THEIR foot."
+
+/decl/emote/visible/hrub
+ key = "hrub"
+ check_restraints = TRUE
+ emote_message_3p = "rubs USER_THEIR hands together."
+
+/decl/emote/visible/hspread
+ key = "hspread"
+ check_restraints = TRUE
+ emote_message_3p = "spreads USER_THEIR hands."
+
+/decl/emote/visible/pocket
+ key = "pocket"
+ check_restraints = TRUE
+ emote_message_3p = "shoves USER_THEIR hands in USER_THEIR pockets."
+
+/decl/emote/visible/rsalute
+ key = "rsalute"
+ check_restraints = TRUE
+ emote_message_3p = "returns the salute."
+
+/decl/emote/visible/rshoulder
+ key = "rshoulder"
+ emote_message_3p = "rolls USER_THEIR shoulders."
+
+/decl/emote/visible/squint
+ key = "squint"
+ emote_message_3p = "squints."
+ emote_message_3p_target = "squints at TARGET."
+
+/decl/emote/visible/tfist
+ key = "tfist"
+ emote_message_3p = "tightens USER_THEIR hands into fists."
+
+/decl/emote/visible/tilt
+ key = "tilt"
+ emote_message_3p = "tilts USER_THEIR head."
diff --git a/code/modules/emotes/definitions/visible_animated.dm b/code/modules/emotes/definitions/visible_animated.dm
new file mode 100644
index 00000000000..2e035d289c7
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_animated.dm
@@ -0,0 +1,76 @@
+/decl/emote/visible/spin
+ key = "spin"
+ check_restraints = TRUE
+ emote_message_3p = "spins!"
+
+/decl/emote/visible/spin/do_extra(mob/user)
+ if(istype(user))
+ user.spin(20, 1)
+
+/decl/emote/visible/sidestep
+ key = "sidestep"
+ check_restraints = TRUE
+ emote_message_3p = "steps rhythmically and moves side to side."
+
+/decl/emote/visible/sidestep/do_extra(mob/user)
+ if(istype(user))
+ animate(user, pixel_x = 5, time = 5)
+ sleep(3)
+ animate(user, pixel_x = -5, time = 5)
+ animate(pixel_x = user.default_pixel_x, pixel_y = user.default_pixel_x, time = 2)
+
+/decl/emote/visible/flip
+ key = "flip"
+ emote_message_1p = "You do a flip!"
+ emote_message_3p = "does a flip!"
+ emote_sound = 'sound/effects/bodyfall4.ogg'
+
+/decl/emote/visible/flip/do_extra(mob/user)
+ . = ..()
+ if(istype(user))
+ user.SpinAnimation(7,1)
+
+/decl/emote/visible/floorspin
+ key = "floorspin"
+ emote_message_1p = "You spin around on the floor!"
+ emote_message_3p = "spins around on the floor!"
+ var/static/list/spin_dirs = list(
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH,
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH,
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST,
+ EAST,
+ SOUTH
+ )
+
+/decl/emote/visible/floorspin/proc/spin_dir(var/mob/user)
+ set waitfor = FALSE
+ for(var/i in spin_dirs)
+ user.set_dir(i)
+ sleep(1)
+ if(QDELETED(user))
+ return
+
+/decl/emote/visible/floorspin/proc/spin_anim(var/mob/user)
+ set waitfor = FALSE
+ sleep(1)
+ if(!QDELETED(user))
+ user.SpinAnimation(10,1)
+
+/decl/emote/visible/floorspin/do_extra(mob/user)
+ . = ..()
+ if(istype(user))
+ spin_dir(user)
+ spin_anim(user)
diff --git a/code/modules/emotes/definitions/visible_vomit.dm b/code/modules/emotes/definitions/visible_vomit.dm
new file mode 100644
index 00000000000..1ec79dea6a9
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_vomit.dm
@@ -0,0 +1,10 @@
+/decl/emote/visible/vomit
+ key = "vomit"
+
+/decl/emote/visible/vomit/do_emote(var/atom/user, var/extra_params)
+ if(isliving(user))
+ var/mob/living/M = user
+ if(!M.isSynthetic())
+ M.vomit()
+ return
+ to_chat(src, SPAN_WARNING("You are unable to vomit."))
diff --git a/code/modules/emotes/definitions/visible_vr.dm b/code/modules/emotes/definitions/visible_vr.dm
new file mode 100644
index 00000000000..69252cf43be
--- /dev/null
+++ b/code/modules/emotes/definitions/visible_vr.dm
@@ -0,0 +1,7 @@
+/decl/emote/visible/mlem
+ key = "mlem"
+ emote_message_3p = "mlems USER_THEIR tongue up over USER_THEIR nose. Mlem."
+
+/decl/emote/visible/blep
+ key = "blep"
+ emote_message_3p = "bleps USER_THEIR tongue out. Blep."
diff --git a/code/modules/emotes/emote_define.dm b/code/modules/emotes/emote_define.dm
new file mode 100644
index 00000000000..845a5202d31
--- /dev/null
+++ b/code/modules/emotes/emote_define.dm
@@ -0,0 +1,181 @@
+// Note about emote messages:
+// - USER / TARGET will be replaced with the relevant name, in bold.
+// - USER_THEM / TARGET_THEM / USER_THEIR / TARGET_THEIR will be replaced with a
+// gender-appropriate version of the same.
+// - Impaired messages do not do any substitutions.
+
+/decl/emote
+ var/key // Command to use emote ie. '*[key]'
+ var/emote_message_1p // First person message ('You do a flip!')
+ var/emote_message_3p // Third person message ('Urist McBackflip does a flip!')
+ var/emote_message_synthetic_1p // First person message for robits.
+ var/emote_message_synthetic_3p // Third person message for robits.
+
+ var/emote_message_impaired // Deaf/blind message ('You hear someone flipping out.', 'You see someone opening and closing their mouth')
+
+ var/emote_message_1p_target // 'You do a flip at Urist McTarget!'
+ var/emote_message_3p_target // 'Urist McShitter does a flip at Urist McTarget!'
+ var/emote_message_synthetic_1p_target // First person targeted message for robits.
+ var/emote_message_synthetic_3p_target // Third person targeted message for robits.
+
+ var/emote_message_radio // A message to send over the radio if one picks up this emote.
+ var/emote_message_radio_synthetic // As above, but for synthetics.
+ var/emote_message_muffled // A message to show if the emote is audible and the user is muzzled.
+
+ var/list/emote_sound // A sound for the emote to play.
+ // Can either be a single sound, a list of sounds to pick from, or an
+ // associative array of gender to single sounds/a list of sounds.
+ var/list/emote_sound_synthetic // As above, but used when check_synthetic() is true.
+ var/emote_volume = 50 // Volume of sound to play.
+ var/emote_volume_synthetic = 50 // As above, but used when check_synthetic() is true.
+
+ var/message_type = VISIBLE_MESSAGE // Audible/visual flag
+ var/check_restraints // Can this emote be used while restrained?
+ var/check_range // falsy, or a range outside which the emote will not work
+ var/conscious = TRUE // Do we need to be awake to emote this?
+ var/emote_range = 0 // If >0, restricts emote visibility to viewers within range.
+
+/decl/emote/proc/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params)
+ if(target)
+ if(emote_message_synthetic_1p_target && check_synthetic(user))
+ return emote_message_synthetic_1p_target
+ return emote_message_1p_target
+ if(emote_message_synthetic_1p && check_synthetic(user))
+ return emote_message_synthetic_1p
+ return emote_message_1p
+
+/decl/emote/proc/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
+ if(target)
+ if(emote_message_synthetic_3p_target && check_synthetic(user))
+ return emote_message_synthetic_3p_target
+ return emote_message_3p_target
+ if(emote_message_synthetic_3p && check_synthetic(user))
+ return emote_message_synthetic_3p
+ return emote_message_3p
+
+/decl/emote/proc/get_emote_sound(var/atom/user)
+ if(check_synthetic(user) && emote_sound_synthetic)
+ return list(
+ "sound" = emote_sound_synthetic,
+ "vol" = emote_volume_synthetic
+ )
+ if(emote_sound)
+ return list(
+ "sound" = emote_sound,
+ "vol" = emote_volume
+ )
+
+/decl/emote/proc/do_emote(var/atom/user, var/extra_params)
+ if(ismob(user) && check_restraints)
+ var/mob/M = user
+ if(M.restrained())
+ to_chat(user, SPAN_WARNING("You are restrained and cannot do that."))
+ return
+
+ var/atom/target
+ if(can_target() && extra_params)
+ extra_params = lowertext(extra_params)
+ for(var/atom/thing in view(user))
+ if(extra_params == lowertext(thing.name))
+ target = thing
+ break
+
+ if(target && target != user && check_range)
+ if (get_dist(user, target) > check_range)
+ to_chat(user, SPAN_WARNING("\The [target] is too far away."))
+ return
+
+ var/use_1p = get_emote_message_1p(user, target, extra_params)
+ if(use_1p)
+ if(target)
+ use_1p = replace_target_tokens(use_1p, target)
+ use_1p = "[capitalize(replace_user_tokens(use_1p, user))]"
+ var/use_3p = get_emote_message_3p(user, target, extra_params)
+ if(use_3p)
+ if(target)
+ use_3p = replace_target_tokens(use_3p, target)
+ use_3p = "\The [user] [replace_user_tokens(use_3p, user)]"
+ var/use_radio = get_radio_message(user)
+ if(use_radio)
+ if(target)
+ use_radio = replace_target_tokens(use_radio, target)
+ use_radio = replace_user_tokens(use_radio, user)
+
+ var/use_range = emote_range
+ if (!use_range)
+ use_range = world.view
+
+ if(ismob(user))
+ var/mob/M = user
+ if(message_type == AUDIBLE_MESSAGE)
+ if(isliving(user))
+ var/mob/living/L = user
+ if(L.silent)
+ M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired)
+ return
+ else
+ M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, hearing_distance = use_range, radio_message = use_radio)
+ else
+ M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, range = use_range)
+
+ do_extra(user, target)
+ do_sound(user)
+
+/decl/emote/proc/replace_target_tokens(var/msg, var/atom/target)
+ . = msg
+ if(istype(target))
+ var/datum/gender/target_gender = gender_datums[target.get_visible_gender()]
+ . = replacetext(., "TARGET_THEM", target_gender.him)
+ . = replacetext(., "TARGET_THEIR", target_gender.his)
+ . = replacetext(., "TARGET_SELF", target_gender.himself)
+ . = replacetext(., "TARGET", "\the [target]")
+
+/decl/emote/proc/replace_user_tokens(var/msg, var/atom/user)
+ . = msg
+ if(istype(user))
+ var/datum/gender/user_gender = gender_datums[user.get_visible_gender()]
+ . = replacetext(., "USER_THEM", user_gender.him)
+ . = replacetext(., "USER_THEIR", user_gender.his)
+ . = replacetext(., "USER_SELF", user_gender.himself)
+ . = replacetext(., "USER", "\the [user]")
+
+/decl/emote/proc/get_radio_message(var/atom/user)
+ if(emote_message_radio_synthetic && check_synthetic(user))
+ return emote_message_radio_synthetic
+ return emote_message_radio
+
+/decl/emote/proc/do_extra(var/atom/user, var/atom/target)
+ return
+
+/decl/emote/proc/do_sound(var/atom/user)
+ var/list/use_sound = get_emote_sound(user)
+ if(!islist(use_sound) || length(use_sound) < 2)
+ return
+ var/sound_to_play = use_sound["sound"]
+ if(!sound_to_play)
+ return
+ if(islist(sound_to_play))
+ if(sound_to_play[user.gender])
+ sound_to_play = sound_to_play[user.gender]
+ if(islist(sound_to_play) && length(sound_to_play))
+ sound_to_play = pick(sound_to_play)
+ if(sound_to_play)
+ playsound(user.loc, sound_to_play, use_sound["vol"], 0, preference = /datum/client_preference/emote_noises) //VOREStation Add - Preference
+
+/decl/emote/proc/check_user(var/atom/user)
+ return TRUE
+
+/decl/emote/proc/can_target()
+ return (emote_message_1p_target || emote_message_3p_target)
+
+/decl/emote/dd_SortValue()
+ return key
+
+/decl/emote/proc/check_synthetic(var/mob/living/user)
+ . = istype(user) && user.isSynthetic()
+ if(!. && ishuman(user) && message_type == AUDIBLE_MESSAGE)
+ var/mob/living/carbon/human/H = user
+ if(H.should_have_organ(O_LUNGS))
+ var/obj/item/organ/internal/lungs/L = H.internal_organs_by_name[O_LUNGS]
+ if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
+ . = TRUE
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
new file mode 100644
index 00000000000..3e45f05091e
--- /dev/null
+++ b/code/modules/emotes/emote_mob.dm
@@ -0,0 +1,183 @@
+/mob/proc/can_emote(var/emote_type)
+ return (stat == CONSCIOUS)
+
+/mob/living/can_emote(var/emote_type)
+ return (..() && !(silent && emote_type == AUDIBLE_MESSAGE))
+
+/mob/proc/emote(var/act, var/m_type, var/message)
+ set waitfor = FALSE
+ // s-s-snowflake
+ if(src.stat == DEAD && act != "deathgasp")
+ return
+
+ if(usr == src) //client-called emote
+ if (client && (client.prefs.muted & MUTE_IC))
+ to_chat(src, "You cannot send IC messages (muted).")
+ return
+
+ if(act == "help")
+ to_chat(src,"Usable emotes: [english_list(usable_emotes)].")
+ return
+
+ if(!can_emote(m_type))
+ to_chat(src, SPAN_WARNING("You cannot currently [m_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!"))
+ return
+
+ if(act == "me")
+ return custom_emote(m_type, message)
+
+ if(act == "custom")
+ if(!message)
+ message = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src) //VOREStation Edit - Reflect too long messages, within reason
+ if(!message)
+ return
+ if (!m_type)
+ if(alert(src, "Is this an audible emote?", "Emote", "Yes", "No") == "No")
+ m_type = VISIBLE_MESSAGE
+ else
+ m_type = AUDIBLE_MESSAGE
+ return custom_emote(m_type, message)
+
+ var/splitpoint = findtext(act, " ")
+ if(splitpoint > 0)
+ var/tempstr = act
+ act = copytext(tempstr,1,splitpoint)
+ message = copytext(tempstr,splitpoint+1,0)
+
+ //VOREStation Add - NIF soulcatcher shortcuts
+ if(act == "nsay")
+ return nsay(message)
+
+ if(act == "nme")
+ return nme(message)
+ //VOREStation Add End
+
+ var/decl/emote/use_emote = usable_emotes[act]
+ if(!use_emote)
+ to_chat(src, SPAN_WARNING("Unknown emote '[act]'. Type say *help for a list of usable emotes."))
+ return
+
+ if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS)
+ return
+
+ if(use_emote.message_type == AUDIBLE_MESSAGE && is_muzzled())
+ audible_message("\The [src] [use_emote.emote_message_muffled || "makes a muffled sound."]")
+ return
+ else
+ use_emote.do_emote(src, message)
+
+ for (var/obj/item/weapon/implant/I in src)
+ if (I.implanted)
+ I.trigger(act, src)
+
+/mob/proc/format_emote(var/emoter = null, var/message = null)
+ var/pretext
+ var/subtext
+ var/nametext
+ var/end_char
+ var/start_char
+ var/name_anchor
+
+ if(!message || !emoter)
+ return
+
+ message = html_decode(message)
+
+ name_anchor = findtext(message, "*")
+ if(name_anchor > 0) // User supplied emote with visible_emote token (default ^)
+ pretext = copytext(message, 1, name_anchor)
+ subtext = copytext(message, name_anchor + 1, length(message) + 1)
+ else
+ // No token. Just the emote as usual.
+ subtext = message
+
+ // Oh shit, we got this far! Let's see... did the user attempt to use more than one token?
+ if(findtext(subtext, "*"))
+ // abort abort!
+ to_chat(emoter, SPAN_WARNING("You may use only one \"["*"]\" symbol in your emote."))
+ return
+
+ if(pretext)
+ // Add a space at the end if we didn't already supply one.
+ end_char = copytext(pretext, length(pretext), length(pretext) + 1)
+ if(end_char != " ")
+ pretext += " "
+
+ // Grab the last character of the emote message.
+ end_char = copytext(subtext, length(subtext), length(subtext) + 1)
+ if(!(end_char in list(".", "?", "!", "\"", "-", "~"))) // gotta include ~ for all you fucking weebs
+ // No punctuation supplied. Tack a period on the end.
+ subtext += "."
+
+ // Add a space to the subtext, unless it begins with an apostrophe or comma.
+ if(subtext != ".")
+ // First, let's get rid of any existing space, to account for sloppy emoters ("X, ^ , Y")
+ subtext = trim_left(subtext)
+ start_char = copytext(subtext, 1, 2)
+ if(start_char != "," && start_char != "'")
+ subtext = " " + subtext
+
+ pretext = capitalize(html_encode(pretext))
+ nametext = html_encode(nametext)
+ subtext = html_encode(subtext)
+ // Store the player's name in a nice bold, naturalement
+ nametext = "[emoter]"
+ return pretext + nametext + subtext
+
+/mob/proc/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message, var/range = world.view)
+
+ if((usr && stat) || (!use_me && usr == src))
+ to_chat(src, "You are unable to emote.")
+ return
+
+ var/input
+ if(!message)
+ input = sanitize(input(src,"Choose an emote to display.") as text|null)
+ else
+ input = message
+
+ if(input)
+ message = format_emote(src, message)
+ else
+ return
+
+ if(input)
+ log_emote(message,src) //Log before we add junk
+ message = "[src] [input]"
+ else
+ return
+
+ if(message)
+ message = encode_html_emphasis(message)
+
+ // Hearing gasp and such every five seconds is not good emotes were not global for a reason.
+ // Maybe some people are okay with that.
+ var/turf/T = get_turf(src)
+ if(!T) return
+ var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2,remote_ghosts = client ? TRUE : FALSE)
+ var/list/m_viewers = in_range["mobs"]
+ var/list/o_viewers = in_range["objs"]
+
+ for(var/mob in m_viewers)
+ var/mob/M = mob
+ spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes.
+ if(M)
+ if(isobserver(M))
+ message = "[src] ([ghost_follow_link(src, M)]) [input]"
+ M.show_message(message, m_type)
+
+ for(var/obj in o_viewers)
+ var/obj/O = obj
+ spawn(0)
+ if(O)
+ O.see_emote(src, message, m_type)
+
+
+
+// Specific mob type exceptions below.
+/mob/living/silicon/ai/emote(var/act, var/type, var/message)
+ var/obj/machinery/hologram/holopad/T = src.holo
+ if(T && T.masters[src]) //Is the AI using a holopad?
+ src.holopad_emote(message)
+ else //Emote normally, then.
+ ..()
diff --git a/code/modules/events/meteor_strike_vr.dm b/code/modules/events/meteor_strike_vr.dm
index 8868c577cd6..83b1f8ac2d9 100644
--- a/code/modules/events/meteor_strike_vr.dm
+++ b/code/modules/events/meteor_strike_vr.dm
@@ -61,10 +61,6 @@
var/turf/mob_turf = get_turf(L)
if(!mob_turf || !(mob_turf.z in impacted.expected_z_levels))
continue
- if(!L.buckled && !issilicon(L))
- if(!L.Check_Shoegrip())
- L.throw_at(get_step_rand(L),1,5)
- L.Weaken(5)
if(L.client)
to_chat(L, "The ground lurches beneath you!")
shake_camera(L, 6, 1)
diff --git a/code/modules/events/supply_demand_vr.dm b/code/modules/events/supply_demand_vr.dm
index 6447630c9e5..64d402c443e 100644
--- a/code/modules/events/supply_demand_vr.dm
+++ b/code/modules/events/supply_demand_vr.dm
@@ -274,8 +274,7 @@
/datum/event/supply_demand/proc/choose_chemistry_items(var/differentTypes)
// Checking if they show up in health analyzer is good huristic for it being a drug
var/list/medicineReagents = list()
- for(var/path in typesof(/datum/chemical_reaction) - /datum/chemical_reaction)
- var/datum/chemical_reaction/CR = path // Stupid casting required for reading
+ for(var/decl/chemical_reaction/instant/CR in SSchemistry.chemical_reactions)
var/datum/reagent/R = SSchemistry.chemical_reagents[initial(CR.result)]
if(R && R.scannable)
medicineReagents += R
@@ -288,8 +287,7 @@
/datum/event/supply_demand/proc/choose_bar_items(var/differentTypes)
var/list/drinkReagents = list()
- for(var/path in typesof(/datum/chemical_reaction) - /datum/chemical_reaction)
- var/datum/chemical_reaction/CR = path // Stupid casting required for reading
+ for(var/decl/chemical_reaction/instant/drinks/CR in SSchemistry.chemical_reactions)
var/datum/reagent/R = SSchemistry.chemical_reagents[initial(CR.result)]
if(istype(R, /datum/reagent/drink) || istype(R, /datum/reagent/ethanol))
drinkReagents += R
diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm
index 8acb089a4c6..747fa0f75f6 100644
--- a/code/modules/examine/descriptions/weapons.dm
+++ b/code/modules/examine/descriptions/weapons.dm
@@ -30,7 +30,7 @@
description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \
then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."
-/obj/item/weapon/gun/energy/gun/stunrevolver
+/obj/item/weapon/gun/energy/stunrevolver
description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \
then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."
diff --git a/code/modules/food/food/cans_vr.dm b/code/modules/food/food/cans_vr.dm
new file mode 100644
index 00000000000..4807d021ef5
--- /dev/null
+++ b/code/modules/food/food/cans_vr.dm
@@ -0,0 +1,75 @@
+//////////////////////Bepis Drinks (04/29/2021)//////////////////////
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/bepis
+ name = "\improper Bepis"
+ desc = "It has a smell of 'off-brand' whenever you open it..."
+ description_fluff = "Puts the 'B' in Best Soda! Bepis is the number one competitor to \
+ Space Cola and has vendors scattered across the frontier. While the drink is not as \
+ popular as Space Cola, many people across known space enjoy the sweet beverage."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "bepis"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/bepis/Initialize()
+ . = ..()
+ reagents.add_reagent("bepis", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/astrodew
+ name = "\improper Astro Dew Spring Water"
+ desc = "A can of refreshing 'spring' water! Or so the can claims."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "watercan"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/astrodew/Initialize()
+ . = ..()
+ reagents.add_reagent("water", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee
+ name = "\improper Café Del Consumir"
+ desc = "A can of deliciously sweet iced coffee that originates from Earth."
+ description_fluff = "Café Del Consumir originates from a small coffee brewery in México \
+ that still opperates to this day. Café Del Consumir prides itself on being true to form \
+ and retaining its original recipe. They've been producing and selling thier product across \
+ the galaxy for decades without fail. NanoTrasen has attempted to by out the small company for \
+ years now, howerver all attempts they've made have failed."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "coffeecan"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/icecoffee/Initialize()
+ . = ..()
+ reagents.add_reagent("icecoffee", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/buzz
+ name = "\improper Buzz Fuzz"
+ desc = "Uses real honey, making it a sweet tooth's dream drink."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "buzzfuzz"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/buzz/Initialize()
+ . = ..()
+ reagents.add_reagent("buzz_fuzz", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/shambler
+ name = "\improper Shambler's Juice"
+ desc = "~Shake me up some of that Shambler's Juice!~"
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "shambler"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/shambler/Initialize()
+ . = ..()
+ reagents.add_reagent("shamblers", 30)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/cranberry
+ name = "\improper Sprited Cranberry"
+ desc = "A delicious blend of fresh cranberry juice and various spices, the perfect drink."
+ icon = 'icons/obj/drinks_vr.dmi'
+ icon_state = "cranberry"
+ center_of_mass = list("x"=16, "y"=10)
+
+/obj/item/weapon/reagent_containers/food/drinks/cans/cranberry/Initialize()
+ . = ..()
+ reagents.add_reagent("sprited_cranberry", 30)
\ No newline at end of file
diff --git a/code/modules/food/food/drinks/bottle.dm b/code/modules/food/food/drinks/bottle.dm
index 56d303371a7..1f7beec6b9e 100644
--- a/code/modules/food/food/drinks/bottle.dm
+++ b/code/modules/food/food/drinks/bottle.dm
@@ -341,20 +341,20 @@
. = ..()
reagents.add_reagent("absinthe", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor
- name = "Emeraldine Melon Liquor"
+/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor //MODIFIED ON 04/21/2021
+ name = "Emeraldine Melon Liqueur"
desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light."
- icon_state = "alco-green" //Placeholder.
+ icon_state = "melon_liqueur"
center_of_mass = list("x"=16, "y"=6)
/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor/Initialize()
. = ..()
reagents.add_reagent("melonliquor", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao
+/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao //MODIFIED ON 04/21/2021
name = "Miss Blue Curacao"
desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic."
- icon_state = "alco-blue" //Placeholder.
+ icon_state = "blue_curacao"
center_of_mass = list("x"=16, "y"=6)
/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao/Initialize()
@@ -371,36 +371,6 @@
. = ..()
reagents.add_reagent("grenadine", 100)
-/obj/item/weapon/reagent_containers/food/drinks/bottle/cola
- name = "\improper Space Cola"
- desc = "Cola. in space"
- icon_state = "colabottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/cola/Initialize()
- . = ..()
- reagents.add_reagent("cola", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up
- name = "\improper Space-Up"
- desc = "Tastes like a hull breach in your mouth."
- icon_state = "space-up_bottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up/Initialize()
- . = ..()
- reagents.add_reagent("space_up", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind
- name = "\improper Space Mountain Wind"
- desc = "Blows right through you like a space wind."
- icon_state = "space_mountain_wind_bottle"
- center_of_mass = list("x"=16, "y"=6)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind/Initialize()
- . = ..()
- reagents.add_reagent("spacemountainwind", 100)
-
/obj/item/weapon/reagent_containers/food/drinks/bottle/pwine
name = "Warlock's Velvet"
desc = "What a delightful packaging for a surely high quality wine! The vintage must be amazing!"
@@ -421,7 +391,107 @@
. = ..()
reagents.add_reagent("unathiliquor", 100)
-//////////////////////////JUICES AND STUFF ///////////////////////
+/obj/item/weapon/reagent_containers/food/drinks/bottle/sake
+ name = "Mono-No-Aware Luxury Sake"
+ desc = "Dry alcohol made from rice, a favorite of businessmen."
+ icon_state = "sakebottle"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/sake/Initialize()
+ . = ..()
+ reagents.add_reagent("sake", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne
+ name = "Gilthari Luxury Champagne"
+ desc = "For those special occassions."
+ icon_state = "champagne"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne/Initialize()
+ . = ..()
+ reagents.add_reagent("champagne", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps
+ name = "Dr. Bone's Peppermint Schnapps"
+ desc = "A flavoured grain liqueur with a fresh, minty taste."
+ icon_state = "schnapps_pep"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_pep", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps
+ name = "Dr. Bone's Peach Schnapps"
+ desc = "A flavoured grain liqueur with a fruity peach taste."
+ icon_state = "schnapps_pea"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_pea", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps
+ name = "Dr. Bone's Lemonade Schnapps"
+ desc = "A flavoured grain liqueur with a sweetish, lemon taste."
+ icon_state = "schnapps_lem"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps/Initialize()
+ . = ..()
+ reagents.add_reagent("schnapps_lem", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/jager
+ name = "Schusskonig"
+ desc = "A complex tasting digestif. Thank god the original's trademark lapsed."
+ icon_state = "jager_bottle"
+ center_of_mass = list("x"=16, "y"=3)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/jager/Initialize()
+ . = ..()
+ reagents.add_reagent("jager", 100)
+
+//////////////////////////JUICES AND STUFF///////////////////////
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/cola //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space Cola"
+ desc = "Cola. In space."
+ icon_state = "colabottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/cola/Initialize()
+ . = ..()
+ reagents.add_reagent("cola", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space-Up"
+ desc = "Tastes like a hull breach in your mouth."
+ icon_state = "space-up_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_up/Initialize()
+ . = ..()
+ reagents.add_reagent("space_up", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind //MODIFIED ON 04/21/2021
+ name = "\improper two-liter Space Mountain Wind"
+ desc = "Blows right through you like a space wind."
+ icon_state = "space_mountain_wind_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/space_mountain_wind/Initialize()
+ . = ..()
+ reagents.add_reagent("spacemountainwind", 100)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/dr_gibb //ADDED ON 04/21/2021
+ name = "\improper two-liter Dr. Gibb"
+ desc = "A delicious mixture of 42 different flavors."
+ icon_state = "dr_gibb_bottle"
+ center_of_mass = list("x"=16, "y"=6)
+
+/obj/item/weapon/reagent_containers/food/drinks/bottle/dr_gibb/Initialize()
+ . = ..()
+ reagents.add_reagent("dr_gibb", 100)
/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice
name = "Orange Juice"
@@ -507,7 +577,8 @@
. = ..()
reagents.add_reagent("lemonjuice", 100)
-//Small bottles
+//////////////////////////SMALL BOTTLES///////////////////////
+
/obj/item/weapon/reagent_containers/food/drinks/bottle/small
volume = 50
smash_duration = 1
@@ -578,63 +649,3 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale/hushedwhisper/Initialize()
. = ..()
reagents.add_reagent("ale", 50)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/sake
- name = "Mono-No-Aware Luxury Sake"
- desc = "Dry alcohol made from rice, a favorite of businessmen."
- icon_state = "sakebottle"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/sake/Initialize()
- . = ..()
- reagents.add_reagent("sake", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne
- name = "Gilthari Luxury Champagne"
- desc = "For those special occassions."
- icon_state = "champagne"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne/Initialize()
- . = ..()
- reagents.add_reagent("champagne", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps
- name = "Dr. Bone's Peppermint Schnapps"
- desc = "A flavoured grain liqueur with a fresh, minty taste."
- icon_state = "schnapps_pep"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_pep", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps
- name = "Dr. Bone's Peach Schnapps"
- desc = "A flavoured grain liqueur with a fruity peach taste."
- icon_state = "schnapps_pea"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_pea", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps
- name = "Dr. Bone's Lemonade Schnapps"
- desc = "A flavoured grain liqueur with a sweetish, lemon taste."
- icon_state = "schnapps_lem"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps/Initialize()
- . = ..()
- reagents.add_reagent("schnapps_lem", 100)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/jager
- name = "Schusskonig"
- desc = "A complex tasting digestif. Thank god the original's trademark lapsed."
- icon_state = "jager_bottle"
- center_of_mass = list("x"=16, "y"=3)
-
-/obj/item/weapon/reagent_containers/food/drinks/bottle/jager/Initialize()
- . = ..()
- reagents.add_reagent("jager", 100)
diff --git a/code/modules/food/recipe_dump.dm b/code/modules/food/recipe_dump.dm
index df0e6874aa6..63dc510eb94 100644
--- a/code/modules/food/recipe_dump.dm
+++ b/code/modules/food/recipe_dump.dm
@@ -8,13 +8,11 @@
//////////////////////// DRINK
var/list/drink_recipes = list()
- for(var/path in typesof(/datum/chemical_reaction/drinks) - /datum/chemical_reaction/drinks)
- var/datum/chemical_reaction/drinks/CR = new path()
- drink_recipes[path] = list("Result" = CR.name,
+ for(var/decl/chemical_reaction/instant/drinks/CR in SSchemistry.chemical_reactions)
+ drink_recipes[CR.type] = list("Result" = CR.name,
"ResAmt" = CR.result_amount,
"Reagents" = CR.required_reagents,
"Catalysts" = CR.catalysts)
- qdel(CR)
//////////////////////// FOOD
var/list/food_recipes = typesof(/datum/recipe) - /datum/recipe
@@ -43,16 +41,14 @@
qdel(R)
//////////////////////// FOOD+ (basically condiments, tofu, cheese, soysauce, etc)
- for(var/path in typesof(/datum/chemical_reaction/food) - /datum/chemical_reaction/food)
- var/datum/chemical_reaction/food/CR = new path()
- food_recipes[path] = list("Result" = CR.name,
+ for(var/decl/chemical_reaction/instant/food/CR in SSchemistry.chemical_reactions)
+ food_recipes[CR.type] = list("Result" = CR.name,
"ResAmt" = CR.result_amount,
"Reagents" = CR.required_reagents,
"Catalysts" = CR.catalysts,
"Fruit" = list(),
"Ingredients" = list(),
"Image" = null)
- qdel(CR)
//////////////////////// PROCESSING
//Items needs further processing into human-readability.
diff --git a/code/modules/genetics/side_effects.dm b/code/modules/genetics/side_effects.dm
index fbbce61398e..25d8ba32e6f 100644
--- a/code/modules/genetics/side_effects.dm
+++ b/code/modules/genetics/side_effects.dm
@@ -21,7 +21,7 @@
duration = 10*30
start(mob/living/carbon/human/H)
- H.emote("me", 1, "starts turning very red..")
+ H.custom_emote(VISIBLE_MESSAGE, "starts turning very red..")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("dexalin"))
@@ -37,7 +37,7 @@
duration = 10*60
start(mob/living/carbon/human/H)
- H.emote("me", 1, "'s limbs start shivering uncontrollably.")
+ H.custom_emote(VISIBLE_MESSAGE, "'s limbs start shivering uncontrollably.")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("bicaridine"))
@@ -54,7 +54,7 @@
duration = 10*90
start(mob/living/carbon/human/H)
- H.emote("me", 1, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
+ H.custom_emote(VISIBLE_MESSAGE, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("anti_toxin"))
@@ -69,7 +69,7 @@
start(mob/living/carbon/human/H)
var/datum/gender/T = gender_datums[H.get_visible_gender()]
- H.emote("me", 1, "has drool running down from [T.his] mouth.")
+ H.custom_emote(VISIBLE_MESSAGE, "has drool running down from [T.his] mouth.")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("anti_toxin"))
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index e68425111f5..4454ea3a1a9 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -286,12 +286,17 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
var/DBQuery/query = dbcon_old.NewQuery("SELECT id, author, title, category FROM library ORDER BY [sortby]")
query.Execute()
+ var/show_admin_options = check_rights(R_ADMIN, show_msg = FALSE)
+
while(query.NextRow())
var/id = query.item[1]
var/author = query.item[2]
var/title = query.item[3]
var/category = query.item[4]
- dat += "| [author] | [title] | [category] | \[Order\] |
"
+ dat += "| [author] | [title] | [category] | \[Order\]"
+ if(show_admin_options) // This isn't the only check, since you can just href-spoof press this button. Just to tidy things up.
+ dat += "\[Del\]"
+ dat += " |
"
dat += "
"
dat += "
(Return to main menu)
"
@@ -451,6 +456,18 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
B.item_state = B.icon_state
src.visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
break
+
+ if(href_list["delid"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/sqlid = sanitizeSQL(href_list["delid"])
+ establish_old_db_connection()
+ if(!dbcon_old.IsConnected())
+ alert("Connection to Archive has been severed. Aborting.")
+ else
+ var/DBQuery/query = dbcon_old.NewQuery("DELETE FROM library WHERE id=[sqlid]")
+ query.Execute()
+
if(href_list["orderbyid"])
var/orderid = input("Enter your order:") as num|null
if(orderid)
diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/modules/materials/fifty_spawner.dm
similarity index 100%
rename from code/game/objects/items/stacks/fifty_spawner.dm
rename to code/modules/materials/fifty_spawner.dm
diff --git a/code/modules/materials/fifty_spawner_mats_vr.dm b/code/modules/materials/fifty_spawner_mats_vr.dm
new file mode 100644
index 00000000000..0b6e29ffa0a
--- /dev/null
+++ b/code/modules/materials/fifty_spawner_mats_vr.dm
@@ -0,0 +1,19 @@
+/obj/fiftyspawner/titanium
+ name = "stack of titanium"
+ type_to_spawn = /obj/item/stack/material/titanium
+
+/obj/fiftyspawner/titanium_glass
+ name = "stack of ti-glass"
+ type_to_spawn = /obj/item/stack/material/glass/titanium
+
+/obj/fiftyspawner/plastitanium
+ name = "stack of plastitanium"
+ type_to_spawn = /obj/item/stack/material/plastitanium
+
+/obj/fiftyspawner/plastitanium_hull
+ name = "stack of plastitanium"
+ type_to_spawn = /obj/item/stack/material/plastitanium/hull
+
+/obj/fiftyspawner/plastitanium_glass
+ name = "stack of plastitanium glass"
+ type_to_spawn = /obj/item/stack/material/glass/plastitanium
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
deleted file mode 100644
index c1239b234c9..00000000000
--- a/code/modules/materials/material_recipes.dm
+++ /dev/null
@@ -1,278 +0,0 @@
-/datum/material/proc/get_recipes()
- if(!recipes)
- generate_recipes()
- return recipes
-
-/datum/material/proc/generate_recipes()
- recipes = list()
-
- // If is_brittle() returns true, these are only good for a single strike.
- recipes += new/datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] armor plate insert", /obj/item/weapon/material/armor_plating/insert, 2, time = 40, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
-
- if(integrity>=50)
- recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
-
- if(hardness>50)
- recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
-
-/datum/material/steel/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe_list("office chairs",list( \
- new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") \
- ))
- recipes += new/datum/stack_recipe_list("comfy chairs", list( \
- new/datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("yellow comfy chair", /obj/structure/bed/chair/comfy/yellow, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("orange comfy chair", /obj/structure/bed/chair/comfy/orange, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- ))
- recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]")
- //recipes += new/datum/stack_recipe("fire axe cabinet frame", /obj/item/frame/fireaxe_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1)
- recipes += new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe_list("airlock assemblies", list( \
- new/datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("eng atmos airlock assembly", /obj/structure/door_assembly/door_assembly_eat, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- ))
- //recipes += new/datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")//VOREStation Removal
- recipes += new/datum/stack_recipe("medical stand", /obj/structure/medical_stand, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")//VOREStation Replacement
- recipes += new/datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]")
- recipes += new/datum/stack_recipe_list("modular computer frames", list( \
- new/datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20, recycle_material = "[name]"),\
- new/datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10, recycle_material = "[name]"),\
- new/datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10, recycle_material = "[name]"),\
- new/datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5, recycle_material = "[name]"),\
- ))
- recipes += new/datum/stack_recipe_list("filing cabinets", list( \
- new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("tall filing cabinet", /obj/structure/filingcabinet/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- new/datum/stack_recipe("chest drawer", /obj/structure/filingcabinet/chestdrawer, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \
- ))
- recipes += new/datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
-
-/datum/material/plasteel/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]")
-
-/datum/material/stone/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
-
-/datum/material/stone/marble/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]")
-
-/datum/material/plastic/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 500u
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 250u
- recipes += new/datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 100u
- recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
-
-/datum/material/wood/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") //VOREStation Add
- recipes += new/datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
-
-/datum/material/wood/log/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]")
-
-/datum/material/cardboard/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe_list("folders",list( \
- new/datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue, recycle_material = "[name]"), \
- new/datum/stack_recipe("grey folder", /obj/item/weapon/folder, recycle_material = "[name]"), \
- new/datum/stack_recipe("red folder", /obj/item/weapon/folder/red, recycle_material = "[name]"), \
- new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white, recycle_material = "[name]"), \
- new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow, recycle_material = "[name]"), \
- ))
-
-/datum/material/snow/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]")
-
-/datum/material/snowbrick/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
-
-/datum/material/wood/sif/generate_recipes()
- ..()
- recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE)
- for(var/datum/stack_recipe/r_recipe in recipes)
- if(r_recipe.title == "wood floor tile")
- recipes -= r_recipe
- continue
- if(r_recipe.title == "wooden chair")
- recipes -= r_recipe
- continue
-
-/datum/material/supermatter/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]")
-
-/datum/material/cloth/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
-
-/datum/material/resin/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] nest", /obj/structure/bed/nest, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder/resin, 2, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]")
-
-/datum/material/leather/generate_recipes()
- recipes = list()
- recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
- recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
- recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
- recipes += new/datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm
deleted file mode 100644
index bf5b54d8535..00000000000
--- a/code/modules/materials/material_recipes_vr.dm
+++ /dev/null
@@ -1,90 +0,0 @@
-
-/datum/material/steel/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe_list("mounted chairs", list(
- new/datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10),
- new/datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10)
- ))
- recipes += new/datum/stack_recipe_list("mounted comfy chairs", list(
- new/datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20),
- new/datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20)
- ))
- recipes += new/datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10)
- recipes += new/datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20)
- recipes += new/datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2)
- recipes += new/datum/stack_recipe_list("sofas", list(
- new/datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \
- new/datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \
- ))
-
-/datum/material/durasteel/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2)
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30)
-
-/datum/material/plastitanium/generate_recipes()
- . = ..()
- recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
deleted file mode 100644
index 3fd995378c5..00000000000
--- a/code/modules/materials/material_sheets.dm
+++ /dev/null
@@ -1,565 +0,0 @@
-// Stacked resources. They use a material datum for a lot of inherited values.
-// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well
-/obj/item/stack/material
- force = 5.0
- throwforce = 5
- w_class = ITEMSIZE_NORMAL
- throw_speed = 3
- throw_range = 3
- center_of_mass = null
- max_amount = 50
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi',
- slot_r_hand_str = 'icons/mob/items/righthand_material.dmi',
- )
-
- var/default_type = DEFAULT_WALL_MATERIAL
- var/datum/material/material
- var/perunit = SHEET_MATERIAL_AMOUNT
- var/apply_colour //temp pending icon rewrite
- drop_sound = 'sound/items/drop/axe.ogg'
- pickup_sound = 'sound/items/pickup/axe.ogg'
-
-/obj/item/stack/material/Initialize()
- . = ..()
-
- randpixel_xy()
-
- if(!default_type)
- default_type = DEFAULT_WALL_MATERIAL
- material = get_material_by_name("[default_type]")
- if(!material)
- return INITIALIZE_HINT_QDEL
-
- recipes = material.get_recipes()
- stacktype = material.stack_type
- if(islist(material.stack_origin_tech))
- origin_tech = material.stack_origin_tech.Copy()
-
- if(apply_colour)
- color = material.icon_colour
-
- if(!material.conductive)
- flags |= NOCONDUCT
-
- matter = material.get_matter()
- update_strings()
-
-/obj/item/stack/material/get_material()
- return material
-
-/obj/item/stack/material/proc/update_strings()
- // Update from material datum.
- singular_name = material.sheet_singular_name
-
- if(amount>1)
- name = "[material.use_name] [material.sheet_plural_name]"
- desc = "A stack of [material.use_name] [material.sheet_plural_name]."
- gender = PLURAL
- else
- name = "[material.use_name] [material.sheet_singular_name]"
- desc = "A [material.sheet_singular_name] of [material.use_name]."
- gender = NEUTER
-
-/obj/item/stack/material/use(var/used)
- . = ..()
- update_strings()
- return
-
-/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
- var/obj/item/stack/material/M = S
- if(!istype(M) || material.name != M.material.name)
- return 0
- var/transfer = ..(S,tamount,1)
- if(src) update_strings()
- if(M) M.update_strings()
- return transfer
-
-/obj/item/stack/material/attack_self(var/mob/user)
- if(!material.build_windows(user, src))
- ..()
-
-/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user)
- if(istype(W,/obj/item/stack/cable_coil))
- material.build_wired_product(user, W, src)
- return
- else if(istype(W, /obj/item/stack/rods))
- material.build_rod_product(user, W, src)
- return
- return ..()
-
-//VOREStation Add
-/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob)
- if(M.handle_eat_minerals(src, user))
- return
- ..()
-
-/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent.
- if(user.handle_eat_minerals(src))
- return
- ..()
-//VOREStation Add End
-
-/obj/item/stack/material/iron
- name = "iron"
- icon_state = "sheet-ingot"
- default_type = "iron"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/lead
- name = "lead"
- icon_state = "sheet-ingot"
- default_type = "lead"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/sandstone
- name = "sandstone brick"
- icon_state = "sheet-sandstone"
- default_type = "sandstone"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/boots.ogg'
- pickup_sound = 'sound/items/pickup/boots.ogg'
-
-/obj/item/stack/material/marble
- name = "marble brick"
- icon_state = "sheet-marble"
- default_type = "marble"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/boots.ogg'
- pickup_sound = 'sound/items/pickup/boots.ogg'
-
-/obj/item/stack/material/diamond
- name = "diamond"
- icon_state = "sheet-diamond"
- default_type = "diamond"
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
-
-/obj/item/stack/material/uranium
- name = "uranium"
- icon_state = "sheet-uranium"
- default_type = "uranium"
- no_variants = FALSE
-
-/obj/item/stack/material/phoron
- name = "solid phoron"
- icon_state = "sheet-phoron"
- default_type = "phoron"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
-
-/obj/item/stack/material/plastic
- name = "plastic"
- icon_state = "sheet-plastic"
- default_type = "plastic"
- no_variants = FALSE
-
-/obj/item/stack/material/graphite
- name = "graphite"
- icon_state = "sheet-puck"
- default_type = MAT_GRAPHITE
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/gold
- name = "gold"
- icon_state = "sheet-ingot"
- default_type = "gold"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/silver
- name = "silver"
- icon_state = "sheet-ingot"
- default_type = "silver"
- no_variants = FALSE
- apply_colour = TRUE
-
-//Valuable resource, cargo can sell it.
-/obj/item/stack/material/platinum
- name = "platinum"
- icon_state = "sheet-adamantine"
- default_type = "platinum"
- no_variants = FALSE
- apply_colour = TRUE
-
-//Extremely valuable to Research.
-/obj/item/stack/material/mhydrogen
- name = "metallic hydrogen"
- icon_state = "sheet-mythril"
- default_type = "mhydrogen"
- no_variants = FALSE
-
-//Fuel for MRSPACMAN generator.
-/obj/item/stack/material/tritium
- name = "tritium"
- icon_state = "sheet-puck"
- default_type = "tritium"
- apply_colour = TRUE
- no_variants = FALSE
-
-/obj/item/stack/material/osmium
- name = "osmium"
- icon_state = "sheet-ingot"
- default_type = "osmium"
- apply_colour = 1
- no_variants = FALSE
-
-//R-UST port
-// Fusion fuel.
-/obj/item/stack/material/deuterium
- name = "deuterium"
- icon_state = "sheet-puck"
- default_type = "deuterium"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/steel
- name = DEFAULT_WALL_MATERIAL
- icon_state = "sheet-refined"
- default_type = DEFAULT_WALL_MATERIAL
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/steel/hull
- name = MAT_STEELHULL
- default_type = MAT_STEELHULL
-
-/obj/item/stack/material/plasteel
- name = "plasteel"
- icon_state = "sheet-reinforced"
- default_type = "plasteel"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/plasteel/hull
- name = MAT_PLASTEELHULL
- default_type = MAT_PLASTEELHULL
-
-/obj/item/stack/material/durasteel
- name = "durasteel"
- icon_state = "sheet-reinforced"
- item_state = "sheet-metal"
- default_type = "durasteel"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/durasteel/hull
- name = MAT_DURASTEELHULL
-
-/obj/item/stack/material/titanium
- name = MAT_TITANIUM
- icon_state = "sheet-refined"
- apply_colour = TRUE
- item_state = "sheet-silver"
- default_type = MAT_TITANIUM
- no_variants = FALSE
-
-/obj/item/stack/material/titanium/hull
- name = MAT_TITANIUMHULL
- default_type = MAT_TITANIUMHULL
-
-// Particle Smasher and Exotic material.
-/obj/item/stack/material/verdantium
- name = MAT_VERDANTIUM
- icon_state = "sheet-wavy"
- item_state = "mhydrogen"
- default_type = MAT_VERDANTIUM
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/morphium
- name = MAT_MORPHIUM
- icon_state = "sheet-wavy"
- item_state = "mhydrogen"
- default_type = MAT_MORPHIUM
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/morphium/hull
- name = MAT_MORPHIUMHULL
- default_type = MAT_MORPHIUMHULL
-
-/obj/item/stack/material/valhollide
- name = MAT_VALHOLLIDE
- icon_state = "sheet-gem"
- item_state = "diamond"
- default_type = MAT_VALHOLLIDE
- no_variants = FALSE
- apply_colour = TRUE
-
-// Forged in the equivalent of Hell, one piece at a time.
-/obj/item/stack/material/supermatter
- name = MAT_SUPERMATTER
- icon_state = "sheet-super"
- item_state = "diamond"
- default_type = MAT_SUPERMATTER
- apply_colour = TRUE
-
-/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack.
- slowdown = amount / 10
- w_class = min(5, round(amount / 10) + 1)
- throw_range = round(amount / 7) + 1
-
-/obj/item/stack/material/supermatter/use(var/used)
- . = ..()
- update_mass()
- return
-
-/obj/item/stack/material/supermatter/attack_hand(mob/user)
- . = ..()
-
- update_mass()
- SSradiation.radiate(src, 5 + amount)
- var/mob/living/M = user
- if(!istype(M))
- return
-
- var/burn_user = TRUE
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- var/obj/item/clothing/gloves/G = H.gloves
- if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
- burn_user = FALSE
-
- if(burn_user)
- H.visible_message("\The [src] flashes as it scorches [H]'s hands!")
- H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk")
- H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk")
- H.drop_from_inventory(src, get_turf(H))
- return
-
- if(istype(user, /mob/living/silicon/robot))
- burn_user = FALSE
-
- if(burn_user)
- M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk")
-
-/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature.
- if(prob((4 / severity) * 20))
- SSradiation.radiate(get_turf(src), amount * 4)
- explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25))
- qdel(src)
- return
- SSradiation.radiate(get_turf(src), amount * 2)
- ..()
-
-/obj/item/stack/material/wood
- name = "wooden plank"
- icon_state = "sheet-wood"
- default_type = MAT_WOOD
- strict_color_stacking = TRUE
- apply_colour = 1
- drop_sound = 'sound/items/drop/wooden.ogg'
- pickup_sound = 'sound/items/pickup/wooden.ogg'
- no_variants = FALSE
-
-/obj/item/stack/material/wood/sif
- name = "alien wooden plank"
- color = "#0099cc"
- default_type = MAT_SIFWOOD
-
-/obj/item/stack/material/log
- name = "log"
- icon_state = "sheet-log"
- default_type = MAT_LOG
- no_variants = FALSE
- color = "#824B28"
- max_amount = 25
- w_class = ITEMSIZE_HUGE
- description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks."
- var/plank_type = /obj/item/stack/material/wood
- drop_sound = 'sound/items/drop/wooden.ogg'
- pickup_sound = 'sound/items/pickup/wooden.ogg'
-
-/obj/item/stack/material/log/sif
- name = "alien log"
- default_type = MAT_SIFLOG
- color = "#0099cc"
- plank_type = /obj/item/stack/material/wood/sif
-
-/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
- if(!istype(W) || W.force <= 0)
- return ..()
- if(W.sharp && W.edge)
- var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed
- user.setClickCooldown(time)
- if(do_after(user, time, src) && use(1))
- to_chat(user, "You cut up a log into planks.")
- playsound(src, 'sound/effects/woodcutting.ogg', 50, 1)
- var/obj/item/stack/material/wood/existing_wood = null
- for(var/obj/item/stack/material/wood/M in user.loc)
- if(M.material.name == src.material.name)
- existing_wood = M
- break
-
- var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc)
- new_wood.amount = 2
- if(existing_wood && new_wood.transfer_to(existing_wood))
- to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.")
- else
- return ..()
-
-
-/obj/item/stack/material/cloth
- name = "cloth"
- icon_state = "sheet-cloth"
- default_type = "cloth"
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
-
-/obj/item/stack/material/cloth/diyaab
- color = "#c6ccf0"
-
-/obj/item/stack/material/resin
- name = "resin"
- icon_state = "sheet-resin"
- default_type = "resin"
- no_variants = TRUE
- apply_colour = TRUE
- pass_color = TRUE
- strict_color_stacking = TRUE
-
-/obj/item/stack/material/cardboard
- name = "cardboard"
- icon_state = "sheet-card"
- default_type = "cardboard"
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/cardboardbox.ogg'
- pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
-
-/obj/item/stack/material/snow
- name = "snow"
- desc = "The temptation to build a snowman rises."
- icon_state = "sheet-snow"
- drop_sound = 'sound/items/drop/gloves.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
- default_type = "snow"
-
-/obj/item/stack/material/snowbrick
- name = "snow brick"
- desc = "For all of your igloo building needs."
- icon_state = "sheet-snowbrick"
- default_type = "packed snow"
- drop_sound = 'sound/items/drop/gloves.ogg'
- pickup_sound = 'sound/items/pickup/clothing.ogg'
-
-/obj/item/stack/material/leather
- name = "leather"
- desc = "The by-product of mob grinding."
- icon_state = "sheet-leather"
- default_type = MAT_LEATHER
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/leather.ogg'
- pickup_sound = 'sound/items/pickup/leather.ogg'
-
-/obj/item/stack/material/chitin
- name = "chitin"
- desc = "The by-product of mob grinding."
- icon_state = "chitin"
- default_type = MAT_CHITIN
- no_variants = FALSE
- pass_color = TRUE
- strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/leather.ogg'
- pickup_sound = 'sound/items/pickup/leather.ogg'
-
-/obj/item/stack/material/glass
- name = "glass"
- icon_state = "sheet-transparent"
- default_type = "glass"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- pickup_sound = 'sound/items/pickup/glass.ogg'
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/reinforced
- name = "reinforced glass"
- icon_state = "sheet-rtransparent"
- default_type = "rglass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/phoronglass
- name = "borosilicate glass"
- desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures"
- singular_name = "borosilicate glass sheet"
- icon_state = "sheet-transparent"
- default_type = "borosilicate glass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/glass/phoronrglass
- name = "reinforced borosilicate glass"
- desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods."
- singular_name = "reinforced borosilicate glass sheet"
- icon_state = "sheet-rtransparent"
- default_type = "reinforced borosilicate glass"
- no_variants = FALSE
- apply_colour = TRUE
-
-/obj/item/stack/material/bronze
- name = "bronze"
- icon_state = "sheet-ingot"
- singular_name = "bronze ingot"
- default_type = "bronze"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/tin
- name = "tin"
- icon_state = "sheet-ingot"
- singular_name = "tin ingot"
- default_type = "tin"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/copper
- name = "copper"
- icon_state = "sheet-ingot"
- singular_name = "copper ingot"
- default_type = "copper"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/painite
- name = "painite"
- icon_state = "sheet-gem"
- singular_name = "painite gem"
- default_type = "painite"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/void_opal
- name = "void opal"
- icon_state = "sheet-void_opal"
- singular_name = "void opal"
- default_type = "void opal"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/quartz
- name = "quartz"
- icon_state = "sheet-gem"
- singular_name = "quartz gem"
- default_type = "quartz"
- apply_colour = 1
- no_variants = FALSE
-
-/obj/item/stack/material/aluminium
- name = "aluminium"
- icon_state = "sheet-ingot"
- singular_name = "aluminium ingot"
- default_type = "aluminium"
- apply_colour = 1
- no_variants = FALSE
diff --git a/code/modules/materials/material_sheets_vr.dm b/code/modules/materials/material_sheets_vr.dm
deleted file mode 100644
index 71d7e7d3ea8..00000000000
--- a/code/modules/materials/material_sheets_vr.dm
+++ /dev/null
@@ -1,66 +0,0 @@
-/obj/item/stack/material/titanium
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-titanium"
- no_variants = FALSE
-
-/obj/fiftyspawner/titanium
- name = "stack of titanium"
- type_to_spawn = /obj/item/stack/material/titanium
-
-/obj/item/stack/material/glass/titanium
- name = "ti-glass sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-titaniumglass"
- item_state = "sheet-silver"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- default_type = MAT_TITANIUMGLASS
-
-/obj/fiftyspawner/titanium_glass
- name = "stack of ti-glass"
- type_to_spawn = /obj/item/stack/material/glass/titanium
-
-/obj/item/stack/material/plastitanium
- name = "plastitanium sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_PLASTITANIUM
-
-/obj/fiftyspawner/plastitanium
- name = "stack of plastitanium"
- type_to_spawn = /obj/item/stack/material/plastitanium
-
-/obj/item/stack/material/plastitanium/hull
- name = "plastitanium hull sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_PLASTITANIUMHULL
-
-/obj/fiftyspawner/plastitanium_hull
- name = "stack of plastitanium"
- type_to_spawn = /obj/item/stack/material/plastitanium/hull
-
-/obj/item/stack/material/glass/plastitanium
- name = "plastitanium glass sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitaniumglass"
- item_state = "sheet-silver"
- no_variants = FALSE
- drop_sound = 'sound/items/drop/glass.ogg'
- default_type = MAT_PLASTITANIUMGLASS
-
-/obj/fiftyspawner/plastitanium_glass
- name = "stack of plastitanium glass"
- type_to_spawn = /obj/item/stack/material/glass/plastitanium
-
-/obj/item/stack/material/gold/hull
- name = "gold hull sheets"
- icon = 'icons/obj/stacks_vr.dmi'
- icon_state = "sheet-plastitanium"
- item_state = "sheet-silver"
- no_variants = FALSE
- default_type = MAT_GOLDHULL
\ No newline at end of file
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
deleted file mode 100644
index b591ee26c54..00000000000
--- a/code/modules/materials/materials.dm
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
- MATERIAL DATUMS
- This data is used by various parts of the game for basic physical properties and behaviors
- of the metals/materials used for constructing many objects. Each var is commented and should be pretty
- self-explanatory but the various object types may have their own documentation. ~Z
-
- PATHS THAT USE DATUMS
- turf/simulated/wall
- obj/item/weapon/material
- obj/structure/barricade
- obj/item/stack/material
- obj/structure/table
-
- VALID ICONS
- WALLS
- stone
- metal
- solid
- resin
- ONLY WALLS
- cult
- hull
- curvy
- jaggy
- brick
- REINFORCEMENT
- reinf_over
- reinf_mesh
- reinf_cult
- reinf_metal
- DOORS
- stone
- metal
- resin
- wood
-*/
-
-// Assoc list containing all material datums indexed by name.
-var/list/name_to_material
-
-//Returns the material the object is made of, if applicable.
-//Will we ever need to return more than one value here? Or should we just return the "dominant" material.
-/obj/proc/get_material()
- return null
-
-//mostly for convenience
-/obj/proc/get_material_name()
- var/datum/material/material = get_material()
- if(material)
- return material.name
-
-// Builds the datum list above.
-/proc/populate_material_list(force_remake=0)
- if(name_to_material && !force_remake) return // Already set up!
- name_to_material = list()
- for(var/type in subtypesof(/datum/material))
- var/datum/material/new_mineral = new type
- if(!new_mineral.name)
- qdel(new_mineral)
- continue
- name_to_material[lowertext(new_mineral.name)] = new_mineral
- return 1
-
-// Safety proc to make sure the material list exists before trying to grab from it.
-/proc/get_material_by_name(name)
- if(!name_to_material)
- populate_material_list()
- return name_to_material[name]
-
-/proc/material_display_name(name)
- var/datum/material/material = get_material_by_name(name)
- if(material)
- return material.display_name
- return null
-
-// Material definition and procs follow.
-/datum/material
- var/name // Unique name for use in indexing the list.
- var/display_name // Prettier name for display.
- var/use_name
- var/flags = 0 // Various status modifiers.
- var/sheet_singular_name = "sheet"
- var/sheet_plural_name = "sheets"
- var/is_fusion_fuel
-
- // Shards/tables/structures
- var/shard_type = SHARD_SHRAPNEL // Path of debris object.
- var/shard_icon // Related to above.
- var/shard_can_repair = 1 // Can shards be turned into sheets with a welder?
- var/list/recipes // Holder for all recipes usable with a sheet of this material.
- var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding.
-
- // Icons
- var/icon_colour // Colour applied to products of this material.
- var/icon_base = "metal" // Wall and table base icon tag. See header.
- var/door_icon_base = "metal" // Door base icon tag. See header.
- var/icon_reinf = "reinf_metal" // Overlay used
- var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks.
- var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects?
-
- // Attributes
- var/cut_delay = 0 // Delay in ticks when cutting through this wall.
- var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings.
- var/ignition_point // K, point at which the material catches on fire.
- var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this
- var/integrity = 150 // General-use HP value for products.
- var/protectiveness = 10 // How well this material works as armor. Higher numbers are better, diminishing returns applies.
- var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors.
- var/reflectivity = 0 // How reflective to light is the material? Currently used for laser reflection and defense.
- var/explosion_resistance = 5 // Only used by walls currently.
- var/negation = 0 // Objects that respect this will randomly absorb impacts with this var as the percent chance.
- var/spatial_instability = 0 // Objects that have trouble staying in the same physical space by sheer laws of nature have this. Percent for respecting items to cause teleportation.
- var/conductive = 1 // Objects without this var add NOCONDUCT to flags on spawn.
- var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10.
- var/list/composite_material // If set, object matter var will be a list containing these values.
- var/luminescence
- var/radiation_resistance = 0 // Radiation resistance, which is added on top of a material's weight for blocking radiation. Needed to make lead special without superrobust weapons.
- var/supply_conversion_value // Supply points per sheet that this material sells for.
-
- // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
- var/created_window
- var/created_fulltile_window
- var/rod_product
- var/wire_product
- var/list/window_options = list()
-
- // Damage values.
- var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. Also used for bullet protection in armor.
- var/weight = 20 // Determines blunt damage/throwforce for weapons.
-
- // Noise when someone is faceplanted onto a table made of this material.
- var/tableslam_noise = 'sound/weapons/tablehit1.ogg'
- // Noise made when a simple door made of this material opens or closes.
- var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg'
- // Path to resulting stacktype. Todo remove need for this.
- var/stack_type
- // Wallrot crumble message.
- var/rotting_touch_message = "crumbles under your touch"
-
-// Placeholders for light tiles and rglass.
-/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
- if(!rod_product)
- to_chat(user, "You cannot make anything out of \the [target_stack]")
- return
- if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1)
- to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.")
- return
- used_stack.use(1)
- target_stack.use(1)
- var/obj/item/stack/S = new rod_product(get_turf(user))
- S.add_fingerprint(user)
- S.add_to_stacks(user)
-
-/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
- if(!wire_product)
- to_chat(user, "You cannot make anything out of \the [target_stack]")
- return
- if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1)
- to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.")
- return
-
- used_stack.use(5)
- target_stack.use(1)
- to_chat(user, "You attach wire to the [name].")
- var/obj/item/product = new wire_product(get_turf(user))
- user.put_in_hands(product)
-
-// Make sure we have a display name and shard icon even if they aren't explicitly set.
-/datum/material/New()
- ..()
- if(!display_name)
- display_name = name
- if(!use_name)
- use_name = display_name
- if(!shard_icon)
- shard_icon = shard_type
-
-// This is a placeholder for proper integration of windows/windoors into the system.
-/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
- return 0
-
-// Weapons handle applying a divisor for this value locally.
-/datum/material/proc/get_blunt_damage()
- return weight //todo
-
-// Return the matter comprising this material.
-/datum/material/proc/get_matter()
- var/list/temp_matter = list()
- if(islist(composite_material))
- for(var/material_string in composite_material)
- temp_matter[material_string] = composite_material[material_string]
- else if(SHEET_MATERIAL_AMOUNT)
- temp_matter[name] = SHEET_MATERIAL_AMOUNT
- return temp_matter
-
-// As above.
-/datum/material/proc/get_edge_damage()
- return hardness //todo
-
-// Snowflakey, only checked for alien doors at the moment.
-/datum/material/proc/can_open_material_door(var/mob/living/user)
- return 1
-
-// Currently used for weapons and objects made of uranium to irradiate things.
-/datum/material/proc/products_need_process()
- return (radioactivity>0) //todo
-
-// Used by walls when qdel()ing to avoid neighbor merging.
-/datum/material/placeholder
- name = "placeholder"
-
-// Places a girder object when a wall is dismantled, also applies reinforced material.
-/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material)
- var/obj/structure/girder/G = new(target)
- if(reinf_material)
- G.reinf_material = reinf_material
- G.reinforce_girder()
- if(girder_material)
- if(istype(girder_material, /datum/material))
- girder_material = girder_material.name
- G.set_material(girder_material)
-
-
-// General wall debris product placement.
-// Not particularly necessary aside from snowflakey cult girders.
-/datum/material/proc/place_dismantled_product(var/turf/target)
- place_sheet(target)
-
-// Debris product. Used ALL THE TIME.
-/datum/material/proc/place_sheet(var/turf/target)
- if(stack_type)
- return new stack_type(target)
-
-// As above.
-/datum/material/proc/place_shard(var/turf/target)
- if(shard_type)
- return new /obj/item/weapon/material/shard(target, src.name)
-
-// Used by walls and weapons to determine if they break or not.
-/datum/material/proc/is_brittle()
- return !!(flags & MATERIAL_BRITTLE)
-
-/datum/material/proc/combustion_effect(var/turf/T, var/temperature)
- return
-
-// Used by walls to do on-touch things, after checking for crumbling and open-ability.
-/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
- return
-
-// Datum definitions follow.
-/datum/material/uranium
- name = "uranium"
- stack_type = /obj/item/stack/material/uranium
- radioactivity = 12
- icon_base = "stone"
- icon_reinf = "reinf_stone"
- icon_colour = "#007A00"
- weight = 22
- stack_origin_tech = list(TECH_MATERIAL = 5)
- door_icon_base = "stone"
- supply_conversion_value = 2
-
-/datum/material/diamond
- name = "diamond"
- stack_type = /obj/item/stack/material/diamond
- flags = MATERIAL_UNMELTABLE
- cut_delay = 60
- icon_colour = "#00FFE1"
- opacity = 0.4
- reflectivity = 0.6
- conductive = 0
- conductivity = 1
- shard_type = SHARD_SHARD
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- hardness = 100
- stack_origin_tech = list(TECH_MATERIAL = 6)
- supply_conversion_value = 8
-
-/datum/material/gold
- name = "gold"
- stack_type = /obj/item/stack/material/gold
- icon_colour = "#EDD12F"
- weight = 24
- hardness = 40
- conductivity = 41
- stack_origin_tech = list(TECH_MATERIAL = 4)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 2
-
-/datum/material/gold/bronze //placeholder for ashtrays
- name = "bronze"
- icon_colour = "#EDD12F"
-
-/datum/material/silver
- name = "silver"
- stack_type = /obj/item/stack/material/silver
- icon_colour = "#D1E6E3"
- weight = 22
- hardness = 50
- conductivity = 63
- stack_origin_tech = list(TECH_MATERIAL = 3)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 2
-
-//R-UST port
-/datum/material/supermatter
- name = "supermatter"
- icon_colour = "#FFFF00"
- stack_type = /obj/item/stack/material/supermatter
- shard_type = SHARD_SHARD
- radioactivity = 20
- stack_type = null
- luminescence = 3
- ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
- icon_base = "stone"
- shard_type = SHARD_SHARD
- hardness = 30
- door_icon_base = "stone"
- sheet_singular_name = "crystal"
- sheet_plural_name = "crystals"
- is_fusion_fuel = 1
- stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4)
-
-/datum/material/phoron
- name = "phoron"
- stack_type = /obj/item/stack/material/phoron
- ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
- icon_base = "stone"
- icon_colour = "#FC2BC5"
- shard_type = SHARD_SHARD
- hardness = 30
- stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2)
- door_icon_base = "stone"
- sheet_singular_name = "crystal"
- sheet_plural_name = "crystals"
- supply_conversion_value = 5
-
-/*
-// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately.
-/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier)
- if(isnull(ignition_point))
- return 0
- if(temperature < ignition_point)
- return 0
- var/totalPhoron = 0
- for(var/turf/simulated/floor/target_tile in range(2,T))
- var/phoronToDeduce = (temperature/30) * effect_multiplier
- totalPhoron += phoronToDeduce
- target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C)
- spawn (0)
- target_tile.hotspot_expose(temperature, 400)
- return round(totalPhoron/100)
-*/
-
-/datum/material/stone
- name = "sandstone"
- stack_type = /obj/item/stack/material/sandstone
- icon_base = "stone"
- icon_reinf = "reinf_stone"
- icon_colour = "#D9C179"
- shard_type = SHARD_STONE_PIECE
- weight = 22
- hardness = 55
- protectiveness = 5 // 20%
- conductive = 0
- conductivity = 5
- door_icon_base = "stone"
- sheet_singular_name = "brick"
- sheet_plural_name = "bricks"
-
-/datum/material/stone/marble
- name = "marble"
- icon_colour = "#AAAAAA"
- weight = 26
- hardness = 30 //VOREStation Edit - Please.
- integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system
- stack_type = /obj/item/stack/material/marble
- supply_conversion_value = 2
-
-/datum/material/steel
- name = DEFAULT_WALL_MATERIAL
- stack_type = /obj/item/stack/material/steel
- integrity = 150
- conductivity = 11 // Assuming this is carbon steel, it would actually be slightly less conductive than iron, but lets ignore that.
- protectiveness = 10 // 33%
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#666666"
-
-/datum/material/steel/hull
- name = MAT_STEELHULL
- stack_type = /obj/item/stack/material/steel/hull
- integrity = 250
- explosion_resistance = 10
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- icon_colour = "#666677"
-
-/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets.
- new /obj/item/stack/material/steel(target)
-
-/datum/material/diona
- name = "biomass"
- icon_colour = null
- stack_type = null
- integrity = 600
- icon_base = "diona"
- icon_reinf = "noreinf"
-
-/datum/material/diona/place_dismantled_product()
- return
-
-/datum/material/diona/place_dismantled_girder(var/turf/target)
- spawn_diona_nymph(target)
-
-/datum/material/steel/holographic
- name = "holo" + DEFAULT_WALL_MATERIAL
- display_name = DEFAULT_WALL_MATERIAL
- stack_type = null
- shard_type = SHARD_NONE
-
-/datum/material/plasteel
- name = "plasteel"
- stack_type = /obj/item/stack/material/plasteel
- integrity = 400
- melting_point = 6000
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#777777"
- explosion_resistance = 25
- hardness = 80
- weight = 23
- protectiveness = 20 // 50%
- conductivity = 13 // For the purposes of balance.
- stack_origin_tech = list(TECH_MATERIAL = 2)
- composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo
- supply_conversion_value = 6
-
-/datum/material/plasteel/hull
- name = MAT_PLASTEELHULL
- stack_type = /obj/item/stack/material/plasteel/hull
- integrity = 600
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- icon_colour = "#777788"
- explosion_resistance = 40
-
-/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
- new /obj/item/stack/material/plasteel(target)
-
-// Very rare alloy that is reflective, should be used sparingly.
-/datum/material/durasteel
- name = "durasteel"
- stack_type = /obj/item/stack/material/durasteel/hull
- integrity = 600
- melting_point = 7000
- icon_base = "metal"
- icon_reinf = "reinf_metal"
- icon_colour = "#6EA7BE"
- explosion_resistance = 75
- hardness = 100
- weight = 28
- protectiveness = 60 // 75%
- reflectivity = 0.7 // Not a perfect mirror, but close.
- stack_origin_tech = list(TECH_MATERIAL = 8)
- composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug
- supply_conversion_value = 9
-
-/datum/material/durasteel/hull //The 'Hardball' of starship hulls.
- name = MAT_DURASTEELHULL
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- icon_colour = "#45829a"
- explosion_resistance = 90
- reflectivity = 0.9
-
-/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets.
- new /obj/item/stack/material/durasteel(target)
-
-/datum/material/plasteel/titanium
- name = MAT_TITANIUM
- stack_type = /obj/item/stack/material/titanium
- conductivity = 2.38
- icon_base = "metal"
- door_icon_base = "metal"
- icon_colour = "#D1E6E3"
- icon_reinf = "reinf_metal"
- composite_material = null
-
-/datum/material/plasteel/titanium/hull
- name = MAT_TITANIUMHULL
- stack_type = /obj/item/stack/material/titanium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
-
-/datum/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
- new /obj/item/stack/material/titanium(target)
-
-/datum/material/glass
- name = "glass"
- stack_type = /obj/item/stack/material/glass
- flags = MATERIAL_BRITTLE
- icon_colour = "#00E1FF"
- opacity = 0.3
- integrity = 100
- shard_type = SHARD_SHARD
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- hardness = 30
- weight = 15
- protectiveness = 0 // 0%
- conductive = 0
- conductivity = 1 // Glass shards don't conduct.
- door_icon_base = "stone"
- destruction_desc = "shatters"
- window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
- created_window = /obj/structure/window/basic
- created_fulltile_window = /obj/structure/window/basic/full
- rod_product = /obj/item/stack/material/glass/reinforced
-
-/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
-
- if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len)
- return 0
-
- if(!user.IsAdvancedToolUser())
- to_chat(user, "This task is too complex for your clumsy hands.")
- return 1
-
- var/turf/T = user.loc
- if(!istype(T))
- to_chat(user, "You must be standing on open flooring to build a window.")
- return 1
-
- var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)"
- var/choice = input(title, "What would you like to construct?") as null|anything in window_options
-
- if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T)
- return 1
-
- // Get data for building windows here.
- var/list/possible_directions = cardinal.Copy()
- var/window_count = 0
- for (var/obj/structure/window/check_window in user.loc)
- window_count++
- possible_directions -= check_window.dir
- for (var/obj/structure/windoor_assembly/check_assembly in user.loc)
- window_count++
- possible_directions -= check_assembly.dir
- for (var/obj/machinery/door/window/check_windoor in user.loc)
- window_count++
- possible_directions -= check_windoor.dir
-
- // Get the closest available dir to the user's current facing.
- var/build_dir = SOUTHWEST //Default to southwest for fulltile windows.
- var/failed_to_build
-
- if(window_count >= 4)
- failed_to_build = 1
- else
- if(choice in list("One Direction","Windoor"))
- if(possible_directions.len)
- for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,270), turn(user.dir,180)))
- if(direction in possible_directions)
- build_dir = direction
- break
- else
- failed_to_build = 1
- if(failed_to_build)
- to_chat(user, "There is no room in this location.")
- return 1
-
- var/build_path = /obj/structure/windoor_assembly
- var/sheets_needed = window_options[choice]
- if(choice == "Windoor")
- if(is_reinforced())
- build_path = /obj/structure/windoor_assembly/secure
- else if(choice == "Full Window")
- build_path = created_fulltile_window
- else
- build_path = created_window
-
- if(used_stack.get_amount() < sheets_needed)
- to_chat(user, "You need at least [sheets_needed] sheets to build this.")
- return 1
-
- // Build the structure and update sheet count etc.
- used_stack.use(sheets_needed)
- new build_path(T, build_dir, 1)
- return 1
-
-/datum/material/glass/proc/is_reinforced()
- return (hardness > 35) //todo
-
-/datum/material/glass/reinforced
- name = "rglass"
- display_name = "reinforced glass"
- stack_type = /obj/item/stack/material/glass/reinforced
- flags = MATERIAL_BRITTLE
- icon_colour = "#00E1FF"
- opacity = 0.3
- integrity = 100
- shard_type = SHARD_SHARD
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- hardness = 40
- weight = 30
- stack_origin_tech = list(TECH_MATERIAL = 2)
- composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "glass" = SHEET_MATERIAL_AMOUNT)
- window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
- created_window = /obj/structure/window/reinforced
- created_fulltile_window = /obj/structure/window/reinforced/full
- wire_product = null
- rod_product = null
-
-/datum/material/glass/phoron
- name = "borosilicate glass"
- display_name = "borosilicate glass"
- stack_type = /obj/item/stack/material/glass/phoronglass
- flags = MATERIAL_BRITTLE
- integrity = 100
- icon_colour = "#FC2BC5"
- stack_origin_tech = list(TECH_MATERIAL = 4)
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/phoronbasic
- created_fulltile_window = /obj/structure/window/phoronbasic/full
- wire_product = null
- rod_product = /obj/item/stack/material/glass/phoronrglass
-
-/datum/material/glass/phoron/reinforced
- name = "reinforced borosilicate glass"
- display_name = "reinforced borosilicate glass"
- stack_type = /obj/item/stack/material/glass/phoronrglass
- stack_origin_tech = list(TECH_MATERIAL = 5)
- composite_material = list() //todo
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/phoronreinforced
- created_fulltile_window = /obj/structure/window/phoronreinforced/full
- hardness = 40
- weight = 30
- stack_origin_tech = list(TECH_MATERIAL = 2)
- composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "borosilicate glass" = SHEET_MATERIAL_AMOUNT)
- rod_product = null
-
-/datum/material/plastic
- name = "plastic"
- stack_type = /obj/item/stack/material/plastic
- flags = MATERIAL_BRITTLE
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#CCCCCC"
- hardness = 10
- weight = 12
- protectiveness = 5 // 20%
- conductive = 0
- conductivity = 2 // For the sake of material armor diversity, we're gonna pretend this plastic is a good insulator.
- melting_point = T0C+371 //assuming heat resistant plastic
- stack_origin_tech = list(TECH_MATERIAL = 3)
-
-/datum/material/plastic/holographic
- name = "holoplastic"
- display_name = "plastic"
- stack_type = null
- shard_type = SHARD_NONE
-
-/datum/material/graphite
- name = MAT_GRAPHITE
- stack_type = /obj/item/stack/material/graphite
- flags = MATERIAL_BRITTLE
- icon_base = "solid"
- icon_reinf = "reinf_mesh"
- icon_colour = "#333333"
- hardness = 75
- weight = 15
- integrity = 175
- protectiveness = 15
- conductivity = 18
- melting_point = T0C+3600
- radiation_resistance = 15
- stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2)
-
-/datum/material/osmium
- name = "osmium"
- stack_type = /obj/item/stack/material/osmium
- icon_colour = "#9999FF"
- stack_origin_tech = list(TECH_MATERIAL = 5)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- conductivity = 100
- supply_conversion_value = 6
-
-/datum/material/tritium
- name = "tritium"
- stack_type = /obj/item/stack/material/tritium
- icon_colour = "#777777"
- stack_origin_tech = list(TECH_MATERIAL = 5)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- is_fusion_fuel = 1
- conductive = 0
-
-/datum/material/deuterium
- name = "deuterium"
- stack_type = /obj/item/stack/material/deuterium
- icon_colour = "#999999"
- stack_origin_tech = list(TECH_MATERIAL = 3)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- is_fusion_fuel = 1
- conductive = 0
-
-/datum/material/mhydrogen
- name = "mhydrogen"
- stack_type = /obj/item/stack/material/mhydrogen
- icon_colour = "#E6C5DE"
- stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5)
- conductivity = 100
- is_fusion_fuel = 1
- supply_conversion_value = 6
-
-/datum/material/platinum
- name = "platinum"
- stack_type = /obj/item/stack/material/platinum
- icon_colour = "#9999FF"
- weight = 27
- conductivity = 9.43
- stack_origin_tech = list(TECH_MATERIAL = 2)
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 5
-
-/datum/material/iron
- name = "iron"
- stack_type = /obj/item/stack/material/iron
- icon_colour = "#5C5454"
- weight = 22
- conductivity = 10
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
-
-/datum/material/lead
- name = MAT_LEAD
- stack_type = /obj/item/stack/material/lead
- icon_colour = "#273956"
- weight = 23 // Lead is a bit more dense than silver IRL, and silver has 22 ingame.
- conductivity = 10
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- radiation_resistance = 25 // Lead is Special and so gets to block more radiation than it normally would with just weight, totalling in 48 protection.
- supply_conversion_value = 2
-
-// Particle Smasher and other exotic materials.
-
-/datum/material/verdantium
- name = MAT_VERDANTIUM
- stack_type = /obj/item/stack/material/verdantium
- icon_base = "metal"
- door_icon_base = "metal"
- icon_reinf = "reinf_metal"
- icon_colour = "#4FE95A"
- integrity = 80
- protectiveness = 15
- weight = 15
- hardness = 30
- shard_type = SHARD_SHARD
- negation = 15
- conductivity = 60
- reflectivity = 0.3
- radiation_resistance = 5
- stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 5, TECH_BIO = 4)
- sheet_singular_name = "sheet"
- sheet_plural_name = "sheets"
- supply_conversion_value = 8
-
-/datum/material/morphium
- name = MAT_MORPHIUM
- stack_type = /obj/item/stack/material/morphium
- icon_base = "metal"
- door_icon_base = "metal"
- icon_colour = "#37115A"
- icon_reinf = "reinf_metal"
- protectiveness = 60
- integrity = 300
- conductive = 0
- conductivity = 1.5
- hardness = 90
- shard_type = SHARD_SHARD
- weight = 30
- negation = 25
- explosion_resistance = 85
- reflectivity = 0.2
- radiation_resistance = 10
- stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1)
- supply_conversion_value = 13
-
-/datum/material/morphium/hull
- name = MAT_MORPHIUMHULL
- stack_type = /obj/item/stack/material/morphium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
-
-/datum/material/valhollide
- name = MAT_VALHOLLIDE
- stack_type = /obj/item/stack/material/valhollide
- icon_base = "stone"
- door_icon_base = "stone"
- icon_reinf = "reinf_mesh"
- icon_colour = "##FFF3B2"
- protectiveness = 30
- integrity = 240
- weight = 30
- hardness = 45
- negation = 2
- conductive = 0
- conductivity = 5
- reflectivity = 0.5
- radiation_resistance = 20
- spatial_instability = 30
- stack_origin_tech = list(TECH_MATERIAL = 7, TECH_PHORON = 5, TECH_BLUESPACE = 5)
- sheet_singular_name = "gem"
- sheet_plural_name = "gems"
-
-
-// Adminspawn only, do not let anyone get this.
-/datum/material/alienalloy
- name = "alienalloy"
- display_name = "durable alloy"
- stack_type = null
- flags = MATERIAL_UNMELTABLE
- icon_colour = "#6C7364"
- integrity = 1200
- melting_point = 6000 // Hull plating.
- explosion_resistance = 200 // Hull plating.
- hardness = 500
- weight = 500
- protectiveness = 80 // 80%
-
-// Likewise.
-/datum/material/alienalloy/elevatorium
- name = "elevatorium"
- display_name = "elevator panelling"
- icon_colour = "#666666"
-
-// Ditto.
-/datum/material/alienalloy/dungeonium
- name = "dungeonium"
- display_name = "ultra-durable"
- icon_base = "dungeon"
- icon_colour = "#FFFFFF"
-
-/datum/material/alienalloy/bedrock
- name = "bedrock"
- display_name = "impassable rock"
- icon_base = "rock"
- icon_colour = "#FFFFFF"
-
-/datum/material/alienalloy/alium
- name = "alium"
- display_name = "alien"
- icon_base = "alien"
- icon_colour = "#FFFFFF"
-
-/datum/material/resin
- name = "resin"
- icon_colour = "#35343a"
- icon_base = "resin"
- dooropen_noise = 'sound/effects/attackblob.ogg'
- door_icon_base = "resin"
- icon_reinf = "reinf_mesh"
- melting_point = T0C+300
- sheet_singular_name = "blob"
- sheet_plural_name = "blobs"
- conductive = 0
- explosion_resistance = 60
- radiation_resistance = 10
- stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7)
- stack_type = /obj/item/stack/material/resin
-
-/datum/material/resin/can_open_material_door(var/mob/living/user)
- var/mob/living/carbon/M = user
- if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
- return 1
- return 0
-
-/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
- var/mob/living/carbon/M = L
- if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
- to_chat(M, "\The [W] shudders under your touch, starting to become porous.")
- playsound(W, 'sound/effects/attackblob.ogg', 50, 1)
- if(do_after(L, 5 SECONDS))
- spawn(2)
- playsound(W, 'sound/effects/attackblob.ogg', 100, 1)
- W.dismantle_wall()
- return 1
- return 0
-
-/datum/material/wood
- name = MAT_WOOD
- stack_type = /obj/item/stack/material/wood
- icon_colour = "#9c5930"
- integrity = 50
- icon_base = "wood"
- explosion_resistance = 2
- shard_type = SHARD_SPLINTER
- shard_can_repair = 0 // you can't weld splinters back into planks
- hardness = 15
- weight = 18
- protectiveness = 8 // 28%
- conductive = 0
- conductivity = 1
- melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood
- ignition_point = T0C+288
- stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1)
- dooropen_noise = 'sound/effects/doorcreaky.ogg'
- door_icon_base = "wood"
- destruction_desc = "splinters"
- sheet_singular_name = "plank"
- sheet_plural_name = "planks"
-
-/datum/material/wood/log
- name = MAT_LOG
- icon_base = "log"
- stack_type = /obj/item/stack/material/log
- sheet_singular_name = null
- sheet_plural_name = "pile"
- pass_stack_colors = TRUE
- supply_conversion_value = 1
-
-/datum/material/wood/log/sif
- name = MAT_SIFLOG
- icon_colour = "#0099cc" // Cyan-ish
- stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
- stack_type = /obj/item/stack/material/log/sif
-
-/datum/material/wood/holographic
- name = "holowood"
- display_name = "wood"
- stack_type = null
- shard_type = SHARD_NONE
-
-/datum/material/wood/sif
- name = MAT_SIFWOOD
- stack_type = /obj/item/stack/material/wood/sif
- icon_colour = "#0099cc" // Cyan-ish
- stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
-
-/datum/material/cardboard
- name = "cardboard"
- stack_type = /obj/item/stack/material/cardboard
- flags = MATERIAL_BRITTLE
- integrity = 10
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#AAAAAA"
- hardness = 1
- weight = 1
- protectiveness = 0 // 0%
- conductive = 0
- ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough
- melting_point = T0C+232 //temperature at which cardboard walls would be destroyed
- stack_origin_tech = list(TECH_MATERIAL = 1)
- door_icon_base = "wood"
- destruction_desc = "crumples"
- radiation_resistance = 1
- pass_stack_colors = TRUE
-
-/datum/material/snow
- name = MAT_SNOW
- stack_type = /obj/item/stack/material/snow
- flags = MATERIAL_BRITTLE
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#FFFFFF"
- integrity = 1
- hardness = 1
- weight = 1
- protectiveness = 0 // 0%
- stack_origin_tech = list(TECH_MATERIAL = 1)
- melting_point = T0C+1
- destruction_desc = "crumples"
- sheet_singular_name = "pile"
- sheet_plural_name = "pile" //Just a bigger pile
- radiation_resistance = 1
-
-/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly
- name = "packed snow"
- flags = MATERIAL_BRITTLE
- stack_type = /obj/item/stack/material/snowbrick
- icon_base = "stone"
- icon_reinf = "reinf_stone"
- icon_colour = "#D8FDFF"
- integrity = 50
- weight = 2
- hardness = 2
- protectiveness = 0 // 0%
- stack_origin_tech = list(TECH_MATERIAL = 1)
- melting_point = T0C+1
- destruction_desc = "crumbles"
- sheet_singular_name = "brick"
- sheet_plural_name = "bricks"
- radiation_resistance = 1
-
-/datum/material/cloth //todo
- name = "cloth"
- stack_origin_tech = list(TECH_MATERIAL = 2)
- door_icon_base = "wood"
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- flags = MATERIAL_PADDING
- conductive = 0
- integrity = 40
- pass_stack_colors = TRUE
- supply_conversion_value = 2
-
-/datum/material/cloth/syncloth
- name = "syncloth"
- stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2)
- door_icon_base = "wood"
- ignition_point = T0C+532
- melting_point = T0C+600
- integrity = 200
- protectiveness = 15 // 4%
- flags = MATERIAL_PADDING
- conductive = 0
- pass_stack_colors = TRUE
- supply_conversion_value = 3
-
-/datum/material/cult
- name = "cult"
- display_name = "disturbing stone"
- icon_base = "cult"
- icon_colour = "#402821"
- icon_reinf = "reinf_cult"
- shard_type = SHARD_STONE_PIECE
- sheet_singular_name = "brick"
- sheet_plural_name = "bricks"
- conductive = 0
-
-/datum/material/cult/place_dismantled_girder(var/turf/target)
- new /obj/structure/girder/cult(target, "cult")
-
-/datum/material/cult/place_dismantled_product(var/turf/target)
- new /obj/effect/decal/cleanable/blood(target)
-
-/datum/material/cult/reinf
- name = "cult2"
- display_name = "human remains"
-
-/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
- new /obj/effect/decal/remains/human(target)
-
-/datum/material/chitin
- name = MAT_CHITIN
- icon_colour = "#8d6653"
- stack_type = /obj/item/stack/material/chitin
- stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4)
- icon_base = "solid"
- icon_reinf = "reinf_mesh"
- integrity = 60
- weight = 10
- ignition_point = T0C+400
- melting_point = T0C+500
- protectiveness = 20
- conductive = 0
- supply_conversion_value = 4
-
-//TODO PLACEHOLDERS:
-/datum/material/leather
- name = MAT_LEATHER
- display_name = "plainleather"
- icon_colour = "#5C4831"
- stack_type = /obj/item/stack/material/leather
- stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
- flags = MATERIAL_PADDING
- ignition_point = T0C+300
- melting_point = T0C+300
- protectiveness = 3 // 13%
- conductive = 0
- integrity = 40
- supply_conversion_value = 3
-
-/datum/material/carpet
- name = "carpet"
- display_name = "comfy"
- use_name = "red upholstery"
- icon_colour = "#DA020A"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- sheet_singular_name = "tile"
- sheet_plural_name = "tiles"
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cotton
- name = "cotton"
- display_name ="cotton"
- icon_colour = "#FFFFFF"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-// This all needs to be OOP'd and use inheritence if its ever used in the future.
-/datum/material/cloth_teal
- name = "teal"
- display_name ="teal"
- use_name = "teal cloth"
- icon_colour = "#00EAFA"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_black
- name = "black"
- display_name = "black"
- use_name = "black cloth"
- icon_colour = "#505050"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_green
- name = "green"
- display_name = "green"
- use_name = "green cloth"
- icon_colour = "#01C608"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_puple
- name = "purple"
- display_name = "purple"
- use_name = "purple cloth"
- icon_colour = "#9C56C4"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_blue
- name = "blue"
- display_name = "blue"
- use_name = "blue cloth"
- icon_colour = "#6B6FE3"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_beige
- name = "beige"
- display_name = "beige"
- use_name = "beige cloth"
- icon_colour = "#E8E7C8"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_lime
- name = "lime"
- display_name = "lime"
- use_name = "lime cloth"
- icon_colour = "#62E36C"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_yellow
- name = "yellow"
- display_name = "yellow"
- use_name = "yellow cloth"
- icon_colour = "#EEF573"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/cloth_orange
- name = "orange"
- display_name = "orange"
- use_name = "orange cloth"
- icon_colour = "#E3BF49"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- protectiveness = 1 // 4%
- conductive = 0
-
-/datum/material/toy_foam
- name = "foam"
- display_name = "foam"
- use_name = "foam"
- flags = MATERIAL_PADDING
- ignition_point = T0C+232
- melting_point = T0C+300
- icon_colour = "#ff9900"
- hardness = 1
- weight = 1
- protectiveness = 0 // 0%
- conductive = 0
-
-/datum/material/void_opal
- name = "void opal"
- display_name = "void opal"
- use_name = "void opal"
- icon_colour = "#0f0f0f"
- stack_type = /obj/item/stack/material/void_opal
- flags = MATERIAL_UNMELTABLE
- cut_delay = 60
- reflectivity = 0
- conductivity = 1
- shard_type = SHARD_SHARD
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- hardness = 100
- stack_origin_tech = list(TECH_ARCANE = 1, TECH_MATERIAL = 6)
- sheet_singular_name = "gem"
- sheet_plural_name = "gems"
- supply_conversion_value = 30 // These are hilariously rare.
-
-/datum/material/painite
- name = "painite"
- display_name = "painite"
- use_name = "painite"
- icon_colour = "#6b4947"
- stack_type = /obj/item/stack/material/painite
- flags = MATERIAL_UNMELTABLE
- reflectivity = 0.3
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- sheet_singular_name = "gem"
- sheet_plural_name = "gems"
- supply_conversion_value = 4
-
-/datum/material/tin
- name = "tin"
- display_name = "tin"
- use_name = "tin"
- stack_type = /obj/item/stack/material/tin
- icon_colour = "#b2afaf"
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 1
- hardness = 50
- weight = 13
-
-/datum/material/copper
- name = "copper"
- display_name = "copper"
- use_name = "copper"
- stack_type = /obj/item/stack/material/copper
- conductivity = 52
- icon_colour = "#af633e"
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 1
- weight = 13
- hardness = 50
-
-/datum/material/quartz
- name = "quartz"
- display_name = "quartz"
- use_name = "quartz"
- icon_colour = "#e6d7df"
- stack_type = /obj/item/stack/material/quartz
- tableslam_noise = 'sound/effects/Glasshit.ogg'
- sheet_singular_name = "crystal"
- sheet_plural_name = "crystals"
- supply_conversion_value = 4
-
-/datum/material/aluminium
- name = "aluminium"
- display_name = "aluminium"
- use_name = "aluminium"
- icon_colour = "#e5e2d0"
- stack_type = /obj/item/stack/material/aluminium
- sheet_singular_name = "ingot"
- sheet_plural_name = "ingots"
- supply_conversion_value = 2
- weight = 10
diff --git a/code/modules/materials/materials/_materials.dm b/code/modules/materials/materials/_materials.dm
new file mode 100644
index 00000000000..1b6cabffd96
--- /dev/null
+++ b/code/modules/materials/materials/_materials.dm
@@ -0,0 +1,284 @@
+/*
+ MATERIAL DATUMS
+ This data is used by various parts of the game for basic physical properties and behaviors
+ of the metals/materials used for constructing many objects. Each var is commented and should be pretty
+ self-explanatory but the various object types may have their own documentation. ~Z
+
+ PATHS THAT USE DATUMS
+ turf/simulated/wall
+ obj/item/weapon/material
+ obj/structure/barricade
+ obj/item/stack/material
+ obj/structure/table
+
+ VALID ICONS
+ WALLS
+ stone
+ metal
+ solid
+ resin
+ ONLY WALLS
+ cult
+ hull
+ curvy
+ jaggy
+ brick
+ REINFORCEMENT
+ reinf_over
+ reinf_mesh
+ reinf_cult
+ reinf_metal
+ DOORS
+ stone
+ metal
+ resin
+ wood
+*/
+
+// Assoc list containing all material datums indexed by name.
+var/list/name_to_material
+
+//Returns the material the object is made of, if applicable.
+//Will we ever need to return more than one value here? Or should we just return the "dominant" material.
+/obj/proc/get_material()
+ return null
+
+//mostly for convenience
+/obj/proc/get_material_name()
+ var/datum/material/material = get_material()
+ if(material)
+ return material.name
+
+// Builds the datum list above.
+/proc/populate_material_list(force_remake=0)
+ if(name_to_material && !force_remake) return // Already set up!
+ name_to_material = list()
+ for(var/type in subtypesof(/datum/material))
+ var/datum/material/new_mineral = new type
+ if(!new_mineral.name)
+ continue
+ name_to_material[lowertext(new_mineral.name)] = new_mineral
+ return 1
+
+// Safety proc to make sure the material list exists before trying to grab from it.
+/proc/get_material_by_name(name)
+ if(!name_to_material)
+ populate_material_list()
+ return name_to_material[name]
+
+/proc/material_display_name(name)
+ var/datum/material/material = get_material_by_name(name)
+ if(material)
+ return material.display_name
+ return null
+
+// Material definition and procs follow.
+/datum/material
+ var/name // Unique name for use in indexing the list.
+ var/display_name // Prettier name for display.
+ var/use_name
+ var/flags = 0 // Various status modifiers.
+ var/sheet_singular_name = "sheet"
+ var/sheet_plural_name = "sheets"
+ var/is_fusion_fuel
+
+ // Shards/tables/structures
+ var/shard_type = SHARD_SHRAPNEL // Path of debris object.
+ var/shard_icon // Related to above.
+ var/shard_can_repair = 1 // Can shards be turned into sheets with a welder?
+ var/list/recipes // Holder for all recipes usable with a sheet of this material.
+ var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding.
+
+ // Icons
+ var/icon_colour // Colour applied to products of this material.
+ var/icon_base = "metal" // Wall and table base icon tag. See header.
+ var/door_icon_base = "metal" // Door base icon tag. See header.
+ var/icon_reinf = "reinf_metal" // Overlay used
+ var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks.
+ var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects?
+
+ // Attributes
+ var/cut_delay = 0 // Delay in ticks when cutting through this wall.
+ var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings.
+ var/ignition_point // K, point at which the material catches on fire.
+ var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this
+ var/integrity = 150 // General-use HP value for products.
+ var/protectiveness = 10 // How well this material works as armor. Higher numbers are better, diminishing returns applies.
+ var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors.
+ var/reflectivity = 0 // How reflective to light is the material? Currently used for laser reflection and defense.
+ var/explosion_resistance = 5 // Only used by walls currently.
+ var/negation = 0 // Objects that respect this will randomly absorb impacts with this var as the percent chance.
+ var/spatial_instability = 0 // Objects that have trouble staying in the same physical space by sheer laws of nature have this. Percent for respecting items to cause teleportation.
+ var/conductive = 1 // Objects without this var add NOCONDUCT to flags on spawn.
+ var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10.
+ var/list/composite_material // If set, object matter var will be a list containing these values.
+ var/luminescence
+ var/radiation_resistance = 0 // Radiation resistance, which is added on top of a material's weight for blocking radiation. Needed to make lead special without superrobust weapons.
+ var/supply_conversion_value // Supply points per sheet that this material sells for.
+
+ // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
+ var/created_window
+ var/created_fulltile_window
+ var/rod_product
+ var/wire_product
+ var/list/window_options = list()
+
+ // Damage values.
+ var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. Also used for bullet protection in armor.
+ var/weight = 20 // Determines blunt damage/throwforce for weapons.
+
+ // Noise when someone is faceplanted onto a table made of this material.
+ var/tableslam_noise = 'sound/weapons/tablehit1.ogg'
+ // Noise made when a simple door made of this material opens or closes.
+ var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg'
+ // Path to resulting stacktype. Todo remove need for this.
+ var/stack_type
+ // Wallrot crumble message.
+ var/rotting_touch_message = "crumbles under your touch"
+
+// Placeholders for light tiles and rglass.
+/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!rod_product)
+ to_chat(user, "You cannot make anything out of \the [target_stack]")
+ return
+ if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1)
+ to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.")
+ return
+ used_stack.use(1)
+ target_stack.use(1)
+ var/obj/item/stack/S = new rod_product(get_turf(user))
+ S.add_fingerprint(user)
+ S.add_to_stacks(user)
+
+/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!wire_product)
+ to_chat(user, "You cannot make anything out of \the [target_stack]")
+ return
+ if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1)
+ to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.")
+ return
+
+ used_stack.use(5)
+ target_stack.use(1)
+ to_chat(user, "You attach wire to the [name].")
+ var/obj/item/product = new wire_product(get_turf(user))
+ user.put_in_hands(product)
+
+// Make sure we have a display name and shard icon even if they aren't explicitly set.
+/datum/material/New()
+ ..()
+ if(!display_name)
+ display_name = name
+ if(!use_name)
+ use_name = display_name
+ if(!shard_icon)
+ shard_icon = shard_type
+
+// This is a placeholder for proper integration of windows/windoors into the system.
+/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+ return 0
+
+// Weapons handle applying a divisor for this value locally.
+/datum/material/proc/get_blunt_damage()
+ return weight //todo
+
+// Return the matter comprising this material.
+/datum/material/proc/get_matter()
+ var/list/temp_matter = list()
+ if(islist(composite_material))
+ for(var/material_string in composite_material)
+ temp_matter[material_string] = composite_material[material_string]
+ else if(SHEET_MATERIAL_AMOUNT)
+ temp_matter[name] = SHEET_MATERIAL_AMOUNT
+ return temp_matter
+
+// As above.
+/datum/material/proc/get_edge_damage()
+ return hardness //todo
+
+// Snowflakey, only checked for alien doors at the moment.
+/datum/material/proc/can_open_material_door(var/mob/living/user)
+ return 1
+
+// Currently used for weapons and objects made of uranium to irradiate things.
+/datum/material/proc/products_need_process()
+ return (radioactivity>0) //todo
+
+// Used by walls when qdel()ing to avoid neighbor merging.
+/datum/material/placeholder
+ name = "placeholder"
+
+// Places a girder object when a wall is dismantled, also applies reinforced material.
+/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material)
+ var/obj/structure/girder/G = new(target)
+ if(reinf_material)
+ G.reinf_material = reinf_material
+ G.reinforce_girder()
+ if(girder_material)
+ if(istype(girder_material, /datum/material))
+ girder_material = girder_material.name
+ G.set_material(girder_material)
+
+
+// General wall debris product placement.
+// Not particularly necessary aside from snowflakey cult girders.
+/datum/material/proc/place_dismantled_product(var/turf/target)
+ place_sheet(target)
+
+// Debris product. Used ALL THE TIME.
+/datum/material/proc/place_sheet(var/turf/target)
+ if(stack_type)
+ return new stack_type(target)
+
+// As above.
+/datum/material/proc/place_shard(var/turf/target)
+ if(shard_type)
+ return new /obj/item/weapon/material/shard(target, src.name)
+
+// Used by walls and weapons to determine if they break or not.
+/datum/material/proc/is_brittle()
+ return !!(flags & MATERIAL_BRITTLE)
+
+/datum/material/proc/combustion_effect(var/turf/T, var/temperature)
+ return
+
+// Used by walls to do on-touch things, after checking for crumbling and open-ability.
+/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+ return
+
+/datum/material/proc/get_recipes()
+ if(!recipes)
+ generate_recipes()
+ return recipes
+
+/datum/material/proc/generate_recipes()
+ // If is_brittle() returns true, these are only good for a single strike.
+ recipes = list(
+ new /datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate insert", /obj/item/weapon/material/armor_plating/insert, 2, time = 40, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
+
+ if(integrity>=50)
+ recipes += list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
+
+ if(hardness>50)
+ recipes += list(
+ new /datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/_materials_vr.dm b/code/modules/materials/materials/_materials_vr.dm
new file mode 100644
index 00000000000..8c91622fb35
--- /dev/null
+++ b/code/modules/materials/materials/_materials_vr.dm
@@ -0,0 +1,9 @@
+/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob)
+ if(M.handle_eat_minerals(src, user))
+ return
+ ..()
+
+/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent.
+ if(user.handle_eat_minerals(src))
+ return
+ ..()
diff --git a/code/modules/materials/materials/alien_alloy.dm b/code/modules/materials/materials/alien_alloy.dm
new file mode 100644
index 00000000000..741f0275b75
--- /dev/null
+++ b/code/modules/materials/materials/alien_alloy.dm
@@ -0,0 +1,36 @@
+// Adminspawn only, do not let anyone get this.
+/datum/material/alienalloy
+ name = "alienalloy"
+ display_name = "durable alloy"
+ stack_type = null
+ flags = MATERIAL_UNMELTABLE
+ icon_colour = "#6C7364"
+ integrity = 1200
+ melting_point = 6000 // Hull plating.
+ explosion_resistance = 200 // Hull plating.
+ hardness = 500
+ weight = 500
+ protectiveness = 80 // 80%
+
+/datum/material/alienalloy/elevatorium
+ name = "elevatorium"
+ display_name = "elevator panelling"
+ icon_colour = "#666666"
+
+/datum/material/alienalloy/dungeonium
+ name = "dungeonium"
+ display_name = "ultra-durable"
+ icon_base = "dungeon"
+ icon_colour = "#FFFFFF"
+
+/datum/material/alienalloy/bedrock
+ name = "bedrock"
+ display_name = "impassable rock"
+ icon_base = "rock"
+ icon_colour = "#FFFFFF"
+
+/datum/material/alienalloy/alium
+ name = "alium"
+ display_name = "alien"
+ icon_base = "alien"
+ icon_colour = "#FFFFFF"
\ No newline at end of file
diff --git a/code/modules/materials/materials/cult.dm b/code/modules/materials/materials/cult.dm
new file mode 100644
index 00000000000..7d8d4be9f2f
--- /dev/null
+++ b/code/modules/materials/materials/cult.dm
@@ -0,0 +1,23 @@
+/datum/material/cult
+ name = "cult"
+ display_name = "disturbing stone"
+ icon_base = "cult"
+ icon_colour = "#402821"
+ icon_reinf = "reinf_cult"
+ shard_type = SHARD_STONE_PIECE
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+ conductive = 0
+
+/datum/material/cult/place_dismantled_girder(var/turf/target)
+ new /obj/structure/girder/cult(target, "cult")
+
+/datum/material/cult/place_dismantled_product(var/turf/target)
+ new /obj/effect/decal/cleanable/blood(target)
+
+/datum/material/cult/reinf
+ name = "cult2"
+ display_name = "human remains"
+
+/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
+ new /obj/effect/decal/remains/human(target)
\ No newline at end of file
diff --git a/code/modules/materials/materials/gems.dm b/code/modules/materials/materials/gems.dm
new file mode 100644
index 00000000000..9ec22a86b13
--- /dev/null
+++ b/code/modules/materials/materials/gems.dm
@@ -0,0 +1,154 @@
+/datum/material/phoron
+ name = "phoron"
+ stack_type = /obj/item/stack/material/phoron
+ ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
+ icon_base = "stone"
+ icon_colour = "#FC2BC5"
+ shard_type = SHARD_SHARD
+ hardness = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2)
+ door_icon_base = "stone"
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ supply_conversion_value = 5
+
+/*
+// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately.
+/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier)
+ if(isnull(ignition_point))
+ return 0
+ if(temperature < ignition_point)
+ return 0
+ var/totalPhoron = 0
+ for(var/turf/simulated/floor/target_tile in range(2,T))
+ var/phoronToDeduce = (temperature/30) * effect_multiplier
+ totalPhoron += phoronToDeduce
+ target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C)
+ spawn (0)
+ target_tile.hotspot_expose(temperature, 400)
+ return round(totalPhoron/100)
+*/
+
+/datum/material/diamond
+ name = "diamond"
+ stack_type = /obj/item/stack/material/diamond
+ flags = MATERIAL_UNMELTABLE
+ cut_delay = 60
+ icon_colour = "#00FFE1"
+ opacity = 0.4
+ reflectivity = 0.6
+ conductive = 0
+ conductivity = 1
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 100
+ stack_origin_tech = list(TECH_MATERIAL = 6)
+ supply_conversion_value = 8
+
+/datum/material/quartz
+ name = "quartz"
+ display_name = "quartz"
+ use_name = "quartz"
+ icon_colour = "#e6d7df"
+ stack_type = /obj/item/stack/material/quartz
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ supply_conversion_value = 4
+
+/datum/material/painite
+ name = "painite"
+ display_name = "painite"
+ use_name = "painite"
+ icon_colour = "#6b4947"
+ stack_type = /obj/item/stack/material/painite
+ flags = MATERIAL_UNMELTABLE
+ reflectivity = 0.3
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+ supply_conversion_value = 4
+
+/datum/material/void_opal
+ name = "void opal"
+ display_name = "void opal"
+ use_name = "void opal"
+ icon_colour = "#0f0f0f"
+ stack_type = /obj/item/stack/material/void_opal
+ flags = MATERIAL_UNMELTABLE
+ cut_delay = 60
+ reflectivity = 0
+ conductivity = 1
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 100
+ stack_origin_tech = list(TECH_ARCANE = 1, TECH_MATERIAL = 6)
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+ supply_conversion_value = 30 // These are hilariously rare.
+
+// Particle Smasher and other exotic materials.
+/datum/material/valhollide
+ name = MAT_VALHOLLIDE
+ stack_type = /obj/item/stack/material/valhollide
+ icon_base = "stone"
+ door_icon_base = "stone"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "##FFF3B2"
+ protectiveness = 30
+ integrity = 240
+ weight = 30
+ hardness = 45
+ negation = 2
+ conductive = 0
+ conductivity = 5
+ reflectivity = 0.5
+ radiation_resistance = 20
+ spatial_instability = 30
+ stack_origin_tech = list(TECH_MATERIAL = 7, TECH_PHORON = 5, TECH_BLUESPACE = 5)
+ sheet_singular_name = "gem"
+ sheet_plural_name = "gems"
+
+/datum/material/verdantium
+ name = MAT_VERDANTIUM
+ stack_type = /obj/item/stack/material/verdantium
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_reinf = "reinf_metal"
+ icon_colour = "#4FE95A"
+ integrity = 80
+ protectiveness = 15
+ weight = 15
+ hardness = 30
+ shard_type = SHARD_SHARD
+ negation = 15
+ conductivity = 60
+ reflectivity = 0.3
+ radiation_resistance = 5
+ stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 5, TECH_BIO = 4)
+ sheet_singular_name = "sheet"
+ sheet_plural_name = "sheets"
+ supply_conversion_value = 8
+
+/datum/material/morphium
+ name = MAT_MORPHIUM
+ stack_type = /obj/item/stack/material/morphium
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_colour = "#37115A"
+ icon_reinf = "reinf_metal"
+ protectiveness = 60
+ integrity = 300
+ conductive = 0
+ conductivity = 1.5
+ hardness = 90
+ shard_type = SHARD_SHARD
+ weight = 30
+ negation = 25
+ explosion_resistance = 85
+ reflectivity = 0.2
+ radiation_resistance = 10
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1)
+ supply_conversion_value = 13
+
+
diff --git a/code/modules/materials/materials/glass.dm b/code/modules/materials/materials/glass.dm
new file mode 100644
index 00000000000..79535422785
--- /dev/null
+++ b/code/modules/materials/materials/glass.dm
@@ -0,0 +1,143 @@
+/datum/material/glass
+ name = "glass"
+ stack_type = /obj/item/stack/material/glass
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#00E1FF"
+ opacity = 0.3
+ integrity = 100
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 30
+ weight = 15
+ protectiveness = 0 // 0%
+ conductive = 0
+ conductivity = 1 // Glass shards don't conduct.
+ door_icon_base = "stone"
+ destruction_desc = "shatters"
+ window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
+ created_window = /obj/structure/window/basic
+ created_fulltile_window = /obj/structure/window/basic/full
+ rod_product = /obj/item/stack/material/glass/reinforced
+
+/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+
+ if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len)
+ return 0
+
+ if(!user.IsAdvancedToolUser())
+ to_chat(user, "This task is too complex for your clumsy hands.")
+ return 1
+
+ var/turf/T = user.loc
+ if(!istype(T))
+ to_chat(user, "You must be standing on open flooring to build a window.")
+ return 1
+
+ var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)"
+ var/choice = input(title, "What would you like to construct?") as null|anything in window_options
+
+ if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T)
+ return 1
+
+ // Get data for building windows here.
+ var/list/possible_directions = cardinal.Copy()
+ var/window_count = 0
+ for (var/obj/structure/window/check_window in user.loc)
+ window_count++
+ possible_directions -= check_window.dir
+ for (var/obj/structure/windoor_assembly/check_assembly in user.loc)
+ window_count++
+ possible_directions -= check_assembly.dir
+ for (var/obj/machinery/door/window/check_windoor in user.loc)
+ window_count++
+ possible_directions -= check_windoor.dir
+
+ // Get the closest available dir to the user's current facing.
+ var/build_dir = SOUTHWEST //Default to southwest for fulltile windows.
+ var/failed_to_build
+
+ if(window_count >= 4)
+ failed_to_build = 1
+ else
+ if(choice in list("One Direction","Windoor"))
+ if(possible_directions.len)
+ for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,270), turn(user.dir,180)))
+ if(direction in possible_directions)
+ build_dir = direction
+ break
+ else
+ failed_to_build = 1
+ if(failed_to_build)
+ to_chat(user, "There is no room in this location.")
+ return 1
+
+ var/build_path = /obj/structure/windoor_assembly
+ var/sheets_needed = window_options[choice]
+ if(choice == "Windoor")
+ if(is_reinforced())
+ build_path = /obj/structure/windoor_assembly/secure
+ else if(choice == "Full Window")
+ build_path = created_fulltile_window
+ else
+ build_path = created_window
+
+ if(used_stack.get_amount() < sheets_needed)
+ to_chat(user, "You need at least [sheets_needed] sheets to build this.")
+ return 1
+
+ // Build the structure and update sheet count etc.
+ used_stack.use(sheets_needed)
+ new build_path(T, build_dir, 1)
+ return 1
+
+/datum/material/glass/proc/is_reinforced()
+ return (hardness > 35) //todo
+
+/datum/material/glass/reinforced
+ name = "rglass"
+ display_name = "reinforced glass"
+ stack_type = /obj/item/stack/material/glass/reinforced
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#00E1FF"
+ opacity = 0.3
+ integrity = 100
+ shard_type = SHARD_SHARD
+ tableslam_noise = 'sound/effects/Glasshit.ogg'
+ hardness = 40
+ weight = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "glass" = SHEET_MATERIAL_AMOUNT)
+ window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2)
+ created_window = /obj/structure/window/reinforced
+ created_fulltile_window = /obj/structure/window/reinforced/full
+ wire_product = null
+ rod_product = null
+
+/datum/material/glass/phoron
+ name = "borosilicate glass"
+ display_name = "borosilicate glass"
+ stack_type = /obj/item/stack/material/glass/phoronglass
+ flags = MATERIAL_BRITTLE
+ integrity = 100
+ icon_colour = "#FC2BC5"
+ stack_origin_tech = list(TECH_MATERIAL = 4)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/phoronbasic
+ created_fulltile_window = /obj/structure/window/phoronbasic/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/phoronrglass
+
+/datum/material/glass/phoron/reinforced
+ name = "reinforced borosilicate glass"
+ display_name = "reinforced borosilicate glass"
+ stack_type = /obj/item/stack/material/glass/phoronrglass
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ composite_material = list() //todo
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/phoronreinforced
+ created_fulltile_window = /obj/structure/window/phoronreinforced/full
+ hardness = 40
+ weight = 30
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "borosilicate glass" = SHEET_MATERIAL_AMOUNT)
+ rod_product = null
diff --git a/code/modules/materials/materials/glass_vr.dm b/code/modules/materials/materials/glass_vr.dm
new file mode 100644
index 00000000000..9d7cd818796
--- /dev/null
+++ b/code/modules/materials/materials/glass_vr.dm
@@ -0,0 +1,33 @@
+/datum/material/glass/titaniumglass
+ name = MAT_TITANIUMGLASS
+ display_name = "titanium glass"
+ stack_type = /obj/item/stack/material/glass/titanium
+ integrity = 150
+ hardness = 50
+ weight = 50
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#A7A3A6"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/titanium
+ created_fulltile_window = /obj/structure/window/titanium/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/titanium
+ composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
+
+/datum/material/glass/plastaniumglass
+ name = MAT_PLASTITANIUMGLASS
+ display_name = "plas-titanium glass"
+ stack_type = /obj/item/stack/material/glass/plastitanium
+ integrity = 200
+ hardness = 60
+ weight = 80
+ flags = MATERIAL_BRITTLE
+ icon_colour = "#676366"
+ stack_origin_tech = list(TECH_MATERIAL = 6)
+ window_options = list("One Direction" = 1, "Full Window" = 4)
+ created_window = /obj/structure/window/plastitanium
+ created_fulltile_window = /obj/structure/window/plastitanium/full
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/plastitanium
+ composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
diff --git a/code/modules/materials/materials/holographic.dm b/code/modules/materials/materials/holographic.dm
new file mode 100644
index 00000000000..ff6474ec1e7
--- /dev/null
+++ b/code/modules/materials/materials/holographic.dm
@@ -0,0 +1,17 @@
+/datum/material/steel/holographic
+ name = "holo" + DEFAULT_WALL_MATERIAL
+ display_name = DEFAULT_WALL_MATERIAL
+ stack_type = null
+ shard_type = SHARD_NONE
+
+/datum/material/plastic/holographic
+ name = "holoplastic"
+ display_name = "plastic"
+ stack_type = null
+ shard_type = SHARD_NONE
+
+/datum/material/wood/holographic
+ name = "holowood"
+ display_name = "wood"
+ stack_type = null
+ shard_type = SHARD_NONE
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/hull.dm b/code/modules/materials/materials/metals/hull.dm
new file mode 100644
index 00000000000..caf8f13de74
--- /dev/null
+++ b/code/modules/materials/materials/metals/hull.dm
@@ -0,0 +1,53 @@
+/datum/material/steel/hull
+ name = MAT_STEELHULL
+ stack_type = /obj/item/stack/material/steel/hull
+ integrity = 250
+ explosion_resistance = 10
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#666677"
+
+/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets.
+ new /obj/item/stack/material/steel(target)
+
+/datum/material/plasteel/hull
+ name = MAT_PLASTEELHULL
+ stack_type = /obj/item/stack/material/plasteel/hull
+ integrity = 600
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#777788"
+ explosion_resistance = 40
+
+/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+ new /obj/item/stack/material/plasteel(target)
+
+/datum/material/durasteel/hull //The 'Hardball' of starship hulls.
+ name = MAT_DURASTEELHULL
+ stack_type = /obj/item/stack/material/durasteel/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#45829a"
+ explosion_resistance = 90
+ reflectivity = 0.9
+
+/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets.
+ new /obj/item/stack/material/durasteel(target)
+
+/datum/material/titanium/hull
+ name = MAT_TITANIUMHULL
+ stack_type = /obj/item/stack/material/titanium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+
+/datum/material/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
+ new /obj/item/stack/material/titanium(target)
+
+/datum/material/morphium/hull
+ name = MAT_MORPHIUMHULL
+ stack_type = /obj/item/stack/material/morphium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+
+/datum/material/morphium/hull/place_sheet(var/turf/target)
+ new /obj/item/stack/material/morphium(target)
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/hull_vr.dm b/code/modules/materials/materials/metals/hull_vr.dm
new file mode 100644
index 00000000000..3c35b3cf398
--- /dev/null
+++ b/code/modules/materials/materials/metals/hull_vr.dm
@@ -0,0 +1,20 @@
+/datum/material/plastitanium/hull
+ name = MAT_PLASTITANIUMHULL
+ stack_type = /obj/item/stack/material/plastitanium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#585658"
+ explosion_resistance = 50
+
+/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+ new /obj/item/stack/material/plastitanium(target)
+
+/datum/material/gold/hull
+ name = MAT_GOLDHULL
+ stack_type = /obj/item/stack/material/gold/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ explosion_resistance = 50
+
+/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal gold sheets.
+ new /obj/item/stack/material/gold(target)
diff --git a/code/modules/materials/materials/metals/metals.dm b/code/modules/materials/materials/metals/metals.dm
new file mode 100644
index 00000000000..a36ffef5c1c
--- /dev/null
+++ b/code/modules/materials/materials/metals/metals.dm
@@ -0,0 +1,199 @@
+
+
+
+
+// Very rare alloy that is reflective, should be used sparingly.
+/datum/material/durasteel
+ name = "durasteel"
+ stack_type = /obj/item/stack/material/durasteel
+ integrity = 600
+ melting_point = 7000
+ icon_base = "metal"
+ icon_reinf = "reinf_metal"
+ icon_colour = "#6EA7BE"
+ explosion_resistance = 75
+ hardness = 100
+ weight = 28
+ protectiveness = 60 // 75%
+ reflectivity = 0.7 // Not a perfect mirror, but close.
+ stack_origin_tech = list(TECH_MATERIAL = 8)
+ composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug
+ supply_conversion_value = 9
+
+/datum/material/titanium
+ name = MAT_TITANIUM
+ stack_type = /obj/item/stack/material/titanium
+ conductivity = 2.38
+ icon_base = "metal"
+ door_icon_base = "metal"
+ icon_colour = "#D1E6E3"
+ icon_reinf = "reinf_metal"
+ composite_material = null
+
+/datum/material/iron
+ name = "iron"
+ stack_type = /obj/item/stack/material/iron
+ icon_colour = "#5C5454"
+ weight = 22
+ conductivity = 10
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+
+/datum/material/lead
+ name = MAT_LEAD
+ stack_type = /obj/item/stack/material/lead
+ icon_colour = "#273956"
+ weight = 23 // Lead is a bit more dense than silver IRL, and silver has 22 ingame.
+ conductivity = 10
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ radiation_resistance = 25 // Lead is Special and so gets to block more radiation than it normally would with just weight, totalling in 48 protection.
+ supply_conversion_value = 2
+
+/datum/material/gold
+ name = "gold"
+ stack_type = /obj/item/stack/material/gold
+ icon_colour = "#EDD12F"
+ weight = 24
+ hardness = 40
+ conductivity = 41
+ stack_origin_tech = list(TECH_MATERIAL = 4)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+
+/datum/material/silver
+ name = "silver"
+ stack_type = /obj/item/stack/material/silver
+ icon_colour = "#D1E6E3"
+ weight = 22
+ hardness = 50
+ conductivity = 63
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+
+/datum/material/platinum
+ name = "platinum"
+ stack_type = /obj/item/stack/material/platinum
+ icon_colour = "#9999FF"
+ weight = 27
+ conductivity = 9.43
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 5
+
+/datum/material/uranium
+ name = "uranium"
+ stack_type = /obj/item/stack/material/uranium
+ radioactivity = 12
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#007A00"
+ weight = 22
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ door_icon_base = "stone"
+ supply_conversion_value = 2
+
+/datum/material/mhydrogen
+ name = "mhydrogen"
+ stack_type = /obj/item/stack/material/mhydrogen
+ icon_colour = "#E6C5DE"
+ stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5)
+ conductivity = 100
+ is_fusion_fuel = 1
+ supply_conversion_value = 6
+
+/datum/material/deuterium
+ name = "deuterium"
+ stack_type = /obj/item/stack/material/deuterium
+ icon_colour = "#999999"
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ is_fusion_fuel = 1
+ conductive = 0
+
+/datum/material/tritium
+ name = "tritium"
+ stack_type = /obj/item/stack/material/tritium
+ icon_colour = "#777777"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ is_fusion_fuel = 1
+ conductive = 0
+
+/datum/material/osmium
+ name = "osmium"
+ stack_type = /obj/item/stack/material/osmium
+ icon_colour = "#9999FF"
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ conductivity = 100
+ supply_conversion_value = 6
+
+/datum/material/graphite
+ name = MAT_GRAPHITE
+ stack_type = /obj/item/stack/material/graphite
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#333333"
+ hardness = 75
+ weight = 15
+ integrity = 175
+ protectiveness = 15
+ conductivity = 18
+ melting_point = T0C+3600
+ radiation_resistance = 15
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2)
+
+/datum/material/bronze
+ name = "bronze"
+ stack_type = /obj/item/stack/material/bronze
+ icon_colour = "#EDD12F"
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ integrity = 120
+ conductivity = 12
+ protectiveness = 9 // 33%
+
+/datum/material/tin
+ name = "tin"
+ display_name = "tin"
+ use_name = "tin"
+ stack_type = /obj/item/stack/material/tin
+ icon_colour = "#b2afaf"
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 1
+ hardness = 50
+ weight = 13
+
+/datum/material/copper
+ name = "copper"
+ display_name = "copper"
+ use_name = "copper"
+ stack_type = /obj/item/stack/material/copper
+ conductivity = 52
+ icon_colour = "#af633e"
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 1
+ weight = 13
+ hardness = 50
+
+/datum/material/aluminium
+ name = "aluminium"
+ display_name = "aluminium"
+ use_name = "aluminium"
+ icon_colour = "#e5e2d0"
+ stack_type = /obj/item/stack/material/aluminium
+ sheet_singular_name = "ingot"
+ sheet_plural_name = "ingots"
+ supply_conversion_value = 2
+ weight = 10
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/metals_vr.dm b/code/modules/materials/materials/metals/metals_vr.dm
new file mode 100644
index 00000000000..f600b2fe025
--- /dev/null
+++ b/code/modules/materials/materials/metals/metals_vr.dm
@@ -0,0 +1,6 @@
+/datum/material/durasteel/generate_recipes()
+ . = ..()
+ recipes += list(
+ new /datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2),
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30),
+ )
diff --git a/code/modules/materials/materials/metals/plasteel.dm b/code/modules/materials/materials/metals/plasteel.dm
new file mode 100644
index 00000000000..6fc7ed29dec
--- /dev/null
+++ b/code/modules/materials/materials/metals/plasteel.dm
@@ -0,0 +1,27 @@
+/datum/material/plasteel
+ name = "plasteel"
+ stack_type = /obj/item/stack/material/plasteel
+ integrity = 400
+ melting_point = 6000
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#777777"
+ explosion_resistance = 25
+ hardness = 80
+ weight = 23
+ protectiveness = 20 // 50%
+ conductivity = 13 // For the purposes of balance.
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo
+ supply_conversion_value = 6
+
+/datum/material/plasteel/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/plasteel_vr.dm b/code/modules/materials/materials/metals/plasteel_vr.dm
new file mode 100644
index 00000000000..bca3fdf27b8
--- /dev/null
+++ b/code/modules/materials/materials/metals/plasteel_vr.dm
@@ -0,0 +1,22 @@
+/datum/material/plastitanium
+ name = MAT_PLASTITANIUM
+ stack_type = /obj/item/stack/material/plastitanium
+ integrity = 600
+ melting_point = 9000
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#585658"
+ explosion_resistance = 35
+ hardness = 90
+ weight = 40
+ protectiveness = 30
+ conductivity = 7
+ stack_origin_tech = list(TECH_MATERIAL = 5)
+ composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT)
+ supply_conversion_value = 8
+
+/datum/material/plastitanium/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20),
+ )
diff --git a/code/modules/materials/materials/metals/steel.dm b/code/modules/materials/materials/metals/steel.dm
new file mode 100644
index 00000000000..ca323c81374
--- /dev/null
+++ b/code/modules/materials/materials/metals/steel.dm
@@ -0,0 +1,87 @@
+/datum/material/steel
+ name = DEFAULT_WALL_MATERIAL
+ stack_type = /obj/item/stack/material/steel
+ integrity = 150
+ conductivity = 11 // Assuming this is carbon steel, it would actually be slightly less conductive than iron, but lets ignore that.
+ protectiveness = 10 // 33%
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#666666"
+
+/datum/material/steel/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe_list("office chairs",list(
+ new /datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
+ )),
+ new /datum/stack_recipe_list("comfy chairs", list(
+ new /datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("yellow comfy chair", /obj/structure/bed/chair/comfy/yellow, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("orange comfy chair", /obj/structure/bed/chair/comfy/orange, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe_list("airlock assemblies", list(
+ new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("eng atmos airlock assembly", /obj/structure/door_assembly/door_assembly_eat, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe_list("modular computer frames", list(
+ new /datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10, recycle_material = "[name]"),\
+ new /datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5, recycle_material = "[name]"),\
+ )),
+ new /datum/stack_recipe_list("filing cabinets", list(
+ new /datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("tall filing cabinet", /obj/structure/filingcabinet/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("chest drawer", /obj/structure/filingcabinet/chestdrawer, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ )),
+ new /datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]"),
+ new /datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]"),
+ new /datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ //new /datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Removal
+ new /datum/stack_recipe("medical stand", /obj/structure/medical_stand, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Replacement,
+ new /datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]"),
+ new /datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]"),
+ new /datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/metals/steel_vr.dm b/code/modules/materials/materials/metals/steel_vr.dm
new file mode 100644
index 00000000000..b112f362171
--- /dev/null
+++ b/code/modules/materials/materials/metals/steel_vr.dm
@@ -0,0 +1,82 @@
+/datum/material/steel/generate_recipes()
+ . = ..()
+ recipes += list(
+ new /datum/stack_recipe_list("mounted chairs",list(
+ new /datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10)
+ )),
+ new /datum/stack_recipe_list("mounted comfy chairs",list(
+ new /datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20)
+ )),
+ new /datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10),
+ new /datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20),
+ new /datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2),
+ new /datum/stack_recipe_list("sofas",list(
+ new /datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \
+ new /datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \
+ )),
+ )
diff --git a/code/modules/materials/materials/organic/animal_products.dm b/code/modules/materials/materials/organic/animal_products.dm
new file mode 100644
index 00000000000..592cc6bc7bb
--- /dev/null
+++ b/code/modules/materials/materials/organic/animal_products.dm
@@ -0,0 +1,28 @@
+/datum/material/diona
+ name = "biomass"
+ icon_colour = null
+ stack_type = null
+ integrity = 600
+ icon_base = "diona"
+ icon_reinf = "noreinf"
+
+/datum/material/diona/place_dismantled_product()
+ return
+
+/datum/material/diona/place_dismantled_girder(var/turf/target)
+ spawn_diona_nymph(target)
+
+/datum/material/chitin
+ name = MAT_CHITIN
+ icon_colour = "#8d6653"
+ stack_type = /obj/item/stack/material/chitin
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4)
+ icon_base = "solid"
+ icon_reinf = "reinf_mesh"
+ integrity = 60
+ weight = 10
+ ignition_point = T0C+400
+ melting_point = T0C+500
+ protectiveness = 20
+ conductive = 0
+ supply_conversion_value = 4
diff --git a/code/modules/materials/materials/organic/cloth.dm b/code/modules/materials/materials/organic/cloth.dm
new file mode 100644
index 00000000000..588a7ad86fb
--- /dev/null
+++ b/code/modules/materials/materials/organic/cloth.dm
@@ -0,0 +1,121 @@
+/datum/material/cloth
+ name = "cloth"
+ stack_origin_tech = list(TECH_MATERIAL = 2)
+ door_icon_base = "wood"
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ protectiveness = 1 // 4%
+ flags = MATERIAL_PADDING
+ conductive = 0
+ integrity = 40
+ pass_stack_colors = TRUE
+ supply_conversion_value = 2
+
+/datum/material/cloth/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"),
+ new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+ )
+
+/datum/material/cloth/syncloth
+ name = "syncloth"
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2)
+ ignition_point = T0C+532
+ melting_point = T0C+600
+ integrity = 200
+ protectiveness = 15 // 4%
+ pass_stack_colors = TRUE
+ supply_conversion_value = 3
+
+/datum/material/cloth/teal
+ name = "teal"
+ display_name ="teal"
+ use_name = "teal cloth"
+ icon_colour = "#00EAFA"
+
+/datum/material/cloth/black
+ name = "black"
+ display_name = "black"
+ use_name = "black cloth"
+ icon_colour = "#505050"
+
+/datum/material/cloth/green
+ name = "green"
+ display_name = "green"
+ use_name = "green cloth"
+ icon_colour = "#01C608"
+
+/datum/material/cloth/puple
+ name = "purple"
+ display_name = "purple"
+ use_name = "purple cloth"
+ icon_colour = "#9C56C4"
+
+/datum/material/cloth/blue
+ name = "blue"
+ display_name = "blue"
+ use_name = "blue cloth"
+ icon_colour = "#6B6FE3"
+
+/datum/material/cloth/beige
+ name = "beige"
+ display_name = "beige"
+ use_name = "beige cloth"
+ icon_colour = "#E8E7C8"
+
+/datum/material/cloth/lime
+ name = "lime"
+ display_name = "lime"
+ use_name = "lime cloth"
+ icon_colour = "#62E36C"
+
+/datum/material/cloth/yellow
+ name = "yellow"
+ display_name = "yellow"
+ use_name = "yellow cloth"
+ icon_colour = "#EEF573"
+
+/datum/material/cloth/orange
+ name = "orange"
+ display_name = "orange"
+ use_name = "orange cloth"
+ icon_colour = "#E3BF49"
+
+
+
+/datum/material/carpet
+ name = "carpet"
+ display_name = "comfy"
+ use_name = "red upholstery"
+ icon_colour = "#DA020A"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ sheet_singular_name = "tile"
+ sheet_plural_name = "tiles"
+ protectiveness = 1 // 4%
+ conductive = 0
+
+/datum/material/cotton
+ name = "cotton"
+ display_name ="cotton"
+ icon_colour = "#FFFFFF"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ protectiveness = 1 // 4%
+ conductive = 0
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/leather.dm b/code/modules/materials/materials/organic/leather.dm
new file mode 100644
index 00000000000..f5fc8cb2f97
--- /dev/null
+++ b/code/modules/materials/materials/organic/leather.dm
@@ -0,0 +1,37 @@
+/datum/material/leather
+ name = MAT_LEATHER
+ display_name = "plainleather"
+ icon_colour = "#5C4831"
+ stack_type = /obj/item/stack/material/leather
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+300
+ melting_point = T0C+300
+ protectiveness = 3 // 13%
+ conductive = 0
+ integrity = 40
+ supply_conversion_value = 3
+
+/datum/material/leather/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"),
+ new /datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/resin.dm b/code/modules/materials/materials/organic/resin.dm
new file mode 100644
index 00000000000..a42735627aa
--- /dev/null
+++ b/code/modules/materials/materials/organic/resin.dm
@@ -0,0 +1,45 @@
+/datum/material/resin
+ name = "resin"
+ icon_colour = "#35343a"
+ icon_base = "resin"
+ dooropen_noise = 'sound/effects/attackblob.ogg'
+ door_icon_base = "resin"
+ icon_reinf = "reinf_mesh"
+ melting_point = T0C+300
+ sheet_singular_name = "blob"
+ sheet_plural_name = "blobs"
+ conductive = 0
+ explosion_resistance = 60
+ radiation_resistance = 10
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7)
+ stack_type = /obj/item/stack/material/resin
+
+/datum/material/resin/can_open_material_door(var/mob/living/user)
+ var/mob/living/carbon/M = user
+ if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
+ return TRUE
+ return FALSE
+
+/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+ var/mob/living/carbon/M = L
+ if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
+ to_chat(M, "\The [W] shudders under your touch, starting to become porous.")
+ playsound(W, 'sound/effects/attackblob.ogg', 50, 1)
+ if(do_after(L, 5 SECONDS))
+ spawn(2)
+ playsound(W, 'sound/effects/attackblob.ogg', 100, 1)
+ W.dismantle_wall()
+ return TRUE
+ return FALSE
+
+/datum/material/resin/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] nest", /obj/structure/bed/nest, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder/resin, 2, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/organic/wood.dm b/code/modules/materials/materials/organic/wood.dm
new file mode 100644
index 00000000000..ecdad547ca5
--- /dev/null
+++ b/code/modules/materials/materials/organic/wood.dm
@@ -0,0 +1,84 @@
+/datum/material/wood
+ name = MAT_WOOD
+ stack_type = /obj/item/stack/material/wood
+ icon_colour = "#9c5930"
+ integrity = 50
+ icon_base = "wood"
+ explosion_resistance = 2
+ shard_type = SHARD_SPLINTER
+ shard_can_repair = 0 // you can't weld splinters back into planks
+ hardness = 15
+ weight = 18
+ protectiveness = 8 // 28%
+ conductive = 0
+ conductivity = 1
+ melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood
+ ignition_point = T0C+288
+ stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1)
+ dooropen_noise = 'sound/effects/doorcreaky.ogg'
+ door_icon_base = "wood"
+ destruction_desc = "splinters"
+ sheet_singular_name = "plank"
+ sheet_plural_name = "planks"
+
+/datum/material/wood/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), //VOREStation Add
+ new /datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]"),
+ new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]")
+ )
+
+/datum/material/wood/sif
+ name = MAT_SIFWOOD
+ stack_type = /obj/item/stack/material/wood/sif
+ icon_colour = "#0099cc" // Cyan-ish
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
+
+/datum/material/wood/sif/generate_recipes()
+ ..()
+ recipes += new /datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE)
+ for(var/datum/stack_recipe/r_recipe in recipes)
+ if(r_recipe.title == "wood floor tile")
+ recipes -= r_recipe
+ continue
+ if(r_recipe.title == "wooden chair")
+ recipes -= r_recipe
+ continue
+
+/datum/material/wood/log
+ name = MAT_LOG
+ icon_base = "log"
+ stack_type = /obj/item/stack/material/log
+ sheet_singular_name = null
+ sheet_plural_name = "pile"
+ pass_stack_colors = TRUE
+ supply_conversion_value = 1
+
+/datum/material/wood/log/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]")
+ )
+
+/datum/material/wood/log/sif
+ name = MAT_SIFLOG
+ icon_colour = "#0099cc" // Cyan-ish
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
+ stack_type = /obj/item/stack/material/log/sif
\ No newline at end of file
diff --git a/code/modules/materials/materials/other_vr.dm b/code/modules/materials/materials/other_vr.dm
new file mode 100644
index 00000000000..d54dd4f726e
--- /dev/null
+++ b/code/modules/materials/materials/other_vr.dm
@@ -0,0 +1,32 @@
+/datum/material/flesh
+ name = "flesh"
+ display_name = "chunk of flesh"
+ icon_colour = "#dd90aa"
+ sheet_singular_name = "meat"
+ sheet_plural_name = "meats"
+ integrity = 1200
+ melting_point = 6000
+ explosion_resistance = 200
+ hardness = 500
+ weight = 500
+
+/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
+ name = " "
+ display_name = ""
+ icon_colour = "#000000"
+ sheet_singular_name = "fluff"
+ sheet_plural_name = "fluffs"
+ hardness = 60
+ weight = 20 //Strong as iron.
+
+/datum/material/darkglass
+ name = "darkglass"
+ display_name = "darkglass"
+ icon_base = "darkglass"
+ icon_colour = "#FFFFFF"
+
+/datum/material/fancyblack
+ name = "fancyblack"
+ display_name = "fancyblack"
+ icon_base = "fancyblack"
+ icon_colour = "#FFFFFF"
diff --git a/code/modules/materials/materials/plastic.dm b/code/modules/materials/materials/plastic.dm
new file mode 100644
index 00000000000..6cf45fe677e
--- /dev/null
+++ b/code/modules/materials/materials/plastic.dm
@@ -0,0 +1,88 @@
+/datum/material/plastic
+ name = "plastic"
+ stack_type = /obj/item/stack/material/plastic
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#CCCCCC"
+ hardness = 10
+ weight = 12
+ protectiveness = 5 // 20%
+ conductive = 0
+ conductivity = 2 // For the sake of material armor diversity, we're gonna pretend this plastic is a good insulator.
+ melting_point = T0C+371 //assuming heat resistant plastic
+ stack_origin_tech = list(TECH_MATERIAL = 3)
+
+/datum/material/plastic/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 500u
+ new /datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 250u
+ new /datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 100u
+ new /datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]"),
+ new /datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
+ )
+
+/datum/material/cardboard
+ name = "cardboard"
+ stack_type = /obj/item/stack/material/cardboard
+ flags = MATERIAL_BRITTLE
+ integrity = 10
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#AAAAAA"
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ conductive = 0
+ ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough
+ melting_point = T0C+232 //temperature at which cardboard walls would be destroyed
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ door_icon_base = "wood"
+ destruction_desc = "crumples"
+ radiation_resistance = 1
+ pass_stack_colors = TRUE
+
+/datum/material/cardboard/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]"),
+ new /datum/stack_recipe_list("folders",list(
+ new /datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue, recycle_material = "[name]"),
+ new /datum/stack_recipe("grey folder", /obj/item/weapon/folder, recycle_material = "[name]"),
+ new /datum/stack_recipe("red folder", /obj/item/weapon/folder/red, recycle_material = "[name]"),
+ new /datum/stack_recipe("white folder", /obj/item/weapon/folder/white, recycle_material = "[name]"),
+ new /datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow, recycle_material = "[name]")
+ ))
+ )
+
+/datum/material/toy_foam
+ name = "foam"
+ display_name = "foam"
+ use_name = "foam"
+ flags = MATERIAL_PADDING
+ ignition_point = T0C+232
+ melting_point = T0C+300
+ icon_colour = "#ff9900"
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ conductive = 0
\ No newline at end of file
diff --git a/code/modules/materials/materials/snow.dm b/code/modules/materials/materials/snow.dm
new file mode 100644
index 00000000000..bd535798118
--- /dev/null
+++ b/code/modules/materials/materials/snow.dm
@@ -0,0 +1,56 @@
+/datum/material/snow
+ name = MAT_SNOW
+ stack_type = /obj/item/stack/material/snow
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#FFFFFF"
+ integrity = 1
+ hardness = 1
+ weight = 1
+ protectiveness = 0 // 0%
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumples"
+ sheet_singular_name = "pile"
+ sheet_plural_name = "pile" //Just a bigger pile
+ radiation_resistance = 1
+
+/datum/material/snow/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]")
+ )
+
+/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly
+ name = "packed snow"
+ flags = MATERIAL_BRITTLE
+ stack_type = /obj/item/stack/material/snowbrick
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#D8FDFF"
+ integrity = 50
+ weight = 2
+ hardness = 2
+ protectiveness = 0 // 0%
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumbles"
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+ radiation_resistance = 1
+
+/datum/material/snowbrick/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"),
+ new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/stone.dm b/code/modules/materials/materials/stone.dm
new file mode 100644
index 00000000000..823dd19914c
--- /dev/null
+++ b/code/modules/materials/materials/stone.dm
@@ -0,0 +1,35 @@
+/datum/material/stone
+ name = "sandstone"
+ stack_type = /obj/item/stack/material/sandstone
+ icon_base = "stone"
+ icon_reinf = "reinf_stone"
+ icon_colour = "#D9C179"
+ shard_type = SHARD_STONE_PIECE
+ weight = 22
+ hardness = 55
+ protectiveness = 5 // 20%
+ conductive = 0
+ conductivity = 5
+ door_icon_base = "stone"
+ sheet_singular_name = "brick"
+ sheet_plural_name = "bricks"
+
+/datum/material/stone/generate_recipes()
+ ..()
+ recipes += new /datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")
+
+/datum/material/stone/marble
+ name = "marble"
+ icon_colour = "#AAAAAA"
+ weight = 26
+ hardness = 30 //VOREStation Edit - Please.
+ integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system
+ stack_type = /obj/item/stack/material/marble
+ supply_conversion_value = 2
+
+/datum/material/stone/marble/generate_recipes()
+ ..()
+ recipes += list(
+ new /datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]"),
+ new /datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials/supermatter.dm b/code/modules/materials/materials/supermatter.dm
new file mode 100644
index 00000000000..5ee3b34671c
--- /dev/null
+++ b/code/modules/materials/materials/supermatter.dm
@@ -0,0 +1,23 @@
+//R-UST port
+/datum/material/supermatter
+ name = "supermatter"
+ icon_colour = "#FFFF00"
+ stack_type = /obj/item/stack/material/supermatter
+ shard_type = SHARD_SHARD
+ radioactivity = 20
+ stack_type = null
+ luminescence = 3
+ ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
+ icon_base = "stone"
+ shard_type = SHARD_SHARD
+ hardness = 30
+ door_icon_base = "stone"
+ sheet_singular_name = "crystal"
+ sheet_plural_name = "crystals"
+ is_fusion_fuel = 1
+ stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4)
+
+/datum/material/supermatter/generate_recipes()
+ recipes = list(
+ new /datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]")
+ )
\ No newline at end of file
diff --git a/code/modules/materials/materials_vr.dm b/code/modules/materials/materials_vr.dm
deleted file mode 100644
index e66f1ebfa85..00000000000
--- a/code/modules/materials/materials_vr.dm
+++ /dev/null
@@ -1,104 +0,0 @@
-/datum/material/flesh
- name = "flesh"
- display_name = "chunk of flesh"
- icon_colour = "#dd90aa"
- sheet_singular_name = "meat"
- sheet_plural_name = "meats"
- integrity = 1200
- melting_point = 6000
- explosion_resistance = 200
- hardness = 500
- weight = 500
-
-/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
- name = " "
- display_name = ""
- icon_colour = "#000000"
- sheet_singular_name = "fluff"
- sheet_plural_name = "fluffs"
- hardness = 60
- weight = 20 //Strong as iron.
-
-/datum/material/darkglass
- name = "darkglass"
- display_name = "darkglass"
- icon_base = "darkglass"
- icon_colour = "#FFFFFF"
-
-/datum/material/fancyblack
- name = "fancyblack"
- display_name = "fancyblack"
- icon_base = "fancyblack"
- icon_colour = "#FFFFFF"
-
-/datum/material/glass/titaniumglass
- name = MAT_TITANIUMGLASS
- display_name = "titanium glass"
- stack_type = /obj/item/stack/material/glass/titanium
- integrity = 150
- hardness = 50
- weight = 50
- flags = MATERIAL_BRITTLE
- icon_colour = "#A7A3A6"
- stack_origin_tech = list(TECH_MATERIAL = 5)
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/titanium
- created_fulltile_window = /obj/structure/window/titanium/full
- wire_product = null
- rod_product = /obj/item/stack/material/glass/titanium
- composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
-
-/datum/material/plastitanium
- name = MAT_PLASTITANIUM
- stack_type = /obj/item/stack/material/plastitanium
- integrity = 600
- melting_point = 9000
- icon_base = "solid"
- icon_reinf = "reinf_over"
- icon_colour = "#585658"
- explosion_resistance = 35
- hardness = 90
- weight = 40
- protectiveness = 30
- conductivity = 7
- stack_origin_tech = list(TECH_MATERIAL = 5)
- composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT)
- supply_conversion_value = 8
-
-/datum/material/plastitanium/hull
- name = MAT_PLASTITANIUMHULL
- stack_type = /obj/item/stack/material/plastitanium/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- icon_colour = "#585658"
- explosion_resistance = 50
-
-/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
- new /obj/item/stack/material/plastitanium(target)
-
-/datum/material/glass/plastaniumglass
- name = MAT_PLASTITANIUMGLASS
- display_name = "plas-titanium glass"
- stack_type = /obj/item/stack/material/glass/plastitanium
- integrity = 200
- hardness = 60
- weight = 80
- flags = MATERIAL_BRITTLE
- icon_colour = "#676366"
- stack_origin_tech = list(TECH_MATERIAL = 6)
- window_options = list("One Direction" = 1, "Full Window" = 4)
- created_window = /obj/structure/window/plastitanium
- created_fulltile_window = /obj/structure/window/plastitanium/full
- wire_product = null
- rod_product = /obj/item/stack/material/glass/plastitanium
- composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
-
-/datum/material/gold/hull
- name = MAT_GOLDHULL
- stack_type = /obj/item/stack/material/gold/hull
- icon_base = "hull"
- icon_reinf = "reinf_mesh"
- explosion_resistance = 50
-
-/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
- new /obj/item/stack/material/gold(target)
\ No newline at end of file
diff --git a/code/modules/materials/sheets/_sheets.dm b/code/modules/materials/sheets/_sheets.dm
new file mode 100644
index 00000000000..7572d0e6545
--- /dev/null
+++ b/code/modules/materials/sheets/_sheets.dm
@@ -0,0 +1,89 @@
+// Stacked resources. They use a material datum for a lot of inherited values.
+// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well
+/obj/item/stack/material
+ force = 5.0
+ throwforce = 5
+ w_class = ITEMSIZE_NORMAL
+ throw_speed = 3
+ throw_range = 3
+ center_of_mass = null
+ max_amount = 50
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_material.dmi',
+ )
+
+ var/default_type = DEFAULT_WALL_MATERIAL
+ var/datum/material/material
+ var/perunit = SHEET_MATERIAL_AMOUNT
+ var/apply_colour //temp pending icon rewrite
+ drop_sound = 'sound/items/drop/axe.ogg'
+ pickup_sound = 'sound/items/pickup/axe.ogg'
+
+/obj/item/stack/material/Initialize()
+ . = ..()
+
+ randpixel_xy()
+
+ if(!default_type)
+ default_type = DEFAULT_WALL_MATERIAL
+ material = get_material_by_name("[default_type]")
+ if(!material)
+ return INITIALIZE_HINT_QDEL
+
+ recipes = material.get_recipes()
+ stacktype = material.stack_type
+ if(islist(material.stack_origin_tech))
+ origin_tech = material.stack_origin_tech.Copy()
+
+ if(apply_colour)
+ color = material.icon_colour
+
+ if(!material.conductive)
+ flags |= NOCONDUCT
+
+ matter = material.get_matter()
+ update_strings()
+
+/obj/item/stack/material/get_material()
+ return material
+
+/obj/item/stack/material/proc/update_strings()
+ // Update from material datum.
+ singular_name = material.sheet_singular_name
+
+ if(amount>1)
+ name = "[material.use_name] [material.sheet_plural_name]"
+ desc = "A stack of [material.use_name] [material.sheet_plural_name]."
+ gender = PLURAL
+ else
+ name = "[material.use_name] [material.sheet_singular_name]"
+ desc = "A [material.sheet_singular_name] of [material.use_name]."
+ gender = NEUTER
+
+/obj/item/stack/material/use(var/used)
+ . = ..()
+ update_strings()
+ return
+
+/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
+ var/obj/item/stack/material/M = S
+ if(!istype(M) || material.name != M.material.name)
+ return 0
+ var/transfer = ..(S,tamount,1)
+ if(src) update_strings()
+ if(M) M.update_strings()
+ return transfer
+
+/obj/item/stack/material/attack_self(var/mob/user)
+ if(!material.build_windows(user, src))
+ ..()
+
+/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user)
+ if(istype(W,/obj/item/stack/cable_coil))
+ material.build_wired_product(user, W, src)
+ return
+ else if(istype(W, /obj/item/stack/rods))
+ material.build_rod_product(user, W, src)
+ return
+ return ..()
\ No newline at end of file
diff --git a/code/modules/materials/sheets/gems.dm b/code/modules/materials/sheets/gems.dm
new file mode 100644
index 00000000000..1906da8eab0
--- /dev/null
+++ b/code/modules/materials/sheets/gems.dm
@@ -0,0 +1,66 @@
+/obj/item/stack/material/phoron
+ name = "solid phoron"
+ icon_state = "sheet-phoron"
+ default_type = "phoron"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+
+/obj/item/stack/material/diamond
+ name = "diamond"
+ icon_state = "sheet-diamond"
+ default_type = "diamond"
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+
+/obj/item/stack/material/painite
+ name = "painite"
+ icon_state = "sheet-gem"
+ singular_name = "painite gem"
+ default_type = "painite"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/void_opal
+ name = "void opal"
+ icon_state = "sheet-void_opal"
+ singular_name = "void opal"
+ default_type = "void opal"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/quartz
+ name = "quartz"
+ icon_state = "sheet-gem"
+ singular_name = "quartz gem"
+ default_type = "quartz"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/valhollide
+ name = MAT_VALHOLLIDE
+ icon_state = "sheet-gem"
+ item_state = "diamond"
+ default_type = MAT_VALHOLLIDE
+ no_variants = FALSE
+ apply_colour = TRUE
+
+// Particle Smasher and Exotic material.
+/obj/item/stack/material/verdantium
+ name = MAT_VERDANTIUM
+ icon_state = "sheet-wavy"
+ item_state = "mhydrogen"
+ default_type = MAT_VERDANTIUM
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/morphium
+ name = MAT_MORPHIUM
+ icon_state = "sheet-wavy"
+ item_state = "mhydrogen"
+ default_type = MAT_MORPHIUM
+ no_variants = FALSE
+ apply_colour = TRUE
+
+
+
diff --git a/code/modules/materials/sheets/glass.dm b/code/modules/materials/sheets/glass.dm
new file mode 100644
index 00000000000..bf891347ea0
--- /dev/null
+++ b/code/modules/materials/sheets/glass.dm
@@ -0,0 +1,33 @@
+/obj/item/stack/material/glass
+ name = "glass"
+ icon_state = "sheet-transparent"
+ default_type = "glass"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ pickup_sound = 'sound/items/pickup/glass.ogg'
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/reinforced
+ name = "reinforced glass"
+ icon_state = "sheet-rtransparent"
+ default_type = "rglass"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/phoronglass
+ name = "borosilicate glass"
+ desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures"
+ singular_name = "borosilicate glass sheet"
+ icon_state = "sheet-transparent"
+ default_type = "borosilicate glass"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/glass/phoronrglass
+ name = "reinforced borosilicate glass"
+ desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods."
+ singular_name = "reinforced borosilicate glass sheet"
+ icon_state = "sheet-rtransparent"
+ default_type = "reinforced borosilicate glass"
+ no_variants = FALSE
+ apply_colour = TRUE
\ No newline at end of file
diff --git a/code/modules/materials/sheets/glass_vr.dm b/code/modules/materials/sheets/glass_vr.dm
new file mode 100644
index 00000000000..23aad9c0cc2
--- /dev/null
+++ b/code/modules/materials/sheets/glass_vr.dm
@@ -0,0 +1,17 @@
+/obj/item/stack/material/glass/titanium
+ name = "ti-glass sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-titaniumglass"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ default_type = MAT_TITANIUMGLASS
+
+/obj/item/stack/material/glass/plastitanium
+ name = "plastitanium glass sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitaniumglass"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/glass.ogg'
+ default_type = MAT_PLASTITANIUMGLASS
diff --git a/code/modules/materials/sheets/metals/hull.dm b/code/modules/materials/sheets/metals/hull.dm
new file mode 100644
index 00000000000..5a6d429f448
--- /dev/null
+++ b/code/modules/materials/sheets/metals/hull.dm
@@ -0,0 +1,18 @@
+/obj/item/stack/material/steel/hull
+ name = MAT_STEELHULL
+ default_type = MAT_STEELHULL
+
+/obj/item/stack/material/plasteel/hull
+ name = MAT_PLASTEELHULL
+ default_type = MAT_PLASTEELHULL
+
+/obj/item/stack/material/durasteel/hull
+ name = MAT_DURASTEELHULL
+
+/obj/item/stack/material/titanium/hull
+ name = MAT_TITANIUMHULL
+ default_type = MAT_TITANIUMHULL
+
+/obj/item/stack/material/morphium/hull
+ name = MAT_MORPHIUMHULL
+ default_type = MAT_MORPHIUMHULL
\ No newline at end of file
diff --git a/code/modules/materials/sheets/metals/hull_vr.dm b/code/modules/materials/sheets/metals/hull_vr.dm
new file mode 100644
index 00000000000..29e267ab818
--- /dev/null
+++ b/code/modules/materials/sheets/metals/hull_vr.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/plastitanium/hull
+ name = "plastitanium hull sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_PLASTITANIUMHULL
+
+/obj/item/stack/material/gold/hull
+ name = "gold hull sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_GOLDHULL
diff --git a/code/modules/materials/sheets/metals/metal.dm b/code/modules/materials/sheets/metals/metal.dm
new file mode 100644
index 00000000000..bbad559c128
--- /dev/null
+++ b/code/modules/materials/sheets/metals/metal.dm
@@ -0,0 +1,140 @@
+/obj/item/stack/material/steel
+ name = DEFAULT_WALL_MATERIAL
+ icon_state = "sheet-refined"
+ default_type = DEFAULT_WALL_MATERIAL
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/plasteel
+ name = "plasteel"
+ icon_state = "sheet-reinforced"
+ default_type = "plasteel"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/durasteel
+ name = "durasteel"
+ icon_state = "sheet-reinforced"
+ item_state = "sheet-metal"
+ default_type = "durasteel"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/titanium
+ name = MAT_TITANIUM
+ icon_state = "sheet-refined"
+ apply_colour = TRUE
+ item_state = "sheet-silver"
+ default_type = MAT_TITANIUM
+ no_variants = FALSE
+
+/obj/item/stack/material/iron
+ name = "iron"
+ icon_state = "sheet-ingot"
+ default_type = "iron"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/lead
+ name = "lead"
+ icon_state = "sheet-ingot"
+ default_type = "lead"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/gold
+ name = "gold"
+ icon_state = "sheet-ingot"
+ default_type = "gold"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/silver
+ name = "silver"
+ icon_state = "sheet-ingot"
+ default_type = "silver"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+//Valuable resource, cargo can sell it.
+/obj/item/stack/material/platinum
+ name = "platinum"
+ icon_state = "sheet-adamantine"
+ default_type = "platinum"
+ no_variants = FALSE
+ apply_colour = TRUE
+
+/obj/item/stack/material/uranium
+ name = "uranium"
+ icon_state = "sheet-uranium"
+ default_type = "uranium"
+ no_variants = FALSE
+
+//Extremely valuable to Research.
+/obj/item/stack/material/mhydrogen
+ name = "metallic hydrogen"
+ icon_state = "sheet-mythril"
+ default_type = "mhydrogen"
+ no_variants = FALSE
+
+// Fusion fuel.
+/obj/item/stack/material/deuterium
+ name = "deuterium"
+ icon_state = "sheet-puck"
+ default_type = "deuterium"
+ apply_colour = 1
+ no_variants = FALSE
+
+//Fuel for MRSPACMAN generator.
+/obj/item/stack/material/tritium
+ name = "tritium"
+ icon_state = "sheet-puck"
+ default_type = "tritium"
+ apply_colour = TRUE
+ no_variants = FALSE
+
+/obj/item/stack/material/osmium
+ name = "osmium"
+ icon_state = "sheet-ingot"
+ default_type = "osmium"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/graphite
+ name = "graphite"
+ icon_state = "sheet-puck"
+ default_type = MAT_GRAPHITE
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/bronze
+ name = "bronze"
+ icon_state = "sheet-ingot"
+ singular_name = "bronze ingot"
+ default_type = "bronze"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/tin
+ name = "tin"
+ icon_state = "sheet-ingot"
+ singular_name = "tin ingot"
+ default_type = "tin"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/copper
+ name = "copper"
+ icon_state = "sheet-ingot"
+ singular_name = "copper ingot"
+ default_type = "copper"
+ apply_colour = 1
+ no_variants = FALSE
+
+/obj/item/stack/material/aluminium
+ name = "aluminium"
+ icon_state = "sheet-ingot"
+ singular_name = "aluminium ingot"
+ default_type = "aluminium"
+ apply_colour = 1
+ no_variants = FALSE
diff --git a/code/modules/materials/sheets/metals/metal_vr.dm b/code/modules/materials/sheets/metals/metal_vr.dm
new file mode 100644
index 00000000000..1a867ea9578
--- /dev/null
+++ b/code/modules/materials/sheets/metals/metal_vr.dm
@@ -0,0 +1,12 @@
+/obj/item/stack/material/titanium
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-titanium"
+ no_variants = FALSE
+
+/obj/item/stack/material/plastitanium
+ name = "plastitanium sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_PLASTITANIUM
diff --git a/code/game/objects/items/stacks/rods.dm b/code/modules/materials/sheets/metals/rods.dm
similarity index 96%
rename from code/game/objects/items/stacks/rods.dm
rename to code/modules/materials/sheets/metals/rods.dm
index 9844ae1cba9..d1c4a1ee240 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/modules/materials/sheets/metals/rods.dm
@@ -1,109 +1,109 @@
-/obj/item/stack/rods
- name = "metal rod"
- desc = "Some rods. Can be used for building, or something."
- singular_name = "metal rod"
- icon_state = "rods"
- w_class = ITEMSIZE_NORMAL
- force = 9.0
- throwforce = 15.0
- throw_speed = 5
- throw_range = 20
- drop_sound = 'sound/items/drop/metalweapon.ogg'
- pickup_sound = 'sound/items/pickup/metalweapon.ogg'
- matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2)
- max_amount = 60
- attack_verb = list("hit", "bludgeoned", "whacked")
-
- color = "#666666"
-
-/obj/item/stack/rods/cyborg
- name = "metal rod synthesizer"
- desc = "A device that makes metal rods."
- gender = NEUTER
- matter = null
- uses_charge = 1
- charge_costs = list(500)
- stacktype = /obj/item/stack/rods
- no_variants = TRUE
-
-/obj/item/stack/rods/Initialize()
- . = ..()
- recipes = rods_recipes
- update_icon()
-
-/obj/item/stack/rods/update_icon()
- var/amount = get_amount()
- if((amount <= 5) && (amount > 0))
- icon_state = "rods-[amount]"
- else
- icon_state = "rods"
-
-var/global/list/datum/stack_recipe/rods_recipes = list( \
- new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0),
- new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1))
-
-/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/WT = W
-
- if(get_amount() < 2)
- to_chat(user, "You need at least two rods to do this.")
- return
-
- if(WT.remove_fuel(0,user))
- var/obj/item/stack/material/steel/new_item = new(usr.loc)
- new_item.add_to_stacks(usr)
- for (var/mob/M in viewers(src))
- M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2)
- var/obj/item/stack/rods/R = src
- src = null
- var/replace = (user.get_inactive_hand()==R)
- R.use(2)
- if (!R && replace)
- user.put_in_hands(new_item)
- return
-
- if (istype(W, /obj/item/weapon/tape_roll))
- var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user))
- new_splint.add_fingerprint(user)
-
- user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \
- "You use make \a [new_splint] out of a [singular_name].")
- src.use(1)
- return
-
- ..()
-
-/*
-/obj/item/stack/rods/attack_self(mob/user as mob)
- src.add_fingerprint(user)
-
- if(!istype(user.loc,/turf)) return 0
-
- if (locate(/obj/structure/grille, usr.loc))
- for(var/obj/structure/grille/G in usr.loc)
- if (G.destroyed)
- G.health = 10
- G.density = 1
- G.destroyed = 0
- G.icon_state = "grille"
- use(1)
- else
- return 1
-
- else if(!in_use)
- if(get_amount() < 2)
- to_chat(user, "You need at least two rods to do this.")
- return
- to_chat(usr, "Assembling grille...")
- in_use = 1
- if (!do_after(usr, 10))
- in_use = 0
- return
- var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc )
- to_chat(usr, "You assemble a grille")
- in_use = 0
- F.add_fingerprint(usr)
- use(2)
- return
+/obj/item/stack/rods
+ name = "metal rod"
+ desc = "Some rods. Can be used for building, or something."
+ singular_name = "metal rod"
+ icon_state = "rods"
+ w_class = ITEMSIZE_NORMAL
+ force = 9.0
+ throwforce = 15.0
+ throw_speed = 5
+ throw_range = 20
+ drop_sound = 'sound/items/drop/metalweapon.ogg'
+ pickup_sound = 'sound/items/pickup/metalweapon.ogg'
+ matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2)
+ max_amount = 60
+ attack_verb = list("hit", "bludgeoned", "whacked")
+
+ color = "#666666"
+
+/obj/item/stack/rods/cyborg
+ name = "metal rod synthesizer"
+ desc = "A device that makes metal rods."
+ gender = NEUTER
+ matter = null
+ uses_charge = 1
+ charge_costs = list(500)
+ stacktype = /obj/item/stack/rods
+ no_variants = TRUE
+
+/obj/item/stack/rods/Initialize()
+ . = ..()
+ recipes = rods_recipes
+ update_icon()
+
+/obj/item/stack/rods/update_icon()
+ var/amount = get_amount()
+ if((amount <= 5) && (amount > 0))
+ icon_state = "rods-[amount]"
+ else
+ icon_state = "rods"
+
+var/global/list/datum/stack_recipe/rods_recipes = list( \
+ new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0),
+ new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1))
+
+/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/WT = W
+
+ if(get_amount() < 2)
+ to_chat(user, "You need at least two rods to do this.")
+ return
+
+ if(WT.remove_fuel(0,user))
+ var/obj/item/stack/material/steel/new_item = new(usr.loc)
+ new_item.add_to_stacks(usr)
+ for (var/mob/M in viewers(src))
+ M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2)
+ var/obj/item/stack/rods/R = src
+ src = null
+ var/replace = (user.get_inactive_hand()==R)
+ R.use(2)
+ if (!R && replace)
+ user.put_in_hands(new_item)
+ return
+
+ if (istype(W, /obj/item/weapon/tape_roll))
+ var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user))
+ new_splint.add_fingerprint(user)
+
+ user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \
+ "You use make \a [new_splint] out of a [singular_name].")
+ src.use(1)
+ return
+
+ ..()
+
+/*
+/obj/item/stack/rods/attack_self(mob/user as mob)
+ src.add_fingerprint(user)
+
+ if(!istype(user.loc,/turf)) return 0
+
+ if (locate(/obj/structure/grille, usr.loc))
+ for(var/obj/structure/grille/G in usr.loc)
+ if (G.destroyed)
+ G.health = 10
+ G.density = 1
+ G.destroyed = 0
+ G.icon_state = "grille"
+ use(1)
+ else
+ return 1
+
+ else if(!in_use)
+ if(get_amount() < 2)
+ to_chat(user, "You need at least two rods to do this.")
+ return
+ to_chat(usr, "Assembling grille...")
+ in_use = 1
+ if (!do_after(usr, 10))
+ in_use = 0
+ return
+ var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc )
+ to_chat(usr, "You assemble a grille")
+ in_use = 0
+ F.add_fingerprint(usr)
+ use(2)
+ return
*/
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/animal_products.dm b/code/modules/materials/sheets/organic/animal_products.dm
new file mode 100644
index 00000000000..4620da5ea9c
--- /dev/null
+++ b/code/modules/materials/sheets/organic/animal_products.dm
@@ -0,0 +1,31 @@
+/obj/item/stack/material/chitin
+ name = "chitin"
+ desc = "The by-product of mob grinding."
+ icon_state = "chitin"
+ default_type = MAT_CHITIN
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+
+//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
+/obj/item/stack/xenochitin
+ name = "alien chitin"
+ desc = "A piece of the hide of a terrible creature."
+ singular_name = "alien chitin piece"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "chitin"
+ stacktype = "hide-chitin"
+
+/obj/item/xenos_claw
+ name = "alien claw"
+ desc = "The claw of a terrible creature."
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "claw"
+
+/obj/item/weed_extract
+ name = "weed extract"
+ desc = "A piece of slimy, purplish weed."
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "weed_extract"
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/resin.dm b/code/modules/materials/sheets/organic/resin.dm
new file mode 100644
index 00000000000..7120911f2d5
--- /dev/null
+++ b/code/modules/materials/sheets/organic/resin.dm
@@ -0,0 +1,8 @@
+/obj/item/stack/material/resin
+ name = "resin"
+ icon_state = "sheet-resin"
+ default_type = "resin"
+ no_variants = TRUE
+ apply_colour = TRUE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/hide.dm b/code/modules/materials/sheets/organic/tanning/hide.dm
new file mode 100644
index 00000000000..a8b229c9eba
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/hide.dm
@@ -0,0 +1,90 @@
+/obj/item/stack/animalhide
+ name = "hide"
+ desc = "The hide of some creature."
+ description_info = "Use something sharp, like a knife, to scrape the hairs/feathers/etc off this hide to prepare it for tanning."
+ icon_state = "sheet-hide"
+ drop_sound = 'sound/items/drop/cloth.ogg'
+ pickup_sound = 'sound/items/pickup/cloth.ogg'
+ amount = 1
+ max_amount = 20
+ stacktype = "hide"
+ no_variants = TRUE
+// This needs to be very clearly documented for players. Whether it should stay in the main description is up for debate.
+/obj/item/stack/animalhide/examine(var/mob/user)
+ . = ..()
+ . += description_info
+
+//Step one - dehairing.
+/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(has_edge(W) || is_sharp(W))
+ //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message)
+ user.visible_message("\The [user] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh")
+ var/scraped = 0
+ while(amount > 0 && do_after(user, 2.5 SECONDS)) // 2.5s per hide
+ //Try locating an exisitng stack on the tile and add to there if possible
+ var/obj/item/stack/hairlesshide/H = null
+ for(var/obj/item/stack/hairlesshide/HS in user.loc) // Could be scraping something inside a locker, hence the .loc, not get_turf
+ if(HS.amount < HS.max_amount)
+ H = HS
+ break
+
+ // Either we found a valid stack, in which case increment amount,
+ // Or we need to make a new stack
+ if(istype(H))
+ H.amount++
+ else
+ H = new /obj/item/stack/hairlesshide(user.loc)
+
+ // Increment the amount
+ src.use(1)
+ scraped++
+
+ if(scraped)
+ to_chat(user, SPAN_NOTICE("You scrape the hair off [scraped] hide\s."))
+ else
+ ..()
+
+/obj/item/stack/animalhide/human
+ name = "skin"
+ desc = "The by-product of sapient farming."
+ singular_name = "skin piece"
+ icon_state = "sheet-hide"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+ stacktype = "hide-human"
+
+/obj/item/stack/animalhide/corgi
+ name = "corgi hide"
+ desc = "The by-product of corgi farming."
+ singular_name = "corgi hide piece"
+ icon_state = "sheet-corgi"
+ stacktype = "hide-corgi"
+
+/obj/item/stack/animalhide/cat
+ name = "cat hide"
+ desc = "The by-product of cat farming."
+ singular_name = "cat hide piece"
+ icon_state = "sheet-cat"
+ stacktype = "hide-cat"
+
+/obj/item/stack/animalhide/monkey
+ name = "monkey hide"
+ desc = "The by-product of monkey farming."
+ singular_name = "monkey hide piece"
+ icon_state = "sheet-monkey"
+ stacktype = "hide-monkey"
+
+/obj/item/stack/animalhide/lizard
+ name = "lizard skin"
+ desc = "Sssssss..."
+ singular_name = "lizard skin piece"
+ icon_state = "sheet-lizard"
+ stacktype = "hide-lizard"
+
+/obj/item/stack/animalhide/xeno
+ name = "alien hide"
+ desc = "The skin of a terrible creature."
+ singular_name = "alien hide piece"
+ icon_state = "sheet-xeno"
+ stacktype = "hide-xeno"
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/hide_hairless.dm b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm
new file mode 100644
index 00000000000..72b235e415d
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm
@@ -0,0 +1,48 @@
+//Step two - washing..... it's actually in washing machine code, and ere.
+
+/obj/item/stack/hairlesshide
+ name = "hairless hide"
+ desc = "This hide was stripped of it's hair, but still needs tanning."
+ description_info = "Get it wet to continue tanning this into leather.
\
+ You could set it in a river, wash it with a sink, or just splash water on it with a bucket."
+ singular_name = "hairless hide piece"
+ icon_state = "sheet-hairlesshide"
+ no_variants = FALSE
+ max_amount = 20
+ stacktype = "hairlesshide"
+
+/obj/item/stack/hairlesshide/examine(var/mob/user)
+ . = ..()
+ . += description_info
+
+/obj/item/stack/hairlesshide/water_act(var/wateramount)
+ . = ..()
+ wateramount = min(amount, round(wateramount))
+ for(var/i in 1 to wateramount)
+ var/obj/item/stack/wetleather/H = null
+ for(var/obj/item/stack/wetleather/HS in get_turf(src)) // Doesn't have a user, can't just use their loc
+ if(HS.amount < HS.max_amount)
+ H = HS
+ break
+
+ // Either we found a valid stack, in which case increment amount,
+ // Or we need to make a new stack
+ if(istype(H))
+ H.amount++
+ else
+ H = new /obj/item/stack/wetleather(get_turf(src))
+
+ // Increment the amount
+ src.use(1)
+
+/obj/item/stack/hairlesshide/proc/rapidcure(var/stacknum = 1)
+ stacknum = min(stacknum, amount)
+
+ while(stacknum)
+ var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src))
+
+ if(istype(I))
+ I.dry()
+
+ use(1)
+ stacknum -= 1
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/tanning/leather_wet.dm b/code/modules/materials/sheets/organic/tanning/leather_wet.dm
new file mode 100644
index 00000000000..64f672512ce
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/leather_wet.dm
@@ -0,0 +1,51 @@
+//Step three - drying
+/obj/item/stack/wetleather
+ name = "wet leather"
+ desc = "This leather has been cleaned but still needs to be dried."
+ description_info = "To finish tanning the leather, you need to dry it. \
+ You could place it under a fire, \
+ put it in a drying rack, \
+ or build a tanning rack from steel or wooden boards."
+ singular_name = "wet leather piece"
+ icon_state = "sheet-wetleather"
+ var/wetness = 30 //Reduced when exposed to high temperautres
+ var/drying_threshold_temperature = 500 //Kelvin to start drying
+ no_variants = FALSE
+ max_amount = 20
+ stacktype = "wetleather"
+
+ var/dry_type = /obj/item/stack/material/leather
+
+/obj/item/stack/wetleather/examine(var/mob/user)
+ . = ..()
+ . += description_info
+ . += "\The [src] is [get_dryness_text()]."
+
+/obj/item/stack/wetleather/proc/get_dryness_text()
+ if(wetness > 20)
+ return "wet"
+ if(wetness > 10)
+ return "damp"
+ if(wetness)
+ return "almost dry"
+ return "dry"
+
+/obj/item/stack/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
+ if(exposed_temperature >= drying_threshold_temperature)
+ wetness--
+ if(wetness == 0)
+ dry()
+
+/obj/item/stack/wetleather/proc/dry()
+ var/obj/item/stack/material/leather/L = new(src.loc)
+ L.amount = amount
+ use(amount)
+ return L
+
+/obj/item/stack/wetleather/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified)
+ . = ..()
+ if(.) // If it transfers any, do a weighted average of the wetness
+ var/obj/item/stack/wetleather/W = S
+ var/oldamt = W.amount - .
+ W.wetness = round(((oldamt * W.wetness) + (. * wetness)) / W.amount)
diff --git a/code/modules/materials/sheets/organic/tanning/tanning_rack.dm b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
new file mode 100644
index 00000000000..96d70d90967
--- /dev/null
+++ b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm
@@ -0,0 +1,70 @@
+/obj/structure/tanning_rack
+ name = "tanning rack"
+ desc = "A rack used to stretch leather out and hold it taut during the tanning process."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "spike"
+
+ var/obj/item/stack/wetleather/drying = null
+
+/obj/structure/tanning_rack/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src) // SSObj fires ~every 2s , starting from wetness 30 takes ~1m
+
+/obj/structure/tanning_rack/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/structure/tanning_rack/process()
+ if(drying && drying.wetness)
+ drying.wetness = max(drying.wetness - 1, 0)
+ if(!drying.wetness)
+ visible_message("The [drying] is dry!")
+ update_icon()
+
+/obj/structure/tanning_rack/examine(var/mob/user)
+ . = ..()
+ if(drying)
+ . += "\The [drying] is [drying.get_dryness_text()]."
+
+/obj/structure/tanning_rack/update_icon()
+ overlays.Cut()
+ if(drying)
+ var/image/I
+ if(drying.wetness)
+ I = image(icon, "leather_wet")
+ else
+ I = image(icon, "leather_dry")
+ add_overlay(I)
+
+/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user)
+ if(istype(A, /obj/item/stack/wetleather))
+ if(!drying) // If not drying anything, start drying the thing
+ if(user.unEquip(A, target = src))
+ drying = A
+ else // Drying something, add if possible
+ var/obj/item/stack/wetleather/W = A
+ W.transfer_to(drying, W.amount, TRUE)
+ update_icon()
+ return TRUE
+ return ..()
+
+/obj/structure/tanning_rack/attack_hand(var/mob/user)
+ if(drying)
+ var/obj/item/stack/S = drying
+ if(!drying.wetness) // If it's dry, make a stack of dry leather and prepare to put that in their hands
+ var/obj/item/stack/material/leather/L = new(src)
+ L.amount = drying.amount
+ drying.use(drying.amount)
+ S = L
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(!H.put_in_any_hand_if_possible(S))
+ S.forceMove(get_turf(src))
+ else
+ S.forceMove(get_turf(src))
+ drying = null
+ update_icon()
+
+/obj/structure/tanning_rack/attack_robot(var/mob/user)
+ attack_hand(user) // That has checks to
\ No newline at end of file
diff --git a/code/modules/materials/sheets/organic/textiles.dm b/code/modules/materials/sheets/organic/textiles.dm
new file mode 100644
index 00000000000..a534ee19b1c
--- /dev/null
+++ b/code/modules/materials/sheets/organic/textiles.dm
@@ -0,0 +1,23 @@
+/obj/item/stack/material/leather
+ name = "leather"
+ desc = "The by-product of mob grinding."
+ icon_state = "sheet-leather"
+ default_type = MAT_LEATHER
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
+
+/obj/item/stack/material/cloth
+ name = "cloth"
+ icon_state = "sheet-cloth"
+ default_type = "cloth"
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+
+/obj/item/stack/material/cloth/diyaab
+ color = "#c6ccf0"
diff --git a/code/modules/materials/sheets/organic/wood.dm b/code/modules/materials/sheets/organic/wood.dm
new file mode 100644
index 00000000000..d3d1fd6418e
--- /dev/null
+++ b/code/modules/materials/sheets/organic/wood.dm
@@ -0,0 +1,55 @@
+/obj/item/stack/material/wood
+ name = "wooden plank"
+ icon_state = "sheet-wood"
+ default_type = MAT_WOOD
+ strict_color_stacking = TRUE
+ apply_colour = 1
+ drop_sound = 'sound/items/drop/wooden.ogg'
+ pickup_sound = 'sound/items/pickup/wooden.ogg'
+ no_variants = FALSE
+
+/obj/item/stack/material/wood/sif
+ name = "alien wooden plank"
+ color = "#0099cc"
+ default_type = MAT_SIFWOOD
+
+/obj/item/stack/material/log
+ name = "log"
+ icon_state = "sheet-log"
+ default_type = MAT_LOG
+ no_variants = FALSE
+ color = "#824B28"
+ max_amount = 25
+ w_class = ITEMSIZE_HUGE
+ description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks."
+ var/plank_type = /obj/item/stack/material/wood
+ drop_sound = 'sound/items/drop/wooden.ogg'
+ pickup_sound = 'sound/items/pickup/wooden.ogg'
+
+/obj/item/stack/material/log/sif
+ name = "alien log"
+ default_type = MAT_SIFLOG
+ color = "#0099cc"
+ plank_type = /obj/item/stack/material/wood/sif
+
+/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
+ if(!istype(W) || W.force <= 0)
+ return ..()
+ if(W.sharp && W.edge)
+ var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed
+ user.setClickCooldown(time)
+ if(do_after(user, time, src) && use(1))
+ to_chat(user, "You cut up a log into planks.")
+ playsound(src, 'sound/effects/woodcutting.ogg', 50, 1)
+ var/obj/item/stack/material/wood/existing_wood = null
+ for(var/obj/item/stack/material/wood/M in user.loc)
+ if(M.material.name == src.material.name)
+ existing_wood = M
+ break
+
+ var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc)
+ new_wood.amount = 2
+ if(existing_wood && new_wood.transfer_to(existing_wood))
+ to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.")
+ else
+ return ..()
diff --git a/code/modules/materials/sheets/plastic.dm b/code/modules/materials/sheets/plastic.dm
new file mode 100644
index 00000000000..41415af606a
--- /dev/null
+++ b/code/modules/materials/sheets/plastic.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/plastic
+ name = "plastic"
+ icon_state = "sheet-plastic"
+ default_type = "plastic"
+ no_variants = FALSE
+
+/obj/item/stack/material/cardboard
+ name = "cardboard"
+ icon_state = "sheet-card"
+ default_type = "cardboard"
+ no_variants = FALSE
+ pass_color = TRUE
+ strict_color_stacking = TRUE
+ drop_sound = 'sound/items/drop/cardboardbox.ogg'
+ pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
diff --git a/code/modules/materials/sheets/snow.dm b/code/modules/materials/sheets/snow.dm
new file mode 100644
index 00000000000..7ecc4c4e64d
--- /dev/null
+++ b/code/modules/materials/sheets/snow.dm
@@ -0,0 +1,16 @@
+// Ok, technically not stones, but the snowbrick's function is similar to sandstone and marble
+/obj/item/stack/material/snow
+ name = "snow"
+ desc = "The temptation to build a snowman rises."
+ icon_state = "sheet-snow"
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+ default_type = "snow"
+
+/obj/item/stack/material/snowbrick
+ name = "snow brick"
+ desc = "For all of your igloo building needs."
+ icon_state = "sheet-snowbrick"
+ default_type = "packed snow"
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
\ No newline at end of file
diff --git a/code/modules/materials/sheets/stone.dm b/code/modules/materials/sheets/stone.dm
new file mode 100644
index 00000000000..17347ff9d8f
--- /dev/null
+++ b/code/modules/materials/sheets/stone.dm
@@ -0,0 +1,15 @@
+/obj/item/stack/material/sandstone
+ name = "sandstone brick"
+ icon_state = "sheet-sandstone"
+ default_type = "sandstone"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/boots.ogg'
+ pickup_sound = 'sound/items/pickup/boots.ogg'
+
+/obj/item/stack/material/marble
+ name = "marble brick"
+ icon_state = "sheet-marble"
+ default_type = "marble"
+ no_variants = FALSE
+ drop_sound = 'sound/items/drop/boots.ogg'
+ pickup_sound = 'sound/items/pickup/boots.ogg'
diff --git a/code/modules/materials/sheets/supermatter.dm b/code/modules/materials/sheets/supermatter.dm
new file mode 100644
index 00000000000..c56f2980881
--- /dev/null
+++ b/code/modules/materials/sheets/supermatter.dm
@@ -0,0 +1,55 @@
+// Forged in the equivalent of Hell, one piece at a time.
+/obj/item/stack/material/supermatter
+ name = MAT_SUPERMATTER
+ icon_state = "sheet-super"
+ item_state = "diamond"
+ default_type = MAT_SUPERMATTER
+ apply_colour = TRUE
+
+/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack.
+ slowdown = amount / 10
+ w_class = min(5, round(amount / 10) + 1)
+ throw_range = round(amount / 7) + 1
+
+/obj/item/stack/material/supermatter/use(var/used)
+ . = ..()
+ update_mass()
+ return
+
+/obj/item/stack/material/supermatter/attack_hand(mob/user)
+ . = ..()
+
+ update_mass()
+ SSradiation.radiate(src, 5 + amount)
+ var/mob/living/M = user
+ if(!istype(M))
+ return
+
+ var/burn_user = TRUE
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets)))
+ burn_user = FALSE
+
+ if(burn_user)
+ H.visible_message("\The [src] flashes as it scorches [H]'s hands!")
+ H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk")
+ H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk")
+ H.drop_from_inventory(src, get_turf(H))
+ return
+
+ if(istype(user, /mob/living/silicon/robot))
+ burn_user = FALSE
+
+ if(burn_user)
+ M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk")
+
+/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature.
+ if(prob((4 / severity) * 20))
+ SSradiation.radiate(get_turf(src), amount * 4)
+ explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25))
+ qdel(src)
+ return
+ SSradiation.radiate(get_turf(src), amount * 2)
+ ..()
\ No newline at end of file
diff --git a/code/modules/mining/machine_input_output_plates.dm b/code/modules/mining/machinery/machine_input_output_plates.dm
similarity index 90%
rename from code/modules/mining/machine_input_output_plates.dm
rename to code/modules/mining/machinery/machine_input_output_plates.dm
index d8693a1316b..0e7680e6728 100644
--- a/code/modules/mining/machine_input_output_plates.dm
+++ b/code/modules/mining/machinery/machine_input_output_plates.dm
@@ -1,19 +1,19 @@
-/**********************Input and output plates**************************/
-
-/obj/machinery/mineral/input
- icon = 'icons/mob/screen1.dmi'
- icon_state = "x2"
- name = "Input area"
- density = 0
- anchored = 1.0
- New()
- icon_state = "blank"
-
-/obj/machinery/mineral/output
- icon = 'icons/mob/screen1.dmi'
- icon_state = "x"
- name = "Output area"
- density = 0
- anchored = 1.0
- New()
+/**********************Input and output plates**************************/
+
+/obj/machinery/mineral/input
+ icon = 'icons/mob/screen1.dmi'
+ icon_state = "x2"
+ name = "Input area"
+ density = 0
+ anchored = 1.0
+ New()
+ icon_state = "blank"
+
+/obj/machinery/mineral/output
+ icon = 'icons/mob/screen1.dmi'
+ icon_state = "x"
+ name = "Output area"
+ density = 0
+ anchored = 1.0
+ New()
icon_state = "blank"
\ No newline at end of file
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machinery/machine_processing.dm
similarity index 100%
rename from code/modules/mining/machine_processing.dm
rename to code/modules/mining/machinery/machine_processing.dm
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machinery/machine_stacking.dm
similarity index 100%
rename from code/modules/mining/machine_stacking.dm
rename to code/modules/mining/machinery/machine_stacking.dm
diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machinery/machine_unloading.dm
similarity index 100%
rename from code/modules/mining/machine_unloading.dm
rename to code/modules/mining/machinery/machine_unloading.dm
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 9747179320c..2608e3c7887 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -40,7 +40,7 @@ var/list/mining_overlay_cache = list()
var/datum/artifact_find/artifact_find
var/ignore_mapgen
- var/ore_types = list(
+ var/static/list/ore_types = list(
"hematite" = /obj/item/weapon/ore/iron,
"uranium" = /obj/item/weapon/ore/uranium,
"gold" = /obj/item/weapon/ore/gold,
diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
index 9956084c11d..0d15c5675aa 100644
--- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
@@ -52,6 +52,7 @@
EQUIPMENT("Defense Equipment - Plasteel Machete", /obj/item/weapon/material/knife/machete, 50),
EQUIPMENT("Defense Equipment - Razor Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/manhacks/station/locked, 100),
EQUIPMENT("Defense Equipment - Sentry Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/ward, 150),
+ EQUIPMENT("Defense Equipment - Frontier Carbine", /obj/item/weapon/gun/energy/locked/frontier/carbine, 750),
EQUIPMENT("Fishing Net", /obj/item/weapon/material/fishing_net, 50),
EQUIPMENT("Titanium Fishing Rod", /obj/item/weapon/material/fishing_rod/modern, 100),
EQUIPMENT("Durasteel Fishing Rod", /obj/item/weapon/material/fishing_rod/modern/strong, 750),
@@ -81,6 +82,7 @@
prize_list["Digging Tools"] = list(
EQUIPMENT("Survey Tools - Shovel", /obj/item/weapon/shovel, 40),
EQUIPMENT("Survey Tools - Mechanical Trap", /obj/item/weapon/beartrap, 50),
+ EQUIPMENT("Survey Tools - Binoculars", /obj/item/device/binoculars,40),
)
prize_list["Miscellaneous"] = list(
EQUIPMENT("Absinthe", /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe, 10),
diff --git a/code/modules/mining/shelter_atoms_vr.dm b/code/modules/mining/shelter_atoms_vr.dm
index 4e24c543155..1c0fc5010e5 100644
--- a/code/modules/mining/shelter_atoms_vr.dm
+++ b/code/modules/mining/shelter_atoms_vr.dm
@@ -331,6 +331,9 @@ GLOBAL_LIST_EMPTY(unique_deployable)
light_power = 1
light_color = "#FFFFFF"
+/obj/structure/fans/hardlight/ex_act()
+ return
+
/obj/structure/fans/hardlight/colorable
name = "hardlight shield"
icon_state = "hardlight_colorable"
diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm
index 9d6735ee8b6..1badc92926a 100644
--- a/code/modules/mob/death.dm
+++ b/code/modules/mob/death.dm
@@ -73,7 +73,7 @@
if(src.loc && istype(loc,/obj/belly) || istype(loc,/obj/item/device/dogborg/sleeper)) deathmessage = "no message" //VOREStation Add - Prevents death messages from inside mobs
facing_dir = null
- if(!gibbed && deathmessage != "no message") // This is gross, but reliable. Only brains use it.
+ if(!gibbed && deathmessage != DEATHGASP_NO_MESSAGE)
src.visible_message("\The [src.name] [deathmessage]")
set_stat(DEAD)
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 2a8af560804..f59ebf612cd 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -1,64 +1,9 @@
-// All mobs should have custom emote, really..
-//m_type == 1 --> visual.
-//m_type == 2 --> audible
-/mob/proc/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
- if(stat || !use_me && usr == src)
- to_chat(src, "You are unable to emote.")
- return
-
- var/muzzled = is_muzzled()
- if(m_type == 2 && muzzled) return
-
- var/input
- if(!message)
- input = sanitize_or_reflect(input(src,"Choose an emote to display.") as text|null, src) //VOREStation Edit - Reflect too long messages, within reason
- else
- input = message
- if(input)
- log_emote(message,src) //Log before we add junk
- message = "[src] [input]"
- else
- return
-
-
- if (message)
- message = encode_html_emphasis(message)
-
- // Hearing gasp and such every five seconds is not good emotes were not global for a reason.
- // Maybe some people are okay with that.
-
- var/turf/T = get_turf(src)
- if(!T) return
- var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2,remote_ghosts = client ? TRUE : FALSE)
- var/list/m_viewers = in_range["mobs"]
- var/list/o_viewers = in_range["objs"]
-
- for(var/mob in m_viewers)
- var/mob/M = mob
- spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes.
- if(M)
- if(isobserver(M))
- //VOREStation Edit Start
- var/mob/observer/dead/D = M
- if(ckey || (src in view(D)))
- M.show_message(message, m_type)
- message = "[src] ([ghost_follow_link(src, M)]) [input]"
- else
- M.show_message(message, m_type)
- //VOREStation Edit End
-
- for(var/obj in o_viewers)
- var/obj/O = obj
- spawn(0)
- if(O)
- O.see_emote(src, message, m_type)
-
// Shortcuts for above proc
/mob/proc/visible_emote(var/act_desc)
- custom_emote(1, act_desc)
+ custom_emote(VISIBLE_MESSAGE, act_desc)
/mob/proc/audible_emote(var/act_desc)
- custom_emote(2, act_desc)
+ custom_emote(AUDIBLE_MESSAGE, act_desc)
/mob/proc/emote_dead(var/message)
diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm
index cdcba151bc3..e012fdee222 100644
--- a/code/modules/mob/living/bot/cleanbot.dm
+++ b/code/modules/mob/living/bot/cleanbot.dm
@@ -10,6 +10,7 @@
wait_if_pulled = 1
min_target_dist = 0
+ var/vocal = 1
var/cleaning = 0
var/wet_floors = 0
var/spray_blood = 0
@@ -26,7 +27,7 @@
return ..()
/mob/living/bot/cleanbot/handleIdle()
- if(!wet_floors && !spray_blood && prob(2))
+ if(!wet_floors && !spray_blood && vocal && prob(2))
custom_emote(2, "makes an excited booping sound!")
playsound(src, 'sound/machines/synth_yes.ogg', 50, 0)
@@ -163,9 +164,10 @@
data["on"] = on
data["open"] = open
data["locked"] = locked
-
+
data["blood"] = blood
data["patrol"] = will_patrol
+ data["vocal"] = vocal
data["wet_floors"] = wet_floors
data["spray_blood"] = spray_blood
@@ -192,6 +194,9 @@
will_patrol = !will_patrol
patrol_path = null
. = TRUE
+ if("vocal")
+ vocal = !vocal
+ . = TRUE
if("wet_floors")
wet_floors = !wet_floors
to_chat(usr, "You twiddle the screw.")
diff --git a/code/modules/mob/living/bot/edCLNbot.dm b/code/modules/mob/living/bot/edCLNbot.dm
index b4d3dfbccaa..a0b0dc31450 100644
--- a/code/modules/mob/living/bot/edCLNbot.dm
+++ b/code/modules/mob/living/bot/edCLNbot.dm
@@ -12,6 +12,7 @@
patrol_speed = 3
target_speed = 6
+ vocal = 1
cleaning = 0
blood = 0
var/red_switch = 0
@@ -25,7 +26,7 @@
icon_state = "edCLN[on]"
/mob/living/bot/cleanbot/edCLN/handleIdle()
- if(prob(10))
+ if(vocal && prob(10))
custom_emote(2, "makes a less than thrilled beeping sound.")
playsound(src, 'sound/machines/synth_yes.ogg', 50, 0)
diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm
index 9334fbbcec2..01d9702aa81 100644
--- a/code/modules/mob/living/bot/farmbot.dm
+++ b/code/modules/mob/living/bot/farmbot.dm
@@ -96,9 +96,18 @@
turn_on()
. = TRUE
+ switch(action)
+ if("power")
+ if(!access_scanner.allowed(src))
+ return FALSE
+ if(on)
+ turn_off()
+ else
+ turn_on()
+ . = TRUE
+
if(locked)
return TRUE
-
switch(action)
if("water")
waters_trays = !waters_trays
diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm
index 31d1dc0e256..54fbc8403cb 100644
--- a/code/modules/mob/living/bot/floorbot.dm
+++ b/code/modules/mob/living/bot/floorbot.dm
@@ -12,6 +12,7 @@
wait_if_pulled = 1
min_target_dist = 0
+ var/vocal = 1
var/amount = 10 // 1 for tile, 2 for lattice
var/maxAmount = 60
var/tilemake = 0 // When it reaches 100, bot makes a tile
@@ -41,7 +42,8 @@
data["on"] = on
data["open"] = open
data["locked"] = locked
-
+
+ data["vocal"] = vocal
data["amount"] = amount
data["possible_bmode"] = list("NORTH", "EAST", "SOUTH", "WEST")
@@ -56,7 +58,6 @@
data["eattiles"] = eattiles
data["maketiles"] = maketiles
data["bmode"] = dir2text(targetdirection)
-
return data
/mob/living/bot/floorbot/attack_hand(var/mob/user)
@@ -74,8 +75,8 @@
/mob/living/bot/floorbot/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
-
- add_fingerprint(usr)
+
+ add_fingerprint(src)
switch(action)
if("start")
@@ -84,11 +85,14 @@
else
turn_on()
. = TRUE
-
+
if(locked && !issilicon(usr))
return
switch(action)
+ if("vocal")
+ vocal = !vocal
+ . = TRUE
if("improve")
improvefloors = !improvefloors
. = TRUE
@@ -108,7 +112,7 @@
tilemake = 0
addTiles(1)
- if(prob(1))
+ if(vocal && prob(1))
custom_emote(2, "makes an excited beeping sound!")
playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm
index 828ca72da0c..6592c37e0c2 100644
--- a/code/modules/mob/living/bot/medbot.dm
+++ b/code/modules/mob/living/bot/medbot.dm
@@ -312,7 +312,6 @@
declare_treatment = !declare_treatment
. = TRUE
-
/mob/living/bot/medbot/emag_act(var/remaining_uses, var/mob/user)
. = ..()
if(!emagged)
diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm
index fa0b76009f1..92cc55f7f06 100644
--- a/code/modules/mob/living/bot/mulebot.dm
+++ b/code/modules/mob/living/bot/mulebot.dm
@@ -70,17 +70,16 @@
ui.open()
/mob/living/bot/mulebot/tgui_data(mob/user)
- var/list/data = list(
- "suffix" = suffix,
- "power" = on,
- "issilicon" = issilicon(user),
- "load" = load,
- "locked" = locked,
- "auto_return" = auto_return,
- "crates_only" = crates_only,
- "hatch" = open,
- "safety" = safety,
- )
+ var/list/data = ..()
+ data["suffix"] = suffix
+ data["power"] = on
+ data["issillicon"] = issilicon(user)
+ data["load"] = load
+ data["locked"] = locked
+ data["auto_return"] = auto_return
+ data["crates_only"] = crates_only
+ data["hatch"] = open
+ data["safety"] = safety
return data
/mob/living/bot/mulebot/tgui_act(action, params)
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index 583b2d7af6a..9e2ce96412e 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -108,6 +108,7 @@
data["check_arrest"] = null
data["arrest_type"] = null
data["declare_arrests"] = null
+ data["bot_patrolling"] = null
data["will_patrol"] = null
if(!locked || issilicon(user))
@@ -116,8 +117,8 @@
data["check_arrest"] = check_arrest
data["arrest_type"] = arrest_type
data["declare_arrests"] = declare_arrests
- if(using_map.bot_patrolling)
- data["will_patrol"] = will_patrol
+ data["bot_patrolling"] = using_map.bot_patrolling
+ data["patrol"] = will_patrol
return data
@@ -127,7 +128,7 @@
/mob/living/bot/secbot/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
-
+
add_fingerprint(usr)
switch(action)
diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm
index 01f1d2f57d2..739c3b09c6b 100644
--- a/code/modules/mob/living/carbon/alien/diona/diona.dm
+++ b/code/modules/mob/living/carbon/alien/diona/diona.dm
@@ -1,3 +1,29 @@
+var/list/_nymph_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/bug_hiss,
+ /decl/emote/audible/bug_chitter,
+ /decl/emote/audible/chirp
+)
+
/mob/living/carbon/alien/diona
name = "diona nymph"
voice_name = "diona nymph"
@@ -20,6 +46,9 @@
holder_type = /obj/item/weapon/holder/diona
var/obj/item/hat
+/mob/living/carbon/alien/diona/get_default_emotes()
+ return global._nymph_default_emotes
+
/mob/living/carbon/alien/diona/Initialize()
. = ..()
species = GLOB.all_species[SPECIES_DIONA]
diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm
index 5cff048e10b..b0517e7a952 100644
--- a/code/modules/mob/living/carbon/alien/emote.dm
+++ b/code/modules/mob/living/carbon/alien/emote.dm
@@ -1,108 +1,31 @@
-/mob/living/carbon/alien/emote(var/act, var/m_type=1, var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_alien_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible,
+ /decl/emote/audible/deathgasp_alien,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/chirp
+)
- var/muzzled = is_muzzled()
- act = lowertext(act)
-
- switch(act)
- if("sign")
- if(!restrained())
- var/num = null
- if(text2num(param))
- num = "the number [text2num(param)]"
- if(num)
- message = "[src] signs [num]."
- m_type = 1
- if("burp")
- if(!muzzled)
- message = "[src] burps."
- m_type = 2
- if("deathgasp")
- message = "[src] lets out a waning guttural screech, green blood bubbling from its maw."
- m_type = 2
- if("scratch")
- if(!restrained())
- message = "[src] scratches."
- m_type = 1
- if("whimper")
- if(!muzzled)
- message = "[src] whimpers."
- m_type = 2
- if("tail")
- message = "[src] waves its tail."
- m_type = 1
- if("gasp")
- message = "[src] gasps."
- m_type = 2
- if("shiver")
- message = "[src] shivers."
- m_type = 2
- if("drool")
- message = "[src] drools."
- m_type = 1
- if("scretch")
- if(!muzzled)
- message = "[src] scretches."
- m_type = 2
- if("choke")
- message = "[src] chokes."
- m_type = 2
- if("moan")
- message = "[src] moans!"
- m_type = 2
- if("nod")
- message = "[src] nods its head."
- m_type = 1
-// if("sit")
-// message = "[src] sits down." //Larvan can't sit down, /N
-// m_type = 1
- if("sway")
- message = "[src] sways around dizzily."
- m_type = 1
- if("sulk")
- message = "[src] sulks down sadly."
- m_type = 1
- if("twitch")
- message = "[src] twitches."
- m_type = 1
- if("twitch_v")
- message = "[src] twitches violently."
- m_type = 1
- if("dance")
- if(!restrained())
- message = "[src] dances around happily."
- m_type = 1
- if("roll")
- if(!restrained())
- message = "[src] rolls."
- m_type = 1
- if("shake")
- message = "[src] shakes its head."
- m_type = 1
- if("gnarl")
- if(!muzzled)
- message = "[src] gnarls and shows its teeth.."
- m_type = 2
- if("jump")
- message = "[src] jumps!"
- m_type = 1
- if("hiss_")
- message = "[src] hisses softly."
- m_type = 1
- if("collapse")
- Paralyse(2)
- message = "[src] collapses!"
- m_type = 2
- if("chirp")
- message = "[src] chirps!"
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0)
- m_type = 2
- if("help")
- to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
-
- if(!stat)
- ..(act, m_type, message)
+/mob/living/carbon/alien/get_default_emotes()
+ . = global._alien_default_emotes
diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm
index 8b6e7f71756..687372c6ee1 100644
--- a/code/modules/mob/living/carbon/brain/death.dm
+++ b/code/modules/mob/living/carbon/brain/death.dm
@@ -3,7 +3,7 @@
container.icon_state = "mmi_dead"
return ..(gibbed,"beeps shrilly as the MMI flatlines!")
else
- return ..(gibbed,"no message")
+ return ..(gibbed, DEATHGASP_NO_MESSAGE)
/mob/living/carbon/brain/gib()
if(istype(container, /obj/item/device/mmi))
diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm
index 05706fe299e..cb6ed6a1b7b 100644
--- a/code/modules/mob/living/carbon/brain/emote.dm
+++ b/code/modules/mob/living/carbon/brain/emote.dm
@@ -1,47 +1,17 @@
-/mob/living/carbon/brain/emote(var/act,var/m_type=1,var/message = null)
- if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
- return
+var/list/_brain_default_emotes = list(
+ /decl/emote/audible/alarm,
+ /decl/emote/audible/alert,
+ /decl/emote/audible/notice,
+ /decl/emote/audible/whistle,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/beep,
+ /decl/emote/audible/boop,
+ /decl/emote/visible/blink,
+ /decl/emote/visible/flash
+)
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- act = copytext(act, 1, t1)
+/mob/living/carbon/brain/can_emote()
+ return (istype(container, /obj/item/device/mmi) && ..())
- if(stat == DEAD)
- return
- switch(act)
- if("alarm")
- to_chat(src, "You sound an alarm.")
- message = "[src] sounds an alarm."
- m_type = 2
- if("alert")
- to_chat(src, "You let out a distressed noise.")
- message = "[src] lets out a distressed noise."
- m_type = 2
- if("notice")
- to_chat(src, "You play a loud tone.")
- message = "[src] plays a loud tone."
- m_type = 2
- if("flash")
- message = "The lights on [src] flash quickly."
- m_type = 1
- if("blink")
- message = "[src] blinks."
- m_type = 1
- if("whistle")
- to_chat(src, "You whistle.")
- message = "[src] whistles."
- m_type = 2
- if("beep")
- to_chat(src, "You beep.")
- message = "[src] beeps."
- m_type = 2
- if("boop")
- to_chat(src, "You boop.")
- message = "[src] boops."
- m_type = 2
- if("help")
- to_chat(src, "alarm, alert, notice, flash, blink, whistle, beep, boop")
-
- if(!stat)
- ..(act, m_type, message)
-
\ No newline at end of file
+/mob/living/carbon/brain/get_default_emotes()
+ return global._brain_default_emotes
diff --git a/code/modules/mob/living/carbon/human/MedicalSideEffects.dm b/code/modules/mob/living/carbon/human/MedicalSideEffects.dm
index 91622f806df..9af29570741 100644
--- a/code/modules/mob/living/carbon/human/MedicalSideEffects.dm
+++ b/code/modules/mob/living/carbon/human/MedicalSideEffects.dm
@@ -127,7 +127,7 @@
if(11 to 30)
H.custom_pain("The muscles in your body cramp up painfully.",0)
if(31 to INFINITY)
- H.emote("me",1,"flinches as all the muscles in their body cramp up.")
+ H.custom_emote(VISIBLE_MESSAGE, "flinches as all the muscles in their body cramp up.")
H.custom_pain("There's pain all over your body.",1)
// ITCH
@@ -145,5 +145,5 @@
if(11 to 30)
H.custom_pain("You want to scratch your itch badly.",0)
if(31 to INFINITY)
- H.emote("me",1,"shivers slightly.")
+ H.custom_emote(VISIBLE_MESSAGE, "shivers slightly.")
H.custom_pain("This itch makes it really hard to concentrate.",1)
diff --git a/code/modules/mob/living/carbon/human/chem_side_effects.dm b/code/modules/mob/living/carbon/human/chem_side_effects.dm
index 91622f806df..9af29570741 100644
--- a/code/modules/mob/living/carbon/human/chem_side_effects.dm
+++ b/code/modules/mob/living/carbon/human/chem_side_effects.dm
@@ -127,7 +127,7 @@
if(11 to 30)
H.custom_pain("The muscles in your body cramp up painfully.",0)
if(31 to INFINITY)
- H.emote("me",1,"flinches as all the muscles in their body cramp up.")
+ H.custom_emote(VISIBLE_MESSAGE, "flinches as all the muscles in their body cramp up.")
H.custom_pain("There's pain all over your body.",1)
// ITCH
@@ -145,5 +145,5 @@
if(11 to 30)
H.custom_pain("You want to scratch your itch badly.",0)
if(31 to INFINITY)
- H.emote("me",1,"shivers slightly.")
+ H.custom_emote(VISIBLE_MESSAGE, "shivers slightly.")
H.custom_pain("This itch makes it really hard to concentrate.",1)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 6afe10cdec7..a705f034506 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -1,843 +1,140 @@
-/mob/living/carbon/human/emote(var/act,var/m_type=1,var/message = null)
- var/param = null
-
- var/datum/gender/T = gender_datums[get_visible_gender()]
-
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
-
- var/muzzled = is_muzzled()
- //var/m_type = 1
-
- for(var/obj/item/organ/O in organs)
- for(var/obj/item/weapon/implant/I in O)
- if(I.implanted)
- I.trigger(act, src)
-
- if(stat == DEAD && (act != "deathgasp"))
- return
-
- if(attempt_vr(src, "handle_emote_vr", list(act, m_type, message))) return //VOREStation Add - Custom Emote Handler
-
- switch(act)
- if("airguitar")
- if(!restrained())
- message = "is strumming the air and headbanging like a safari chimp."
- m_type = 1
-
- //Machine-only emotes
- if("ping", "beep", "buzz", "yes", "ye", "dwoop", "no", "rcough", "rsneeze")
-
- if(!isSynthetic())
- to_chat(src, "You are not a synthetic.")
- return
-
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- var/display_msg = "beeps"
- var/use_sound = 'sound/machines/twobeep.ogg'
- if(act == "buzz")
- display_msg = "buzzes"
- use_sound = 'sound/machines/buzz-sigh.ogg'
- else if(act == "ping")
- display_msg = "pings"
- use_sound = 'sound/machines/ping.ogg'
- else if(act == "yes" || act == "ye")
- display_msg = "emits an affirmative blip"
- use_sound = 'sound/machines/synth_yes.ogg'
- else if(act == "dwoop")
- display_msg = "chirps happily"
- use_sound = 'sound/machines/dwoop.ogg'
- else if(act == "no")
- display_msg = "emits a negative blip"
- use_sound = 'sound/machines/synth_no.ogg'
- else if(act == "rcough")
- display_msg = "emits a robotic cough"
- if(get_gender() == FEMALE)
- use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
- else
- use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
- else if(act == "rsneeze")
- display_msg = "emits a robotic sneeze"
- if(get_gender() == FEMALE)
- use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
- else
- use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
-
- if(param)
- message = "[display_msg] at [param]."
- else
- message = "[display_msg]."
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- m_type = 1
-
- //Promethean-only emotes
- if("squish")
- /* VOREStation Removal Start - Eh. People can squish maybe.
- if(species.bump_flag != SLIME) //This should definitely do it.
- to_chat(src, "You are not a slime thing!")
- return
- */ //VOREStation Removal End
- playsound(src, 'sound/effects/slime_squish.ogg', 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add //Credit to DrMinky (freesound.org) for the sound.
- message = "squishes."
- m_type = 1
-
- if("chirp")
- /* VOREStation Removal Start - Eh. People can chirp maybe.
- if ((species.bump_flag != SLIME) && (species.name != SPECIES_DIONA))
- to_chat(src, "You are not a diona or slime!")
- return
- */ //VOREStation Removal End
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0)
- message = "chirps."
- m_type = 2
-
- //Skrell-only emotes
- if("warble")
- if(species.name != SPECIES_SKRELL)
- to_chat(src, "You are not a Skrell!")
- return
-
- playsound(src, 'sound/effects/warble.ogg', 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add // Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
- message = "warbles."
- m_type = 2
-
- if("blink")
- message = "blinks."
- m_type = 1
-
- if("blink_r")
- message = "blinks rapidly."
- m_type = 1
-
- if("bow")
- if(!buckled)
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "bows to [param]."
- else
- message = "bows."
- m_type = 1
-
- if("custom")
- var/input = sanitize(input("Choose an emote to display.") as text|null)
- if(!input)
- return
- var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
- if(input2 == "Visible")
- m_type = 1
- else if(input2 == "Hearable")
- if(miming)
- return
- m_type = 2
- else
- alert("Unable to use this emote, must be either hearable or visible.")
- return
- return custom_emote(m_type, input)
-
- if("me")
-
- //if(silent && silent > 0 && findtext(message,"\"",1, null) > 0)
- // return //This check does not work and I have no idea why, I'm leaving it in for reference.
-
- if(client)
- if(client.prefs.muted & MUTE_IC)
- to_chat(src, "You cannot send IC messages (muted).")
- return
- if(stat)
- return
- if(!(message))
- return
- return custom_emote(m_type, message)
-
- if("salute")
- if(!buckled)
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "salutes to [param]."
- else
- message = "salutes."
- m_type = 1
-
- if("choke")
- if(miming)
- message = "clutches [T.his] throat desperately!"
- m_type = 1
- else
- if(!muzzled)
- message = "chokes!"
- m_type = 2
- else
- message = "makes a strong noise."
- m_type = 2
-
- if("clap")
- if(!restrained())
- message = "claps."
- playsound(src, 'sound/misc/clapping.ogg')
- m_type = 2
- if(miming)
- m_type = 1
-
- if("flap")
- if(!restrained())
- message = "flaps [T.his] wings."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("aflap")
- if(!restrained())
- message = "flaps [T.his] wings ANGRILY!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("drool")
- message = "drools."
- m_type = 1
-
- if("eyebrow")
- message = "raises an eyebrow."
- m_type = 1
-
- if("chuckle")
- if(miming)
- message = "appears to chuckle."
- m_type = 1
- else
- if(!muzzled)
- message = "chuckles."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("twitch")
- message = "twitches."
- m_type = 1
-
- if("twitch_v")
- message = "twitches violently."
- m_type = 1
-
- if("faint")
- message = "faints."
- if(sleeping)
- return //Can't faint while asleep
- Sleeping(10)
- m_type = 1
-
- if("cough", "coughs")
- if(miming)
- message = "appears to cough!"
- m_type = 1
- else
- if(!muzzled)
- var/robotic = 0
- m_type = 2
- if(should_have_organ(O_LUNGS))
- var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
- if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
- robotic = 1
- if(!robotic && !isSynthetic())
- message = "coughs!"
- if(get_gender() == FEMALE)
- if(species.female_cough_sounds)
- playsound(src, pick(species.female_cough_sounds), 120, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- if(species.male_cough_sounds)
- playsound(src, pick(species.male_cough_sounds), 120, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "emits a robotic cough"
- var/use_sound
- if(get_gender() == FEMALE)
- use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
- else
- use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "makes a strong noise."
- m_type = 2
-
- if("frown")
- message = "frowns."
- m_type = 1
-
- if("nod")
- message = "nods."
- m_type = 1
-
- if("blush")
- message = "blushes."
- m_type = 1
-
- if("wave")
- message = "waves."
- m_type = 1
-
- if("gasp")
- if(miming)
- message = "appears to be gasping!"
- m_type = 1
- else
- if(!muzzled)
- message = "gasps!"
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("deathgasp")
- message = "[species.get_death_message()]"
- m_type = 1
-
- if("giggle")
- if(miming)
- message = "giggles silently!"
- m_type = 1
- else
- if(!muzzled)
- message = "giggles."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("glare")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "glares at [param]."
- else
- message = "glares."
-
- if("stare")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "stares at [param]."
- else
- message = "stares."
-
- if("look")
- var/M = null
- if(param)
- for(var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- param = null
-
- if(param)
- message = "looks at [param]."
- else
- message = "looks."
- m_type = 1
-
- if("grin")
- message = "grins."
- m_type = 1
-
- if("cry")
- if(miming)
- message = "cries."
- m_type = 1
- else
- if(!muzzled)
- message = "cries."
- m_type = 2
- else
- message = "makes a weak noise. [T.he] [get_visible_gender() == NEUTER ? "frown" : "frowns"]." // no good, non-unwieldy alternative to this ternary at the moment
- m_type = 2
-
- if("sigh")
- if(miming)
- message = "sighs."
- m_type = 1
- else
- if(!muzzled)
- message = "sighs."
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("laugh")
- if(miming)
- message = "acts out a laugh."
- m_type = 1
- else
- if(!muzzled)
- message = "laughs."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("mumble")
- message = "mumbles!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("grumble")
- if(miming)
- message = "grumbles!"
- m_type = 1
- if(!muzzled)
- message = "grumbles!"
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("groan")
- if(miming)
- message = "appears to groan!"
- m_type = 1
- else
- if(!muzzled)
- message = "groans!"
- m_type = 2
- else
- message = "makes a loud noise."
- m_type = 2
-
- if("moan")
- if(miming)
- message = "appears to moan!"
- m_type = 1
- else
- message = "moans!"
- m_type = 2
-
- if("johnny")
- var/M
- if(param)
- M = param
- if(!M)
- param = null
- else
- if(miming)
- message = "takes a drag from a cigarette and blows \"[M]\" out in smoke."
- m_type = 1
- else
- message = "says, \"[M], please. He had a family.\" [name] takes a drag from a cigarette and blows his name out in smoke."
- m_type = 2
-
- if("point")
- if(!restrained())
- var/mob/M = null
- if(param)
- for(var/atom/A as mob|obj|turf|area in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- message = "points."
- else
- pointed(M)
-
- if(M)
- message = "points to [M]."
- else
- m_type = 1
-
- if("crack")
- if(!restrained())
- message = "cracks [T.his] knuckles."
- playsound(src, 'sound/voice/knuckles.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- m_type = 1
-
- if("raise")
- if(!restrained())
- message = "raises a hand."
- m_type = 1
-
- if("shake")
- message = "shakes [T.his] head."
- m_type = 1
-
- if("shrug")
- message = "shrugs."
- m_type = 1
-
- if("signal")
- if(!restrained())
- var/t1 = round(text2num(param))
- if(isnum(t1))
- if(t1 <= 5 && (!r_hand || !l_hand))
- message = "raises [t1] finger\s."
- else if(t1 <= 10 && (!r_hand && !l_hand))
- message = "raises [t1] finger\s."
- m_type = 1
-
- if("smile")
- message = "smiles."
- m_type = 1
-
- if("shiver")
- message = "shivers."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("pale")
- message = "goes pale for a second."
- m_type = 1
-
- if("tremble")
- message = "trembles in fear!"
- m_type = 1
-
- if("sneeze", "sneezes")
- if(miming)
- message = "sneezes."
- m_type = 1
- else
- if(!muzzled)
- var/robotic = 0
- m_type = 2
- if(should_have_organ(O_LUNGS))
- var/obj/item/organ/internal/lungs/L = internal_organs_by_name[O_LUNGS]
- if(L && L.robotic == 2) //Hard-coded to 2, incase we add lifelike robotic lungs
- robotic = 1
- if(!robotic && !isSynthetic())
- message = "sneezes."
- if(get_gender() == FEMALE)
- playsound(src, species.female_sneeze_sound, 70, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- playsound(src, species.male_sneeze_sound, 70, preference = /datum/client_preference/emote_noises) //VOREStation Add
- m_type = 2
- else
- message = "emits a robotic sneeze"
- var/use_sound
- if(get_gender() == FEMALE)
- use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
- else
- use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
- playsound(src, use_sound, 50, 0, preference = /datum/client_preference/emote_noises) //VOREStation Add
- else
- message = "makes a strange noise."
- m_type = 2
-
- if("sniff")
- message = "sniffs."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("snore")
- if(miming)
- message = "sleeps soundly."
- m_type = 1
- else
- if(!muzzled)
- message = "snores."
- m_type = 2
- else
- message = "makes a noise."
- m_type = 2
-
- if("whimper")
- if(miming)
- message = "appears hurt."
- m_type = 1
- else
- if(!muzzled)
- message = "whimpers."
- m_type = 2
- else
- message = "makes a weak noise."
- m_type = 2
-
- if("wink")
- message = "winks."
- m_type = 1
-
- if("yawn")
- if(!muzzled)
- message = "yawns."
- m_type = 2
- if(miming)
- m_type = 1
-
- if("collapse")
- Paralyse(2)
- message = "collapses!"
- m_type = 2
- if(miming)
- m_type = 1
-
- if("hug")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M == src)
- M = null
-
- if(M)
- message = "hugs [M]."
- else
- message = "hugs [T.himself]."
-
- if("handshake")
- m_type = 1
- if(!restrained() && !r_hand)
- var/mob/living/M = null
- if(param)
- for(var/mob/living/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M == src)
- M = null
-
- if(M)
- if(M.canmove && !M.r_hand && !M.restrained())
- message = "shakes hands with [M]."
- else
- message = "holds out [T.his] hand to [M]."
-
- if("dap")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M)
- message = "gives daps to [M]."
- else
- message = "sadly can't find anybody to give daps to, and daps [T.himself]. Shameful."
-
- if("slap", "slaps")
- m_type = 1
- if(!restrained())
- var/M = null
- if(param)
- for(var/mob/A in view(1, null))
- if(param == A.name)
- M = A
- break
- if(M)
- message = "slaps [M] across the face. Ouch!"
- playsound(src, 'sound/effects/snap.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //VOREStation Add
- if(ishuman(M)) //Snowflakey!
- var/mob/living/carbon/human/H = M
- if(istype(H.wear_mask,/obj/item/clothing/mask/smokable))
- H.drop_from_inventory(H.wear_mask)
- else
- message = "slaps [T.himself]!"
- playsound(src, 'sound/effects/snap.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //VOREStation Add
-
- if("scream", "screams")
- if(miming)
- message = "acts out a scream!"
- m_type = 1
- else
- if(!muzzled)
- message = "[species.scream_verb]!"
- m_type = 2
- /* Removed, pending the location of some actually good, properly licensed sounds.
- if(get_gender() == FEMALE)
- playsound(src, "[species.female_scream_sound]", 80, 1)
- else
- playsound(src, "[species.male_scream_sound]", 80, 1) //default to male screams if no gender is present.
- */
- else
- message = "makes a very loud noise."
- m_type = 2
-
- if("snap", "snaps")
- m_type = 2
- var/mob/living/carbon/human/H = src
- var/obj/item/organ/external/L = H.get_organ("l_hand")
- var/obj/item/organ/external/R = H.get_organ("r_hand")
- var/left_hand_good = 0
- var/right_hand_good = 0
- if(L && (!(L.status & ORGAN_DESTROYED)) && (!(L.splinted)) && (!(L.status & ORGAN_BROKEN)))
- left_hand_good = 1
- if(R && (!(R.status & ORGAN_DESTROYED)) && (!(R.splinted)) && (!(R.status & ORGAN_BROKEN)))
- right_hand_good = 1
-
- if(!left_hand_good && !right_hand_good)
- to_chat(usr, "You need at least one hand in good working order to snap your fingers.")
- return
-
- message = "snaps [T.his] fingers."
- playsound(src, 'sound/effects/fingersnap.ogg', 50, 1, -3, preference = /datum/client_preference/emote_noises) //VOREStation Add
-
- if("swish")
- animate_tail_once()
-
- if("wag", "sway")
- animate_tail_start()
-
- if("qwag", "fastsway")
- animate_tail_fast()
-
- if("swag", "stopsway")
- animate_tail_stop()
-
- if("vomit")
- if(isSynthetic())
- to_chat(src, "You are unable to vomit.")
- return
- vomit()
- return
-
- if("whistle" || "whistles")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles a tune."
- playsound(src, 'sound/voice/longwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises) //praying this doesn't get abused
- else
- message = "whistles a robotic tune."
- playsound(src, 'sound/voice/longwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("qwhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles quietly."
- playsound(src, 'sound/voice/shortwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "whistles robotically."
- playsound(src, 'sound/voice/shortwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("wwhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "whistles inappropriately."
- playsound(src, 'sound/voice/wolfwhistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "beeps inappropriately."
- playsound(src, 'sound/voice/wolfwhistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("swhistle")
- if(!muzzled)
- if(!isSynthetic())
- message = "summon whistles."
- playsound(src, 'sound/voice/summon_whistle.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "summon whistles robotically."
- playsound(src, 'sound/voice/summon_whistle_robot.ogg', 50, 1, preference = /datum/client_preference/emote_noises)
- else
- message = "makes a light spitting noise, a poor attempt at a whistle."
-
- if("flip")
- m_type = 1
- if (!src.restrained())
- //message = "performs an amazing, gravity-defying backflip before landing skillfully back to the ground."
- playsound(src.loc, 'sound/effects/bodyfall4.ogg', 50, 1)
- src.SpinAnimation(7,1)
- else
- to_chat(usr, "You can't quite do something as difficult as a backflip while so... restricted.")
-
- if("spin")
- m_type = 1
- if (!src.restrained())
- //message = "spins in a dance smoothly on their feet. Wow!"
- src.spin(20, 1)
- else
- to_chat(usr, "You can't quite do something as difficult as a spin while so... restricted.")
-
- if("floorspin")
- m_type = 1
- if (!src.restrained())
- //message = "gets down on the floor and spins their entire body around!"
- spawn(0)
- for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
- set_dir(i)
- sleep(1)
- src.SpinAnimation(20,1)
- else
- to_chat(usr, "You can't quite do something as difficult as a spin while so... restricted.")
-
- if("sidestep")
- m_type = 1
- if (!src.restrained())
- //message = "steps rhymatically and conservatively as they move side to side."
- playsound(src.loc, 'sound/effects/bodyfall4.ogg', 50, 1)
- var/default_pixel_x = initial(pixel_x)
- var/default_pixel_y = initial(pixel_y)
- default_pixel_x = src.default_pixel_x
- default_pixel_y = src.default_pixel_y
-
- animate(src, pixel_x = 5, time = 20)
- sleep(3)
- animate(src, pixel_x = -5, time = 20)
- animate(pixel_x = default_pixel_x, pixel_y = default_pixel_y, time = 2)
- else
- to_chat(usr, "Sidestepping sure seems unachieveable when you're this restricted.")
-
- if("help")
- to_chat(src, "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
- frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
- qwhistle, raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, swhistle, \
- tremble, twitch, twitch_v, vomit, whimper, wink, whistle, wwhistle, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble")
-
- else
- to_chat(src, "Unusable emote '[act]'. Say *help or *vhelp for a list.") //VOREStation Edit, mention *vhelp for Virgo-specific emotes located in emote_vr.dm.
-
- if(message)
- custom_emote(m_type,message)
+var/list/_human_default_emotes = list(
+ /decl/emote/visible/blink,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/sneeze,
+ /decl/emote/audible/sniff,
+ /decl/emote/audible/snore,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/whistle,
+ /decl/emote/audible/whistle/quiet,
+ /decl/emote/audible/whistle/wolf,
+ /decl/emote/audible/whistle/summon,
+ /decl/emote/audible/yawn,
+ /decl/emote/audible/clap,
+ /decl/emote/audible/chuckle,
+ /decl/emote/audible/cough,
+ /decl/emote/audible/cry,
+ /decl/emote/audible/sigh,
+ /decl/emote/audible/laugh,
+ /decl/emote/audible/mumble,
+ /decl/emote/audible/grumble,
+ /decl/emote/audible/groan,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/grunt,
+ /decl/emote/audible/slap,
+ /decl/emote/audible/crack,
+ /decl/emote/human,
+ /decl/emote/human/deathgasp,
+ /decl/emote/audible/giggle,
+ /decl/emote/audible/scream,
+ /decl/emote/visible/airguitar,
+ /decl/emote/visible/blink_r,
+ /decl/emote/visible/bow,
+ /decl/emote/visible/salute,
+ /decl/emote/visible/flap,
+ /decl/emote/visible/aflap,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/eyebrow,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/faint,
+ /decl/emote/visible/frown,
+ /decl/emote/visible/blush,
+ /decl/emote/visible/wave,
+ /decl/emote/visible/glare,
+ /decl/emote/visible/stare,
+ /decl/emote/visible/look,
+ /decl/emote/visible/point,
+ /decl/emote/visible/raise,
+ /decl/emote/visible/grin,
+ /decl/emote/visible/shrug,
+ /decl/emote/visible/smile,
+ /decl/emote/visible/pale,
+ /decl/emote/visible/tremble,
+ /decl/emote/visible/wink,
+ /decl/emote/visible/hug,
+ /decl/emote/visible/dap,
+ /decl/emote/visible/signal,
+ /decl/emote/visible/handshake,
+ /decl/emote/visible/afold,
+ /decl/emote/visible/alook,
+ /decl/emote/visible/eroll,
+ /decl/emote/visible/hbow,
+ /decl/emote/visible/hip,
+ /decl/emote/visible/holdup,
+ /decl/emote/visible/hshrug,
+ /decl/emote/visible/crub,
+ /decl/emote/visible/erub,
+ /decl/emote/visible/fslap,
+ /decl/emote/visible/ftap,
+ /decl/emote/visible/hrub,
+ /decl/emote/visible/hspread,
+ /decl/emote/visible/pocket,
+ /decl/emote/visible/rsalute,
+ /decl/emote/visible/rshoulder,
+ /decl/emote/visible/squint,
+ /decl/emote/visible/tfist,
+ /decl/emote/visible/tilt,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/snap,
+ /decl/emote/visible/vomit,
+ /decl/emote/visible/floorspin,
+ /decl/emote/visible/flip,
+ //VOREStation Add
+ /decl/emote/audible/awoo,
+ /decl/emote/audible/awoo2,
+ /decl/emote/audible/growl,
+ /decl/emote/audible/woof,
+ /decl/emote/audible/woof2,
+ /decl/emote/audible/nya,
+ /decl/emote/audible/mrowl,
+ /decl/emote/audible/peep,
+ /decl/emote/audible/chirp,
+ /decl/emote/audible/hoot,
+ /decl/emote/audible/weh,
+ /decl/emote/audible/merp,
+ /decl/emote/audible/myarp,
+ /decl/emote/audible/bark,
+ /decl/emote/audible/bork,
+ /decl/emote/audible/mrow,
+ /decl/emote/audible/hypno,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/rattle,
+ /decl/emote/audible/squeak,
+ /decl/emote/audible/geck,
+ /decl/emote/audible/baa,
+ /decl/emote/audible/baa2,
+ /decl/emote/audible/mar,
+ /decl/emote/audible/wurble,
+ /decl/emote/audible/snort,
+ /decl/emote/audible/meow,
+ /decl/emote/audible/moo,
+ /decl/emote/audible/croak,
+ /decl/emote/audible/gao,
+ /decl/emote/audible/cackle,
+
+ /decl/emote/visible/mlem,
+ /decl/emote/visible/blep,
+
+ /decl/emote/helper/vwag,
+ /decl/emote/helper/vflap
+ //VOREStation Add End
+)
+
+/mob/living/carbon/human/get_default_emotes()
+ return global._human_default_emotes
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
diff --git a/code/modules/mob/living/carbon/human/emote_vr.dm b/code/modules/mob/living/carbon/human/emote_vr.dm
index d8deee8e7bf..f4bc98bcbe6 100644
--- a/code/modules/mob/living/carbon/human/emote_vr.dm
+++ b/code/modules/mob/living/carbon/human/emote_vr.dm
@@ -1,185 +1,11 @@
-/mob
- var/nextemote = 1
+/mob/living/carbon/human/verb/toggle_resizing_immunity()
+ set name = "Toggle Resizing Immunity"
+ set desc = "Toggles your ability to resist resizing attempts"
+ set category = "IC"
-/mob/living/carbon/human/proc/handle_emote_vr(var/act,var/m_type=1,var/message = null)
- //Reduces emote spamming
- if(nextemote >= world.time)// || user.stat != CONSCIOUS
- return 1
- nextemote = world.time + 12
+ resizable = !resizable
+ to_chat(src, "You are now [resizable ? "susceptible" : "immune"] to being resized.")
- switch(act)
- if("vwag")
- if(toggle_tail(message = 1))
- m_type = 1
- message = "[wagging ? "starts" : "stops"] wagging their tail."
- else
- return 1
- if("vflap")
- if(toggle_wing(message = 1))
- m_type = 1
- message = "[flapping ? "starts" : "stops"] flapping their wings."
- else
- return 1
- if("mlem")
- message = "mlems [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] tongue up over [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] nose. Mlem."
- m_type = 1
- if("blep")
- message = "bleps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] tongue out. Blep."
- m_type = 1
- if("awoo")
- m_type = 2
- message = "lets out an awoo."
- playsound(src, 'sound/voice/awoo.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("awoo2")
- m_type = 2
- message = "lets out an awoo."
- playsound(src, 'sound/voice/long_awoo.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("growl")
- m_type = 2
- message = "lets out a growl."
- playsound(src, 'sound/voice/growl.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("woof")
- m_type = 2
- message = "lets out a woof."
- playsound(src, 'sound/voice/woof.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("woof2")
- m_type = 2
- message = "lets out a woof."
- playsound(src, 'sound/voice/woof2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("nya")
- message = "lets out a nya."
- m_type = 2
- playsound(src, 'sound/voice/nya.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("mrowl")
- message = "mrowls."
- m_type = 2
- playsound(src, 'sound/voice/mrow.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("peep")
- message = "peeps like a bird."
- m_type = 2
- playsound(src, 'sound/voice/peep.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("chirp")
- message = "chirps!"
- playsound(src, 'sound/misc/nymphchirp.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- m_type = 2
- if("hoot")
- message = "hoots!"
- playsound(src, 'sound/voice/hoot.ogg', 50, 1, ,-1, preference = /datum/client_preference/emote_noises)
- m_type = 2
- if("weh")
- message = "lets out a weh."
- m_type = 2
- playsound(src, 'sound/voice/weh.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("merp")
- message = "lets out a merp."
- m_type = 2
- playsound(src, 'sound/voice/merp.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("myarp")
- message = "lets out a myarp."
- m_type = 2
- playsound(src, 'sound/voice/myarp.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("bark")
- message = "lets out a bark."
- m_type = 2
- playsound(src, 'sound/voice/bark2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("bork")
- m_type = 2
- message = "lets out a bork."
- playsound(src, 'sound/voice/bork.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if ("mrow")
- m_type = 2
- message = "lets out a mrow."
- playsound(src, 'sound/voice/mrow.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if ("hypno")
- m_type = 2
- message = "lets out a mystifying tone."
- playsound(src, 'sound/voice/hypno.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("hiss")
- message = "lets out a hiss."
- m_type = 2
- playsound(src, 'sound/voice/hiss.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("rattle")
- message = "rattles!"
- m_type = 2
- playsound(src, 'sound/voice/rattle.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("squeak")
- message = "lets out a squeak."
- m_type = 2
- playsound(src, 'sound/effects/mouse_squeak.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("geck")
- message = "geckers!"
- m_type = 2
- playsound(src, 'sound/voice/geck.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("baa")
- message = "lets out a baa."
- m_type = 2
- playsound(src, 'sound/voice/baa.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("baa2")
- message = "bleats."
- m_type = 2
- playsound(src, 'sound/voice/baa2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("deathgasp2")
- message = "[species.get_death_message()]"
- m_type = 1
- playsound(src, 'sound/voice/deathgasp2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("mar")
- message = "lets out a mar."
- m_type = 2
- playsound(src, 'sound/voice/mar.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("wurble")
- message = "lets out a wurble."
- m_type = 2
- playsound(src, 'sound/voice/wurble.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- if("snort")
- message = "snorts!"
- m_type = 2
- playsound(src, 'sound/voice/Snort.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("meow")
- message = "gently meows!"
- m_type = 2
- playsound(src, 'sound/voice/Meow.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("moo")
- message = "takes a breath and lets out a moo."
- m_type = 2
- playsound(src, 'sound/voice/Moo.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("croak")
- message = "rumbles their throat, puffs their cheeks and croaks."
- m_type = 2
- playsound(src, 'sound/voice/Croak.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("gao")
- message = "lets out a gao."
- m_type = 2
- playsound(src, 'sound/voice/gao.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("cackle")
- message = "cackles hysterically!"
- m_type = 2
- playsound(src, 'sound/voice/YeenCackle.ogg', 50, 0, preference = /datum/client_preference/emote_noises)
- if("nsay")
- nsay()
- return TRUE
- if("nme")
- nme()
- return TRUE
- if("flip")
- var/list/involved_parts = list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
- //Check if they are physically capable
- if(sleeping || resting || buckled || weakened || restrained() || involved_parts.len < 2)
- to_chat(src, "You can't *flip in your current state!")
- return 1
- else
- nextemote += 12 //Double delay
- handle_flip_vr()
- message = "does a flip!"
- m_type = 1
- if("vhelp") //Help for Virgo-specific emotes.
- to_chat(src, "vwag, vflap, mlem, blep, awoo, awoo2, growl, nya, peep, chirp, hoot, weh, merp, myarp, bark, bork, mrow, mrowl, hypno, hiss, rattle, squeak, geck, baa, baa2, mar, wurble, snort, meow, moo, croak, gao, cackle, nsay, nme, flip")
- return TRUE
-
- if(message)
- custom_emote(m_type,message)
- return TRUE
-
- return FALSE
/mob/living/carbon/human/proc/handle_flip_vr()
var/original_density = density
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b351c3d79be..1cb3adaa28d 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -53,6 +53,7 @@
sync_organ_dna()
//verbs |= /mob/living/proc/toggle_selfsurgery //VOREStation Removal
+ AddComponent(/datum/component/personal_crafting)
/mob/living/carbon/human/Destroy()
human_mob_list -= src
@@ -1162,6 +1163,9 @@
//A slew of bits that may be affected by our species change
regenerate_icons()
+ // Update our available emote list.
+ update_emotes()
+
if(species)
//if(mind) //VOREStation Removal
//apply_traits() //VOREStation Removal
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 0199d387ae5..cdfef35b596 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -69,10 +69,10 @@ emp_act
drop_from_inventory(c_hand)
if (affected.robotic >= ORGAN_ROBOT)
- emote("me", 1, "drops what they were holding, their [affected.name] malfunctioning!")
+ custom_emote(VISIBLE_MESSAGE, "drops what they were holding, their [affected.name] malfunctioning!")
else
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
- emote("me", 1, "[affected.organ_can_feel_pain() ? "" : emote_scream] drops what they were holding in their [affected.name]!")
+ custom_emote(VISIBLE_MESSAGE, "[affected.organ_can_feel_pain() ? "" : emote_scream] drops what they were holding in their [affected.name]!")
..(stun_amount, agony_amount, def_zone)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 34b93b25738..15ea6a45542 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -81,7 +81,6 @@
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
- var/miming = null //Toggle for the mime's abilities.
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
@@ -156,4 +155,3 @@
// Custom Species Name
var/custom_species
-
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 6795d670647..c0360d3297a 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -98,7 +98,8 @@
// This is the 'mechanical' check for synthetic-ness, not appearance
// Returns the company that made the synthetic
/mob/living/carbon/human/isSynthetic()
- if(synthetic) return synthetic //Your synthetic-ness is not going away
+ if(synthetic)
+ return synthetic //Your synthetic-ness is not going away
var/obj/item/organ/external/T = organs_by_name[BP_TORSO]
if(T && T.robotic >= ORGAN_ROBOT)
src.verbs += /mob/living/carbon/human/proc/self_diagnostics
@@ -106,9 +107,9 @@
src.verbs += /mob/living/carbon/human/proc/setmonitor_state
var/datum/robolimb/R = all_robolimbs[T.model]
synthetic = R
+ update_emotes()
return synthetic
-
- return 0
+ return FALSE
// Would an onlooker know this person is synthetic?
// Based on sort of logical reasoning, 'Look at head, look at torso'
diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm
index 4637bde1bd2..f9c9bc831d1 100644
--- a/code/modules/mob/living/carbon/human/human_organs.dm
+++ b/code/modules/mob/living/carbon/human/human_organs.dm
@@ -164,7 +164,7 @@
drop_from_inventory(r_hand)
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
- emote("me", 1, "[(can_feel_pain()) ? "" : emote_scream ]drops what they were holding in their [E.name]!")
+ custom_emote(VISIBLE_MESSAGE, "[(can_feel_pain()) ? "" : emote_scream ]drops what they were holding in their [E.name]!")
else if(E.is_malfunctioning())
switch(E.body_part)
@@ -177,7 +177,7 @@
continue
drop_from_inventory(r_hand)
- emote("me", 1, "drops what they were holding, their [E.name] malfunctioning!")
+ custom_emote(VISIBLE_MESSAGE, "drops what they were holding, their [E.name] malfunctioning!")
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 286c257b972..767d68a56e7 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1556,7 +1556,7 @@
if(shock_stage >= 30)
if(shock_stage == 30 && !isbelly(loc)) //VOREStation Edit
- emote("me",1,"is having trouble keeping their eyes open.")
+ custom_emote(VISIBLE_MESSAGE, "is having trouble keeping their eyes open.")
eye_blurry = max(2, eye_blurry)
stuttering = max(stuttering, 5)
@@ -1565,7 +1565,7 @@
if (shock_stage >= 60)
if(shock_stage == 60 && !isbelly(loc)) //VOREStation Edit
- emote("me",1,"'s body becomes limp.")
+ custom_emote(VISIBLE_MESSAGE, "'s body becomes limp.")
if (prob(2))
to_chat(src, "[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!")
Weaken(20)
@@ -1582,7 +1582,7 @@
if(shock_stage == 150)
if(!isbelly(loc)) //VOREStation Edit
- emote("me",1,"can no longer stand, collapsing!")
+ custom_emote(VISIBLE_MESSAGE, "can no longer stand, collapsing!")
Weaken(20)
if(shock_stage >= 150)
diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
index b29bead4f9c..e8ff96175a7 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
@@ -25,7 +25,8 @@
speech_sounds = list('sound/voice/shriek1.ogg')
speech_chance = 20
- scream_verb = "shrieks"
+ scream_verb_1p = "shriek"
+ scream_verb_3p = "shrieks"
male_scream_sound = 'sound/voice/shriek1.ogg'
female_scream_sound = 'sound/voice/shriek1.ogg'
male_cough_sounds = list('sound/voice/shriekcough.ogg')
@@ -86,7 +87,11 @@
/datum/mob_descriptor/height = -1,
/datum/mob_descriptor/build = 1,
/datum/mob_descriptor/vox_markings = 0
- )
+ )
+
+ default_emotes = list(
+ /decl/emote/audible/vox_shriek
+ )
/datum/species/vox/get_random_name(var/gender)
var/datum/language/species_language = GLOB.all_languages[default_language]
diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
index 73c182dfadd..7f16315e851 100644
--- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
+++ b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_trait.dm
@@ -2,7 +2,7 @@
allowed_species = list(SPECIES_SHADEKIN)
var/color = BLUE_EYES
name = "Shadekin Blue Adaptation"
- desc = "Makes your shadekin adapted as a Blue eyed kin! This gives you decreased energy regeneration in darkness, decreased regeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Blue eyed kin! This gives you decreased energy regeneration in darkness, decreased regeneration in the light and unchanged health!"
cost = 0
var_changes = list( "total_health" = 100,
"energy_light" = 0.5,
@@ -13,7 +13,7 @@
/datum/trait/kintype/red
name = "Shadekin Red Adaptation"
color = RED_EYES
- desc = "Makes your shadekin adapted as a Red eyed kin! This gives you minimal energy regeneration in darkness, moderate regeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Red eyed kin! This gives you minimal energy regeneration in darkness, moderate degeneration in the light and increased health!"
var_changes = list( "total_health" = 200,
"energy_light" = -1,
"energy_dark" = 0.1,
@@ -22,37 +22,37 @@
/datum/trait/kintype/purple
name = "Shadekin Purple Adaptation"
color = PURPLE_EYES
- desc = "Makes your shadekin adapted as a Purple eyed kin! This gives you moderate energy regeneration in darkness, minor degeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Purple eyed kin! This gives you moderate energy regeneration in darkness, minor degeneration in the light and increased health!"
var_changes = list( "total_health" = 150,
- "energy_light" = 1,
- "energy_dark" = -0.5,
+ "energy_light" = -0.5,
+ "energy_dark" = 1,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/yellow
name = "Shadekin Yellow Adaptation"
color = YELLOW_EYES
- desc = "Makes your shadekin adapted as a Yellow eyed kin! This gives you the highest energy regeneration in darkness, high degeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Yellow eyed kin! This gives you the highest energy regeneration in darkness, high degeneration in the light and unchanged health!"
var_changes = list( "total_health" = 100,
- "energy_light" = 3,
- "energy_dark" = -2,
+ "energy_light" = -2,
+ "energy_dark" = 3,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/green
name = "Shadekin Green Adaptation"
color = GREEN_EYES
- desc = "Makes your shadekin adapted as a Green eyed kin! This gives you high energy regeneration in darkness, minor regeneration in the light amd unchanged health!"
+ desc = "Makes your shadekin adapted as a Green eyed kin! This gives you high energy regeneration in darkness, minor regeneration in the light and unchanged health!"
var_changes = list( "total_health" = 100,
- "energy_light" = 2,
- "energy_dark" = 0.125,
+ "energy_light" = 0.125,
+ "energy_dark" = 2,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/orange
name = "Shadekin Orange Adaptation"
color = ORANGE_EYES
- desc = "Makes your shadekin adapted as a Orange eyed kin! This gives you minor energy regeneration in darkness, modeate degeneration in the light amd increased health!"
+ desc = "Makes your shadekin adapted as a Orange eyed kin! This gives you minor energy regeneration in darkness, moderate degeneration in the light and increased health!"
var_changes = list( "total_health" = 175,
- "energy_light" = 0.25,
- "energy_dark" = -0.5,
+ "energy_light" = -0.5,
+ "energy_dark" = 0.25,
"unarmed_types" = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin,/datum/unarmed_attack/shadekinharmbap))
/datum/trait/kintype/apply(var/datum/species/shadekin/S,var/mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 80ad0763e27..3ae68b2c7d8 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -75,7 +75,8 @@
var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) //VOREStation Edit
//Soundy emotey things.
- var/scream_verb = "screams"
+ var/scream_verb_1p = "scream"
+ var/scream_verb_3p = "screams"
var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace!
var/female_scream_sound //= 'sound/goonstation/voice/female_scream.ogg' Removed due to licensing, replace!
var/male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
diff --git a/code/modules/mob/living/carbon/human/species/species_getters.dm b/code/modules/mob/living/carbon/human/species/species_getters.dm
index 0eeea4f9d4c..7b635613ea1 100644
--- a/code/modules/mob/living/carbon/human/species/species_getters.dm
+++ b/code/modules/mob/living/carbon/human/species/species_getters.dm
@@ -44,7 +44,7 @@
if(config.show_human_death_message)
return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message)
else
- return "no message"
+ return DEATHGASP_NO_MESSAGE
/datum/species/proc/get_ssd(var/mob/living/carbon/human/H)
if(H)
diff --git a/code/modules/mob/living/carbon/human/species/species_vr.dm b/code/modules/mob/living/carbon/human/species/species_vr.dm
index 06c9d2bdf38..486264e2c81 100644
--- a/code/modules/mob/living/carbon/human/species/species_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/species_vr.dm
@@ -23,6 +23,8 @@
var/silk_color = "#FFFFFF"
var/list/traits = list()
+ //Vars that need to be copied when producing a copy of species.
+ var/list/copy_vars = list("base_species", "icobase", "deform", "tail", "tail_animation", "icobase_tail", "color_mult", "primitive_form", "appearance_flags", "flesh_color", "base_color", "blood_mask", "damage_mask", "damage_overlays", "move_trail", "has_floating_eyes")
/datum/species/proc/give_numbing_bite() //Holy SHIT this is hacky, but it works. Updating a mob's attacks mid game is insane.
unarmed_attacks = list()
@@ -42,31 +44,20 @@
nif.nifsofts = nifsofts
else
..()
-/datum/species/proc/produceCopy(var/list/traits,var/mob/living/carbon/human/H, var/custom_base)
- var/datum/species/S
- //If species allows custom base, and custom base is set, apply it, otherwise use default.
- if(selects_bodytype && custom_base)
- S = GLOB.all_species[custom_base]
- else
- S = GLOB.all_species[src.name]
- ASSERT(S)
+/datum/species/proc/produceCopy(var/list/traits, var/mob/living/carbon/human/H, var/custom_base)
+ ASSERT(src)
ASSERT(istype(H))
- var/datum/species/new_copy = new S.type()
+ var/datum/species/new_copy = new src.type()
- for(var/i in S.vars) //Thorough copy of species.
- if(new_copy.vars[i] != S.vars[i])
- //Skipping lists because they may contain more lists, copy those manually.
- //Also ignoring type var since it's read-only and will runtime.
- if(islist(vars[i]))
- continue
- new_copy.vars[i] = S.vars[i]
+ if(selects_bodytype && custom_base) //If race selects a bodytype, retrieve the custom_base species and copy needed variables.
+ var/datum/species/S = GLOB.all_species[custom_base]
+ S.copy_variables(new_copy, copy_vars)
- for(var/organ in S.has_limbs) //Copy important organ data generated by species.
- var/list/organ_data = S.has_limbs[organ]
+ for(var/organ in has_limbs) //Copy important organ data generated by species.
+ var/list/organ_data = has_limbs[organ]
new_copy.has_limbs[organ] = organ_data.Copy()
new_copy.traits = traits
-
//If you had traits, apply them
if(new_copy.traits)
for(var/trait in new_copy.traits)
@@ -85,6 +76,19 @@
return new_copy
+/datum/species/proc/copy_variables(var/datum/species/S, var/list/whitelist)
+ //List of variables to ignore, trying to copy type will runtime.
+ var/list/blacklist = list("type", "loc", "client", "ckey")
+ //Makes thorough copy of species datum.
+ for(var/i in vars)
+ if(S.vars[i] != vars[i] && !islist(vars[i])) //If vars are same, no point in copying.
+ if(i in blacklist)
+ continue
+ if(whitelist)//If whitelist is provided, only vars in the list will be copied.
+ if(i in whitelist)
+ S.vars[i] = vars[i]
+ continue
+ S.vars[i] = vars[i]
/datum/species/get_bodytype()
- return base_species
\ No newline at end of file
+ return base_species
diff --git a/code/modules/mob/living/carbon/human/species/station/blank_vr.dm b/code/modules/mob/living/carbon/human/species/station/blank_vr.dm
index c358fda022c..72e49694d38 100644
--- a/code/modules/mob/living/carbon/human/species/station/blank_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/blank_vr.dm
@@ -46,8 +46,8 @@
var/datum/species/real = GLOB.all_species[base_species]
return real.race_key
-/datum/species/custom/produceCopy(var/list/traits,var/mob/living/carbon/human/H)
- . = ..()
+/datum/species/custom/produceCopy(var/list/traits, var/mob/living/carbon/human/H, var/custom_base)
+ . = ..(traits, H, custom_base)
H.maxHealth = H.species.total_health
H.hunger_rate = H.species.hunger_factor
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index bfb1b7d5e3d..8ec116221ed 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -119,6 +119,15 @@ var/datum/species/shapeshifter/promethean/prometheans
var/heal_rate = 0.5 // Temp. Regen per tick.
+ default_emotes = list(
+ /decl/emote/audible/squish,
+ /decl/emote/audible/chirp,
+ /decl/emote/visible/bounce,
+ /decl/emote/visible/jiggle,
+ /decl/emote/visible/lightup,
+ /decl/emote/visible/vibrate
+ )
+
/datum/species/shapeshifter/promethean/New()
..()
prometheans = src
diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
index ec0bab797cb..a0a505d61aa 100644
--- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
@@ -163,12 +163,14 @@
return ..()
/mob/living/simple_mob/protean_blob/adjustBruteLoss(var/amount)
+ amount *= 1.5
if(humanform)
return humanform.adjustBruteLoss(amount)
else
return ..()
/mob/living/simple_mob/protean_blob/adjustFireLoss(var/amount)
+ amount *= 1.5
if(humanform)
return humanform.adjustFireLoss(amount)
else
diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
index 087338fd739..8bd2192be8c 100755
--- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm
@@ -313,8 +313,8 @@
material_name = MAT_STEEL
/datum/modifier/protean/steel/tick()
- holder.adjustBruteLoss(-2,include_robo = TRUE) //Looks high, but these ARE modified by species resistances, so this is really 20% of this
- holder.adjustFireLoss(-1,include_robo = TRUE) //And this is really double this
+ holder.adjustBruteLoss(-1,include_robo = TRUE) //Modified by species resistances
+ holder.adjustFireLoss(-0.5,include_robo = TRUE) //Modified by species resistances
var/mob/living/carbon/human/H = holder
for(var/organ in H.internal_organs)
var/obj/item/organ/O = organ
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index f74505e770b..21e19f68d43 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -160,6 +160,16 @@
/datum/mob_descriptor/build = 2
)
+ default_emotes = list(
+ /decl/emote/human/swish,
+ /decl/emote/human/wag,
+ /decl/emote/human/sway,
+ /decl/emote/human/qwag,
+ /decl/emote/human/fastsway,
+ /decl/emote/human/swag,
+ /decl/emote/human/stopsway
+ )
+
/datum/species/unathi/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -250,6 +260,16 @@
O_INTESTINE = /obj/item/organ/internal/intestine
)
+ default_emotes = list(
+ /decl/emote/human/swish,
+ /decl/emote/human/wag,
+ /decl/emote/human/sway,
+ /decl/emote/human/qwag,
+ /decl/emote/human/fastsway,
+ /decl/emote/human/swag,
+ /decl/emote/human/stopsway
+ )
+
/datum/species/tajaran/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -533,6 +553,11 @@
genders = list(PLURAL)
+ default_emotes = list(
+ /decl/emote/audible/chirp,
+ /decl/emote/audible/multichirp
+ )
+
/datum/species/diona/can_understand(var/mob/other)
if(istype(other, /mob/living/carbon/alien/diona))
return TRUE
diff --git a/code/modules/mob/living/carbon/human/species/station/teshari.dm b/code/modules/mob/living/carbon/human/species/station/teshari.dm
index 3a282707c35..42afbbdbfcb 100644
--- a/code/modules/mob/living/carbon/human/species/station/teshari.dm
+++ b/code/modules/mob/living/carbon/human/species/station/teshari.dm
@@ -139,7 +139,7 @@
descriptors = list(
/datum/mob_descriptor/height = -3,
/datum/mob_descriptor/build = -3
- )
+ )
var/static/list/flight_bodyparts = list(
BP_L_ARM,
@@ -152,6 +152,12 @@
/obj/item/clothing/suit/straight_jacket
)
+ default_emotes = list(
+ /decl/emote/audible/teshsqueak,
+ /decl/emote/audible/teshchirp,
+ /decl/emote/audible/teshtrill
+ )
+
/datum/species/teshari/equip_survival_gear(var/mob/living/carbon/human/H)
..()
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
@@ -159,7 +165,7 @@
/datum/species/teshari/handle_falling(mob/living/carbon/human/H, atom/hit_atom, damage_min, damage_max, silent, planetary)
// Tesh can glide to save themselves from some falls. Basejumping bird
- // without parachute, or falling bird without free wings goes splat.
+ // without parachute, or falling bird without free wings, goes splat.
// Are we landing from orbit, or handcuffed/unconscious/tied to something?
if(planetary || !istype(H) || H.incapacitated(INCAPACITATION_DEFAULT|INCAPACITATION_DISABLED))
diff --git a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
index 011059a9e04..df7edc45af2 100644
--- a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
+++ b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
@@ -1,6 +1,8 @@
#define ORGANICS 1
#define SYNTHETICS 2
+/datum/trait/neutral
+
/datum/trait/neutral/metabolism_up
name = "Fast Metabolism"
desc = "You process ingested and injected reagents faster, but get hungry faster (Teshari speed)."
diff --git a/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm b/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm
index be1783d9dff..19e274306b4 100644
--- a/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm
@@ -3,39 +3,44 @@
** These are only traits that they should reasonably be able to evolve to acquire themselves.
** I won't add the resistances though because those are kinda lame for a 'chimera to take!
*/
-/datum/trait/weaver/xenochimera
+/datum/trait/positive/weaver/xenochimera
allowed_species = list(SPECIES_XENOCHIMERA)
name = "Xenochimera: Weaver"
desc = "You've evolved your body to produce silk that you can fashion into articles of clothing and other objects."
cost = 0
+ category = 0
custom_only = FALSE
-/datum/trait/hardfeet/xenochimera
+/datum/trait/positive/hardfeet/xenochimera
allowed_species = list(SPECIES_XENOCHIMERA)
name = "Xenochimera: Hard Feet"
desc = "Your body has adapted to make your feet immune to glass shards, whether by developing hooves, chitin, or just horrible callous."
cost = 0
+ category = 0
custom_only = FALSE
// Why put this on Xenochimera of all species? I have no idea, but someone may be enough of a lunatic to take it.
-/datum/trait/neural_hypersensitivity/xenochimera
+/datum/trait/negative/neural_hypersensitivity/xenochimera
allowed_species = list(SPECIES_XENOCHIMERA)
name = "Xenochimera: Neural Hypersensitivity"
desc = "Despite your evolutionary efforts, you are unusually sensitive to pain. \
Given your species' typical reactions to pain, this can only end well for you!"
cost = 0
+ category = 0
custom_only = FALSE
-/datum/trait/melee_attack_fangs/xenochimera
+/datum/trait/positive/melee_attack_fangs/xenochimera
allowed_species = list(SPECIES_XENOCHIMERA)
name = "Xenochimera: Sharp Melee & Numbing Fangs"
desc = "Your hunting instincts manifest in earnest! You have grown numbing fangs alongside your naturally grown hunting weapons."
cost = 0
+ category = 0
custom_only = FALSE
-/datum/trait/snowwalker/xenochimera
+/datum/trait/positive/snowwalker/xenochimera
allowed_species = list(SPECIES_XENOCHIMERA)
name = "Xenochimera: Snow Walker"
desc = "You've adapted to traversing snowy terrain. Snow does not slow you down!"
cost = 0
+ category = 0
custom_only = FALSE
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index bfb4856017b..d5f51aece28 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -147,7 +147,11 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
anim_time = 1 //Thud
if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone.
- M.Turn(90)
+ var/randn = rand(1, 2)
+ if(randn <= 1) // randomly choose a rotation
+ M.Turn(-90)
+ else
+ M.Turn(90)
M.Scale(desired_scale_y, desired_scale_x)//VOREStation Edit
if(species.icon_height == 64)//VOREStation Edit
M.Translate(13,-22)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 877e8542767..ae1b09ae714 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -433,38 +433,5 @@ proc/get_radio_key_from_channel(var/channel)
/mob/proc/GetVoice()
return name
-/mob/living/emote(var/act, var/type, var/message) //emote code is terrible, this is so that anything that isn't
- if(stat) //already snowflaked to shit can call the parent and handle emoting sanely
- return FALSE
-
- if(..(act, type, message))
- return TRUE
-
- if(act && type && message)
- log_emote(message, src)
-
- for(var/mob/M in dead_mob_list)
- if(!M.client)
- continue
-
- if(isnewplayer(M))
- continue
-
- if(isobserver(M) && M.is_preference_enabled(/datum/client_preference/ghost_sight))
- M.show_message(message)
-
- switch(type)
- if(1) // Visible
- visible_message(message)
- return TRUE
- if(2) // Audible
- audible_message(message)
- return TRUE
- else
- if(act == "help")
- return // Mobs handle this individually
- to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
-
-
/mob/proc/speech_bubble_appearance()
return "normal"
diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm
index 00a5e429932..6aa6ae2150f 100644
--- a/code/modules/mob/living/silicon/emote.dm
+++ b/code/modules/mob/living/silicon/emote.dm
@@ -1,113 +1,13 @@
-/mob/living/silicon/emote(var/act, var/m_type = 1,var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_silicon_default_emotes = list(
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/audible/synth/dwoop,
+ /decl/emote/audible/synth/security,
+ /decl/emote/audible/synth/security/halt
+)
- if(findtext(act, "s", -1) && !findtext(act, "_", -2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act, 1, length(act))
-
- switch(act)
- if("beep")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] beeps at [param]."
- else
- message = "[src] beeps."
- playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
- m_type = 1
-
- if("ping")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] pings at [param]."
- else
- message = "[src] pings."
- playsound(src, 'sound/machines/ping.ogg', 50, 0)
- m_type = 1
-
- if("buzz")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] buzzes at [param]."
- else
- message = "[src] buzzes."
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- m_type = 1
-
- if("yes", "ye")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] emits an affirmative blip at [param]."
- else
- message = "[src] emits an affirmative blip."
- playsound(src, 'sound/machines/synth_yes.ogg', 50, 0)
- m_type = 1
-
- if("dwoop")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] chirps happily at [param]"
- else
- message = "[src] chirps happily."
- playsound(src, 'sound/machines/dwoop.ogg', 50, 0)
- m_type = 1
-
- if("no")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if (param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if (param)
- message = "[src] emits a negative blip at [param]."
- else
- message = "[src] emits a negative blip."
- playsound(src, 'sound/machines/synth_no.ogg', 50, 0)
- m_type = 1
-
- ..(act, m_type, message)
\ No newline at end of file
+/mob/living/silicon/get_default_emotes()
+ return global._silicon_default_emotes
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index 9560c6b528e..2b83568e7bf 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -1,155 +1,33 @@
-/mob/living/silicon/robot/emote(var/act,var/m_type=1,var/message = null)
- var/param = null
- if(findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- param = copytext(act, t1 + 1, length(act) + 1)
- act = copytext(act, 1, t1)
+var/list/_robot_default_emotes = list(
+ /decl/emote/audible/clap,
+ /decl/emote/visible/bow,
+ /decl/emote/visible/salute,
+ /decl/emote/visible/flap,
+ /decl/emote/visible/aflap,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/glare,
+ /decl/emote/visible/look,
+ /decl/emote/visible/stare,
+ /decl/emote/visible/deathgasp_robot,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/synth/ping,
+ /decl/emote/audible/synth/buzz,
+ /decl/emote/audible/synth/confirm,
+ /decl/emote/audible/synth/deny,
+ /decl/emote/audible/synth/dwoop,
+ /decl/emote/audible/synth/security,
+ /decl/emote/audible/synth/security/halt,
+ //VOREStation Add
+ /decl/emote/visible/mlem,
+ /decl/emote/visible/blep
+ //VOREStation Add End
+)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
-
- switch(act)
- if("salute")
- if(!src.buckled)
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] salutes to [param]."
- else
- message = "[src] salutes."
- m_type = 1
- if("bow")
- if(!src.buckled)
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] bows to [param]."
- else
- message = "[src] bows."
- m_type = 1
-
- if("clap")
- if(!src.restrained())
- message = "[src] claps."
- m_type = 2
- if("flap")
- if(!src.restrained())
- message = "[src] flaps its wings."
- m_type = 2
-
- if("aflap")
- if(!src.restrained())
- message = "[src] flaps its wings ANGRILY!"
- m_type = 2
-
- if("twitch")
- message = "[src] twitches."
- m_type = 1
-
- if("twitch_v")
- message = "[src] twitches violently."
- m_type = 1
-
- if("nod")
- message = "[src] nods."
- m_type = 1
-
- if("deathgasp")
- message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
- m_type = 1
-
- if("glare")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] glares at [param]."
- else
- message = "[src] glares."
-
- if("stare")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
- if(!M)
- param = null
-
- if(param)
- message = "[src] stares at [param]."
- else
- message = "[src] stares."
-
- if("look")
- var/M = null
- if(param)
- for (var/mob/A in view(null, null))
- if(param == A.name)
- M = A
- break
-
- if(!M)
- param = null
-
- if(param)
- message = "[src] looks at [param]."
- else
- message = "[src] looks."
- m_type = 1
-
- if("law")
- if(istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
- message = "[src] shows its legal authorization barcode."
-
- playsound(src, 'sound/voice/biamthelaw.ogg', 50, 0)
- m_type = 2
- else
- to_chat(src, "You are not THE LAW, pal.")
-
- if("halt")
- if(istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
- message = "[src] 's speakers skreech, \"Halt! Security!\"."
-
- playsound(src, 'sound/voice/halt.ogg', 50, 0)
- m_type = 2
- else
- to_chat(src, "You are not security.")
- //Vorestation addition start
- if("bark")
- if (istype(module,/obj/item/weapon/robot_module/robot/knine) || istype(module,/obj/item/weapon/robot_module/robot/medihound) || istype(module,/obj/item/weapon/robot_module/robot/scrubpup) || istype(module,/obj/item/weapon/robot_module/robot/ert) || istype(module,/obj/item/weapon/robot_module/robot/science) || istype(module,/obj/item/weapon/robot_module/robot/engiedog) || istype(module,/obj/item/weapon/robot_module/robot/clerical/brodog) || istype(module,/obj/item/weapon/robot_module/robot/kmine) )
- message = "[src] lets out a bark."
-
- playsound(src, 'sound/voice/bark2.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
- m_type = 2
- else
- to_chat(src, "You're not a dog!")
- //Vorestation addition end
-
-
-
- if("help")
- to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitch_s, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look, beep, ping, \nbuzz, law, halt, yes, dwoop, no")
-
- ..(act, m_type, message)
+/mob/living/silicon/robot/get_default_emotes()
+ return global._robot_default_emotes
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 229aa7b66a9..82bc2e24989 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -209,12 +209,12 @@
/mob/living/silicon/robot/proc/setup_PDA()
if (!rbPDA)
rbPDA = new/obj/item/device/pda/ai(src)
- rbPDA.set_name_and_job(custom_name,"[modtype] [braintype]")
+ rbPDA.set_name_and_job(name,"[modtype] [braintype]")
/mob/living/silicon/robot/proc/setup_communicator()
if (!communicator)
communicator = new/obj/item/device/communicator/integrated(src)
- communicator.register_device(src.name, "[modtype] [braintype]")
+ communicator.register_device(name, "[modtype] [braintype]")
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
//Improved /N
diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm
index ef870cb1f35..34f6096ede0 100644
--- a/code/modules/mob/living/silicon/say.dm
+++ b/code/modules/mob/living/silicon/say.dm
@@ -114,7 +114,7 @@
return 0
return 1
-/mob/living/silicon/ai/emote(var/act, var/type, var/message)
+/mob/living/silicon/ai/emote(var/act, var/m_type, var/message)
var/obj/machinery/hologram/holopad/T = holo
if(T && T.masters[src]) //Is the AI using a holopad?
. = holopad_emote(message)
diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
index b51577ce078..f18a745486b 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
@@ -84,6 +84,7 @@
icon_state = "[icon_dead]-[vore_fullness]"
else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest && (vore_icons & SA_ICON_REST))
icon_state = "[icon_rest]-[vore_fullness]"
+ update_transform()
/mob/living/simple_mob/proc/will_eat(var/mob/living/M)
if(client) //You do this yourself, dick!
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
index a12a76a6796..45ce8eb9ad5 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
@@ -50,3 +50,9 @@
pixel_y = -16
old_x = -16
old_y = -16
+
+/mob/living/simple_mob/animal/giant_spider/nurse/eggless/lay_eggs(turf/T)
+ return FALSE
+
+/mob/living/simple_mob/animal/giant_spider/nurse/queen/eggless/lay_eggs(turf/T)
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
index 9db6a6bffa0..c48f94bf277 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/cat.dm
@@ -1,3 +1,32 @@
+var/list/_cat_default_emotes = list(
+ /decl/emote/visible,
+ /decl/emote/visible/scratch,
+ /decl/emote/visible/drool,
+ /decl/emote/visible/nod,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/sulk,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/twitch_v,
+ /decl/emote/visible/dance,
+ /decl/emote/visible/roll,
+ /decl/emote/visible/shake,
+ /decl/emote/visible/jump,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/collapse,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/sidestep,
+ /decl/emote/audible,
+ /decl/emote/audible/hiss,
+ /decl/emote/audible/whimper,
+ /decl/emote/audible/gasp,
+ /decl/emote/audible/scretch,
+ /decl/emote/audible/choke,
+ /decl/emote/audible/moan,
+ /decl/emote/audible/gnarl,
+ /decl/emote/audible/purr,
+ /decl/emote/audible/purrlong
+)
+
/mob/living/simple_mob/animal/passive/cat
name = "cat"
desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers."
@@ -28,6 +57,9 @@
update_icon()
return ..()
+/mob/living/simple_mob/animal/passive/cat/get_default_emotes()
+ return global._cat_default_emotes
+
/mob/living/simple_mob/animal/passive/cat/handle_special()
if(!stat && prob(2)) // spooky
var/mob/observer/dead/spook = locate() in range(src, 5)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
index 903f4b9ce61..c30dd4be5ae 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
@@ -1,6 +1,24 @@
+/datum/category_item/catalogue/fauna/snake
+ name = "Wildlife - Snake"
+ desc = "Classification: Reptilia Serpentes\
+
\
+ Snakes are elongated, limbless, carnivorous reptiles of the suborder Serpentes \
+ Like all other squamates, snakes are ectothermic, amniote vertebrates covered in overlapping scales. \
+ Many species of snakes have skulls with several more joints than their lizard ancestors, \
+ enabling them to swallow prey much larger than their heads with their highly mobile jaws. \
+
\
+ This species of snake is nonvenomous and use their large bodies to primarily subdue their prey. \
+ Nonvenomous snakes either swallow prey alive or kill them by constriction - this is dependant on the prey. \
+
\
+ This specific snake is nonvenomous and is mostly passive - however they will attack if threatened - it is \
+ recommended that persons keep their distance as to not provoke these animals."
+ value = CATALOGUER_REWARD_TRIVIAL
+
/mob/living/simple_mob/animal/passive/snake
name = "snake"
desc = "A big thick snake."
+ tt_desc = "Reptilia Serpentes"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/snake)
icon_state = "snake"
icon_living = "snake"
diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
index a5419bc5599..f8d47a4b2dc 100644
--- a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
@@ -1,5 +1,21 @@
-// The top-level slime defines. Xenobio slimes and feral slimes will inherit from this.
+var/list/_slime_default_emotes = list(
+ /decl/emote/audible/moan,
+ /decl/emote/visible/twitch,
+ /decl/emote/visible/sway,
+ /decl/emote/visible/shiver,
+ /decl/emote/visible/bounce,
+ /decl/emote/visible/jiggle,
+ /decl/emote/visible/lightup,
+ /decl/emote/visible/vibrate,
+ /decl/emote/slime,
+ /decl/emote/slime/pout,
+ /decl/emote/slime/sad,
+ /decl/emote/slime/angry,
+ /decl/emote/slime/frown,
+ /decl/emote/slime/smile
+)
+// The top-level slime defines. Xenobio slimes and feral slimes will inherit from this.
/mob/living/simple_mob/slime
name = "slime"
desc = "It's a slime."
@@ -64,6 +80,9 @@
can_enter_vent_with = list(/obj/item/clothing/head)
+/mob/living/simple_mob/slime/get_default_emotes()
+ return global._slime_default_emotes
+
/datum/say_list/slime
speak = list("Blorp...", "Blop...")
emote_see = list("bounces", "jiggles", "sways")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
index 5b96ab7ee8f..66e38f6a8f9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
@@ -1,13 +1,28 @@
-/datum/category_item/catalogue/fauna/deathclaw //TODO: VIRGO_LORE_WRITING_WIP
+/datum/category_item/catalogue/fauna/deathclaw
name = "Creature - Deathclaw"
- desc = "A massive beast, tall as three standard-size humans, with massive, terrifying claws, \
- and dark, black fangs. It's entire body is yellowish, like sand, and it's skin is leathery and tough. \
- It seems to have adapted to the harsh desert environment on Virgo 4, and makes it's home inside the caves."
+ desc = "Classification: Trioceros dominus\
+
\
+ Originally the Deathclaw was a top secret genetics project that was run by ancestral Zorren which was \
+ lost to time. While it is not immediately evident in their body structure, these creatures bare a \
+ subtle genetic connection to Zorren, however, this connection is marred by the other genes that \
+ have been grafted onto the DNA strucutre of the Deathclaw. The creatures are known to attack humans \
+ and other animals regularly to protect their territory or to hunt for food. It is speculated that \
+ they escaped roughly around the time as whatever calamity befell the Zorren many centuries ago \
+ as sighting of these beasts in the wild began around that time according to recovered Zorren texts. \
+
\
+ Deathclaws are a large, carnivorous, bipedal reptile species, designed for maximum lethality. \
+ Deathclaws are made even more dangerous by their reproductive instincts. deathclaws are an oviparous species, \
+ female deathclaws will lay eggs in clusters, sired by the strongest male deathclaws in the pack, typically the alpha male.\
+
\
+ These creatures are considered an invasive species, and thus hunters are encouraged to hunt them \
+ although they are cautioned when doing so due to the danger that the creature poses."
value = CATALOGUER_REWARD_HARD
/mob/living/simple_mob/vore/aggressive/deathclaw
name = "deathclaw"
desc = "Big! Big! The size of three men! Claws as long as my forearm! Ripped apart! Ripped apart!"
+ tt_desc = "Trioceros dominus"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/deathclaw)
icon_dead = "deathclaw-dead"
icon_living = "deathclaw"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
index c35e421fab2..ec8a8f2f65a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
@@ -1,15 +1,31 @@
-/datum/category_item/catalogue/fauna/fennec //TODO: VIRGO_LORE_WRITING_WIP
+/datum/category_item/catalogue/fauna/fennec
name = "Wildlife - Fennec"
- desc = "A small, dusty, big-eared sandfox, native to Virgo 4. It looks like a Zorren that's on all fours, \
- and it's easy to see the resemblance to the little dunefox-like critters the Zorren are. However, the fennecs \
- lack the sentience the Zorren have, and are therefore naught more than cute little critters, with a hungry \
- attitude, willing to eat damn near anything they come across or can bump into. Bapping them will make them stop."
+ desc = "Classification: Vulpes zerda maxima\
+
\
+ The Fennec fox is a small crepuscular fox native to Earth in Sol that nearly went extinct in the 2030s.\
+ Through conservation efforts and the rise of space colonies, the Fennec was brought back from the brink \
+ and is now labeled as 'Least Concern'. During the great Sol Expansion Period, Fennec were brought with \
+ colonist as a means of companionship and as a ecosystem balance for desert worlds such as Virgo 4. \
+ Their presence on Virgo 4 is largely due to convergent evolution. While their genetics are closely \
+ related to their Sol counterparts, they are in fact a totally different species of fennec that have followed. \
+ a separate evolutional path. Virgo Fennec are upwards of five times larger than their Sol cousins and consequently \
+ have a larger appetite. Their diet mainly consists of whatever small creatures that they manage to scrounge from \
+ the sands of Virgo 4, however they have been known to hunt larger prey in desperate times.\
+
\
+ Fennec foxes reach sexual maturity at around nine months and mate between January and April \
+ They usually breed only once per year. After mating, the male becomes very aggressive and protects \
+ the female, provides her with food during pregnancy and lactation.\
+
\
+ Virgo Fennecs have been observed to be passive and do not actively hunt large prey as their bodies have \
+ grown accustomed to less available food sources. However, travellers are still cautioned on approaching \
+ them as Virgo Fennec have been known to swallow prey whole depending on the prey's size."
value = CATALOGUER_REWARD_TRIVIAL
/mob/living/simple_mob/vore/fennec
name = "fennec" //why isn't this in the fox file, fennecs are foxes silly.
desc = "It's a dusty big-eared sandfox! Adorable!"
- tt_desc = "Vulpes zerda"
+ tt_desc = "Vulpes zerda maxima"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/fennec)
icon_state = "fennec"
icon_living = "fennec"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm b/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
index 9e1609336d5..c6ea3efbc16 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
@@ -1,7 +1,27 @@
+/datum/category_item/catalogue/fauna/frog
+ name = "Wildlife - Giant Frog"
+ desc = "Classification: Anura gigantus\
+
\
+ A frog is any member of a diverse and largely carnivorous group of short-bodied, tailless amphibians composing \
+ the order Anura. This specific species - Anura gigantus - is a mutated form of Frogs, largely due to exposure to mutagen chemicals. \
+ These Giant Frogs are descendants from scientific frogs that were used for study during the great Sol Expansion Period. \
+ Modern day Giant Frogs have reverted to a more feral state compared to their original ancestors and are hostile \
+ towards humans and other small wildlife - hunting them for food.\
+
\
+ The particular breed of Frog that was originally used in the scientific experiments were known as explosive breeders.\
+ With explosive breeders, mature adult frogs arrive at breeding sites in response to certain trigger factors such as rainfall \
+ occurring in an arid area. In these frogs, mating and spawning take place promptly and the speed of larval growth is rapid in \
+ order to make use of the ephemeral pools before they dry up. Because of this, the Frog population is through the roof and has \
+ become a major issue for various colonies and stations.\
+
\
+ These animals, are considered an invasive species, and thus hunters are encouraged to hunt them."
+ value = CATALOGUER_REWARD_TRIVIAL
+
/mob/living/simple_mob/vore/aggressive/frog
name = "giant frog"
desc = "You've heard of having a frog in your throat, now get ready for the reverse."
tt_desc = "Anura gigantus"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/frog)
icon_dead = "frog-dead"
icon_living = "frog"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm b/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
index 5307a05cd03..8572416cd09 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
@@ -1,8 +1,18 @@
-/datum/category_item/catalogue/fauna/mimic //TODO: VIRGO_LORE_WRITING_WIP
+/datum/category_item/catalogue/fauna/mimic
name = "Aberration - Mimic"
- desc = "A being that seems to take the form of a crate, for whatever reason. \
- It seems to lie in wait for it's prey, and then pounce once the unsuspecting person attempts to open it. \
- For whatever reason, they seem native to underground areas, and they're very tough, and hard to kill, able to pounce fast."
+ desc = "Classification: Mimus vorare\
+
\
+ Mimics are morph creatures that share properties with the likes of Prometheans. They could assume any shape, \
+ provided that they retained the same volume. In order to most effectively lure prey, they most commonly \
+ take the shape of chests and other objects likely to be touched by someone - though the latter is rarer \
+ than the former. \
+
\
+ Mimics prefer consuming large prey such as humans or humanoid species, however, for means of survival they \
+ might resort to eating smaller prey. A meal of one or two humanoids could sustain a mimic for several \
+ months at a time - the main reason that they prey on humanoids to begin with. They reproduced asexually \
+ by splitting their mass, the young growing to adulthood within a few years time.\
+
\
+ Mimics have no concerns beyond surviving and acquiring food."
value = CATALOGUER_REWARD_HARD
/obj/structure/closet/crate/mimic
@@ -63,9 +73,11 @@
/mob/living/simple_mob/vore/aggressive/mimic
name = "crate"
desc = "A rectangular steel crate."
+
+
icon_state = "crate"
icon_living = "crate"
- icon = 'icons/obj/storage_vr.dmi'
+ icon = 'icons/obj/storage.dmi'
faction = "mimic"
@@ -101,6 +113,8 @@
showvoreprefs = 0 //Hides mechanical vore prefs for mimics. You can't see their gaping maws when they're just sitting idle.
/mob/living/simple_mob/vore/aggressive/mimic
+ tt_desc = "Mimus vorare"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mimic)
vore_active = 1
vore_pounce_chance = 10
swallowTime = 3 SECONDS
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
index a49309e7138..4d268567b8f 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
@@ -34,7 +34,6 @@
// Vore vars
vore_active = 1
- vore_bump_chance = 10
vore_bump_emote = "playfully lunges at"
vore_pounce_chance = 40
vore_pounce_maxhealth = 100 // They won't pounce by default, as they're passive. This is just so the nom check succeeds. :u
@@ -140,6 +139,7 @@
movement_cooldown = 0.5 // very fast bunbun.
+ vore_bump_chance = 10
vore_pounce_chance = 100
vore_pounce_falloff = 0.2
@@ -149,4 +149,4 @@
ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
/mob/living/simple_mob/vore/rabbit/killer/ex_act()
- gib()
\ No newline at end of file
+ gib()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
index d708f265bb3..a1afb7bbb20 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
@@ -1,14 +1,28 @@
-/datum/category_item/catalogue/fauna/rat //TODO: VIRGO_LORE_WRITING_WIP
+/datum/category_item/catalogue/fauna/rat
name = "Creature - Rat"
- desc = "A massive rat, some sort of mutated descendant of normal Earth rats. These ones seem particularly hungry, \
- and are able to pounce and stun their targets - presumably to eat them. Their bodies are long and greyfurred, \
- with a pink nose and large teeth, just like their regular-sized counterparts."
+ desc = "Classification: Mus muscular\
+
\
+ Rats are various medium-sized, long-tailed rodents. Species of rats are found throughout the order Rodentia, \
+ but stereotypical rats are found in the genus Rattus. This specific species of rat is a mutated descendant from lab rats. \
+ It is unclear what experiment caused this species to grow to such an unnatural size, however it hasn't affected the rat's \
+ general docile nature. When encountered by humans or other species it generally ignores them unless provoked.\
+
\
+ Rats become sexually mature at age 6 weeks, but reach social maturity at about 5 to 6 months of age. \
+ The average lifespan of rats varies by species, but many only live about a year due to predation. \
+ However, due to the large nature of this particular species of rat, predation is usually not that much of an issue. \
+ This doesn't mean that there is an overpopulation, though, quite the opposite. Giant Rats are rare and this is usually \
+ due to small litter sizes and lack of proper food sources. Areas that one would typically see a Giant Rat is large garbage \
+ disposals or areas that have large amounts of live food (other rats, mice, etc.) such as maintenance tunnels. \
+
\
+ Male rats are called bucks; unmated females, does, pregnant or parent females, dams; and infants, kittens or pups. \
+ A group of rats is referred to as a mischief."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/vore/aggressive/rat
name = "giant rat"
desc = "In what passes for a hierarchy among verminous rodents, this one is king."
tt_desc = "Mus muscular"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/rat)
icon_state = "rous"
icon_living = "rous"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
index 619e0acad0f..3c7aabfca4a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
@@ -1,12 +1,28 @@
/datum/category_item/catalogue/fauna/sect_drone
name = "Creature - Sect Drone"
- desc = "Database Update Pending" //TODO: Virgo Lore Writing WIP
+ desc = "Classification: V Insecta gigantus\
+
\
+ A massively-sized insect that is native to Virgo 3B. Much like its queen, it bears the combined physical traits \
+ of several of Earth's insects. Its forelegs have claws bearing serrated edges much like a Mantis, which it uses \
+ in both self-defense and during its hunts. On it's back are two large semi transparent wings like a beetle that it \
+ uses for increased mobility. Covering its body is a layer of light, thick, and protective chitin, resilient enough to absorb \
+ most physical damage while being light enough for the Sect Drone to hover. \
+
\
+ It is not uncommon for a Sect Drone to go out alone to search for potential prey to bring back to the nest. \
+ Regardless of reason, it is cautioned against approaching a Sect Drone as, like their queen, their behaviour is wildly \
+ inconsistent. A Sect Drone can vary from hostile to docile depending on certain factors that scientists have \
+ yet to uncover. \
+
\
+ The lack of chitin on the underside of its abdomen is deliberate, as the flesh is very elastic and stretchable, \
+ allowing the drone to carry multiple large prey inside of its stomach with relative ease."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/vore/sect_drone
name = "sect drone"
desc = "A large, chitin-plated insectoid whose multiple cyan eyes cast a frightful blue light. Its \
abdomen has an unusually soft and... flexible-looking underbelly..."
+ tt_desc = "V Insecta gigantus"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/sect_drone)
icon_dead = "sect_drone_dead"
icon_living = "sect_drone"
@@ -64,4 +80,4 @@
say_list_type = /datum/say_list/sect_drone
/datum/say_list/sect_drone
- say_got_target = list("chitters threateningly!")
\ No newline at end of file
+ say_got_target = list("chitters threateningly!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
index bb0933dd862..649062e8733 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
@@ -2,20 +2,30 @@
/datum/category_item/catalogue/fauna/sect_queen
name = "Creature - Sect Queen"
- desc = "A massively-sized insect that is native, although rarely spotted outside of its colony, to Virgo 3B. \
+ desc = "Classification: V Insecta maximus gigantus\
+
\
+ A massively-sized insect that is native - although rarely spotted outside of its colony - to Virgo 3B. \
It bears the combined physical traits of several of Earth's insects. Its forelegs have claws bearing serrated \
- edges, which it uses in both self-defense and during its hunts. Covering its body is a layer of thick and \
- protective chitin, resilient enough to absorb most physical damage. It is not uncommon for a queen to go out \
- alone to search for potential new nesting grounds... or perhaps it does so to seek bigger prey that its much \
- smaller drones might be unable to acquire. The lack of chitin on the underside of its abdomen is deliberate, \
- as the flesh is very elastic and stretchable, allowing the queen to carry multiple large prey inside of its \
- stomach with ease."
+ edges much like a Mantis, which it uses in both self-defense and during its hunts. Covering its body is a layer \
+ of thick and protective chitin, resilient enough to absorb most physical damage. \
+
\
+ Though rarely seen, it is not uncommon for a queen to go out alone to search for potential new nesting grounds \
+ or perhaps it does so to seek bigger prey that its much smaller drones might be unable to acquire. \
+ Regardless of reason, it is cautioned against approaching a Sect Queen as their behaviour is wildly \
+ inconsistent. A Sect Queen can vary from hostile to docile depending on certain factors that scientists have \
+ yet to uncover. \
+
\
+ The lack of chitin on the underside of its abdomen is deliberate, as the flesh is very elastic and stretchable, \
+ allowing the queen to carry multiple large prey inside of its stomach with ease. There is no know limit to home much \
+ prey a single specimen can carry and scientists are wary to find said limit."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/vore/sect_queen
name = "sect queen"
desc = "A titanic, chitin-plated insectoid whose multiple crimson eyes cast a frightful red light. Its \
abdomen has an unusually soft and... flexible-looking underbelly..."
+ tt_desc = "V Insecta maximus gigantus"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/sect_queen)
icon_dead = "sect_queen_dead"
icon_living = "sect_queen"
@@ -72,4 +82,4 @@
say_list_type = /datum/say_list/sect_queen
/datum/say_list/sect_queen
- say_got_target = list("chitters angrily!")
\ No newline at end of file
+ say_got_target = list("chitters angrily!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm b/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
index de2139fd1a8..651599e3525 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
@@ -1,6 +1,29 @@
+/datum/category_item/catalogue/fauna/giant_snake
+ name = "Creature - Giant Snake"
+ desc = "Classification: Serpentes gigantus\
+
\
+ Snakes are elongated, limbless, carnivorous reptiles of the suborder Serpentes \
+ Like all other squamates, snakes are ectothermic, amniote vertebrates covered in overlapping scales. \
+ Many species of snakes have skulls with several more joints than their lizard ancestors, \
+ enabling them to swallow prey much larger than their heads with their highly mobile jaws. \
+ This particular species of snake has likely been mutated by deliberate gene manipulation of some sort and as a \
+ result has grown to unnatural size. Biologically this snake is no different than that of the common snake, \
+ but this species has been known to have increased hostility towards wildlife. Scientists are still studying \
+ this new species for any differences in behavior or biology beyond the increase in size. \
+
\
+ This species of snake is nonvenomous and use their large bodies to primarily subdue their prey. \
+ Nonvenomous snakes either swallow prey alive or kill them by constriction - this is dependant on the prey. \
+
\
+ This snake is extremely hostile to all wildlife and living beings and should be avoided at all costs. \
+ People who spot these creatures are urged to inform the nearest militant entity so that they can be \
+ dealt with in a professional manner."
+ value = CATALOGUER_REWARD_HARD
+
/mob/living/simple_mob/vore/aggressive/giant_snake
name = "giant snake"
desc = "Snakes. Why did it have to be snakes?"
+ tt_desc = "Serpentes gigantus"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/giant_snake)
icon_dead = "snake-dead"
icon_living = "snake"
diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm
index 2d070d1a298..9caa58cb33d 100644
--- a/code/modules/mob/living/voice/voice.dm
+++ b/code/modules/mob/living/voice/voice.dm
@@ -137,6 +137,6 @@
return TRUE
return ..()
-/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
+/mob/living/voice/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message = null, var/range = world.view)
if(!comm) return
..(m_type,message,comm.video_range)
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index d6f04cd0d59..1c1321a715d 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -44,6 +44,7 @@
disconnect_time = null //VOREStation Addition: clear the disconnect time
sight |= SEE_SELF
..()
+ SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
if(loc && !isturf(loc))
client.eye = loc
@@ -81,4 +82,5 @@
update_client_z(T.z)
if(cloaked && cloaked_selfimage)
- client.images += cloaked_selfimage
\ No newline at end of file
+ client.images += cloaked_selfimage
+ SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
\ No newline at end of file
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 3b4b478a7eb..c41691a8575 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -42,6 +42,7 @@
lastarea = get_area(src)
hook_vr("mob_new",list(src)) //VOREStation Code
update_transform() // Some mobs may start bigger or smaller than normal.
+ update_emotes()
return ..()
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
@@ -49,19 +50,19 @@
if(!client && !teleop) return
if (type)
- if((type & 1) && (is_blind() || paralysis) )//Vision related
+ if((type & VISIBLE_MESSAGE) && (is_blind() || paralysis) )//Vision related
if (!( alt ))
return
else
msg = alt
type = alt_type
- if ((type & 2) && is_deaf())//Hearing related
+ if ((type & AUDIBLE_MESSAGE) && is_deaf())//Hearing related
if (!( alt ))
return
else
msg = alt
type = alt_type
- if ((type & 1) && (sdisabilities & BLIND))
+ if ((type & VISIBLE_MESSAGE) && (sdisabilities & BLIND))
return
// Added voice muffling for Issue 41.
if(stat == UNCONSCIOUS || sleeping > 0)
@@ -77,14 +78,17 @@
// message is the message output to anyone who can see e.g. "[src] does something!"
// self_message (optional) is what the src mob sees e.g. "You do something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
-/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null)
+/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null, var/range = world.view)
if(self_message)
if(LAZYLEN(exclude_mobs))
exclude_mobs |= src
else
exclude_mobs = list(src)
src.show_message(self_message, 1, blind_message, 2)
- . = ..(message, blind_message, exclude_mobs)
+ // Transfer messages about what we are doing to upstairs
+ if(shadow)
+ shadow.visible_message(message, self_message, blind_message, exclude_mobs, range)
+ . = ..(message, blind_message, exclude_mobs, range) // Really not ideal that atom/visible_message has different arg numbering :(
// Returns an amount of power drawn from the object (-1 if it's not viable).
// If drain_check is set it will not actually drain power, just return a value.
@@ -99,7 +103,7 @@
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message)
+/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message, var/radio_message)
var/range = hearing_distance || world.view
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
@@ -107,16 +111,21 @@
var/list/hearing_mobs = hear["mobs"]
var/list/hearing_objs = hear["objs"]
- for(var/obj in hearing_objs)
- var/obj/O = obj
- O.show_message(message, 2, deaf_message, 1)
+ if(radio_message)
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.hear_talk(src, list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], radio_message)), null)
+ else
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
for(var/mob in hearing_mobs)
var/mob/M = mob
var/msg = message
if(self_message && M==src)
msg = self_message
- M.show_message(msg, 2, deaf_message, 1)
+ M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
/mob/proc/findname(msg)
for(var/mob/M in mob_list)
@@ -576,9 +585,6 @@
/mob/proc/get_gender()
return gender
-/mob/proc/get_visible_gender()
- return gender
-
/mob/proc/see(message)
if(!is_active())
return 0
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index ebcc9cf35a2..259aaf75c85 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -477,19 +477,26 @@
/mob/proc/update_gravity()
return
+#define DO_MOVE(this_dir) var/final_dir = turn(this_dir, -dir2angle(dir)); Move(get_step(mob, final_dir), final_dir);
+
/client/verb/moveup()
set name = ".moveup"
set instant = 1
- Move(get_step(mob, NORTH), NORTH)
+ DO_MOVE(NORTH)
+
/client/verb/movedown()
set name = ".movedown"
set instant = 1
- Move(get_step(mob, SOUTH), SOUTH)
+ DO_MOVE(SOUTH)
+
/client/verb/moveright()
set name = ".moveright"
set instant = 1
- Move(get_step(mob, EAST), EAST)
+ DO_MOVE(EAST)
+
/client/verb/moveleft()
set name = ".moveleft"
set instant = 1
- Move(get_step(mob, WEST), WEST)
+ DO_MOVE(WEST)
+
+#undef DO_MOVE
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 64ffdbed901..959b0ad99e3 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -28,8 +28,10 @@
/mob/new_player/proc/new_player_panel_proc()
var/output = "