diff --git a/_maps/shuttles/emergency_arena.dmm b/_maps/shuttles/emergency_arena.dmm
index 1314b8a732..2ba9206830 100644
--- a/_maps/shuttles/emergency_arena.dmm
+++ b/_maps/shuttles/emergency_arena.dmm
@@ -43,7 +43,7 @@
},
/area/shuttle/escape/arena)
"l" = (
-/obj/structure/closet/crate/necropolis/tendril,
+/obj/structure/closet/crate/necropolis/tendril/magic,
/turf/open/indestructible/necropolis/air,
/area/shuttle/escape/arena)
"m" = (
@@ -65,10 +65,18 @@
/obj/structure/healingfountain,
/turf/open/indestructible/necropolis/air,
/area/shuttle/escape/arena)
+"t" = (
+/obj/structure/closet/crate/necropolis/tendril/misc,
+/turf/open/indestructible/necropolis/air,
+/area/shuttle/escape/arena)
"z" = (
/obj/effect/landmark/shuttle_arena_safe,
/turf/open/indestructible/necropolis/air,
/area/shuttle/escape/arena)
+"H" = (
+/obj/structure/closet/crate/necropolis/tendril/weapon_armor,
+/turf/open/indestructible/necropolis/air,
+/area/shuttle/escape/arena)
(1,1,1) = {"
a
@@ -264,16 +272,16 @@ m
l
j
m
-l
+H
j
k
-l
+H
j
m
-l
+t
j
m
-j
+t
j
p
g
@@ -524,16 +532,16 @@ m
l
j
m
-l
+H
j
m
-l
+H
j
m
-l
+t
j
m
-j
+t
j
p
g
diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm
new file mode 100644
index 0000000000..35d99a982d
--- /dev/null
+++ b/code/__DEFINES/research/anomalies.dm
@@ -0,0 +1,21 @@
+// Anomaly core types
+/// Bluespace cores
+#define ANOMALY_CORE_BLUESPACE /obj/item/assembly/signaler/anomaly/bluespace
+/// Gravitational cores
+#define ANOMALY_CORE_GRAVITATIONAL /obj/item/assembly/signaler/anomaly/grav
+/// Flux
+#define ANOMALY_CORE_FLUX /obj/item/assembly/signaler/anomaly/flux
+/// Vortex
+#define ANOMALY_CORE_VORTEX /obj/item/assembly/signaler/anomaly/vortex
+/// Pyro
+#define ANOMALY_CORE_PYRO /obj/item/assembly/signaler/anomaly/pyro
+
+// Max amounts of cores you can make
+#define MAX_CORES_BLUESPACE 8
+#define MAX_CORES_GRAVITATIONAL 8
+#define MAX_CORES_FLUX 8
+#define MAX_CORES_VORTEX 8
+#define MAX_CORES_PYRO 8
+
+/// chance supermatter anomalies drop real cores
+#define SUPERMATTER_ANOMALY_DROP_CHANCE 20
diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm
index 8b4f8d5b54..aad5b4cab1 100644
--- a/code/__HELPERS/files.dm
+++ b/code/__HELPERS/files.dm
@@ -71,3 +71,18 @@
/proc/pathflatten(path)
return replacetext(path, "/", "_")
+
+/// Returns the md5 of a file at a given path.
+/proc/md5filepath(path)
+ . = md5(file(path))
+
+/// Save file as an external file then md5 it.
+/// Used because md5ing files stored in the rsc sometimes gives incorrect md5 results.
+/proc/md5asfile(file)
+ var/static/notch = 0
+ // its importaint this code can handle md5filepath sleeping instead of hard blocking, if it's converted to use rust_g.
+ var/filename = "tmp/md5asfile.[world.realtime].[world.timeofday].[world.time].[world.tick_usage].[notch]"
+ notch = WRAP(notch+1, 0, 2^15)
+ fcopy(file, filename)
+ . = md5filepath(filename)
+ fdel(filename)
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 11332863f5..2bd477d98c 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -1126,12 +1126,13 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
var/list/partial = splittext(iconData, "{")
return replacetext(copytext_char(partial[2], 3, -5), "\n", "")
-/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
+/proc/icon2html(thing, target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE)
if (!thing)
return
var/key
var/icon/I = thing
+
if (!target)
return
if (target == world)
@@ -1147,17 +1148,26 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
if (!isicon(I))
if (isfile(thing)) //special snowflake
var/name = sanitize_filename("[generate_asset_name(thing)].png")
- if(!SSassets.cache[name])
+ if (!SSassets.cache[name])
SSassets.transport.register_asset(name, thing)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, name)
+ if(sourceonly)
+ return SSassets.transport.get_asset_url(name)
return "
"
var/atom/A = thing
- if (isnull(dir))
- dir = A.dir
+
+ I = A.icon
if (isnull(icon_state))
icon_state = A.icon_state
- I = A.icon
+ if (!(icon_state in icon_states(I, 1)))
+ icon_state = initial(A.icon_state)
+ if (isnull(dir))
+ dir = initial(A.dir)
+
+ if (isnull(dir))
+ dir = A.dir
+
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
var/icon/temp = I
I = icon()
diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm
index c639a91439..b814ba4be8 100644
--- a/code/controllers/subsystem/research.dm
+++ b/code/controllers/subsystem/research.dm
@@ -301,6 +301,17 @@ SUBSYSTEM_DEF(research)
//[88nodes * 5000points/node] / [1.5hr * 90min/hr * 60s/min]
//Around 450000 points max???
+ /// The global list of raw anomaly types that have been refined, for hard limits.
+ var/list/created_anomaly_types = list()
+ /// The hard limits of cores created for each anomaly type. For faster code lookup without switch statements.
+ var/list/anomaly_hard_limit_by_type = list(
+ ANOMALY_CORE_BLUESPACE = MAX_CORES_BLUESPACE,
+ ANOMALY_CORE_PYRO = MAX_CORES_PYRO,
+ ANOMALY_CORE_GRAVITATIONAL = MAX_CORES_GRAVITATIONAL,
+ ANOMALY_CORE_VORTEX = MAX_CORES_VORTEX,
+ ANOMALY_CORE_FLUX = MAX_CORES_FLUX
+ )
+
/datum/controller/subsystem/research/Initialize()
point_types = TECHWEB_POINT_TYPE_LIST_ASSOCIATIVE_NAMES
initialize_all_techweb_designs()
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index cfb4c9a120..795508320b 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
var/turf/T = get_turf(loc)
ram_turf(T)
- if(prob(10) && !isspaceturf(T))//randomly takes a 'hit' from ramming
+ if(prob(10) && !isspaceturf(T) && !istype(T, /turf/closed/mineral) && !istype(T, /turf/open/floor/plating/asteroid))//randomly takes a 'hit' from ramming
get_hit()
/obj/effect/meteor/Destroy()
@@ -136,7 +136,8 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
if(A)
ram_turf(get_turf(A))
playsound(src.loc, meteorsound, 40, 1)
- get_hit()
+ if(!istype(A, /turf/closed/mineral) && !istype(A, /turf/open/floor/plating/asteroid))
+ get_hit()
/obj/effect/meteor/proc/ram_turf(turf/T)
//first bust whatever is in the turf
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 2b7411d03f..b82d932e6d 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -551,4 +551,4 @@ Class Procs:
AM.pixel_y = -8 + (round( . / 3)*8)
/obj/machinery/rust_heretic_act()
- take_damage(500, BRUTE, "melee", 1)
+ take_damage(500, BRUTE, "melee", 1)
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 871fe838d7..7e3a5205de 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -17,11 +17,15 @@
var/countdown_colour
var/obj/effect/countdown/anomaly/countdown
-/obj/effect/anomaly/Initialize(mapload, new_lifespan)
+ /// chance we drop a core when neutralized
+ var/core_drop_chance = 100
+
+/obj/effect/anomaly/Initialize(mapload, new_lifespan, core_drop_chance = 100)
. = ..()
GLOB.poi_list |= src
START_PROCESSING(SSobj, src)
impact_area = get_area(src)
+ src.core_drop_chance = core_drop_chance
if (!impact_area)
return INITIALIZE_HINT_QDEL
@@ -54,6 +58,8 @@
GLOB.poi_list.Remove(src)
STOP_PROCESSING(SSobj, src)
qdel(countdown)
+ if(aSignal)
+ QDEL_NULL(aSignal)
return ..()
/obj/effect/anomaly/proc/anomalyEffect()
@@ -70,12 +76,12 @@
/obj/effect/anomaly/proc/anomalyNeutralize()
new /obj/effect/particle_effect/smoke/bad(loc)
- for(var/atom/movable/O in src)
- O.forceMove(drop_location())
+ if(prob(core_drop_chance))
+ aSignal.forceMove(drop_location())
+ aSignal = null
qdel(src)
-
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_ANALYZER) //revert if runtimed
to_chat(user, "Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].")
diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm
index 5ed719ff94..9b658bc5f1 100644
--- a/code/game/objects/items/charter.dm
+++ b/code/game/objects/items/charter.dm
@@ -13,6 +13,7 @@
var/ignores_timeout = FALSE
var/response_timer_id = null
var/approval_time = 600
+ var/allow_unicode = FALSE
var/static/regex/standard_station_regex
@@ -48,6 +49,9 @@
if(!new_name)
return
+ if(!allow_unicode && (length(new_name) != length_char(new_name)))
+ to_chat(user, "Unicode is not allowed. Adminhelp if you want to use it so badly.")
+ return
log_game("[key_name(user)] has proposed to name the station as \
[new_name]")
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 806aed92ed..8e59e91e38 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -1146,3 +1146,8 @@
build_path = /obj/machinery/atmospherics/components/unary/shuttle/heater
req_components = list(/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/matter_bin = 1)
+
+/obj/item/circuitboard/machine/explosive_compressor
+ name = "Explosive Compressor (Machine Board)"
+ build_path = /obj/machinery/research/explosive_compressor
+ req_components = list(/obj/item/stock_parts/matter_bin = 3)
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 277d132b12..6396a4fe3d 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -445,8 +445,7 @@
if(do_after(user, isnull(defib?.disarm_shock_time)? disarm_shock_time : defib.disarm_shock_time, target = M))
M.visible_message("[user] zaps [M] with [src]!", \
"[user] zaps [M] with [src]!")
- M.adjustStaminaLoss(50)
- M.DefaultCombatKnockdown(100)
+ M.DefaultCombatKnockdown(140)
M.updatehealth() //forces health update before next life tick
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
M.emote("gasp")
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 32d9c02a27..8b0d46be44 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -289,3 +289,9 @@
. = TRUE
update_icon()
+
+/**
+ * Returns if this is ready to be detonated. Checks if both tanks are in place.
+ */
+/obj/item/transfer_valve/proc/ready()
+ return tank_one && tank_two
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 653e95c21e..3f2dc2506a 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -237,6 +237,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
resistance_flags = FIRE_PROOF
total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
+/obj/item/katana/lavaland
+ desc = "Woefully underpowered in Lavaland."
+ block_chance = 30
+ force = 25 //Like a fireaxe but one handed and can block!
+
/obj/item/katana/cursed
slot_flags = null
diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm
index 2911babd83..edc4f0c91f 100644
--- a/code/game/objects/structures/lavaland/necropolis_tendril.dm
+++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm
@@ -10,6 +10,7 @@
max_mobs = 3
max_integrity = 250
mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril)
+ var/loot_type = /obj/structure/closet/crate/necropolis/tendril/all
move_resist=INFINITY // just killing it tears a massive hole in the ground, let's not move it
anchored = TRUE
@@ -41,7 +42,7 @@ GLOBAL_LIST_INIT(tendrils, list())
/obj/structure/spawner/lavaland/deconstruct(disassembled)
new /obj/effect/collapse(loc)
- new /obj/structure/closet/crate/necropolis/tendril(loc)
+ new loot_type(loc)
return ..()
diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm
index 41cee06db1..72d976bf11 100644
--- a/code/modules/asset_cache/asset_cache_item.dm
+++ b/code/modules/asset_cache/asset_cache_item.dm
@@ -24,12 +24,10 @@
/datum/asset_cache_item/New(name, file)
if (!isfile(file))
file = fcopy_rsc(file)
- hash = md5(file)
+
+ hash = md5asfile(file) //icons sent to the rsc sometimes md5 incorrectly
if (!hash)
- hash = md5(fcopy_rsc(file))
- if (!hash)
- CRASH("invalid asset sent to asset cache")
- debug_world_log("asset cache unexpected success of second fcopy_rsc")
+ CRASH("invalid asset sent to asset cache")
src.name = name
var/extstart = findlasttext(name, ".")
if (extstart)
diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm
index fd6fee362d..125bfe2034 100644
--- a/code/modules/cargo/packs/science.dm
+++ b/code/modules/cargo/packs/science.dm
@@ -192,3 +192,49 @@
crate_type = /obj/structure/closet/crate/secure/science
dangerous = TRUE
+//////// RAW ANOMALY CORES
+
+/datum/supply_pack/science/raw_flux_anomaly
+ name = "Raw Flux Anomaly"
+ desc = "The raw core of a flux anomaly, ready to be implosion-compressed into a powerful artifact."
+ cost = 5000
+ access = ACCESS_TOX
+ contains = list(/obj/item/raw_anomaly_core/flux)
+ crate_name = "raw flux anomaly"
+ crate_type = /obj/structure/closet/crate/secure/science
+
+/datum/supply_pack/science/raw_grav_anomaly
+ name = "Raw Gravitational Anomaly"
+ desc = "The raw core of a gravitational anomaly, ready to be implosion-compressed into a powerful artifact."
+ cost = 5000
+ access = ACCESS_TOX
+ contains = list(/obj/item/raw_anomaly_core/grav)
+ crate_name = "raw pyro anomaly"
+ crate_type = /obj/structure/closet/crate/secure/science
+
+/datum/supply_pack/science/raw_vortex_anomaly
+ name = "Raw Vortex Anomaly"
+ desc = "The raw core of a vortex anomaly, ready to be implosion-compressed into a powerful artifact."
+ cost = 5000
+ access = ACCESS_TOX
+ contains = list(/obj/item/raw_anomaly_core/vortex)
+ crate_name = "raw vortex anomaly"
+ crate_type = /obj/structure/closet/crate/secure/science
+
+/datum/supply_pack/science/raw_bluespace_anomaly
+ name = "Raw Bluespace Anomaly"
+ desc = "The raw core of a bluespace anomaly, ready to be implosion-compressed into a powerful artifact."
+ cost = 5000
+ access = ACCESS_TOX
+ contains = list(/obj/item/raw_anomaly_core/bluespace)
+ crate_name = "raw bluespace anomaly"
+ crate_type = /obj/structure/closet/crate/secure/science
+
+/datum/supply_pack/science/raw_pyro_anomaly
+ name = "Raw Pyro Anomaly"
+ desc = "The raw core of a pyro anomaly, ready to be implosion-compressed into a powerful artifact."
+ cost = 5000
+ access = ACCESS_TOX
+ contains = list(/obj/item/raw_anomaly_core/pyro)
+ crate_name = "raw pyro anomaly"
+ crate_type = /obj/structure/closet/crate/secure/science
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 80ce2522ff..a4d88158e2 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -22,7 +22,7 @@
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
var/state = 0
- var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/book) //Things allowed in the bookcase
+ var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/book, /obj/item/gun/magic/wand/book) //Things allowed in the bookcase
/obj/structure/bookcase/examine(mob/user)
. = ..()
@@ -192,7 +192,7 @@
desc = "Crack it open, inhale the musk of its pages, and learn something new."
throw_speed = 1
throw_range = 5
- w_class = WEIGHT_CLASS_NORMAL //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever)
+ w_class = WEIGHT_CLASS_NORMAL //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever)
attack_verb = list("bashed", "whacked", "educated")
resistance_flags = FLAMMABLE
var/dat //Actual page content
diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm
index 27259ce812..31ee37c3b0 100644
--- a/code/modules/mining/equipment/mining_tools.dm
+++ b/code/modules/mining/equipment/mining_tools.dm
@@ -66,6 +66,16 @@
force = 19
custom_materials = list(/datum/material/diamond=4000)
+/obj/item/pickaxe/rosegold
+ name = "rose gold pickaxe"
+ icon_state = "rgpickaxe"
+ item_state = "rgpickaxe"
+ toolspeed = 0.1
+ desc = "A pickaxe with a light rose gold head and some red glowing runes. Extremely robust at cracking rock walls and digging up dirt."
+ force = 19
+ custom_materials = list(/datum/material/gold=4000)
+ digrange = 3
+
/obj/item/pickaxe/plasteel
name = "plasteel-tipped pickaxe"
icon_state = "titaxe"
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 9a136decb6..746d8ecabe 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -7,78 +7,202 @@
icon_state = "necrocrate"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+/obj/structure/closet/crate/necropolis/tendril/random
+ name = "necropolis crate"
+ desc = "A chest for a chest, a head for a head."
+
+/obj/structure/closet/crate/necropolis/tendril/random/PopulateContents()
+ var/loot = rand(1,3)
+ switch(loot)
+ if(1)
+ new /obj/structure/closet/crate/necropolis/tendril/magic(src)
+ if(2)
+ new /obj/structure/closet/crate/necropolis/tendril/weapon_armor(src)
+ if(3)
+ new /obj/structure/closet/crate/necropolis/tendril/misc(src)
+
/obj/structure/closet/crate/necropolis/tendril
desc = "It's watching you suspiciously."
-/obj/structure/closet/crate/necropolis/tendril/PopulateContents()
- var/loot = rand(1,29)
+/obj/structure/closet/crate/necropolis/tendril/magic
+ name = "relic necropolis chest"
+
+/obj/structure/closet/crate/necropolis/tendril/weapon_armor
+ name = "armament necropolis chest"
+
+/obj/structure/closet/crate/necropolis/tendril/misc
+
+/obj/structure/closet/crate/necropolis/tendril/all
+ desc = "It's watching you suspiciously."
+
+/obj/structure/closet/crate/necropolis/tendril/magic/PopulateContents()
+ var/loot = rand(1,10)
switch(loot)
if(1)
- new /obj/item/shared_storage/red(src)
- if(2)
- new /obj/item/clothing/suit/space/hardsuit/cult(src)
- if(3)
new /obj/item/soulstone/anybody(src)
+ if(2)
+ new /obj/item/rod_of_asclepius(src)
+ if(3)
+ new /obj/item/organ/heart/cursed/wizard(src)
if(4)
- new /obj/item/katana/cursed(src)
+ new /obj/item/book/granter/spell/summonitem(src)
if(5)
- new /obj/item/clothing/glasses/godeye(src)
+ new /obj/item/borg/upgrade/modkit/lifesteal(src)
+ new /obj/item/bedsheet/cult(src)
if(6)
- new /obj/item/reagent_containers/glass/bottle/potion/flight(src)
+ new /obj/item/clothing/neck/necklace/memento_mori(src)
if(7)
- new /obj/item/pickaxe/diamond(src)
+ new /obj/item/warp_cube/red(src)
if(8)
+ new /obj/item/immortality_talisman(src)
+ if(9)
+ new /obj/item/gun/magic/wand/book/healing(src)
+ if(10)
+ new /obj/item/reagent_containers/glass/bottle/ichor/red(src)
+ new /obj/item/reagent_containers/glass/bottle/ichor/blue(src)
+ new /obj/item/reagent_containers/glass/bottle/ichor/green(src)
+
+/obj/structure/closet/crate/necropolis/tendril/weapon_armor/PopulateContents()
+ var/loot = rand(1,11)
+ switch(loot)
+ if(1)
+ new /obj/item/clothing/suit/space/hardsuit/cult(src)
+ if(2)
+ new /obj/item/katana/lavaland(src)
+ if(3)
if(prob(50))
new /obj/item/disk/design_disk/modkit_disc/resonator_blast(src)
else
new /obj/item/disk/design_disk/modkit_disc/rapid_repeater(src)
- if(9)
- new /obj/item/rod_of_asclepius(src)
- if(10)
- new /obj/item/organ/heart/cursed/wizard(src)
- if(11)
- new /obj/item/ship_in_a_bottle(src)
- if(12)
+ if(4)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old(src)
- if(13)
- new /obj/item/jacobs_ladder(src)
- if(14)
+ if(5)
new /obj/item/nullrod/scythe/talking(src)
- if(15)
+ if(6)
new /obj/item/nullrod/armblade(src)
- if(16)
- new /obj/item/guardiancreator(src)
- if(17)
+ if(7)
+ new /obj/item/reagent_containers/food/drinks/bottle/holywater/hell(src)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old(src)
+ if(8)
+ new /obj/item/grenade/clusterbuster/inferno(src)
+ if(9)
+ new /obj/item/gun/magic/wand/book/shock(src)
+ if(10)
+ new /obj/item/gun/magic/wand/book/page(src)
+ if(11)
+ new /obj/item/gun/magic/wand/book/spark(src)
+
+/obj/structure/closet/crate/necropolis/tendril/misc/PopulateContents()
+ var/loot = rand(1,11)
+ switch(loot)
+ if(1)
+ new /obj/item/shared_storage/red(src)
+ if(2)
+ new /obj/item/reagent_containers/glass/bottle/potion/flight(src)
+ if(3)
+ new /obj/item/ship_in_a_bottle(src)
+ if(4)
+ new /obj/item/voodoo(src)
+ if(5)
+ new /obj/item/book_of_babel(src)
+ if(6)
+ new /obj/item/jacobs_ladder(src)
+ if(7)
if(prob(50))
new /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe(src)
else
new /obj/item/disk/design_disk/modkit_disc/bounty(src)
- if(18)
- new /obj/item/warp_cube/red(src)
- if(19)
+ if(8)
new /obj/item/wisp_lantern(src)
- if(20)
- new /obj/item/immortality_talisman(src)
- if(21)
- new /obj/item/gun/magic/hook(src)
- if(22)
+ if(9)
+ new /obj/item/pickaxe/rosegold(src)
+ if(10)
+ new /obj/item/bedsheet/cosmos(src)
+ new /obj/item/melee/skateboard/hoverboard(src)
+ if(11)
+ if(prob(50))
+ new /obj/item/malf_upgrade
+ else
+ new /obj/item/disk/tech_disk/illegal
+ if(12)
+ new /obj/item/clothing/suit/space/hardsuit/cult(src)
+ if(13)
+ new /obj/item/katana/lavaland(src)
+ if(14)
+ if(prob(50))
+ new /obj/item/disk/design_disk/modkit_disc/resonator_blast(src)
+ else
+ new /obj/item/disk/design_disk/modkit_disc/rapid_repeater(src)
+
+/obj/structure/closet/crate/necropolis/tendril/all/PopulateContents()
+ var/loot = rand(1,31)
+ switch(loot)
+ if(1)
+ new /obj/item/shared_storage/red(src)
+ if(2)
+ new /obj/item/reagent_containers/glass/bottle/potion/flight(src)
+ if(3)
+ new /obj/item/ship_in_a_bottle(src)
+ if(4)
new /obj/item/voodoo(src)
- if(23)
- new /obj/item/grenade/clusterbuster/inferno(src)
- if(24)
+ if(5)
+ new /obj/item/book_of_babel(src)
+ if(6)
+ new /obj/item/jacobs_ladder(src)
+ if(7)
+ if(prob(50))
+ new /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe(src)
+ else
+ new /obj/item/disk/design_disk/modkit_disc/bounty(src)
+ if(8)
+ new /obj/item/wisp_lantern(src)
+ if(9)
+ new /obj/item/pickaxe/rosegold(src)
+ if(10)
+ new /obj/item/bedsheet/cosmos(src)
+ new /obj/item/melee/skateboard/hoverboard(src)
+ if(11)
+ new /obj/item/disk/tech_disk/illegal
+ if(15)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old(src)
+ if(16)
+ new /obj/item/nullrod/scythe/talking(src)
+ if(17)
+ new /obj/item/nullrod/armblade(src)
+ if(18)
new /obj/item/reagent_containers/food/drinks/bottle/holywater/hell(src)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old(src)
+ if(19)
+ new /obj/item/grenade/clusterbuster/inferno(src)
+ if(20)
+ new /obj/item/gun/magic/wand/book/shock(src)
+ if(21)
+ new /obj/item/gun/magic/wand/book/page(src)
+ if(22)
+ new /obj/item/gun/magic/wand/book/spark(src)
+ if(23)
+ new /obj/item/soulstone/anybody(src)
+ if(24)
+ new /obj/item/rod_of_asclepius(src)
if(25)
- new /obj/item/book/granter/spell/summonitem(src)
+ new /obj/item/organ/heart/cursed/wizard(src)
if(26)
- new /obj/item/book_of_babel(src)
+ new /obj/item/book/granter/spell/summonitem(src)
if(27)
new /obj/item/borg/upgrade/modkit/lifesteal(src)
new /obj/item/bedsheet/cult(src)
if(28)
new /obj/item/clothing/neck/necklace/memento_mori(src)
+ if(28)
+ new /obj/item/warp_cube/red(src)
if(29)
- new /obj/item/disk/tech_disk/illegal(src)
+ new /obj/item/immortality_talisman(src)
+ if(30)
+ new /obj/item/gun/magic/wand/book/healing(src)
+ if(31)
+ new /obj/item/reagent_containers/glass/bottle/ichor/red(src)
+ new /obj/item/reagent_containers/glass/bottle/ichor/blue(src)
+ new /obj/item/reagent_containers/glass/bottle/ichor/green(src)
//KA modkit design discs
/obj/item/disk/design_disk/modkit_disc
@@ -744,7 +868,7 @@
new /obj/item/lava_staff(src)
if(3)
new /obj/item/book/granter/spell/sacredflame(src)
- new /obj/item/gun/magic/wand/fireball(src)
+ new /obj/item/gun/magic/hook(src)
if(4)
new /obj/item/dragons_blood(src)
@@ -983,7 +1107,7 @@
if(2)
new /obj/item/gun/ballistic/revolver/doublebarrel/super(src)
if(3)
- new /obj/item/gun/magic/staff/spellblade(src)
+ new /obj/item/guardiancreator(src)
/obj/structure/closet/crate/necropolis/bubblegum/crusher
name = "bloody bubblegum chest"
@@ -1072,6 +1196,7 @@
var/random_crystal = pick(choices)
new random_crystal(src)
new /obj/item/organ/vocal_cords/colossus(src)
+ new /obj/item/clothing/glasses/godeye(src)
/obj/structure/closet/crate/necropolis/colossus/crusher
name = "angelic colossus chest"
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index 795184bad5..3de4c8b41b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -141,7 +141,7 @@ Difficulty: Medium
loot = list(/obj/item/staff/storm)
elimination = 0
else if(prob(20))
- loot = list(/obj/structure/closet/crate/necropolis/tendril)
+ loot = list(/obj/structure/closet/crate/necropolis/tendril/random) //This one spawns a chest that could be any of the three types
..()
/obj/item/gps/internal/legion
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index e3edd171c0..e347056924 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -25,6 +25,7 @@
var/list/attack_action_types = list()
var/can_talk = FALSE
var/obj/loot_drop = null
+ var/crate_type = /obj/structure/closet/crate/necropolis/tendril
var/owner
//Gives player-controlled variants the ability to swap attacks
@@ -182,7 +183,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
activator = null
-obj/structure/elite_tumor/proc/spawn_elite(var/mob/dead/observer/elitemind)
+/obj/structure/elite_tumor/proc/spawn_elite(var/mob/dead/observer/elitemind)
var/selectedspawn = pick(potentialspawns)
mychild = new selectedspawn(loc)
visible_message("[mychild] emerges from [src]!")
@@ -193,7 +194,7 @@ obj/structure/elite_tumor/proc/spawn_elite(var/mob/dead/observer/elitemind)
icon_state = "tumor_popped"
INVOKE_ASYNC(src, .proc/arena_checks)
-obj/structure/elite_tumor/proc/return_elite()
+/obj/structure/elite_tumor/proc/return_elite()
mychild.forceMove(loc)
visible_message("[mychild] emerges from [src]!")
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
@@ -271,11 +272,11 @@ obj/structure/elite_tumor/proc/return_elite()
visible_message("[mychild] suddenly reappears above [src]!")
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
-obj/structure/elite_tumor/proc/onEliteLoss()
+/obj/structure/elite_tumor/proc/onEliteLoss()
playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, 0, 50, TRUE, TRUE)
visible_message("[src] begins to convulse violently before beginning to dissipate.")
visible_message("As [src] closes, something is forced up from down below.")
- var/obj/structure/closet/crate/necropolis/tendril/lootbox = new /obj/structure/closet/crate/necropolis/tendril(loc)
+ var/obj/structure/closet/crate/necropolis/tendril/lootbox = new mychild.crate_type(loc)
if(!boosted)
mychild = null
activator = null
@@ -290,7 +291,7 @@ obj/structure/elite_tumor/proc/onEliteLoss()
activator = null
qdel(src)
-obj/structure/elite_tumor/proc/onEliteWon()
+/obj/structure/elite_tumor/proc/onEliteWon()
activity = TUMOR_PASSIVE
activator = null
mychild.revive(full_heal = TRUE, admin_revive = TRUE)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
index d9f3cfba3d..4e8f4f6160 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
@@ -40,6 +40,7 @@
mouse_opacity = MOUSE_OPACITY_ICON
deathmessage = "explodes into gore!"
loot_drop = /obj/item/crusher_trophy/broodmother_tongue
+ crate_type = /obj/structure/closet/crate/necropolis/tendril/weapon_armor
attack_action_types = list(/datum/action/innate/elite_attack/tentacle_patch,
/datum/action/innate/elite_attack/spawn_children,
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
index fce5b636e4..032bc2d60d 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
@@ -38,7 +38,7 @@
deathsound = 'sound/magic/demon_dies.ogg'
deathmessage = "begins to shudder as it becomes transparent..."
loot_drop = /obj/item/clothing/neck/cloak/herald_cloak
-
+ crate_type = /obj/structure/closet/crate/necropolis/tendril/magic
can_talk = 1
attack_action_types = list(/datum/action/innate/elite_attack/herald_trishot,
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
index 15ed0135fe..6c13bb903e 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
@@ -38,7 +38,7 @@
deathsound = 'sound/magic/curse.ogg'
deathmessage = "'s arms reach out before it falls apart onto the floor, lifeless."
loot_drop = /obj/item/crusher_trophy/legionnaire_spine
-
+ crate_type = /obj/structure/closet/crate/necropolis/tendril/misc
attack_action_types = list(/datum/action/innate/elite_attack/legionnaire_charge,
/datum/action/innate/elite_attack/head_detach,
/datum/action/innate/elite_attack/bonfire_teleport,
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
index 7995e4d20f..b3300a86bb 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
@@ -38,7 +38,7 @@
deathsound = 'sound/magic/repulse.ogg'
deathmessage = "'s lights flicker, before its top part falls down."
loot_drop = /obj/item/clothing/accessory/pandora_hope
-
+ crate_type = /obj/structure/closet/crate/necropolis/tendril/magic
attack_action_types = list(/datum/action/innate/elite_attack/singular_shot,
/datum/action/innate/elite_attack/magic_box,
/datum/action/innate/elite_attack/pandora_teleport,
@@ -190,4 +190,4 @@
/obj/item/clothing/accessory/pandora_hope/on_uniform_dropped(obj/item/clothing/under/U, user)
var/mob/living/L = user
if(L && L.mind)
- SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "hope_lavaland")
+ SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "hope_lavaland")
\ No newline at end of file
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index d4e3f6ad0d..e3fdbd3654 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -639,7 +639,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(produces_gas)
env.merge(removed)
air_update_turf()
-
+
/*********
END CITADEL CHANGES
*********/
@@ -1033,12 +1033,12 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(L)
switch(type)
if(FLUX_ANOMALY)
- var/obj/effect/anomaly/flux/A = new(L, 300, FALSE)
+ var/obj/effect/anomaly/flux/A = new(L, 300, SUPERMATTER_ANOMALY_DROP_CHANCE)
A.explosive = FALSE
if(GRAVITATIONAL_ANOMALY)
- new /obj/effect/anomaly/grav(L, 250, FALSE)
+ new /obj/effect/anomaly/grav(L, 250, SUPERMATTER_ANOMALY_DROP_CHANCE)
if(PYRO_ANOMALY)
- new /obj/effect/anomaly/pyro(L, 200, FALSE)
+ new /obj/effect/anomaly/pyro(L, 200, SUPERMATTER_ANOMALY_DROP_CHANCE)
/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list())
if(QDELETED(zapstart))
diff --git a/code/modules/projectiles/ammunition/special/magic.dm b/code/modules/projectiles/ammunition/special/magic.dm
index cc039c5f2b..8380bf82e9 100644
--- a/code/modules/projectiles/ammunition/special/magic.dm
+++ b/code/modules/projectiles/ammunition/special/magic.dm
@@ -43,3 +43,17 @@
/obj/item/ammo_casing/magic/locker
projectile_type = /obj/item/projectile/magic/locker
+
+//Spell book ammo casing
+/obj/item/ammo_casing/magic/book
+ projectile_type = /obj/item/projectile/magic/spellcard/book
+
+/obj/item/ammo_casing/magic/book/spark
+ projectile_type = /obj/item/projectile/magic/spellcard/book/spark
+
+/obj/item/ammo_casing/magic/book/heal
+ projectile_type = /obj/item/projectile/magic/spellcard/book/heal
+ harmful = FALSE
+
+/obj/item/ammo_casing/magic/book/shock
+ projectile_type = /obj/item/projectile/magic/spellcard/book/shock
diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
index 78ca6e9280..9ea030da99 100644
--- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm
+++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
@@ -20,7 +20,6 @@
var/caliber
var/multiload = 1
var/start_empty = 0
- var/load_delay = 0 //how long do we take to load (deciseconds)
var/list/bullet_cost
var/list/base_cost// override this one as well if you override bullet_cost
@@ -76,19 +75,12 @@
return 1
/obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = FALSE, replace_spent = 0)
- if(INTERACTING_WITH(user, src) || INTERACTING_WITH(user, A))
- to_chat(user, "You're already doing that!")
- return FALSE
var/num_loaded = 0
if(!can_load(user))
return
if(istype(A, /obj/item/ammo_box))
var/obj/item/ammo_box/AM = A
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
- if(load_delay || AM.load_delay)
- var/loadtime = max(AM.load_delay, load_delay)
- if(!do_after(user, loadtime, target = src))
- return FALSE
var/did_load = give_round(AC, replace_spent)
if(did_load)
AM.stored_ammo -= AC
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index 8cd49bdf16..70058801f8 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -156,8 +156,6 @@
max_ammo = 4
var/pixeloffsetx = 4
start_empty = TRUE
- multiload = FALSE
- load_delay = 6 //6ds
/obj/item/ammo_box/shotgun/update_overlays()
. = ..()
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index 1aefa51a51..fa8099a257 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -53,8 +53,6 @@
..()
if (istype(A, /obj/item/ammo_box/magazine))
var/obj/item/ammo_box/magazine/AM = A
- if(AM.load_delay && !do_after(user, AM.load_delay, target = src))
- return FALSE
if (!magazine && istype(AM, mag_type))
if(user.transferItemToLoc(AM, src))
magazine = AM
diff --git a/code/modules/projectiles/guns/ballistic/magweapon.dm b/code/modules/projectiles/guns/ballistic/magweapon.dm
index 4e27a73300..c01a2fb74a 100644
--- a/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -51,11 +51,6 @@
cell.use(shot.energy_cost)
. = ..()
-/obj/item/gun/ballistic/automatic/magrifle/emp_act(severity)
- . = ..()
- if(!(. & EMP_PROTECT_CONTENTS))
- cell.use(round(cell.charge / severity))
-
/obj/item/gun/ballistic/automatic/magrifle/get_cell()
return cell
diff --git a/code/modules/projectiles/guns/magic/spell_book.dm b/code/modules/projectiles/guns/magic/spell_book.dm
new file mode 100644
index 0000000000..752a6ae5ac
--- /dev/null
+++ b/code/modules/projectiles/guns/magic/spell_book.dm
@@ -0,0 +1,66 @@
+/obj/item/gun/magic/wand/book
+ name = "blank spellbook"
+ desc = "It's not just a book, it's a SPELL book!"
+ ammo_type = /obj/item/ammo_casing/magic
+ icon = 'icons/obj/library.dmi'
+ icon_state = "book"
+ w_class = WEIGHT_CLASS_NORMAL
+ charges = 10 //We start with max pages
+ max_charges = 10
+ variable_charges = FALSE
+
+/obj/item/gun/magic/wand/book/zap_self(mob/living/user)
+ to_chat(user, "The book has [charges] pages\s remaining.")
+
+/obj/item/gun/magic/wand/book/attackby(obj/item/S, mob/living/user, params)
+ if(!istype(S, /obj/item/paper))
+ return ..()
+ if(charges < max_charges)
+ charges++
+ recharge_newshot()
+ to_chat(user, "You add a new page to [src].")
+ qdel(S)
+ update_icon()
+ process()
+ else
+ to_chat(user, "The [src] has no more room for pages!")
+
+//////////////////////
+//Spell Book - SPARK//
+//////////////////////
+
+/obj/item/gun/magic/wand/book/spark
+ name = "Spell Book of Spark"
+ desc = "A spell book that fires burn pages to set the target ablaze!"
+ ammo_type = /obj/item/ammo_casing/magic/book/spark
+ icon_state = "spellbook_spark"
+
+//////////////////////
+//Spell Book - PAGE///
+//////////////////////
+
+/obj/item/gun/magic/wand/book/page
+ name = "Spell Book of Throw"
+ desc = "A spell book that throws pages at its target!"
+ ammo_type = /obj/item/ammo_casing/magic/book
+ icon_state = "spellbook_page"
+
+//////////////////////
+//Spell Book - SHOCK//
+//////////////////////
+
+/obj/item/gun/magic/wand/book/shock
+ name = "Spell Book of Shock"
+ desc = "A spell book that uses its pages to capture energy in the air and send it in a bolt at its target!"
+ ammo_type = /obj/item/ammo_casing/magic/book/shock
+ icon_state = "spellbook_shock"
+
+////////////////////////
+//Spell Book - HEALING//
+////////////////////////
+
+/obj/item/gun/magic/wand/book/healing
+ name = "Spell Book of Mending"
+ desc = "A spell book that uses its pages to heal and repair the target! The back of the book lists what it works on, and it seems to only be of flesh and of metal beings..."
+ ammo_type = /obj/item/ammo_casing/magic/book/heal
+ icon_state = "spellbook_healing"
diff --git a/code/modules/projectiles/projectile/magic/spellcard.dm b/code/modules/projectiles/projectile/magic/spellcard.dm
index 1b8f326573..5015a97e78 100644
--- a/code/modules/projectiles/projectile/magic/spellcard.dm
+++ b/code/modules/projectiles/projectile/magic/spellcard.dm
@@ -4,3 +4,60 @@
icon_state = "spellcard"
damage_type = BURN
damage = 2
+
+/obj/item/projectile/magic/spellcard/book
+ nodamage = FALSE
+ name = "enchanted page"
+ desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
+ icon_state = "spellcard"
+ damage_type = BURN
+ damage = 12
+ flag = "magic"
+
+/obj/item/projectile/magic/spellcard/book/spark
+ damage = 4
+ var/fire_stacks = 4
+
+/obj/item/projectile/magic/spellcard/book/spark/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ var/mob/living/carbon/M = target
+ if(ismob(target))
+ if(M.anti_magic_check())
+ M.visible_message("[src] vanishes on contact with [target]!")
+ return BULLET_ACT_BLOCK
+
+ if(iscarbon(target))
+ M.adjust_fire_stacks(fire_stacks)
+ M.IgniteMob()
+ return
+ else
+ damage = 20 //If we are a simplemob we deal 5x damage
+
+/obj/item/projectile/magic/spellcard/book/shock
+ damage = 0
+ stamina = 11
+ stutter = 5
+ jitter = 20
+ knockdown = 10
+
+/obj/item/projectile/magic/spellcard/book/heal
+ damage = 0
+ nodamage = TRUE
+
+/obj/item/projectile/magic/spellcard/book/heal/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ var/mob/living/carbon/M = target
+ if(ismob(target))
+ if(M.anti_magic_check())
+ M.visible_message("[src] vanishes on contact with [target]!")
+ return BULLET_ACT_BLOCK
+ if(iscarbon(target))
+ M.visible_message("[src] mends [target]!")
+ M.adjustBruteLoss(-5) //HEALS
+ M.adjustOxyLoss(-5)
+ M.adjustBruteLoss(-5)
+ M.adjustFireLoss(-5)
+ M.adjustToxLoss(-5, TRUE) //heals TOXINLOVERs
+ M.adjustCloneLoss(-5)
+ M.adjustStaminaLoss(-5)
+ return
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 821c482883..bb9f6a978a 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -2226,6 +2226,7 @@
color = "#f7685e"
metabolization_rate = REAGENTS_METABOLISM * 0.25
+
/datum/reagent/wittel
name = "Wittel"
description = "An extremely rare metallic-white substance only found on demon-class planets."
@@ -2287,6 +2288,7 @@
/datum/reagent/gravitum/on_mob_end_metabolize(mob/living/L)
L.RemoveElement(/datum/element/forced_gravity, 0)
+
//body bluids
/datum/reagent/consumable/semen
name = "Semen"
@@ -2463,3 +2465,56 @@ datum/reagent/eldritch
return
..()
+/datum/reagent/red_ichor
+ name = "Red Ichor"
+ can_synth = FALSE
+ description = "A unknown red liquid, linked to healing of most moral wounds."
+ color = "#c10000"
+ metabolization_rate = REAGENTS_METABOLISM * 2.5
+
+/datum/reagent/red_ichor/on_mob_life(mob/living/carbon/M)
+ M.adjustBruteLoss(-50)
+ M.adjustOxyLoss(-50)
+ M.adjustBruteLoss(-50)
+ M.adjustFireLoss(-50)
+ M.adjustToxLoss(-50, TRUE) //heals TOXINLOVERs
+ M.adjustCloneLoss(-50)
+ M.adjustStaminaLoss(-50)
+ ..()
+
+/datum/reagent/green_ichor
+ name = "Green Ichor"
+ can_synth = FALSE
+ description = "A unknown green liquid, linked to healing of most internal wounds."
+ color = "#158c00"
+ metabolization_rate = REAGENTS_METABOLISM * 2.5
+
+/datum/reagent/green_ichor/on_mob_life(mob/living/carbon/M)
+ M.adjustOrganLoss(ORGAN_SLOT_LUNGS, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_HEART, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_LIVER, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_EARS, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_STOMACH, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_TONGUE, -100)
+ M.adjustOrganLoss(ORGAN_SLOT_EYES, -100)
+ ..()
+
+/datum/reagent/blue_ichor
+ name = "Blue Ichor"
+ can_synth = FALSE
+ description = "A unknown blue liquid, linked to healing the mind."
+ color = "#0914e0"
+ metabolization_rate = REAGENTS_METABOLISM * 2.5
+
+/datum/reagent/blue_ichor/on_mob_life(mob/living/carbon/M)
+ M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -100)
+ M.cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
+ M.hallucination = 0
+ M.dizziness = 0
+ M.disgust = 0
+ M.drowsyness = 0
+ M.stuttering = 0
+ M.confused = 0
+ M.SetSleeping(0, 0)
+ ..()
+
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 20abcf847f..2cd0a76a4b 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -416,3 +416,20 @@
/obj/item/reagent_containers/glass/bottle/bromine
name = "bromine bottle"
list_reagents = list(/datum/reagent/bromine = 30)
+
+//Ichors
+/obj/item/reagent_containers/glass/bottle/ichor
+ possible_transfer_amounts = list(1)
+ volume = 1
+
+/obj/item/reagent_containers/glass/bottle/ichor/red
+ name = "healing potion"
+ list_reagents = list(/datum/reagent/red_ichor = 1)
+
+/obj/item/reagent_containers/glass/bottle/ichor/blue
+ name = "blue potion"
+ list_reagents = list(/datum/reagent/blue_ichor = 1)
+
+/obj/item/reagent_containers/glass/bottle/ichor/green
+ name = "green potion"
+ list_reagents = list(/datum/reagent/green_ichor = 1)
\ No newline at end of file
diff --git a/code/modules/research/anomaly/explosive_compressor.dm b/code/modules/research/anomaly/explosive_compressor.dm
new file mode 100644
index 0000000000..23983e31dc
--- /dev/null
+++ b/code/modules/research/anomaly/explosive_compressor.dm
@@ -0,0 +1,152 @@
+#define MAX_RADIUS_REQUIRED 8000 //tritbomb
+#define MIN_RADIUS_REQUIRED 20 //maxcap
+/**
+ * # Explosive compressor machines
+ *
+ * The explosive compressor machine used in anomaly core production.
+ *
+ * Uses the standard toxins/tank explosion scaling to compress raw anomaly cores into completed ones. The required explosion radius increases as more cores of that type are created.
+ */
+/obj/machinery/research/explosive_compressor
+ name = "implosion compressor"
+ desc = "An advanced machine capable of implosion-compressing raw anomaly cores into finished artifacts."
+ icon = 'icons/obj/machines/research.dmi'
+ icon_state = "explosive_compressor"
+ density = TRUE
+ circuit = /obj/item/circuitboard/machine/explosive_compressor
+
+ /// The raw core inserted in the machine.
+ var/obj/item/raw_anomaly_core/inserted_core
+ /// The TTV inserted in the machine.
+ var/obj/item/transfer_valve/inserted_bomb
+ /// The last time we did say_requirements(), because someone will inevitably click spam this.
+ var/last_requirements_say = 0
+
+/obj/machinery/research/explosive_compressor/examine(mob/user)
+ . = ..()
+ . += "Ctrl-Click to remove an inserted core."
+ . += "Click with an empty hand to gather information about the required radius of an inserted core. Insert a ready TTV to start the implosion process if a core is inserted."
+
+/obj/machinery/research/explosive_compressor/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ if(!inserted_core)
+ to_chat(user, "There is no core inserted.")
+ return
+ if(last_requirements_say + 3 SECONDS > world.time)
+ return
+ last_requirements_say = world.time
+ say_requirements(inserted_core)
+
+/obj/machinery/research/explosive_compressor/CtrlClick(mob/living/user)
+ . = ..()
+ if(!istype(user) || !user.Adjacent(src) || !(user.mobility_flags & MOBILITY_USE))
+ return
+ if(!inserted_core)
+ to_chat(user, "There is no core inserted.")
+ return
+ inserted_core.forceMove(get_turf(user))
+ to_chat(user, "You remove [inserted_core] from [src].")
+ user.put_in_hands(inserted_core)
+ inserted_core = null
+
+/**
+ * Says (no, literally) the data of required explosive power for a certain anomaly type.
+ */
+/obj/machinery/research/explosive_compressor/proc/say_requirements(obj/item/raw_anomaly_core/C)
+ var/required = get_required_radius(C.anomaly_type)
+ if(isnull(required))
+ say("Unfortunately, due to diminishing supplies of condensed anomalous matter, [C] and any cores of its type are no longer of a sufficient quality level to be compressed into a working core.")
+ else
+ say("[C] requires a minimum of a theoretical radius of [required] to successfully implode into a charged anomaly core.")
+
+/**
+ * Determines how much explosive power (last value, so light impact theoretical radius) is required to make a certain anomaly type.
+ *
+ * Returns null if the max amount has already been reached.
+ *
+ * Arguments:
+ * * anomaly_type - anomaly type define
+ */
+/obj/machinery/research/explosive_compressor/proc/get_required_radius(anomaly_type)
+ var/already_made = SSresearch.created_anomaly_types[anomaly_type]
+ var/hard_limit = SSresearch.anomaly_hard_limit_by_type[anomaly_type]
+ if(already_made >= hard_limit)
+ return //return null
+ // my crappy autoscale formula
+ // linear scaling.
+ var/radius_span = MAX_RADIUS_REQUIRED - MIN_RADIUS_REQUIRED
+ var/radius_increase_per_core = radius_span / hard_limit
+ var/radius = clamp(round(MIN_RADIUS_REQUIRED + radius_increase_per_core * already_made, 1), MIN_RADIUS_REQUIRED, MAX_RADIUS_REQUIRED)
+ return radius
+
+/obj/machinery/research/explosive_compressor/attackby(obj/item/I, mob/living/user, params)
+ if(default_unfasten_wrench(user, I))
+ return
+ if(default_deconstruction_screwdriver(user, "explosive_compressor", "explosive_compressor", I))
+ return
+ if(default_deconstruction_crowbar(I))
+ return
+ . = ..()
+ if(istype(I, /obj/item/raw_anomaly_core))
+ if(inserted_core)
+ to_chat(user, "There is already a core in [src].")
+ return
+ if(!user.transferItemToLoc(I, src))
+ to_chat(user, "[I] is stuck to your hand.")
+ return
+ inserted_core = I
+ to_chat(user, "You insert [I] into [src].")
+ return
+ if(istype(I, /obj/item/transfer_valve))
+ // If they don't have a bomb core inserted, don't let them insert this. If they do, insert and do implosion.
+ if(!inserted_core)
+ to_chat(user, "There is no core inserted in [src]. What would be the point of detonating an implosion without a core?")
+ return
+ var/obj/item/transfer_valve/valve = I
+ if(!valve.ready())
+ to_chat(user, "[valve] is incomplete.")
+ return
+ if(!user.transferItemToLoc(I, src))
+ to_chat(user, "[I] is stuck to your hand.")
+ return
+ inserted_bomb = I
+ to_chat(user, "You insert [I] and press the start button.")
+ do_implosion()
+
+/**
+ * The ""explosion"" proc.
+ */
+/obj/machinery/research/explosive_compressor/proc/do_implosion()
+ var/required_radius = get_required_radius(inserted_core.anomaly_type)
+ // By now, we should be sure that we have a core, a TTV, and that the TTV has both tanks in place.
+ var/datum/gas_mixture/mix1 = inserted_bomb.tank_one.air_contents
+ var/datum/gas_mixture/mix2 = inserted_bomb.tank_two.air_contents
+ // Snowflaked tank explosion
+ var/datum/gas_mixture/mix = new(70) // Standard tank volume, 70L
+ mix.merge(mix1)
+ mix.merge(mix2)
+ mix.react()
+ if(mix.return_pressure() < TANK_FRAGMENT_PRESSURE)
+ // They failed so miserably we're going to give them their bomb back.
+ inserted_bomb.forceMove(drop_location())
+ inserted_bomb = null
+ inserted_core.forceMove(drop_location())
+ inserted_core = null
+ say("Transfer valve resulted in negligible explosive power. Items ejected.")
+ return
+ mix.react() // build more pressure
+ var/pressure = mix.return_pressure()
+ var/range = (pressure - TANK_FRAGMENT_PRESSURE) / TANK_FRAGMENT_SCALE
+ QDEL_NULL(inserted_bomb) // bomb goes poof
+ if(range < required_radius)
+ inserted_bomb.forceMove(src)
+ say("Resultant detonation failed to produce enough implosive power to compress [inserted_core]. Core ejected.")
+ return
+ inserted_core.create_core(drop_location(), TRUE, TRUE)
+ inserted_core = null
+ say("Success. Resultant detonation has theoretical range of [range]. Required radius was [required_radius]. Core production complete.")
+
+#undef MAX_RADIUS_REQUIRED
+#undef MIN_RADIUS_REQUIRED
diff --git a/code/modules/research/anomaly/raw_anomaly.dm b/code/modules/research/anomaly/raw_anomaly.dm
new file mode 100644
index 0000000000..2342edd28f
--- /dev/null
+++ b/code/modules/research/anomaly/raw_anomaly.dm
@@ -0,0 +1,73 @@
+/**
+ * # Raw Anomaly Cores
+ *
+ * The current precursor to anomaly cores, these are manufactured into 'finished' anomaly cores for use in research, items, and more.
+ *
+ * The current amounts created is stored in SSresearch.created_anomaly_types[ANOMALY_CORE_TYPE_DEFINE] = amount
+ * The hard limits are in code/__DEFINES/anomalies.dm
+ */
+/obj/item/raw_anomaly_core
+ name = "raw anomaly core"
+ desc = "You shouldn't be seeing this. Someone screwed up."
+ icon = 'icons/obj/assemblies/new_assemblies.dmi'
+ icon_state = "broken_state"
+
+ /// Anomaly type
+ var/anomaly_type
+
+/obj/item/raw_anomaly_core/bluespace
+ name = "raw bluespace core"
+ desc = "The raw core of a bluespace anomaly, glowing and full of potential."
+ anomaly_type = /obj/item/assembly/signaler/anomaly/bluespace
+ icon_state = "rawcore_bluespace"
+
+/obj/item/raw_anomaly_core/vortex
+ name = "raw vortex core"
+ desc = "The raw core of a vortex anomaly. Feels heavy to the touch."
+ anomaly_type = /obj/item/assembly/signaler/anomaly/vortex
+ icon_state = "rawcore_vortex"
+
+/obj/item/raw_anomaly_core/grav
+ name = "raw gravity core"
+ desc = "The raw core of a gravity anomaly. The air seems attracted to it."
+ anomaly_type = /obj/item/assembly/signaler/anomaly/grav
+ icon_state = "rawcore_grav"
+
+/obj/item/raw_anomaly_core/pyro
+ desc = "The raw core of a pyro anomaly. It is warm to the touch."
+ name = "raw pyro core"
+ anomaly_type = /obj/item/assembly/signaler/anomaly/pyro
+ icon_state = "rawcore_pyro"
+
+/obj/item/raw_anomaly_core/flux
+ name = "raw flux core"
+ desc = "The raw core of a flux anomaly, faintly crackling with energy."
+ anomaly_type = /obj/item/assembly/signaler/anomaly/flux
+ icon_state = "rawcore_flux"
+
+/obj/item/raw_anomaly_core/random
+ name = "random raw core"
+ desc = "You should not see this!"
+ icon_state = "rawcore_bluespace"
+
+/obj/item/raw_anomaly_core/random/Initialize(mapload)
+ . = ..()
+ var/path = pick(subtypesof(/obj/item/raw_anomaly_core))
+ new path(loc)
+ return INITIALIZE_HINT_QDEL
+
+/**
+ * Created the resulting core after being "made" into it.
+ *
+ * Arguments:
+ * * newloc - Where the new core will be created
+ * * del_self - should we qdel(src)
+ * * count_towards_limit - should we increment the amount of created cores on SSresearch
+ */
+/obj/item/raw_anomaly_core/proc/create_core(newloc, del_self = FALSE, count_towards_limit = FALSE)
+ . = new anomaly_type(newloc)
+ if(count_towards_limit)
+ var/existing = SSresearch.created_anomaly_types[anomaly_type] || 0
+ SSresearch.created_anomaly_types[anomaly_type] = existing + 1
+ if(del_self)
+ qdel(src)
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index c4ded65e9c..0f1004221c 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -10,6 +10,12 @@
tool_behaviour = TOOL_RETRACTOR
toolspeed = 1
+/obj/item/retractor/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
+
/obj/item/retractor/advanced
name = "mechanical pinches"
desc = "An agglomerate of rods and gears."
@@ -55,6 +61,12 @@
tool_behaviour = TOOL_HEMOSTAT
toolspeed = 1
+/obj/item/hemostat/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
+
/obj/item/hemostat/augment
name = "hemostat"
desc = "Tiny servos power a pair of pincers to stop bleeding."
@@ -79,6 +91,12 @@
tool_behaviour = TOOL_CAUTERY
toolspeed = 1
+/obj/item/cautery/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
+
/obj/item/cautery/augment
name = "cautery"
desc = "A heated element that cauterizes wounds."
@@ -107,6 +125,12 @@
tool_behaviour = TOOL_DRILL
toolspeed = 1
+/obj/item/surgicaldrill/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
+
/obj/item/surgicaldrill/advanced
name = "searing tool"
desc = "It projects a high power laser used for medical application."
@@ -172,6 +196,12 @@
. = ..()
AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0)
+/obj/item/scalpel/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
+
/obj/item/scalpel/advanced
name = "laser scalpel"
desc = "An advanced scalpel which uses laser technology to cut."
@@ -255,6 +285,11 @@
. = ..()
AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering
+/obj/item/circular_saw/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
/obj/item/circular_saw/augment
name = "circular saw"
@@ -392,3 +427,9 @@
attack_verb = list("corrected", "properly set")
tool_behaviour = TOOL_BONESET
toolspeed = 1
+
+/obj/item/bonesetter/attack(mob/living/L, mob/user)
+ if(user.a_intent == INTENT_HELP)
+ to_chat(user, "You refrain from hitting [L] with [src], as you are in help intent.")
+ return
+ return ..()
diff --git a/html/changelogs/AutoChangeLog-pr-12452.yml b/html/changelogs/AutoChangeLog-pr-12452.yml
new file mode 100644
index 0000000000..d9806ec781
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12452.yml
@@ -0,0 +1,14 @@
+author: "Putnam for debugging ammo loading! Thx!!"
+delete-after: True
+changes:
+ - rscdel: "Removed spell blade, diamond picaxe, and fire wand from lava land loot tables"
+ - tweak: "Each mini boss now has its own type of crate."
+ - tweak: "Each spike has its own type of crate that it pulls its now smaller loot table from"
+ - balance: "Moved god eye from spike loot table to hard spawn collosses fight"
+ - balance: "Moved holoparasight from spike loot table to bubble gum"
+ - balance: "Moved magic meat hook from spike loot table to drake"
+ - rscadd: "2 more crates to Arena Shuttle as well as 4-4-4 of each new type of chest"
+ - balance: "Replaced the diamond pick loot with a better one"
+ - tweak: "Replaced the cursted katana with a non cursted verson that deals half the damage and has less block!"
+ - rscadd: "Three new potions, blue heals the mind like a mama potion, Green heals the soul aka the organs! Lastly Red heals the body, by 100 damage of each main types. Best not to waste them!"
+ - rscadd: "Four more \"wands\" Spellbooks! These fun little guys shoot out its own pages to do the affect, one will set the target on fire like a bullet, one will harm them a bit, one will heal the target a small bit - How nice! Last one will give them a few statis affects like a taser bolt but without as much power or tasing affect"
diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi
index 727d69b1e3..6e14c4c6ca 100644
Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ
diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi
index e7063b71db..400c5bdfa0 100644
Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
index 4e6e0fa153..131fe7ec0f 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -253,6 +253,7 @@
holder.remove_reagent(type, cached_volume)
holder.add_reagent(/datum/reagent/fermi/PEsmaller, cached_volume)
+/*
/datum/chemical_reaction/fermi/astral
name = "Astrogen"
id = /datum/reagent/fermi/astral
@@ -274,7 +275,7 @@
FermiChem = TRUE
FermiExplode = TRUE
PurityMin = 0.25
-
+*/
/datum/chemical_reaction/fermi/enthrall //check this
name = "MKUltra"
diff --git a/tgstation.dme b/tgstation.dme
index fc348bd5fe..5b61111c4b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -142,6 +142,7 @@
#include "code\__DEFINES\mapping\maploader.dm"
#include "code\__DEFINES\material\worth.dm"
#include "code\__DEFINES\mobs\slowdowns.dm"
+#include "code\__DEFINES\research\anomalies.dm"
#include "code\__DEFINES\research\stock_parts.dm"
#include "code\__DEFINES\skills\defines.dm"
#include "code\__DEFINES\skills\helpers.dm"
@@ -3023,6 +3024,7 @@
#include "code\modules\projectiles\guns\energy\pulse.dm"
#include "code\modules\projectiles\guns\energy\special.dm"
#include "code\modules\projectiles\guns\energy\stun.dm"
+#include "code\modules\projectiles\guns\magic\spell_book.dm"
#include "code\modules\projectiles\guns\magic\staff.dm"
#include "code\modules\projectiles\guns\magic\wand.dm"
#include "code\modules\projectiles\guns\misc\beam_rifle.dm"
@@ -3141,6 +3143,8 @@
#include "code\modules\research\server.dm"
#include "code\modules\research\stock_parts.dm"
#include "code\modules\research\anomaly\anomaly_core.dm"
+#include "code\modules\research\anomaly\explosive_compressor.dm"
+#include "code\modules\research\anomaly\raw_anomaly.dm"
#include "code\modules\research\designs\AI_module_designs.dm"
#include "code\modules\research\designs\autobotter_designs.dm"
#include "code\modules\research\designs\autoylathe_designs.dm"