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