diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index db9a620ad6..375b841141 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -44116,20 +44116,20 @@
/obj/structure/window/reinforced{
dir = 4
},
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "N2O to Pure"
- },
/obj/machinery/atmospherics/pipe/simple/green/visible,
/obj/effect/turf_decal/tile/red{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel/cafeteria,
/area/engine/atmos)
"bIZ" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
-/obj/machinery/atmospherics/pipe/simple/yellow/visible{
- dir = 4
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "N2O to Pure"
},
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
@@ -47280,10 +47280,6 @@
/area/engine/atmos)
"bPw" = (
/obj/machinery/atmospherics/pipe/simple/green/visible,
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "Plasma to Pure"
- },
/obj/structure/window/reinforced{
dir = 4
},
@@ -47301,6 +47297,9 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/engine/atmos)
"bPx" = (
@@ -49746,10 +49745,6 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"bUH" = (
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "CO2 to Pure"
- },
/obj/machinery/atmospherics/pipe/simple/green/visible,
/obj/structure/window/reinforced{
dir = 4
@@ -49768,6 +49763,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
"bUI" = (
@@ -53170,13 +53168,10 @@
name = "Inner Pipe Access";
req_access_txt = "24"
},
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 1;
- name = "O2 to Pure"
- },
/obj/machinery/atmospherics/pipe/simple/green/visible{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel/dark,
/area/engine/atmos)
"cbl" = (
@@ -81712,6 +81707,14 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plating,
/area/crew_quarters/cryopod)
+"eJq" = (
+/obj/machinery/atmospherics/pipe/simple/cyan/visible,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "CO2 to Pure"
+ },
+/turf/open/floor/plasteel/dark,
+/area/engine/atmos)
"eQf" = (
/obj/machinery/computer/shuttle/mining/common{
dir = 1
@@ -82112,6 +82115,13 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"kJW" = (
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 1;
+ name = "O2 to Pure"
+ },
+/turf/open/floor/plasteel/dark,
+/area/engine/atmos)
"kOt" = (
/obj/item/multitool,
/obj/item/screwdriver,
@@ -82335,6 +82345,14 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/port)
+"njd" = (
+/obj/machinery/atmospherics/pipe/simple/cyan/visible,
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Plasma to Pure"
+ },
+/turf/open/floor/plasteel/dark,
+/area/engine/atmos)
"nnK" = (
/obj/item/stack/sheet/glass/fifty,
/obj/item/paper_bin,
@@ -126382,7 +126400,7 @@ dDm
bIS
bZK
cbk
-ccP
+kJW
ceh
cfx
bAR
@@ -127657,11 +127675,11 @@ bIZ
bKG
bMl
dhj
-bIZ
+njd
bKG
bMl
bKG
-bIZ
+eJq
bKG
bMl
bYB
diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm
index 128c9f1938..3210341cc3 100644
--- a/code/__DEFINES/dcs/flags.dm
+++ b/code/__DEFINES/dcs/flags.dm
@@ -39,3 +39,17 @@
//Ouch my toes!
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
+
+#define SPELL_SKIP_ALL_REQS (1<<0)
+#define SPELL_SKIP_CENTCOM (1<<1)
+#define SPELL_SKIP_STAT (1<<2)
+#define SPELL_SKIP_CLOTHES (1<<3)
+#define SPELL_SKIP_ANTIMAGIC (1<<4)
+#define SPELL_SKIP_VOCAL (1<<5)
+#define SPELL_SKIP_MOBTYPE (1<<6)
+#define SPELL_WIZARD_HAT (1<<7)
+#define SPELL_WIZARD_ROBE (1<<8)
+#define SPELL_CULT_HELMET (1<<9)
+#define SPELL_CULT_ARMOR (1<<10)
+#define SPELL_WIZARD_GARB (SPELL_WIZARD_HAT|SPELL_WIZARD_ROBE)
+#define SPELL_CULT_GARB (SPELL_CULT_HELMET|SPELL_CULT_ARMOR)
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index a088b0fc57..1ef8b9bb66 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -179,6 +179,8 @@
// #define SPEECH_FORCED 7
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
+#define COMSIG_MOB_SPELL_CAST_CHECK "mob_spell_cast_check" //called from base of /obj/effect/proc_holder/spell/cast_check(): (spell)
+
// /mob/living signals
#define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 19e418579e..74df2bf9a1 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -659,7 +659,7 @@
return FALSE
var/obj/effect/proc_holder/spell/S = target
if(owner)
- return S.can_cast(owner)
+ return S.can_cast(owner, FALSE, TRUE)
return FALSE
/datum/action/spell_action/alien
diff --git a/code/datums/elements/spellcasting.dm b/code/datums/elements/spellcasting.dm
new file mode 100644
index 0000000000..b325fd3a3a
--- /dev/null
+++ b/code/datums/elements/spellcasting.dm
@@ -0,0 +1,37 @@
+/datum/element/spellcasting //allows to cast certain spells or skip requirements.
+ element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
+ id_arg_index = 2
+ var/cast_flags
+ var/cast_slots
+ var/list/users_by_item = list()
+
+/datum/element/spellcasting/Attach(datum/target, _flags, _slots)
+ . = ..()
+ if(isitem(target))
+ RegisterSignal(target, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
+ RegisterSignal(target, COMSIG_ITEM_DROPPED, .proc/on_drop)
+ else if(ismob(target))
+ RegisterSignal(target, COMSIG_MOB_SPELL_CAST_CHECK, .proc/on_cast)
+ else
+ return ELEMENT_INCOMPATIBLE
+ cast_flags = _flags
+ cast_slots = _slots
+
+/datum/element/spellcasting/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_MOB_SPELL_CAST_CHECK))
+ if(users_by_item[target])
+ var/mob/user = users_by_item[target]
+ UnregisterSignal(user, COMSIG_MOB_SPELL_CAST_CHECK)
+
+/datum/element/spellcasting/proc/on_equip(datum/source, mob/equipper, slot)
+ if(slot in cast_slots)
+ RegisterSignal(equipper, COMSIG_MOB_SPELL_CAST_CHECK, .proc/on_cast)
+ users_by_item[source] = equipper
+
+/datum/element/spellcasting/proc/on_drop(datum/source, mob/user)
+ UnregisterSignal(user, COMSIG_MOB_SPELL_CAST_CHECK)
+ users_by_item -= source
+
+/datum/element/spellcasting/proc/on_cast(mob/caster, obj/effect/proc_holder/spell)
+ return cast_flags
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index f036b25518..e933e02c15 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -41,7 +41,7 @@
desc = "You can breathe fire at a target."
school = "evocation"
charge_max = 600
- clothes_req = FALSE
+ clothes_req = NONE
range = 20
base_icon_state = "fireball"
action_icon_state = "fireball0"
@@ -121,7 +121,7 @@
name = "Convoke Void" //magic the gathering joke here
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
school = "evocation"
- clothes_req = FALSE
+ clothes_req = NONE
charge_max = 600
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
invocation_type = "shout"
@@ -155,7 +155,7 @@
dropmessage = "You let the electricity from your hand dissipate."
hand_path = /obj/item/melee/touch_attack/shock
charge_max = 400
- clothes_req = FALSE
+ clothes_req = NONE
action_icon_state = "zap"
/obj/item/melee/touch_attack/shock
@@ -211,7 +211,7 @@
name = "Remember the Scent"
desc = "Get a scent off of the item you're currently holding to track it. With an empty hand, you'll track the scent you've remembered."
charge_max = 100
- clothes_req = FALSE
+ clothes_req = NONE
range = -1
include_user = TRUE
action_icon_state = "nose"
@@ -289,8 +289,7 @@
/obj/effect/proc_holder/spell/self/self_amputation
name = "Drop a limb"
desc = "Concentrate to make a random limb pop right off your body."
- clothes_req = FALSE
- human_req = FALSE
+ clothes_req = NONE
charge_max = 100
action_icon_state = "autotomy"
@@ -327,8 +326,7 @@
/obj/effect/proc_holder/spell/self/lay_genetic_web
name = "Lay Web"
desc = "Drops a web. Only you will be able to traverse your web easily, making it pretty good for keeping you safe."
- clothes_req = FALSE
- human_req = FALSE
+ clothes_req = NONE
charge_max = 4 SECONDS //the same time to lay a web
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "lay_web"
@@ -369,8 +367,7 @@
/obj/effect/proc_holder/spell/self/tongue_spike
name = "Launch spike"
desc = "Shoot your tongue out in the direction you're facing, embedding it and dealing damage until they remove it."
- clothes_req = FALSE
- human_req = TRUE
+ clothes_req = NONE
charge_max = 100
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "spike"
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index de57bf0402..b8a5e72d55 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -511,7 +511,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
drafted_rules -= starting_rule
starting_rule.trim_candidates()
- starting_rule.scale_up(extra_rulesets_amount, threat)
+ starting_rule.scale_up(extra_rulesets_amount, threat_level)
if (starting_rule.pre_execute())
log_threat("[starting_rule.ruletype] - [starting_rule.name] [starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE)
if(starting_rule.flags & HIGHLANDER_RULESET)
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index f6755057e2..cec6f31e99 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -241,5 +241,5 @@
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
- flags = TRAITOR_RULESET
+ flags = TRAITOR_RULESET | MINOR_RULESET
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 2)
diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
index 71eb7ec533..35d5a04488 100644
--- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm
+++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
@@ -53,6 +53,8 @@ Property weights are:
var/turf/T = get_turf(H)
if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction))
threat += H.threat()
+ for(var/obj/item/phylactery/P in GLOB.poi_list)
+ threat += 25 // can't be giving them too much of a break
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
if (M?.mind?.assigned_role && M.stat != DEAD)
var/datum/job/J = SSjob.GetJob(M.mind.assigned_role)
@@ -135,17 +137,19 @@ Property weights are:
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
rule.trim_candidates()
- var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
- /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
- pick this particular ruleset.
- Let's use a toy example: there's 60 threat level and 10 threat spent.
- We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
- Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
- When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
- is 2.26 times as likely to be picked, all other things considered.
- Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
- */
- var/threat_weight = 1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))
+ var/threat_weight = 1
+ if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
+ var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
+ /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
+ pick this particular ruleset.
+ Let's use a toy example: there's 60 threat level and 10 threat spent.
+ We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
+ Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
+ When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
+ is 2.26 times as likely to be picked, all other things considered.
+ Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
+ */
+ threat_weight = 1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
@@ -168,8 +172,10 @@ Property weights are:
rule.candidates = list(newPlayer)
rule.trim_candidates()
- var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
- var/threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
+ var/threat_weight = 1
+ if(!(rule.flags & MINOR_RULESET))
+ var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
+ threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
@@ -200,7 +206,7 @@ Property weights are:
weight = 1
event_frequency_lower = 2 MINUTES
event_frequency_upper = 10 MINUTES
- flags = WAROPS_ALWAYS_ALLOWED | FORCE_IF_WON
+ flags = WAROPS_ALWAYS_ALLOWED
min_players = 40
var/refund_cooldown = 0
@@ -245,7 +251,10 @@ Property weights are:
config_tag = "random"
weight = 1
desc = "No weighting at all; every ruleset has the same chance of happening. Cooldowns vary wildly. As random as it gets."
- forced_threat_level = 100
+
+/datum/dynamic_storyteller/random/on_start()
+ ..()
+ GLOB.dynamic_forced_threat_level = rand(0,100)
/datum/dynamic_storyteller/random/get_midround_cooldown()
return rand(GLOB.dynamic_midround_delay_min/2, GLOB.dynamic_midround_delay_max*2)
@@ -318,9 +327,10 @@ Property weights are:
property_weights = list("story_potential" = 2)
-/datum/dynamic_storyteller/story/do_process()
+/datum/dynamic_storyteller/story/calculate_threat()
var/current_time = (world.time / SSautotransfer.targettime)*180
- mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.5),0.1)
+ mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1)
+ ..()
/datum/dynamic_storyteller/classic
name = "Classic"
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index e1b0cbb661..a12847ccf7 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -113,24 +113,24 @@
desc = "Looks like some cables tied together. Could be used to tie something up."
icon_state = "cuff"
item_state = "coil"
- item_color = "red"
- color = "#ff0000"
+ color = "red"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
custom_materials = list(/datum/material/iron=150, /datum/material/glass=75)
breakouttime = 300 //Deciseconds = 30s
- cuffsound = 'sound/weapons/cablecuff.ogg'
-
-/obj/item/restraints/handcuffs/cable/Initialize(mapload, param_color)
- . = ..()
-
- var/list/cable_colors = GLOB.cable_colors
- item_color = param_color || item_color || pick(cable_colors)
- if(cable_colors[item_color])
- item_color = cable_colors[item_color]
- color = null
- add_atom_colour(item_color, FIXED_COLOUR_PRIORITY)
+ cuffsound = 'sound/weapons/cablecuff.ogg'
+/obj/item/restraints/handcuffs/cable/attack_self(mob/user)
+ to_chat(user, "You start unwinding the cable restraints back into coil")
+ if(!do_after(user, 25, TRUE, user))
+ return
+ qdel(src)
+ var/obj/item/stack/cable_coil/coil = new(get_turf(user))
+ coil.amount = 15
+ user.put_in_hands(coil)
+ coil.color = color
+ to_chat(user, "You unwind the cable restraints back into coil")
+
/obj/item/restraints/handcuffs/cable/red
item_color = "red"
color = "#ff0000"
@@ -162,6 +162,13 @@
/obj/item/restraints/handcuffs/cable/white
item_color = "white"
+/obj/item/restraints/handcuffs/cable/random
+
+/obj/item/restraints/handcuffs/cable/random/Initialize(mapload)
+ . = ..()
+ var/list/cable_colors = GLOB.cable_colors
+ color = pick(cable_colors)
+
/obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/rods))
diff --git a/code/game/objects/items/implants/implant_spell.dm b/code/game/objects/items/implants/implant_spell.dm
index 5db7dc761c..496638c51f 100644
--- a/code/game/objects/items/implants/implant_spell.dm
+++ b/code/game/objects/items/implants/implant_spell.dm
@@ -21,7 +21,7 @@
if (!spell)
return FALSE
if (autorobeless && spell.clothes_req)
- spell.clothes_req = FALSE
+ spell.clothes_req = NONE
target.AddSpell(spell)
return TRUE
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index 130bc55244..64a0026424 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -15,7 +15,7 @@
attack_verb = list("beaten")
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
- var/stamforce = 25
+ var/stamforce = 35
var/status = FALSE
var/knockdown = TRUE
var/obj/item/stock_parts/cell/cell
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index edeb74eeaf..148e5cfbd5 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -353,6 +353,11 @@
brightness_on = 0
actions_types = list()
+
+/obj/item/clothing/head/helmet/space/hardsuit/cult/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_CULT_HELMET, ITEM_SLOT_HEAD)
+
/obj/item/clothing/suit/space/hardsuit/cult
name = "\improper Nar'Sien hardened armor"
icon_state = "cult_armor"
@@ -363,6 +368,10 @@
armor = list("melee" = 70, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 40, "acid" = 75)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cult
+/obj/item/clothing/suit/space/hardsuit/cult/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_CULT_ARMOR, ITEM_SLOT_OCLOTHING)
+
/obj/item/sharpener/cult
name = "eldritch whetstone"
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index a99e3900b0..2d84ed7c22 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -117,7 +117,7 @@
tinfoil_check = FALSE
/obj/effect/proc_holder/spell/aoe_turf/revenant
- clothes_req = 0
+ clothes_req = NONE
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_background_icon_state = "bg_revenant"
panel = "Revenant Abilities (Locked)"
@@ -135,7 +135,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
-/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
+/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, silent = FALSE)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
diff --git a/code/modules/antagonists/santa/santa.dm b/code/modules/antagonists/santa/santa.dm
index bf42188cf6..f58a21ba42 100644
--- a/code/modules/antagonists/santa/santa.dm
+++ b/code/modules/antagonists/santa/santa.dm
@@ -18,7 +18,7 @@
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents)
var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new
- telespell.clothes_req = 0 //santa robes aren't actually magical.
+ telespell.clothes_req = NONE //santa robes aren't actually magical.
owner.AddSpell(telespell) //does the station have chimneys? WHO KNOWS!
/datum/antagonist/santa/proc/give_objective()
diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm
index 494a5208e7..2bcda1d400 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook.dm
@@ -104,7 +104,7 @@
dat += " Cooldown:[S.charge_max/10]"
dat += " Cost:[cost]
"
dat += "[S.desc][desc]
"
- dat += "[S.clothes_req?"Needs wizard garb":"Can be cast without wizard garb"]
"
+ dat += "[S.clothes_req & SPELL_WIZARD_GARB ? "Needs wizard garb" : "Can be cast without wizard garb"]
"
return dat
/datum/spellbook_entry/fireball
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index 39bb737f1b..f714a86f22 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -309,7 +309,7 @@
name = "Summon Servant"
desc = "This spell can be used to call your servant, whenever you need it."
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
invocation = "JE VES"
invocation_type = "whisper"
range = -1
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 1bad198c73..1f23569a9c 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -422,6 +422,10 @@
heat_protection = HEAD //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
+/obj/item/clothing/head/helmet/space/hardsuit/wizard/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD)
+
/obj/item/clothing/suit/space/hardsuit/wizard
icon_state = "hardsuit-wiz"
name = "gem-encrusted hardsuit"
@@ -436,9 +440,10 @@
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/wizard
mutantrace_variation = STYLE_DIGITIGRADE
-/obj/item/clothing/suit/space/hardsuit/wizard/Initialize()
+/obj/item/clothing/suit/space/hardsuit/wizard/ComponentInitialize()
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE)
+ AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING)
//Medical hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/medical
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 3731a1a35e..c3ddda2328 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -9,6 +9,12 @@
equip_delay_other = 50
resistance_flags = FIRE_PROOF | ACID_PROOF
dog_fashion = /datum/dog_fashion/head/blue_wizard
+ var/magic_flags = SPELL_WIZARD_HAT
+
+/obj/item/clothing/head/wizard/ComponentInitialize()
+ . = ..()
+ if(magic_flags)
+ AddElement(/datum/element/spellcasting, magic_flags, ITEM_SLOT_HEAD)
/obj/item/clothing/head/wizard/red
name = "red wizard hat"
@@ -36,7 +42,7 @@
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
- dog_fashion = /datum/dog_fashion/head/blue_wizard
+ magic_flags = NONE
/obj/item/clothing/head/wizard/marisa
name = "witch hat"
@@ -50,6 +56,7 @@
icon_state = "magus"
item_state = "magus"
dog_fashion = null
+ magic_flags = SPELL_WIZARD_HAT|SPELL_CULT_HELMET
/obj/item/clothing/head/wizard/santa
name = "Santa's hat"
@@ -72,6 +79,12 @@
strip_delay = 50
equip_delay_other = 50
resistance_flags = FIRE_PROOF | ACID_PROOF
+ var/magic_flags = SPELL_WIZARD_ROBE
+
+/obj/item/clothing/suit/wizrobe/ComponentInitialize()
+ . = ..()
+ if(magic_flags)
+ AddElement(/datum/element/spellcasting, magic_flags, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/suit/wizrobe/red
name = "red wizard robe"
@@ -102,13 +115,14 @@
desc = "A set of armored robes that seem to radiate a dark power."
icon_state = "magusblue"
item_state = "magusblue"
+ magic_flags = SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR
/obj/item/clothing/suit/wizrobe/magusred
name = "\improper Magus robe"
desc = "A set of armored robes that seem to radiate a dark power."
icon_state = "magusred"
item_state = "magusred"
-
+ magic_flags = SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR
/obj/item/clothing/suit/wizrobe/santa
name = "Santa's suit"
@@ -117,33 +131,27 @@
item_state = "santa"
/obj/item/clothing/suit/wizrobe/fake
- name = "wizard robe"
desc = "A rather dull blue robe meant to mimick real wizard robes."
icon_state = "wizard-fake"
- item_state = "wizrobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
+ magic_flags = NONE
/obj/item/clothing/head/wizard/marisa/fake
- name = "witch hat"
- desc = "Strange-looking hat-wear, makes you want to cast fireballs."
- icon_state = "marisa"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
+ magic_flags = NONE
/obj/item/clothing/suit/wizrobe/marisa/fake
- name = "witch robe"
- desc = "Magic is all about the spell power, ZE!"
- icon_state = "marisa"
- item_state = "marisarobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
+ magic_flags = NONE
/obj/item/clothing/suit/wizrobe/paper
name = "papier-mache robe" // no non-latin characters!
@@ -198,6 +206,10 @@
slowdown = 0
resistance_flags = FIRE_PROOF | ACID_PROOF
+/obj/item/clothing/suit/space/hardsuit/shielded/wizard/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD)
+
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard
name = "battlemage helmet"
desc = "A suitably impressive helmet.."
@@ -209,6 +221,10 @@
actions_types = null //No inbuilt light
resistance_flags = FIRE_PROOF | ACID_PROOF
+/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING)
+
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/attack_self(mob/user)
return
diff --git a/code/modules/events/wizard/aid.dm b/code/modules/events/wizard/aid.dm
index 8525674e07..5f49b48900 100644
--- a/code/modules/events/wizard/aid.dm
+++ b/code/modules/events/wizard/aid.dm
@@ -15,7 +15,7 @@
var/spell_improved = FALSE
for(var/obj/effect/proc_holder/spell/S in L.mind.spell_list)
if(S.clothes_req)
- S.clothes_req = 0
+ S.clothes_req = NONE
spell_improved = TRUE
if(spell_improved)
to_chat(L, "You suddenly feel like you never needed those garish robes in the first place...")
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index b3ec36e0bb..bf8aa888cc 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -301,6 +301,9 @@
rate = 0.04
glow_color = "#AAD84B"
+/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/S)
+ return -max(S.potency*(rate*0.2), 0.2)
+
/datum/plant_gene/trait/glow/white
name = "White Bioluminescence"
glow_color = "#FFFFFF"
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 0d6a6e64d7..22725248dc 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1555,7 +1555,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.adjustCloneLoss(10)
target.adjustBruteLoss(10)
-
+
else if(!(target.mobility_flags & MOBILITY_STAND))
target.forcesay(GLOB.hit_appends)
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 803af56dec..7c5f0f473a 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -146,5 +146,7 @@
if(transfer_name)
H.name = caster.name
- clothes_req = 0
- human_req = 0
+
+ clothes_req = NONE
+ mobs_whitelist = null
+ mobs_blacklist = null
diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm
index 67ec46cf2d..04d53e7d05 100644
--- a/code/modules/mob/living/simple_animal/friendly/gondola.dm
+++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm
@@ -33,6 +33,10 @@
if (!(istype(src, /mob/living/simple_animal/pet/gondola/gondolapod)))
CreateGondola()
+/mob/living/simple_animal/pet/gondola/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/spellcasting, SPELL_SKIP_VOCAL) // so they can cast spells despite being silent.
+
/mob/living/simple_animal/pet/gondola/proc/CreateGondola()
icon_state = null
icon_living = null
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 08bd1cedbc..83d27e7ea6 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -762,7 +762,7 @@ Difficulty: Very Hard
name = "Exit Possession"
desc = "Exits the body you are possessing."
charge_max = 60
- clothes_req = 0
+ clothes_req = NONE
invocation_type = "none"
max_targets = 1
range = -1
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index fb31e48d90..8c622c7f29 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -169,7 +169,7 @@
desc = "You will trigger a large amount of lights around you to flicker."
charge_max = 300
- clothes_req = 0
+ clothes_req = NONE
range = 14
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets,mob/user = usr)
@@ -185,7 +185,7 @@
message = "You glare your eyes."
charge_max = 600
- clothes_req = 0
+ clothes_req = NONE
range = 10
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets,mob/user = usr)
@@ -201,7 +201,7 @@
desc = "Toggle your nightvision mode."
charge_max = 10
- clothes_req = 0
+ clothes_req = NONE
message = "You toggle your night vision!"
range = -1
diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm
index 7265540679..15d641299d 100644
--- a/code/modules/mob/living/simple_animal/hostile/wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm
@@ -43,23 +43,23 @@
/mob/living/simple_animal/hostile/wizard/Initialize()
. = ..()
fireball = new /obj/effect/proc_holder/spell/aimed/fireball
- fireball.clothes_req = 0
- fireball.human_req = 0
- fireball.player_lock = 0
+ fireball.clothes_req = NONE
+ fireball.mobs_whitelist = null
+ fireball.player_lock = FALSE
AddSpell(fireball)
var/obj/item/implant/exile/I = new
I.implant(src, null, TRUE)
mm = new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
- mm.clothes_req = 0
- mm.human_req = 0
- mm.player_lock = 0
+ mm.clothes_req = NONE
+ mm.mobs_whitelist = null
+ mm.player_lock = FALSE
AddSpell(mm)
blink = new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
- blink.clothes_req = 0
- blink.human_req = 0
- blink.player_lock = 0
+ blink.clothes_req = NONE
+ blink.mobs_whitelist = null
+ blink.player_lock = FALSE
blink.outer_tele_radius = 3
AddSpell(blink)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 5225534cee..86c0aa253c 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -632,7 +632,7 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/mob/proc/add_spells_to_statpanel(list/spells)
for(var/obj/effect/proc_holder/spell/S in spells)
- if(S.can_be_cast_by(src))
+ if((!S.mobs_blacklist || !S.mobs_blacklist[src]) && (!S.mobs_whitelist || S.mobs_whitelist[src]))
switch(S.charge_type)
if("recharge")
statpanel("[S.panel]","[S.charge_counter/10.0]/[S.charge_max/10]",S)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 8d5de661ae..93f82991fd 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -196,7 +196,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/update_stored(length = 1, colorC = "red")
stored.amount = length
- stored.item_color = colorC
+ stored.color = colorC
stored.update_icon()
////////////////////////////////////////////
@@ -469,7 +469,6 @@ By design, d1 is the smallest direction and d2 is the highest
// Definitions
////////////////////////////////
-GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15)))
/obj/item/stack/cable_coil
name = "cable coil"
@@ -482,7 +481,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
max_amount = MAXCOIL
amount = MAXCOIL
merge_type = /obj/item/stack/cable_coil // This is here to let its children merge between themselves
- item_color = "red"
+ color = "red"
desc = "A coil of insulated power cable."
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
@@ -504,7 +503,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
var/cable_color = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white")
- item_color = cable_color
+ color = cable_color
update_icon()
/obj/item/stack/cable_coil/suicide_act(mob/user)
@@ -514,18 +513,11 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
return(OXYLOSS)
-/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null, param_color = null)
+/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null)
. = ..()
-
- var/list/cable_colors = GLOB.cable_colors
- item_color = param_color || item_color || pick(cable_colors)
- if(cable_colors[item_color])
- item_color = cable_colors[item_color]
-
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
update_icon()
- recipes = GLOB.cable_coil_recipes
///////////////////////////////////
// General procedures
@@ -541,7 +533,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
if(affecting && affecting.status == BODYPART_ROBOTIC)
if(user == H)
user.visible_message("[user] starts to fix some of the wires in [H]'s [affecting.name].", "You start fixing some of the wires in [H]'s [affecting.name].")
- if(!do_mob(user, H, 50))
+ if(!do_after(user, H, 50))
return
if(item_heal_robotic(H, user, 0, 15))
use(1)
@@ -553,8 +545,6 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/update_icon()
icon_state = "[initial(item_state)][amount < 3 ? amount : ""]"
name = "cable [amount < 3 ? "piece" : "coil"]"
- color = null
- add_atom_colour(item_color, FIXED_COLOUR_PRIORITY)
/obj/item/stack/cable_coil/attack_hand(mob/user)
. = ..()
@@ -562,9 +552,28 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
return
var/obj/item/stack/cable_coil/new_cable = ..()
if(istype(new_cable))
- new_cable.item_color = item_color
+ new_cable.color = color
new_cable.update_icon()
+/obj/item/stack/cable_coil/attack_self(mob/user)
+ if(!check_cable_amount(user))
+ return
+ to_chat(user, "You start making some cable restraints.")
+ if(do_after(user, 30, TRUE, user) && check_cable_amount(user))
+ amount -= 15
+ var/obj/item/restraints/handcuffs/cable/result = new(get_turf(user))
+ user.put_in_hands(result)
+ result.color = color
+ to_chat(user, "You make some restraints out of cable")
+ return
+ to_chat(user, "You fail to make cable restraints, you need to stand still while doing so.")
+
+/obj/item/stack/cable_coil/proc/check_cable_amount(user)
+ if(amount < 15) //We dont care about cyborgs here, so we dont use get_amount()
+ to_chat(user, "You dont have enough cable coil to make restraints out of them")
+ return FALSE
+ return TRUE
+
//add cables to the stack
/obj/item/stack/cable_coil/proc/give(extra)
if(amount + extra > max_amount)
@@ -581,7 +590,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/proc/get_new_cable(location)
var/path = /obj/structure/cable
- return new path(location, item_color)
+ return new path(location, color)
// called when cable_coil is clicked on a turf
/obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user, dirnew)
@@ -738,7 +747,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
C.d2 = nd2
//updates the stored cable coil
- C.update_stored(2, item_color)
+ C.update_stored(2, color)
C.add_fingerprint(user)
C.update_icon()
@@ -769,40 +778,36 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/////////////////////////////
/obj/item/stack/cable_coil/red
- item_color = "red"
- color = "#ff0000"
+ color = "red"
/obj/item/stack/cable_coil/yellow
- item_color = "yellow"
- color = "#ffff00"
+ color = "yellow"
/obj/item/stack/cable_coil/blue
- item_color = "blue"
- color = "#1919c8"
+ color = "blue"
/obj/item/stack/cable_coil/green
- item_color = "green"
- color = "#00aa00"
+ color = "green"
/obj/item/stack/cable_coil/pink
- item_color = "pink"
color = "#ff3ccd"
/obj/item/stack/cable_coil/orange
- item_color = "orange"
color = "#ff8000"
/obj/item/stack/cable_coil/cyan
- item_color = "cyan"
- color = "#00ffff"
+ color = "cyan"
/obj/item/stack/cable_coil/white
- item_color = "white"
+ color = "white"
/obj/item/stack/cable_coil/random
- item_color = null
color = "#ffffff"
+/obj/item/stack/cable_coil/random/Initialize(mapload, new_amount = null, param_color = null)
+ . = ..()
+ var/list/cable_colors = GLOB.cable_colors
+ color = pick(cable_colors)
/obj/item/stack/cable_coil/random/five
amount = 5
@@ -820,36 +825,33 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
update_icon()
/obj/item/stack/cable_coil/cut/red
- item_color = "red"
- color = "#ff0000"
+ color = "red"
/obj/item/stack/cable_coil/cut/yellow
- item_color = "yellow"
- color = "#ffff00"
+ color = "yellow"
/obj/item/stack/cable_coil/cut/blue
- item_color = "blue"
- color = "#1919c8"
+ color = "blue"
/obj/item/stack/cable_coil/cut/green
- item_color = "green"
- color = "#00aa00"
+ color = "green"
/obj/item/stack/cable_coil/cut/pink
- item_color = "pink"
color = "#ff3ccd"
-
/obj/item/stack/cable_coil/cut/orange
- item_color = "orange"
color = "#ff8000"
/obj/item/stack/cable_coil/cut/cyan
- item_color = "cyan"
- color = "#00ffff"
+ color = "cyan"
/obj/item/stack/cable_coil/cut/white
- item_color = "white"
+ color = "white"
/obj/item/stack/cable_coil/cut/random
- item_color = null
- color = "#ffffff"
\ No newline at end of file
+ color = "#ffffff"
+
+/obj/item/stack/cable_coil/cut/random/Initialize(mapload, new_amount = null, param_color = null)
+ . = ..()
+ var/list/cable_colors = GLOB.cable_colors
+ color = pick(cable_colors)
+
\ No newline at end of file
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index d06ad972e6..dd40648191 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -41,7 +41,7 @@
var/firing = FALSE
/// Used in gun-in-mouth execution/suicide and similar, while TRUE nothing should work on this like firing or modification and so on and so forth.
var/busy_action = FALSE
- var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
+ var/weapon_weight = WEAPON_LIGHT //used for inaccuracy and wielding requirements/penalties
var/spread = 0 //Spread induced by the gun itself.
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
diff --git a/code/modules/projectiles/guns/ballistic/magweapon.dm b/code/modules/projectiles/guns/ballistic/magweapon.dm
index f1d02e5cc2..e71f414bd8 100644
--- a/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -1,10 +1,10 @@
/obj/item/gun/ballistic/automatic/magrifle
- name = "\improper Magnetic Rifle"
+ name = "magnetic rifle"
desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
icon_state = "magrifle"
item_state = "arg"
force = 10
- slot_flags = NONE
+ slot_flags = ITEM_SLOT_BACK
mag_type = /obj/item/ammo_box/magazine/mmag
fire_sound = 'sound/weapons/magrifle.ogg'
can_suppress = FALSE
@@ -17,6 +17,7 @@
inaccuracy_modifier = 0
dualwield_spread_mult = 1.4
weapon_weight = WEAPON_MEDIUM
+ w_class = WEIGHT_CLASS_BULKY
var/obj/item/stock_parts/cell/cell
var/cell_type = /obj/item/stock_parts/cell/magnetic
@@ -63,12 +64,13 @@
spawnwithmagazine = FALSE
/obj/item/gun/ballistic/automatic/magrifle/hyperburst
- name = "\improper Hyper-Burst Rifle"
+ name = "\improper Hyper-Burst rifle"
desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
icon_state = "hyperburst"
- item_state = "arg"
+ slot_flags = NONE //too lazy for the sprites rn and it's pretty stronk anyway.
mag_type = /obj/item/ammo_box/magazine/mhyper
fire_sound = 'sound/weapons/magburst.ogg'
+ w_class = WEIGHT_CLASS_HUGE
fire_delay = 40
recoil = 2
weapon_weight = WEAPON_HEAVY
@@ -83,6 +85,8 @@
name = "magpistol"
desc = "A handgun utilizing maglev technologies to propel a ferromagnetic slug to extreme velocities."
icon_state = "magpistol"
+ w_class = WEIGHT_CLASS_NORMAL
+ slot_flags = ITEM_SLOT_BELT
fire_sound = 'sound/weapons/magpistol.ogg'
mag_type = /obj/item/ammo_box/magazine/mmag/small
fire_delay = 2
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 2fe9b326eb..bcd3a97ccd 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -24,6 +24,7 @@
icon_state = "toyburst"
obj_flags = NONE
fire_delay = 40
+ w_class = WEIGHT_CLASS_HUGE
weapon_weight = WEAPON_HEAVY
selfcharge = EGUN_SELFCHARGE
charge_delay = 2
@@ -56,12 +57,14 @@
/obj/item/gun/energy/laser/carbine
name = "laser carbine"
desc = "A ruggedized laser carbine featuring much higher capacity and improved handling when compared to a normal laser gun."
- icon = 'icons/obj/guns/energy.dmi'
icon_state = "lasernew"
- item_state = "laser"
+ item_state = "lasernew"
+ slot_flags = ITEM_SLOT_BACK
+ w_class = WEIGHT_CLASS_BULKY
+ weapon_weight = WEAPON_MEDIUM
+ inaccuracy_modifier = 0.5
force = 10
throwforce = 10
- ammo_type = list(/obj/item/ammo_casing/energy/lasergun)
cell_type = /obj/item/stock_parts/cell/lascarbine
resistance_flags = FIRE_PROOF | ACID_PROOF
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 22dee60eb4..9452722183 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -109,10 +109,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used
- var/clothes_req = 1 //see if it requires clothes
- var/cult_req = 0 //SPECIAL SNOWFLAKE clothes required for cult only spells
- var/human_req = 0 //spell can only be cast by humans
- var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities
+ var/clothes_req = SPELL_WIZARD_GARB //see if it requires clothes
+ var/list/mobs_whitelist //spell can only be casted by mobs in this typecache.
+ var/list/mobs_blacklist //The opposite of the above.
var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells
var/phase_allowed = 0 // If true, the spell can be cast while phased, eg. blood crawling, ethereal jaunting
var/antimagic_allowed = TRUE // If false, the spell cannot be cast while under the effect of antimagic
@@ -144,79 +143,17 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
action_background_icon_state = "bg_spell"
base_action = /datum/action/spell_action/spell
-/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
- if(player_lock)
- if(!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list))
- to_chat(user, "You shouldn't have this spell! Something's wrong.")
- return FALSE
- else
- if(!(src in user.mob_spell_list))
- return FALSE
+/obj/effect/proc_holder/spell/Initialize()
+ . = ..()
+ if(mobs_whitelist)
+ mobs_whitelist = typecacheof(mobs_whitelist)
+ if(mobs_blacklist)
+ mobs_blacklist = typecacheof(mobs_blacklist)
- var/turf/T = get_turf(user)
- if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
- to_chat(user, "You can't cast this spell here.")
+/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = FALSE, mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
+ if(!can_cast(user, skipcharge))
return FALSE
- if(!skipcharge)
- if(!charge_check(user))
- return FALSE
-
- if(user.stat && !stat_allowed)
- to_chat(user, "Not when you're incapacitated.")
- return FALSE
-
- if(!antimagic_allowed)
- var/antimagic = user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE)
- if(antimagic)
- if(isitem(antimagic))
- to_chat(user, "[antimagic] is interfering with your magic.")
- else
- to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.")
- return FALSE
-
- if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
- to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.")
- return FALSE
-
- if(ishuman(user))
-
- var/mob/living/carbon/human/H = user
-
- if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal())
- to_chat(user, "You can't get the words out!")
- return FALSE
-
- var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe,
- /obj/item/clothing/suit/space/hardsuit/wizard,
- /obj/item/clothing/head/wizard,
- /obj/item/clothing/head/helmet/space/hardsuit/wizard,
- /obj/item/clothing/suit/space/hardsuit/shielded/wizard,
- /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard))
-
- if(clothes_req) //clothes check
- if(!is_type_in_typecache(H.wear_suit, casting_clothes))
- to_chat(H, "I don't feel strong enough without my robe.")
- return FALSE
- if(!is_type_in_typecache(H.head, casting_clothes))
- to_chat(H, "I don't feel strong enough without my hat.")
- return FALSE
- if(cult_req) //CULT_REQ CLOTHES CHECK
- if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult))
- to_chat(H, "I don't feel strong enough without my armor.")
- return FALSE
- if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult))
- to_chat(H, "I don't feel strong enough without my helmet.")
- return FALSE
- else
- if(clothes_req || human_req)
- to_chat(user, "This spell can only be cast by humans!")
- return FALSE
- if(nonabstract_req && (isbrain(user) || ispAI(user)))
- to_chat(user, "This spell can only be cast by physical beings!")
- return FALSE
-
-
if(!skipcharge)
switch(charge_type)
if("recharge")
@@ -227,7 +164,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
adjust_var(user, holder_var_type, holder_var_amount)
if(action)
action.UpdateButtonIcon()
- return 1
+ return TRUE
/obj/effect/proc_holder/spell/proc/charge_check(mob/user, silent = FALSE)
switch(charge_type)
@@ -482,11 +419,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/updateButtonIcon(status_only, force)
action.UpdateButtonIcon(status_only, force)
-/obj/effect/proc_holder/spell/proc/can_be_cast_by(mob/caster)
- if((human_req || clothes_req) && !ishuman(caster))
- return 0
- return 1
-
/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
//Checks for obstacles from A to B
var/obj/dummy = new(A.loc)
@@ -499,24 +431,65 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
qdel(dummy)
return 1
-/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
- if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
+/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
+ var/magic_flags = SEND_SIGNAL(user, COMSIG_MOB_SPELL_CAST_CHECK, src)
+ if(magic_flags & SPELL_SKIP_ALL_REQS)
+ return TRUE
+
+ if(player_lock && (!user.mind || !(src in user.mind.spell_list)))
+ if(!silent)
+ to_chat(user, "You shouldn't have this spell! Something's wrong.")
return FALSE
- if(!charge_check(user,TRUE))
+ if(!(src in user.mob_spell_list))
return FALSE
- if(user.stat && !stat_allowed)
- return FALSE
-
- if(!antimagic_allowed && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE))
- return FALSE
-
- if(!ishuman(user))
- if(clothes_req || human_req)
+ if(!centcom_cancast && !(magic_flags & SPELL_SKIP_CENTCOM)) //Certain spells are not allowed on the centcom zlevel
+ var/turf/T = get_turf(user)
+ if(is_centcom_level(T.z))
+ if(!silent)
+ to_chat(user, "You can't cast this spell here.")
return FALSE
- if(nonabstract_req && (isbrain(user) || ispAI(user)))
+
+ if(!skipcharge)
+ if(!charge_check(user))
return FALSE
+
+ if(user.stat && !stat_allowed && !(magic_flags & SPELL_SKIP_STAT))
+ if(!silent)
+ to_chat(user, "Not when you're incapacitated.")
+ return FALSE
+
+ if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
+ if(!silent)
+ to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.")
+ return FALSE
+
+ if(clothes_req && !(magic_flags & SPELL_SKIP_CLOTHES))
+ var/met_requirements = magic_flags & (clothes_req)
+ if(met_requirements != clothes_req)
+ if(!silent)
+ var/the_many_hats = met_requirements & (clothes_req & (SPELL_WIZARD_HAT|SPELL_CULT_HELMET))
+ var/the_many_suits = met_requirements & (clothes_req & (SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR))
+ var/without_hat_robe = the_many_suits ? "a proper headwear" : the_many_hats ? "a proper suit" : "proper garments"
+ to_chat(user, "I don't feel strong enough to cast this spell without [without_hat_robe].")
+ return FALSE
+
+ if(!antimagic_allowed && !(magic_flags & SPELL_SKIP_ANTIMAGIC) && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE))
+ return FALSE
+
+
+ if(!(magic_flags & SPELL_SKIP_VOCAL) && (invocation_type in list("whisper", "shout")) && isliving(user))
+ var/mob/living/L = user
+ if(!L.can_speak_vocal())
+ if(!silent)
+ to_chat(L, "You can't get the words out!")
+ return FALSE
+
+ if(!(magic_flags & SPELL_SKIP_MOBTYPE) && ((mobs_whitelist && !mobs_whitelist[user]) || (mobs_blacklist && mobs_blacklist[user])))
+ if(!silent)
+ to_chat(user, "This spell can't be casted in this current form!")
+ return FALSE
return TRUE
/obj/effect/proc_holder/spell/self //Targets only the caster. Good for buffs and heals, but probably not wise for fireballs (although they usually fireball themselves anyway, honke)
@@ -531,8 +504,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/self/basic_heal //This spell exists mainly for debugging purposes, and also to show how casting works
name = "Lesser Heal"
desc = "Heals a small amount of brute and burn damage."
- human_req = 1
- clothes_req = 0
+ mobs_whitelist = list(/mob/living/carbon/human)
+ clothes_req = NONE
charge_max = 100
cooldown_min = 50
invocation = "Victus sano!"
diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm
index 5ba85bef6b..786026a1bc 100644
--- a/code/modules/spells/spell_types/aimed.dm
+++ b/code/modules/spells/spell_types/aimed.dm
@@ -16,7 +16,7 @@
if(!istype(user))
return
var/msg
- if(!can_cast(user))
+ if(!can_cast(user, FALSE, TRUE))
msg = "You can no longer cast [name]!"
remove_ranged_ability(msg)
return
@@ -95,7 +95,6 @@
desc = "Fire a high powered lightning bolt at your foes!"
school = "evocation"
charge_max = 150
- clothes_req = 1
invocation = "ZAP MUTHA'FUCKA"
invocation_type = "shout"
cooldown_min = 30
@@ -113,7 +112,7 @@
desc = "This spell fires a fireball at a target and does not require wizard garb."
school = "evocation"
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
invocation = "ONI SOMA"
invocation_type = "shout"
range = 20
@@ -131,7 +130,7 @@
desc = "Blazing hot rapid-fire homing cards. Banish your foes with its mystical power!"
school = "evocation"
charge_max = 50
- clothes_req = 0
+ clothes_req = NONE
invocation = "Sigi'lu M'Fan 'Tasia"
invocation_type = "shout"
range = 40
diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm
index 17a895490e..8a615750e0 100644
--- a/code/modules/spells/spell_types/area_teleport.dm
+++ b/code/modules/spells/spell_types/area_teleport.dm
@@ -1,7 +1,7 @@
/obj/effect/proc_holder/spell/targeted/area_teleport
name = "Area teleport"
desc = "This spell teleports you to a type of area of your selection."
- nonabstract_req = 1
+ mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
var/invocation_area = 1 //if the invocation appends the selected area
diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/barnyard.dm
index ccb0280779..4b972e8030 100644
--- a/code/modules/spells/spell_types/barnyard.dm
+++ b/code/modules/spells/spell_types/barnyard.dm
@@ -5,7 +5,7 @@
charge_type = "recharge"
charge_max = 150
charge_counter = 0
- clothes_req = 0
+ clothes_req = NONE
stat_allowed = 0
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
diff --git a/code/modules/spells/spell_types/bloodcrawl.dm b/code/modules/spells/spell_types/bloodcrawl.dm
index 49d73b445b..e59fc2049d 100644
--- a/code/modules/spells/spell_types/bloodcrawl.dm
+++ b/code/modules/spells/spell_types/bloodcrawl.dm
@@ -2,7 +2,7 @@
name = "Blood Crawl"
desc = "Use pools of blood to phase out of existence."
charge_max = 0
- clothes_req = 0
+ clothes_req = NONE
//If you couldn't cast this while phased, you'd have a problem
phase_allowed = 1
selection_type = "range"
diff --git a/code/modules/spells/spell_types/charge.dm b/code/modules/spells/spell_types/charge.dm
index d2513097ea..7728a879c5 100644
--- a/code/modules/spells/spell_types/charge.dm
+++ b/code/modules/spells/spell_types/charge.dm
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 600
- clothes_req = 0
+ clothes_req = NONE
invocation = "DIRI CEL"
invocation_type = "whisper"
range = -1
diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm
index 7ff4f30e33..b609655526 100644
--- a/code/modules/spells/spell_types/conjure.dm
+++ b/code/modules/spells/spell_types/conjure.dm
@@ -60,7 +60,7 @@
name = "Link Worlds"
desc = "A whole new dimension for you to play with! They won't be happy about it, though."
invocation = "WTF"
- clothes_req = FALSE
+ clothes_req = NONE
charge_max = 600
cooldown_min = 200
summon_type = list(/obj/structure/spawner/nether)
@@ -74,7 +74,7 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
var/obj/item/item
var/item_type = /obj/item/banhammer
school = "conjuration"
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index 0c0b20f0fc..e8f3ab7d06 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -7,7 +7,7 @@
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser/cult
- cult_req = 1
+ clothes_req = SPELL_CULT_GARB
charge_max = 2500
@@ -17,7 +17,7 @@
school = "transmutation"
charge_max = 50
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 2
@@ -37,7 +37,7 @@
school = "conjuration"
charge_max = 20
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -53,7 +53,7 @@
school = "conjuration"
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -70,7 +70,7 @@
school = "conjuration"
charge_max = 300
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -83,7 +83,7 @@
school = "conjuration"
charge_max = 2400
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -94,7 +94,7 @@
summon_type = list(/obj/item/soulstone)
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/cult
- cult_req = 1
+ clothes_req = SPELL_CULT_GARB
charge_max = 3600
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult
@@ -105,7 +105,7 @@
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire."
school = "transmutation"
charge_max = 400
- clothes_req = FALSE
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
wall_type = /obj/effect/forcefield/cult
@@ -121,7 +121,7 @@
school = "transmutation"
charge_max = 250
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -143,7 +143,7 @@
school = "evocation"
charge_max = 400
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile/lesser"
@@ -161,7 +161,7 @@
school = "conjuration"
charge_max = 200
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -185,7 +185,7 @@
stat_allowed = FALSE
school = "evocation"
- clothes_req = FALSE
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
action_icon = 'icons/mob/actions/actions_cult.dmi'
@@ -232,7 +232,7 @@
stat_allowed = FALSE
school = "evocation"
- clothes_req = FALSE
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
action_icon = 'icons/mob/actions/actions_cult.dmi'
@@ -294,7 +294,7 @@
proj_lifespan = 15
proj_step_delay = 7
charge_max = 350
- clothes_req = FALSE
+ clothes_req = NONE
action_icon = 'icons/mob/actions/actions_cult.dmi'
action_icon_state = "cultfist"
action_background_icon_state = "bg_demon"
diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm
index 3952a347e0..34b033fd17 100644
--- a/code/modules/spells/spell_types/devil.dm
+++ b/code/modules/spells/spell_types/devil.dm
@@ -4,7 +4,7 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
item_type = /obj/item/twohanded/pitchfork/demonic
school = "conjuration"
@@ -37,7 +37,7 @@
invocation = "Just sign on the dotted line."
include_user = 0
range = 5
- clothes_req = 0
+ clothes_req = NONE
school = "conjuration"
charge_max = 150
@@ -79,7 +79,7 @@
school = "evocation"
charge_max = 80
- clothes_req = 0
+ clothes_req = NONE
invocation = "Your very soul will catch fire!"
invocation_type = "shout"
range = 2
@@ -92,7 +92,7 @@
name = "Infernal Jaunt"
desc = "Use hellfire to phase out of existence."
charge_max = 200
- clothes_req = 0
+ clothes_req = NONE
selection_type = "range"
range = -1
cooldown_min = 0
@@ -167,7 +167,7 @@
name = "Sin Touch"
desc = "Subtly encourage someone to sin."
charge_max = 1800
- clothes_req = 0
+ clothes_req = NONE
selection_type = "range"
range = 2
cooldown_min = 0
@@ -206,7 +206,7 @@
desc = "When what a Devil really needs is funk."
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
school = "conjuration"
charge_max = 10
diff --git a/code/modules/spells/spell_types/devil_boons.dm b/code/modules/spells/spell_types/devil_boons.dm
index 5d335745d2..ab3e3cc27e 100644
--- a/code/modules/spells/spell_types/devil_boons.dm
+++ b/code/modules/spells/spell_types/devil_boons.dm
@@ -4,7 +4,7 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
school = "conjuration"
charge_max = 100
cooldown_min = 10
@@ -32,7 +32,7 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
charge_max = 50
cooldown_min = 10
action_icon = 'icons/mob/actions/actions_silicon.dmi'
@@ -51,7 +51,7 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
+ clothes_req = NONE
charge_max = 50
cooldown_min = 10
action_icon = 'icons/mob/actions/actions_spells.dmi'
@@ -73,4 +73,4 @@
friendShell = new /obj/effect/mob_spawn/human/demonic_friend(L.loc, L.mind, src)
/obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket/robeless
- clothes_req = FALSE
+ clothes_req = NONE
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 424a3b7671..f485ae578f 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -4,13 +4,12 @@
school = "transmutation"
charge_max = 300
- clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
cooldown_min = 100 //50 deciseconds reduction per rank
include_user = 1
- nonabstract_req = 1
+ mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/jaunt_duration = 50 //in deciseconds
var/jaunt_in_time = 5
var/jaunt_in_type = /obj/effect/temp_visual/wizard
diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm
index aa2fa5ab8b..e0c21066cf 100644
--- a/code/modules/spells/spell_types/forcewall.dm
+++ b/code/modules/spells/spell_types/forcewall.dm
@@ -3,7 +3,7 @@
desc = "Create a magical barrier that only you can pass through. Does not require wizard garb."
school = "transmutation"
charge_max = 80
- clothes_req = 0
+ clothes_req = NONE
invocation = "TARCOL MINTI ZHERI"
invocation_type = "shout"
sound = 'sound/magic/forcewall.ogg'
diff --git a/code/modules/spells/spell_types/infinite_guns.dm b/code/modules/spells/spell_types/infinite_guns.dm
index feb6eeddb6..cfdf0d4a8d 100644
--- a/code/modules/spells/spell_types/infinite_guns.dm
+++ b/code/modules/spells/spell_types/infinite_guns.dm
@@ -7,7 +7,6 @@
school = "conjuration"
charge_max = 750
- clothes_req = 1
cooldown_min = 10 //Gun wizard
action_icon_state = "bolt_action"
var/summon_path = /obj/item/gun/ballistic/shotgun/boltaction/enchanted
diff --git a/code/modules/spells/spell_types/knock.dm b/code/modules/spells/spell_types/knock.dm
index be5f516680..9cbaa5baa3 100644
--- a/code/modules/spells/spell_types/knock.dm
+++ b/code/modules/spells/spell_types/knock.dm
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
invocation = "AULIE OXIN FIERA"
invocation_type = "whisper"
range = 3
diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm
index 207ccd8374..f6f56c049a 100644
--- a/code/modules/spells/spell_types/lichdom.dm
+++ b/code/modules/spells/spell_types/lichdom.dm
@@ -8,7 +8,7 @@
becoming a lich destroys all internal organs except the brain."
school = "necromancy"
charge_max = 10
- clothes_req = 0
+ clothes_req = NONE
centcom_cancast = 0
invocation = "NECREM IMORTIUM!"
invocation_type = "shout"
diff --git a/code/modules/spells/spell_types/lightning.dm b/code/modules/spells/spell_types/lightning.dm
index f4812e7462..81b26cf464 100644
--- a/code/modules/spells/spell_types/lightning.dm
+++ b/code/modules/spells/spell_types/lightning.dm
@@ -3,7 +3,6 @@
desc = "Blast lightning at your foes!"
charge_type = "recharge"
charge_max = 270
- clothes_req = 1
invocation = "UN'LTD P'WAH!"
invocation_type = "shout"
range = 7
diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm
index 621efdc821..a3bb81ae55 100644
--- a/code/modules/spells/spell_types/mime.dm
+++ b/code/modules/spells/spell_types/mime.dm
@@ -8,10 +8,10 @@
invocation_emote_self = "You form a wall in front of yourself."
summon_lifespan = 300
charge_max = 300
- clothes_req = 0
+ clothes_req = NONE
range = 0
cast_sound = null
- human_req = 1
+ mobs_whitelist = list(/mob/living/carbon/human)
action_icon_state = "mime"
action_background_icon_state = "bg_mime"
@@ -32,8 +32,8 @@
desc = "Make or break a vow of silence."
school = "mime"
panel = "Mime"
- clothes_req = 0
- human_req = 1
+ clothes_req = NONE
+ mobs_whitelist = list(/mob/living/carbon/human)
charge_max = 3000
range = -1
include_user = 1
@@ -75,7 +75,7 @@
invocation_emote_self = "You form a blockade in front of yourself."
charge_max = 600
sound = null
- clothes_req = 0
+ clothes_req = NONE
range = -1
include_user = 1
@@ -98,7 +98,7 @@
school = "mime"
panel = "Mime"
charge_max = 300
- clothes_req = 0
+ clothes_req = NONE
invocation_type = "emote"
invocation_emote_self = "You fire your finger gun!"
range = 20
diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm
index cbc25fb98e..d2ef015d1d 100644
--- a/code/modules/spells/spell_types/mind_transfer.dm
+++ b/code/modules/spells/spell_types/mind_transfer.dm
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 600
- clothes_req = 0
+ clothes_req = NONE
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
diff --git a/code/modules/spells/spell_types/rod_form.dm b/code/modules/spells/spell_types/rod_form.dm
index 5a532db7ac..7a96d0ac55 100644
--- a/code/modules/spells/spell_types/rod_form.dm
+++ b/code/modules/spells/spell_types/rod_form.dm
@@ -1,8 +1,6 @@
/obj/effect/proc_holder/spell/targeted/rod_form
name = "Rod Form"
desc = "Take on the form of an immovable rod, destroying all in your path."
- clothes_req = 1
- human_req = 0
charge_max = 250
cooldown_min = 100
range = -1
diff --git a/code/modules/spells/spell_types/santa.dm b/code/modules/spells/spell_types/santa.dm
index 3da6d90558..64ed925455 100644
--- a/code/modules/spells/spell_types/santa.dm
+++ b/code/modules/spells/spell_types/santa.dm
@@ -4,7 +4,7 @@
desc = "This spell lets you reach into S-space and retrieve presents! Yay!"
school = "santa"
charge_max = 600
- clothes_req = 0
+ clothes_req = NONE
invocation = "HO HO HO"
invocation_type = "shout"
range = 3
diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm
index 0b492cc6b0..83996b5bfb 100644
--- a/code/modules/spells/spell_types/shadow_walk.dm
+++ b/code/modules/spells/spell_types/shadow_walk.dm
@@ -2,7 +2,7 @@
name = "Shadow Walk"
desc = "Grants unlimited movement in darkness."
charge_max = 0
- clothes_req = 0
+ clothes_req = NONE
phase_allowed = 1
selection_type = "range"
range = -1
diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm
index 46eb14013f..c6966ccee9 100644
--- a/code/modules/spells/spell_types/shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift.dm
@@ -1,8 +1,7 @@
/obj/effect/proc_holder/spell/targeted/shapeshift
name = "Shapechange"
desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed."
- clothes_req = 0
- human_req = 0
+ clothes_req = NONE
charge_max = 200
cooldown_min = 50
range = -1
@@ -59,8 +58,9 @@
var/mob/living/shape = new shapeshift_type(caster.loc)
H = new(shape,src,caster)
- clothes_req = 0
- human_req = 0
+ clothes_req = NONE
+ mobs_whitelist = null
+ mobs_blacklist = null
/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Restore(mob/living/shape)
var/obj/shapeshift_holder/H = locate() in shape
@@ -70,7 +70,8 @@
H.restore()
clothes_req = initial(clothes_req)
- human_req = initial(human_req)
+ mobs_whitelist = typecacheof(initial(mobs_whitelist))
+ mobs_blacklist = typecacheof(initial(mobs_blacklist))
/obj/effect/proc_holder/spell/targeted/shapeshift/dragon
name = "Dragon Form"
diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm
index 7a19787675..3af4d3883f 100644
--- a/code/modules/spells/spell_types/spacetime_distortion.dm
+++ b/code/modules/spells/spell_types/spacetime_distortion.dm
@@ -11,7 +11,7 @@
cooldown_min = 300
level_max = 0
-/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr)
+/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
if(ready)
return ..()
return FALSE
diff --git a/code/modules/spells/spell_types/summonitem.dm b/code/modules/spells/spell_types/summonitem.dm
index ca56e51272..94de75faac 100644
--- a/code/modules/spells/spell_types/summonitem.dm
+++ b/code/modules/spells/spell_types/summonitem.dm
@@ -3,7 +3,7 @@
desc = "This spell can be used to recall a previously marked item to your hand from anywhere in the universe."
school = "transmutation"
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
invocation = "GAR YOK"
invocation_type = "whisper"
range = -1
diff --git a/code/modules/spells/spell_types/taeclowndo.dm b/code/modules/spells/spell_types/taeclowndo.dm
index d2b0782b07..5b1e09565b 100644
--- a/code/modules/spells/spell_types/taeclowndo.dm
+++ b/code/modules/spells/spell_types/taeclowndo.dm
@@ -4,7 +4,6 @@
invocation_type = "none"
include_user = 1
range = -1
- clothes_req = 0
item_type = /obj/item/reagent_containers/food/snacks/pie/cream
charge_max = 30
@@ -20,7 +19,7 @@
charge_type = "recharge"
charge_max = 100
cooldown_min = 100
- clothes_req = 0
+ clothes_req = NONE
invocation_type = "none"
range = 7
selection_type = "view"
@@ -61,7 +60,7 @@
hand_path = /obj/item/melee/touch_attack/megahonk
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
cooldown_min = 100
action_icon = 'icons/mecha/mecha_equipment.dmi'
@@ -75,7 +74,7 @@
hand_path = /obj/item/melee/touch_attack/bspie
charge_max = 450
- clothes_req = 0
+ clothes_req = NONE
cooldown_min = 450
action_icon = 'icons/obj/food/piecake.dmi'
diff --git a/code/modules/spells/spell_types/telepathy.dm b/code/modules/spells/spell_types/telepathy.dm
index 34f100f753..4b4f91eb18 100644
--- a/code/modules/spells/spell_types/telepathy.dm
+++ b/code/modules/spells/spell_types/telepathy.dm
@@ -2,7 +2,7 @@
name = "Telepathy"
desc = "Telepathically transmits a message to the target."
charge_max = 0
- clothes_req = 0
+ clothes_req = NONE
range = 7
include_user = 0
action_icon = 'icons/mob/actions/actions_revenant.dmi'
diff --git a/code/modules/spells/spell_types/the_traps.dm b/code/modules/spells/spell_types/the_traps.dm
index 7402dbfbc8..87928e6a7e 100644
--- a/code/modules/spells/spell_types/the_traps.dm
+++ b/code/modules/spells/spell_types/the_traps.dm
@@ -5,7 +5,6 @@
charge_max = 250
cooldown_min = 50
- clothes_req = 1
invocation = "CAVERE INSIDIAS"
invocation_type = "shout"
range = 3
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index e5b9144535..a23e16cf88 100644
--- a/code/modules/spells/spell_types/touch_attacks.dm
+++ b/code/modules/spells/spell_types/touch_attacks.dm
@@ -56,7 +56,6 @@
school = "evocation"
charge_max = 600
- clothes_req = 1
cooldown_min = 200 //100 deciseconds reduction per rank
action_icon_state = "gib"
@@ -68,7 +67,6 @@
school = "transmutation"
charge_max = 600
- clothes_req = 1
cooldown_min = 200 //100 deciseconds reduction per rank
action_icon_state = "statue"
@@ -81,7 +79,7 @@
school = "evocation"
charge_max = 100
- clothes_req = 0
+ clothes_req = NONE
cooldown_min = 20
action_icon_state = "nuclearfist"
diff --git a/code/modules/spells/spell_types/turf_teleport.dm b/code/modules/spells/spell_types/turf_teleport.dm
index 8a45f2be22..59f04c7039 100644
--- a/code/modules/spells/spell_types/turf_teleport.dm
+++ b/code/modules/spells/spell_types/turf_teleport.dm
@@ -1,7 +1,7 @@
/obj/effect/proc_holder/spell/targeted/turf_teleport
name = "Turf Teleport"
desc = "This spell teleports the target to the turf in range."
- nonabstract_req = 1
+ mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/inner_tele_radius = 1
var/outer_tele_radius = 2
diff --git a/code/modules/spells/spell_types/voice_of_god.dm b/code/modules/spells/spell_types/voice_of_god.dm
index eb8950086c..495681a818 100644
--- a/code/modules/spells/spell_types/voice_of_god.dm
+++ b/code/modules/spells/spell_types/voice_of_god.dm
@@ -4,7 +4,7 @@
charge_max = 1200 //variable
cooldown_min = 0
level_max = 1
- clothes_req = 0
+ clothes_req = NONE
action_icon = 'icons/mob/actions/actions_items.dmi'
action_icon_state = "voice_of_god"
var/command
@@ -13,9 +13,10 @@
var/list/spans = list("colossus","yell")
var/speech_sound = 'sound/magic/clockwork/invoke_general.ogg'
-/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr)
+/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr, skipcharge = FALSE, silent = TRUE)
if(!user.can_speak())
- to_chat(user, "You are unable to speak!")
+ if(!silent)
+ to_chat(user, "You are unable to speak!")
return FALSE
return TRUE
diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm
index 405bde212a..ace542126c 100644
--- a/code/modules/spells/spell_types/wizard.dm
+++ b/code/modules/spells/spell_types/wizard.dm
@@ -4,7 +4,6 @@
school = "evocation"
charge_max = 200
- clothes_req = 1
invocation = "FORTI GY AMA"
invocation_type = "shout"
range = 7
@@ -38,7 +37,6 @@
school = "transmutation"
charge_max = 400
- clothes_req = 1
invocation = "BIRUZ BENNAR"
invocation_type = "shout"
range = -1
@@ -58,7 +56,7 @@
school = "conjuration"
charge_max = 120
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -77,7 +75,7 @@
school = "conjuration"
charge_max = 360
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -92,7 +90,6 @@
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
charge_max = 400
- clothes_req = 1
invocation = "NEC CANTIO"
invocation_type = "shout"
range = -1
@@ -109,7 +106,6 @@
school = "abjuration"
charge_max = 20
- clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
@@ -131,8 +127,7 @@
name = "quickstep"
charge_max = 100
- clothes_req = 0
- cult_req = 1
+ clothes_req = SPELL_CULT_GARB
/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
name = "Teleport"
@@ -140,7 +135,6 @@
school = "abjuration"
charge_max = 600
- clothes_req = 1
invocation = "SCYAR NILA"
invocation_type = "shout"
range = -1
@@ -156,7 +150,6 @@
name = "Stop Time"
desc = "This spell stops time for everyone except for you, allowing you to move freely while your enemies and even projectiles are frozen."
charge_max = 500
- clothes_req = 1
invocation = "TOKI YO TOMARE"
invocation_type = "shout"
range = 0
@@ -174,7 +167,6 @@
school = "conjuration"
charge_max = 1200
- clothes_req = 1
invocation = "NOUK FHUNMM SACP RISSKA"
invocation_type = "shout"
range = 1
@@ -189,7 +181,7 @@
school = "conjuration"
charge_max = 600
- clothes_req = 0
+ clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -206,7 +198,7 @@
school = "conjuration"
charge_max = 1200
- clothes_req = 0
+ clothes_req = NONE
invocation = "IA IA"
invocation_type = "shout"
summon_amt = 10
@@ -221,7 +213,7 @@
school = "transmutation"
charge_max = 300
- clothes_req = 0
+ clothes_req = NONE
invocation = "STI KALY"
invocation_type = "whisper"
message = "Your eyes cry out in pain!"
@@ -233,7 +225,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult
name = "Summon Creatures (DANGEROUS)"
- cult_req = 1
+ clothes_req = SPELL_CULT_GARB
charge_max = 5000
summon_amt = 2
@@ -253,7 +245,6 @@
name = "Repulse"
desc = "This spell throws everything around the user away."
charge_max = 400
- clothes_req = 1
invocation = "GITTAH WEIGH"
invocation_type = "shout"
range = 5
@@ -314,7 +305,7 @@
desc = "Throw back attackers with a sweep of your tail."
sound = 'sound/magic/tail_swing.ogg'
charge_max = 150
- clothes_req = 0
+ clothes_req = NONE
range = 2
cooldown_min = 150
invocation_type = "none"
@@ -335,7 +326,7 @@
name = "Sacred Flame"
desc = "Makes everyone around you more flammable, and lights yourself on fire."
charge_max = 60
- clothes_req = 0
+ clothes_req = NONE
invocation = "FI'RAN DADISKO"
invocation_type = "shout"
max_targets = 0
@@ -358,7 +349,7 @@
/obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket
name = "Thrown Lightning"
desc = "Forged from eldrich energies, a packet of pure power, known as a spell packet will appear in your hand, that when thrown will stun the target."
- clothes_req = 1
+ clothes_req = SPELL_WIZARD_GARB
item_type = /obj/item/spellpacket/lightningbolt
charge_max = 10
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index 947ccb7924..66a47d21f2 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi
index 2fdb9b88d2..528fd42d23 100644
Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi
index dc8d8a4c3f..5bf347fabf 100644
Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index dd25e05460..7eff305581 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -504,6 +504,7 @@
#include "code\datums\elements\flavor_text.dm"
#include "code\datums\elements\ghost_role_eligibility.dm"
#include "code\datums\elements\mob_holder.dm"
+#include "code\datums\elements\spellcasting.dm"
#include "code\datums\elements\swimming.dm"
#include "code\datums\elements\sword_point.dm"
#include "code\datums\elements\update_icon_blocker.dm"