diff --git a/code/datums/action.dm b/code/datums/action.dm
index cf1046ca8f..60a0722f0f 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -592,49 +592,3 @@
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/dash_weapon.dm b/code/datums/dash_weapon.dm
new file mode 100644
index 0000000000..1637655d18
--- /dev/null
+++ b/code/datums/dash_weapon.dm
@@ -0,0 +1,50 @@
+/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/current_charges = 1
+ var/max_charges = 1
+ 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(current_charges > 0)
+ 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)
+ if(!IsAvailable())
+ return
+ 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)
+ current_charges--
+ holder.update_action_buttons_icon()
+ addtimer(CALLBACK(src, .proc/charge), charge_rate)
+
+/datum/action/innate/dash/proc/charge()
+ current_charges = Clamp(current_charges + 1, 0, max_charges)
+ holder.update_action_buttons_icon()
+ if(recharge_sound)
+ playsound(dashing_item, recharge_sound, 50, 1)
+ to_chat(holder, "[src] now has [current_charges]/[max_charges] charges.")
\ No newline at end of file
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index 876cace14d..a3da1c6cbe 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -98,7 +98,6 @@
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()
@@ -174,11 +173,12 @@
if(H.stat != CONSCIOUS)
var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src)
SS.attack(H, user)
- shards += SS
- return
+ if(!LAZYLEN(SS.contents))
+ qdel(SS)
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))
+ if(istype(SS))
+ SS.transfer_soul("CONSTRUCT",target,user)
qdel(SS)
/datum/action/innate/dash/cult
@@ -193,7 +193,7 @@
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
/datum/action/innate/dash/cult/IsAvailable()
- if(iscultist(holder) && charged)
+ if(iscultist(holder) && current_charges)
return TRUE
else
return FALSE
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 0144872c17..8140dffe53 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -112,7 +112,7 @@
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)].")
+ to_chat(user, "The forge fires are not yet hot enough for this weapon, give it another [DisplayTimeText(cooldowntime)].")
cooldowntime = 0
return
if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 02d835da16..6c073f4b69 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -1,7 +1,7 @@
/obj/item/stack/medical
name = "medical pack"
singular_name = "medical pack"
- icon = 'icons/obj/items_and_weapons.dmi'
+ icon = 'icons/obj/stack_objects.dmi'
amount = 6
max_amount = 6
w_class = WEIGHT_CLASS_TINY
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 8056674074..2bb5d110fc 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -63,7 +63,7 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
/obj/item/stack/sheet/mineral/sandbags
name = "sandbags"
- icon = 'icons/obj/items_and_weapons.dmi'
+ icon = 'icons/obj/stack_objects.dmi'
icon_state = "sandbags"
singular_name = "sandbag"
layer = LOW_ITEM_LAYER
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 3a79ce23db..6e7ffddeb3 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -8,6 +8,7 @@
* Stacks
*/
/obj/item/stack
+ icon = 'icons/obj/stack_objects.dmi'
origin_tech = "materials=1"
gender = PLURAL
var/list/datum/stack_recipe/recipes
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index 28856e17d8..c0c861f4c4 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -162,7 +162,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
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)
+ for(var/obj/item/device/soulstone/SS in sword.contents)
SS.usability = TRUE
for(var/mob/living/simple_animal/shade/EX in SS)
SSticker.mode.remove_cultist(EX.mind, 1, 0)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index 5b8c40a976..bb44f22752 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -307,7 +307,7 @@
/obj/item/melee/supermatter_sword,
/obj/item/shield/changeling,
/obj/item/lava_staff,
- /obj/item/dash/energy_katana,
+ /obj/item/energy_katana,
/obj/item/hierophant_club,
/obj/item/his_grace,
/obj/item/gun/ballistic/minigun,
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index db47d43bd5..9f31c5b055 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -1,493 +1,509 @@
-//The code execution of the emote datum is located at code/datums/emotes.dm
-/mob/living/emote(act, m_type = null, message = null)
- act = lowertext(act)
- var/param = message
- var/custom_param = findchar(act, " ")
- if(custom_param)
- param = copytext(act, custom_param + 1, length(act) + 1)
- act = copytext(act, 1, custom_param)
-
- var/datum/emote/E
- E = E.emote_list[act]
- if(!E)
- to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
- return
- E.run_emote(src, param, m_type)
-
-/* EMOTE DATUMS */
-/datum/emote/living
- mob_type_allowed_typecache = list(/mob/living)
- mob_type_blacklist_typecache = list(/mob/living/simple_animal/slime, /mob/living/brain)
-
-/datum/emote/living/blush
- key = "blush"
- key_third_person = "blushes"
- message = "blushes."
-
-/datum/emote/living/bow
- key = "bow"
- key_third_person = "bows"
- message = "bows."
- message_param = "bows to %t."
-
-/datum/emote/living/burp
- key = "burp"
- key_third_person = "burps"
- message = "burps."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/choke
- key = "choke"
- key_third_person = "chokes"
- message = "chokes!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/cross
- key = "cross"
- key_third_person = "crosses"
- message = "crosses their arms."
- restraint_check = TRUE
-
-/datum/emote/living/chuckle
- key = "chuckle"
- key_third_person = "chuckles"
- message = "chuckles."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/collapse
- key = "collapse"
- key_third_person = "collapses"
- message = "collapses!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/collapse/run_emote(mob/user, params)
- . = ..()
- if(. && isliving(user))
- var/mob/living/L = user
- L.Unconscious(40)
-
-/datum/emote/living/cough
- key = "cough"
- key_third_person = "coughs"
- message = "coughs!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/dance
- key = "dance"
- key_third_person = "dances"
- message = "dances around happily."
- restraint_check = TRUE
-
-/datum/emote/living/deathgasp
- key = "deathgasp"
- key_third_person = "deathgasps"
- message = "seizes up and falls limp, their eyes dead and lifeless..."
- message_robot = "shudders violently for a moment before falling still, its eyes slowly darkening."
- message_AI = "lets out a flurry of sparks, its screen flickering as its systems slowly halt."
- message_alien = "lets out a waning guttural screech, green blood bubbling from its maw..."
- message_larva = "lets out a sickly hiss of air and falls limply to the floor..."
- message_monkey = "lets out a faint chimper as it collapses and stops moving..."
- message_simple = "stops moving..."
- stat_allowed = UNCONSCIOUS
-
-/datum/emote/living/deathgasp/run_emote(mob/user, params)
- var/mob/living/simple_animal/S = user
- if(istype(S) && S.deathmessage)
- message_simple = S.deathmessage
- . = ..()
- message_simple = initial(message_simple)
- if(. && isalienadult(user))
- playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
-
-/datum/emote/living/drool
- key = "drool"
- key_third_person = "drools"
- message = "drools."
-
-/datum/emote/living/faint
- key = "faint"
- key_third_person = "faints"
- message = "faints."
-
-/datum/emote/living/faint/run_emote(mob/user, params)
- . = ..()
- if(. && isliving(user))
- var/mob/living/L = user
- L.SetSleeping(200)
-
-/datum/emote/living/flap
- key = "flap"
- key_third_person = "flaps"
- message = "flaps their wings."
- var/wing_time = 20
-
-/datum/emote/living/flap/run_emote(mob/user, params)
- . = ..()
- if(. && ishuman(user))
- var/mob/living/carbon/human/H = user
- var/open = FALSE
- if(H.dna.features["wings"] != "None")
- if("wingsopen" in H.dna.species.mutant_bodyparts)
- open = TRUE
- H.CloseWings()
- else
- H.OpenWings()
- addtimer(CALLBACK(H, open ? /mob/living/carbon/human.proc/OpenWings : /mob/living/carbon/human.proc/CloseWings), wing_time)
-
-/datum/emote/living/flap/aflap
- key = "aflap"
- key_third_person = "aflaps"
- message = "flaps their wings ANGRILY!"
- wing_time = 10
-
-/datum/emote/living/flip
- key = "flip"
- key_third_person = "flips"
- restraint_check = TRUE
-
-/datum/emote/living/flip/run_emote(mob/user, params)
- . = ..()
- if(!.)
- user.SpinAnimation(7,1)
-
-/datum/emote/living/frown
- key = "frown"
- key_third_person = "frowns"
- message = "frowns."
-
-/datum/emote/living/gag
- key = "gag"
- key_third_person = "gags"
- message = "gags."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/gasp
- key = "gasp"
- key_third_person = "gasps"
- message = "gasps!"
- emote_type = EMOTE_AUDIBLE
- stat_allowed = UNCONSCIOUS
-
-/datum/emote/living/giggle
- key = "giggle"
- key_third_person = "giggles"
- message = "giggles."
- message_mime = "giggles silently!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/glare
- key = "glare"
- key_third_person = "glares"
- message = "glares."
- message_param = "glares at %t."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/grin
- key = "grin"
- key_third_person = "grins"
- message = "grins."
-
-/datum/emote/living/groan
- key = "groan"
- key_third_person = "groans"
- message = "groans!"
- message_mime = "appears to groan!"
-
-/datum/emote/living/grimace
- key = "grimace"
- key_third_person = "grimaces"
- message = "grimaces."
-
-/datum/emote/living/jump
- key = "jump"
- key_third_person = "jumps"
- message = "jumps!"
- restraint_check = TRUE
-
-/datum/emote/living/kiss
- key = "kiss"
- key_third_person = "kisses"
- message = "blows a kiss."
- message_param = "blows a kiss to %t."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/laugh
- key = "laugh"
- key_third_person = "laughs"
- message = "laughs."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/look
- key = "look"
- key_third_person = "looks"
- message = "looks."
- message_param = "looks at %t."
-
-/datum/emote/living/nod
- key = "nod"
- key_third_person = "nods"
- message = "nods."
- message_param = "nods at %t."
-
-/datum/emote/living/point
- key = "point"
- key_third_person = "points"
- message = "points."
- message_param = "points at %t."
- restraint_check = TRUE
-
-/datum/emote/living/pout
- key = "pout"
- key_third_person = "pouts"
- message = "pouts."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/scream
- key = "scream"
- key_third_person = "screams"
- message = "screams."
- message_mime = "acts out a scream!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/scowl
- key = "scowl"
- key_third_person = "scowls"
- message = "scowls."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/shake
- key = "shake"
- key_third_person = "shakes"
- message = "shakes their head."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/shiver
- key = "shiver"
- key_third_person = "shiver"
- message = "shivers."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/sigh
- key = "sigh"
- key_third_person = "sighs"
- message = "sighs."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/sit
- key = "sit"
- key_third_person = "sits"
- message = "sits down."
-
-/datum/emote/living/smile
- key = "smile"
- key_third_person = "smiles"
- message = "smiles."
-
-/datum/emote/living/sneeze
- key = "sneeze"
- key_third_person = "sneezes"
- message = "sneezes."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/smug
- key = "smug"
- key_third_person = "smugs"
- message = "grins smugly."
-
-/datum/emote/living/sniff
- key = "sniff"
- key_third_person = "sniffs"
- message = "sniffs."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/snore
- key = "snore"
- key_third_person = "snores"
- message = "snores."
- message_mime = "sleeps soundly."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/stare
- key = "stare"
- key_third_person = "stares"
- message = "stares."
- message_param = "stares at %t."
-
-/datum/emote/living/strech
- key = "stretch"
- key_third_person = "stretches"
- message = "stretches their arms."
-
-/datum/emote/living/sulk
- key = "sulk"
- key_third_person = "sulks"
- message = "sulks down sadly."
-
-/datum/emote/living/surrender
- key = "surrender"
- key_third_person = "surrenders"
+//The code execution of the emote datum is located at code/datums/emotes.dm
+/mob/living/emote(act, m_type = null, message = null)
+ act = lowertext(act)
+ var/param = message
+ var/custom_param = findchar(act, " ")
+ if(custom_param)
+ param = copytext(act, custom_param + 1, length(act) + 1)
+ act = copytext(act, 1, custom_param)
+
+ var/datum/emote/E
+ E = E.emote_list[act]
+ if(!E)
+ to_chat(src, "Unusable emote '[act]'. Say *help for a list.")
+ return
+ E.run_emote(src, param, m_type)
+
+/* EMOTE DATUMS */
+/datum/emote/living
+ mob_type_allowed_typecache = list(/mob/living)
+ mob_type_blacklist_typecache = list(/mob/living/simple_animal/slime, /mob/living/brain)
+
+/datum/emote/living/blush
+ key = "blush"
+ key_third_person = "blushes"
+ message = "blushes."
+
+/datum/emote/living/bow
+ key = "bow"
+ key_third_person = "bows"
+ message = "bows."
+ message_param = "bows to %t."
+
+/datum/emote/living/burp
+ key = "burp"
+ key_third_person = "burps"
+ message = "burps."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/choke
+ key = "choke"
+ key_third_person = "chokes"
+ message = "chokes!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/cross
+ key = "cross"
+ key_third_person = "crosses"
+ message = "crosses their arms."
+ restraint_check = TRUE
+
+/datum/emote/living/chuckle
+ key = "chuckle"
+ key_third_person = "chuckles"
+ message = "chuckles."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/collapse
+ key = "collapse"
+ key_third_person = "collapses"
+ message = "collapses!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/collapse/run_emote(mob/user, params)
+ . = ..()
+ if(. && isliving(user))
+ var/mob/living/L = user
+ L.Unconscious(40)
+
+/datum/emote/living/cough
+ key = "cough"
+ key_third_person = "coughs"
+ message = "coughs!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/dance
+ key = "dance"
+ key_third_person = "dances"
+ message = "dances around happily."
+ restraint_check = TRUE
+
+/datum/emote/living/deathgasp
+ key = "deathgasp"
+ key_third_person = "deathgasps"
+ message = "seizes up and falls limp, their eyes dead and lifeless..."
+ message_robot = "shudders violently for a moment before falling still, its eyes slowly darkening."
+ message_AI = "lets out a flurry of sparks, its screen flickering as its systems slowly halt."
+ message_alien = "lets out a waning guttural screech, green blood bubbling from its maw..."
+ message_larva = "lets out a sickly hiss of air and falls limply to the floor..."
+ message_monkey = "lets out a faint chimper as it collapses and stops moving..."
+ message_simple = "stops moving..."
+ stat_allowed = UNCONSCIOUS
+
+/datum/emote/living/deathgasp/run_emote(mob/user, params)
+ var/mob/living/simple_animal/S = user
+ if(istype(S) && S.deathmessage)
+ message_simple = S.deathmessage
+ . = ..()
+ message_simple = initial(message_simple)
+ if(. && isalienadult(user))
+ playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
+
+/datum/emote/living/drool
+ key = "drool"
+ key_third_person = "drools"
+ message = "drools."
+
+/datum/emote/living/faint
+ key = "faint"
+ key_third_person = "faints"
+ message = "faints."
+
+/datum/emote/living/faint/run_emote(mob/user, params)
+ . = ..()
+ if(. && isliving(user))
+ var/mob/living/L = user
+ L.SetSleeping(200)
+
+/datum/emote/living/flap
+ key = "flap"
+ key_third_person = "flaps"
+ message = "flaps their wings."
+ var/wing_time = 20
+
+/datum/emote/living/flap/run_emote(mob/user, params)
+ . = ..()
+ if(. && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/open = FALSE
+ if(H.dna.features["wings"] != "None")
+ if("wingsopen" in H.dna.species.mutant_bodyparts)
+ open = TRUE
+ H.CloseWings()
+ else
+ H.OpenWings()
+ addtimer(CALLBACK(H, open ? /mob/living/carbon/human.proc/OpenWings : /mob/living/carbon/human.proc/CloseWings), wing_time)
+
+/datum/emote/living/flap/aflap
+ key = "aflap"
+ key_third_person = "aflaps"
+ message = "flaps their wings ANGRILY!"
+ wing_time = 10
+
+/datum/emote/living/flip
+ key = "flip"
+ key_third_person = "flips"
+ restraint_check = TRUE
+
+/datum/emote/living/flip/run_emote(mob/user, params)
+ . = ..()
+ if(!.)
+ user.SpinAnimation(7,1)
+
+/datum/emote/living/frown
+ key = "frown"
+ key_third_person = "frowns"
+ message = "frowns."
+
+/datum/emote/living/gag
+ key = "gag"
+ key_third_person = "gags"
+ message = "gags."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/gasp
+ key = "gasp"
+ key_third_person = "gasps"
+ message = "gasps!"
+ emote_type = EMOTE_AUDIBLE
+ stat_allowed = UNCONSCIOUS
+
+/datum/emote/living/giggle
+ key = "giggle"
+ key_third_person = "giggles"
+ message = "giggles."
+ message_mime = "giggles silently!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/glare
+ key = "glare"
+ key_third_person = "glares"
+ message = "glares."
+ message_param = "glares at %t."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/grin
+ key = "grin"
+ key_third_person = "grins"
+ message = "grins."
+
+/datum/emote/living/groan
+ key = "groan"
+ key_third_person = "groans"
+ message = "groans!"
+ message_mime = "appears to groan!"
+
+/datum/emote/living/grimace
+ key = "grimace"
+ key_third_person = "grimaces"
+ message = "grimaces."
+
+/datum/emote/living/jump
+ key = "jump"
+ key_third_person = "jumps"
+ message = "jumps!"
+ restraint_check = TRUE
+
+/datum/emote/living/kiss
+ key = "kiss"
+ key_third_person = "kisses"
+ message = "blows a kiss."
+ message_param = "blows a kiss to %t."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/laugh
+ key = "laugh"
+ key_third_person = "laughs"
+ message = "laughs."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/laugh/can_run_emote(mob/living/user)
+ . = ..()
+ if(. && iscarbon(user))
+ var/mob/living/carbon/C = user
+ return !C.silent
+
+/datum/emote/living/laugh/run_emote(mob/user, params)
+ . = ..()
+ if(. && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.dna.species.id == "human")
+ if(user.gender == FEMALE)
+ playsound(H, 'sound/voice/human/womanlaugh.ogg', 50, 1)
+ else
+ playsound(H, pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg'), 50, 1)
+
+/datum/emote/living/look
+ key = "look"
+ key_third_person = "looks"
+ message = "looks."
+ message_param = "looks at %t."
+
+/datum/emote/living/nod
+ key = "nod"
+ key_third_person = "nods"
+ message = "nods."
+ message_param = "nods at %t."
+
+/datum/emote/living/point
+ key = "point"
+ key_third_person = "points"
+ message = "points."
+ message_param = "points at %t."
+ restraint_check = TRUE
+
+/datum/emote/living/pout
+ key = "pout"
+ key_third_person = "pouts"
+ message = "pouts."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/scream
+ key = "scream"
+ key_third_person = "screams"
+ message = "screams."
+ message_mime = "acts out a scream!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/scowl
+ key = "scowl"
+ key_third_person = "scowls"
+ message = "scowls."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/shake
+ key = "shake"
+ key_third_person = "shakes"
+ message = "shakes their head."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/shiver
+ key = "shiver"
+ key_third_person = "shiver"
+ message = "shivers."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/sigh
+ key = "sigh"
+ key_third_person = "sighs"
+ message = "sighs."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/sit
+ key = "sit"
+ key_third_person = "sits"
+ message = "sits down."
+
+/datum/emote/living/smile
+ key = "smile"
+ key_third_person = "smiles"
+ message = "smiles."
+
+/datum/emote/living/sneeze
+ key = "sneeze"
+ key_third_person = "sneezes"
+ message = "sneezes."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/smug
+ key = "smug"
+ key_third_person = "smugs"
+ message = "grins smugly."
+
+/datum/emote/living/sniff
+ key = "sniff"
+ key_third_person = "sniffs"
+ message = "sniffs."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/snore
+ key = "snore"
+ key_third_person = "snores"
+ message = "snores."
+ message_mime = "sleeps soundly."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/stare
+ key = "stare"
+ key_third_person = "stares"
+ message = "stares."
+ message_param = "stares at %t."
+
+/datum/emote/living/strech
+ key = "stretch"
+ key_third_person = "stretches"
+ message = "stretches their arms."
+
+/datum/emote/living/sulk
+ key = "sulk"
+ key_third_person = "sulks"
+ message = "sulks down sadly."
+
+/datum/emote/living/surrender
+ key = "surrender"
+ key_third_person = "surrenders"
message = "puts their hands on their head and falls to the ground, they surrender!"
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/surrender/run_emote(mob/user, params)
- . = ..()
- if(. && isliving(user))
- var/mob/living/L = user
- L.Knockdown(200)
-
-/datum/emote/living/sway
- key = "sway"
- key_third_person = "sways"
- message = "sways around dizzily."
-
-/datum/emote/living/tremble
- key = "tremble"
- key_third_person = "trembles"
- message = "trembles in fear!"
-
-/datum/emote/living/twitch
- key = "twitch"
- key_third_person = "twitches"
- message = "twitches violently."
-
-/datum/emote/living/twitch_s
- key = "twitch_s"
- message = "twitches."
-
-/datum/emote/living/wave
- key = "wave"
- key_third_person = "waves"
- message = "waves."
-
-/datum/emote/living/whimper
- key = "whimper"
- key_third_person = "whimpers"
- message = "whimpers."
- message_mime = "appears hurt."
-
-/datum/emote/living/wsmile
- key = "wsmile"
- key_third_person = "wsmiles"
- message = "smiles weakly."
-
-/datum/emote/living/yawn
- key = "yawn"
- key_third_person = "yawns"
- message = "yawns."
- emote_type = EMOTE_AUDIBLE
-
-/datum/emote/living/custom
- key = "me"
- key_third_person = "custom"
- message = null
-
-/datum/emote/living/custom/proc/check_invalid(mob/user, input)
- . = TRUE
- if(copytext(input,1,5) == "says")
- to_chat(user, "Invalid emote.")
- else if(copytext(input,1,9) == "exclaims")
- to_chat(user, "Invalid emote.")
- else if(copytext(input,1,6) == "yells")
- to_chat(user, "Invalid emote.")
- else if(copytext(input,1,5) == "asks")
- to_chat(user, "Invalid emote.")
- else
- . = FALSE
-
-/datum/emote/living/custom/run_emote(mob/user, params, type_override = null)
- if(jobban_isbanned(user, "emote"))
- to_chat(user, "You cannot send custom emotes (banned).")
- return FALSE
- else if(user.client && user.client.prefs.muted & MUTE_IC)
- to_chat(user, "You cannot send IC messages (muted).")
- return FALSE
- else if(!params)
- var/custom_emote = copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
- if(custom_emote && !check_invalid(user, custom_emote))
- var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
- switch(type)
- if("Visible")
- emote_type = EMOTE_VISIBLE
- if("Hearable")
- emote_type = EMOTE_AUDIBLE
- else
- alert("Unable to use this emote, must be either hearable or visible.")
- return
- message = custom_emote
- else
- message = params
- if(type_override)
- emote_type = type_override
- . = ..()
- message = null
- emote_type = EMOTE_VISIBLE
-
-/datum/emote/living/custom/replace_pronoun(mob/user, message)
- return message
-
-/datum/emote/living/help
- key = "help"
-
-/datum/emote/living/help/run_emote(mob/user, params)
- var/list/keys = list()
- var/list/message = list("Available emotes, you can use them with say \"*emote\": ")
-
- var/datum/emote/E
- var/list/emote_list = E.emote_list
- for(var/e in emote_list)
- if(e in keys)
- continue
- E = emote_list[e]
- if(E.can_run_emote(user, TRUE))
- keys += E.key
-
- keys = sortList(keys)
-
- for(var/emote in keys)
- if(LAZYLEN(message) > 1)
- message += ", [emote]"
- else
- message += "[emote]"
-
- message += "."
-
- message = jointext(message, "")
-
- to_chat(user, message)
-
-/datum/emote/sound/beep
- key = "beep"
- key_third_person = "beeps"
- message = "beeps."
- message_param = "beeps at %t."
- sound = 'sound/machines/twobeep.ogg'
-
-/datum/emote/living/spin
- key = "spin"
- key_third_person = "spins"
-
-/datum/emote/living/spin/run_emote(mob/user)
- user.spin(20, 1)
- if(iscyborg(user))
- var/mob/living/silicon/robot/R = user
- if(R.buckled_mobs)
- for(var/mob/M in R.buckled_mobs)
- if(R.riding_datum)
- R.riding_datum.force_dismount(M)
- else
- R.unbuckle_all_mobs()
- ..()
-
-/datum/emote/living/circle
- key = "circle"
- key_third_person = "circles"
- restraint_check = TRUE
-
-/datum/emote/living/circle/run_emote(mob/user, params)
- . = ..()
- var/obj/item/circlegame/N = new(user)
- if(user.put_in_hands(N))
- to_chat(user, "You make a circle with your hand.")
- else
- qdel(N)
- to_chat(user, "You don't have any free hands to make a circle with.")
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/surrender/run_emote(mob/user, params)
+ . = ..()
+ if(. && isliving(user))
+ var/mob/living/L = user
+ L.Knockdown(200)
+
+/datum/emote/living/sway
+ key = "sway"
+ key_third_person = "sways"
+ message = "sways around dizzily."
+
+/datum/emote/living/tremble
+ key = "tremble"
+ key_third_person = "trembles"
+ message = "trembles in fear!"
+
+/datum/emote/living/twitch
+ key = "twitch"
+ key_third_person = "twitches"
+ message = "twitches violently."
+
+/datum/emote/living/twitch_s
+ key = "twitch_s"
+ message = "twitches."
+
+/datum/emote/living/wave
+ key = "wave"
+ key_third_person = "waves"
+ message = "waves."
+
+/datum/emote/living/whimper
+ key = "whimper"
+ key_third_person = "whimpers"
+ message = "whimpers."
+ message_mime = "appears hurt."
+
+/datum/emote/living/wsmile
+ key = "wsmile"
+ key_third_person = "wsmiles"
+ message = "smiles weakly."
+
+/datum/emote/living/yawn
+ key = "yawn"
+ key_third_person = "yawns"
+ message = "yawns."
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/custom
+ key = "me"
+ key_third_person = "custom"
+ message = null
+
+/datum/emote/living/custom/proc/check_invalid(mob/user, input)
+ . = TRUE
+ if(copytext(input,1,5) == "says")
+ to_chat(user, "Invalid emote.")
+ else if(copytext(input,1,9) == "exclaims")
+ to_chat(user, "Invalid emote.")
+ else if(copytext(input,1,6) == "yells")
+ to_chat(user, "Invalid emote.")
+ else if(copytext(input,1,5) == "asks")
+ to_chat(user, "Invalid emote.")
+ else
+ . = FALSE
+
+/datum/emote/living/custom/run_emote(mob/user, params, type_override = null)
+ if(jobban_isbanned(user, "emote"))
+ to_chat(user, "You cannot send custom emotes (banned).")
+ return FALSE
+ else if(user.client && user.client.prefs.muted & MUTE_IC)
+ to_chat(user, "You cannot send IC messages (muted).")
+ return FALSE
+ else if(!params)
+ var/custom_emote = copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN)
+ if(custom_emote && !check_invalid(user, custom_emote))
+ var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
+ switch(type)
+ if("Visible")
+ emote_type = EMOTE_VISIBLE
+ if("Hearable")
+ emote_type = EMOTE_AUDIBLE
+ else
+ alert("Unable to use this emote, must be either hearable or visible.")
+ return
+ message = custom_emote
+ else
+ message = params
+ if(type_override)
+ emote_type = type_override
+ . = ..()
+ message = null
+ emote_type = EMOTE_VISIBLE
+
+/datum/emote/living/custom/replace_pronoun(mob/user, message)
+ return message
+
+/datum/emote/living/help
+ key = "help"
+
+/datum/emote/living/help/run_emote(mob/user, params)
+ var/list/keys = list()
+ var/list/message = list("Available emotes, you can use them with say \"*emote\": ")
+
+ var/datum/emote/E
+ var/list/emote_list = E.emote_list
+ for(var/e in emote_list)
+ if(e in keys)
+ continue
+ E = emote_list[e]
+ if(E.can_run_emote(user, TRUE))
+ keys += E.key
+
+ keys = sortList(keys)
+
+ for(var/emote in keys)
+ if(LAZYLEN(message) > 1)
+ message += ", [emote]"
+ else
+ message += "[emote]"
+
+ message += "."
+
+ message = jointext(message, "")
+
+ to_chat(user, message)
+
+/datum/emote/sound/beep
+ key = "beep"
+ key_third_person = "beeps"
+ message = "beeps."
+ message_param = "beeps at %t."
+ sound = 'sound/machines/twobeep.ogg'
+
+/datum/emote/living/spin
+ key = "spin"
+ key_third_person = "spins"
+
+/datum/emote/living/spin/run_emote(mob/user)
+ user.spin(20, 1)
+ if(iscyborg(user))
+ var/mob/living/silicon/robot/R = user
+ if(R.buckled_mobs)
+ for(var/mob/M in R.buckled_mobs)
+ if(R.riding_datum)
+ R.riding_datum.force_dismount(M)
+ else
+ R.unbuckle_all_mobs()
+ ..()
+
+/datum/emote/living/circle
+ key = "circle"
+ key_third_person = "circles"
+ restraint_check = TRUE
+
+/datum/emote/living/circle/run_emote(mob/user, params)
+ . = ..()
+ var/obj/item/circlegame/N = new(user)
+ if(user.put_in_hands(N))
+ to_chat(user, "You make a circle with your hand.")
+ else
+ qdel(N)
+ to_chat(user, "You don't have any free hands to make a circle with.")
diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm
index 853cca2057..5a65a58d76 100644
--- a/code/modules/ninja/energy_katana.dm
+++ b/code/modules/ninja/energy_katana.dm
@@ -1,60 +1,4 @@
-/obj/item/dash
- name = "abstract dash weapon"
- var/max_charges = 3
- var/current_charges = 3
- var/charge_rate = 30 //In deciseconds
- var/dash_toggled = TRUE
-
- var/bypass_density = FALSE //Can we beam past windows/airlocks/etc
-
- var/start_effect_type = /obj/effect/temp_visual/dir_setting/ninja/phase/out
- var/end_effect_type = /obj/effect/temp_visual/dir_setting/ninja/phase
- var/beam_icon_state = "blur"
- var/dash_beam_type = /obj/effect/ebeam
-
-/obj/item/dash/proc/charge()
- current_charges = Clamp(current_charges + 1, 0, max_charges)
- if(istype(loc, /mob/living))
- to_chat(loc, "[src] now has [current_charges]/[max_charges] charges.")
-
-/obj/item/dash/attack_self(mob/user)
- dash_toggled = !dash_toggled
- to_chat(user, "You [dash_toggled ? "enable" : "disable"] the dash function on [src].")
-
-/obj/item/dash/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
- if(dash_toggled)
- dash(user, target)
- return
-
-/obj/item/dash/proc/dash(mob/user, atom/target)
- if(!current_charges)
- return
-
- if(Adjacent(target))
- return
-
- if(target.density)
- return
-
- var/turf/T = get_turf(target)
-
- if(!bypass_density)
- for(var/turf/turf in getline(get_turf(user),T))
- for(var/atom/A in turf)
- if(A.density)
- return
-
- if(target in view(user.client.view, get_turf(user)))
- var/obj/spot1 = new start_effect_type(T, user.dir)
- user.forceMove(T)
- playsound(T, 'sound/magic/blink.ogg', 25, 1)
- playsound(T, "sparks", 50, 1)
- var/obj/spot2 = new end_effect_type(get_turf(user), user.dir)
- spot1.Beam(spot2, beam_icon_state,time = 2, maxdistance = 20, beam_type = dash_beam_type)
- current_charges--
- addtimer(CALLBACK(src, .proc/charge), charge_rate)
-
-/obj/item/dash/energy_katana
+/obj/item/energy_katana
name = "energy katana"
desc = "A katana infused with strong energy."
icon_state = "energy_katana"
@@ -73,12 +17,20 @@
sharpness = IS_SHARP
max_integrity = 200
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- bypass_density = TRUE
var/datum/effect_system/spark_spread/spark_system
+ var/datum/action/innate/dash/ninja/jaunt
+ var/dash_toggled = TRUE
-/obj/item/dash/energy_katana/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+/obj/item/energy_katana/Initialize()
+ . = ..()
+ jaunt = new(src)
+ spark_system = new /datum/effect_system/spark_spread()
+ spark_system.set_up(5, 0, src)
+ spark_system.attach(src)
+
+/obj/item/energy_katana/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(dash_toggled)
- return ..()
+ jaunt.Teleport(user, target)
if(proximity_flag && (isobj(target) || issilicon(target)))
spark_system.start()
playsound(user, "sparks", 50, 1)
@@ -99,7 +51,7 @@
//If we hit the Ninja who owns this Katana, they catch it.
//Works for if the Ninja throws it or it throws itself or someone tries
//To throw it at the ninja
-/obj/item/dash/energy_katana/throw_impact(atom/hit_atom)
+/obj/item/energy_katana/throw_impact(atom/hit_atom)
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
@@ -110,7 +62,7 @@
..()
-/obj/item/dash/energy_katana/proc/returnToOwner(mob/living/carbon/human/user, doSpark = 1, caught = 0)
+/obj/item/energy_katana/proc/returnToOwner(mob/living/carbon/human/user, doSpark = 1, caught = 0)
if(!istype(user))
return
forceMove(get_turf(user))
@@ -137,12 +89,15 @@
if(msg)
to_chat(user, "[msg]")
-/obj/item/dash/energy_katana/Initialize()
- . = ..()
- spark_system = new /datum/effect_system/spark_spread()
- spark_system.set_up(5, 0, src)
- spark_system.attach(src)
-/obj/item/dash/energy_katana/Destroy()
+/obj/item/energy_katana/Destroy()
QDEL_NULL(spark_system)
return ..()
+
+/datum/action/innate/dash/ninja
+ current_charges = 3
+ max_charges = 3
+ charge_rate = 30
+ recharge_sound = null
+
+
diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm
index 4ec9cde23c..2fd732f0ce 100644
--- a/code/modules/ninja/outfit.dm
+++ b/code/modules/ninja/outfit.dm
@@ -12,7 +12,7 @@
l_pocket = /obj/item/grenade/plastic/x4
r_pocket = /obj/item/tank/internals/emergency_oxygen
internals_slot = slot_r_store
- belt = /obj/item/dash/energy_katana
+ belt = /obj/item/energy_katana
implants = list(/obj/item/implant/explosive)
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index 40d18951e6..1dcfed99c0 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -30,7 +30,7 @@ Contents:
var/datum/effect_system/spark_spread/spark_system
var/list/stored_research = list()//For stealing station research.
var/obj/item/disk/tech_disk/t_disk//To copy design onto disk.
- var/obj/item/dash/energy_katana/energyKatana //For teleporting the katana back to the ninja (It's an ability)
+ var/obj/item/energy_katana/energyKatana //For teleporting the katana back to the ninja (It's an ability)
//Other articles of ninja gear worn together, used to easily reference them after initializing.
var/obj/item/clothing/head/helmet/space/space_ninja/n_hood
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index a3db8f7bc2..308fd47a16 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -169,18 +169,7 @@
/datum/reagent/consumable/laughter/on_mob_life(mob/living/carbon/M)
if(!iscarbon(M))
return
- if(!M.silent)//cant laugh if you're mute
- M.emote("laugh")
- var/laughnum = rand(1,2)
- if(M.gender == MALE)
- if(laughnum == 1)
- playsound(get_turf(M), 'sound/voice/human/manlaugh1.ogg', 50, 1)
- if(laughnum == 2)
- playsound(get_turf(M), 'sound/voice/human/manlaugh2.ogg', 50, 1)
- else if(M.gender == FEMALE)
- playsound(get_turf(M), 'sound/voice/human/womanlaugh.ogg', 65, 1)
- else//non-binary gender just sounds like a man
- playsound(get_turf(M), 'sound/voice/human/manlaugh1.ogg', 50, 1)
+ M.emote("laugh")
..()
/datum/reagent/consumable/potato_juice
diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi
new file mode 100644
index 0000000000..f21c6c7579
Binary files /dev/null and b/icons/obj/stack_objects.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 1d878fc78b..2dba779e78 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -257,6 +257,7 @@
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
#include "code\datums\cinematic.dm"
+#include "code\datums\dash_weapon.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datum.dm"
#include "code\datums\datumvars.dm"