diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 35b70bdb84..d33eaa35da 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -6,7 +6,8 @@
#define PLANE_SPACE -95
#define PLANE_SPACE_PARALLAX -90
-#define GAME_PLANE 0
+#define GAME_PLANE -1
+#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
#define SPACE_LAYER 1.8
#define ABOVE_SPACE_LAYER 1.9
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index 49ccb411fc..a9807a599c 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -74,6 +74,10 @@ GLOBAL_PROTECT(config_dir)
if(copytext(L, 1, 2) == "#")
continue
+ var/lockthis = copytext(L, 1, 2) == "@"
+ if(lockthis)
+ L = copytext(L, 2)
+
var/pos = findtext(L, " ")
var/entry = null
var/value = null
@@ -96,6 +100,9 @@ GLOBAL_PROTECT(config_dir)
log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
continue
+ if(lockthis)
+ E.protection |= CONFIG_ENTRY_LOCKED
+
var/validated = E.ValidateAndSet(value)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
diff --git a/code/datums/action.dm b/code/datums/action.dm
index a65294fa40..cf1046ca8f 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -591,3 +591,50 @@
var/mob/M = owner
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
+
+/datum/action/innate/dash
+ name = "Dash"
+ desc = "Teleport to the targeted location."
+ icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "jetboot"
+ var/charged = TRUE
+ var/charge_rate = 250
+ var/mob/living/carbon/human/holder
+ var/obj/item/dashing_item
+ var/dash_sound = 'sound/magic/blink.ogg'
+ var/recharge_sound = 'sound/magic/charge.ogg'
+ var/beam_effect = "blur"
+ var/phasein = /obj/effect/temp_visual/dir_setting/ninja/phase
+ var/phaseout = /obj/effect/temp_visual/dir_setting/ninja/phase/out
+
+/datum/action/innate/dash/Grant(mob/user, obj/dasher)
+ . = ..()
+ dashing_item = dasher
+ holder = user
+
+/datum/action/innate/dash/IsAvailable()
+ if(charged)
+ return TRUE
+ else
+ return FALSE
+
+/datum/action/innate/dash/Activate()
+ dashing_item.attack_self(holder) //Used to toggle dash behavior in the dashing item
+
+/datum/action/innate/dash/proc/Teleport(mob/user, atom/target)
+ var/turf/T = get_turf(target)
+ if(target in view(user.client.view, get_turf(user)))
+ var/obj/spot1 = new phaseout(get_turf(user), user.dir)
+ user.forceMove(T)
+ playsound(T, dash_sound, 25, 1)
+ var/obj/spot2 = new phasein(get_turf(user), user.dir)
+ spot1.Beam(spot2,beam_effect,time=20)
+ charged = FALSE
+ holder.update_action_buttons_icon()
+ addtimer(CALLBACK(src, .proc/charge), charge_rate)
+
+/datum/action/innate/dash/proc/charge()
+ charged = TRUE
+ holder.update_action_buttons_icon()
+ playsound(dashing_item, recharge_sound, 50, 1)
+ to_chat(holder, "[dashing_item] is ready for another jaunt.")
\ No newline at end of file
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index 25b04b4312..20d218f767 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -384,3 +384,31 @@
if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"])
owner.stun_absorption -= "blooddrunk"
+/datum/status_effect/sword_spin
+ id = "Bastard Sword Spin"
+ duration = 50
+ tick_interval = 8
+ alert_type = null
+
+
+/datum/status_effect/sword_spin/on_apply()
+ owner.visible_message("[owner] begins swinging the sword with inhuman strength!")
+ var/oldcolor = owner.color
+ owner.color = "#ff0000"
+ owner.add_stun_absorption("bloody bastard sword", duration, 2, "doesn't even flinch as the sword's power courses through them!", "You shrug off the stun!", " glowing with a blazing red aura!")
+ owner.spin(duration,1)
+ animate(owner, color = oldcolor, time = duration, easing = EASE_IN)
+ addtimer(CALLBACK(owner, /atom/proc/update_atom_colour), duration)
+ playsound(owner, 'sound/weapons/fwoosh.wav', 75, 0)
+ return ..()
+
+
+/datum/status_effect/sword_spin/tick()
+ playsound(owner, 'sound/weapons/fwoosh.wav', 75, 0)
+ var/obj/item/slashy
+ slashy = owner.get_active_held_item()
+ for(var/mob/living/M in orange(1,owner))
+ slashy.attack(M, owner)
+
+/datum/status_effect/sword_spin/on_remove()
+ owner.visible_message("[owner]'s inhuman strength dissipates and the sword's runes grow cold!")
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index 55f8ece5e6..876cace14d 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -72,6 +72,170 @@
if(is_servant_of_ratvar(C) && C.reagents)
C.reagents.add_reagent("heparin", 1)
+/obj/item/twohanded/required/cult_bastard
+ name = "bloody bastard sword"
+ desc = "An enormous sword used by Nar-Sien cultists to rapidly harvest the souls of non-believers."
+ w_class = WEIGHT_CLASS_HUGE
+ block_chance = 50
+ throwforce = 20
+ force = 35
+ armour_penetration = 45
+ throw_speed = 1
+ throw_range = 3
+ sharpness = IS_SHARP
+ light_color = "#ff0000"
+ attack_verb = list("cleaved", "slashed", "torn", "hacked", "ripped", "diced", "carved")
+ icon_state = "cultbastard"
+ item_state = "cultbastard"
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
+ inhand_x_dimension = 64
+ inhand_y_dimension = 64
+ actions_types = list()
+ flags_2 = SLOWS_WHILE_IN_HAND_2
+ var/datum/action/innate/dash/cult/jaunt
+ var/datum/action/innate/cult/spin2win/linked_action
+ var/spinning = FALSE
+ var/spin_cooldown = 250
+ var/list/shards = list()
+ var/dash_toggled = TRUE
+
+/obj/item/twohanded/required/cult_bastard/Initialize()
+ . = ..()
+ set_light(4)
+ jaunt = new(src)
+ linked_action = new(src)
+
+/obj/item/twohanded/required/cult_bastard/can_be_pulled(user)
+ return FALSE
+
+/obj/item/twohanded/required/cult_bastard/attack_self(mob/user)
+ dash_toggled = !dash_toggled
+ if(dash_toggled)
+ to_chat(loc, "You raise the [src] and prepare to jaunt with it.")
+ else
+ to_chat(loc, "You lower the [src] and prepare to swing it normally.")
+
+/obj/item/twohanded/required/cult_bastard/pickup(mob/living/user)
+ . = ..()
+ if(!iscultist(user))
+ if(!is_servant_of_ratvar(user))
+ to_chat(user, "\"I wouldn't advise that.\"")
+ to_chat(user, "An overwhelming sense of nausea overpowers you!")
+ user.Dizzy(80)
+ user.Knockdown(30)
+ return
+ else
+ to_chat(user, "\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"")
+ to_chat(user, "A horrible force yanks at your arm!")
+ user.emote("scream")
+ user.apply_damage(30, BRUTE, pick("l_arm", "r_arm"))
+ user.Knockdown(50)
+ return
+ jaunt.Grant(user, src)
+ linked_action.Grant(user, src)
+ user.update_icons()
+
+/obj/item/twohanded/required/cult_bastard/dropped(mob/user)
+ . = ..()
+ linked_action.Remove(user)
+ jaunt.Remove(user)
+ user.update_icons()
+
+/obj/item/twohanded/required/cult_bastard/IsReflect()
+ if(spinning)
+ playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
+ return TRUE
+ else
+ ..()
+
+/obj/item/twohanded/required/cult_bastard/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(prob(final_block_chance))
+ if(attack_type == PROJECTILE_ATTACK)
+ owner.visible_message("[owner] deflects [attack_text] with [src]!")
+ playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 100, 1)
+ return TRUE
+ else
+ playsound(src, 'sound/weapons/parry.ogg', 75, 1)
+ owner.visible_message("[owner] parries [attack_text] with [src]!")
+ return TRUE
+ return FALSE
+
+/obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
+ . = ..()
+ if(dash_toggled && jaunt.IsAvailable())
+ jaunt.Teleport(user, target)
+ return
+ if(!proximity)
+ return
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(H.stat != CONSCIOUS)
+ var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src)
+ SS.attack(H, user)
+ shards += SS
+ return
+ if(istype(target, /obj/structure/constructshell) && contents.len)
+ var/obj/item/device/soulstone/SS = contents[1]
+ if(istype(SS) && SS.transfer_soul("CONSTRUCT",target,user))
+ qdel(SS)
+
+/datum/action/innate/dash/cult
+ name = "Rend the Veil"
+ desc = "Use the sword to shear open the flimsy fabric of this reality and teleport to your target."
+ icon_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon_state = "phaseshift"
+ dash_sound = 'sound/magic/enter_blood.ogg'
+ recharge_sound = 'sound/magic/exit_blood.ogg'
+ beam_effect = "sendbeam"
+ phasein = /obj/effect/temp_visual/dir_setting/cult/phase
+ phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
+
+/datum/action/innate/dash/cult/IsAvailable()
+ if(iscultist(holder) && charged)
+ return TRUE
+ else
+ return FALSE
+
+
+
+/datum/action/innate/cult/spin2win
+ name = "Geometer's Fury"
+ desc = "You draw on the power of the sword's ancient runes, spinning it wildly around you as you become immune to most attacks."
+ background_icon_state = "bg_demon"
+ button_icon_state = "sintouch"
+ var/cooldown = 0
+ var/mob/living/carbon/human/holder
+ var/obj/item/twohanded/required/cult_bastard/sword
+
+/datum/action/innate/cult/spin2win/Grant(mob/user, obj/bastard)
+ . = ..()
+ sword = bastard
+ holder = user
+
+/datum/action/innate/cult/spin2win/IsAvailable()
+ if(iscultist(holder) && cooldown <= world.time)
+ return TRUE
+ else
+ return FALSE
+
+/datum/action/innate/cult/spin2win/Activate()
+ cooldown = world.time + sword.spin_cooldown
+ holder.changeNext_move(50)
+ holder.apply_status_effect(/datum/status_effect/sword_spin)
+ sword.spinning = TRUE
+ sword.block_chance = 100
+ sword.slowdown += 1.5
+ addtimer(CALLBACK(src, .proc/stop_spinning), 50)
+ holder.update_action_buttons_icon()
+
+/datum/action/innate/cult/spin2win/proc/stop_spinning()
+ sword.spinning = FALSE
+ sword.block_chance = 50
+ sword.slowdown -= 1.5
+ sleep(sword.spin_cooldown)
+ holder.update_action_buttons_icon()
/obj/item/restraints/legcuffs/bola/cult
name = "nar'sien bola"
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index c1ccf9a368..0144872c17 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -100,15 +100,21 @@
if(cooldowntime > world.time)
to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].")
return
- var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Nar-Sien Hardsuit")
+ var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Bastard Sword")
var/pickedtype
switch(choice)
if("Shielded Robe")
pickedtype = /obj/item/clothing/suit/hooded/cultrobes/cult_shield
if("Flagellant's Robe")
pickedtype = /obj/item/clothing/suit/hooded/cultrobes/berserker
- if("Nar-Sien Hardsuit")
- pickedtype = /obj/item/clothing/suit/space/hardsuit/cult
+ if("Bastard Sword")
+ if((world.time - SSticker.round_start_time) >= 12000)
+ pickedtype = /obj/item/twohanded/required/cult_bastard
+ else
+ cooldowntime = 12000 - (world.time - SSticker.round_start_time)
+ to_chat(user, "The forge fires are not yet hot enough for this weapon, give it another [DisplayTimeText(cooldowntime - world.time)].")
+ cooldowntime = 0
+ return
if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
cooldowntime = world.time + 2400
var/obj/item/N = new pickedtype(get_turf(src))
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index df57ded774..149c2ae912 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -199,7 +199,6 @@
SSticker.mode.cult -= A.mind
SSticker.mode.update_cult_icons_removed(A.mind)
qdel(T)
- user.drop_item()
qdel(src)
else
to_chat(user, "Creation failed!: The soul stone is empty! Go kill someone!")
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index dc6993cdbe..28856e17d8 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -156,6 +156,24 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
var/unholy2clean = A.reagents.get_reagent_amount("unholywater")
A.reagents.del_reagent("unholywater")
A.reagents.add_reagent("holywater",unholy2clean)
+ if(istype(A, /obj/item/twohanded/required/cult_bastard))
+ var/obj/item/twohanded/required/cult_bastard/sword = A
+ to_chat(user, "You begin to exorcise [sword].")
+ playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,1)
+ if(do_after(user, 40, target = sword))
+ playsound(src,'sound/effects/pray_chaplain.ogg',60,1)
+ for(var/obj/item/device/soulstone/SS in sword.shards)
+ SS.usability = TRUE
+ for(var/mob/living/simple_animal/shade/EX in SS)
+ SSticker.mode.remove_cultist(EX.mind, 1, 0)
+ EX.icon_state = "ghost1"
+ EX.name = "Purified [EX.name]"
+ SS.release_shades(user)
+ qdel(SS)
+ new /obj/item/nullrod/claymore(get_turf(sword))
+ user.visible_message("[user] has purified the [sword]!!")
+ qdel(sword)
+
/obj/item/storage/book/bible/booze
desc = "To be applied to the head repeatedly."
diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm
index 935b62f46a..5c36c5a6ba 100644
--- a/code/game/objects/structures/beds_chairs/bed.dm
+++ b/code/game/objects/structures/beds_chairs/bed.dm
@@ -21,6 +21,10 @@
var/buildstacktype = /obj/item/stack/sheet/metal
var/buildstackamount = 2
+/obj/structure/bed/examine(mob/user)
+ ..()
+ to_chat(user, "It's held together by a couple of bolts.")
+
/obj/structure/bed/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(buildstacktype)
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index aed1679322..9d6985c620 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -1,6 +1,6 @@
/obj/structure/chair
name = "chair"
- desc = "You sit in this. Either by will or force.\nDrag your sprite to sit in the chair. Alt-click to rotate it clockwise."
+ desc = "You sit in this. Either by will or force."
icon = 'icons/obj/chairs.dmi'
icon_state = "chair"
anchored = TRUE
@@ -14,6 +14,14 @@
var/item_chair = /obj/item/chair // if null it can't be picked up
layer = OBJ_LAYER
+/obj/structure/chair/examine(mob/user)
+ ..()
+ to_chat(user, "It's held together by a couple of bolts.")
+ if(!has_buckled_mobs())
+ to_chat(user, "Drag your sprite to sit in it. Alt-click to rotate.")
+ else
+ to_chat(user, "Alt-click to rotate.")
+
/obj/structure/chair/Initialize()
. = ..()
if(!anchored) //why would you put these on the shuttle?
@@ -140,7 +148,7 @@
/obj/structure/chair/comfy
name = "comfy chair"
- desc = "It looks comfy.\nAlt-click to rotate it clockwise."
+ desc = "It looks comfy."
icon_state = "comfychair"
color = rgb(255,255,255)
resistance_flags = FLAMMABLE
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index c7b63be32b..3d77be1bb5 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -76,8 +76,12 @@
/obj/structure/closet/examine(mob/user)
..()
+ if(welded)
+ to_chat(user, "It's welded shut.")
if(anchored)
- to_chat(user, "It is anchored to the ground.")
+ to_chat(user, "It is bolted to the ground.")
+ if(opened)
+ to_chat(user, "The parts are welded together.")
else if(secure && !opened)
to_chat(user, "Alt-click to [locked ? "unlock" : "lock"].")
@@ -453,4 +457,4 @@
/obj/structure/closet/return_temperature()
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 914be24cfd..1683ac00e6 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -1,5 +1,5 @@
/obj/structure/grille
- desc = "A flimsy lattice of metal rods, with screws to secure it to the floor."
+ desc = "A flimsy framework of metal rods."
name = "grille"
icon = 'icons/obj/structures.dmi'
icon_state = "grille"
@@ -17,6 +17,13 @@
var/grille_type = null
var/broken_type = /obj/structure/grille/broken
+/obj/structure/grille/examine(mob/user)
+ ..()
+ if(anchored)
+ to_chat(user, "It's secured in place with screws. The rods look like they could be cut through.")
+ if(!anchored)
+ to_chat(user, "The anchoring screws are unscrewed. The rods look like they could be cut through.")
+
/obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
switch(the_rcd.mode)
if(RCD_DECONSTRUCT)
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index d578b307db..c0dcd866d8 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -16,6 +16,13 @@
smooth = SMOOTH_MORE
// flags_1 = CONDUCT_1
+/obj/structure/lattice/examine(mob/user)
+ ..()
+ deconstruction_hints(user)
+
+/obj/structure/lattice/proc/deconstruction_hints(mob/user)
+ to_chat(user, "The rods look like they could be cut. There's space for more rods or a tile.")
+
/obj/structure/lattice/Initialize(mapload)
. = ..()
for(var/obj/structure/lattice/LAT in loc)
@@ -79,6 +86,9 @@
smooth = SMOOTH_TRUE
canSmoothWith = null
+/obj/structure/lattice/catwalk/deconstruction_hints(mob/user)
+ to_chat(user, "The supporting rods look like they could be cut.")
+
/obj/structure/lattice/catwalk/ratvar_act()
new /obj/structure/lattice/catwalk/clockwork(loc)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 116ced183f..c54661066a 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -34,6 +34,13 @@
smooth = SMOOTH_TRUE
canSmoothWith = list(/obj/structure/table, /obj/structure/table/reinforced)
+/obj/structure/table/examine(mob/user)
+ ..()
+ deconstruction_hints(user)
+
+/obj/structure/table/proc/deconstruction_hints(mob/user)
+ to_chat(user, "The top is screwed on, but the main bolts are also visible.")
+
/obj/structure/table/Initialize()
. = ..()
for(var/obj/structure/table/T in src.loc)
@@ -285,7 +292,7 @@
*/
/obj/structure/table/reinforced
name = "reinforced table"
- desc = "A reinforced version of the four legged table, much harder to simply deconstruct."
+ desc = "A reinforced version of the four legged table."
icon = 'icons/obj/smooth_structures/reinforced_table.dmi'
icon_state = "r_table"
deconstruction_ready = 0
@@ -295,6 +302,12 @@
integrity_failure = 50
armor = list(melee = 10, bullet = 30, laser = 30, energy = 100, bomb = 20, bio = 0, rad = 0, fire = 80, acid = 70)
+/obj/structure/table/reinforced/deconstruction_hints(mob/user)
+ if(deconstruction_ready)
+ to_chat(user, "The top cover has been welded loose and the main frame's bolts are exposed.")
+ else
+ to_chat(user, "The top cover is firmly welded on.")
+
/obj/structure/table/reinforced/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool))
var/obj/item/weldingtool/WT = W
@@ -405,6 +418,10 @@
pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.
max_integrity = 20
+/obj/structure/rack/examine(mob/user)
+ ..()
+ to_chat(user, "It's held together by a couple of bolts.")
+
/obj/structure/rack/CanPass(atom/movable/mover, turf/target)
if(src.density == 0) //Because broken racks -Agouri |TODO: SPRITE!|
return 1
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 02206646d2..97634f7629 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -161,10 +161,10 @@
broken = 0
burnt = 0
if(user && !silent)
- to_chat(user, "You remove the broken plating.")
+ to_chat(user, "You remove the broken plating.")
else
if(user && !silent)
- to_chat(user, "You remove the floor tile.")
+ to_chat(user, "You remove the floor tile.")
if(floor_tile && make_tile)
new floor_tile(src)
return make_plating()
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index a24642c735..428c965197 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -8,10 +8,15 @@
*/
/turf/open/floor/wood
+ desc = "Stylish dark wood."
icon_state = "wood"
floor_tile = /obj/item/stack/tile/wood
broken_states = list("wood-broken", "wood-broken2", "wood-broken3", "wood-broken4", "wood-broken5", "wood-broken6", "wood-broken7")
+/turf/open/floor/wood/examine(mob/user)
+ ..()
+ to_chat(user, "There's a few screws and a small crack visible.")
+
/turf/open/floor/wood/attackby(obj/item/C, mob/user, params)
if(..())
return
@@ -42,16 +47,16 @@
broken = 0
burnt = 0
if(user && !silent)
- to_chat(user, "You remove the broken planks.")
+ to_chat(user, "You remove the broken planks.")
else
if(make_tile)
if(user && !silent)
- to_chat(user, "You unscrew the planks.")
+ to_chat(user, "You unscrew the planks.")
if(floor_tile)
new floor_tile(src)
else
if(user && !silent)
- to_chat(user, "You forcefully pry off the planks, destroying them in the process.")
+ to_chat(user, "You forcefully pry off the planks, destroying them in the process.")
return make_plating()
/turf/open/floor/wood/cold
@@ -78,7 +83,7 @@
if(istype(C, /obj/item/shovel) && params)
new ore_type(src)
new ore_type(src) //Make some sand if you shovel grass
- user.visible_message("[user] digs up [src].", "You [src.turfverb] [src].")
+ user.visible_message("[user] digs up [src].", "You [src.turfverb] [src].")
playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1)
make_plating()
if(..())
@@ -143,6 +148,10 @@
canSmoothWith = list(/turf/open/floor/carpet)
flags_1 = NONE
+/turf/open/floor/carpet/examine(mob/user)
+ ..()
+ to_chat(user, "There's a small crack on the edge of it.")
+
/turf/open/floor/carpet/Initialize()
. = ..()
update_icon()
diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm
index 247382d03c..0dd3673f6a 100644
--- a/code/game/turfs/simulated/floor/light_floor.dm
+++ b/code/game/turfs/simulated/floor/light_floor.dm
@@ -12,6 +12,10 @@
var/can_modify_colour = TRUE
+/turf/open/floor/light/examine(mob/user)
+ ..()
+ to_chat(user, "There's a small crack on the edge of it.")
+
/turf/open/floor/light/Initialize()
. = ..()
update_icon()
diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm
index 63c883f88c..b194127de8 100644
--- a/code/game/turfs/simulated/floor/plasteel_floor.dm
+++ b/code/game/turfs/simulated/floor/plasteel_floor.dm
@@ -4,6 +4,10 @@
broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
burnt_states = list("floorscorched1", "floorscorched2")
+/turf/open/floor/plasteel/examine(mob/user)
+ ..()
+ to_chat(user, "There's a small crack on the edge of it.")
+
/turf/open/floor/plasteel/update_icon()
if(!..())
return 0
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 8ad6657784..3e16da8b9f 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -12,6 +12,13 @@
icon_state = "plating"
intact = FALSE
+/turf/open/floor/plating/examine(mob/user)
+ ..()
+ if(broken || burnt)
+ to_chat(user, "It looks like the dents could be welded smooth.")
+ return
+ to_chat(user, "There are few attachment holes for a new tile or reinforcement rods.")
+
/turf/open/floor/plating/Initialize()
if (!broken_states)
broken_states = list("platingdmg1", "platingdmg2", "platingdmg3")
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index 2649a3a14d..848a7e8219 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -193,7 +193,7 @@
var/list/L = list(45)
if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
- L += -45
+ L -= 45
// Expand the edges of our tunnel
for(var/edge_angle in L)
diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm
index 04c97aa7d5..74354e78c7 100644
--- a/code/game/turfs/simulated/floor/reinf_floor.dm
+++ b/code/game/turfs/simulated/floor/reinf_floor.dm
@@ -1,11 +1,16 @@
/turf/open/floor/engine
name = "reinforced floor"
+ desc = "Extremely sturdy."
icon_state = "engine"
thermal_conductivity = 0.025
heat_capacity = INFINITY
floor_tile = /obj/item/stack/rods
+/turf/open/floor/engine/examine(mob/user)
+ ..()
+ to_chat(user, "The reinforcement rods are wrenched firmly in place.")
+
/turf/open/floor/engine/airless
initial_gas_mix = "TEMP=2.7"
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index ae5f5c2fbb..33f02bc759 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -25,6 +25,21 @@
var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/book) //Things allowed in the bookcase
+/obj/structure/bookcase/examine(mob/user)
+ ..()
+ if(!anchored)
+ to_chat(user, "The bolts on the bottom are unsecured.")
+ if(anchored)
+ to_chat(user, "It's secured in place with bolts.")
+ switch(state)
+ if(0)
+ to_chat(user, "There's a small crack visible on the back panel.")
+ if(1)
+ to_chat(user, "There's space inside for a wooden shelf.")
+ if(2)
+ to_chat(user, "There's a small crack visible on the shelf.")
+
+
/obj/structure/bookcase/Initialize(mapload)
. = ..()
if(!mapload)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 6068ef2d66..d90db23679 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -250,6 +250,9 @@
if(health >= 0 && !(status_flags & FAKEDEATH))
if(lying)
+ if(buckled)
+ to_chat(M, "You need to unbuckle [src] first to do that!")
+ return
M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \
"You shake [src] trying to get [p_them()] up!")
else if(check_zone(M.zone_selected) == "head")
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 70a5f5225c..63b84b9cf3 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -4,6 +4,7 @@
voice_name = "Unknown"
icon = 'icons/mob/human.dmi'
icon_state = "caucasian_m"
+ appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE
/mob/living/carbon/human/Initialize()
verbs += /mob/living/proc/mob_sleep
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index ef044e462b..84bf5bdf80 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -37,7 +37,7 @@
if(H.nutrition > NUTRITION_LEVEL_FULL)
H.nutrition = NUTRITION_LEVEL_FULL
if(light_amount > 0.2) //if there's enough light, heal
- H.heal_overall_damage(0.05,0)
+ H.heal_overall_damage(0.75,0)
H.adjustOxyLoss(-0.5)
if(H.nutrition < NUTRITION_LEVEL_STARVING + 55)
diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm
index 4ce8570c2b..016a3635ef 100644
--- a/code/modules/mob/living/carbon/human/species_types/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm
@@ -37,6 +37,7 @@
C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW
if(regen_cooldown < world.time)
C.heal_overall_damage(4,4)
+ C.adjustToxLoss(-4)
if(prob(4))
playsound(C, pick(spooks), 50, TRUE, 10)
if(C.InCritical())
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm
index 259ca4327d..325b971171 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm
@@ -86,7 +86,7 @@
if(istype(head, /obj/item/clothing/mask))
used_head_icon = 'icons/mob/mask.dmi'
var/mutable_appearance/head_overlay = head.build_worn_icon(state = head.icon_state, default_layer = DRONE_HEAD_LAYER, default_icon_file = used_head_icon)
- head_overlay.pixel_y += -15
+ head_overlay.pixel_y -= 15
drone_overlays[DRONE_HEAD_LAYER] = head_overlay
diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm
index 62b8cee415..8eaaa40097 100644
--- a/code/modules/ninja/suit/gloves.dm
+++ b/code/modules/ninja/suit/gloves.dm
@@ -63,7 +63,7 @@
if(isnum(.)) //Numerical values of drained handle their feedback here, Alpha values handle it themselves (Research hacking)
if(.)
- to_chat(H, "Gained [.] energy from \the [A].")
+ to_chat(H, "Gained [DisplayPower(.)] of energy from [A].")
else
to_chat(H, "\The [A] has run dry of power, you must find another source!")
else
diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm
index 603f8843ca..5ee2ecec05 100644
--- a/code/modules/projectiles/guns/misc/blastcannon.dm
+++ b/code/modules/projectiles/guns/misc/blastcannon.dm
@@ -12,21 +12,17 @@
randomspread = FALSE
var/obj/item/device/transfer_valve/bomb
- var/datum/gas_mixture/air1
- var/datum/gas_mixture/air2
/obj/item/gun/blastcannon/New()
if(!pin)
pin = new
- . = ..()
+ return ..()
/obj/item/gun/blastcannon/Destroy()
if(bomb)
qdel(bomb)
bomb = null
- air1 = null
- air2 = null
- . = ..()
+ return ..()
/obj/item/gun/blastcannon/attack_self(mob/user)
if(bomb)
@@ -35,7 +31,7 @@
user.visible_message("[user] detaches the [bomb] from the [src]")
bomb = null
update_icon()
- . = ..(user)
+ return ..()
/obj/item/gun/blastcannon/update_icon()
if(bomb)
@@ -46,7 +42,6 @@
icon_state = initial(icon_state)
name = initial(name)
desc = initial(desc)
- . = ..()
/obj/item/gun/blastcannon/attackby(obj/O, mob/user)
if(istype(O, /obj/item/device/transfer_valve))
@@ -59,20 +54,17 @@
return FALSE
user.visible_message("[user] attaches the [O] to the [src]!")
bomb = O
- O.loc = src
+ O.forceMove(src)
update_icon()
return TRUE
- . = ..()
+ return ..()
/obj/item/gun/blastcannon/proc/calculate_bomb()
if(!istype(bomb)||!istype(bomb.tank_one)||!istype(bomb.tank_two))
return 0
- air1 = bomb.tank_one.air_contents
- air2 = bomb.tank_two.air_contents
- var/datum/gas_mixture/temp
- temp.volume = air1.volume + air2.volume
- temp.merge(air1)
- temp.merge(air2)
+ var/datum/gas_mixture/temp = new(60) //directional buff.
+ temp.merge(bomb.tank_one.air_contents.remove_ratio(1))
+ temp.merge(bomb.tank_two.air_contents.remove_ratio(2))
for(var/i in 1 to 6)
temp.react()
var/pressure = temp.return_pressure()
@@ -82,7 +74,7 @@
return (pressure/TANK_FRAGMENT_SCALE)
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
- if((!bomb) || (target == user) || (target.loc == user) || (!target) || (target.loc == user.loc) || (target.loc in range(user, 2)) || (target in range(user, 2)))
+ if((!bomb) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
var/power = calculate_bomb()
qdel(bomb)
@@ -90,13 +82,17 @@
var/heavy = power * 0.2
var/medium = power * 0.5
var/light = power
- user.visible_message("[user] opens \the [bomb] on \his [src.name] and fires a blast wave at \the [target]!","You open \the [bomb] on your [src.name] and fire a blast wave at \the [target]!")
+ user.visible_message("[user] opens \the [bomb] on \his [name] and fires a blast wave at \the [target]!","You open \the [bomb] on your [name] and fire a blast wave at \the [target]!")
playsound(user, "explosion", 100, 1)
var/turf/starting = get_turf(user)
+ var/turf/targturf = get_turf(target)
var/area/A = get_area(user)
- var/log_str = "Blast wave fired at [ADMIN_COORDJMP(starting)] ([A.name]) by [user.name]([user.ckey]) with power [heavy]/[medium]/[light]."
+ var/log_str = "Blast wave fired from [ADMIN_COORDJMP(starting)] ([A.name]) at [ADMIN_COORDJMP(targturf)] ([target.name]) by [user.name]([user.ckey]) with power [heavy]/[medium]/[light]."
message_admins(log_str)
log_game(log_str)
+ var/obj/item/projectile/blastwave/BW = new(loc, heavy, medium, light)
+ BW.preparePixelProjectile(target, get_turf(target), user, params, 0)
+ BW.fire()
/obj/item/projectile/blastwave
name = "blast wave"
@@ -109,6 +105,12 @@
var/lightr = 0
range = 150
+/obj/item/projectile/blastwave/Initialize(mapload, _h, _m, _l)
+ heavyr = _h
+ mediumr = _m
+ lightr = _l
+ return ..()
+
/obj/item/projectile/blastwave/Range()
..()
if(heavyr)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 3aba80fe64..937326a60b 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -90,8 +90,6 @@
new impact_effect_type(target_loca, target, src)
return 0
var/mob/living/L = target
- if(L.buckled && ismob(L.buckled))
- L = L.buckled
if(blocked != 100) // not completely blocked
if(damage && L.blood_volume && damage_type == BRUTE)
var/splatter_dir = dir
@@ -178,6 +176,8 @@
var/mob/living/picked_mob = pick(mobs_list)
if(!prehit(picked_mob))
return FALSE
+ if(ismob(picked_mob.buckled))
+ picked_mob = picked_mob.buckled
picked_mob.bullet_act(src, def_zone)
qdel(src)
return TRUE
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 6f4ae50243..8395ef4d83 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -10,7 +10,7 @@
/obj/item/projectile/bullet/pellet/Range()
..()
- damage += -0.75
+ damage -= 0.75
if(damage < 0)
qdel(src)
@@ -66,7 +66,7 @@
/obj/item/projectile/bullet/c38
name = ".38 bullet"
damage = 15
- knockdown = 30
+ knockdown = 60
stamina = 50
// 10mm (Stechkin)
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 4b939bf4f1..3b83dd8e62 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -44,9 +44,11 @@
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
actions_types = list(/datum/action/item_action/organ_action/use)
+ sight_flags = SEE_BLACKNESS
var/night_vision = TRUE
/obj/item/organ/eyes/night_vision/ui_action_click()
+ sight_flags = initial(sight_flags)
switch(lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
@@ -56,6 +58,7 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
else
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
+ sight_flags &= ~SEE_BLACKNESS
owner.update_sight()
/obj/item/organ/eyes/night_vision/alien
diff --git a/config/config.txt b/config/config.txt
index d5d2725714..72f168dcce 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -1,3 +1,11 @@
+# You can use the @ character at the beginning of a config option to lock it from being edited in-game
+# Example usage:
+# @SERVERNAME tgstation
+# Which sets the SERVERNAME, and disallows admins from being able to change it using View Variables.
+# @LOG_TWITTER 0
+# Which explicitly disables LOG_TWITTER, as well as locking it.
+# There are various options which are hard-locked for security reasons.
+
## Server name: This appears at the top of the screen in-game and in the BYOND hub. Uncomment and replace 'tgstation' with the name of your choice.
# SERVERNAME tgstation
diff --git a/html/changelogs/AutoChangeLog-pr-3041.yml b/html/changelogs/AutoChangeLog-pr-3041.yml
new file mode 100644
index 0000000000..872bbc4b99
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3041.yml
@@ -0,0 +1,5 @@
+author: "Robustin"
+delete-after: True
+changes:
+ - rscadd: "Blood cultists can now create a unique bastard sword at their forge"
+ - rscdel: "Blood cultists can no longer obtain a hardsuit from the forge"
diff --git a/html/changelogs/AutoChangeLog-pr-3105.yml b/html/changelogs/AutoChangeLog-pr-3105.yml
new file mode 100644
index 0000000000..b48644c148
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3105.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - balance: "The detectives gun has been restored from a system change that nerfed knockdown in general. We need to have a serious discussion about anti revolver hate in this community."
diff --git a/html/changelogs/AutoChangeLog-pr-3114.yml b/html/changelogs/AutoChangeLog-pr-3114.yml
new file mode 100644
index 0000000000..abe6380887
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3114.yml
@@ -0,0 +1,4 @@
+author: "Daniel0Mclovin"
+delete-after: True
+changes:
+ - tweak: "Modify health regeneration from 0.05 to 0.75"
diff --git a/html/changelogs/AutoChangeLog-pr-3127.yml b/html/changelogs/AutoChangeLog-pr-3127.yml
new file mode 100644
index 0000000000..050e9cb4d7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3127.yml
@@ -0,0 +1,4 @@
+author: "Raeschen"
+delete-after: True
+changes:
+ - rscadd: "FTL Milky Way added to music"
diff --git a/html/changelogs/AutoChangeLog-pr-3133.yml b/html/changelogs/AutoChangeLog-pr-3133.yml
new file mode 100644
index 0000000000..ac49ae1821
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3133.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - spellcheck: "Beds, chairs, closets, grilles, lattices, catwalks, tables, racks, floors, plating and bookcases now show hints about constructing/deconstructing them."
diff --git a/html/changelogs/AutoChangeLog-pr-3134.yml b/html/changelogs/AutoChangeLog-pr-3134.yml
new file mode 100644
index 0000000000..5b8bcf21b6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3134.yml
@@ -0,0 +1,4 @@
+author: "ShizCalev"
+delete-after: True
+changes:
+ - bugfix: "You now have to unbuckle a player PRIOR to shaking them up off a bed or resin nest."
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
index a9a952733a..1b450ab3e0 100644
Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
index bff96a991b..bbeddf9152 100644
Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi
index 94c0c03835..b5ac65c2a8 100644
Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ
diff --git a/sound/music/milkyway.ogg b/sound/music/milkyway.ogg
new file mode 100644
index 0000000000..59d9ba63f4
Binary files /dev/null and b/sound/music/milkyway.ogg differ
diff --git a/sound/weapons/fwoosh.wav b/sound/weapons/fwoosh.wav
new file mode 100644
index 0000000000..1723c4e9b8
Binary files /dev/null and b/sound/weapons/fwoosh.wav differ
diff --git a/sound/weapons/parry.ogg b/sound/weapons/parry.ogg
new file mode 100644
index 0000000000..1f86716337
Binary files /dev/null and b/sound/weapons/parry.ogg differ
diff --git a/strings/round_start_sounds.txt b/strings/round_start_sounds.txt
index 01323a6120..177f612ee1 100644
--- a/strings/round_start_sounds.txt
+++ b/strings/round_start_sounds.txt
@@ -20,3 +20,4 @@ sound/music/oceanman.ogg
sound/music/indeep.ogg
sound/music/goodbyemoonmen.ogg
sound/music/flytothemoon_otomatone.ogg
+sound/music/milkyway.ogg
\ No newline at end of file