diff --git a/code/datums/ghost_query.dm b/code/datums/ghost_query.dm
index 2857476027..d041558a0c 100644
--- a/code/datums/ghost_query.dm
+++ b/code/datums/ghost_query.dm
@@ -132,3 +132,9 @@
question = "A curious explorer has touched a mysterious rune. \
Would you like to play as the creature it summons?"
cutoff_number = 1
+
+/datum/ghost_query/cursedblade
+ role_name = "Cursed Sword"
+ question = "A cursed blade has been discovered by a curious explorer. \
+ Would you like to play as the soul imprisoned within?"
+ cutoff_number = 1
diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm
index c7212c336d..81f233cdec 100644
--- a/code/game/objects/items/weapons/melee/misc.dm
+++ b/code/game/objects/items/weapons/melee/misc.dm
@@ -50,4 +50,41 @@
// Randomizes color
/obj/item/weapon/melee/umbrella/random/New()
color = "#"+get_random_colour()
- ..()
\ No newline at end of file
+ ..()
+
+/obj/item/weapon/melee/cursedblade
+ name = "crystal blade"
+ desc = "The red crystal blade's polished surface glints in the light, giving off a faint glow."
+ icon_state = "soulblade"
+ slot_flags = SLOT_BELT | SLOT_BACK
+ force = 30
+ throwforce = 10
+ w_class = ITEMSIZE_NORMAL
+ sharp = 1
+ edge = 1
+ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ can_speak = 1
+ var/list/voice_mobs = list() //The curse of the sword is that it has someone trapped inside.
+
+
+/obj/item/weapon/melee/cursedblade/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
+ if(default_parry_check(user, attacker, damage_source) && prob(50))
+ user.visible_message("\The [user] parries [attack_text] with \the [src]!")
+ playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1)
+ return 1
+ return 0
+
+/obj/item/weapon/melee/cursedblade/proc/ghost_inhabit(var/mob/candidate)
+ if(!isobserver(candidate))
+ return
+ //Handle moving the ghost into the new shell.
+ announce_ghost_joinleave(candidate, 0, "They are occupying a cursed sword now.")
+ var/mob/living/voice/new_voice = new /mob/living/voice(src) //Make the voice mob the ghost is going to be.
+ new_voice.transfer_identity(candidate) //Now make the voice mob load from the ghost's active character in preferences.
+ new_voice.mind = candidate.mind //Transfer the mind, if any.
+ new_voice.ckey = candidate.ckey //Finally, bring the client over.
+ new_voice.name = "cursed sword" //Cursed swords shouldn't be known characters.
+ new_voice.real_name = "cursed sword"
+ voice_mobs.Add(new_voice)
+ listening_objects |= src
\ No newline at end of file
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 3833133f4a..31d5189ddb 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -13,6 +13,7 @@
var/armor_penetration = 0
var/show_messages
var/preserve_item = 0 //whether this object is preserved when its owner goes into cryo-storage, gateway, etc
+ var/can_speak = 0 //For MMIs and admin trickery. If an object has a brainmob in its contents, set this to 1 to allow it to speak.
var/show_examine = TRUE // Does this pop up on a mob when the mob is examined?
diff --git a/code/game/objects/structures/ghost_pods/ghost_pods.dm b/code/game/objects/structures/ghost_pods/ghost_pods.dm
index 03cc4bec3f..16dcd2ddb7 100644
--- a/code/game/objects/structures/ghost_pods/ghost_pods.dm
+++ b/code/game/objects/structures/ghost_pods/ghost_pods.dm
@@ -10,12 +10,14 @@
var/needscharger //For drone pods that want their pod to turn into a charger.
// Call this to get a ghost volunteer.
-/obj/structure/ghost_pod/proc/trigger()
+/obj/structure/ghost_pod/proc/trigger(var/alert, var/adminalert)
if(!ghost_query_type)
return FALSE
if(busy)
return FALSE
+ visible_message(alert)
+ log_and_message_admins(adminalert)
busy = TRUE
var/datum/ghost_query/Q = new ghost_query_type()
var/list/winner = Q.query()
@@ -44,7 +46,7 @@
/obj/structure/ghost_pod/manual/attack_hand(var/mob/living/user)
if(!used)
if(confirm_before_open)
- if(alert(user, "Are you sure you want to open \the [src]?", "Confirm", "No", "Yes") == "No")
+ if(alert(user, "Are you sure you want to touch \the [src]?", "Confirm", "No", "Yes") == "No")
return
trigger()
diff --git a/code/game/objects/structures/ghost_pods/silicon.dm b/code/game/objects/structures/ghost_pods/silicon.dm
index 4e954afd4e..1e7210a1ec 100644
--- a/code/game/objects/structures/ghost_pods/silicon.dm
+++ b/code/game/objects/structures/ghost_pods/silicon.dm
@@ -13,9 +13,7 @@
needscharger = TRUE
/obj/structure/ghost_pod/manual/lost_drone/trigger()
- ..()
- visible_message("\The [src] appears to be attempting to restart the robot contained inside.")
- log_and_message_admins("is attempting to open \a [src].")
+ ..("\The [src] appears to be attempting to restart the robot contained inside.", "is attempting to open \a [src].")
/obj/structure/ghost_pod/manual/lost_drone/create_occupant(var/mob/M)
density = FALSE
@@ -68,14 +66,13 @@
description_info = "This will summon some manner of creature through quite dubious means. The creature will be controlled by a player."
icon_state = "corgirune"
icon_state_opened = "corgirune-inert"
- density = TRUE
+ density = FALSE
+ anchored = TRUE
ghost_query_type = /datum/ghost_query/corgi_rune
confirm_before_open = TRUE
/obj/structure/ghost_pod/manual/corgi/trigger()
- ..()
- visible_message("\The [usr] places their hand on the rune!")
- log_and_message_admins("is attempting to summon a corgi.")
+ ..("\The [usr] places their hand on the rune!", "is attempting to summon a corgi.")
/obj/structure/ghost_pod/manual/corgi/create_occupant(var/mob/M)
density = FALSE
@@ -86,4 +83,29 @@
R.ckey = M.ckey
visible_message("With a bright flash of light, \the [src] disappears, and in its place stands a small corgi.")
log_and_message_admins("successfully touched \a [src] and summoned a corgi.")
+ ..()
+
+/obj/structure/ghost_pod/manual/cursedblade
+ name = "abandoned blade"
+ desc = "A red crystal blade that someone jammed deep into a stone. If you try hard enough, you might be able to remove it."
+ icon_state = "soulblade-embedded"
+ icon_state_opened = "soulblade-released"
+ density = TRUE
+ anchored = TRUE
+ ghost_query_type = /datum/ghost_query/cursedblade
+ confirm_before_open = TRUE
+
+/obj/structure/ghost_pod/manual/cursedblade/trigger()
+ ..("\The [usr] attempts to pull out the sword!", "is activating a cursed blade.")
+
+/obj/structure/ghost_pod/manual/cursedblade/create_occupant(var/mob/M)
+ density = FALSE
+ var/obj/item/weapon/melee/cursedblade/R = new(get_turf(src))
+ to_chat(M, "You are a Cursed Sword, discovered by a hapless explorer. \
+ You were once an explorer yourself, when one day you discovered a strange sword made from a red crystal. As soon as you touched it,\
+ your body was reduced to ashes and your soul was cursed to remain trapped in the blade forever. \
+ Now it is up to you to decide whether you want to be a faithful companion, or a bitter prisoner of the blade.")
+ R.ghost_inhabit(M)
+ visible_message("The blade shines brightly for a brief moment as [usr] pulls it out of the stone!")
+ log_and_message_admins("successfully acquired a cursed sword.")
..()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 1aaa236446..07f65f62b5 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -6,6 +6,7 @@
icon = 'icons/obj/assemblies.dmi'
icon_state = "mmi_empty"
w_class = ITEMSIZE_NORMAL
+ can_speak = 1
origin_tech = list(TECH_BIO = 3)
req_access = list(access_robotics)
diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm
index 8797cd596a..a09d8ce3e5 100644
--- a/code/modules/mob/living/carbon/brain/say.dm
+++ b/code/modules/mob/living/carbon/brain/say.dm
@@ -5,8 +5,8 @@
message = sanitize(message)
- if(!(container && istype(container, /obj/item/device/mmi)))
- return //No MMI, can't speak, bucko./N
+ if(!(container && container.can_speak))
+ return //Certain objects can speak, like MMIs. Most others cannot. -Q
else
var/datum/language/speaking = parse_language(message)
if(speaking)
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index 415c4cd5a8..601d40b4dc 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/items/lefthand_melee.dmi b/icons/mob/items/lefthand_melee.dmi
index 9c5b5d72ee..790d93eca6 100644
Binary files a/icons/mob/items/lefthand_melee.dmi and b/icons/mob/items/lefthand_melee.dmi differ
diff --git a/icons/mob/items/righthand_melee.dmi b/icons/mob/items/righthand_melee.dmi
index 85e99773f7..8c1068a033 100644
Binary files a/icons/mob/items/righthand_melee.dmi and b/icons/mob/items/righthand_melee.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 230f4f8821..bb968eec1b 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index 20ec01a737..8adc02e3b5 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/maps/submaps/surface_submaps/mountains/SwordCave.dmm b/maps/submaps/surface_submaps/mountains/SwordCave.dmm
new file mode 100644
index 0000000000..8c15e58da8
--- /dev/null
+++ b/maps/submaps/surface_submaps/mountains/SwordCave.dmm
@@ -0,0 +1,55 @@
+"a" = (/turf/template_noop,/area/template_noop)
+"b" = (/turf/simulated/mineral,/area/submap/cave/swordcave)
+"c" = (/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"d" = (/obj/machinery/crystal,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"e" = (/turf/simulated/floor/water,/area/submap/cave/swordcave)
+"f" = (/turf/simulated/floor/water/deep,/area/submap/cave/swordcave)
+"g" = (/obj/structure/ghost_pod/manual/cursedblade,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"h" = (/mob/living/simple_animal/hostile/faithless/cult,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"i" = (/obj/item/device/gps/explorer,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"j" = (/obj/structure/loot_pile/surface/bones,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+"k" = (/mob/living/simple_animal/hostile/scarybat/cult,/turf/simulated/mineral/floor/ignore_mapgen,/area/submap/cave/swordcave)
+
+(1,1,1) = {"
+aaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaa
+aaaaabbbbbbbbbbbcccdccccbbbbbbbbbbbbaaaaa
+aaaabbbbbbcccccccccccccccccccccbbbbbbaaaa
+aaabbbbbbcccccccccccccccccccccccdbbbbbaaa
+aabbbbccccccceeeeeeeeeeeeeccccccccbbbbbaa
+aabbbccccccceeeeeeeeeeeeeeeccccccccbbbbaa
+aabbbcdcccceeeffffffffffffeeeccccccbbbbaa
+aabbbccccceefeeeeeeefeeeeeeeeecccccbbbbaa
+aabbbccccceefeeccceeeeeeeefffeeccccbbbaaa
+aabbbcccceeffeecccccecccceefffeecccbbbaaa
+aabbbcccceeffeeeccgcccchcceeffeecccbbbaaa
+aabbbcccdeeffeeccijcdccccceefeeccdcbbbaaa
+abbbccccceefffeeeccccccceeefeeccccccbbaaa
+abbbcccccceefffeeeccccceeeffeeccccccbbbaa
+abbbcdccccceefffeeeeeeeeffffeeccccccbbbaa
+abbcccckcccceeffffeeeeefffffeeccccccbbbaa
+abbcccccccccceeffffffffffffeeccccdccbbbaa
+abbccccccccccceeffeeeeeefffeecccccccbbbaa
+abbbccccdcccccceefeeeeeeeeeeckccccccbbbaa
+abbbcccccccccccceeecccdceeecccccccccbbaaa
+abbbcccccccccccccecccccccceccccdckccbbaaa
+abbbcccccccccckcccccccccccccccccccccbbaaa
+abbbbcccccckccccccccccccccckccccccccbbaaa
+abbbbbcccccccccccccccckccccccccckcccbbaaa
+aabbbbbccccccccccccccccccccccccccccbbbaaa
+aabbbbbccccccccccccdccccccccccccccbbbbaaa
+aabbbbbcccccdccccccccccccccccccccbbbbbaaa
+aabbbbbccccccccccckccccccccdcccccbbbbaaaa
+aabbbbbbbccccccccccccccccccccccccbbbbaaaa
+aaabbbbbbbcccccccccccccccdccccccbbbbaaaaa
+aaaabbbbbbcckcccccdcccccccccccccbbbbaaaaa
+aaaaabbbbbcccccccccccccccccccccbbbbbaaaaa
+aaaaabbbbbccccccccccccccccccccbbbbbaaaaaa
+aaaaaabbbbbcccdccccccccccccccbbbbbaaaaaaa
+aaaaaaabbbbbcccccccckccccckcbbbbbbaaaaaaa
+aaaaaaabbbbbbcccccccccccccccbbbbbaaaaaaaa
+aaaaaaabbbbbbbbbbbbccccccccccbbbaaaaaaaaa
+aaaaaaaaabbbbbbbbbbbccccccccccbaaaaaaaaaa
+aaaaaaaaaaabbbbbbbbbbccccccccccaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaacccdccccaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaccccccaaaaaaaaaaaa
+"}
diff --git a/maps/submaps/surface_submaps/mountains/mountains.dm b/maps/submaps/surface_submaps/mountains/mountains.dm
index 58fdce2971..c661b94bec 100644
--- a/maps/submaps/surface_submaps/mountains/mountains.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains.dm
@@ -27,6 +27,7 @@
#include "IceCave1A.dmm"
#include "IceCave1B.dmm"
#include "IceCave1C.dmm"
+#include "SwordCave.dmm"
#include "SupplyDrop1.dmm"
#include "BlastMine1.dmm"
#endif
@@ -171,6 +172,11 @@
mappath = 'maps/submaps/surface_submaps/mountains/IceCave1C.dmm'
cost = 10
+/datum/map_template/surface/mountains/normal/SwordCave
+ name = "Cursed Sword Cave"
+ desc = "An underground lake. The sword on the lake's island holds a terrible secret."
+ mappath = 'maps/submaps/surface_submaps/mountains/SwordCave.dmm'
+
/datum/map_template/surface/mountains/normal/supplydrop1
name = "Supply Drop 1"
desc = "A drop pod that landed deep within the mountains."
diff --git a/maps/submaps/surface_submaps/mountains/mountains_areas.dm b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
index e17290aa3a..2555b558f9 100644
--- a/maps/submaps/surface_submaps/mountains/mountains_areas.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
@@ -76,13 +76,13 @@
name = "Ice Cave 1B"
/area/submap/cave/IceCave1C
-
name = "Ice Cave 1C"
- name = "Mine Vault"
+
+/area/submap/cave/swordcave
+ name = "Cursed Sword Cave"
/area/submap/cave/SupplyDrop1
name = "Supply Drop 1"
/area/submap/cave/BlastMine1
- name = "Blast Mine 1"
-
+ name = "Blast Mine 1"
\ No newline at end of file