[MIRROR] [Ready] Makes the admin-only high frequency blade !FUN! and adds it to the spellbook [MDB IGNORE] (#10550)
* [Ready] Makes the admin-only high frequency blade !FUN! and adds it to the spellbook (#63861) * makes the vibro sword fun * AND IT WILL COME LIKE A FLOOD OF PAIN * POURING DOWN ON ME * AND IT WILL NOT LET UP * UNTIL THE END IS HERE * AND IT WILL COME THROUGH THE DARKEST DAY * IN MY FINAL HOUR * AND IT WILL NEVER REST UNTIL THE CLOUDS ARE CLEAR * only love is with us now * something warm and pure * find the peace within ourselves * no need for a cure * MAKING WHOLE THE FABRIC OF SOCIETY * COLLECTIVE CONSCIOUSNESS CONTROLLED AS YOU WILL SEE * MIND CONTROL * WOOOOOOOOOOOOOOOOOOOO * YEAAAAAAAH Co-authored-by: Urumasi <Urumasi@ email.cz> * decompose that matrix bitch ass * sord * you will die Co-authored-by: Urumasi <Urumasi@ email.cz> * [Ready] Makes the admin-only high frequency blade !FUN! and adds it to the spellbook Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com> Co-authored-by: Urumasi <Urumasi@ email.cz>
@@ -16,11 +16,14 @@
|
||||
/// If other operations were applied on the matrix, such as shearing, the result
|
||||
/// will not be precise.
|
||||
///
|
||||
/// Negative scales are not supported.
|
||||
/// Negative scales are now supported. =)
|
||||
/matrix/proc/decompose()
|
||||
var/datum/decompose_matrix/decompose_matrix = new
|
||||
. = decompose_matrix
|
||||
decompose_matrix.scale_x = sqrt(a * a + d * d)
|
||||
var/flip_sign = (a*e - b*d < 0)? -1 : 1 // Det < 0 => only 1 axis is flipped - start doing some sign flipping
|
||||
// If both axis are flipped, nothing bad happens and Det >= 0, it just treats it like a 180° rotation
|
||||
// If only 1 axis is flipped, we need to flip one direction - in this case X, so we flip a, b and the x scaling
|
||||
decompose_matrix.scale_x = sqrt(a * a + d * d) * flip_sign
|
||||
decompose_matrix.scale_y = sqrt(b * b + e * e)
|
||||
decompose_matrix.shift_x = c
|
||||
decompose_matrix.shift_y = f
|
||||
@@ -28,8 +31,8 @@
|
||||
return
|
||||
// If only translated, scaled and rotated, a/xs == e/ys and -d/xs == b/xy
|
||||
var/cossine = (a/decompose_matrix.scale_x + e/decompose_matrix.scale_y) / 2
|
||||
var/sine = (b/decompose_matrix.scale_y - d/decompose_matrix.scale_x) / 2
|
||||
decompose_matrix.rotation = arctan(cossine, sine)
|
||||
var/sine = (b/decompose_matrix.scale_y - d/decompose_matrix.scale_x) / 2 * flip_sign
|
||||
decompose_matrix.rotation = arctan(cossine, sine) * flip_sign
|
||||
|
||||
/matrix/proc/TurnTo(old_angle, new_angle)
|
||||
. = new_angle - old_angle
|
||||
|
||||
@@ -215,7 +215,7 @@ GLOBAL_LIST_INIT(phobia_objs, list(
|
||||
|
||||
"anime" = typecacheof(list(/obj/item/clothing/under/costume/schoolgirl, /obj/item/katana, /obj/item/food/sashimi, /obj/item/food/chawanmushi,
|
||||
/obj/item/reagent_containers/food/drinks/bottle/sake, /obj/item/throwing_star, /obj/item/clothing/head/kitty/genuine, /obj/item/clothing/suit/space/space_ninja,
|
||||
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/vibro_weapon,
|
||||
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/highfrequencyblade,
|
||||
/obj/item/nullrod/scythe/vibro, /obj/item/energy_katana, /obj/item/toy/katana, /obj/item/nullrod/claymore/katana, /obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe
|
||||
)),
|
||||
|
||||
@@ -236,10 +236,10 @@ GLOBAL_LIST_INIT(phobia_objs, list(
|
||||
|
||||
"anime" = typecacheof(list(/obj/item/clothing/under/costume/schoolgirl, /obj/item/katana, /obj/item/food/sashimi, /obj/item/food/chawanmushi,
|
||||
/obj/item/reagent_containers/food/drinks/bottle/sake, /obj/item/throwing_star, /obj/item/clothing/head/kitty/genuine, /obj/item/clothing/suit/space/space_ninja,
|
||||
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/vibro_weapon,
|
||||
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/highfrequencyblade,
|
||||
/obj/item/nullrod/scythe/vibro, /obj/item/energy_katana, /obj/item/toy/katana, /obj/item/nullrod/claymore/katana, /obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe
|
||||
)),
|
||||
|
||||
|
||||
"blood" = typecacheof(list(/obj/machinery/iv_drip, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/blood, /obj/effect/decal/cleanable/blood)),
|
||||
))
|
||||
|
||||
|
||||
@@ -785,67 +785,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
|
||||
//HF blade
|
||||
/obj/item/vibro_weapon
|
||||
icon_state = "hfrequency0"
|
||||
base_icon_state = "hfrequency"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
name = "vibro sword"
|
||||
desc = "A potent weapon capable of cutting through nearly anything. Wielding it in two hands will allow you to deflect gunfire."
|
||||
armour_penetration = 100
|
||||
block_chance = 40
|
||||
force = 20
|
||||
throwforce = 20
|
||||
throw_speed = 4
|
||||
sharpness = SHARP_EDGED
|
||||
attack_verb_continuous = list("cuts", "slices", "dices")
|
||||
attack_verb_simple = list("cut", "slice", "dice")
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
|
||||
/obj/item/vibro_weapon/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
|
||||
|
||||
/obj/item/vibro_weapon/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 20, 105)
|
||||
AddComponent(/datum/component/two_handed, force_multiplier=2, icon_wielded="[base_icon_state]1")
|
||||
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/vibro_weapon/proc/on_wield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = TRUE
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/vibro_weapon/proc/on_unwield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = FALSE
|
||||
|
||||
/obj/item/vibro_weapon/update_icon_state()
|
||||
icon_state = "[base_icon_state]0"
|
||||
return ..()
|
||||
|
||||
/obj/item/vibro_weapon/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(wielded)
|
||||
final_block_chance *= 2
|
||||
if(wielded || attack_type != PROJECTILE_ATTACK)
|
||||
if(prob(final_block_chance))
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
owner.visible_message(span_danger("[owner] deflects [attack_text] with [src]!"))
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
|
||||
return TRUE
|
||||
else
|
||||
owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!"))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/melee/moonlight_greatsword
|
||||
name = "moonlight greatsword"
|
||||
desc = "Don't tell anyone you put any points into dex, though."
|
||||
@@ -863,3 +802,158 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts")
|
||||
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
|
||||
|
||||
//High Frequency Blade
|
||||
|
||||
/obj/item/highfrequencyblade
|
||||
name = "high frequency blade"
|
||||
desc = "A sword reinforced by a powerful alternating current and resonating at extremely high vibration frequencies. \
|
||||
This oscillation weakens the molecular bonds of anything it cuts, thereby increasing its cutting ability."
|
||||
icon_state = "hfrequency0"
|
||||
worn_icon_state = "hfrequency0"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
force = 10
|
||||
wound_bonus = 25
|
||||
bare_wound_bonus = 50
|
||||
throwforce = 25
|
||||
throw_speed = 4
|
||||
embedding = list("embed_chance" = 100)
|
||||
block_chance = 25
|
||||
sharpness = SHARP_EDGED
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
/// Wielding status.
|
||||
var/wielded = FALSE
|
||||
/// Previous x position of where we clicked on the target's icon
|
||||
var/previous_x
|
||||
/// Previous y position of where we clicked on the target's icon
|
||||
var/previous_y
|
||||
/// The previous target we attacked
|
||||
var/datum/weakref/previous_target
|
||||
|
||||
/obj/item/highfrequencyblade/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
|
||||
/obj/item/highfrequencyblade/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed)
|
||||
|
||||
/obj/item/highfrequencyblade/update_icon_state()
|
||||
icon_state = "hfrequency[wielded]"
|
||||
return ..()
|
||||
|
||||
/obj/item/highfrequencyblade/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(attack_type == PROJECTILE_ATTACK)
|
||||
if(wielded || prob(final_block_chance))
|
||||
owner.visible_message(span_danger("[owner] deflects [attack_text] with [src]!"))
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(prob(final_block_chance * (wielded ? 2 : 1)))
|
||||
owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!"))
|
||||
return TRUE
|
||||
|
||||
/obj/item/highfrequencyblade/attack(mob/living/target, mob/living/user, params)
|
||||
if(!wielded)
|
||||
return ..()
|
||||
slash(target, user, params)
|
||||
|
||||
/obj/item/highfrequencyblade/attack_atom(atom/target, mob/living/user, params)
|
||||
if(wielded)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/highfrequencyblade/afterattack(atom/target, mob/user, proximity_flag, params)
|
||||
if(!wielded)
|
||||
return ..()
|
||||
if(!proximity_flag || !(isclosedturf(target) || isitem(target) || ismachinery(target) || isstructure(target)))
|
||||
return
|
||||
slash(target, user, params)
|
||||
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/highfrequencyblade/proc/on_wield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = TRUE
|
||||
update_icon(UPDATE_ICON_STATE)
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/highfrequencyblade/proc/on_unwield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = FALSE
|
||||
update_icon(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/item/highfrequencyblade/proc/slash(atom/target, mob/living/user, params)
|
||||
user.changeNext_move(0.1 SECONDS)
|
||||
user.do_attack_animation(target, "nothing")
|
||||
var/list/modifiers = params2list(params)
|
||||
var/damage_mod = 1
|
||||
var/x_slashed = text2num(modifiers[ICON_X]) || world.icon_size/2 //in case we arent called by a client
|
||||
var/y_slashed = text2num(modifiers[ICON_Y]) || world.icon_size/2 //in case we arent called by a client
|
||||
new /obj/effect/temp_visual/slash(get_turf(target), target, x_slashed, y_slashed)
|
||||
if(target == previous_target?.resolve()) //if the same target, we calculate a damage multiplier if you swing your mouse around
|
||||
var/x_mod = previous_x - x_slashed
|
||||
var/y_mod = previous_y - y_slashed
|
||||
damage_mod = max(1, round((sqrt(x_mod ** 2 + y_mod ** 2) / 10), 0.1))
|
||||
previous_target = WEAKREF(target)
|
||||
previous_x = x_slashed
|
||||
previous_y = y_slashed
|
||||
playsound(src, 'sound/weapons/bladeslice.ogg', 100, vary = TRUE)
|
||||
playsound(src, 'sound/weapons/zapbang.ogg', 50, vary = TRUE)
|
||||
if(isliving(target))
|
||||
var/mob/living/living_target = target
|
||||
living_target.apply_damage(force*damage_mod, BRUTE, sharpness = SHARP_EDGED, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, def_zone = user.zone_selected)
|
||||
log_combat(user, living_target, "slashed", src)
|
||||
if(living_target.stat == DEAD && prob(force*damage_mod*0.5))
|
||||
living_target.visible_message(span_danger("[living_target] explodes in a shower of gore!"), blind_message = span_hear("You hear organic matter ripping and tearing!"))
|
||||
living_target.gib()
|
||||
log_combat(user, living_target, "gibbed", src)
|
||||
else if(target.uses_integrity)
|
||||
target.take_damage(force*damage_mod*3, BRUTE, MELEE, FALSE, null, 50)
|
||||
else if(iswallturf(target) && prob(force*damage_mod*0.5))
|
||||
var/turf/closed/wall/wall_target = target
|
||||
wall_target.dismantle_wall()
|
||||
else if(ismineralturf(target) && prob(force*damage_mod))
|
||||
var/turf/closed/mineral/mineral_target = target
|
||||
mineral_target.gets_drilled()
|
||||
|
||||
/obj/effect/temp_visual/slash
|
||||
icon_state = "highfreq_slash"
|
||||
alpha = 150
|
||||
duration = 0.5 SECONDS
|
||||
plane = ABOVE_GAME_PLANE
|
||||
|
||||
/obj/effect/temp_visual/slash/Initialize(mapload, atom/target, x_slashed, y_slashed)
|
||||
. = ..()
|
||||
if(!target)
|
||||
return
|
||||
var/matrix/new_transform = matrix()
|
||||
new_transform.Turn(rand(1, 360)) // Random slash angle
|
||||
var/datum/decompose_matrix/decomp = target.transform.decompose()
|
||||
new_transform.Translate((x_slashed - world.icon_size/2) * decomp.scale_x, (y_slashed - world.icon_size/2) * decomp.scale_y) // Move to where we clicked
|
||||
//Follow target's transform while ignoring scaling
|
||||
new_transform.Turn(decomp.rotation)
|
||||
new_transform.Translate(decomp.shift_x, decomp.shift_y)
|
||||
new_transform.Translate(target.pixel_x, target.pixel_y) // Follow target's pixel offsets
|
||||
transform = new_transform
|
||||
//Double the scale of the matrix by doubling the 2x2 part without touching the translation part
|
||||
var/matrix/scaled_transform = new_transform + matrix(new_transform.a, new_transform.b, 0, new_transform.d, new_transform.e, 0)
|
||||
animate(src, duration*0.5, color = COLOR_BLUE, transform = scaled_transform, alpha = 255)
|
||||
|
||||
/obj/item/highfrequencyblade/wizard
|
||||
desc = "A blade that was mastercrafted by a legendary blacksmith. Its' enchantments let it slash through anything."
|
||||
force = 8
|
||||
throwforce = 20
|
||||
wound_bonus = 20
|
||||
bare_wound_bonus = 25
|
||||
|
||||
/obj/item/highfrequencyblade/wizard/attack_self(mob/user, modifiers)
|
||||
if(!IS_WIZARD(user))
|
||||
balloon_alert(user, "you're too weak!")
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -509,6 +509,12 @@
|
||||
category = "Mobility"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/item/highfrequencyblade
|
||||
name = "High Frequency Blade"
|
||||
desc = "An incredibly swift enchanted blade resonating at a frequency high enough to be able to slice through anything."
|
||||
item_path = /obj/item/highfrequencyblade/wizard
|
||||
cost = 3
|
||||
|
||||
/datum/spellbook_entry/duffelbag
|
||||
name = "Bestow Cursed Duffel Bag"
|
||||
desc = "A curse that firmly attaches a demonic duffel bag to the target's back. The duffel bag will make the person it's attached to take periodical damage if it is not fed regularly, and regardless of whether or not it's been fed, it will slow the person wearing it down significantly."
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
permeability_coefficient = 0.01
|
||||
body_parts_covered = CHEST|GROIN|ARMS|LEGS
|
||||
armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 20, FIRE = 100, ACID = 100, WOUND = 20)
|
||||
allowed = list(/obj/item/teleportation_scroll)
|
||||
allowed = list(/obj/item/teleportation_scroll, /obj/item/highfrequencyblade/wizard)
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
strip_delay = 50
|
||||
equip_delay_other = 50
|
||||
|
||||
@@ -91,8 +91,11 @@
|
||||
if(decompose.scale_x != 1 || decompose.scale_y != 1)
|
||||
var/base_w = img.Width()
|
||||
var/base_h = img.Height()
|
||||
img.Scale(base_w * decompose.scale_x, base_h * decompose.scale_y)
|
||||
xo -= base_w * (decompose.scale_x - 1) / 2
|
||||
// scale_x can be negative
|
||||
img.Scale(base_w * abs(decompose.scale_x), base_h * decompose.scale_y)
|
||||
if(decompose.scale_x < 0)
|
||||
img.Flip(EAST)
|
||||
xo -= base_w * (decompose.scale_x - SIGN(decompose.scale_x)) / 2 * SIGN(decompose.scale_x)
|
||||
yo -= base_h * (decompose.scale_y - 1) / 2
|
||||
// Rotation
|
||||
if(decompose.rotation != 0)
|
||||
|
||||
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 906 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 91 KiB |