diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm
index c86be0af72f..ba4973fb229 100644
--- a/code/defines/procs/helpers.dm
+++ b/code/defines/procs/helpers.dm
@@ -937,7 +937,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
output += A
return output
-/proc/get_turf_loc(var/mob/M) //gets the location of the turf that the mob is on, or what the mob is in is on, etc
+/proc/get_turf_loc(var/atom/movable/M) //gets the location of the turf that the atom is on, or what the atom is in is on, etc
//in case they're in a closet or sleeper or something
var/atom/loc = M.loc
while(!istype(loc, /turf/))
diff --git a/code/modules/chemical/Chemistry-Recipes.dm b/code/modules/chemical/Chemistry-Recipes.dm
index 9272c726a91..0bcdf892f47 100644
--- a/code/modules/chemical/Chemistry-Recipes.dm
+++ b/code/modules/chemical/Chemistry-Recipes.dm
@@ -604,6 +604,65 @@ datum
return
+ metroidteleport
+ name = "Metroid Teleport"
+ id = "m_tele"
+ result = null
+ required_reagents = list("plasma" = 1, "acid" = 1)
+ result_amount = 1
+ required_container = /obj/item/metroid_core
+ required_other = 4
+ on_reaction(var/datum/reagents/holder, var/created_volume)
+
+ // Calculate new position (searches through beacons in world)
+ var/obj/item/device/radio/beacon/chosen
+ var/list/possible = list()
+ for(var/obj/item/device/radio/beacon/W in world)
+ possible += W
+
+ if(possible.len > 0)
+ chosen = pick(possible)
+
+ if(chosen)
+ // Calculate previous position for transition
+
+ var/turf/FROM = get_turf_loc(holder.my_atom) // the turf of origin we're travelling FROM
+ var/turf/TO = get_turf_loc(chosen) // the turf of origin we're travelling TO
+
+ playsound(TO, 'phasein.ogg', 100, 1)
+
+ var/list/flashers = list()
+ for(var/mob/living/carbon/M in viewers(TO, null))
+ flick("e_flash", M.flash) // flash dose faggots
+ flashers += M
+
+ var/y_distance = TO.y - FROM.y
+ var/x_distance = TO.x - FROM.x
+ for (var/atom/movable/A in range(3, FROM )) // iterate thru list of mobs in the area
+ if(A == chosen) continue // don't teleport the actual beacon that's just stupid as fukkkkk
+
+ var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, TO.z) // calculate the new place
+ if(!A.Move(newloc)) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving
+ A.loc = locate(A.x + x_distance, A.y + y_distance, TO.z)
+
+ spawn()
+ if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
+ var/mob/M = A
+ if(M.client)
+ var/obj/blueeffect = new /obj(src)
+ blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ blueeffect.icon = 'effects.dmi'
+ blueeffect.icon_state = "shieldsparkles"
+ blueeffect.layer = 17
+ blueeffect.mouse_opacity = 0
+ M.client.screen += blueeffect
+ sleep(20)
+ M.client.screen -= blueeffect
+ del(blueeffect)
+
+
+
+
metroidchloral
name = "Metroid Chloral"
id = "m_bunch"
diff --git a/code/modules/critters/critter.dm b/code/modules/critters/critter.dm
index bcbcc130216..4c2c0dfe370 100644
--- a/code/modules/critters/critter.dm
+++ b/code/modules/critters/critter.dm
@@ -60,6 +60,10 @@
angertext = "charges at"
attacktext = "attacks"
+ attack_sound = null // the sound it makes when it attacks!
+
+ attack_speed = 25 // delay of attack
+
proc
patrol_step()
@@ -71,6 +75,7 @@
TakeDamage(var/damage = 0)
Target_Attacker(var/target)
Harvest(var/obj/item/weapon/W, var/mob/living/user)//Controls havesting things from dead critters
+ AfterAttack(var/mob/living/target)
diff --git a/code/modules/critters/critter_AI.dm b/code/modules/critters/critter_AI.dm
index cd8d8055f2a..5fed407dea7 100644
--- a/code/modules/critters/critter_AI.dm
+++ b/code/modules/critters/critter_AI.dm
@@ -153,13 +153,40 @@
for(var/mob/O in viewers(src, null))
O.show_message("\red [src] [src.attacktext] [src.target]!", 1)
if(ismob(src.target))
- src.target:bruteloss += rand(melee_damage_lower,melee_damage_upper)
+
+
+ var/damage = rand(melee_damage_lower, melee_damage_upper)
+
+ if(istype(target, /mob/living/carbon/human))
+ var/dam_zone = pick("head", "chest", "l_hand", "r_hand", "l_leg", "r_leg", "groin")
+ if (dam_zone == "chest")
+ if ((((target:wear_suit && target:wear_suit.body_parts_covered & UPPER_TORSO) || (target:w_uniform && target:w_uniform.body_parts_covered & LOWER_TORSO)) && prob(10)))
+ if(prob(20))
+ target:show_message("\blue You have been protected from a hit to the chest.")
+ return
+ if (istype(target:organs[text("[]", dam_zone)], /datum/organ/external))
+ var/datum/organ/external/temp = target:organs[text("[]", dam_zone)]
+ if (temp.take_damage(damage, 0))
+ target:UpdateDamageIcon()
+ else
+ target:UpdateDamage()
+ target:updatehealth()
+
+ else
+ target:bruteloss += damage
+
+ if(attack_sound)
+ playsound(loc, attack_sound, 50, 1, -1)
+
+ AfterAttack(target)
+
+
if(isobj(src.target))
if(istype(target, /obj/mecha))
src.target:take_damage(rand(melee_damage_lower,melee_damage_upper))
else
src.target:TakeDamage(rand(melee_damage_lower,melee_damage_upper))
- spawn(25)
+ spawn(attack_speed)
src.attacking = 0
return
diff --git a/code/modules/critters/critter_defenses.dm b/code/modules/critters/critter_defenses.dm
index b31dcfdb3fd..5d944e40acb 100644
--- a/code/modules/critters/critter_defenses.dm
+++ b/code/modules/critters/critter_defenses.dm
@@ -34,8 +34,9 @@ Contains the procs that control attacking critters
if(!target) return
src.target = target
src.oldtarget_name = target:name
- for(var/mob/O in viewers(src, null))
- O.show_message("\red [src] [src.angertext] [target:name]!", 1)
+ if(task != "chasing")
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [src] [src.angertext] [target:name]!", 1)
src.task = "chasing"
return
diff --git a/code/modules/critters/critters.dm b/code/modules/critters/critters.dm
index ad4d215d19f..3d03574946c 100644
--- a/code/modules/critters/critters.dm
+++ b/code/modules/critters/critters.dm
@@ -145,9 +145,13 @@
firevuln = 2
brutevuln = 1
melee_damage_lower = 5
- melee_damage_upper = 10
- angertext = "swims at"
+ melee_damage_upper = 15
+ angertext = "lunges at"
attacktext = "bites"
+ attack_sound = 'bite.ogg'
+ attack_speed = 10
+ var/stunchance = 10 // chance to tackle things down
+
Harvest(var/obj/item/weapon/W, var/mob/living/user)
@@ -167,14 +171,24 @@
return 1
return 0
+ AfterAttack(var/mob/living/target)
+ if(prob(stunchance))
+ if(target.weakened <= 0)
+ target.weakened += rand(10, 15)
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [src] knocks down [target]!", 1)
+ playsound(loc, 'pierce.ogg', 25, 1, -1)
+
/obj/critter/spesscarp/elite
- desc = "Oh shit, you're really fucked now. It has an evil gleam in it's eye."
+ desc = "Oh shit, you're really fucked now. It has an evil gleam in its eye."
health = 50
max_health = 50
- melee_damage_lower = 10
- melee_damage_upper = 20
+ melee_damage_lower = 20
+ melee_damage_upper = 35
+ stunchance = 15
+ attack_speed = 7
// opensdoors = 1 would give all access dono if want
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index c30e399a9c3..517bfda3ca8 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -635,8 +635,8 @@
var/damage = rand(1, 3)
- if(istype(src, /mob/living/carbon/metroid/adult))
- damage = rand(20, 40)
+ if(istype(M, /mob/living/carbon/metroid/adult))
+ damage = rand(10, 40)
else
damage = rand(5, 35)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5e0cd6d6d93..889aa9eb0de 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1664,10 +1664,10 @@
var/damage = rand(1, 3)
- if(istype(src, /mob/living/carbon/metroid/adult))
- damage = rand(20, 40)
+ if(istype(M, /mob/living/carbon/metroid/adult))
+ damage = rand(10, 35)
else
- damage = rand(5, 35)
+ damage = rand(5, 25)
var/dam_zone = pick("head", "chest", "l_hand", "r_hand", "l_leg", "r_leg", "groin")