diff --git a/code/datums/action.dm b/code/datums/action.dm
index a65294fa40..b0ee243978 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -591,3 +591,7 @@
var/mob/M = owner
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
+<<<<<<< HEAD
+=======
+
+>>>>>>> 380413f... Ports dash weapons to the dash datum (#31222)
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 55f8ece5e6..b6f25fc746 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -72,6 +72,173 @@
if(is_servant_of_ratvar(C) && C.reagents)
C.reagents.add_reagent("heparin", 1)
+<<<<<<< HEAD
+=======
+/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.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) && current_charges)
+ 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()
+>>>>>>> 380413f... Ports dash weapons to the dash datum (#31222)
/obj/item/restraints/legcuffs/bola/cult
name = "nar'sien bola"
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/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm
index 8901c1b9fa..33283db352 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,23 +17,40 @@
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)
playsound(user, 'sound/weapons/blade1.ogg', 50, 1)
target.emag_act(user)
+/obj/item/energy_katana/pickup(mob/living/user)
+ . = ..()
+ jaunt.Grant(user, src)
+ user.update_icons()
+
+/obj/item/energy_katana/dropped(mob/user)
+ . = ..()
+ jaunt.Remove(user)
+ user.update_icons()
//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))
@@ -100,7 +61,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))
@@ -127,12 +88,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/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"