diff --git a/code/modules/mining/lavaland/cain_and_abel/_cain_and_abel.dm b/code/modules/mining/lavaland/cain_and_abel/_cain_and_abel.dm index ec32f5a4d07..6faf813094b 100644 --- a/code/modules/mining/lavaland/cain_and_abel/_cain_and_abel.dm +++ b/code/modules/mining/lavaland/cain_and_abel/_cain_and_abel.dm @@ -24,39 +24,40 @@ reach = 2 attack_icon = 'icons/effects/effects.dmi' attack_icon_state = "cain_abel_attack" - ///our current combo count + /// Our current combo count var/combo_count = 0 - ///the maximum combo we can reach + /// The maximum combo we can reach var/max_combo = 6 - ///percentage boost we get on every combo + /// Percentage boost we get on every combo var/damage_boost = 1.15 - ///pixel offsets of our wisps - var/static/list/wisp_offsets = list( - list(9, 12), - list(14, 0), - list(9, -12), - list(-9, 12), - list(-14, 0), - list(-9, -12), - ) - ///what throw mode we're using + /// Animation positions used by wisps + var/static/list/animation_steps + /// What throw mode we're using var/throw_mode = THROW_MODE_CRYSTALS - ///flames we have up! + /// Flames we have up! var/list/current_wisps = list() - ///cooldown till we can throw blades again + /// Cooldown till we can throw blades again COOLDOWN_DECLARE(throw_cooldown) /obj/item/cain_and_abel/Initialize(mapload) . = ..() AddComponent(/datum/component/two_handed, require_twohands = TRUE, force_unwielded = force, force_wielded = force) + if (length(animation_steps)) + return + animation_steps = list( + new /datum/abel_wisp_frame(-18, -2, MOB_LAYER, EASE_OUT, EASE_IN), + new /datum/abel_wisp_frame(-6, -6, ABOVE_MOB_LAYER, EASE_IN, EASE_OUT), + new /datum/abel_wisp_frame(6, -6, ABOVE_MOB_LAYER, EASE_IN, EASE_OUT), + new /datum/abel_wisp_frame(18, -2, MOB_LAYER, EASE_OUT, EASE_IN), + new /datum/abel_wisp_frame(6, 2, BELOW_MOB_LAYER, EASE_IN, EASE_OUT), + new /datum/abel_wisp_frame(-6, 2, BELOW_MOB_LAYER, EASE_IN, EASE_OUT), + ) /obj/item/cain_and_abel/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) . = ..() - if(!isliving(old_loc)) - return - - unset_user(old_loc) + if(isliving(old_loc)) + unset_user(old_loc) /obj/item/cain_and_abel/proc/unset_user(mob/living/source) if(HAS_TRAIT(source, TRAIT_RELAYING_ATTACKER)) @@ -65,7 +66,6 @@ set_combo(new_value = 0, user = source) UnregisterSignal(source, list(COMSIG_ATOM_WAS_ATTACKED)) - /obj/item/cain_and_abel/equipped(mob/user, slot) . = ..() @@ -92,8 +92,6 @@ for(var/index in 0 to (length(current_wisps) - 1)) addtimer(CALLBACK(src, PROC_REF(fire_wisp), user, interacting_with), index * 0.15 SECONDS) - - set_combo(new_value = 0, user = user) return ITEM_INTERACT_SUCCESS /obj/item/cain_and_abel/attack(mob/living/target, mob/living/carbon/human/user) @@ -117,29 +115,55 @@ user.balloon_alert(user, "crystals [throw_mode == THROW_MODE_CRYSTALS ? "activated" : "deactivated"]") return TRUE -/obj/item/cain_and_abel/proc/set_combo(new_value, mob/living/user) - combo_count = (new_value <= max_combo) ? new_value : 0 - handle_wisps(user) +/obj/item/cain_and_abel/proc/set_combo(new_value, mob/living/user, instant = FALSE) + new_value = clamp(new_value, 0, max_combo) + if (new_value == combo_count) + return -/obj/item/cain_and_abel/proc/handle_wisps(mob/living/user) - var/should_remove = length(current_wisps) > combo_count - var/wisps_to_alter = abs(combo_count - length(current_wisps)) - - for(var/i = 1, i <= wisps_to_alter, i++) - if(!should_remove) + if (new_value > combo_count) + for (var/i in 1 to new_value - combo_count) add_wisp(user) - continue - var/obj/my_wisp = current_wisps[i] - remove_wisp(my_wisp) + else + for (var/i in 1 to combo_count - new_value) + remove_wisp(current_wisps[i], instant) + + combo_count = new_value /obj/item/cain_and_abel/proc/add_wisp(mob/living/user) var/obj/effect/overlay/blood_wisp/new_wisp = new(src) current_wisps += new_wisp - var/list/position = wisp_offsets[length(current_wisps)] user.vis_contents += new_wisp - new_wisp.pixel_x = position[1] - new_wisp.pixel_y = position[2] RegisterSignal(new_wisp, COMSIG_QDELETING, PROC_REF(on_wisp_delete)) + for (var/wisp_index in 1 to length(current_wisps)) + var/obj/effect/overlay/blood_wisp/wisp = current_wisps[wisp_index] + var/spawn_index = floor(length(animation_steps) / length(current_wisps) * wisp_index) + var/datum/abel_wisp_frame/spawn_position = animation_steps[spawn_index] + + // Latest added wisp is teleported to its spawn position, others animate from their current position + if (wisp_index == length(current_wisps)) + wisp.pixel_w = spawn_position.x + wisp.pixel_z = spawn_position.y + wisp.layer = spawn_position.layer + else + animate(wisp, tag = "wisp_anim_x") + animate(wisp, tag = "wisp_anim_y") + + var/start_index = spawn_index % length(animation_steps) + 1 + var/datum/abel_wisp_frame/position = animation_steps[start_index] + animate(wisp, pixel_w = position.x, layer = position.layer, time = 0.6 SECONDS, loop = -1, tag = "wisp_anim_x") + // We need to animate x and y coordinates separately as they have different easing steps + for (var/frame_index in 1 to length(animation_steps) - 1) + // Get actual index starting from our *next* animation step, not initial position + var/anim_index = (start_index + frame_index - 1) % length(animation_steps) + 1 + position = animation_steps[anim_index] + animate(time = 0.6 SECONDS, pixel_w = position.x, layer = position.layer, easing = SINE_EASING | position.x_easing) + + animate(wisp, time = 0.6 SECONDS, pixel_z = position.y, loop = -1, tag = "wisp_anim_y") + for (var/frame_index in 1 to length(animation_steps) - 1) + // Get actual index starting from our *next* animation step, not initial position + var/anim_index = (start_index + frame_index - 1) % length(animation_steps) + 1 + position = animation_steps[anim_index] + animate(time = 0.6 SECONDS, pixel_z = position.y, easing = SINE_EASING | position.y_easing) /obj/item/cain_and_abel/proc/on_wisp_delete(datum/source) SIGNAL_HANDLER @@ -148,7 +172,27 @@ /obj/item/cain_and_abel/proc/fire_wisp(atom/user, atom/target) user.fire_projectile(/obj/projectile/dagger_wisp, target) + set_combo(combo_count - 1, user, TRUE) -/obj/item/cain_and_abel/proc/remove_wisp(obj/wisp_to_remove) +/obj/item/cain_and_abel/proc/remove_wisp(obj/wisp_to_remove, instant = FALSE) + if (instant) + qdel(wisp_to_remove) + return animate(wisp_to_remove, alpha = 0, time = 0.2 SECONDS) QDEL_IN(wisp_to_remove, 0.2 SECONDS) + +/// Frame data for cain & abel wisps so we don't have to make list monstrocities +/datum/abel_wisp_frame + var/x = 0 + var/y = 0 + var/layer = MOB_LAYER + var/x_easing = NONE + var/y_easing = NONE + +/datum/abel_wisp_frame/New(x, y, layer, x_easing, y_easing) + . = ..() + src.x = x + src.y = y + src.layer = layer + src.x_easing = x_easing + src.y_easing = y_easing diff --git a/code/modules/mining/lavaland/cain_and_abel/dagger_effects.dm b/code/modules/mining/lavaland/cain_and_abel/dagger_effects.dm index d19da3b9569..e3984219bd0 100644 --- a/code/modules/mining/lavaland/cain_and_abel/dagger_effects.dm +++ b/code/modules/mining/lavaland/cain_and_abel/dagger_effects.dm @@ -1,6 +1,5 @@ //effect when we're swinging wildly around /obj/effect/temp_visual/dagger_slash - name = "Blood Wisp" mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE @@ -19,10 +18,10 @@ //flames we collect around our body /obj/effect/overlay/blood_wisp + name = "Blood Wisp" mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE - layer = ABOVE_HUD_PLANE + vis_flags = VIS_INHERIT_PLANE icon = 'icons/effects/effects.dmi' icon_state = "blood_wisp" light_power = 2