diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 608fcfcce20..11b03d7102a 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -218,3 +218,5 @@
#define hasorgans(A) (ishuman(A))
#define is_admin(user) (check_rights(R_ADMIN, 0, (user)) != 0)
+
+#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
\ No newline at end of file
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 7f1683ba415..d6dbf1dddbb 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -140,6 +140,15 @@
..()
animate(src, alpha = 0, time = duration)
+/obj/effect/temp_visual/decoy/fading/threesecond
+ duration = 40
+
+/obj/effect/temp_visual/decoy/fading/fivesecond
+ duration = 50
+
+/obj/effect/temp_visual/decoy/fading/halfsecond
+ duration = 5
+
/obj/effect/temp_visual/fire
icon = 'icons/goonstation/effects/fire.dmi'
icon_state = "3"
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index d45e6f6ead8..db96f9fce96 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -34,7 +34,7 @@ Difficulty: Medium
move_to_delay = 3
projectiletype = /obj/item/projectile/kinetic/miner
projectilesound = 'sound/weapons/kenetic_accel.ogg'
- ranged = 1
+ ranged = TRUE
ranged_cooldown_time = 16
pixel_x = -16
crusher_loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator, /obj/item/crusher_trophy/miner_eye)
@@ -47,8 +47,12 @@ Difficulty: Medium
var/dashing = FALSE
var/dash_cooldown = 15
var/guidance = FALSE
+ var/transform_stop_attack = FALSE // stops the blood drunk miner from attacking after transforming his weapon until the next attack chain
deathmessage = "falls to the ground, decaying into glowing particles."
death_sound = "bodyfall"
+ attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
+ /datum/action/innate/megafauna_attack/kinetic_accelerator,
+ /datum/action/innate/megafauna_attack/transform_weapon)
/obj/item/gps/internal/miner
icon_state = null
@@ -56,13 +60,52 @@ Difficulty: Medium
desc = "The sweet blood, oh, it sings to me."
invisibility = 100
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
- guidance = TRUE
-
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize(mapload)
. = ..()
- if(. && prob(12))
- INVOKE_ASYNC(src, .proc/dash)
+ miner_saw = new(src)
+ internal_gps = new/obj/item/gps/internal/miner(src)
+
+ // Add a zone selection UI; otherwise the mob can't melee attack properly.
+ zone_sel = new /obj/screen/zone_sel()
+
+/datum/action/innate/megafauna_attack/dash
+ name = "Dash To Target"
+ icon_icon = 'icons/mob/actions/actions.dmi'
+ button_icon_state = "sniper_zoom"
+ chosen_message = "You are now dashing to your target."
+ chosen_attack_num = 1
+
+/datum/action/innate/megafauna_attack/kinetic_accelerator
+ name = "Fire Kinetic Accelerator"
+ icon_icon = 'icons/obj/guns/energy.dmi'
+ button_icon_state = "kineticgun"
+ chosen_message = "You are now shooting your kinetic accelerator."
+ chosen_attack_num = 2
+
+/datum/action/innate/megafauna_attack/transform_weapon
+ name = "Transform Weapon"
+ icon_icon = 'icons/obj/lavaland/artefacts.dmi'
+ button_icon_state = "cleaving_saw"
+ chosen_message = "You are now transforming your weapon."
+ chosen_attack_num = 3
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
+ if(client)
+ switch(chosen_attack)
+ if(1)
+ dash(target)
+ if(2)
+ shoot_ka()
+ if(3)
+ transform_weapon()
+ return
+
+ Goto(target, move_to_delay, minimum_distance)
+ if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
+ dash_attack()
+ else
+ shoot_ka()
+ transform_weapon()
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
force = 6
@@ -79,14 +122,6 @@ Difficulty: Medium
icon_state = "ka_tracer"
range = MINER_DASH_RANGE
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
- . = ..()
- miner_saw = new(src)
- internal_gps = new/obj/item/gps/internal/miner(src)
-
- // Add a zone selection UI; otherwise the mob can't melee attack properly.
- zone_sel = new /obj/screen/zone_sel()
-
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
var/adjustment_amount = amount * 0.1
if(world.time + adjustment_amount > next_move)
@@ -104,16 +139,19 @@ Difficulty: Medium
return FALSE
return ..()
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity)
if(dash())
return
return ..()
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/MeleeAction(patience = TRUE)
+ transform_stop_attack = FALSE
+ return ..()
+
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
- if(QDELETED(target))
- return
- if(next_move > world.time || !Adjacent(target)) //some cheating
- INVOKE_ASYNC(src, .proc/quick_attack_loop)
+ if(client)
+ transform_stop_attack = FALSE
+ if(QDELETED(target) || transform_stop_attack)
return
face_atom(target)
if(isliving(target))
@@ -132,8 +170,6 @@ Difficulty: Medium
miner_saw.melee_attack_chain(src, target)
if(guidance)
adjustHealth(-2)
- transform_weapon()
- INVOKE_ASYNC(src, .proc/quick_attack_loop)
return TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
@@ -146,16 +182,10 @@ Difficulty: Medium
. = ..()
if(. && target && !targets_the_same)
wander = TRUE
- transform_weapon()
- INVOKE_ASYNC(src, .proc/quick_attack_loop)
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
- Goto(target, move_to_delay, minimum_distance)
- if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
- INVOKE_ASYNC(src, .proc/dash, target)
- else
- shoot_ka()
- transform_weapon()
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash_attack()
+ INVOKE_ASYNC(src, .proc/dash, target)
+ shoot_ka()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
@@ -166,21 +196,6 @@ Difficulty: Medium
Shoot(target)
changeNext_move(CLICK_CD_RANGE)
-//I'm still of the belief that this entire proc needs to be wiped from existence.
-// do not take my touching of it to be endorsement of it. ~mso
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
- while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
- stoplag(1)
- sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
- if(QDELETED(target))
- return
- if(dashing || next_move > world.time || !Adjacent(target))
- if(dashing && next_move <= world.time)
- next_move = world.time + 1
- INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
- return
- AttackingTarget()
-
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
if(world.time < dash_cooldown)
return
@@ -189,7 +204,9 @@ Difficulty: Medium
var/turf/own_turf = get_turf(src)
if(!QDELETED(dash_target))
self_dist_to_target += get_dist(dash_target, own_turf)
- for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
+ for(var/turf/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
+ if(O.density)
+ continue
var/turf_dist_to_target = 0
if(!QDELETED(dash_target))
turf_dist_to_target += get_dist(dash_target, O)
@@ -218,26 +235,29 @@ Difficulty: Medium
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
- var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
- animate(D, alpha = 0, time = 5)
+ var/obj/effect/temp_visual/decoy/fading/halfsecond/D = new (own_turf, src)
forceMove(step_back_turf)
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
dashing = TRUE
alpha = 0
animate(src, alpha = 255, time = 5)
- sleep(2)
+ SLEEP_CHECK_DEATH(2)
D.forceMove(step_forward_turf)
forceMove(target_turf)
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
- sleep(1)
+ SLEEP_CHECK_DEATH(1)
dashing = FALSE
- shoot_ka()
return TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
if(time_until_next_transform <= world.time)
miner_saw.transform_cooldown = 0
miner_saw.transform_weapon(src, TRUE)
+ if(!miner_saw.active)
+ rapid_melee = 5 // 4 deci cooldown before changes, npcpool subsystem wait is 20, 20/4 = 5
+ else
+ rapid_melee = 3 // same thing but halved (slightly rounded up)
+ transform_stop_attack = TRUE
icon_state = "miner[miner_saw.active ? "_transformed":""]"
icon_living = "miner[miner_saw.active ? "_transformed":""]"
time_until_next_transform = world.time + rand(50, 100)
@@ -263,4 +283,12 @@ Difficulty: Medium
sleep(4)
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
+ guidance = TRUE
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
+ . = ..()
+ if(. && prob(12))
+ INVOKE_ASYNC(src, .proc/dash)
+
#undef MINER_DASH_RANGE
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index b618ff9e650..20df360a51a 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -32,10 +32,15 @@
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
+ var/chosen_attack = 1 // chosen attack num
+ var/list/attack_action_types = list()
/mob/living/simple_animal/hostile/megafauna/New()
..()
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
+ for(var/action_type in attack_action_types)
+ var/datum/action/innate/megafauna_attack/attack_action = new action_type()
+ attack_action.Grant(src)
/mob/living/simple_animal/hostile/megafauna/Destroy()
QDEL_NULL(internal_gps)
@@ -113,3 +118,21 @@
SSmedals.SetScore(BOSS_SCORE, C, 1)
SSmedals.SetScore(score_type, C, 1)
return TRUE
+
+/datum/action/innate/megafauna_attack
+ name = "Megafauna Attack"
+ icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon_state = ""
+ var/mob/living/simple_animal/hostile/megafauna/M
+ var/chosen_message
+ var/chosen_attack_num = 0
+
+/datum/action/innate/megafauna_attack/Grant(mob/living/L)
+ if(istype(L, /mob/living/simple_animal/hostile/megafauna))
+ M = L
+ return ..()
+ return FALSE
+
+/datum/action/innate/megafauna_attack/Activate()
+ M.chosen_attack = chosen_attack_num
+ to_chat(M, chosen_message)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
deleted file mode 100644
index efc18895141..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ /dev/null
@@ -1,225 +0,0 @@
-/mob/living/simple_animal/hostile/asteroid/
- vision_range = 2
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- unsuitable_atmos_damage = 15
- faction = list("mining")
- weather_immunities = list("lava","ash")
- obj_damage = 30
- environment_smash = 2
- minbodytemp = 0
- heat_damage_per_tick = 20
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "strikes"
- status_flags = 0
- a_intent = INTENT_HARM
- var/throw_message = "bounces off of"
- var/icon_aggro = null // for swapping to when we get aggressive
- see_in_dark = 8
- lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- mob_size = MOB_SIZE_LARGE
-
-/mob/living/simple_animal/hostile/asteroid/Aggro()
- ..()
- icon_state = icon_aggro
-
-/mob/living/simple_animal/hostile/asteroid/LoseAggro()
- ..()
- if(stat == CONSCIOUS)
- icon_state = icon_living
-
-/mob/living/simple_animal/hostile/asteroid/bullet_act(var/obj/item/projectile/P)//Reduces damage from most projectiles to curb off-screen kills
- if(!stat)
- Aggro()
- if(P.damage < 30 && P.damage_type != BRUTE)
- P.damage = (P.damage / 3)
- visible_message("The [P] has a reduced effect on [src]!")
- ..()
-
-/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM)//No floor tiling them to death, wiseguy
- if(istype(AM, /obj/item))
- var/obj/item/T = AM
- if(!stat)
- Aggro()
- if(T.throwforce <= 20)
- visible_message("The [T.name] [src.throw_message] [src.name]!")
- return
- ..()
-
-/mob/living/simple_animal/hostile/asteroid/basilisk
- name = "basilisk"
- desc = "A territorial beast, covered in a thick shell that absorbs energy. Its stare causes victims to freeze from the inside."
- icon = 'icons/mob/animal.dmi'
- icon_state = "Basilisk"
- icon_living = "Basilisk"
- icon_aggro = "Basilisk_alert"
- icon_dead = "Basilisk_dead"
- icon_gib = "syndicate_gib"
- move_to_delay = 20
- projectiletype = /obj/item/projectile/temp/basilisk
- projectilesound = 'sound/weapons/pierce.ogg'
- ranged = 1
- ranged_message = "stares"
- ranged_cooldown_time = 30
- throw_message = "does nothing against the hard shell of"
- vision_range = 2
- speed = 3
- maxHealth = 200
- health = 200
- harm_intent_damage = 5
- obj_damage = 60
- melee_damage_lower = 12
- melee_damage_upper = 12
- attacktext = "bites into"
- a_intent = INTENT_HARM
- speak_emote = list("chitters")
- attack_sound = 'sound/weapons/bladeslice.ogg'
- aggro_vision_range = 9
- idle_vision_range = 2
- turns_per_move = 5
- loot = list(/obj/item/stack/ore/diamond{layer = 4.1},
- /obj/item/stack/ore/diamond{layer = 4.1})
-
-/obj/item/projectile/temp/basilisk
- name = "freezing blast"
- icon_state = "ice_2"
- damage = 0
- damage_type = BURN
- nodamage = 1
- flag = "energy"
- temperature = 50
-
-/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(var/new_target)
- if(..()) //we have a target
- if(isliving(target))
- var/mob/living/L = target
- if(L.bodytemperature > 261)
- L.bodytemperature = 261
- visible_message("The [src.name]'s stare chills [L.name] to the bone!")
-
-/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity)
- switch(severity)
- if(1.0)
- gib()
- if(2.0)
- adjustBruteLoss(140)
- if(3.0)
- adjustBruteLoss(110)
-
-/mob/living/simple_animal/hostile/asteroid/goliath
- name = "goliath"
- desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
- icon = 'icons/mob/animal.dmi'
- icon_state = "Goliath"
- icon_living = "Goliath"
- icon_aggro = "Goliath_alert"
- icon_dead = "Goliath_dead"
- icon_gib = "syndicate_gib"
- attack_sound = 'sound/weapons/punch4.ogg'
- mouse_opacity = MOUSE_OPACITY_OPAQUE
- move_to_delay = 40
- ranged = 1
- ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
- ranged_cooldown_time = 120
- friendly = "wails at"
- speak_emote = list("bellows")
- vision_range = 4
- speed = 3
- maxHealth = 300
- health = 300
- harm_intent_damage = 1 //Only the manliest of men can kill a Goliath with only their fists.
- obj_damage = 100
- melee_damage_lower = 25
- melee_damage_upper = 25
- attacktext = "pulverizes"
- attack_sound = 'sound/weapons/punch1.ogg'
- throw_message = "does nothing to the rocky hide of the"
- aggro_vision_range = 9
- idle_vision_range = 5
- move_force = MOVE_FORCE_VERY_STRONG
- move_resist = MOVE_FORCE_VERY_STRONG
- pull_force = MOVE_FORCE_VERY_STRONG
- var/pre_attack = 0
- loot = list(/obj/item/stack/sheet/animalhide/goliath_hide{layer = ABOVE_MOB_LAYER})
-
-/mob/living/simple_animal/hostile/asteroid/goliath/Life()
- ..()
- handle_preattack()
-
-/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
- if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack)
- pre_attack++
- if(!pre_attack || stat || AIStatus == AI_IDLE)
- return
- icon_state = "Goliath_preattack"
-
-/mob/living/simple_animal/hostile/asteroid/goliath/revive()
- move_force = MOVE_FORCE_VERY_STRONG
- move_resist = MOVE_FORCE_VERY_STRONG
- pull_force = MOVE_FORCE_VERY_STRONG
- ..()
-
-/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire()
- var/tturf = get_turf(target)
- if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
- visible_message("The [src.name] digs its tentacles under [target.name]!")
- new /obj/effect/goliath_tentacle/original(tturf)
- ranged_cooldown = world.time + ranged_cooldown_time
- icon_state = icon_aggro
- pre_attack = 0
- return
-
-/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(damage)
- ranged_cooldown--
- handle_preattack()
- ..()
-
-/mob/living/simple_animal/hostile/asteroid/goliath/Aggro()
- vision_range = aggro_vision_range
- handle_preattack()
- if(icon_state != icon_aggro)
- icon_state = icon_aggro
- return
-
-/obj/effect/goliath_tentacle/
- name = "Goliath tentacle"
- icon = 'icons/mob/animal.dmi'
- icon_state = "Goliath_tentacle"
- var/latched = 0
-
-/obj/effect/goliath_tentacle/New()
- var/turftype = get_turf(src)
- if(istype(turftype, /turf/simulated/mineral))
- var/turf/simulated/mineral/M = turftype
- M.gets_drilled()
- spawn(20)
- Trip()
-
-/obj/effect/goliath_tentacle/original
-
-/obj/effect/goliath_tentacle/original/New()
- for(var/obj/effect/goliath_tentacle/original/O in loc)//No more GG NO RE from 2+ goliaths simultaneously tentacling you
- if(O != src)
- qdel(src)
- var/list/directions = cardinal.Copy()
- var/counter
- for(counter = 1, counter <= 3, counter++)
- var/spawndir = pick(directions)
- directions -= spawndir
- var/turf/T = get_step(src,spawndir)
- new /obj/effect/goliath_tentacle(T)
- ..()
-
-
-/obj/effect/goliath_tentacle/proc/Trip()
- for(var/mob/living/M in src.loc)
- M.Stun(5)
- M.adjustBruteLoss(rand(10,15))
- latched = 1
- if(src && M)
- visible_message("The [src.name] grabs hold of [M.name]!")
- if(!latched)
- qdel(src)
- else
- spawn(50)
- qdel(src)
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index a4f7cce2f51..0c5f2647ae8 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -33,6 +33,7 @@
ranged = 1
retreat_distance = 5
minimum_distance = 5
+ projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
casingtype = /obj/item/ammo_casing/a357
loot = list(/obj/effect/mob_spawn/human/corpse/russian/ranged, /obj/item/gun/projectile/revolver/mateba)
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 546fa3ad50d..d95c18dd831 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -262,6 +262,7 @@
minimum_distance = 5
icon_state = "syndicateranged"
icon_living = "syndicateranged"
+ projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
casingtype = /obj/item/ammo_casing/c45
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier, /obj/item/gun/projectile/automatic/c20r)
diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi
new file mode 100644
index 00000000000..e8f2d4ada83
Binary files /dev/null and b/icons/mob/actions/actions_animal.dmi differ