diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index f46d9e3537..5cb6a24e26 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -105,7 +105,7 @@ Code:
user << "You transfer the frequency and code of \the [signaler2.name] to \the [name]"
else
..()
-
+
/obj/item/device/assembly/signaler/proc/signal()
if(!radio_connection) return
@@ -194,3 +194,9 @@ Code:
/obj/item/device/assembly/signaler/anomaly/attack_self()
return
+
+/obj/item/device/assembly/signaler/cyborg
+ origin_tech = null
+
+/obj/item/device/assembly/signaler/cyborg/attackby(obj/item/weapon/W, mob/user, params)
+ return
diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm
index a512f12125..a313d6aa0f 100644
--- a/code/modules/library/soapstone.dm
+++ b/code/modules/library/soapstone.dm
@@ -1,22 +1,40 @@
+#define SOAPSTONE_PREFIX_FILE "strings/soapstone_prefixes.txt"
+#define SOAPSTONE_SUFFIX_FILE "soapstone_suffixes.json"
+//Vocabulary lists; soapstones use a prefix and a suffix. Optionally, they can have a prefix and suffix, then a conjunction that links another set.
+var/global/list/soapstone_prefixes = list() //Read from "strings/soapstone_prefixes.txt"; if you're adding your own, put **** where the subject should be!
+var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffixes.json"
/obj/item/soapstone
name = "chisel"
- desc = "Leave informative messages for the crew, including the crew of future shifts!\nEven if out of uses, it can still be used to remove messages.\n(Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
+ desc = "Leave \"informative\" messages for the crew, including the crew of future shifts!\n\
+ (Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
icon = 'icons/obj/items.dmi'
icon_state = "soapstone"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
- var/tool_speed = 50
var/remaining_uses = 3
var/non_dull_name
- var/w_engrave = "engrave"
- var/w_engraving = "engraving"
- var/w_chipping = "chipping"
var/w_dull = "dull"
/obj/item/soapstone/New()
. = ..()
+ if(!soapstone_prefixes.len)
+ soapstone_prefixes = file2list(SOAPSTONE_PREFIX_FILE, "\n")
+ if(!soapstone_suffixes.len)
+ soapstone_suffixes = list(\
+ "Characters" = strings(SOAPSTONE_SUFFIX_FILE, "Characters"), \
+ "Careers" = strings(SOAPSTONE_SUFFIX_FILE, "Careers"), \
+ "Antagonists" = strings(SOAPSTONE_SUFFIX_FILE, "Antagonists"), \
+ "Objects" = strings(SOAPSTONE_SUFFIX_FILE, "Objects"), \
+ "Techniques" = strings(SOAPSTONE_SUFFIX_FILE, "Techniques"), \
+ "Actions" = strings(SOAPSTONE_SUFFIX_FILE, "Actions"), \
+ "Geography" = strings(SOAPSTONE_SUFFIX_FILE, "Geography"), \
+ "Orientation" = strings(SOAPSTONE_SUFFIX_FILE, "Orientation"), \
+ "Body parts" = strings(SOAPSTONE_SUFFIX_FILE, "Body parts"), \
+ "Concepts" = strings(SOAPSTONE_SUFFIX_FILE, "Concepts"), \
+ "Musings" = strings(SOAPSTONE_SUFFIX_FILE, "Musings"), \
+ )
random_name()
check_name() // could start empty
@@ -25,9 +43,6 @@
non_dull_name = name
if(name == "chalk" || name == "magic marker")
desc = replacetext(desc, "engraving", "scribbling")
- w_engrave = "scribble"
- w_engraving = "scribbling"
- w_chipping = "sketching"
if(name == "chalk")
w_dull = "used"
if(name == "magic marker")
@@ -35,9 +50,6 @@
if(name == "soapstone" || name == "chisel")
desc = replacetext(desc, "scribbling", "engraving")
- w_engrave = initial(w_engrave)
- w_engraving = initial(w_engraving)
- w_chipping = initial(w_chipping)
w_dull = "dull"
/obj/item/soapstone/examine(mob/user)
@@ -48,59 +60,48 @@
user << "It looks like it can be used an unlimited number of times."
/obj/item/soapstone/afterattack(atom/target, mob/user, proximity)
+ if(!remaining_uses)
+ user << "[src] is [w_dull] and can't be used anymore!"
+ return
var/turf/T = get_turf(target)
if(!proximity)
return
-
-
- var/obj/structure/chisel_message/already_message = locate(/obj/structure/chisel_message) in T
-
- var/our_message = FALSE
- if(already_message)
- our_message = already_message.creator_key == user.ckey
-
- if(!remaining_uses && !already_message)
- // The dull chisel is dull.
- user << "[src] is [w_dull]."
- return
-
- if(!good_chisel_message_location(T))
- user << "It's not appropriate to [w_engrave] on [T]."
- return
-
- if(already_message)
- user.visible_message("[user] starts erasing [already_message].", "You start erasing [already_message].", "You hear a [w_chipping] sound.")
- playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
-
- // Removing our own messages refunds a charge
-
- if(do_after(user, tool_speed, target=target))
- user.visible_message("[user] has erased [already_message].", "You erased [already_message].")
- already_message.persists = FALSE
- qdel(already_message)
- playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
- if(our_message)
+ var/obj/structure/chisel_message/msg = locate() in T
+ if(msg)
+ if(msg.creator_key != user.ckey)
+ user << "There's already a message there!"
+ return
+ else
+ if(alert(user, "Erase this message?", name, "Yes", "No") == "Yes")
+ user.visible_message("[user] erases [msg].", "You permanently erase [msg].")
+ playsound(T, 'sound/items/gavel.ogg', 50, 1)
refund_use()
+ msg.persists = 0
+ qdel(msg)
+ return
+ return
+ if(!good_chisel_message_location(T))
+ user << "You can't write there!"
return
-
- var/message = stripped_input(user, "What would you like to [w_engrave]?", "[name] Message")
- if(!message)
- user << "You decide not to [w_engrave] anything."
+ var/prefix = input(user, "Choose a prefix for your message.", name) as null|anything in soapstone_prefixes
+ if(!prefix)
return
-
- if(!target.Adjacent(user) && locate(/obj/structure/chisel_message) in T)
- user << "You decide not to [w_engrave] anything."
+ var/suffix_category_string = input(user, "Choose a suffix category.", "[prefix]...") as null|anything in soapstone_suffixes
+ var/list/suffix_category = soapstone_suffixes[suffix_category_string]
+ if(!suffix_category || !suffix_category.len)
return
-
- playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
- user.visible_message("[user] starts [w_engraving] a message into [T].", "You start [w_engraving] a message into [T].", "You hear a [w_chipping] sound.")
- if(can_use() && do_after(user, tool_speed, target=T) && can_use())
- if(!locate(/obj/structure/chisel_message in T))
- user << "You [w_engrave] a message into [T]."
- playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
- var/obj/structure/chisel_message/M = new(T)
- M.register(user, message)
- remove_use()
+ var/suffix = input(user, "Choose a suffix.", "[prefix]...") as null|anything in suffix_category
+ if(!suffix)
+ return
+ var/processed_message = replacetext(prefix, "****", suffix)
+ if(!user.Adjacent(T) || !good_chisel_message_location(T) || locate(/obj/structure/chisel_message) in T)
+ return
+ user.visible_message("[user] writes a message onto [T]!", "You write a message onto [T].")
+ playsound(T, 'sound/items/gavel.ogg', 50, 1)
+ var/obj/structure/chisel_message/M = new(T)
+ M.register(user, processed_message)
+ remove_use()
+ return 1
/obj/item/soapstone/proc/can_use()
if(remaining_uses == -1 || remaining_uses >= 0)
@@ -171,6 +172,34 @@
var/map
var/persists = TRUE
+ var/positive_ratings = 0
+ var/negative_ratings = 0
+
+ var/list/raters = list() //Ckeys who have rated this message
+
+/obj/structure/chisel_message/attack_hand(mob/user)
+ if(user.ckey == creator_key)
+ user << "You can't rate your own messages!"
+ return
+ if(raters[user.ckey])
+ user << "You've already rated this message!"
+ return
+ switch(alert(user, "How would you like to rate this message?", "Message Rating", "Positive", "Negative", "Cancel"))
+ if("Positive")
+ for(var/client/C in clients)
+ if(C.ckey == creator_key)
+ C.mob << "One of your messages was rated as positive!"
+ user << "You rated this message as positive."
+ positive_ratings++
+ raters[user.ckey] = "positive"
+ if("Negative")
+ for(var/client/C in clients)
+ if(C.ckey == creator_key)
+ C.mob << "One of your messages was rated as negative!"
+ user << "You rated this message as negative."
+ negative_ratings++
+ raters[user.ckey] = "negative"
+
/obj/structure/chisel_message/New(newloc)
..()
SSpersistence.chisel_messages += src
@@ -190,12 +219,6 @@
map = MAP_NAME
update_icon()
-/obj/structure/chisel_message/update_icon()
- ..()
- var/hash = md5(hidden_message)
- var/newcolor = copytext(hash, 1, 7)
- add_atom_colour("#[newcolor]", FIXED_COLOUR_PRIORITY)
-
/obj/structure/chisel_message/proc/pack()
var/list/data = list()
data["hidden_message"] = hidden_message
@@ -206,6 +229,9 @@
var/turf/T = get_turf(src)
data["x"] = T.x
data["y"] = T.y
+ data["pos_ratings"] = positive_ratings
+ data["neg_ratings"] = positive_ratings
+ data["raters"] = raters
return data
/obj/structure/chisel_message/proc/unpack(list/data)
@@ -213,6 +239,9 @@
creator_name = data["creator_name"]
creator_key = data["creator_key"]
realdate = data["realdate"]
+ positive_ratings = data["pos_ratings"]
+ negative_ratings = data["neg_ratings"]
+ raters = data["raters"]
var/x = data["x"]
var/y = data["y"]
@@ -222,7 +251,10 @@
/obj/structure/chisel_message/examine(mob/user)
..()
- user << "[hidden_message]"
+ user << "[hidden_message]"
+ user << "Ratings: [positive_ratings] [negative_ratings]"
+ if(raters[user.ckey])
+ user << "You rated this message as [raters[user.ckey]]."
/obj/structure/chisel_message/Destroy()
if(persists)
diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm
index 052c4899ae..5888cee361 100644
--- a/code/modules/paperwork/contract.dm
+++ b/code/modules/paperwork/contract.dm
@@ -292,7 +292,7 @@
/obj/item/weapon/paper/contract/infernal/magic/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0)
if(!istype(user) || !user.mind)
return -1
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball(null))
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
return ..()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index c5f5283c54..81c9879996 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -51,6 +51,7 @@
obj_integrity = 200
max_integrity = 200
integrity_failure = 50
+ resistance_flags = FIRE_PROOF
var/area/area
var/areastring = null
var/obj/item/weapon/stock_parts/cell/cell
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index df4421f971..f614c10ca3 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -736,6 +736,10 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list ( \
pixel_y = rand(-2,2)
update_icon()
+/obj/item/stack/cable_coil/red
+ item_color = "red"
+ icon_state = "coil_red"
+
/obj/item/stack/cable_coil/yellow
item_color = "yellow"
icon_state = "coil_yellow"
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 0c9ad083a9..eef1a5a799 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -168,6 +168,8 @@
investigate_log("lost power and turned off","singulo")
log_game("Emitter lost power in ([x],[y],[z])")
return
+ if(!check_delay())
+ return FALSE
fire_beam()
/obj/machinery/power/emitter/proc/check_delay()
@@ -175,9 +177,16 @@
return TRUE
return FALSE
-/obj/machinery/power/emitter/proc/fire_beam()
+/obj/machinery/power/emitter/proc/fire_beam_pulse()
if(!check_delay())
return FALSE
+ if(state != 2)
+ return FALSE
+ if(avail(active_power_usage))
+ add_load(active_power_usage)
+ fire_beam()
+
+/obj/machinery/power/emitter/proc/fire_beam()
src.last_shot = world.time
if(src.shot_number < 3)
src.fire_delay = 20
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 9c11a4289b..861d73fc89 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -63,8 +63,10 @@
/obj/singularity/narsie/Bump(atom/A)
- forceMove(get_turf(A))
- A.narsie_act()
+ var/turf/T = get_turf(A)
+ if(T == loc)
+ T = get_step(A, A.dir) //please don't slam into a window like a bird, nar-sie
+ forceMove(T)
/obj/singularity/narsie/mezzer()
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index e9409e42e9..701e7baff7 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -90,10 +90,10 @@
if((last_zap + zap_cooldown) > world.time)
return FALSE
last_zap = world.time
- var/coeff = (12 - (input_power_multiplier * 3))
- coeff = max(coeff, 1)
- var/shock_coeff = (5 - input_power_multiplier)
- shock_coeff = max(shock_coeff, 1)
+ var/coeff = (20 - ((input_power_multiplier - 1) * 3))
+ coeff = max(coeff, 10)
+ var/shock_coeff = (4 - (input_power_multiplier - 2))
+ shock_coeff = max(shock_coeff, 2)
var/power = (powernet.avail/coeff)
add_load(power)
playsound(src.loc, 'sound/magic/LightningShock.ogg', 100, 1, extrarange = 5)
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index fba93b7d5b..8092b59d90 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -203,7 +203,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
else if(isliving(A))
var/dist = get_dist(source, A)
var/mob/living/L = A
- if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD)
+ if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !L.tesla_ignore)
closest_mob = L
closest_atom = A
closest_dist = dist
diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm
index 0c6a09a98a..68681c1124 100644
--- a/code/modules/projectiles/ammunition/special.dm
+++ b/code/modules/projectiles/ammunition/special.dm
@@ -23,7 +23,7 @@
projectile_type = /obj/item/projectile/magic/door
/obj/item/ammo_casing/magic/fireball
- projectile_type = /obj/item/projectile/magic/fireball
+ projectile_type = /obj/item/projectile/magic/aoe/fireball
/obj/item/ammo_casing/magic/chaos
projectile_type = /obj/item/projectile/magic
@@ -35,7 +35,6 @@
projectile_type = /obj/item/projectile/magic/arcane_barrage
/obj/item/ammo_casing/magic/chaos/newshot()
- projectile_type = pick(typesof(/obj/item/projectile/magic))
..()
/obj/item/ammo_casing/magic/honk
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index bc2a1f045c..4de87637ee 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -267,6 +267,7 @@
if(user)
user.update_inv_hands()
feedback_add_details("gun_fired","[src.type]")
+ return 1
/obj/item/weapon/gun/attack(mob/M as mob, mob/user)
if(user.a_intent == INTENT_HARM) //Flogging
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index e4aae72ca6..f133b08a79 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -343,3 +343,16 @@
new /obj/item/stack/cable_coil(get_turf(src), 10)
slung = 0
update_icon()
+
+/obj/item/weapon/gun/ballistic/revolver/reverse //Fires directly at its user... unless the user is a clown, of course.
+ clumsy_check = 0
+
+/obj/item/weapon/gun/ballistic/revolver/reverse/can_trigger_gun(mob/living/user)
+ if((user.disabilities & CLUMSY) || (user.mind && user.mind.assigned_role == "Clown"))
+ return ..()
+ if(process_fire(user, user, 0, zone_override = "head"))
+ user.visible_message("[user] somehow manages to shoot [user.p_them()]self in the face!", "You somehow shoot yourself in the face! How the hell?!")
+ user.emote("scream")
+ user.drop_item()
+ user.Weaken(4)
+ return
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index ba81adbae2..df24b4d081 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -38,6 +38,13 @@
max_charges = 10
recharge_rate = 2
no_den_usage = 1
+ var/allowed_projectile_types = list(/obj/item/projectile/magic/change, /obj/item/projectile/magic/animate, /obj/item/projectile/magic/resurrection,
+ /obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
+ /obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage)
+
+/obj/item/weapon/gun/magic/staff/chaos/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override, bonus_spread = 0)
+ chambered.projectile_type = pick(allowed_projectile_types)
+ . = ..(target, user, message, params, zone_override, bonus_spread)
/obj/item/weapon/gun/magic/staff/door
name = "staff of door creation"
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 04a83ca3c0..eedc640911 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -17,53 +17,6 @@
var/mob/M = target
M.death(0)
-/obj/item/projectile/magic/fireball
- name = "bolt of fireball"
- icon_state = "fireball"
- damage = 10
- damage_type = BRUTE
- nodamage = 0
-
- //explosion values
- var/exp_heavy = 0
- var/exp_light = 2
- var/exp_flash = 3
- var/exp_fire = 2
-
-/obj/item/projectile/magic/fireball/Range()
- var/turf/T1 = get_step(src,turn(dir, -45))
- var/turf/T2 = get_step(src,turn(dir, 45))
- var/turf/T3 = get_step(src,dir)
- var/mob/living/L = locate(/mob/living) in T1 //if there's a mob alive in our front right diagonal, we hit it.
- if(L && L.stat != DEAD)
- Bump(L,1) //Magic Bullet #teachthecontroversy
- return
- L = locate(/mob/living) in T2
- if(L && L.stat != DEAD)
- Bump(L,1)
- return
- L = locate(/mob/living) in T3
- if(L && L.stat != DEAD)
- Bump(L,1)
- return
- ..()
-
-/obj/item/projectile/magic/fireball/on_hit(target)
- . = ..()
- var/turf/T = get_turf(target)
- explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
- if(ismob(target)) //multiple flavors of pain
- var/mob/living/M = target
- M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
-
-/obj/item/projectile/magic/fireball/infernal
- name = "infernal fireball"
- exp_heavy = -1
- exp_light = -1
- exp_flash = 4
- exp_fire= 5
-
-
/obj/item/projectile/magic/resurrection
name = "bolt of resurrection"
icon_state = "ion"
@@ -387,3 +340,85 @@
nodamage = 0
armour_penetration = 0
flag = "magic"
+
+/obj/item/projectile/magic/aoe
+ name = "Area Bolt"
+ desc = "What the fuck does this do?!"
+ damage = 0
+ var/proxdet = TRUE
+
+/obj/item/projectile/magic/aoe/Range()
+ if(proxdet)
+ var/turf/T1 = get_step(src,turn(dir, -45))
+ var/turf/T2 = get_step(src,turn(dir, 45))
+ var/turf/T3 = get_step(src,dir)
+ var/mob/living/L = locate(/mob/living) in T1 //if there's a mob alive in our front right diagonal, we hit it.
+ if(L && L.stat != DEAD)
+ Bump(L,1) //Magic Bullet #teachthecontroversy
+ return
+ L = locate(/mob/living) in T2
+ if(L && L.stat != DEAD)
+ Bump(L,1)
+ return
+ L = locate(/mob/living) in T3
+ if(L && L.stat != DEAD)
+ Bump(L,1)
+ return
+ ..()
+
+/obj/item/projectile/magic/aoe/lightning
+ name = "lightning bolt"
+ icon_state = "tesla_projectile" //Better sprites are REALLY needed and appreciated!~
+ damage = 15
+ damage_type = BURN
+ nodamage = 0
+ speed = 0.3
+ flag = "magic"
+
+ var/tesla_power = 20000
+ var/tesla_range = 15
+ var/tesla_boom = FALSE
+ var/chain
+ var/mob/living/caster
+
+/obj/item/projectile/magic/aoe/lightning/fire(setAngle)
+ if(caster)
+ chain = caster.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY)
+ ..()
+
+/obj/item/projectile/magic/aoe/lightning/on_hit(target)
+ . = ..()
+ tesla_zap(src, tesla_range, tesla_power, tesla_boom)
+ qdel(src)
+
+/obj/item/projectile/magic/aoe/lightning/Destroy()
+ qdel(chain)
+ . = ..()
+
+/obj/item/projectile/magic/aoe/fireball
+ name = "bolt of fireball"
+ icon_state = "fireball"
+ damage = 10
+ damage_type = BRUTE
+ nodamage = 0
+
+ //explosion values
+ var/exp_heavy = 0
+ var/exp_light = 2
+ var/exp_flash = 3
+ var/exp_fire = 2
+
+/obj/item/projectile/magic/aoe/fireball/on_hit(target)
+ . = ..()
+ var/turf/T = get_turf(target)
+ explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
+ if(ismob(target)) //multiple flavors of pain
+ var/mob/living/M = target
+ M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
+
+/obj/item/projectile/magic/aoe/fireball/infernal
+ name = "infernal fireball"
+ exp_heavy = -1
+ exp_light = -1
+ exp_flash = 4
+ exp_fire= 5
diff --git a/code/modules/research/designs/AI_module_designs.dm b/code/modules/research/designs/AI_module_designs.dm
index 7f39ffbce5..af2c5b262b 100644
--- a/code/modules/research/designs/AI_module_designs.dm
+++ b/code/modules/research/designs/AI_module_designs.dm
@@ -84,6 +84,15 @@
build_path = /obj/item/weapon/aiModule/reset/purge
category = list("AI Modules")
+/datum/design/board/remove_module
+ name = "Module Design (Law Removal)"
+ desc = "Allows for the construction of a Law Removal AI Core Module."
+ id = "remove_module"
+ req_tech = list("programming" = 5, "materials" = 5)
+ materials = list(MAT_GLASS = 1000, MAT_DIAMOND = 100)
+ build_path = /obj/item/weapon/aiModule/remove
+ category = list("AI Modules")
+
/datum/design/board/freeformcore_module
name = "AI Core Module (Freeform)"
desc = "Allows for the construction of a Freeform AI Core Module."
@@ -130,11 +139,13 @@
build_path = /obj/item/weapon/aiModule/core/full/corp
category = list("AI Modules")
-/datum/design/board/custom_module
- name = "Core Module Design (Custom)"
- desc = "Allows for the construction of a Custom AI Core Module."
- id = "custom_module"
+/datum/design/board/default_module
+ name = "Core Module Design (Default)"
+ desc = "Allows for the construction of a Default AI Core Module."
+ id = "default_module"
req_tech = list("programming" = 5, "materials" = 5)
materials = list(MAT_GLASS = 1000, MAT_DIAMOND = 100)
build_path = /obj/item/weapon/aiModule/core/full/custom
category = list("AI Modules")
+
+
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 4600af491f..528fd77298 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -344,7 +344,7 @@
if(MT)
visible_message("[src] dangerously overheats, launching a flaming fuel orb!")
investigate_log("Experimentor has launched a fireball at [M]!", "experimentor")
- var/obj/item/projectile/magic/fireball/FB = new /obj/item/projectile/magic/fireball(start)
+ var/obj/item/projectile/magic/aoe/fireball/FB = new /obj/item/projectile/magic/aoe/fireball(start)
FB.original = MT
FB.current = start
FB.yo = MT.y - start.y
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 079c16671e..af4cd2063b 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -212,6 +212,8 @@
else
return
+ SSshuttle.emergencyCallAmount++
+
if(prob(70))
SSshuttle.emergencyLastCallLoc = signalOrigin
else
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index ee88e2e79c..b2dbd4f04f 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -11,6 +11,21 @@
return 0
. = ..()
+/obj/machinery/atmospherics/onShuttleMove()
+ . = ..()
+ for(DEVICE_TYPE_LOOP)
+ if(get_area(nodes[I]) != get_area(src))
+ nullifyNode(I)
+
+#define DIR_CHECK_TURF_AREA(X) (get_area(get_ranged_target_turf(src, X, 1)) != A)
+/obj/structure/cable/onShuttleMove()
+ . = ..()
+ var/A = get_area(src)
+ //cut cables on the edge
+ if(DIR_CHECK_TURF_AREA(NORTH) || DIR_CHECK_TURF_AREA(SOUTH) || DIR_CHECK_TURF_AREA(EAST) || DIR_CHECK_TURF_AREA(WEST))
+ cut_cable_from_powernet()
+#undef DIR_CHECK_TURF_AREA
+
/atom/movable/light/onShuttleMove()
return 0
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 979f2623f4..a5545c91cd 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -316,9 +316,9 @@
I = image("icon"='icons/mob/human_parts.dmi', "icon_state"="[species_id]_[body_zone]", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
else
if(should_draw_gender)
- I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]_[icon_gender]", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
+ I = image("icon"='icons/mob/augments.dmi', "icon_state"="[icon_state]_[icon_gender]", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
else
- I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
+ I = image("icon"='icons/mob/augments.dmi', "icon_state"="[icon_state]", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
standing += I
return standing
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index bd01b14c21..8e5197ef60 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -35,6 +35,8 @@
var/turf/target_turf = get_turf(src)
for(var/i in 1 to t_range-1)
var/turf/new_turf = get_step(target_turf, direction)
+ if(!new_turf)
+ break
target_turf = new_turf
if(new_turf.density)
break
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index 6d0001c421..653a131144 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -158,3 +158,34 @@
flash2.forceMove(user.loc)
flash2 = null
..()
+
+
+
+
+/obj/item/bodypart/l_arm/robot/surplus
+ name = "surplus prosthetic left arm"
+ desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
+ icon = 'icons/mob/augments.dmi'
+ icon_state = "surplus_l_arm"
+ max_damage = 20
+
+/obj/item/bodypart/r_arm/robot/surplus
+ name = "surplus prosthetic right arm"
+ desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
+ icon = 'icons/mob/augments.dmi'
+ icon_state = "surplus_r_arm"
+ max_damage = 20
+
+/obj/item/bodypart/l_leg/robot/surplus
+ name = "surplus prosthetic leg"
+ desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
+ icon = 'icons/mob/augments.dmi'
+ icon_state = "surplus_l_leg"
+ max_damage = 20
+
+/obj/item/bodypart/r_leg/robot/surplus
+ name = "surplus prosthetic leg"
+ desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
+ icon = 'icons/mob/augments.dmi'
+ icon_state = "surplus_r_leg"
+ max_damage = 20
\ No newline at end of file
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 7316a188ce..3342ef840c 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -664,6 +664,7 @@
/obj/item/organ/tongue/robot
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
+ status = ORGAN_ROBOTIC
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
@@ -807,6 +808,7 @@
name = "robotic eyes"
icon_state = "cybernetic_eyeballs"
desc = "Your vision is augmented."
+ status = ORGAN_ROBOTIC
/obj/item/organ/eyes/robotic/emp_act(severity)
if(!owner)
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 15a54b6e13..8385403efc 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -20,7 +20,7 @@
var/oldname = target.real_name
target.real_name = target.dna.species.random_name(target.gender,1)
var/newname = target.real_name //something about how the code handles names required that I use this instead of target.real_name
- user.visible_message("[user] alters [oldname]'s appearance completely, [target.p_they()] are now [newname]!", "You alter [oldname]'s appearance completely, [target.p_they()] are now [newname].")
+ user.visible_message("[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!", "You alter [oldname]'s appearance completely, [target.p_they()] is now [newname].")
if(ishuman(target))
var/mob/living/carbon/human/H = target
H.sec_hud_set_ID()
diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm
index 65507a3091..56300c2545 100644
--- a/code/modules/uplink/uplink_item.dm
+++ b/code/modules/uplink/uplink_item.dm
@@ -638,6 +638,7 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
desc = "A highly experimental bioterror agent which creates dormant nodules to be etched into the grey matter of the brain. On death, these nodules take control of the dead body, causing limited revivification, along with slurred speech, aggression, and the ability to infect others with this agent."
item = /obj/item/weapon/storage/box/syndie_kit/romerol
cost = 25
+ cant_discount = TRUE
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/gang)
/datum/uplink_item/stealthy_weapons/dart_pistol
@@ -1166,6 +1167,14 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
category = "Role-Restricted"
exclude_modes = list(/datum/game_mode/nuclear)
+/datum/uplink_item/role_restricted/reverse_revolver
+ name = "Reverse Revolver"
+ desc = "A revolver that always fires at its user. \"Accidentally\" drop your weapon, then watch as the greedy corporate pigs blow their own brains all over the wall. \
+ The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Honk."
+ cost = 14
+ item = /obj/item/weapon/gun/ballistic/revolver/reverse
+ restricted_roles = list("Clown")
+
/datum/uplink_item/role_restricted/ez_clean_bundle
name = "EZ Clean Grenade Bundle"
desc = "A box with three cleaner grenades using the trademark Waffle Co. formula. Serves as a cleaner and causes acid damage to anyone standing nearby. The acid only affects carbon-based creatures."
@@ -1174,6 +1183,17 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
surplus = 20
restricted_roles = list("Janitor")
+/datum/uplink_item/role_restricted/his_grace
+ name = "His Grace"
+ desc = "An incredibly dangerous weapon recovered from a station overcome by the grey tide. Once activated, it will thirst for blood and must be used to kill in order to sate that thirst. \
+ His Grace grants benefits to its wielder, with a more intense hunger equaling more benefits, but be wary: if it gets too hungry, it will kill you and destroy your body. \
+ If you leave His Grace alone for some time, it will eventually return to its inactive state. \
+ To activate His Grace, place five assorted organs inside of it and use it in your hand."
+ item = /obj/item/weapon/storage/toolbox/artistic/his_grace
+ cost = 20
+ restricted_roles = list("Chaplain")
+ surplus = 5 //Very low chance to get it in a surplus crate even without being the chaplain
+
// Pointless
/datum/uplink_item/badass
category = "(Pointless) Badassery"
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index 9c28b5e624..74c8e1647e 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -97,9 +97,7 @@
user << "It's on fire!"
var/healthpercent = (obj_integrity/max_integrity) * 100
switch(healthpercent)
- if(100 to INFINITY)
- user << "It seems pristine and undamaged."
- if(50 to 100)
+ if(50 to 99)
user << "It looks slightly damaged."
if(25 to 50)
user << "It appears heavily damaged."