diff --git a/code/datums/accents.dm b/code/datums/accents.dm
index 9baba90c32..ce32aa0884 100644
--- a/code/datums/accents.dm
+++ b/code/datums/accents.dm
@@ -78,23 +78,22 @@
speech_args[SPEECH_MESSAGE] = lowertext(message)
return speech_args
-/datum/accent/bone
+/datum/accent/span
var/span_flag
-/datum/accent/bone/modify_speech(list/speech_args)
- speech_args[SPEECH_SPANS] = span_flag
+/datum/accent/span/modify_speech(list/speech_args)
+ speech_args[SPEECH_SPANS] |= span_flag
return speech_args
//bone tongues either have the sans accent or the papyrus accent
-/datum/accent/bone/sans
+/datum/accent/span/sans
span_flag = SPAN_SANS
-/datum/accent/bone/papyrus
+/datum/accent/span/papyrus
span_flag = SPAN_PAPYRUS
-/datum/accent/robot/modify_speech(list/speech_args)
- speech_args[SPEECH_SPANS] = SPAN_ROBOT
- return speech_args
+/datum/accent/span/robot
+ span_flag = SPAN_ROBOT
/datum/accent/dullahan/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner)
if(owner)
diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm
index 717e99e8b2..df0a2a091a 100644
--- a/code/datums/components/crafting/recipes/recipes_clothing.dm
+++ b/code/datums/components/crafting/recipes/recipes_clothing.dm
@@ -273,6 +273,16 @@
time = 30
category = CAT_CLOTHING
+/datum/crafting_recipe/twinsheath
+ name = "Twin Sword Sheath"
+ result = /obj/item/storage/belt/sabre/twin
+ reqs = list(/obj/item/stack/sheet/mineral/wood = 3,
+ /obj/item/stack/sheet/leather = 8)
+ tools = list(TOOL_WIRECUTTER)
+ time = 70
+ category = CAT_CLOTHING
+
+
/datum/crafting_recipe/durathread_reinforcement_kit
name = "Durathread Reinforcement Kit"
result = /obj/item/armorkit
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index f113be728d..14987bac44 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -120,6 +120,53 @@
category = CAT_MISC
always_availible = FALSE // Disabled til learned
+/datum/crafting_recipe/furnace
+ name = "Sandstone Furnace"
+ result = /obj/structure/furnace
+ time = 300
+ reqs = list(/obj/item/stack/sheet/mineral/sandstone = 15,
+ /obj/item/stack/sheet/metal = 4,
+ /obj/item/stack/rods = 2)
+ tools = list(TOOL_CROWBAR)
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
+/datum/crafting_recipe/tableanvil
+ name = "Table Anvil"
+ result = /obj/structure/anvil/obtainable/table
+ time = 300
+ reqs = list(/obj/item/stack/sheet/metal = 4,
+ /obj/item/stack/rods = 2)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
+/datum/crafting_recipe/sandvil
+ name = "Sandstone Anvil"
+ result = /obj/structure/anvil/obtainable/sandstone
+ time = 300
+ reqs = list(/obj/item/stack/sheet/mineral/sandstone = 24)
+ tools = list(TOOL_CROWBAR)
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
+/datum/crafting_recipe/basaltblock
+ name = "Sintered Basalt Block"
+ result = /obj/item/basaltblock
+ time = 200
+ reqs = list(/obj/item/stack/ore/glass/basalt = 50)
+ tools = list(TOOL_WELDER)
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
+/datum/crafting_recipe/basaltanvil
+ name = "Basalt Anvil"
+ result = /obj/structure/anvil/obtainable/basalt
+ time = 200
+ reqs = list(/obj/item/basaltblock = 5)
+ tools = list(TOOL_CROWBAR)
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
///////////////////
//Tools & Storage//
///////////////////
@@ -175,6 +222,17 @@
subcategory = CAT_TOOL
category = CAT_MISC
+/datum/crafting_recipe/toolboxhammer
+ name = "Toolbox Hammer"
+ result = /obj/item/melee/smith/hammer/toolbox
+ tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
+ reqs = list(/obj/item/storage/toolbox = 1,
+ /obj/item/stack/sheet/metal = 4,
+ /obj/item/stack/rods = 2)
+ time = 40
+ subcategory = CAT_TOOL
+ category = CAT_MISC
+
/datum/crafting_recipe/papersack
name = "Paper Sack"
result = /obj/item/storage/box/papersack
@@ -358,6 +416,25 @@
//Unsorted//
////////////
+
+
+/datum/crafting_recipe/stick
+ name = "Stick"
+ time = 30
+ reqs = list(/obj/item/stack/sheet/mineral/wood = 1)
+ result = /obj/item/stick
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
+
+/datum/crafting_recipe/swordhilt
+ name = "Sword Hilt"
+ time = 30
+ reqs = list(/obj/item/stack/sheet/mineral/wood = 2)
+ result = /obj/item/swordhandle
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
/datum/crafting_recipe/blackcarpet
name = "Black Carpet"
reqs = list(/obj/item/stack/tile/carpet = 50, /obj/item/toy/crayon/black = 1)
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index 1469965b57..30a04d7382 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -35,23 +35,24 @@ Unless you know what you're doing, only use the first three numbers. They're in
value_per_unit = 0.025
beauty_modifier = 0.075
-///Slight force increase
+///Slight force decrease. It's gold, it's soft as fuck.
/datum/material/gold
name = "gold"
desc = "Gold"
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
- strength_modifier = 1.2
+ strength_modifier = 0.8
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/gold
value_per_unit = 0.0625
beauty_modifier = 0.15
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 1.15, "energy" = 1.15, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 0.7, "acid" = 1.1)
-///Has no special properties
+///Small force increase, for diamond swords
/datum/material/diamond
name = "diamond"
desc = "Highly pressurized carbon"
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
+ strength_modifier = 1.1
alpha = 132
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
@@ -106,6 +107,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "bluespace crystal"
desc = "Crystals with bluespace properties"
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
+ integrity_modifier = 0.2 //these things shatter when thrown.
alpha = 200
categories = list(MAT_CATEGORY_ORE = TRUE)
beauty_modifier = 0.5
@@ -139,7 +141,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "titanium"
desc = "Titanium"
color = "#b3c0c7"
- strength_modifier = 1.3
+ strength_modifier = 1.1
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/titanium
value_per_unit = 0.0625
@@ -203,7 +205,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "adamantine"
desc = "A powerful material made out of magic, I mean science!"
color = "#6d7e8e"
- strength_modifier = 1.5
+ strength_modifier = 1.3
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/adamantine
value_per_unit = 0.25
@@ -276,6 +278,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
desc = "Mir'ntrath barhah Nar'sie."
color = "#3C3434"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
+ strength_modifier = 1.2
sheet_type = /obj/item/stack/sheet/runed_metal
value_per_unit = 0.75
armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
@@ -286,6 +289,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "bronze"
desc = "Clock Cult? Never heard of it."
color = "#92661A"
+ strength_modifier = 1.1
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/bronze
value_per_unit = 0.025
diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm
index 73748417c3..83c95c6439 100644
--- a/code/datums/skills/_skill_holder.dm
+++ b/code/datums/skills/_skill_holder.dm
@@ -110,7 +110,7 @@
/**
* Automatic skill increase, multiplied by skill affinity if existing.
- * Only works if skill is numerical.
+ * Only works if skill is numerical or levelled..
*/
/datum/mind/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
if(!ispath(skill, /datum/skill))
diff --git a/code/datums/skills/blacksmithing.dm b/code/datums/skills/blacksmithing.dm
new file mode 100644
index 0000000000..0bddae5562
--- /dev/null
+++ b/code/datums/skills/blacksmithing.dm
@@ -0,0 +1,6 @@
+/datum/skill/level/dorfy/blacksmithing
+ name = "Blacksmithing"
+ desc = "Making metal into fancy shapes using heat and force. Higher levels increase both your working speed at an anvil as well as the quality of your works."
+ name_color = COLOR_FLOORTILE_GRAY
+ skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
+ ui_category = SKILL_UI_CAT_MISC
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 7dd17ef93f..961f066675 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -533,6 +533,38 @@
if(100)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN,20)
+/datum/status_effect/corrosion_curse/lesser
+ id = "corrosion_curse_lesser"
+ duration = 20 SECONDS
+
+/datum/status_effect/corrosion_curse/lesser/tick()
+ . = ..()
+ if(!ishuman(owner))
+ return
+ var/mob/living/carbon/human/H = owner
+ var/chance = rand(0,100)
+ switch(chance)
+ if(0 to 19)
+ H.adjustBruteLoss(6)
+ if(20 to 29)
+ H.Dizzy(10)
+ if(30 to 39)
+ H.adjustOrganLoss(ORGAN_SLOT_LIVER,2)
+ if(40 to 49)
+ H.adjustOrganLoss(ORGAN_SLOT_HEART,2)
+ if(50 to 59)
+ H.adjustOrganLoss(ORGAN_SLOT_STOMACH,2)
+ if(60 to 69)
+ H.adjustOrganLoss(ORGAN_SLOT_EYES,5)
+ if(70 to 79)
+ H.adjustOrganLoss(ORGAN_SLOT_EARS,5)
+ if(80 to 89)
+ H.adjustOrganLoss(ORGAN_SLOT_LUNGS,5)
+ if(90 to 99)
+ H.adjustOrganLoss(ORGAN_SLOT_TONGUE,5)
+ if(100)
+ H.adjustOrganLoss(ORGAN_SLOT_BRAIN,10)
+
/datum/status_effect/amok
id = "amok"
status_type = STATUS_EFFECT_REPLACE
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 2e6353b8a8..eac7347479 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -6,10 +6,6 @@ GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (30 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (10 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (30 MINUTES))
-GLOBAL_VAR_INIT(dynamic_event_delay_min, (10 MINUTES))
-GLOBAL_VAR_INIT(dynamic_event_delay_max, (30 MINUTES)) // this is on top of regular events, so can't be quite as often
-
-
// -- Roundstart injection delays
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_min, (2 MINUTES))
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_max, (30 MINUTES))
@@ -58,7 +54,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
// Threat logging vars
/// Starting threat level, for things that increase it but can bring it back down.
var/initial_threat_level = 0
- /// Target threat level right now. Events and antags will try to keep the round at this level.
+ /// Target threat level right now. Antags will try to keep the round at this level.
var/threat_level = 0
/// The current antag threat. Recalculated every time a ruletype starts or ends.
var/threat = 0
@@ -80,8 +76,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
var/list/latejoin_rules = list()
/// List of midround rules used for selecting the rules.
var/list/midround_rules = list()
- /// List of events used for reducing threat without causing antag injection (necessarily).
- var/list/events = list()
/** # Pop range per requirement.
* If the value is five the range is:
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
@@ -119,8 +113,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
var/latejoin_injection_cooldown = 0
/// When world.time is over this number the mode tries to inject a midround ruleset.
var/midround_injection_cooldown = 0
- /// When wor.dtime is over this number the mode tries to do an event.
- var/event_injection_cooldown = 0
/// When TRUE GetInjectionChance returns 100.
var/forced_injection = FALSE
/// Forced ruleset to be executed for the next latejoin.
@@ -184,7 +176,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
dat += "
Injection Timers: ([storyteller.get_injection_chance(TRUE)]% chance)
"
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)/10] seconds"] \[Now!\]
"
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)/10] seconds"] \[Now!\]
"
- dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)/10] seconds"] \[Now!\]
"
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
/datum/game_mode/dynamic/Topic(href, href_list)
@@ -213,10 +204,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
midround_injection_cooldown = 0
forced_injection = TRUE
message_admins("[key_name(usr)] forced a midround injection.", 1)
- else if (href_list["forceevent"])
- event_injection_cooldown = 0
- // events always happen anyway
- message_admins("[key_name(usr)] forced an event.", 1)
else if (href_list["threatlog"])
show_threatlog(usr)
else if (href_list["stacking_limit"])
@@ -374,8 +361,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
generate_threat()
storyteller.start_injection_cooldowns()
- SSevents.frequency_lower = storyteller.event_frequency_lower // 6 minutes by default
- SSevents.frequency_upper = storyteller.event_frequency_upper // 20 minutes by default
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
initial_threat_level = threat_level
return TRUE
@@ -394,9 +379,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
if ("Midround")
if (ruleset.weight)
midround_rules += ruleset
- if("Event")
- if(ruleset.weight)
- events += ruleset
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
@@ -593,8 +575,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
else if(rule.ruletype == "Midround")
midround_rules = remove_from_list(midround_rules, rule.type)
- else if(rule.ruletype == "Event")
- events = remove_from_list(events,rule.type)
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_midround_latejoin_rule, rule), rule.delay)
return TRUE
@@ -703,17 +683,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
picking_midround_latejoin_rule(drafted_rules)
// get_injection_chance can do things on fail
- if(event_injection_cooldown < world.time)
- SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
- event_injection_cooldown = storyteller.get_event_cooldown() + world.time
- message_admins("DYNAMIC: Doing event injection.")
- log_game("DYNAMIC: Doing event injection.")
- update_playercounts()
- var/list/drafted_rules = storyteller.event_draft()
- if(drafted_rules.len > 0)
- SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
- picking_midround_latejoin_rule(drafted_rules)
-
/// Updates current_players.
/datum/game_mode/dynamic/proc/update_playercounts()
current_players[CURRENT_LIVING_PLAYERS] = list()
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm
deleted file mode 100644
index 1ee226875b..0000000000
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm
+++ /dev/null
@@ -1,454 +0,0 @@
-/datum/dynamic_ruleset/event
- ruletype = "Event"
- var/typepath // typepath of the event
- var/triggering
- var/earliest_start = 20 MINUTES
-
-/datum/dynamic_ruleset/event/get_blackbox_info()
- var/list/ruleset_data = list()
- ruleset_data["name"] = name
- ruleset_data["rule_type"] = ruletype
- ruleset_data["cost"] = total_cost
- ruleset_data["weight"] = weight
- ruleset_data["scaled_times"] = scaled_times
- ruleset_data["event_type"] = typepath
- ruleset_data["population_tier"] = indice_pop
- return ruleset_data
-
-/datum/dynamic_ruleset/event/execute()
- var/datum/round_event/E = new typepath()
- E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
- // E.control = src // can't be done! we just don't use events that require these, those can be from_ghost almost always
-
- testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
- deadchat_broadcast("[name] has just been triggered by dynamic!")
- log_game("Random Event triggering: [name] ([typepath])")
-
- return E
-
-/datum/dynamic_ruleset/event/ready(forced = FALSE)
- if (!forced)
- if(earliest_start >= world.time-SSticker.round_start_time)
- return FALSE
- var/job_check = 0
- if (enemy_roles.len > 0)
- for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
- if (M.stat == DEAD)
- continue // Dead players cannot count as opponents
- if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles))
- job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
-
- var/threat = round(mode.threat_level/10)
- if (job_check < required_enemies[threat])
- SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
- return FALSE
- return TRUE
-
-//////////////////////////////////////////////
-// //
-// PIRATES //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/pirates
- name = "Space Pirates"
- config_tag = "pirates"
- typepath = /datum/round_event/pirates
- antag_flag = ROLE_TRAITOR
- enemy_roles = list("AI","Security Officer","Head of Security","Captain")
- required_enemies = list(2,2,1,1,0,0,0,0,0,0)
- weight = 5
- cost = 10
- earliest_start = 30 MINUTES
- blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
- requirements = list(70,60,50,50,40,40,40,30,20,15)
- property_weights = list("story_potential" = 1, "trust" = 1, "chaos" = 1)
- high_population_requirement = 15
-
-/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
- if (!SSmapping.empty_space)
- return FALSE
- return ..()
-
-//////////////////////////////////////////////
-// //
-// SPIDERS //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/spiders
- name = "Spider Infestation"
- config_tag = "spiders"
- typepath = /datum/round_event/spider_infestation
- enemy_roles = list("AI","Security Officer","Head of Security","Captain")
- required_enemies = list(2,2,1,1,0,0,0,0,0,0)
- weight = 5
- cost = 10
- requirements = list(70,60,50,50,40,40,40,30,20,15)
- high_population_requirement = 15
- property_weights = list("chaos" = 1, "valid" = 1)
-
-//////////////////////////////////////////////
-// //
-// CLOGGED VENTS //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/ventclog
- name = "Clogged Vents"
- config_tag = "ventclog"
- typepath = /datum/round_event/vent_clog
- enemy_roles = list("Chemist","Medical Doctor","Chief Medical Officer")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- cost = 2
- weight = 4
- repeatable_weight_decrease = 3
- requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("chaos" = 1, "extended" = 2)
-
-/datum/dynamic_ruleset/event/ventclog/ready()
- if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
- name = "Clogged Vents: Threatening"
- cost = 5
- required_enemies = list(3,3,3,2,2,2,1,1,1,1)
- typepath = /datum/round_event/vent_clog/threatening
- else if(mode.threat_level > 15 && mode.threat > 15 && prob(30))
- name = "Clogged Vents: Catastrophic"
- cost = 15
- required_enemies = list(2,2,1,1,1,1,0,0,0,0)
- typepath = /datum/round_event/vent_clog/catastrophic
- else
- cost = 2
- name = "Clogged Vents: Normal"
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- typepath = /datum/round_event/vent_clog
- return ..()
-
-//////////////////////////////////////////////
-// //
-// ION STORM //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/ion_storm
- name = "Ion Storm"
- config_tag = "ion_storm"
- typepath = /datum/round_event/ion_storm
- enemy_roles = list("Research Director","Captain","Chief Engineer")
- required_enemies = list(1,1,0,0,0,0,0,0,0,0)
- weight = 4
- // no repeatable weight decrease. too variable to be unfun multiple times in one round
- cost = 1
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("story_potential" = 1, "extended" = 1)
- always_max_weight = TRUE
-
-//////////////////////////////////////////////
-// //
-// METEORS //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/meteor_wave
- name = "Meteor Wave"
- config_tag = "meteor_wave"
- typepath = /datum/round_event/meteor_wave
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Captain","Cyborg")
- required_enemies = list(3,3,3,3,3,3,3,3,3,3)
- cost = 15
- weight = 3
- earliest_start = 25 MINUTES
- repeatable_weight_decrease = 2
- requirements = list(60,50,40,30,30,30,30,30,30,30)
- high_population_requirement = 30
- property_weights = list("extended" = -2)
-
-/datum/dynamic_ruleset/event/meteor_wave/ready()
- if(world.time-SSticker.round_start_time > 35 MINUTES && mode.threat_level > 40 && mode.threat >= 25 && prob(30))
- name = "Meteor Wave: Threatening"
- cost = 25
- typepath = /datum/round_event/meteor_wave/threatening
- else if(world.time-SSticker.round_start_time > 45 MINUTES && mode.threat_level > 50 && mode.threat >= 40 && prob(30))
- name = "Meteor Wave: Catastrophic"
- cost = 40
- typepath = /datum/round_event/meteor_wave/catastrophic
- else
- name = "Meteor Wave: Normal"
- cost = 15
- typepath = /datum/round_event/meteor_wave
- return ..()
-
-//////////////////////////////////////////////
-// //
-// ANOMALIES //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/anomaly_bluespace
- name = "Anomaly: Bluespace"
- config_tag = "anomaly_bluespace"
- typepath = /datum/round_event/anomaly/anomaly_bluespace
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- weight = 2
- repeatable_weight_decrease = 1
- cost = 3
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/anomaly_flux
- name = "Anomaly: Hyper-Energetic Flux"
- config_tag = "anomaly_flux"
- typepath = /datum/round_event/anomaly/anomaly_flux
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- weight = 2
- repeatable_weight_decrease = 1
- cost = 5
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 10
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/anomaly_gravitational
- name = "Anomaly: Gravitational"
- config_tag = "anomaly_gravitational"
- typepath = /datum/round_event/anomaly/anomaly_grav
- weight = 2
- repeatable_weight_decrease = 1
- cost = 3
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/anomaly_pyroclastic
- name = "Anomaly: Pyroclastic"
- config_tag = "anomaly_pyroclastic"
- typepath = /datum/round_event/anomaly/anomaly_pyro
- weight = 2
- repeatable_weight_decrease = 1
- cost = 5
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
- required_enemies = list(1,1,1,1,1,1,1,1,1,1)
- requirements = list(10,10,10,10,10,10,10,10,10,10)
- high_population_requirement = 10
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/anomaly_vortex
- name = "Anomaly: Vortex"
- config_tag = "anomaly_vortex"
- typepath = /datum/round_event/anomaly/anomaly_vortex
- weight = 2
- repeatable_weight_decrease = 1
- cost = 5
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
- required_enemies = list(1,1,1,1,1,1,1,1,1,1)
- requirements = list(10,10,10,10,10,10,10,10,10,10)
- high_population_requirement = 10
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-//////////////////////////////////////////////
-// //
-// WOW THAT'S A LOT OF EVENTS //
-// //
-//////////////////////////////////////////////
-
-/datum/dynamic_ruleset/event/brand_intelligence
- name = "Brand Intelligence"
- config_tag = "brand_intelligence"
- typepath = /datum/round_event/brand_intelligence
- weight = 1
- repeatable_weight_decrease = 1
- cost = 2
- enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
- required_enemies = list(1,1,1,1,0,0,0,0,0,0)
- requirements = list(10,10,10,10,10,10,10,10,10,10)
- high_population_requirement = 10
- repeatable = TRUE
- property_weights = list("extended" = -1, "chaos" = 1)
-
-/datum/dynamic_ruleset/event/carp_migration
- name = "Carp Migration"
- config_tag = "carp_migration"
- typepath = /datum/round_event/carp_migration
- weight = 7
- repeatable_weight_decrease = 3
- cost = 4
- requirements = list(10,10,10,10,10,10,10,10,10,10)
- high_population_requirement = 10
- earliest_start = 10 MINUTES
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/communications_blackout
- name = "Communications Blackout"
- config_tag = "communications_blackout"
- typepath = /datum/round_event/communications_blackout
- cost = 4
- weight = 2
- repeatable_weight_decrease = 3
- enemy_roles = list("Chief Engineer","Station Engineer")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1, "chaos" = 1)
-
-/datum/dynamic_ruleset/event/processor_overload
- name = "Processor Overload"
- config_tag = "processor_overload"
- typepath = /datum/round_event/processor_overload
- cost = 4
- weight = 2
- repeatable_weight_decrease = 3
- enemy_roles = list("Chief Engineer","Station Engineer")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1, "chaos" = 1)
- always_max_weight = TRUE
-
-/datum/dynamic_ruleset/event/space_dust
- name = "Minor Space Dust"
- config_tag = "space_dust"
- typepath = /datum/round_event/space_dust
- cost = 2
- weight = 2
- repeatable_weight_decrease = 1
- enemy_roles = list("Chief Engineer","Station Engineer")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- earliest_start = 0 MINUTES
- property_weights = list("extended" = 1)
- always_max_weight = TRUE
-
-/datum/dynamic_ruleset/event/major_dust
- name = "Major Space Dust"
- config_tag = "major_dust"
- typepath = /datum/round_event/meteor_wave/major_dust
- cost = 4
- weight = 2
- repeatable_weight_decrease = 1
- enemy_roles = list("Chief Engineer","Station Engineer")
- required_enemies = list(2,2,2,2,2,2,2,2,2,2)
- requirements = list(10,10,10,10,10,10,10,10,10,10)
- high_population_requirement = 10
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/electrical_storm
- name = "Electrical Storm"
- config_tag = "electrical_storm"
- typepath = /datum/round_event/electrical_storm
- cost = 1
- weight = 2
- repeatable_weight_decrease = 1
- enemy_roles = list("Chief Engineer","Station Engineer")
- required_enemies = list(1,1,1,0,0,0,0,0,0,0)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/heart_attack
- name = "Random Heart Attack"
- config_tag = "heart_attack"
- typepath = /datum/round_event/heart_attack
- cost = 3
- weight = 2
- repeatable_weight_decrease = 1
- enemy_roles = list("Medical Doctor","Chief Medical Officer")
- required_enemies = list(2,2,2,2,2,2,2,2,2,2)
- requirements = list(101,101,101,5,5,5,5,5,5,5)
- high_population_requirement = 5
- repeatable = TRUE
- property_weights = list("extended" = 1)
- always_max_weight = TRUE
-
-/datum/dynamic_ruleset/event/radiation_storm
- name = "Radiation Storm"
- config_tag = "radiation_storm"
- typepath = /datum/round_event/radiation_storm
- cost = 3
- weight = 1
- enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
- required_enemies = list(1,1,1,1,1,1,1,1,1,1)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- property_weights = list("extended" = 1,"chaos" = 1)
-
-/datum/dynamic_ruleset/event/portal_storm_syndicate
- name = "Portal Storm"
- config_tag = "portal_storm"
- typepath = /datum/round_event/portal_storm/syndicate_shocktroop
- cost = 10
- weight = 1
- enemy_roles = list("Head of Security","Security Officer","AI","Captain","Shaft Miner")
- required_enemies = list(2,2,2,2,2,2,2,2,2,2)
- requirements = list(101,101,101,30,30,30,30,30,30,30)
- high_population_requirement = 30
- earliest_start = 30 MINUTES
- property_weights = list("teamwork" = 1,"chaos" = 1, "extended" = -1)
-
-/datum/dynamic_ruleset/event/wormholes
- name = "Wormholes"
- config_tag = "wormhole"
- typepath = /datum/round_event/wormholes
- cost = 3
- weight = 4
- enemy_roles = list("AI","Medical Doctor","Station Engineer","Head of Personnel","Captain")
- required_enemies = list(2,2,2,2,2,2,2,2,2,2)
- requirements = list(5,5,5,5,5,5,5,5,5,5)
- high_population_requirement = 5
- property_weights = list("extended" = 1)
-
-/datum/dynamic_ruleset/event/swarmers
- name = "Swarmers"
- config_tag = "swarmer"
- typepath = /datum/round_event/spawn_swarmer
- cost = 10
- weight = 1
- earliest_start = 30 MINUTES
- enemy_roles = list("AI","Security Officer","Head of Security","Captain","Station Engineer","Atmos Technician","Chief Engineer")
- required_enemies = list(4,4,4,4,3,3,2,2,1,1)
- requirements = list(101,101,101,101,101,101,101,101,101,101)
- high_population_requirement = 5
- property_weights = list("extended" = -2)
-
-/datum/dynamic_ruleset/event/sentient_disease
- name = "Sentient Disease"
- config_tag = "sentient_disease"
- typepath = /datum/round_event/ghost_role/sentient_disease
- enemy_roles = list("Virologist","Chief Medical Officer","Captain","Chemist")
- required_enemies = list(2,1,1,1,0,0,0,0,0,0)
- required_candidates = 1
- weight = 4
- cost = 5
- requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
- property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2)
- high_population_requirement = 5
-
-/datum/dynamic_ruleset/event/revenant
- name = "Revenant"
- config_tag = "revenant"
- typepath = /datum/round_event/ghost_role/revenant
- enemy_roles = list("Chief Engineer","Station Engineer","Captain","Chaplain","AI")
- required_enemies = list(2,1,1,1,0,0,0,0,0,0)
- required_candidates = 1
- weight = 4
- cost = 5
- requirements = list(30,30,30,30,20,15,15,15,15,15)
- high_population_requirement = 15
- property_weights = list("story_potential" = -2, "extended" = -1)
diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
index dd281c456f..ed6cb0ba88 100644
--- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm
+++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
@@ -39,9 +39,6 @@ Property weights are added to the config weight of the ruleset. They are:
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
mode.midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
- var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
- mode.event_injection_cooldown = (round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
-
/datum/dynamic_storyteller/proc/calculate_threat()
var/threat = 0
for(var/datum/antagonist/A in GLOB.antagonists)
@@ -99,10 +96,6 @@ Property weights are added to the config weight of the ruleset. They are:
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
return round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max))
-/datum/dynamic_storyteller/proc/get_event_cooldown()
- var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
- return round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max))
-
/datum/dynamic_storyteller/proc/get_latejoin_cooldown()
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
return round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max))
@@ -195,20 +188,6 @@ Property weights are added to the config weight of the ruleset. They are:
drafted_rules[rule] = calced_weight
return drafted_rules
-/datum/dynamic_storyteller/proc/event_draft()
- var/list/drafted_rules = list()
- for(var/datum/dynamic_ruleset/event/rule in mode.events)
- if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level + 20 - mode.threat) >= rule.cost && rule.ready())
- var/property_weight = 0
- for(var/property in property_weights)
- if(property in rule.property_weights)
- property_weight += rule.property_weights[property] * property_weights[property]
- var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
- if(calced_weight > 0)
- drafted_rules[rule] = calced_weight
- return drafted_rules
-
-
/datum/dynamic_storyteller/chaotic
name = "Chaotic"
config_tag = "chaotic"
@@ -271,9 +250,6 @@ Property weights are added to the config weight of the ruleset. They are:
/datum/dynamic_storyteller/random/get_midround_cooldown()
return rand(GLOB.dynamic_midround_delay_min/2, GLOB.dynamic_midround_delay_max*2)
-/datum/dynamic_storyteller/random/get_event_cooldown()
- return rand(GLOB.dynamic_event_delay_min/2, GLOB.dynamic_event_delay_max*2)
-
/datum/dynamic_storyteller/random/get_latejoin_cooldown()
return rand(GLOB.dynamic_latejoin_delay_min/2, GLOB.dynamic_latejoin_delay_max*2)
@@ -319,13 +295,6 @@ Property weights are added to the config weight of the ruleset. They are:
drafted_rules[rule] = 1
return drafted_rules
-/datum/dynamic_storyteller/random/event_draft()
- var/list/drafted_rules = list()
- for(var/datum/dynamic_ruleset/event/rule in mode.events)
- if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && rule.ready())
- drafted_rules[rule] = 1
- return drafted_rules
-
/datum/dynamic_storyteller/story
name = "Story"
config_tag = "story"
@@ -365,7 +334,7 @@ Property weights are added to the config weight of the ruleset. They are:
/datum/dynamic_storyteller/no_antag
name = "Extended"
config_tag = "semiextended"
- desc = "No standard antags. Threatening events may still spawn."
+ desc = "No standard antags."
curve_centre = -5
curve_width = 0.5
flags = NO_ASSASSIN | FORCE_IF_WON
@@ -377,15 +346,3 @@ Property weights are added to the config weight of the ruleset. They are:
/datum/dynamic_storyteller/no_antag/get_injection_chance(dry_run)
return 0
-
-/datum/dynamic_storyteller/extended
- name = "Super Extended"
- config_tag = "extended"
- desc = "No antags. No dangerous events."
- curve_centre = -20
- weight = 0
- curve_width = 0.5
-
-/datum/dynamic_storyteller/extended/on_start()
- ..()
- GLOB.dynamic_forced_extended = TRUE
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 37d19783b5..806aed92ed 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -390,7 +390,7 @@
/obj/item/circuitboard/machine/thermomachine/examine()
. = ..()
- . += "It is set to layer [pipe_layer]."
+ . += "It is set to layer [pipe_layer]. Use a Multitool on the circuit to change this."
/obj/item/circuitboard/machine/thermomachine/heater
name = "Heater (Machine Board)"
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 7692278ba3..426958b99a 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -117,6 +117,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
new/datum/stack_recipe("Captain Statue", /obj/structure/statue/diamond/captain, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("AI Hologram Statue", /obj/structure/statue/diamond/ai1, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("AI Core Statue", /obj/structure/statue/diamond/ai2, 5, one_per_turf = 1, on_floor = 1), \
+// new/datum/stack_recipe("diamond brick", /obj/item/ingot/diamond, 6, time = 100), \ not yet
))
/obj/item/stack/sheet/mineral/diamond/get_main_recipes()
@@ -145,6 +146,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20), \
new/datum/stack_recipe("Nuke Statue", /obj/structure/statue/uranium/nuke, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("Engineer Statue", /obj/structure/statue/uranium/eng, 5, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("uranium ingot", /obj/item/ingot/uranium, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/uranium/get_main_recipes()
@@ -177,6 +179,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20), \
new/datum/stack_recipe("Scientist Statue", /obj/structure/statue/plasma/scientist, 5, one_per_turf = 1, on_floor = 1), \
+// new/datum/stack_recipe("plasma ingot", /obj/item/ingot/plasma, 6, time = 100), \ no
))
/obj/item/stack/sheet/mineral/plasma/get_main_recipes()
@@ -221,6 +224,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
new/datum/stack_recipe("RD Statue", /obj/structure/statue/gold/rd, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/crown, 5), \
new/datum/stack_recipe("CMO Statue", /obj/structure/statue/gold/cmo, 5, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("gold ingot", /obj/item/ingot/gold, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/gold/get_main_recipes()
@@ -252,6 +256,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("Sec Officer Statue", /obj/structure/statue/silver/sec, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("Sec Borg Statue", /obj/structure/statue/silver/secborg, 5, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("Med Borg Statue", /obj/structure/statue/silver/medborg, 5, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("silver ingot", /obj/item/ingot/silver, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/silver/get_main_recipes()
@@ -278,6 +283,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
GLOBAL_LIST_INIT(bananium_recipes, list ( \
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
new/datum/stack_recipe("Clown Statue", /obj/structure/statue/bananium/clown, 5, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("hilarious ingot", /obj/item/ingot/bananium, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/bananium/get_main_recipes()
@@ -306,6 +312,7 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
GLOBAL_LIST_INIT(titanium_recipes, list ( \
new/datum/stack_recipe("titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20), \
+ new/datum/stack_recipe("titanic ingot", /obj/item/ingot/titanium, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/titanium/get_main_recipes()
@@ -353,6 +360,7 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
*/
GLOBAL_LIST_INIT(adamantine_recipes, list(
new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=1, res_amount=1),
+ new/datum/stack_recipe("adamant ingot", /obj/item/ingot/adamantine, 6, time = 100), \
))
/obj/item/stack/sheet/mineral/adamantine
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 6d726f221e..d55873d9a2 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -121,6 +121,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 50), \
new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("iron ingot", /obj/item/ingot/iron, 6, time = 100), \
null, \
new/datum/stack_recipe("tiny fan", /obj/structure/fans/tiny, 2, time = 4, one_per_turf = TRUE, on_floor = TRUE), \
))
@@ -559,6 +560,9 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
new/datum/stack_recipe("forge", /obj/structure/destructible/cult/forge, 3, time = 40, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("archives", /obj/structure/destructible/cult/tome, 3, time = 40, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("altar", /obj/structure/destructible/cult/talisman, 3, time = 40, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("anvil", /obj/structure/anvil/obtainable/narsie, 4, time = 40, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("runic ingot", /obj/item/ingot/cult, 2, time = 100), \
+ new/datum/stack_recipe("rune smith's hammer", /obj/item/melee/smith/hammer/narsie, 6), \
))
/obj/item/stack/sheet/runed_metal
@@ -621,6 +625,8 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
new/datum/stack_recipe("brass bar stool", /obj/structure/chair/stool/bar/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("brass stool", /obj/structure/chair/stool/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("brass table frame", /obj/structure/table_frame/brass, 1, time = 5, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("brass anvil", /obj/structure/anvil/obtainable/ratvar, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("brass furnace", /obj/structure/furnace/infinite/ratvar, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
null, \
new/datum/stack_recipe("sender - pressure sensor", /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("sender - mech sensor", /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/mech, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE), \
@@ -632,6 +638,8 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
new/datum/stack_recipe("receiver - power nullifier", /obj/structure/destructible/clockwork/trap/power_nullifier, 5, time = 20, one_per_turf = TRUE, on_floor = TRUE, placement_checks = STACK_CHECK_CARDINALS), \
null, \
new/datum/stack_recipe("brass flask", /obj/item/reagent_containers/food/drinks/bottle/holyoil/empty), \
+ new/datum/stack_recipe("brass smith's hammer", /obj/item/melee/smith/hammer/ratvar, 6), \
+ new/datum/stack_recipe("brass ingot", /obj/item/ingot/bronze/ratvar, 6, time = 100), \
))
/obj/item/stack/tile/brass
@@ -687,7 +695,10 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("bronze bar stool", /obj/structure/chair/stool/bar/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("bronze stool", /obj/structure/chair/stool/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
- new /datum/stack_recipe("bronze floor tiles", /obj/item/stack/tile/bronze, 1, 4, 20), \
+ new/datum/stack_recipe("bronze anvil",/obj/structure/anvil/obtainable/bronze, 20, time = 110, one_per_turf = TRUE, on_floor = TRUE), \
+ null,
+ new/datum/stack_recipe("bronze ingot", /obj/item/ingot/bronze, 6, time = 100), \
+ new/datum/stack_recipe("bronze floor tiles", /obj/item/stack/tile/bronze, 1, 4, 20), \
))
/obj/item/stack/sheet/bronze
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 0001494fdd..590df34cde 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -815,3 +815,18 @@
attack_verb = list("bashed", "slashes", "prods", "pokes")
fitting_swords = list(/obj/item/melee/rapier)
starting_sword = /obj/item/melee/rapier
+
+/obj/item/storage/belt/sabre/twin
+ name = "twin sheath"
+ desc = "Two sheaths. One is capable of holding a katana (or bokken) and the other a wakizashi. You could put two wakizashis in if you really wanted to. Now you can really roleplay as a samurai."
+ icon_state = "twinsheath"
+ item_state = "quiver" //this'll do.
+ w_class = WEIGHT_CLASS_BULKY
+ fitting_swords = list(/obj/item/melee/smith/wakizashi, /obj/item/melee/smith/twohand/katana, /obj/item/melee/bokken)
+ starting_sword = null
+
+/obj/item/storage/belt/sabre/twin/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_items = 2
+ STR.max_w_class = WEIGHT_CLASS_BULKY + WEIGHT_CLASS_NORMAL //katana and waki.
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 5803941f36..a388621c92 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -174,7 +174,14 @@
new reward(get_turf(src))
to_chat(user, "You work the forge as dark knowledge guides your hands, creating the [choice]!")
-
+/obj/structure/destructible/cult/forge/attackby(obj/item/I, mob/user)
+ if(!iscultist(user))
+ to_chat(user, "The heat radiating from [src] pushes you back.")
+ return
+ if(istype(I, /obj/item/ingot))
+ var/obj/item/ingot/notsword = I
+ to_chat(user, "You heat the [notsword] in the [src].")
+ notsword.workability = "shapeable"
/obj/structure/destructible/cult/pylon
name = "pylon"
diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/antagonists/disease/disease_event.dm
index 4365fd7538..385cee998b 100644
--- a/code/modules/antagonists/disease/disease_event.dm
+++ b/code/modules/antagonists/disease/disease_event.dm
@@ -3,7 +3,6 @@
name = "Spawn Sentient Disease"
typepath = /datum/round_event/ghost_role/sentient_disease
weight = 7
- gamemode_blacklist = list("dynamic")
max_occurrences = 1
min_players = 5
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
index 79dfbdd7c3..81bc090460 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
@@ -30,6 +30,7 @@
/datum/antagonist/heretic/on_gain()
var/mob/living/current = owner.current
+ owner.teach_crafting_recipe(/datum/crafting_recipe/heretic/codex)
if(ishuman(current))
forge_primary_objectives()
gain_knowledge(/datum/eldritch_knowledge/spell/basic)
@@ -41,7 +42,6 @@
START_PROCESSING(SSprocessing,src)
if(give_equipment)
equip_cultist()
- owner.teach_crafting_recipe(/datum/crafting_recipe/heretic/codex)
return ..()
/datum/antagonist/heretic/on_removal()
@@ -111,17 +111,12 @@
P.find_target(owners,assasination)
protection += P.target
objectives += P
-
var/datum/objective/sacrifice_ecult/SE = new
SE.owner = owner
SE.update_explanation_text()
objectives += SE
- var/datum/objective/escape/escape_objective = new
- escape_objective.owner = owner
- objectives += escape_objective
-
/datum/antagonist/heretic/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
index 899e588bda..99794024f1 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
@@ -20,9 +20,11 @@
if(!is_in_use)
INVOKE_ASYNC(src, .proc/activate , user)
-/obj/effect/eldritch/attacked_by(obj/item/I, mob/living/user)
+/obj/effect/eldritch/attackby(obj/item/I, mob/living/user)
. = ..()
- if(istype(I,/obj/item/nullrod))
+ if(istype(I, /obj/item/storage/book/bible) || istype(I, /obj/item/nullrod))
+ user.say("BEGONE FOUL MAGICKS!!", forced = "bible")
+ to_chat(user, "You disrupt the magic of [src] with [I].")
qdel(src)
/obj/effect/eldritch/proc/activate(mob/living/user)
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
index 4dab6d789d..2052a2fbb3 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
@@ -16,16 +16,19 @@
return
var/dist = get_dist(user.loc,target.loc)
var/dir = get_dir(user.loc,target.loc)
-
- switch(dist)
- if(0 to 15)
- to_chat(user,"[target.real_name] is near you. They are to the [dir2text(dir)] of you!")
- if(16 to 31)
- to_chat(user,"[target.real_name] is somewhere in your vicinty. They are to the [dir2text(dir)] of you!")
- if(32 to 127)
- to_chat(user,"[target.real_name] is far away from you. They are to the [dir2text(dir)] of you!")
- else
- to_chat(user,"[target.real_name] is beyond our reach.")
+
+ if(user.z != target.z)
+ to_chat(user,"[target.real_name] is beyond our reach.")
+ else
+ switch(dist)
+ if(0 to 15)
+ to_chat(user,"[target.real_name] is near you. They are to the [dir2text(dir)] of you!")
+ if(16 to 31)
+ to_chat(user,"[target.real_name] is somewhere in your vicinty. They are to the [dir2text(dir)] of you!")
+ if(32 to 127)
+ to_chat(user,"[target.real_name] is far away from you. They are to the [dir2text(dir)] of you!")
+ else
+ to_chat(user,"[target.real_name] is beyond our reach.")
if(target.stat == DEAD)
to_chat(user,"[target.real_name] is dead. Bring them onto a transmutation rune!")
@@ -86,8 +89,8 @@
desc = "A crescent blade born from a fleshwarped creature. Keenly aware, it seeks to spread to others the excruciations it has endured from dead origins."
icon_state = "flesh_blade"
item_state = "flesh_blade"
- wound_bonus = 5
- bare_wound_bonus = 15
+ wound_bonus = 10
+ bare_wound_bonus = 20
/obj/item/clothing/neck/eldritch_amulet
name = "warm eldritch medallion"
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
index 065844bedf..27868a3e3e 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
@@ -224,7 +224,7 @@
name = "Break of Dawn"
desc = "Starts your journey in the mansus. Allows you to select a target using a living heart on a transmutation rune."
gain_text = "Gates of Mansus open up to your mind."
- next_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh)
+ next_knowledge = list(/datum/eldritch_knowledge/base_rust,/datum/eldritch_knowledge/base_ash,/datum/eldritch_knowledge/base_flesh,/datum/eldritch_knowledge/spell/silence)
cost = 0
spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/mansus_grasp
required_atoms = list(/obj/item/living_heart)
@@ -301,3 +301,11 @@
required_atoms = list(/obj/item/shard,/obj/item/stack/rods)
result_atoms = list(/obj/item/melee/sickly_blade)
route = "Start"
+
+/datum/eldritch_knowledge/spell/silence
+ name = "Silence"
+ desc = "Allows you to use the power of the Mansus to force an individual's tongue to be held down for up to twenty seconds. They'll notice quickly, however."
+ gain_text = "They must hold their tongues, for they do not understand."
+ cost = 1
+ spell_to_add = /obj/effect/proc_holder/spell/pointed/trigger/mute/eldritch
+ route = PATH_SIDE
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
index d84a997e28..799667999e 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
@@ -43,8 +43,9 @@
/obj/item/melee/touch_attack/mansus_fist
name = "Mansus Grasp"
desc = "A sinister looking aura that distorts the flow of reality around it. Causes knockdown, major stamina damage aswell as some Brute. It gains additional beneficial effects with certain knowledges you can research."
- icon_state = "disintegrate"
- item_state = "disintegrate"
+ icon = 'icons/obj/eldritch.dmi'
+ icon_state = "mansus_grasp"
+ item_state = "mansus"
catchphrase = "T'IESA SIE'KTI VISATA"
/obj/item/melee/touch_attack/mansus_fist/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
@@ -118,6 +119,7 @@
/obj/item/melee/touch_attack/blood_siphon
name = "Blood Siphon"
desc = "A sinister looking aura that distorts the flow of reality around it."
+ color = RUNE_COLOR_RED
icon_state = "disintegrate"
item_state = "disintegrate"
catchphrase = "SUN'AI'KINI'MAS"
@@ -260,41 +262,82 @@
/obj/effect/proc_holder/spell/pointed/cleave/long
charge_max = 650
-/obj/effect/proc_holder/spell/pointed/touch/mad_touch
+/obj/effect/proc_holder/spell/targeted/touch/mad_touch
name = "Touch of Madness"
- desc = "Touch spell that drains your enemies sanity."
- school = "transmutation"
- charge_max = 150
+ desc = "Touch spell that allows you to force the knowledge of the mansus upon your foes."
+ hand_path = /obj/item/melee/touch_attack/mad_touch
+ school = "evocation"
+ charge_max = 1800
clothes_req = FALSE
- invocation_type = "none"
- range = 2
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "mad_touch"
action_background_icon_state = "bg_ecult"
-/obj/effect/proc_holder/spell/pointed/touch/mad_touch/can_target(atom/target, mob/user, silent)
- . = ..()
- if(!.)
- return FALSE
- if(!istype(target,/mob/living/carbon/human))
- if(!silent)
- to_chat(user, "You are unable to touch [target]!")
- return FALSE
- return TRUE
+/obj/item/melee/touch_attack/mad_touch
+ name = "Touch of Madness"
+ desc = "A sinister looking aura that shatters your enemies minds."
+ icon = 'icons/obj/eldritch.dmi'
+ icon_state = "mad_touch"
+ item_state = "madness"
+ catchphrase = "SUNA'IKINTI PROTA"
-/obj/effect/proc_holder/spell/pointed/touch/mad_touch/cast(list/targets, mob/user)
- . = ..()
- for(var/mob/living/carbon/target in targets)
- if(ishuman(targets))
- var/mob/living/carbon/human/tar = target
- if(tar.anti_magic_check())
- tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!")
- return
- if(target.mind && !target.mind.has_antag_datum(/datum/antagonist/heretic))
- to_chat(user,"[target.name] has been cursed!")
- SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "gates_of_mansus", /datum/mood_event/gates_of_mansus)
+/obj/item/melee/touch_attack/mad_touch/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
-/obj/effect/proc_holder/spell/pointed/ash_final
+ if(!proximity_flag || target == user)
+ return
+ if(ishuman(target))
+ var/mob/living/carbon/human/tar = target
+ if(tar.anti_magic_check())
+ tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!")
+ return ..()
+
+ if(iscarbon(target))
+ playsound(user, 'sound/effects/curseattack.ogg', 75, TRUE)
+ var/mob/living/carbon/C = target
+ C.adjustOrganLoss(ORGAN_SLOT_BRAIN,35)
+ C.DefaultCombatKnockdown(50, override_stamdmg = 0)
+ C.gain_trauma(/datum/brain_trauma/mild/phobia)
+ to_chat(user,"[target.name] has been cursed!")
+ SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "gates_of_mansus", /datum/mood_event/gates_of_mansus)
+ return ..()
+
+/obj/effect/proc_holder/spell/targeted/touch/grasp_of_decay
+ name = "Grasp of Decay"
+ desc = "A sinister looking touch that rots your foes from the inside out for twenty seconds."
+ hand_path = /obj/item/melee/touch_attack/grasp_of_decay
+ school = "evocation"
+ charge_max = 1200
+ clothes_req = FALSE
+ action_icon = 'icons/mob/actions/actions_ecult.dmi'
+ action_icon_state = "mansus_grasp"
+ action_background_icon_state = "bg_ecult"
+
+/obj/item/melee/touch_attack/grasp_of_decay
+ name = "Grasp of Decay"
+ desc = "A sinister looking aura that rots your foes from the inside out."
+ icon = 'icons/obj/eldritch.dmi'
+ icon_state = "mansus_grasp"
+ item_state = "mansus"
+ catchphrase = "SKILI'EDUONIS"
+
+/obj/item/melee/touch_attack/grasp_of_decay/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+
+ if(!proximity_flag || target == user)
+ return
+ if(ishuman(target))
+ var/mob/living/carbon/human/tar = target
+ if(tar.anti_magic_check())
+ tar.visible_message("Spell bounces off of [target]!","The spell bounces off of you!")
+ return ..()
+
+ if(iscarbon(target))
+ playsound(user, 'sound/effects/curseattack.ogg', 75, TRUE)
+ var/mob/living/carbon/C = target
+ C.DefaultCombatKnockdown(50, override_stamdmg = 0)
+ C.apply_status_effect(/datum/status_effect/corrosion_curse/lesser)
+ return ..()
+
+/obj/effect/proc_holder/spell/pointed/nightwatchers_rite
name = "Nightwatcher's Rite"
desc = "Powerful spell that releases 5 streams of fire away from you."
school = "transmutation"
@@ -307,7 +350,7 @@
action_icon_state = "flames"
action_background_icon_state = "bg_ecult"
-/obj/effect/proc_holder/spell/pointed/ash_final/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/pointed/nightwatchers_rite/cast(list/targets, mob/user)
for(var/X in targets)
var/T
T = line_target(-25, range, X, user)
@@ -322,11 +365,12 @@
INVOKE_ASYNC(src, .proc/fire_line, user,T)
return ..()
-/obj/effect/proc_holder/spell/pointed/ash_final/proc/line_target(offset, range, atom/at , atom/user)
+/obj/effect/proc_holder/spell/pointed/nightwatchers_rite/proc/line_target(offset, range, atom/at , atom/user)
if(!at)
return
var/angle = ATAN2(at.x - user.x, at.y - user.y) + offset
var/turf/T = get_turf(user)
+ playsound(user,'sound/magic/fireball.ogg', 200, 1)
for(var/i in 1 to range)
var/turf/check = locate(user.x + cos(angle) * i, user.y + sin(angle) * i, user.z)
if(!check)
@@ -334,7 +378,7 @@
T = check
return (getline(user, T) - get_turf(user))
-/obj/effect/proc_holder/spell/pointed/ash_final/proc/fire_line(atom/source, list/turfs)
+/obj/effect/proc_holder/spell/pointed/nightwatchers_rite/proc/fire_line(atom/source, list/turfs)
var/list/hit_list = list()
for(var/turf/T in turfs)
if(istype(T, /turf/closed))
@@ -347,8 +391,8 @@
if(L in hit_list || L == source)
continue
hit_list += L
- L.adjustFireLoss(20)
- to_chat(L, "You're hit by [source]'s fire breath!")
+ L.adjustFireLoss(15)
+ to_chat(L, "You're hit by a blast of fire!")
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
@@ -368,7 +412,7 @@
possible_shapes = list(/mob/living/simple_animal/mouse,\
/mob/living/simple_animal/pet/dog/corgi,\
/mob/living/simple_animal/hostile/carp,\
- /mob/living/simple_animal/bot/secbot, \
+ /mob/living/simple_animal/bot/secbot,\
/mob/living/simple_animal/pet/fox,\
/mob/living/simple_animal/pet/cat )
@@ -430,7 +474,7 @@
action_background_icon_state = "bg_ecult"
range = -1
include_user = TRUE
- charge_max = 700
+ charge_max = 1200
action_icon = 'icons/mob/actions/actions_ecult.dmi'
action_icon_state = "fire_ring"
///how long it lasts
@@ -595,6 +639,39 @@
invocation = "AK'LIS"
action_background_icon_state = "bg_ecult"
+/obj/effect/proc_holder/spell/pointed/trigger/mute/eldritch
+ name = "Silence"
+ desc = "Using the power of the mansus, silences a selected unbeliever for twenty seconds."
+ school = "transmutation"
+ charge_max = 1800
+ clothes_req = FALSE
+ invocation = "VIS'TIEK TAVO'LIZUVIS"
+ invocation_type = "whisper"
+ message = "It feels as if your tongue is being held down by an unseen force!"
+ starting_spells = list("/obj/effect/proc_holder/spell/targeted/genetic/mute")
+ ranged_mousepointer = 'icons/effects/mouse_pointers/mute_target.dmi'
+ action_background_icon_state = "bg_ecult"
+ action_icon = 'icons/mob/actions/actions_ecult.dmi'
+ action_icon_state = "mute"
+ active_msg = "You prepare to silence a target..."
+
+/obj/effect/proc_holder/spell/targeted/genetic/mute
+ mutations = list(MUT_MUTE)
+ duration = 200
+ charge_max = 1200 // needs to be higher than the duration or it'll be permanent
+ sound = 'sound/magic/blind.ogg'
+
+/obj/effect/proc_holder/spell/pointed/trigger/mute/can_target(atom/target, mob/user, silent)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!isliving(target))
+ if(!silent)
+ to_chat(user, "You can only silence living beings!")
+ return FALSE
+ return TRUE
+
+
/obj/effect/temp_visual/dir_setting/entropic
icon = 'icons/effects/160x160.dmi'
icon_state = "entropic_plume"
diff --git a/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm
index 8efd9837a9..425052de2a 100644
--- a/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm
+++ b/code/modules/antagonists/eldritch_cult/knowledge/ash_lore.dm
@@ -95,7 +95,30 @@
desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a person is in critical condition it finishes them off."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/targeted/fiery_rebirth
- next_knowledge = list(/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/final/ash_final)
+ next_knowledge = list(/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/flame_immunity)
+ route = PATH_ASH
+
+/datum/eldritch_knowledge/flame_immunity
+ name = "Nightwatcher's Blessing"
+ gain_text = "The True Light will destroy and make something anew of any individual. If only they accepted it."
+ desc = "Becoming one with the ash, you become immune to fire and heat, allowing you to thrive in a more extreme environment.."
+ cost = 2
+ next_knowledge = list(/datum/eldritch_knowledge/spell/nightwatchers_rite)
+ route = PATH_ASH
+ var/list/trait_list = list(TRAIT_RESISTHEAT,TRAIT_NOFIRE)
+
+/datum/eldritch_knowledge/flame_immunity/on_gain(mob/living/user)
+ to_chat(user, "[gain_text]")
+ for(var/X in trait_list)
+ ADD_TRAIT(user,X,MAGIC_TRAIT)
+
+/datum/eldritch_knowledge/spell/nightwatchers_rite
+ name = "Nightwatcher's Rite"
+ gain_text = "When the Glory of the Lantern scorches and sears their skin, nothing will protect them from the ashes."
+ desc = "Fire off five streams of fire from your hand, each setting ablaze targets hit and scorching them upon contact."
+ cost = 2
+ spell_to_add = /obj/effect/proc_holder/spell/pointed/nightwatchers_rite
+ next_knowledge = list(/datum/eldritch_knowledge/final/ash_final)
route = PATH_ASH
/datum/eldritch_knowledge/ash_blade_upgrade
@@ -167,7 +190,7 @@
required_atoms = list(/mob/living/carbon/human)
cost = 5
route = PATH_ASH
- var/list/trait_list = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_BOMBIMMUNE)
+ var/list/trait_list = list(TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_BOMBIMMUNE)
/datum/eldritch_knowledge/final/ash_final/on_finished_recipe(mob/living/user, list/atoms, loc)
priority_announce("$^@*$^@(#&$(@^$^@# Fear the blaze, for Ashbringer [user.real_name] has come! $^@*$^@(#&$(@^$^@#","#$^@*$^@(#&$(@^$^@#", 'sound/announcer/classic/spanomalies.ogg')
diff --git a/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm
index 9684e1fa0c..5e32cf1b4e 100644
--- a/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm
+++ b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm
@@ -70,7 +70,7 @@
desc = "Empowers your Mansus Grasp to be able to create a single ghoul out of a dead player. You cannot raise the same person twice. Ghouls have only 50 HP and look like husks."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/flesh_ghoul)
- var/ghoul_amt = 6
+ var/ghoul_amt = 4
var/list/spooky_scaries
route = PATH_FLESH
@@ -177,7 +177,7 @@
cost = 1
required_atoms = list(/obj/item/kitchen/knife,/obj/item/reagent_containers/food/snacks/grown/poppy,/obj/item/pen,/obj/item/paper)
mob_to_summon = /mob/living/simple_animal/hostile/eldritch/stalker
- next_knowledge = list(/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/summon/rusty,/datum/eldritch_knowledge/final/flesh_final)
+ next_knowledge = list(/datum/eldritch_knowledge/summon/ashy,/datum/eldritch_knowledge/summon/rusty,/datum/eldritch_knowledge/flesh_blade_upgrade_2)
route = PATH_FLESH
/datum/eldritch_knowledge/summon/ashy
@@ -250,3 +250,28 @@
carbon_user.gib()
return ..()
+
+/datum/eldritch_knowledge/flesh_blade_upgrade_2
+ name = "Remembrance"
+ gain_text = "Pain isn't something easily forgotten."
+ desc = "Your blade remembers more, and remembers how easily bones broke just as its flesh did, guaranteeing dislocated, or broken bones."
+ cost = 2
+ next_knowledge = list(/datum/eldritch_knowledge/spell/touch_of_madness)
+ route = PATH_FLESH
+
+/datum/eldritch_knowledge/flesh_blade_upgrade_2/on_eldritch_blade(target,user,proximity_flag,click_parameters)
+ . = ..()
+ if(iscarbon(target))
+ var/mob/living/carbon/carbon_target = target
+ var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
+ var/datum/wound/blunt/moderate/moderate_wound = new
+ moderate_wound.apply_wound(bodypart)
+
+/datum/eldritch_knowledge/spell/touch_of_madness
+ name = "Touch of Madness"
+ gain_text = "The ignorant mind that inhabits their feeble bodies will crumble when they acknowledge - willingly or not, the truth."
+ desc = "By forcing the knowledge of the Mansus upon my foes, I can show them things that would drive any normal man insane."
+ cost = 2
+ spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/mad_touch
+ next_knowledge = list(/datum/eldritch_knowledge/final/flesh_final)
+ route = PATH_FLESH
diff --git a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm
index 74b3753b69..f5c54dd7bf 100644
--- a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm
+++ b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm
@@ -27,8 +27,13 @@
if(E)
E.on_effect()
H.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_EARS,ORGAN_SLOT_EYES,ORGAN_SLOT_LIVER,ORGAN_SLOT_LUNGS,ORGAN_SLOT_STOMACH,ORGAN_SLOT_HEART),25)
+ else
+ for(var/X in user.mind.spell_list)
+ if(!istype(X,/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp))
+ continue
+ var/obj/effect/proc_holder/spell/targeted/touch/mansus_grasp/MG = X
+ MG.charge_counter = min(round(MG.charge_counter + MG.charge_max * 0.75),MG.charge_max)
target.rust_heretic_act()
- target.emp_act(EMP_HEAVY)
return TRUE
/datum/eldritch_knowledge/spell/area_conversion
@@ -43,7 +48,7 @@
/datum/eldritch_knowledge/spell/rust_wave
name = "Patron's Reach"
desc = "You can now send a bolt of rust that corrupts the immediate area, and poisons the first target hit."
- gain_text = "Messengers of hope fear the rustbringer."
+ gain_text = "Messengers of hope fear the Rustbringer."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/aimed/rust_wave
route = PATH_RUST
@@ -92,19 +97,20 @@
banned_knowledge = list(/datum/eldritch_knowledge/ash_blade_upgrade,/datum/eldritch_knowledge/flesh_blade_upgrade)
route = PATH_RUST
-/datum/eldritch_knowledge/rust_blade_upgrade/on_eldritch_blade(target,user,proximity_flag,click_parameters)
+/datum/eldritch_knowledge/rust_blade_upgrade/on_eldritch_blade(mob/target,user,proximity_flag,click_parameters)
. = ..()
- if(iscarbon(target))
- var/mob/living/carbon/carbon_target = target
- carbon_target.reagents.add_reagent(/datum/reagent/eldritch, 5)
+ if(!IS_HERETIC(target))
+ if(iscarbon(target))
+ var/mob/living/carbon/carbon_target = target
+ carbon_target.reagents.add_reagent(/datum/reagent/eldritch, 5)
/datum/eldritch_knowledge/spell/entropic_plume
name = "Entropic Plume"
desc = "You can now send a befuddling plume that blinds, poisons and makes enemies strike each other, while also converting the immediate area into rust."
- gain_text = "Messengers of hope fear the rustbringer."
+ gain_text = "If they knew, the truth would turn them against eachother."
cost = 1
spell_to_add = /obj/effect/proc_holder/spell/cone/staggered/entropic_plume
- next_knowledge = list(/datum/eldritch_knowledge/final/rust_final,/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/rusty)
+ next_knowledge = list(/datum/eldritch_knowledge/rust_fist_upgrade,/datum/eldritch_knowledge/spell/cleave,/datum/eldritch_knowledge/summon/rusty)
route = PATH_RUST
/datum/eldritch_knowledge/armor
@@ -119,12 +125,38 @@
/datum/eldritch_knowledge/essence
name = "Priest's Ritual"
desc = "You can now transmute a tank of water into a bottle of eldritch fluid."
- gain_text = "This is an old recipe, i got it from an owl."
+ gain_text = "This is an old recipe, I got it from an owl."
cost = 1
next_knowledge = list(/datum/eldritch_knowledge/rust_regen,/datum/eldritch_knowledge/spell/ashen_shift)
required_atoms = list(/obj/structure/reagent_dispensers/watertank)
result_atoms = list(/obj/item/reagent_containers/glass/beaker/eldritch)
+/datum/eldritch_knowledge/rust_fist_upgrade
+ name = "Vile Grip"
+ desc = "Empowers your Mansus Grasp further, sickening your foes and making them vomit, while also strengthening the rate at which your hand decays objects."
+ gain_text = "A sickly diseased touch that was, yet, so welcoming."
+ cost = 2
+ next_knowledge = list(/datum/eldritch_knowledge/spell/grasp_of_decay)
+ var/rust_force = 750
+ var/static/list/blacklisted_turfs = typecacheof(list(/turf/closed,/turf/open/space,/turf/open/lava,/turf/open/chasm,/turf/open/floor/plating/rust))
+ route = PATH_RUST
+
+/datum/eldritch_knowledge/rust_fist_upgrade/on_mansus_grasp(atom/target, mob/user, proximity_flag, click_parameters)
+ . = ..()
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.set_disgust(75)
+ return TRUE
+
+/datum/eldritch_knowledge/spell/grasp_of_decay
+ name = "Grasp of Decay"
+ desc = "Applying your knowledge of rust to the human body, a knowledge that could decay your foes from the inside out, resulting in organ failure, vomiting, or eventual death through peeling flesh."
+ gain_text = "Decay, similar to Rust, yet so much more terribly uninviting."
+ cost = 2
+ spell_to_add = /obj/effect/proc_holder/spell/targeted/touch/grasp_of_decay
+ next_knowledge = list(/datum/eldritch_knowledge/final/rust_final)
+ route = PATH_RUST
+
/datum/eldritch_knowledge/final/rust_final
name = "Rustbringer's Oath"
desc = "Bring three corpses onto a transmutation rune. After you finish the ritual, rust will now automatically spread from the rune. Your healing on rust is also tripled, while you become more resilient overall."
diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm
index 7bb7f1aa76..cb534b6613 100644
--- a/code/modules/antagonists/revenant/revenant_spawn_event.dm
+++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm
@@ -4,7 +4,6 @@
name = "Spawn Revenant" // Did you mean 'griefghost'?
typepath = /datum/round_event/ghost_role/revenant
weight = 7
- gamemode_blacklist = list("dynamic")
max_occurrences = 1
min_players = 5
diff --git a/code/modules/antagonists/swarmer/swarmer_event.dm b/code/modules/antagonists/swarmer/swarmer_event.dm
index c626799a53..43ac07cba9 100644
--- a/code/modules/antagonists/swarmer/swarmer_event.dm
+++ b/code/modules/antagonists/swarmer/swarmer_event.dm
@@ -5,7 +5,6 @@
max_occurrences = 1 //Only once okay fam
earliest_start = 30 MINUTES
min_players = 35
- gamemode_blacklist = list("dynamic")
/datum/round_event/spawn_swarmer
diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm
index 65a20bb6c5..1e7d2cdbd7 100644
--- a/code/modules/cargo/packs/misc.dm
+++ b/code/modules/cargo/packs/misc.dm
@@ -13,6 +13,13 @@
//////////////////// Paperwork and Writing Supplies //////////////////////////
//////////////////////////////////////////////////////////////////////////////
+
+/datum/supply_pack/misc/anvil
+ name = "Anvil Crate"
+ desc = "An anvil in a crate, we had to dig this out of the old warehouse. It's got wheels on it so you can move it."
+ cost = 7500
+ contains = list(/obj/structure/anvil/obtainable/basic)
+
/datum/supply_pack/misc/artsupply
name = "Art Supplies"
desc = "Make some happy little accidents with six canvasses, two easels, two boxes of crayons, and a rainbow crayon!"
diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm
index 395b3b88a5..7f0dedaab6 100644
--- a/code/modules/events/anomaly_bluespace.dm
+++ b/code/modules/events/anomaly_bluespace.dm
@@ -4,7 +4,6 @@
max_occurrences = 1
weight = 5
- gamemode_blacklist = list("dynamic")
/datum/round_event/anomaly/anomaly_bluespace
startWhen = 3
diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm
index a9a7ed50b9..8047976330 100644
--- a/code/modules/events/anomaly_flux.dm
+++ b/code/modules/events/anomaly_flux.dm
@@ -5,7 +5,6 @@
min_players = 10
max_occurrences = 5
weight = 20
- gamemode_blacklist = list("dynamic")
/datum/round_event/anomaly/anomaly_flux
startWhen = 10
diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm
index cabd7face8..7d2bb33889 100644
--- a/code/modules/events/anomaly_grav.dm
+++ b/code/modules/events/anomaly_grav.dm
@@ -4,7 +4,6 @@
max_occurrences = 5
weight = 20
- gamemode_blacklist = list("dynamic")
/datum/round_event/anomaly/anomaly_grav
diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm
index 8c8fbd6d36..350c8fc946 100644
--- a/code/modules/events/anomaly_pyro.dm
+++ b/code/modules/events/anomaly_pyro.dm
@@ -4,7 +4,6 @@
max_occurrences = 5
weight = 20
- gamemode_blacklist = list("dynamic")
/datum/round_event/anomaly/anomaly_pyro
startWhen = 3
diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm
index 96d084873d..e2a4ceadf3 100644
--- a/code/modules/events/anomaly_vortex.dm
+++ b/code/modules/events/anomaly_vortex.dm
@@ -5,7 +5,6 @@
min_players = 20
max_occurrences = 2
weight = 5
- gamemode_blacklist = list("dynamic")
/datum/round_event/anomaly/anomaly_vortex
startWhen = 10
diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm
index 0a07e2a693..75c514774c 100644
--- a/code/modules/events/brain_trauma.dm
+++ b/code/modules/events/brain_trauma.dm
@@ -3,6 +3,13 @@
typepath = /datum/round_event/brain_trauma
weight = 25
+/datum/round_event_control/brain_trauma/canSpawnEvent(var/players_amt, var/gamemode)
+ var/list/enemy_roles = list("Medical Doctor","Chief Medical Officer","Paramedic")
+ for (var/mob/M in GLOB.alive_mob_list)
+ if(M.stat != DEAD && (M.mind?.assigned_role in enemy_roles))
+ return TRUE
+ return FALSE
+
/datum/round_event/brain_trauma
fakeable = FALSE
@@ -16,18 +23,19 @@
continue
if(HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
+ if(!is_station_level(H.z))
+ continue
traumatize(H)
break
/datum/round_event/brain_trauma/proc/traumatize(mob/living/carbon/human/H)
var/resistance = pick(
65;TRAUMA_RESILIENCE_BASIC,
- 30;TRAUMA_RESILIENCE_SURGERY,
- 5;TRAUMA_RESILIENCE_LOBOTOMY)
+ 35;TRAUMA_RESILIENCE_SURGERY)
var/trauma_type = pickweight(list(
- BRAIN_TRAUMA_MILD = 60,
- BRAIN_TRAUMA_SEVERE = 30,
+ BRAIN_TRAUMA_MILD = 80,
+ BRAIN_TRAUMA_SEVERE = 10,
BRAIN_TRAUMA_SPECIAL = 10
))
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index 1c88e68377..f0e4bd4a53 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -5,7 +5,6 @@
min_players = 15
max_occurrences = 1
- gamemode_blacklist = list("dynamic")
/datum/round_event/brand_intelligence
announceWhen = 21
diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm
index 2c553fc8a7..d08e6267a0 100644
--- a/code/modules/events/carp_migration.dm
+++ b/code/modules/events/carp_migration.dm
@@ -5,7 +5,6 @@
min_players = 2
earliest_start = 10 MINUTES
max_occurrences = 6
- gamemode_blacklist = list("dynamic")
/datum/round_event/carp_migration
announceWhen = 3
diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm
index 45fa1c8a01..cb62e0df22 100644
--- a/code/modules/events/communications_blackout.dm
+++ b/code/modules/events/communications_blackout.dm
@@ -2,7 +2,6 @@
name = "Communications Blackout"
typepath = /datum/round_event/communications_blackout
weight = 30
- gamemode_blacklist = list("dynamic")
/datum/round_event/communications_blackout
announceWhen = 1
diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm
index 860685c787..eb7edcafbf 100644
--- a/code/modules/events/dust.dm
+++ b/code/modules/events/dust.dm
@@ -5,7 +5,6 @@
max_occurrences = 1000
earliest_start = 0 MINUTES
alert_observers = FALSE
- gamemode_blacklist = list("dynamic")
/datum/round_event/space_dust
startWhen = 1
@@ -29,4 +28,4 @@
fakeable = FALSE
/datum/round_event/sandstorm/tick()
- spawn_meteors(10, GLOB.meteorsC)
\ No newline at end of file
+ spawn_meteors(10, GLOB.meteorsC)
diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm
index 5e5e318e3c..b850b4db62 100644
--- a/code/modules/events/electrical_storm.dm
+++ b/code/modules/events/electrical_storm.dm
@@ -5,7 +5,6 @@
min_players = 5
weight = 40
alert_observers = FALSE
- gamemode_blacklist = list("dynamic")
/datum/round_event/electrical_storm
var/lightsoutAmount = 1
diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm
index b3bc571a4a..8c33e69107 100644
--- a/code/modules/events/heart_attack.dm
+++ b/code/modules/events/heart_attack.dm
@@ -4,7 +4,6 @@
weight = 20
max_occurrences = 2
min_players = 40 // To avoid shafting lowpop
- gamemode_blacklist = list("dynamic")
/datum/round_event/heart_attack/start()
var/list/heart_attack_contestants = list()
@@ -20,4 +19,4 @@
var/mob/living/carbon/human/winner = pickweight(heart_attack_contestants)
var/datum/disease/D = new /datum/disease/heart_failure()
winner.ForceContractDisease(D, FALSE, TRUE)
- announce_to_ghosts(winner)
\ No newline at end of file
+ announce_to_ghosts(winner)
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index b15e9d1f99..c75aff0c4a 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -3,7 +3,6 @@
/datum/round_event_control/ion_storm
name = "Ion Storm"
typepath = /datum/round_event/ion_storm
- gamemode_blacklist = list("dynamic")
weight = 15
min_players = 2
diff --git a/code/modules/events/major_dust.dm b/code/modules/events/major_dust.dm
index c594d7b3c0..d7d8f1aec8 100644
--- a/code/modules/events/major_dust.dm
+++ b/code/modules/events/major_dust.dm
@@ -2,7 +2,6 @@
name = "Major Space Dust"
typepath = /datum/round_event/meteor_wave/major_dust
weight = 8
- gamemode_blacklist = list("dynamic")
/datum/round_event/meteor_wave/major_dust
wave_name = "space dust"
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index 7763f9950d..515e0fe1b3 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -10,7 +10,6 @@
min_players = 15
max_occurrences = 3
earliest_start = 25 MINUTES
- gamemode_blacklist = list("dynamic")
/datum/round_event/meteor_wave
startWhen = 6
diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm
index 6e5512a617..698f5130f1 100644
--- a/code/modules/events/nightmare.dm
+++ b/code/modules/events/nightmare.dm
@@ -2,7 +2,6 @@
name = "Spawn Nightmare"
typepath = /datum/round_event/ghost_role/nightmare
max_occurrences = 1
- gamemode_blacklist = list("dynamic")
min_players = 20
/datum/round_event/ghost_role/nightmare
diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm
index 9ab5e8d517..4cbfb8ae9a 100644
--- a/code/modules/events/pirates.dm
+++ b/code/modules/events/pirates.dm
@@ -5,7 +5,7 @@
max_occurrences = 1
min_players = 10
earliest_start = 30 MINUTES
- gamemode_blacklist = list("nuclear","dynamic")
+ gamemode_blacklist = list("nuclear")
/datum/round_event_control/pirates/preRunEvent()
if (!SSmapping.empty_space)
diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm
index 457b5bd4ec..5ef30d0030 100644
--- a/code/modules/events/portal_storm.dm
+++ b/code/modules/events/portal_storm.dm
@@ -4,7 +4,6 @@
weight = 2
min_players = 15
earliest_start = 30 MINUTES
- gamemode_blacklist = list("dynamic")
/datum/round_event/portal_storm/syndicate_shocktroop
boss_types = list(/mob/living/simple_animal/hostile/syndicate/melee/space/stormtrooper = 2)
diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm
index 22e475a8ef..6bedce6b4b 100644
--- a/code/modules/events/processor_overload.dm
+++ b/code/modules/events/processor_overload.dm
@@ -3,7 +3,6 @@
typepath = /datum/round_event/processor_overload
weight = 15
min_players = 20
- gamemode_blacklist = list("dynamic")
/datum/round_event/processor_overload
announceWhen = 1
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index 0a5bedb464..36e16bb2c9 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -2,7 +2,6 @@
name = "Radiation Storm"
typepath = /datum/round_event/radiation_storm
max_occurrences = 1
- gamemode_blacklist = list("dynamic")
/datum/round_event/radiation_storm
diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm
index d1c327e0f7..23ce6ce730 100644
--- a/code/modules/events/spider_infestation.dm
+++ b/code/modules/events/spider_infestation.dm
@@ -2,7 +2,6 @@
name = "Spider Infestation"
typepath = /datum/round_event/spider_infestation
weight = 5
- gamemode_blacklist = list("dynamic")
max_occurrences = 1
min_players = 15
diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm
index dc672cec45..cd7b23a577 100644
--- a/code/modules/events/vent_clog.dm
+++ b/code/modules/events/vent_clog.dm
@@ -3,7 +3,6 @@
typepath = /datum/round_event/vent_clog
weight = 10
max_occurrences = 3
- gamemode_blacklist = list("dynamic")
min_players = 25
/datum/round_event/vent_clog
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 1b4716b407..0920c9ccb6 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -4,7 +4,6 @@
max_occurrences = 3
weight = 2
min_players = 2
- gamemode_blacklist = list("dynamic")
/datum/round_event/wormholes
diff --git a/code/modules/mining/equipment/mineral_scanner.dm b/code/modules/mining/equipment/mineral_scanner.dm
index 9ccb7c0efc..b2cd840468 100644
--- a/code/modules/mining/equipment/mineral_scanner.dm
+++ b/code/modules/mining/equipment/mineral_scanner.dm
@@ -12,13 +12,14 @@
slot_flags = ITEM_SLOT_BELT
var/cooldown = 35
var/current_cooldown = 0
+ var/range = 7
/obj/item/mining_scanner/attack_self(mob/user)
if(!user.client)
return
if(current_cooldown <= world.time)
current_cooldown = world.time + cooldown
- mineral_scan_pulse(get_turf(user))
+ mineral_scan_pulse(get_turf(user), range)
//Debug item to identify all ore spread quickly
/obj/item/mining_scanner/admin
diff --git a/code/modules/smithing/anvil.dm b/code/modules/smithing/anvil.dm
new file mode 100644
index 0000000000..88711aec37
--- /dev/null
+++ b/code/modules/smithing/anvil.dm
@@ -0,0 +1,315 @@
+#define WORKPIECE_PRESENT 1
+#define WORKPIECE_INPROGRESS 2
+#define WORKPIECE_FINISHED 3
+#define WORKPIECE_SLAG 5
+
+#define RECIPE_SMALLPICK "dbp" //draw bend punch
+#define RECIPE_LARGEPICK "ddbp" //draw draw bend punch
+#define RECIPE_SHOVEL "dfup" //draw fold upset punch
+#define RECIPE_HAMMER "sfp" //shrink fold punch
+
+
+#define RECIPE_SMALLKNIFE "sdd" //shrink draw draw
+#define RECIPE_SHORTSWORD "dff" //draw fold fold
+#define RECIPE_WAKI "dfsf" //draw fold shrink fold
+#define RECIPE_SCIMITAR "dfb" //draw fold bend
+#define RECIPE_SABRE "ddsf" //draw draw shrink fold
+#define RECIPE_RAPIER "sdfd" //shrink draw fold draw
+#define RECIPE_BROADSWORD "dfuf" //draw fold upset fold
+#define RECIPE_ZWEIHANDER "udfsf" //upset draw fold shrink fold
+#define RECIPE_KATANA "fffff" //fold fold fold fold fold
+
+
+#define RECIPE_SCYTHE "bdf" //bend draw fold
+#define RECIPE_COGHEAD "bsf" //bend shrink fold.
+
+
+#define RECIPE_JAVELIN "dbf" //draw bend fold
+#define RECIPE_HALBERD "duffp" //draw upset fold fold punch
+#define RECIPE_GLAIVE "usfp" //upset shrink fold punch
+#define RECIPE_PIKE "ddbf" //draw draw bend fold
+
+/obj/structure/anvil
+ name = "anvil"
+ desc = "Base class of anvil. This shouldn't exist, but is useable."
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "anvil"
+ density = TRUE
+ anchored = TRUE
+ var/workpiece_state = FALSE
+ var/datum/material/workpiece_material
+ var/anvilquality = 0
+ var/currentquality = 0 //lolman? what the fuck do these vars do?
+ var/currentsteps = 0 //even i don't know
+ var/outrightfailchance = 1 //todo: document this shit
+ var/stepsdone = ""
+ var/rng = FALSE
+ var/debug = FALSE //vv this if you want an artifact
+ var/artifactrolled = FALSE
+ var/itemqualitymax = 20
+ var/list/smithrecipes = list(RECIPE_HAMMER = /obj/item/smithing/hammerhead,
+ RECIPE_SCYTHE = /obj/item/smithing/scytheblade,
+ RECIPE_SHOVEL = /obj/item/smithing/shovelhead,
+ RECIPE_COGHEAD = /obj/item/smithing/cogheadclubhead,
+ RECIPE_JAVELIN = /obj/item/smithing/javelinhead,
+ RECIPE_LARGEPICK = /obj/item/smithing/pickaxehead,
+ RECIPE_SMALLPICK = /obj/item/smithing/prospectingpickhead,
+ RECIPE_SHORTSWORD = /obj/item/smithing/shortswordblade,
+ RECIPE_SCIMITAR = /obj/item/smithing/scimitarblade,
+ RECIPE_WAKI = /obj/item/smithing/wakiblade,
+ RECIPE_RAPIER = /obj/item/smithing/rapierblade,
+ RECIPE_SABRE = /obj/item/smithing/sabreblade,
+ RECIPE_SMALLKNIFE = /obj/item/smithing/knifeblade,
+ RECIPE_BROADSWORD = /obj/item/smithing/broadblade,
+ RECIPE_ZWEIHANDER = /obj/item/smithing/zweiblade,
+ RECIPE_KATANA = /obj/item/smithing/katanablade,
+ RECIPE_HALBERD = /obj/item/smithing/halberdhead,
+ RECIPE_GLAIVE = /obj/item/smithing/glaivehead,
+ RECIPE_PIKE = /obj/item/smithing/pikehead)
+
+/obj/structure/anvil/Initialize()
+ ..()
+ currentquality = anvilquality
+
+/obj/structure/anvil/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/ingot))
+ var/obj/item/ingot/notsword = I
+ if(workpiece_state)
+ to_chat(user, "There's already a workpiece! Finish it or take it off.")
+ return FALSE
+ if(notsword.workability == "shapeable")
+ workpiece_state = WORKPIECE_PRESENT
+ workpiece_material = notsword.custom_materials
+ to_chat(user, "You place the [notsword] on the [src].")
+ currentquality = anvilquality
+ var/skillmod = 0
+ if(user.mind.skill_holder)
+ skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/2
+ currentquality += skillmod
+ qdel(notsword)
+ else
+ to_chat(user, "The ingot isn't workable yet!")
+ return FALSE
+ return
+ else if(istype(I, /obj/item/melee/smith/hammer))
+ var/obj/item/melee/smith/hammer/hammertime = I
+ if(workpiece_state == WORKPIECE_PRESENT || workpiece_state == WORKPIECE_INPROGRESS)
+ do_shaping(user, hammertime.qualitymod)
+ return
+ else
+ to_chat(user, "You can't work an empty anvil!")
+ return FALSE
+ return ..()
+
+/obj/structure/anvil/wrench_act(mob/living/user, obj/item/I)
+ ..()
+ default_unfasten_wrench(user, I, 5)
+ return TRUE
+
+
+/obj/structure/anvil/proc/do_shaping(mob/user, var/qualitychange)
+ currentquality += qualitychange
+ var/list/shapingsteps = list("weak hit", "strong hit", "heavy hit", "fold", "draw", "shrink", "bend", "punch", "upset") //weak/strong/heavy hit affect strength. All the other steps shape.
+ workpiece_state = WORKPIECE_INPROGRESS
+ var/stepdone = input(user, "How would you like to work the metal?") in shapingsteps
+ var/steptime = 50
+ if(user.mind.skill_holder)
+ var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1
+ steptime = 50 / skillmod
+ playsound(src, 'sound/effects/clang2.ogg',40, 2)
+ if(!do_after(user, steptime, target = src))
+ return FALSE
+ switch(stepdone)
+ if("weak hit")
+ currentsteps += 1
+ outrightfailchance += 5
+ currentquality += 1
+ if("strong hit")
+ currentsteps += 2
+ outrightfailchance += 9.5
+ currentquality += 2
+ if("heavy hit")
+ currentsteps += 3
+ outrightfailchance += 12.5
+ currentquality += 3
+ if("fold")
+ stepsdone += "f"
+ currentsteps += 1
+ currentquality -= 1
+ if("draw")
+ stepsdone += "d"
+ currentsteps += 1
+ currentquality -= 1
+ if("shrink")
+ stepsdone += "s"
+ currentsteps += 1
+ currentquality -= 1
+ if("bend")
+ stepsdone += "b"
+ currentsteps += 1
+ currentquality -= 1
+ if("punch")
+ stepsdone += "p"
+ currentsteps += 1
+ currentquality -= 1
+ if("upset")
+ stepsdone += "u"
+ currentsteps += 1
+ currentquality -= 1
+ user.visible_message("[user] works the metal on the anvil with their hammer with a loud clang!", \
+ "You [stepdone] the metal with a loud clang!")
+ playsound(src, 'sound/effects/clang2.ogg',40, 2)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/effects/clang2.ogg', 40, 2), 15)
+ if(length(stepsdone) >= 3)
+ tryfinish(user)
+
+/obj/structure/anvil/proc/tryfinish(mob/user)
+ var/artifactchance = 0
+ if(!artifactrolled)
+ artifactchance = (1+(user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/4))/2500
+ artifactrolled = TRUE
+ var/artifact = max(prob(artifactchance), debug)
+ var/finalfailchance = outrightfailchance
+ if(user.mind.skill_holder)
+ var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1
+ finalfailchance = max(0, finalfailchance / skillmod) //lv 2 gives 20% less to fail, 3 30%, etc
+ if((currentsteps > 10 || (rng && prob(finalfailchance))) && !artifact)
+ to_chat(user, "")
+ var/turf/T = get_turf(user)
+ workpiece_state = FALSE
+ new /obj/item/stack/ore/slag(T)
+ currentquality = anvilquality
+ stepsdone = ""
+ currentsteps = 0
+ outrightfailchance = 1
+ artifactrolled = FALSE
+ if(user.mind.skill_holder)
+ user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 25, 400, silent = FALSE)
+ for(var/i in smithrecipes)
+ if(i == stepsdone)
+ var/turf/T = get_turf(user)
+ var/obj/item/smithing/create = smithrecipes[stepsdone]
+ var/obj/item/smithing/finisheditem = new create(T)
+ to_chat(user, "You finish your [finisheditem]!")
+ if(artifact)
+ to_chat(user, "It is an artifact, a creation whose legacy shall live on forevermore.") //todo: SSblackbox
+ currentquality = max(currentquality, 2)
+ finisheditem.quality = currentquality * 3//this is insane i know it's 1/2500 for most of the time and 0.8% at best
+ finisheditem.artifact = TRUE
+ else
+ finisheditem.quality = min(currentquality, itemqualitymax)
+ switch(finisheditem.quality)
+ if(-1000 to -8)
+ finisheditem.desc = "It looks to be the most awfully made object you've ever seen."
+ if(-8)
+ finisheditem.desc = "It looks to be the second most awfully made object you've ever seen."
+ if(-8 to 0)
+ finisheditem.desc = "It looks to be barely passable as... whatever it's trying to pass for."
+ if(0)
+ finisheditem.desc = "It looks to be totally average."
+ if(0 to INFINITY)
+ finisheditem.desc = "It looks to be better than average."
+ workpiece_state = FALSE
+ finisheditem.set_custom_materials(workpiece_material)
+ currentquality = anvilquality
+ stepsdone = ""
+ currentsteps = 0
+ outrightfailchance = 1
+ artifactrolled = FALSE
+ if(user.mind.skill_holder)
+ user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 50, 10000000, silent = FALSE)
+ break
+
+/obj/structure/anvil/debugsuper
+ name = "super ultra epic anvil of debugging."
+ desc = "WOW. A DEBUG ITEM STRUCTURE. EPIC."
+ icon_state = "anvil"
+ anvilquality = 10
+ itemqualitymax = 9001
+ outrightfailchance = 0
+
+/obj/structure/anvil/obtainable
+ name = "anvil"
+ desc = "Base class of anvil. This shouldn't exist, but is useable."
+ anvilquality = 0
+ outrightfailchance = 5
+ rng = TRUE
+
+/obj/structure/anvil/obtainable/table
+ name = "table anvil"
+ desc = "A slightly reinforced table. Good luck."
+ icon_state = "tablevil"
+ anvilquality = -2
+ itemqualitymax = 0
+
+
+/obj/structure/anvil/obtainable/table/do_shaping(mob/user, var/qualitychange)
+ if(prob(5))
+ to_chat(user, "The [src] breaks under the strain!")
+ take_damage(max_integrity)
+ return FALSE
+ else
+ ..()
+
+/obj/structure/anvil/obtainable/bronze
+ name = "slab of bronze"
+ desc = "A big block of bronze. Useable as an anvil."
+ custom_materials = list(/datum/material/bronze=8000)
+ icon_state = "ratvaranvil"
+ anvilquality = -0.5
+ itemqualitymax = 2
+
+/obj/structure/anvil/obtainable/sandstone
+ name = "sandstone brick anvil"
+ desc = "A big block of sandstone. Useable as an anvil."
+ custom_materials = list(/datum/material/sandstone=8000)
+ icon_state = "sandvil"
+ anvilquality = -1
+ itemqualitymax = 2
+
+/obj/structure/anvil/obtainable/basalt
+ name = "basalt brick anvil"
+ desc = "A big block of basalt. Useable as an anvil, better than sandstone. Igneous!"
+ icon_state = "sandvilnoir"
+ anvilquality = -0.5
+ itemqualitymax = 4
+
+/obj/structure/anvil/obtainable/basic
+ name = "anvil"
+ desc = "An anvil. It's got wheels bolted to the bottom."
+ anvilquality = 0
+ itemqualitymax = 6
+
+/obj/structure/anvil/obtainable/ratvar
+ name = "brass anvil"
+ desc = "A big block of what appears to be brass. Useable as an anvil, if whatever's holding the brass together lets you."
+ custom_materials = list(/datum/material/bronze=8000)
+ icon_state = "ratvaranvil"
+ anvilquality = 1
+ itemqualitymax = 8
+
+/obj/structure/anvil/obtainable/ratvar/attackby(obj/item/I, mob/user)
+ if(is_servant_of_ratvar(user))
+ return ..()
+ else
+ to_chat(user, "KNPXWN, QNJCQNW!") //rot13 then rot22 if anyone wants to decode
+
+/obj/structure/anvil/obtainable/narsie
+ name = "runic anvil"
+ desc = "An anvil made of a strange, runic metal."
+ custom_materials = list(/datum/material/runedmetal=8000)
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "evil"
+ anvilquality = 1
+ itemqualitymax = 8
+
+/obj/structure/anvil/obtainable/narsie/attackby(obj/item/I, mob/user)
+ if(iscultist(user))
+ return ..()
+ else
+ to_chat(user, "That is not yours to use!")
+
+#undef WORKPIECE_PRESENT
+#undef WORKPIECE_INPROGRESS
+#undef WORKPIECE_FINISHED
+#undef WORKPIECE_SLAG
diff --git a/code/modules/smithing/finished_items.dm b/code/modules/smithing/finished_items.dm
new file mode 100644
index 0000000000..5db6b09452
--- /dev/null
+++ b/code/modules/smithing/finished_items.dm
@@ -0,0 +1,329 @@
+
+/obj/item/melee/smith
+ name = "base class obj/item/melee/smith" //tin. handles overlay and quality and shit.
+ desc = "cringe"
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "claymore"
+ item_state = "claymore"
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON //yeah ok
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 6
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
+ var/quality
+ var/overlay_state = "stick"
+ var/mutable_appearance/overlay
+ var/wielded_mult = 1
+ var/wield_force = 15
+
+/obj/item/melee/smith/Initialize()
+ ..()
+ if(desc == "cringe")
+ desc = "A handmade [name]."
+ overlay = mutable_appearance(icon, overlay_state)
+ overlay.appearance_flags = RESET_COLOR
+ add_overlay(overlay)
+ if(force < 0)
+ force = 0
+
+
+/obj/item/melee/smith/twohand
+ item_flags = NEEDS_PERMIT //it's a bigass sword/spear. beepsky is going to give you shit for it.
+ sharpness = SHARP_EDGED
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ force = 10
+ wielded_mult = 1.75
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/melee/smith/twohand/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 100, 70) //decent in a pinch, but pretty bad.
+ AddElement(/datum/element/sword_point)
+
+
+
+///////////////////////////
+// Mining //
+///////////////////////////
+/obj/item/mining_scanner/prospector
+ name = "prospector's pickaxe"
+ desc = "A pickaxe that can sound rocks to find mineral deposits and stop gibtonite detonations."
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "minipick" //todo:sprite
+ sharpness = SHARP_POINTY//it doesnt have a blade it has a point
+
+/obj/item/mining_scanner/prospector/Initialize()
+ ..()
+ var/mutable_appearance/overlay
+ desc = "A handmade [name]."
+ overlay = mutable_appearance(icon, "minihandle")
+ overlay.appearance_flags = RESET_COLOR
+ add_overlay(overlay)
+ if(force < 0)
+ force = 0
+
+/obj/item/pickaxe/smithed
+ name = "pickaxe"
+ desc = "A pickaxe."
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "pickaxe"
+ sharpness = SHARP_POINTY
+
+/obj/item/pickaxe/smithed/Initialize()
+ ..()
+ desc = "A handmade [name]."
+ var/mutable_appearance/overlay
+ overlay = mutable_appearance(icon, "stick")
+ overlay.appearance_flags = RESET_COLOR
+ add_overlay(overlay)
+ if(force < 0)
+ force = 0
+
+/obj/item/pickaxe/smithed/attack_self(mob/user)
+ to_chat(user, "Tool does not have a configureable dig range.")
+
+/obj/item/shovel/smithed
+ name = "shovel"
+ desc = "A shovel."
+ icon = 'icons/obj/smith.dmi'
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ icon_state = "shovel"
+ sharpness = SHARP_EDGED //it cuts through the earth
+
+/obj/item/shovel/smithed/Initialize()
+ ..()
+ desc = "A handmade [name]."
+ var/mutable_appearance/overlay
+ overlay = mutable_appearance(icon, "shovelhandle")
+ overlay.appearance_flags = RESET_COLOR
+ add_overlay(overlay)
+ if(force < 0)
+ force = 0
+
+
+///////////////////////////
+// Spears //
+///////////////////////////
+
+
+/obj/item/melee/smith/twohand/halberd
+ name = "halberd"
+ icon_state = "halberd"
+ w_class = WEIGHT_CLASS_HUGE
+ overlay_state = "spearhandle"
+ slot_flags = ITEM_SLOT_BACK
+ wielded_mult = 2.5
+
+/obj/item/melee/smith/twohand/halberd/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
+/obj/item/melee/smith/twohand/javelin
+ name = "javelin"
+ icon_state = "javelin"
+ overlay_state = "longhandle"
+ wielded_mult = 1.5
+ slot_flags = ITEM_SLOT_BACK
+ sharpness = SHARP_POINTY
+
+
+/obj/item/melee/smith/twohand/javelin/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
+/obj/item/melee/smith/twohand/glaive
+ name = "glaive"
+ icon_state = "glaive"
+ overlay_state = "longhandle"
+ slot_flags = ITEM_SLOT_BACK
+ wielded_mult = 2
+
+/obj/item/melee/smith/twohand/glaive/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
+
+/obj/item/melee/smith/twohand/pike
+ name = "pike"
+ icon_state = "pike"
+ w_class = WEIGHT_CLASS_HUGE
+ overlay_state = "longhandle"
+ reach = 2 //yeah ok
+ slot_flags = ITEM_SLOT_BACK
+ sharpness = SHARP_POINTY
+
+//////////////////////////
+// Other Melee //
+///////////////////////////
+
+
+/obj/item/melee/smith/hammer//blacksmithing, not warhammer.
+ name = "hammer"
+ icon_state = "hammer"
+ overlay_state = "hammerhandle"
+ var/qualitymod = 0
+
+/obj/item/scythe/smithed //we need to inherit scythecode, but that's about it.
+ material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+
+
+/obj/item/melee/smith/cogheadclub
+ name = "coghead club"
+ icon_state = "coghead"
+ item_flags = NEEDS_PERMIT
+ overlay_state = "stick"
+
+/obj/item/melee/smith/shortsword
+ name = "gladius"
+ force = 9
+ item_flags = NEEDS_PERMIT
+ sharpness = SHARP_EDGED
+ icon_state = "gladius"
+ overlay_state = "gladiushilt"
+
+/obj/item/melee/smith/shortsword/scimitar
+ name = "scimitar"
+ sharpness = SHARP_EDGED
+ icon_state = "scimitar"
+ overlay_state = "scimitarhilt"
+
+/obj/item/melee/smith/wakizashi
+ name = "wakizashi"
+ sharpness = SHARP_EDGED
+ force = 7
+ item_flags = NEEDS_PERMIT | ITEM_CAN_PARRY
+ obj_flags = UNIQUE_RENAME
+ icon_state = "waki"
+ overlay_state = "wakihilt"
+ block_parry_data = /datum/block_parry_data/waki
+
+/datum/block_parry_data/waki //like longbokken but worse reflect
+ parry_stamina_cost = 6
+ parry_time_windup = 0
+ parry_time_active = 15 //decent window
+ parry_time_spindown = 0
+ parry_time_perfect = 2
+ parry_time_perfect_leeway = 0.75
+ parry_imperfect_falloff_percent = 7.5
+ parry_efficiency_to_counterattack = 100
+ parry_efficiency_considered_successful = 80
+ parry_efficiency_perfect = 120
+ parry_failed_stagger_duration = 3 SECONDS
+ parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 1.9)
+
+/obj/item/melee/smith/twohand/broadsword
+ name = "broadsword"
+ icon_state = "broadsword"
+ overlay_state = "broadhilt"
+ wielded_mult = 1.8
+
+/obj/item/melee/smith/twohand/zweihander
+ name = "zweihander"
+ icon_state = "zwei"
+ overlay_state = "zweihilt"
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON * 2
+ force = 4
+ wielded_mult = 3 //affected more by quality. a -1 is 25% less damage, a +1 is 25% more. These bonuses are tripled when wielded.
+
+/obj/item/melee/smith/twohand/katana
+ name = "katana"
+ icon_state = "katana"
+ overlay_state = "katanahilt"
+ force = 7
+ wielded_mult = 2
+ item_flags = ITEM_CAN_PARRY | NEEDS_PERMIT //want to name your katana "DEMON BLADE" or some shit? go ahead, idiot.
+ obj_flags = UNIQUE_RENAME
+ block_parry_data = /datum/block_parry_data/captain_saber //todo
+
+/obj/item/melee/smith/sabre
+ name = "sabre"
+ icon_state = "sabre"
+ sharpness = SHARP_EDGED
+ overlay_state = "sabrehilt"
+ armour_penetration = 15
+ force = 9
+ hitsound = 'sound/weapons/rapierhit.ogg'
+ item_flags = NEEDS_PERMIT | ITEM_CAN_PARRY
+ block_parry_data = /datum/block_parry_data/captain_saber //yeah this is fine i guess
+
+/obj/item/melee/smith/sabre/rapier
+ name = "rapier"
+ icon_state = "rapier"
+ sharpness = SHARP_EDGED
+ overlay_state = "rapierhilt"
+ force = 6 //less force, stronger parry
+ sharpness = SHARP_POINTY
+ armour_penetration = 30
+ block_parry_data = /datum/block_parry_data/smithrapier
+
+/datum/block_parry_data/smithrapier //parry into riposte. i am pretty sure this is going to be nearly fucking impossible to land.
+ parry_stamina_cost = 12 //dont miss
+ parry_time_active = 4
+ parry_time_perfect = 2
+ parry_time_perfect_leeway = 2
+ parry_failed_stagger_duration = 3 SECONDS
+ parry_failed_clickcd_duration = 3 SECONDS
+ parry_time_windup = 0
+ parry_time_spindown = 0
+ parry_imperfect_falloff_percent = 0
+ parry_efficiency_to_counterattack = 100
+ parry_efficiency_considered_successful = 120
+ parry_efficiency_perfect = 120
+ parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 4)
+
+//unique hammers
+/obj/item/melee/smith/hammer/toolbox
+ name = "toolbox hammer"
+ desc = "A metal filled toolbox on a stick. Useable as a really shitty hammer."
+ w_class = WEIGHT_CLASS_BULKY
+ icon_state = "toolbox"
+ overlay_state = "hammerhandle"
+ qualitymod = -2
+
+/obj/item/melee/smith/hammer/narsie
+ name = "runemetal hammer"
+ custom_materials = list(/datum/material/runedmetal = 12000)
+ desc = "A metal hammer inscribed with geometeric runes."
+ qualitymod = 1
+
+/obj/item/melee/smith/hammer/narsie/attack(mob/living/target, mob/living/carbon/human/user)
+ if(!iscultist(user))
+ user.DefaultCombatKnockdown(100)
+ user.dropItemToGround(src, TRUE)
+ user.visible_message("A powerful force shoves [user] away from [target]!", \
+ "\"You shouldn't be touching tools that aren't yours.\"")
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.apply_damage(rand(force/2, force), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+ else
+ user.adjustBruteLoss(rand(force/2,force))
+ return
+ ..()
+
+/obj/item/melee/smith/hammer/ratvar
+ name = "brass hammer"
+ custom_materials = list(/datum/material/bronze = 12000)
+ desc = "A brass hammer inscribed with... writing? You can't read it."
+ qualitymod = 1
+
+/obj/item/melee/smith/hammer/ratvar/attack(mob/living/target, mob/living/carbon/human/user)
+ if(!is_servant_of_ratvar(user))
+ user.DefaultCombatKnockdown(100)
+ user.dropItemToGround(src, TRUE)
+ user.visible_message("A powerful force shoves [user] away from [target]!", "\"You shouldn't be touching tools that aren't yours.\"")
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.apply_damage(rand(force/2, force), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+ else
+ user.adjustBruteLoss(rand(force/2,force))
+ return
+ ..()
+
+/obj/item/melee/smith/hammer/debug
+ name = "debugging hammer"
+ desc = "A DEBUGGING HAMMER!! EPIC!!."
+ qualitymod = 10
diff --git a/code/modules/smithing/furnace.dm b/code/modules/smithing/furnace.dm
new file mode 100644
index 0000000000..ee1d6a1b93
--- /dev/null
+++ b/code/modules/smithing/furnace.dm
@@ -0,0 +1,75 @@
+/obj/structure/furnace
+ name = "furnace"
+ desc = "A furnace."
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "furnace0"
+ density = TRUE
+ anchored = TRUE
+ var/debug = FALSE //debugging only
+ var/working = TRUE
+ var/fueluse = 1
+
+
+/obj/structure/furnace/Initialize()
+ ..()
+ create_reagents(250, TRANSPARENT)
+ START_PROCESSING(SSobj, src)
+
+/obj/structure/furnace/Destroy()
+ ..()
+ STOP_PROCESSING(SSobj, src)
+
+/obj/structure/furnace/process()
+ if(debug)
+ reagents.add_reagent(/datum/reagent/fuel, 1)
+ return TRUE
+ if(reagents.remove_reagent(/datum/reagent/fuel, fueluse))
+ working = TRUE
+ if(icon_state == "furnace0")
+ icon_state = "furnace1"
+ else
+ working = FALSE
+ icon_state = "furnace0"
+
+/obj/structure/furnace/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/ingot))
+ var/obj/item/ingot/notsword = I
+ if(working)
+ to_chat(user, "You heat the [notsword] in the [src].")
+ notsword.workability = "shapeable"
+ else
+ to_chat(user, "The furnace isn't working!.")
+ else
+ ..()
+
+/obj/structure/furnace/wrench_act(mob/living/user, obj/item/I)
+ ..()
+ default_unfasten_wrench(user, I, 5)
+ return TRUE
+
+/obj/structure/furnace/attackby(obj/item/W, mob/user, params)
+ if(W.reagents)
+ W.reagents.trans_to(src, 250)
+ else
+ return ..()
+
+/obj/structure/furnace/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
+ to_chat(user, "You start furiously plunging [name].")
+ if(do_after(user, 30, target = src))
+ to_chat(user, "You finish plunging the [name].")
+ reagents.reaction(get_turf(src), TOUCH) //splash on the floor
+ reagents.clear_reagents()
+
+/obj/structure/furnace/infinite
+ name = "fuelless furnace"
+ debug = TRUE
+ icon_state = "ratfurnace"
+
+
+/obj/structure/furnace/infinite/ratvar
+ name = "brass furnace"
+ desc = "A brass furnace. Powered by... something, but seems otherwise safe." //todo:sprites they're safe for noncultists because you're just putting ingots in them. also there';s a reason to steal them ig
+
+/obj/structure/furnace/infinite/narsie
+ name = "rune furnace"
+ desc = "A runed furnace. Powered by... something, but seems otherwise safe."
diff --git a/code/modules/smithing/smithed_items.dm b/code/modules/smithing/smithed_items.dm
new file mode 100644
index 0000000000..df30a01f8c
--- /dev/null
+++ b/code/modules/smithing/smithed_items.dm
@@ -0,0 +1,420 @@
+/obj/item/basaltblock
+ name = "basalt block"
+ desc = "A block of basalt."
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "sandvilnoir"
+
+
+/obj/item/smithing
+ name = "base class /obj/item/smithing"
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "unfinished"
+ material_flags = MATERIAL_COLOR | MATERIAL_ADD_PREFIX
+ var/quality = 0 //quality. Changed by the smithing process.
+ var/obj/item/finishingitem = /obj/item/stick //What this item needs to be hit by to create finalitem
+ var/obj/item/finalitem
+ var/artifact = FALSE
+
+/obj/item/ingot
+ name = "ingot"
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "ingot"
+ material_flags = MATERIAL_COLOR | MATERIAL_ADD_PREFIX
+ var/workability = 0
+
+
+/obj/item/ingot/on_attack_hand(mob/user)
+ var/mob/living/carbon/human/H
+ if(workability != "shapeable")
+ return ..()
+ var/prot = 0
+ if(ishuman(user))
+ H = user
+ if(H.gloves)
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.max_heat_protection_temperature)
+ prot = (G.max_heat_protection_temperature > 360)
+ else
+ prot = 1
+ if(prot > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS))
+ to_chat(user, "You pick up the [src].")
+ return ..()
+ else
+ to_chat(user, "You try to move the [src], but you burn your hand on it!")
+ if(H)
+ var/obj/item/bodypart/affecting = H.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
+ if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage
+ H.update_damage_overlays()
+
+/obj/item/ingot/iron
+ custom_materials = list(/datum/material/iron=12000)
+
+/obj/item/ingot/diamond
+ custom_materials = list(/datum/material/diamond=12000) //yeah ok
+
+/obj/item/ingot/uranium
+ custom_materials = list(/datum/material/uranium=12000)
+
+/obj/item/ingot/plasma
+ custom_materials = list(/datum/material/plasma=12000)//yeah ok
+
+/obj/item/ingot/gold
+ custom_materials = list(/datum/material/gold=12000)
+
+/obj/item/ingot/silver
+ custom_materials = list(/datum/material/silver=12000)
+
+/obj/item/ingot/bananium
+ custom_materials = list(/datum/material/bananium=12000)
+
+/obj/item/ingot/titanium
+ custom_materials = list(/datum/material/titanium=12000)
+
+/obj/item/ingot/adamantine
+ custom_materials = list(/datum/material/adamantine=12000)
+
+/obj/item/ingot/cult
+ custom_materials = list(/datum/material/runedmetal=12000)
+
+/obj/item/ingot/bronze
+ custom_materials = list(/datum/material/bronze=12000)
+
+/obj/item/ingot/bronze/ratvar
+ material_flags = MATERIAL_COLOR
+ name = "brass ingnot"
+ desc = "On closer inspection, what appears to be wholly-unsuitable-for-smithing brass is actually more structurally stable bronze. Ratvar must have transformed the brass into bronze. Somehow."
+
+
+/obj/item/smithing/attackby(obj/item/I, mob/user)
+ if(istype(I, finishingitem))
+ qdel(I)
+ startfinish()
+ else
+ return ..()
+
+/obj/item/smithing/proc/startfinish()
+ dofinish()
+
+/obj/item/smithing/proc/dofinish()
+ var/qualname
+ switch(quality)
+ if(-1000 to -5)
+ qualname = "awful"
+ if(-1000 to -2)
+ qualname = "shoddy"
+ if(-1000 to -1)
+ qualname = "poor"
+ if(-1 to 1)
+ qualname = "normal"
+ if(10 to INFINITY)
+ qualname = "legendary"
+ if(7.5 to 10)
+ qualname = "masterwork"
+ if(5.5 to 7.5)
+ qualname = "excellent"
+ if(3.5 to 5.5)
+ qualname = "good"
+ if(0 to 3.5)
+ qualname = "above-average"
+ var/datum/material/mat = custom_materials[1]
+ finalitem.set_custom_materials(custom_materials)
+ mat = mat.name
+ if(artifact)
+ dwarfyartifact(finalitem, mat)
+ else
+ finalitem.name = "[qualname] [mat] [initial(finalitem.name)]"
+ finalitem.desc = "A [qualname] [initial(finalitem.name)]. Its quality is [quality]."
+ finalitem.forceMove(get_turf(src))
+ qdel(src)
+
+
+/obj/item/smithing/proc/dwarfyartifact(var/obj/item/finalitem, var/mat)
+ var/finaldesc = "A [initial(finalitem.name)] made of [mat], all craftsmanship is of the highest quality. It "
+ switch(pick(1,2,3,4,5))
+ if(1)
+ finaldesc += "is encrusted with [pick("","synthetic ","multi-faceted ","magical ","sparkling ") + pick("rubies","emeralds","jade","opals","lapiz lazuli")]."
+ if(2)
+ finaldesc += "is laced with studs of [pick("gold","silver","aluminium","titanium")]."
+ if(3)
+ finaldesc += "is encircled with bands of [pick("durasteel","metallic hydrogen","ferritic-alloy","plasteel","duranium")]."
+ if(4)
+ finaldesc += "menaces with spikes of [pick("ytterbium","uranium","white pearl","black steel")]."
+ if(5)
+ finaldesc += "is encrusted with [pick("","synthetic ","multi-faceted ","magical ","sparkling ") + pick("rubies","emeralds","jade","opals","lapis lazuli")],laced with studs of [pick("gold","silver","aluminium","titanium")], encircled with bands of [pick("durasteel","metallic hydrogen","ferritic-alloy","plasteel","duranium")] and menaces with spikes of [pick("ytterbium","uranium","white pearl","black steel")]."
+ finalitem.desc = finaldesc
+ finalitem.name = pick("Delersibnir", "Nekolangrir", "Zanoreshik","Öntakrítin", "Nogzatan", "Vunomam", "Nazushagsaldôbar", "Sergeb", "Zafaldastot", "Vudnis", "Dostust", "Shotom", "Mugshith", "Angzak", "Oltud", "Deleratîs", "Nökornomal") //one of these is literally BLOOD POOL CREATE.iirc its Nazushagsaldôbar.
+
+/obj/item/smithing/hammerhead
+ name = "smithed hammer head"
+ finalitem = /obj/item/melee/smith/hammer
+ icon_state = "hammer"
+
+/obj/item/smithing/hammerhead/startfinish()
+ var/obj/item/melee/smith/hammer/finalforreal = new /obj/item/melee/smith/hammer(src)
+ finalforreal.force += quality/2
+ finalforreal.qualitymod = quality/4
+ finalitem = finalforreal
+ ..()
+
+
+
+/obj/item/smithing/scytheblade
+ name = "smithed scythe head"
+ finalitem = /obj/item/scythe/smithed
+ icon_state = "scythe"
+
+/obj/item/smithing/scytheblade/startfinish()
+ finalitem = new /obj/item/scythe/smithed(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/shovelhead
+ name = "smithed shovel head"
+ finalitem = /obj/item/shovel/smithed
+ icon_state = "shovel"
+
+/obj/item/smithing/shovelhead/startfinish()
+ finalitem = new /obj/item/shovel/smithed(src)
+ finalitem.force += quality/2
+ if(quality > 0)
+ finalitem.toolspeed = max(0.05,(1-(quality/10)))
+ else
+ finalitem.toolspeed *= max(1, (quality * -1))
+ ..()
+
+/obj/item/smithing/cogheadclubhead
+ name = "smithed coghead club head"
+ finalitem = /obj/item/melee/smith/cogheadclub
+ icon_state = "coghead"
+
+/obj/item/smithing/cogheadclubhead/startfinish()
+ finalitem = new /obj/item/melee/smith/cogheadclub(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/javelinhead
+ name = "smithed javelin head"
+ finalitem = /obj/item/melee/smith/twohand/javelin
+ icon_state = "javelin"
+
+/obj/item/smithing/javelinhead/startfinish()
+ var/obj/item/melee/smith/twohand/javelin/finalforreal = new /obj/item/melee/smith/twohand/javelin(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalforreal.throwforce = finalforreal.force*2
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/pikehead
+ name = "smithed pike head"
+ finalitem = /obj/item/melee/smith/twohand/pike
+ icon_state = "pike"
+
+/obj/item/smithing/pikehead/startfinish()
+ var/obj/item/melee/smith/twohand/pike/finalforreal = new /obj/item/melee/smith/twohand/pike(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalforreal.throwforce = finalforreal.force/10 //its a pike not a javelin
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/pickaxehead
+ name = "smithed pickaxe head"
+ finalitem = /obj/item/pickaxe/smithed
+ icon_state = "pickaxe"
+
+/obj/item/smithing/pickaxehead/startfinish()
+ var/obj/item/pickaxe/smithed/finalforreal = new /obj/item/pickaxe/smithed(src)
+ finalforreal.force += quality/2
+ if(quality > 0)
+ finalforreal.toolspeed = max(0.05,(1-(quality/10)))
+ else
+ finalforreal.toolspeed *= max(1, (quality * -1))
+ switch(quality)
+ if(10 to INFINITY)
+ finalforreal.digrange = 4
+ if(5 to 9)
+ finalforreal.digrange = 3
+ if(3,4)
+ finalforreal.digrange = 2
+ else
+ finalforreal.digrange = 1
+ finalitem = finalforreal
+ ..()
+
+
+/obj/item/smithing/prospectingpickhead
+ name = "smithed prospector's pickaxe head"
+ finalitem = /obj/item/mining_scanner/prospector
+ icon_state = "minipick"
+
+/obj/item/smithing/prospectingpickhead/startfinish()
+ var/obj/item/mining_scanner/prospector/finalforreal = new /obj/item/mining_scanner/prospector(src)
+ finalforreal.range = 2 + quality
+ if(quality)
+ finalforreal.cooldown = 100/quality
+ finalitem = finalforreal
+ ..()
+
+
+/obj/item/smithing/shortswordblade
+ name = "smithed gladius blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/shortsword
+ icon_state = "gladius"
+
+/obj/item/smithing/shortswordblade/startfinish()
+ finalitem = new /obj/item/melee/smith/shortsword(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/scimitarblade
+ name = "smithed scimitar blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/shortsword/scimitar
+ icon_state = "scimitar"
+
+/obj/item/smithing/scimitarblade/startfinish()
+ finalitem = new /obj/item/melee/smith/shortsword/scimitar(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/wakiblade
+ name = "smithed wakizashi blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/wakizashi
+ icon_state = "waki"
+
+/obj/item/smithing/wakiblade/startfinish()
+ finalitem = new /obj/item/melee/smith/wakizashi(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/sabreblade
+ name = "smithed sabre blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/sabre
+ icon_state = "sabre"
+
+/obj/item/smithing/sabreblade/startfinish()
+ finalitem = new /obj/item/melee/smith/sabre(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/rapierblade
+ name = "smithed rapier blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/sabre/rapier
+ icon_state = "rapier"
+
+/obj/item/smithing/rapierblade/startfinish()
+ finalitem = new /obj/item/melee/smith/sabre/rapier(src)
+ finalitem.force += quality
+ ..()
+
+/obj/item/smithing/knifeblade
+ name = "smithed knife blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/kitchen/knife
+ icon_state = "dagger"
+
+/obj/item/smithing/knifeblade/startfinish()
+ finalitem = new /obj/item/kitchen/knife(src)
+ finalitem.force = 4 + quality/2
+ finalitem.icon = 'icons/obj/smith.dmi'
+ finalitem.icon_state = "dagger"
+ finalitem.name = "dagger"
+ finalitem.desc = "A dagger."
+ var/mutable_appearance/overlay = mutable_appearance('icons/obj/smith.dmi', "daggerhilt")
+ overlay.appearance_flags = RESET_COLOR
+ finalitem.add_overlay(overlay)
+ if(finalitem.force < 0)
+ finalitem.force = 0
+ finalitem.material_flags = MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
+ ..()
+
+/obj/item/smithing/broadblade
+ name = "smithed broadsword blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/twohand/broadsword
+ icon_state = "broadsword"
+
+/obj/item/smithing/broadblade/startfinish()
+ var/obj/item/melee/smith/twohand/broadsword/finalforreal = new /obj/item/melee/smith/twohand/broadsword(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/zweiblade
+ name = "smithed zweihander blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/twohand/zweihander
+ icon_state = "zwei"
+
+/obj/item/smithing/zweiblade/startfinish()
+ var/obj/item/melee/smith/twohand/zweihander/finalforreal = new /obj/item/melee/smith/twohand/zweihander(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/halberdhead
+ name = "smithed halberd head"
+ finalitem = /obj/item/melee/smith/twohand/halberd
+ icon_state = "halberd"
+
+/obj/item/smithing/halberdhead/startfinish()
+ var/obj/item/melee/smith/twohand/halberd/finalforreal = new /obj/item/melee/smith/twohand/halberd(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.throwforce = finalforreal.force/3
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/glaivehead
+ name = "smithed glaive head"
+ finalitem = /obj/item/melee/smith/twohand/glaive
+ icon_state = "glaive"
+
+/obj/item/smithing/glaive/startfinish()
+ var/obj/item/melee/smith/twohand/glaive/finalforreal = new /obj/item/melee/smith/twohand/glaive(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.throwforce = finalforreal.force
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalitem = finalforreal
+ ..()
+
+/obj/item/smithing/katanablade
+ name = "smithed katana blade"
+ finishingitem = /obj/item/swordhandle
+ finalitem = /obj/item/melee/smith/twohand/katana
+ icon_state = "katana"
+
+
+/obj/item/smithing/katanablade/startfinish()
+ var/obj/item/melee/smith/twohand/katana/finalforreal = new /obj/item/melee/smith/twohand/katana(src)
+ finalforreal.force += quality
+ finalforreal.wield_force = finalforreal.force*finalforreal.wielded_mult
+ finalforreal.AddComponent(/datum/component/two_handed, force_unwielded=finalforreal.force, force_wielded=finalforreal.wield_force, icon_wielded="[icon_state]")
+ finalitem = finalforreal
+ ..()
+
+/obj/item/stick
+ name = "wooden rod"
+ desc = "It's a rod, suitable for use of a handle of a tool. Also could serve as a weapon, in a pinch."
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "stick"
+ force = 7
+
+/obj/item/swordhandle
+ name = "sword handle"
+ desc = "It's a crudlely shaped wooden sword hilt."
+ icon = 'icons/obj/smith.dmi'
+ icon_state = "shorthilt"
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index 2eb64ca3be..b3bce1ae23 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -172,7 +172,7 @@
maxHealth = 75 //Take brute damage instead
var/chattering = FALSE
var/phomeme_type = "sans"
- var/list/phomeme_types = list(/datum/accent/bone/sans, /datum/accent/bone/papyrus)
+ var/list/phomeme_types = list(/datum/accent/span/sans, /datum/accent/span/papyrus)
/obj/item/organ/tongue/bone/Initialize()
. = ..()
@@ -206,7 +206,7 @@
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
- initial_accents = list(/datum/accent/robot)
+ initial_accents = list(/datum/accent/span/robot)
taste_sensitivity = 25 // not as good as an organic tongue
maxHealth = 100 //RoboTongue!
var/electronics_magic = TRUE
diff --git a/html/changelogs/AutoChangeLog-pr-13244.yml b/html/changelogs/AutoChangeLog-pr-13244.yml
new file mode 100644
index 0000000000..305d5f3584
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13244.yml
@@ -0,0 +1,5 @@
+author: "lolman360, NecromancerAnne"
+delete-after: True
+changes:
+ - rscadd: "The ancient art of blacksmithing, now in pixels."
+ - imageadd: "cool swords and shit (thanks anne)"
diff --git a/html/changelogs/AutoChangeLog-pr-13339.yml b/html/changelogs/AutoChangeLog-pr-13339.yml
new file mode 100644
index 0000000000..360b528911
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13339.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - rscdel: "Dynamic no longer pushes events."
diff --git a/html/changelogs/AutoChangeLog-pr-13341.yml b/html/changelogs/AutoChangeLog-pr-13341.yml
new file mode 100644
index 0000000000..ff06d19bb9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13341.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - balance: "Made spontaneous brain trauma a good deal less annoying."
diff --git a/html/changelogs/AutoChangeLog-pr-13348.yml b/html/changelogs/AutoChangeLog-pr-13348.yml
new file mode 100644
index 0000000000..f804025be6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13348.yml
@@ -0,0 +1,4 @@
+author: "raspy-on-osu"
+delete-after: True
+changes:
+ - tweak: "thermomachine examine text"
diff --git a/icons/effects/mouse_pointers/mute_target.dmi b/icons/effects/mouse_pointers/mute_target.dmi
new file mode 100644
index 0000000000..8e3c278d3b
Binary files /dev/null and b/icons/effects/mouse_pointers/mute_target.dmi differ
diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi
index 0a130f006e..d083206454 100644
Binary files a/icons/mob/actions/actions_ecult.dmi and b/icons/mob/actions/actions_ecult.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 315ca5e924..0a82845910 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 6af883f2e8..abfbb18f84 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi
index c106bd12fc..1a98872463 100644
Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ
diff --git a/icons/obj/eldritch.dmi b/icons/obj/eldritch.dmi
index 50c2913708..294deda628 100644
Binary files a/icons/obj/eldritch.dmi and b/icons/obj/eldritch.dmi differ
diff --git a/icons/obj/smith.dmi b/icons/obj/smith.dmi
new file mode 100644
index 0000000000..a40b9a2b19
Binary files /dev/null and b/icons/obj/smith.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 7c8fbc5dc3..fc348bd5fe 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -648,6 +648,7 @@
#include "code\datums\skills\_skill.dm"
#include "code\datums\skills\_skill_holder.dm"
#include "code\datums\skills\_skill_modifier.dm"
+#include "code\datums\skills\blacksmithing.dm"
#include "code\datums\skills\engineering.dm"
#include "code\datums\skills\medical.dm"
#include "code\datums\skills\modifiers\job.dm"
@@ -737,7 +738,6 @@
#include "code\game\gamemodes\devil\devil agent\devil_agent.dm"
#include "code\game\gamemodes\dynamic\dynamic.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets.dm"
-#include "code\game\gamemodes\dynamic\dynamic_rulesets_events.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm"
@@ -3307,6 +3307,10 @@
#include "code\modules\shuttle\shuttle_creation\shuttle_creator_eye.dm"
#include "code\modules\shuttle\shuttle_creation\shuttle_creator_overlay.dm"
#include "code\modules\shuttle\shuttle_creation\shuttle_upgrades.dm"
+#include "code\modules\smithing\anvil.dm"
+#include "code\modules\smithing\finished_items.dm"
+#include "code\modules\smithing\furnace.dm"
+#include "code\modules\smithing\smithed_items.dm"
#include "code\modules\spells\spell.dm"
#include "code\modules\spells\spell_types\aimed.dm"
#include "code\modules\spells\spell_types\area_teleport.dm"