Merges crusher retool kits into one, datumizes crusher skins, gives dagger and blaster unique animations (#90742)

## About The Pull Request

Merges sword, harpoon, glaive and dagger crusher retools into a single
item which allows you to pick the skin you want upon being applied to a
crusher by converting crusher skins into datums.
I've also improved sprites for all skins and redid the retool kit
itself, as well as gave dagger and blaster unique animations - you swing
with a dagger for normal attacks, stab to rupture the mark, and firing a
shot point-blank does a stabbing animation with the blaster.

![dreamseeker_5nPyNKqzoC](https://github.com/user-attachments/assets/c8858a71-3c0f-49a0-8577-cb8a9e64e0a0)


https://github.com/user-attachments/assets/2d243daf-f1d8-48bf-a661-8a9ac990837c

(Apologies for lack of robust gameplay, I was trying to show the
animations, not kill the goliath)

The harpoon crusher skin now does stabbing animation instead of slashing
one, and I've also fixed animations playing incorrectly when attacking
large mobs/objects

## Why It's Good For The Game

Having multiple items for reskinning crushers feels clunky, and unique
animations are just something that makes sense. Having a swinging
animation for both dagger and blaster looked odd, as you'd probably only
swing one of them at the opponent, so I decided to spice them up.

## Changelog
🆑
add: Dagger-blaster and harpoon crusher skins have received unique
attack animations.
add: Four base crusher retool kits have been merged into one item.
image: Resprited crusher skins and the crusher retool kit
fix: Fixed attack animations being offset when attacking large objects
or mobs.
/🆑
This commit is contained in:
SmArtKar
2025-05-04 15:36:27 +03:00
committed by GitHub
parent ad352a2b7e
commit b0aaeca5ae
10 changed files with 206 additions and 97 deletions
+48 -23
View File
@@ -1544,38 +1544,63 @@
// This is instant on byond's end, but to our clients this looks like a quick drop
animate(src, alpha = old_alpha, pixel_x = old_x, pixel_y = old_y, transform = old_transform, time = 3, easing = CUBIC_EASING)
/atom/movable/proc/do_item_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, animation_type = ATTACK_ANIMATION_BLUNT)
if (visual_effect_icon)
var/image/attack_image = image(icon = 'icons/effects/effects.dmi', icon_state = visual_effect_icon)
attack_image.plane = attacked_atom.plane + 1
// Scale the icon.
attack_image.transform *= 0.4
// The icon should not rotate.
attack_image.appearance_flags = APPEARANCE_UI
var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS)
var/matrix/copy_transform = new(transform)
animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), time = 0.3 SECONDS)
animate(time = 0.1 SECONDS)
animate(alpha = 0, time = 0.3 SECONDS, easing = CIRCULAR_EASING|EASE_OUT)
/atom/movable/proc/do_item_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, animation_type)
if (!visual_effect_icon)
if (used_item)
used_item.animate_attack(src, attacked_atom, animation_type)
return
if (isnull(used_item))
return
var/image/attack_image = isnull(used_item.attack_icon) ? image(icon = used_item) : image(icon = used_item.attack_icon, icon_state = used_item.attack_icon_state)
var/image/attack_image = image(icon = 'icons/effects/effects.dmi', icon_state = visual_effect_icon)
attack_image.plane = attacked_atom.plane + 1
attack_image.pixel_w = used_item.base_pixel_x + used_item.base_pixel_w
attack_image.pixel_z = used_item.base_pixel_y + used_item.base_pixel_z
// Scale the icon.
attack_image.transform *= 0.4
// The icon should not rotate.
attack_image.appearance_flags = APPEARANCE_UI
var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS)
var/matrix/copy_transform = new(transform)
animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), time = 0.3 SECONDS)
animate(time = 0.1 SECONDS)
animate(alpha = 0, time = 0.3 SECONDS, easing = CIRCULAR_EASING|EASE_OUT)
/obj/item/proc/animate_attack(atom/movable/attacker, atom/attacked_atom, animation_type)
var/list/image_override = list()
var/list/animation_override = list()
var/used_icon_angle = icon_angle
var/list/angle_override = list()
SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_ANIMATION, attacker, attacked_atom, animation_type, image_override, animation_override, angle_override)
var/image/attack_image = null
if (!length(image_override))
attack_image = isnull(attack_icon) ? image(icon = src) : image(icon = attack_icon, icon_state = attack_icon_state)
else
attack_image = image_override[1]
if (length(animation_override))
animation_type = animation_override[1]
else if (!animation_type)
switch (get_sharpness())
if (SHARP_EDGED)
animation_type = ATTACK_ANIMATION_SLASH
if (SHARP_POINTY)
animation_type = ATTACK_ANIMATION_PIERCE
else
animation_type = ATTACK_ANIMATION_BLUNT
if (length(angle_override))
used_icon_angle = angle_override[1]
attack_image.plane = attacked_atom.plane + 1
attack_image.pixel_w = attacker.base_pixel_x + attacker.base_pixel_w - attacked_atom.base_pixel_x - attacked_atom.base_pixel_w
attack_image.pixel_z = attacker.base_pixel_y + attacker.base_pixel_z - attacked_atom.base_pixel_y - attacked_atom.base_pixel_z
// Scale the icon.
attack_image.transform *= 0.5
// The icon should not rotate.
attack_image.appearance_flags = APPEARANCE_UI
var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS)
var/matrix/copy_transform = new(transform)
var/matrix/copy_transform = new(attacker.transform)
var/x_sign = 0
var/y_sign = 0
var/direction = get_dir(src, attacked_atom)
var/direction = get_dir(attacker, attacked_atom)
if (direction & NORTH)
y_sign = -1
else if (direction & SOUTH)
@@ -1606,7 +1631,7 @@
if (ATTACK_ANIMATION_PIERCE)
var/attack_angle = dir2angle(direction) + rand(-7, 7)
// Deducting 90 because we're assuming that icon_angle of 0 means an east-facing sprite
var/anim_angle = attack_angle - 90 - used_item.icon_angle
var/anim_angle = attack_angle - 90 - used_icon_angle
var/angle_mult = 1
if (x_sign && y_sign)
angle_mult = 1.4
@@ -1644,7 +1669,7 @@
var/x_rot_sign = 0
var/y_rot_sign = 0
var/attack_dir = (prob(50) ? 1 : -1)
var/anim_angle = dir2angle(direction) - 90 - used_item.icon_angle
var/anim_angle = dir2angle(direction) - 90 - used_icon_angle
if (x_sign)
y_rot_sign = attack_dir