diff --git a/baystation12.dme b/baystation12.dme
index 52310b50e6..a5e0a39cf0 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -118,6 +118,7 @@
#define FILE_DIR "code/modules/mob/living/carbon/alien/humanoid/caste"
#define FILE_DIR "code/modules/mob/living/carbon/alien/larva"
#define FILE_DIR "code/modules/mob/living/carbon/alien/special"
+#define FILE_DIR "code/modules/mob/living/carbon/amorph"
#define FILE_DIR "code/modules/mob/living/carbon/brain"
#define FILE_DIR "code/modules/mob/living/carbon/human"
#define FILE_DIR "code/modules/mob/living/carbon/metroid"
@@ -918,6 +919,7 @@
#include "code\modules\mining\ores_materials_coins.dm"
#include "code\modules\mining\satchel_ore_box.dm"
#include "code\modules\mob\death.dm"
+#include "code\modules\mob\emote.dm"
#include "code\modules\mob\login.dm"
#include "code\modules\mob\logout.dm"
#include "code\modules\mob\mob.dm"
@@ -972,6 +974,11 @@
#include "code\modules\mob\living\carbon\alien\special\muton.dm"
#include "code\modules\mob\living\carbon\alien\special\sectoid.dm"
#include "code\modules\mob\living\carbon\alien\special\snakeman.dm"
+#include "code\modules\mob\living\carbon\amorph\amorph.dm"
+#include "code\modules\mob\living\carbon\amorph\amorph_damage.dm"
+#include "code\modules\mob\living\carbon\amorph\amorph_hud.dm"
+#include "code\modules\mob\living\carbon\amorph\life.dm"
+#include "code\modules\mob\living\carbon\amorph\say.dm"
#include "code\modules\mob\living\carbon\brain\brain.dm"
#include "code\modules\mob\living\carbon\brain\death.dm"
#include "code\modules\mob\living\carbon\brain\hud.dm"
diff --git a/code/game/hud.dm b/code/game/hud.dm
index b46567040e..506b0cfeb2 100644
--- a/code/game/hud.dm
+++ b/code/game/hud.dm
@@ -194,6 +194,9 @@ obj/hud/New(var/type = 0)
else if(isrobot(mymob))
robot_hud()
+ else if(isamorph(mymob))
+ amorph_hud()
+
// else if(ishivebot(mymob))
// hivebot_hud()
diff --git a/code/modules/mining/satchel_ore_box.dm b/code/modules/mining/satchel_ore_box.dm
index 75c99097c5..35378419e0 100644
--- a/code/modules/mining/satchel_ore_box.dm
+++ b/code/modules/mining/satchel_ore_box.dm
@@ -45,7 +45,7 @@
/**********************Ore box**************************/
/obj/structure/ore_box
- icon = 'mining.dmi'
+ //icon = 'mining.dmi'
icon_state = "orebox0"
name = "Ore Box"
desc = "It's heavy"
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
new file mode 100644
index 0000000000..783f3404e8
--- /dev/null
+++ b/code/modules/mob/emote.dm
@@ -0,0 +1,50 @@
+// All mobs should have custom emote, really..
+mob/proc/custom_emote(var/m_type=1,var/message = null)
+
+ if(!emote_allowed && usr == src)
+ usr << "You are unable to emote."
+ return
+
+ var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle)
+ if(m_type == 2 && muzzled) return
+
+ var/input
+ if(!message)
+ input = copytext(sanitize(input(src,"Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN)
+ else
+ input = message
+ if(input)
+ message = "[src] [input]"
+ else
+ return
+
+
+ if (message)
+ log_emote("[name]/[key] : [message]")
+
+ //Hearing gasp and such every five seconds is not good emotes were not global for a reason.
+ // Maybe some people are okay with that.
+
+ for(var/mob/M in world)
+ if (!M.client)
+ continue //skip monkeys and leavers
+ if (istype(M, /mob/new_player))
+ continue
+ if(findtext(message," snores.")) //Because we have so many sleeping people.
+ continue
+ if(M.stat == 2 && M.client.ghost_sight && !(M in viewers(src,null)))
+ M.show_message(message)
+
+
+ if (m_type & 1)
+ for (var/mob/O in viewers(src, null))
+ if(istype(O,/mob/living/carbon/human))
+ for(var/mob/living/parasite/P in O:parasites)
+ P.show_message(message, m_type)
+ O.show_message(message, m_type)
+ else if (m_type & 2)
+ for (var/mob/O in hearers(src.loc, null))
+ if(istype(O,/mob/living/carbon/human))
+ for(var/mob/living/parasite/P in O:parasites)
+ P.show_message(message, m_type)
+ O.show_message(message, m_type)
diff --git a/code/modules/mob/living/carbon/amorph/amorph.dm b/code/modules/mob/living/carbon/amorph/amorph.dm
new file mode 100644
index 0000000000..c2af2ff75d
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/amorph.dm
@@ -0,0 +1,590 @@
+/mob/living/carbon/amorph
+ name = "amorph"
+ real_name = "amorph"
+ voice_name = "amorph"
+ icon = 'icons/mob/amorph.dmi'
+ icon_state = ""
+
+
+ var/species = "Amorph"
+ age = 30.0
+
+ var/used_skillpoints = 0
+ var/skill_specialization = null
+ var/list/skills = null
+
+ var/obj/item/l_ear = null
+
+ // might use this later to recolor armorphs with icon.SwapColor
+ var/slime_color = null
+
+ var/examine_text = ""
+
+
+/mob/living/carbon/amorph/New()
+
+ ..()
+
+ // Amorphs don't have a blood vessel, but they can have reagents in their body
+ var/datum/reagents/R = new/datum/reagents(1000)
+ reagents = R
+ R.my_atom = src
+
+ // Amorphs have no DNA(they're more like carbon-based machines)
+
+ // Amorphs don't have organs
+ ..()
+
+/mob/living/carbon/amorph/Bump(atom/movable/AM as mob|obj, yes)
+ if ((!( yes ) || now_pushing))
+ return
+ now_pushing = 1
+ if (ismob(AM))
+ var/mob/tmob = AM
+
+//BubbleWrap - Should stop you pushing a restrained person out of the way
+
+ if(istype(tmob, /mob/living/carbon/human))
+
+ for(var/mob/M in range(tmob, 1))
+ if( ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
+ if ( !(world.time % 5) )
+ src << "\red [tmob] is restrained, you cannot push past"
+ now_pushing = 0
+ return
+ if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
+ if ( !(world.time % 5) )
+ src << "\red [tmob] is restraining [M], you cannot push past"
+ now_pushing = 0
+ return
+
+ //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
+ if((tmob.a_intent == "help" || tmob.restrained()) && (a_intent == "help" || src.restrained()) && tmob.canmove && canmove) // mutual brohugs all around!
+ var/turf/oldloc = loc
+ loc = tmob.loc
+ tmob.loc = oldloc
+ now_pushing = 0
+ for(var/mob/living/carbon/metroid/Metroid in view(1,tmob))
+ if(Metroid.Victim == tmob)
+ Metroid.UpdateFeed()
+ return
+
+ if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
+ if(prob(99))
+ now_pushing = 0
+ return
+ if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot))
+ if(prob(99))
+ now_pushing = 0
+ return
+ if(tmob.nopush)
+ now_pushing = 0
+ return
+
+ tmob.LAssailant = src
+
+ now_pushing = 0
+ spawn(0)
+ ..()
+ if (!istype(AM, /atom/movable))
+ return
+ if (!now_pushing)
+ now_pushing = 1
+
+ if (!AM.anchored)
+ var/t = get_dir(src, AM)
+ if (istype(AM, /obj/structure/window))
+ if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST)
+ for(var/obj/structure/window/win in get_step(AM,t))
+ now_pushing = 0
+ return
+ step(AM, t)
+ now_pushing = 0
+ return
+ return
+
+/mob/living/carbon/amorph/movement_delay()
+ var/tally = 2 // amorphs are a bit slower than humans
+ var/mob/M = pulling
+
+ if(reagents.has_reagent("hyperzine")) return -1
+
+ if(reagents.has_reagent("nuka_cola")) return -1
+
+ if(analgesic) return -1
+
+ if (istype(loc, /turf/space)) return -1 // It's hard to be slowed down in space by... anything
+
+ var/health_deficiency = traumatic_shock
+ if(health_deficiency >= 40) tally += (health_deficiency / 25)
+
+ var/hungry = (500 - nutrition)/5 // So overeat would be 100 and default level would be 80
+ if (hungry >= 70) tally += hungry/300
+
+ if (bodytemperature < 283.222)
+ tally += (283.222 - bodytemperature) / 10 * 1.75
+ if (stuttering < 10)
+ stuttering = 10
+
+ if(shock_stage >= 10) tally += 3
+
+ if(tally < 0)
+ tally = 0
+
+ if(istype(M) && M.lying) //Pulling lying down people is slower
+ tally += 3
+
+ if(mRun in mutations)
+ tally = 0
+
+ return tally
+
+/mob/living/carbon/amorph/Stat()
+ ..()
+ statpanel("Status")
+
+ stat(null, "Intent: [a_intent]")
+ stat(null, "Move Mode: [m_intent]")
+ if(ticker && ticker.mode && ticker.mode.name == "AI malfunction")
+ if(ticker.mode:malf_mode_declared)
+ stat(null, "Time left: [max(ticker.mode:AI_win_timeleft/(ticker.mode:apcs/3), 0)]")
+ if(emergency_shuttle)
+ if(emergency_shuttle.online && emergency_shuttle.location < 2)
+ var/timeleft = emergency_shuttle.timeleft()
+ if (timeleft)
+ stat(null, "ETA-[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]")
+
+ if (client.statpanel == "Status")
+ if (internal)
+ if (!internal.air_contents)
+ del(internal)
+ else
+ stat("Internal Atmosphere Info", internal.name)
+ stat("Tank Pressure", internal.air_contents.return_pressure())
+ stat("Distribution Pressure", internal.distribute_pressure)
+ if (mind)
+ if (mind.special_role == "Changeling" && changeling)
+ stat("Chemical Storage", changeling.chem_charges)
+ stat("Genetic Damage Time", changeling.geneticdamage)
+
+/mob/living/carbon/amorph/ex_act(severity)
+ flick("flash", flash)
+
+ var/shielded = 0
+ var/b_loss = null
+ var/f_loss = null
+ switch (severity)
+ if (1.0)
+ b_loss += 500
+ if (!prob(getarmor(null, "bomb")))
+ gib()
+ return
+ else
+ var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
+ throw_at(target, 200, 4)
+
+ if (2.0)
+ if (!shielded)
+ b_loss += 60
+
+ f_loss += 60
+
+ if (!prob(getarmor(null, "bomb")))
+ b_loss = b_loss/1.5
+ f_loss = f_loss/1.5
+
+ if(3.0)
+ b_loss += 30
+ if (!prob(getarmor(null, "bomb")))
+ b_loss = b_loss/2
+ if (prob(50) && !shielded)
+ Paralyse(10)
+
+ src.bruteloss += b_loss
+ src.fireloss += f_loss
+
+ UpdateDamageIcon()
+
+
+/mob/living/carbon/amorph/blob_act()
+ if(stat == 2) return
+ show_message("\red The blob attacks you!")
+ src.bruteloss += rand(30,40)
+ UpdateDamageIcon()
+ return
+
+/mob/living/carbon/amorph/u_equip(obj/item/W as obj)
+ // These are the only slots an amorph has
+ if (W == l_ear)
+ l_ear = null
+ else if (W == r_hand)
+ r_hand = null
+
+ update_clothing()
+
+/mob/living/carbon/amorph/db_click(text, t1)
+ var/obj/item/W = equipped()
+ var/emptyHand = (W == null)
+ if ((!emptyHand) && (!istype(W, /obj/item)))
+ return
+ if (emptyHand)
+ usr.next_move = usr.prev_move
+ usr:lastDblClick -= 3 //permit the double-click redirection to proceed.
+ switch(text)
+ if("l_ear")
+ if (l_ear)
+ if (emptyHand)
+ l_ear.DblClick()
+ return
+ else if(emptyHand)
+ return
+ if (!( istype(W, /obj/item/clothing/ears) ) && !( istype(W, /obj/item/device/radio/headset) ) && W.w_class != 1)
+ return
+ u_equip(W)
+ l_ear = W
+ W.equipped(src, text)
+
+ update_clothing()
+
+ return
+
+/mob/living/carbon/amorph/meteorhit(O as obj)
+ for(var/mob/M in viewers(src, null))
+ if ((M.client && !( M.blinded )))
+ M.show_message(text("\red [] has been hit by []", src, O), 1)
+ if (health > 0)
+ if (istype(O, /obj/effect/immovablerod))
+ src.bruteloss += 101
+ else
+ src.bruteloss += 25
+ UpdateDamageIcon()
+ updatehealth()
+ return
+
+/mob/living/carbon/amorph/Move(a, b, flag)
+
+ if (buckled)
+ return
+
+ if (restrained())
+ pulling = null
+
+
+ var/t7 = 1
+ if (restrained())
+ for(var/mob/M in range(src, 1))
+ if ((M.pulling == src && M.stat == 0 && !( M.restrained() )))
+ t7 = null
+ if ((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving)))))
+ var/turf/T = loc
+ . = ..()
+
+ if (pulling && pulling.loc)
+ if(!( isturf(pulling.loc) ))
+ pulling = null
+ return
+ else
+ if(Debug)
+ diary <<"pulling disappeared? at [__LINE__] in mob.dm - pulling = [pulling]"
+ diary <<"REPORT THIS"
+
+ /////
+ if(pulling && pulling.anchored)
+ pulling = null
+ return
+
+ if (!restrained())
+ var/diag = get_dir(src, pulling)
+ if ((diag - 1) & diag)
+ else
+ diag = null
+ if ((get_dist(src, pulling) > 1 || diag))
+ if (ismob(pulling))
+ var/mob/M = pulling
+ var/ok = 1
+ if (locate(/obj/item/weapon/grab, M.grabbed_by))
+ if (prob(75))
+ var/obj/item/weapon/grab/G = pick(M.grabbed_by)
+ if (istype(G, /obj/item/weapon/grab))
+ for(var/mob/O in viewers(M, null))
+ O.show_message(text("\red [] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1)
+ //G = null
+ del(G)
+ else
+ ok = 0
+ if (locate(/obj/item/weapon/grab, M.grabbed_by.len))
+ ok = 0
+ if (ok)
+ var/t = M.pulling
+ M.pulling = null
+
+ //this is the gay blood on floor shit -- Added back -- Skie
+ if (M.lying && (prob(M.getBruteLoss() / 6)))
+ var/turf/location = M.loc
+ if (istype(location, /turf/simulated))
+ location.add_blood(M)
+ if(ishuman(M))
+ var/mob/living/carbon/H = M
+ var/blood_volume = round(H:vessel.get_reagent_amount("blood"))
+ if(blood_volume > 0)
+ H:vessel.remove_reagent("blood",1)
+ if(prob(5))
+ M.adjustBruteLoss(1)
+ visible_message("\red \The [M]'s wounds open more from being dragged!")
+ if(M.pull_damage())
+ if(prob(25))
+ M.adjustBruteLoss(2)
+ visible_message("\red \The [M]'s wounds worsen terribly from being dragged!")
+ var/turf/location = M.loc
+ if (istype(location, /turf/simulated))
+ location.add_blood(M)
+ if(ishuman(M))
+ var/mob/living/carbon/H = M
+ var/blood_volume = round(H:vessel.get_reagent_amount("blood"))
+ if(blood_volume > 0)
+ H:vessel.remove_reagent("blood",1)
+
+ step(pulling, get_dir(pulling.loc, T))
+ M.pulling = t
+ else
+ if (pulling)
+ if (istype(pulling, /obj/structure/window))
+ if(pulling:ini_dir == NORTHWEST || pulling:ini_dir == NORTHEAST || pulling:ini_dir == SOUTHWEST || pulling:ini_dir == SOUTHEAST)
+ for(var/obj/structure/window/win in get_step(pulling,get_dir(pulling.loc, T)))
+ pulling = null
+ if (pulling)
+ step(pulling, get_dir(pulling.loc, T))
+ else
+ pulling = null
+ . = ..()
+ if ((s_active && !( s_active in contents ) ))
+ s_active.close(src)
+
+ for(var/mob/living/carbon/metroid/M in view(1,src))
+ M.UpdateFeed(src)
+ return
+
+/mob/living/carbon/amorph/proc/misc_clothing_updates()
+ // Temporary proc to shove stuff in that was put into update_clothing()
+ // for questionable reasons
+
+ if (client)
+ if (i_select)
+ if (intent)
+ client.screen += hud_used.intents
+
+ var/list/L = dd_text2list(intent, ",")
+ L[1] += ":-11"
+ i_select.screen_loc = dd_list2text(L,",") //ICONS4
+ else
+ i_select.screen_loc = null
+ if (m_select)
+ if (m_int)
+ client.screen += hud_used.mov_int
+
+ var/list/L = dd_text2list(m_int, ",")
+ L[1] += ":-11"
+ m_select.screen_loc = dd_list2text(L,",") //ICONS4
+ else
+ m_select.screen_loc = null
+
+ // Probably a lazy way to make sure all items are on the screen exactly once
+ if (client)
+ client.screen -= contents
+ client.screen += contents
+
+/mob/living/carbon/amorph/rebuild_appearance()
+ // Lazy method: Just rebuild everything.
+ // This can be called when the mob is created, but on other occasions, rebuild_body_overlays(),
+ // rebuild_clothing_overlays() etc. should be called individually.
+
+ misc_clothing_updates() // silly stuff
+
+/mob/living/carbon/amorph/update_body_appearance()
+ // Should be called whenever something about the body appearance itself changes.
+
+ misc_clothing_updates() // silly stuff
+
+ if(lying)
+ icon_state = "lying"
+ else
+ icon_state = "standing"
+
+/mob/living/carbon/amorph/update_lying()
+ // Should be called whenever something about the lying status of the mob might have changed.
+
+ if(lying)
+ icon_state = "lying"
+ else
+ icon_state = "standing"
+
+/mob/living/carbon/amorph/hand_p(mob/M as mob)
+ // not even sure what this is meant to do
+ return
+
+/mob/living/carbon/amorph/restrained()
+ if (handcuffed)
+ return 0 // handcuffs don't work on amorphs
+ return 0
+
+/mob/living/carbon/amorph/var/co2overloadtime = null
+/mob/living/carbon/amorph/var/temperature_resistance = T0C+75
+
+/mob/living/carbon/amorph/show_inv(mob/user as mob)
+ // TODO: add a window for extracting stuff from an amorph's mouth
+
+// called when something steps onto an amorph
+// this could be made more general, but for now just handle mulebot
+/mob/living/carbon/amorph/HasEntered(var/atom/movable/AM)
+ var/obj/machinery/bot/mulebot/MB = AM
+ if(istype(MB))
+ MB.RunOver(src)
+
+//gets assignment from ID or ID inside PDA or PDA itself
+//Useful when player do something with computers
+/mob/living/carbon/amorph/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job")
+ // TODO: get the ID from the amorph's contents
+ return
+
+//gets name from ID or ID inside PDA or PDA itself
+//Useful when player do something with computers
+/mob/living/carbon/amorph/proc/get_authentification_name(var/if_no_id = "Unknown")
+ // TODO: get the ID from the amorph's contents
+ return
+
+//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere
+/mob/living/carbon/amorph/proc/get_visible_name()
+ // amorphs can't wear clothes or anything, so always return face_name
+ return get_face_name()
+
+//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable
+/mob/living/carbon/amorph/proc/get_face_name()
+ // there might later be ways for amorphs to change the appearance of their face
+ return "[real_name]"
+
+
+//gets ID card object from special clothes slot or null.
+/mob/living/carbon/amorph/proc/get_idcard()
+ // TODO: get the ID from the amorph's contents
+
+
+// heal the amorph
+/mob/living/carbon/amorph/heal_overall_damage(var/brute, var/burn)
+ bruteloss -= brute
+ fireloss -= burn
+ bruteloss = max(bruteloss, 0)
+ fireloss = max(fireloss, 0)
+
+ updatehealth()
+ UpdateDamageIcon()
+
+// damage MANY external organs, in random order
+/mob/living/carbon/amorph/take_overall_damage(var/brute, var/burn, var/used_weapon = null)
+ bruteloss += brute
+ fireloss += burn
+
+ updatehealth()
+ UpdateDamageIcon()
+
+/mob/living/carbon/amorph/Topic(href, href_list)
+ if (href_list["refresh"])
+ if((machine)&&(in_range(src, usr)))
+ show_inv(machine)
+
+ if (href_list["mach_close"])
+ var/t1 = text("window=[]", href_list["mach_close"])
+ machine = null
+ src << browse(null, t1)
+
+ if ((href_list["item"] && !( usr.stat ) && usr.canmove && !( usr.restrained() ) && in_range(src, usr) && ticker)) //if game hasn't started, can't make an equip_e
+ var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( )
+ O.source = usr
+ O.target = src
+ O.item = usr.equipped()
+ O.s_loc = usr.loc
+ O.t_loc = loc
+ O.place = href_list["item"]
+ if(href_list["loc"])
+ O.internalloc = href_list["loc"]
+ requests += O
+ spawn( 0 )
+ O.process()
+ return
+
+ if (href_list["criminal"])
+ if(istype(usr, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = usr
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.glasses, /obj/item/clothing/glasses/sunglasses/sechud))
+ var/perpname = "wot"
+ var/modified = 0
+
+ /*if(wear_id)
+ if(istype(wear_id,/obj/item/weapon/card/id))
+ perpname = wear_id:registered_name
+ else if(istype(wear_id,/obj/item/device/pda))
+ var/obj/item/device/pda/tempPda = wear_id
+ perpname = tempPda.owner
+ else*/
+ perpname = src.name
+
+ for (var/datum/data/record/E in data_core.general)
+ if (E.fields["name"] == perpname)
+ for (var/datum/data/record/R in data_core.security)
+ if (R.fields["id"] == E.fields["id"])
+
+ var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Parolled", "Released", "Cancel")
+
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.glasses, /obj/item/clothing/glasses/sunglasses/sechud))
+ if(setcriminal != "Cancel")
+ R.fields["criminal"] = setcriminal
+ modified = 1
+
+ spawn()
+ H.handle_regular_hud_updates()
+
+ if(!modified)
+ usr << "\red Unable to locate a data core entry for this person."
+ ..()
+ return
+
+
+///eyecheck()
+///Returns a number between -1 to 2
+/mob/living/carbon/amorph/eyecheck()
+ return 1
+
+
+/mob/living/carbon/amorph/IsAdvancedToolUser()
+ return 1//Amorphs can use guns and such
+
+
+/mob/living/carbon/amorph/updatehealth()
+ if(src.nodamage)
+ src.health = 100
+ src.stat = 0
+ return
+ src.health = 100 - src.getOxyLoss() - src.getToxLoss() - src.getFireLoss() - src.getBruteLoss() - src.getCloneLoss() -src.halloss
+ return
+
+/mob/living/carbon/amorph/abiotic(var/full_body = 0)
+ return 0
+
+/mob/living/carbon/amorph/abiotic2(var/full_body2 = 0)
+ return 0
+
+/mob/living/carbon/amorph/getBruteLoss()
+ return src.bruteloss
+
+/mob/living/carbon/amorph/adjustBruteLoss(var/amount, var/used_weapon = null)
+ src.bruteloss += amount
+ if(bruteloss < 0) bruteloss = 0
+
+/mob/living/carbon/amorph/getFireLoss()
+ return src.fireloss
+
+/mob/living/carbon/amorph/adjustFireLoss(var/amount,var/used_weapon = null)
+ src.fireloss += amount
+ if(fireloss < 0) fireloss = 0
+
+/mob/living/carbon/amorph/get_visible_gender()
+ return gender
diff --git a/code/modules/mob/living/carbon/amorph/amorph_attack.dm b/code/modules/mob/living/carbon/amorph/amorph_attack.dm
new file mode 100644
index 0000000000..b8c4aa8b60
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/amorph_attack.dm
@@ -0,0 +1,248 @@
+
+
+/mob/living/carbon/amorph/attack_paw(mob/living/carbon/monkey/M as mob)
+ if (!ticker)
+ M << "You cannot attack people before the game has started."
+ return
+
+ ..()
+
+ switch(M.a_intent)
+
+ if ("help")
+ help_shake_act(M)
+ else
+ if (istype(wear_mask, /obj/item/clothing/mask/muzzle))
+ return
+ if (health > 0)
+ attacked += 10
+ playsound(loc, 'bite.ogg', 50, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [M.name] has bit [src]!"), 1)
+ adjustBruteLoss(rand(0, 1))
+ updatehealth()
+ return
+
+/mob/living/carbon/amorph/attack_hand(mob/living/carbon/human/M as mob)
+
+ if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves))
+ var/obj/item/clothing/gloves/G = M.gloves
+ if(G.cell)
+ if(M.a_intent == "hurt")//Stungloves. Any contact will stun the alien.
+ if(G.cell.charge >= 2500)
+ G.cell.charge -= 2500
+ Weaken(5)
+ if (stuttering < 5)
+ stuttering = 5
+ Stun(5)
+
+ for(var/mob/O in viewers(src, null))
+ if (O.client)
+ O.show_message("\red [src] has been touched with the stun gloves by [M]!", 1, "\red You hear someone fall", 2)
+ return
+ else
+ M << "\red Not enough charge! "
+ return
+
+ if (M.a_intent == "help")
+ help_shake_act(M)
+ else
+ if (M.a_intent == "hurt")
+ var/attack_verb
+ switch(M.mutantrace)
+ if("lizard")
+ attack_verb = "scratch"
+ if("plant")
+ attack_verb = "slash"
+ else
+ attack_verb = "punch"
+
+ if(M.type == /mob/living/carbon/human/tajaran)
+ attack_verb = "slash"
+
+ if ((prob(75) && health > 0))
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has [attack_verb]ed [name]!", M), 1)
+
+ var/damage = rand(5, 10)
+ if(M.type != /mob/living/carbon/human/tajaran)
+ playsound(loc, "punch", 25, 1, -1)
+ else if(M.type == /mob/living/carbon/human/tajaran)
+ damage += 10
+ playsound(loc, 'slice.ogg', 25, 1, -1)
+ adjustBruteLoss(damage/10)
+ updatehealth()
+ else
+ if(M.type != /mob/living/carbon/human/tajaran)
+ playsound(loc, 'punchmiss.ogg', 25, 1, -1)
+ else if(M.type == /mob/living/carbon/human/tajaran)
+ playsound(loc, 'slashmiss.ogg', 25, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has attempted to [attack_verb] [name]!", M), 1)
+ else
+ if (M.a_intent == "grab")
+ if (M == src)
+ return
+
+ var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M )
+ G.assailant = M
+ if (M.hand)
+ M.l_hand = G
+ else
+ M.r_hand = G
+ G.layer = 20
+ G.affecting = src
+ grabbed_by += G
+ G.synch()
+
+ LAssailant = M
+
+ playsound(loc, 'thudswoosh.ogg', 50, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ O.show_message(text("\red [] has grabbed [name] passively!", M), 1)
+
+ else
+ if (!( paralysis ))
+ drop_item()
+ playsound(loc, 'thudswoosh.ogg', 50, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has disarmed [name]!", M), 1)
+ return
+
+
+
+/mob/living/carbon/amorph/attack_alien(mob/living/carbon/alien/humanoid/M as mob)
+
+ switch(M.a_intent)
+ if ("help")
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1)
+
+ if ("hurt")
+ if ((prob(95) && health > 0))
+ playsound(loc, 'slice.ogg', 25, 1, -1)
+ var/damage = rand(15, 30)
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has slashed [name]!", M), 1)
+ adjustBruteLoss(damage/10)
+ updatehealth()
+ react_to_attack(M)
+ else
+ playsound(loc, 'slashmiss.ogg', 25, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has attempted to lunge at [name]!", M), 1)
+
+ if ("grab")
+ if (M == src)
+ return
+ var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M )
+ G.assailant = M
+ if (M.hand)
+ M.l_hand = G
+ else
+ M.r_hand = G
+ G.layer = 20
+ G.affecting = src
+ grabbed_by += G
+ G.synch()
+
+ LAssailant = M
+
+ playsound(loc, 'thudswoosh.ogg', 50, 1, -1)
+ for(var/mob/O in viewers(src, null))
+ O.show_message(text("\red [] has grabbed [name] passively!", M), 1)
+
+ if ("disarm")
+ playsound(loc, 'pierce.ogg', 25, 1, -1)
+ var/damage = 5
+ if(prob(95))
+ Weaken(rand(10,15))
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has tackled down [name]!", M), 1)
+ else
+ drop_item()
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red [] has disarmed [name]!", M), 1)
+ adjustBruteLoss(damage)
+ react_to_attack(M)
+ updatehealth()
+ return
+
+
+
+/mob/living/carbon/amorph/attack_animal(mob/living/simple_animal/M as mob)
+ if(M.melee_damage_upper == 0)
+ M.emote("[M.friendly] [src]")
+ else
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [M] [M.attacktext] [src]!", 1)
+ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ bruteloss += damage
+
+/mob/living/carbon/amorph/attack_metroid(mob/living/carbon/metroid/M as mob)
+ if(M.Victim) return // can't attack while eating!
+
+ if (health > -100)
+
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red The [M.name] has [pick("bit","slashed")] []!", src), 1)
+
+ var/damage = rand(1, 3)
+
+ if(istype(M, /mob/living/carbon/metroid/adult))
+ damage = rand(10, 35)
+ else
+ damage = rand(5, 25)
+
+ src.cloneloss += damage
+
+ UpdateDamageIcon()
+
+
+ if(M.powerlevel > 0)
+ var/stunprob = 10
+ var/power = M.powerlevel + rand(0,3)
+
+ switch(M.powerlevel)
+ if(1 to 2) stunprob = 20
+ if(3 to 4) stunprob = 30
+ if(5 to 6) stunprob = 40
+ if(7 to 8) stunprob = 60
+ if(9) stunprob = 70
+ if(10) stunprob = 95
+
+ if(prob(stunprob))
+ M.powerlevel -= 3
+ if(M.powerlevel < 0)
+ M.powerlevel = 0
+
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\red The [M.name] has shocked []!", src), 1)
+
+ Weaken(power)
+ if (stuttering < power)
+ stuttering = power
+ Stun(power)
+
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+
+ if (prob(stunprob) && M.powerlevel >= 8)
+ adjustFireLoss(M.powerlevel * rand(6,10))
+
+
+ updatehealth()
+
+ return
diff --git a/code/modules/mob/living/carbon/amorph/amorph_damage.dm b/code/modules/mob/living/carbon/amorph/amorph_damage.dm
new file mode 100644
index 0000000000..8e52d04292
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/amorph_damage.dm
@@ -0,0 +1,12 @@
+/mob/living/carbon/amorph/proc/HealDamage(zone, brute, burn)
+ return heal_overall_damage(brute, burn)
+
+/mob/living/carbon/amorph/UpdateDamageIcon()
+ // no damage sprites for amorphs yet
+ return
+
+/mob/living/carbon/amorph/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0, var/used_weapon = null)
+ if(damagetype == BRUTE)
+ take_overall_damage(damage, 0)
+ else
+ take_overall_damage(0, damage)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/amorph/amorph_hud.dm b/code/modules/mob/living/carbon/amorph/amorph_hud.dm
new file mode 100644
index 0000000000..91710d8053
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/amorph_hud.dm
@@ -0,0 +1,290 @@
+/obj/hud/proc/amorph_hud(var/ui_style='screen1_old.dmi')
+
+ src.adding = list( )
+ src.other = list( )
+ src.intents = list( )
+ src.mon_blo = list( )
+ src.m_ints = list( )
+ src.mov_int = list( )
+ src.vimpaired = list( )
+ src.darkMask = list( )
+ src.intent_small_hud_objects = list( )
+
+ src.g_dither = new src.h_type( src )
+ src.g_dither.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ src.g_dither.name = "Mask"
+ src.g_dither.icon = ui_style
+ src.g_dither.icon_state = "dither12g"
+ src.g_dither.layer = 18
+ src.g_dither.mouse_opacity = 0
+
+ src.alien_view = new src.h_type(src)
+ src.alien_view.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ src.alien_view.name = "Alien"
+ src.alien_view.icon = ui_style
+ src.alien_view.icon_state = "alien"
+ src.alien_view.layer = 18
+ src.alien_view.mouse_opacity = 0
+
+ src.blurry = new src.h_type( src )
+ src.blurry.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ src.blurry.name = "Blurry"
+ src.blurry.icon = ui_style
+ src.blurry.icon_state = "blurry"
+ src.blurry.layer = 17
+ src.blurry.mouse_opacity = 0
+
+ src.druggy = new src.h_type( src )
+ src.druggy.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ src.druggy.name = "Druggy"
+ src.druggy.icon = ui_style
+ src.druggy.icon_state = "druggy"
+ src.druggy.layer = 17
+ src.druggy.mouse_opacity = 0
+
+ var/obj/screen/using
+
+ using = new src.h_type( src )
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent)
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+//intent small hud objects
+ using = new src.h_type( src )
+ using.name = "help"
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "help" ? "help_small_active" : "help_small")
+ using.screen_loc = ui_help_small
+ using.layer = 21
+ src.adding += using
+ help_intent = using
+
+ using = new src.h_type( src )
+ using.name = "disarm"
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "disarm" ? "disarm_small_active" : "disarm_small")
+ using.screen_loc = ui_disarm_small
+ using.layer = 21
+ src.adding += using
+ disarm_intent = using
+
+ using = new src.h_type( src )
+ using.name = "grab"
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "grab" ? "grab_small_active" : "grab_small")
+ using.screen_loc = ui_grab_small
+ using.layer = 21
+ src.adding += using
+ grab_intent = using
+
+ using = new src.h_type( src )
+ using.name = "harm"
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm_small_active" : "harm_small")
+ using.screen_loc = ui_harm_small
+ using.layer = 21
+ src.adding += using
+ hurt_intent = using
+
+//end intent small hud objects
+
+ using = new src.h_type( src )
+ using.name = "mov_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+ move_intent = using
+
+ using = new src.h_type( src )
+ using.name = "drop"
+ using.icon = ui_style
+ using.icon_state = "act_drop"
+ using.screen_loc = ui_dropbutton
+ using.layer = 19
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "r_hand"
+ using.dir = WEST
+ using.icon = ui_style
+ using.icon_state = "hand_inactive"
+ if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use
+ using.icon_state = "hand_active"
+ using.screen_loc = ui_rhand
+ using.layer = 19
+ src.r_hand_hud_object = using
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "l_hand"
+ using.dir = EAST
+ using.icon = ui_style
+ using.icon_state = "hand_inactive"
+ if(mymob && mymob.hand) //This being 1 means the left hand is in use
+ using.icon_state = "hand_active"
+ using.screen_loc = ui_lhand
+ using.layer = 19
+ src.l_hand_hud_object = using
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand1"
+ using.screen_loc = ui_swaphand1
+ using.layer = 19
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand2"
+ using.screen_loc = ui_swaphand2
+ using.layer = 19
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "mask"
+ using.dir = NORTH
+ using.icon = ui_style
+ using.icon_state = "equip"
+ using.screen_loc = ui_monkey_mask
+ using.layer = 19
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = "back"
+ using.dir = NORTHEAST
+ using.icon = ui_style
+ using.icon_state = "equip"
+ using.screen_loc = ui_back
+ using.layer = 19
+ src.adding += using
+
+ using = new src.h_type( src )
+ using.name = null
+ using.icon = ui_style
+ using.icon_state = "dither50"
+ using.screen_loc = "1,1 to 5,15"
+ using.layer = 17
+ using.mouse_opacity = 0
+ src.vimpaired += using
+ using = new src.h_type( src )
+ using.name = null
+ using.icon = ui_style
+ using.icon_state = "dither50"
+ using.screen_loc = "5,1 to 10,5"
+ using.layer = 17
+ using.mouse_opacity = 0
+ src.vimpaired += using
+ using = new src.h_type( src )
+ using.name = null
+ using.icon = ui_style
+ using.icon_state = "dither50"
+ using.screen_loc = "6,11 to 10,15"
+ using.layer = 17
+ using.mouse_opacity = 0
+ src.vimpaired += using
+ using = new src.h_type( src )
+ using.name = null
+ using.icon = ui_style
+ using.icon_state = "dither50"
+ using.screen_loc = "11,1 to 15,15"
+ using.layer = 17
+ using.mouse_opacity = 0
+ src.vimpaired += using
+
+ mymob.throw_icon = new /obj/screen(null)
+ mymob.throw_icon.icon = ui_style
+ mymob.throw_icon.icon_state = "act_throw_off"
+ mymob.throw_icon.name = "throw"
+ mymob.throw_icon.screen_loc = ui_throw
+
+ mymob.oxygen = new /obj/screen( null )
+ mymob.oxygen.icon = ui_style
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_oxygen
+
+ mymob.pressure = new /obj/screen( null )
+ mymob.pressure.icon = ui_style
+ mymob.pressure.icon_state = "pressure0"
+ mymob.pressure.name = "pressure"
+ mymob.pressure.screen_loc = ui_pressure
+
+ mymob.toxin = new /obj/screen( null )
+ mymob.toxin.icon = ui_style
+ mymob.toxin.icon_state = "tox0"
+ mymob.toxin.name = "toxin"
+ mymob.toxin.screen_loc = ui_toxin
+
+ mymob.internals = new /obj/screen( null )
+ mymob.internals.icon = ui_style
+ mymob.internals.icon_state = "internal0"
+ mymob.internals.name = "internal"
+ mymob.internals.screen_loc = ui_internal
+
+ mymob.fire = new /obj/screen( null )
+ mymob.fire.icon = ui_style
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_fire
+
+ mymob.bodytemp = new /obj/screen( null )
+ mymob.bodytemp.icon = ui_style
+ mymob.bodytemp.icon_state = "temp1"
+ mymob.bodytemp.name = "body temperature"
+ mymob.bodytemp.screen_loc = ui_temp
+
+ mymob.healths = new /obj/screen( null )
+ mymob.healths.icon = ui_style
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_health
+
+ mymob.pullin = new /obj/screen( null )
+ mymob.pullin.icon = ui_style
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_pull
+
+ mymob.blind = new /obj/screen( null )
+ mymob.blind.icon = ui_style
+ mymob.blind.icon_state = "blackanimate"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1 to 15,15"
+ mymob.blind.layer = 0
+ mymob.blind.mouse_opacity = 0
+
+ mymob.flash = new /obj/screen( null )
+ mymob.flash.icon = ui_style
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.zone_sel = new /obj/screen/zone_sel( null )
+ mymob.zone_sel.overlays = null
+ mymob.zone_sel.overlays += image("icon" = 'zone_sel.dmi', "icon_state" = text("[]", mymob.zone_sel.selecting))
+
+ mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
+
+ mymob.client.screen = null
+
+ //, mymob.i_select, mymob.m_select
+ mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.pressure, mymob.toxin, mymob.bodytemp, mymob.internals, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash, mymob.gun_setting_icon) //, mymob.hands, mymob.rest, mymob.sleep, mymob.mach, mymob.hands, )
+ mymob.client.screen += src.adding + src.other
+
+ //if(istype(mymob,/mob/living/carbon/monkey)) mymob.client.screen += src.mon_blo
+
+ return
diff --git a/code/modules/mob/living/carbon/amorph/life.dm b/code/modules/mob/living/carbon/amorph/life.dm
new file mode 100644
index 0000000000..51bc3d833e
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/life.dm
@@ -0,0 +1,516 @@
+/mob/living/carbon/amorph
+ var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie
+
+ var/oxygen_alert = 0
+ var/toxins_alert = 0
+ var/fire_alert = 0
+
+ var/temperature_alert = 0
+
+
+/mob/living/carbon/amorph/Life()
+ set invisibility = 0
+ set background = 1
+
+ if (src.monkeyizing)
+ return
+
+ ..()
+
+ var/datum/gas_mixture/environment // Added to prevent null location errors-- TLE
+ if(src.loc)
+ environment = loc.return_air()
+
+ if (src.stat != 2) //still breathing
+
+ //First, resolve location and get a breath
+
+ if(air_master.current_cycle%4==2)
+ //Only try to take a breath every 4 seconds, unless suffocating
+ breathe()
+
+ else //Still give containing object the chance to interact
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ location_as_object.handle_internal_lifeform(src, 0)
+
+ //Apparently, the person who wrote this code designed it so that
+ //blinded get reset each cycle and then get activated later in the
+ //code. Very ugly. I dont care. Moving this stuff here so its easy
+ //to find it.
+ src.blinded = null
+
+ //Disease Check
+ handle_virus_updates()
+
+ //Handle temperature/pressure differences between body and environment
+ if(environment) // More error checking -- TLE
+ handle_environment(environment)
+
+ //Mutations and radiation
+ handle_mutations_and_radiation()
+
+ //Chemicals in the body
+ handle_chemicals_in_body()
+
+ //Disabilities
+ handle_disabilities()
+
+ //Status updates, death etc.
+ UpdateLuminosity()
+ handle_regular_status_updates()
+
+ if(client)
+ handle_regular_hud_updates()
+
+ //Being buckled to a chair or bed
+ check_if_buckled()
+
+ // Yup.
+ update_canmove()
+
+ clamp_values()
+
+ // Grabbing
+ for(var/obj/item/weapon/grab/G in src)
+ G.process()
+
+/mob/living/carbon/amorph
+ proc
+
+ clamp_values()
+
+ AdjustStunned(0)
+ AdjustParalysis(0)
+ AdjustWeakened(0)
+
+ handle_disabilities()
+ if (src.disabilities & 4)
+ if ((prob(5) && src.paralysis <= 1 && src.r_ch_cou < 1))
+ src.drop_item()
+ spawn( 0 )
+ emote("cough")
+ return
+ if (src.disabilities & 8)
+ if ((prob(10) && src.paralysis <= 1 && src.r_Tourette < 1))
+ Stun(10)
+ spawn( 0 )
+ emote("twitch")
+ return
+ if (src.disabilities & 16)
+ if (prob(10))
+ src.stuttering = max(10, src.stuttering)
+
+ update_mind()
+ if(!mind && client)
+ mind = new
+ mind.current = src
+ mind.key = key
+
+ handle_mutations_and_radiation()
+ // amorphs are immune to this stuff
+
+ breathe()
+ if(src.reagents)
+
+ if(src.reagents.has_reagent("lexorin")) return
+
+ if(!loc) return //probably ought to make a proper fix for this, but :effort: --NeoFite
+
+ var/datum/gas_mixture/environment = loc.return_air()
+ var/datum/gas_mixture/breath
+
+ if(losebreath>0) //Suffocating so do not take a breath
+ src.losebreath--
+ if (prob(75)) //High chance of gasping for air
+ spawn emote("gasp")
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ location_as_object.handle_internal_lifeform(src, 0)
+ else
+ //First, check for air from internal atmosphere (using an air tank and mask generally)
+ breath = get_breath_from_internal(BREATH_VOLUME)
+
+ //No breath from internal atmosphere so get breath from location
+ if(!breath)
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ breath = location_as_object.handle_internal_lifeform(src, BREATH_VOLUME)
+ else if(istype(loc, /turf/))
+ var/breath_moles = environment.total_moles*BREATH_PERCENTAGE
+ breath = loc.remove_air(breath_moles)
+
+ // Handle chem smoke effect -- Doohl
+ var/block = 0
+ if(wear_mask)
+ if(istype(wear_mask, /obj/item/clothing/mask/gas))
+ block = 1
+
+ if(!block)
+
+ for(var/obj/effect/effect/chem_smoke/smoke in view(1, src))
+ if(smoke.reagents.total_volume)
+ smoke.reagents.reaction(src, INGEST)
+ spawn(5)
+ if(smoke)
+ smoke.reagents.copy_to(src, 10) // I dunno, maybe the reagents enter the blood stream through the lungs?
+ break // If they breathe in the nasty stuff once, no need to continue checking
+
+
+ else //Still give containing object the chance to interact
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ location_as_object.handle_internal_lifeform(src, 0)
+
+ handle_breath(breath)
+
+ if(breath)
+ loc.assume_air(breath)
+
+
+ get_breath_from_internal(volume_needed)
+ if(internal)
+ if (!contents.Find(src.internal))
+ internal = null
+ if (!wear_mask || !(wear_mask.flags|MASKINTERNALS) )
+ internal = null
+ if(internal)
+ if (src.internals)
+ src.internals.icon_state = "internal1"
+ return internal.remove_air_volume(volume_needed)
+ else
+ if (src.internals)
+ src.internals.icon_state = "internal0"
+ return null
+
+ update_canmove()
+ if(paralysis || stunned || weakened || buckled || (changeling && changeling.changeling_fakedeath)) canmove = 0
+ else canmove = 1
+
+ handle_breath(datum/gas_mixture/breath)
+ if(src.nodamage)
+ return
+
+ if(!breath || (breath.total_moles == 0))
+ adjustOxyLoss(7)
+
+ oxygen_alert = max(oxygen_alert, 1)
+
+ return 0
+
+ var/safe_oxygen_min = 8 // Minimum safe partial pressure of O2, in kPa
+ //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now)
+ var/SA_para_min = 0.5
+ var/SA_sleep_min = 5
+ var/oxygen_used = 0
+ var/breath_pressure = (breath.total_moles*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
+
+ //Partial pressure of the O2 in our breath
+ var/O2_pp = (breath.oxygen/breath.total_moles)*breath_pressure
+
+ if(O2_pp < safe_oxygen_min) // Too little oxygen
+ if(prob(20))
+ spawn(0) emote("gasp")
+ if (O2_pp == 0)
+ O2_pp = 0.01
+ var/ratio = safe_oxygen_min/O2_pp
+ adjustOxyLoss(min(5*ratio, 7)) // Don't fuck them up too fast (space only does 7 after all!)
+ oxygen_used = breath.oxygen*ratio/6
+ oxygen_alert = max(oxygen_alert, 1)
+ else // We're in safe limits
+ adjustOxyLoss(-5)
+ oxygen_used = breath.oxygen/6
+ oxygen_alert = 0
+
+ breath.oxygen -= oxygen_used
+ breath.carbon_dioxide += oxygen_used
+
+ if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here.
+ for(var/datum/gas/sleeping_agent/SA in breath.trace_gases)
+ var/SA_pp = (SA.moles/breath.total_moles)*breath_pressure
+ if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit
+ Paralyse(3) // 3 gives them one second to wake up and run away a bit!
+ if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
+ src.sleeping = max(src.sleeping+2, 10)
+ else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
+ if(prob(20))
+ spawn(0) emote(pick("giggle", "laugh"))
+
+ return 1
+
+ handle_environment(datum/gas_mixture/environment)
+ if(!environment)
+ return
+ var/environment_heat_capacity = environment.heat_capacity()
+ if(istype(loc, /turf/space))
+ environment_heat_capacity = loc:heat_capacity
+
+ if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10)))
+ var/transfer_coefficient
+
+ transfer_coefficient = 1
+ if(wear_mask && (wear_mask.body_parts_covered & HEAD) && (environment.temperature < wear_mask.protective_temperature))
+ transfer_coefficient *= wear_mask.heat_transfer_coefficient
+
+ handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient)
+
+ if(stat==2)
+ bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000)
+
+ //Account for massive pressure differences
+
+
+ var/pressure = environment.return_pressure()
+
+ // if(!wear_suit) Monkies cannot into space.
+ // if(!istype(wear_suit, /obj/item/clothing/suit/space))
+
+ /*if(pressure < 20)
+ if(prob(25))
+ src << "You feel the splittle on your lips and the fluid on your eyes boiling away, the capillteries in your skin breaking."
+ adjustBruteLoss(5)
+ */
+
+ if(pressure > HAZARD_HIGH_PRESSURE)
+
+ adjustBruteLoss(min((10+(round(pressure/(HIGH_STEP_PRESSURE)-2)*5)),MAX_PRESSURE_DAMAGE))
+
+
+
+ return //TODO: DEFERRED
+
+ handle_temperature_damage(body_part, exposed_temperature, exposed_intensity)
+ if(src.nodamage) return
+ var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
+ if(exposed_temperature > bodytemperature)
+ adjustFireLoss(20.0*discomfort)
+
+ else
+ adjustFireLoss(5.0*discomfort)
+
+ handle_chemicals_in_body()
+ // most chemicals will have no effect on amorphs
+ //if(reagents) reagents.metabolize(src)
+
+ if (src.drowsyness)
+ src.drowsyness--
+ src.eye_blurry = max(2, src.eye_blurry)
+ if (prob(5))
+ src.sleeping += 1
+ Paralyse(5)
+
+ confused = max(0, confused - 1)
+ // decrement dizziness counter, clamped to 0
+ if(resting)
+ dizziness = max(0, dizziness - 5)
+ else
+ dizziness = max(0, dizziness - 1)
+
+ src.updatehealth()
+
+ return //TODO: DEFERRED
+
+ handle_regular_status_updates()
+
+ health = 100 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
+
+ if(getOxyLoss() > 25) Paralyse(3)
+
+ if(src.sleeping)
+ Paralyse(5)
+ if (prob(1) && health) spawn(0) emote("snore")
+
+ if(src.resting)
+ Weaken(5)
+
+ if(health < config.health_threshold_dead && stat != 2)
+ death()
+ else if(src.health < config.health_threshold_crit)
+ if(src.health <= 20 && prob(1)) spawn(0) emote("gasp")
+
+ // shuffle around the chemical effects for amorphs a little ;)
+ if(!src.reagents.has_reagent("antitoxin") && src.stat != 2) src.adjustOxyLoss(2)
+
+ if(src.stat != 2) src.stat = 1
+ Paralyse(5)
+
+ if (src.stat != 2) //Alive.
+
+ if (src.paralysis || src.stunned || src.weakened) //Stunned etc.
+ if (src.stunned > 0)
+ AdjustStunned(-1)
+ src.stat = 0
+ if (src.weakened > 0)
+ AdjustWeakened(-1)
+ src.lying = 1
+ src.stat = 0
+ if (src.paralysis > 0)
+ AdjustParalysis(-1)
+ src.blinded = 1
+ src.lying = 1
+ src.stat = 1
+ var/h = src.hand
+ src.hand = 0
+ drop_item()
+ src.hand = 1
+ drop_item()
+ src.hand = h
+
+ else //Not stunned.
+ src.lying = 0
+ src.stat = 0
+
+ else //Dead.
+ src.lying = 1
+ src.blinded = 1
+ src.stat = 2
+
+ if (src.stuttering) src.stuttering--
+ if (src.slurring) src.slurring--
+
+ if (src.eye_blind)
+ src.eye_blind--
+ src.blinded = 1
+
+ if (src.ear_deaf > 0) src.ear_deaf--
+ if (src.ear_damage < 25)
+ src.ear_damage -= 0.05
+ src.ear_damage = max(src.ear_damage, 0)
+
+ src.density = !( src.lying )
+
+ if (src.disabilities & 128)
+ src.blinded = 1
+ if (src.disabilities & 32)
+ src.ear_deaf = 1
+
+ if (src.eye_blurry > 0)
+ src.eye_blurry--
+ src.eye_blurry = max(0, src.eye_blurry)
+
+ if (src.druggy > 0)
+ src.druggy--
+ src.druggy = max(0, src.druggy)
+
+ return 1
+
+ handle_regular_hud_updates()
+
+ if (src.stat == 2 || (XRAY in mutations))
+ src.sight |= SEE_TURFS
+ src.sight |= SEE_MOBS
+ src.sight |= SEE_OBJS
+ src.see_in_dark = 8
+ src.see_invisible = 2
+ else if (src.stat != 2)
+ src.sight &= ~SEE_TURFS
+ src.sight &= ~SEE_MOBS
+ src.sight &= ~SEE_OBJS
+ src.see_in_dark = 2
+ src.see_invisible = 0
+
+ if (src.sleep)
+ src.sleep.icon_state = text("sleep[]", src.sleeping > 0 ? 1 : 0)
+ src.sleep.overlays = null
+ if(src.sleeping_willingly)
+ src.sleep.overlays += icon(src.sleep.icon, "sleep_willing")
+ if (src.rest) src.rest.icon_state = text("rest[]", src.resting)
+
+ if (src.healths)
+ if (src.stat != 2)
+ switch(health)
+ if(100 to INFINITY)
+ src.healths.icon_state = "health0"
+ if(80 to 100)
+ src.healths.icon_state = "health1"
+ if(60 to 80)
+ src.healths.icon_state = "health2"
+ if(40 to 60)
+ src.healths.icon_state = "health3"
+ if(20 to 40)
+ src.healths.icon_state = "health4"
+ if(0 to 20)
+ src.healths.icon_state = "health5"
+ else
+ src.healths.icon_state = "health6"
+ else
+ src.healths.icon_state = "health7"
+
+ if (pressure)
+ var/datum/gas_mixture/environment = loc.return_air()
+ if(environment)
+ switch(environment.return_pressure())
+
+ if(HAZARD_HIGH_PRESSURE to INFINITY)
+ pressure.icon_state = "pressure2"
+ if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE)
+ pressure.icon_state = "pressure1"
+ if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE)
+ pressure.icon_state = "pressure0"
+ if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE)
+ pressure.icon_state = "pressure-1"
+ else
+ pressure.icon_state = "pressure-2"
+
+ if(src.pullin) src.pullin.icon_state = "pull[src.pulling ? 1 : 0]"
+
+
+ if (src.toxin) src.toxin.icon_state = "tox[src.toxins_alert ? 1 : 0]"
+ if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]"
+ if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]"
+ //NOTE: the alerts dont reset when youre out of danger. dont blame me,
+ //blame the person who coded them. Temporary fix added.
+
+ if(bodytemp)
+ switch(src.bodytemperature) //310.055 optimal body temp
+ if(345 to INFINITY)
+ src.bodytemp.icon_state = "temp4"
+ if(335 to 345)
+ src.bodytemp.icon_state = "temp3"
+ if(327 to 335)
+ src.bodytemp.icon_state = "temp2"
+ if(316 to 327)
+ src.bodytemp.icon_state = "temp1"
+ if(300 to 316)
+ src.bodytemp.icon_state = "temp0"
+ if(295 to 300)
+ src.bodytemp.icon_state = "temp-1"
+ if(280 to 295)
+ src.bodytemp.icon_state = "temp-2"
+ if(260 to 280)
+ src.bodytemp.icon_state = "temp-3"
+ else
+ src.bodytemp.icon_state = "temp-4"
+
+ src.client.screen -= src.hud_used.blurry
+ src.client.screen -= src.hud_used.druggy
+ src.client.screen -= src.hud_used.vimpaired
+
+ if ((src.blind && src.stat != 2))
+ if ((src.blinded))
+ src.blind.layer = 18
+ else
+ src.blind.layer = 0
+
+ if (src.disabilities & 1)
+ src.client.screen += src.hud_used.vimpaired
+
+ if (src.eye_blurry)
+ src.client.screen += src.hud_used.blurry
+
+ if (src.druggy)
+ src.client.screen += src.hud_used.druggy
+
+ if (src.stat != 2)
+ if (src.machine)
+ if (!( src.machine.check_eye(src) ))
+ src.reset_view(null)
+ else
+ if(!client.adminobs)
+ reset_view(null)
+
+ return 1
+
+ handle_virus_updates()
+ // amorphs can't come down with human diseases
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/amorph/say.dm b/code/modules/mob/living/carbon/amorph/say.dm
new file mode 100644
index 0000000000..4663a847a1
--- /dev/null
+++ b/code/modules/mob/living/carbon/amorph/say.dm
@@ -0,0 +1,6 @@
+/mob/living/carbon/amorph/emote(var/act,var/m_type=1,var/message = null)
+ if(act == "me")
+ return custom_emote(m_type, message)
+
+/mob/living/carbon/amorph/say_quote(var/text)
+ return "[src.say_message], \"[text]\"";
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index c01be193cc..a844f2cc78 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -5,6 +5,9 @@
return 1
return 0
+/proc/isamorph(A)
+ return istype(A, /mob/living/carbon/amorph)
+
/proc/ismonkey(A)
if(A && istype(A, /mob/living/carbon/monkey))
return 1