Merge remote-tracking branch 'upstream/master' into tgui4.0-and-camera-console

This commit is contained in:
ShadowLarkens
2020-08-06 21:29:47 -07:00
247 changed files with 5334 additions and 1793 deletions
+14 -2
View File
@@ -54,6 +54,14 @@
var/emp_modifier // Added to the EMP strength, which is an inverse scale from 1 to 4, with 1 being the strongest EMP. 5 is a nullification.
var/explosion_modifier // Added to the bomb strength, which is an inverse scale from 1 to 3, with 1 being gibstrength. 4 is a nullification.
// Note that these are combined with the mob's real armor values additatively. You can also omit specific armor types.
var/list/armor_percent = null // List of armor values to add to the holder when doing armor calculations. This is for percentage based armor. E.g. 50 = half damage.
var/list/armor_flat = null // Same as above but only for flat armor calculations. E.g. 5 = 5 less damage (this comes after percentage).
// Unlike armor, this is multiplicative. Two 50% protection modifiers will be combined into 75% protection (assuming no base protection on the mob).
var/heat_protection = null // Modifies how 'heat' protection is calculated, like wearing a firesuit. 1 = full protection.
var/cold_protection = null // Ditto, but for cold, like wearing a winter coat.
var/siemens_coefficient = null // Similar to above two vars but 0 = full protection, to be consistant with siemens numbers everywhere else.
var/vision_flags // Vision flags to add to the mob. SEE_MOB, SEE_OBJ, etc.
/datum/modifier/New(var/new_holder, var/new_origin)
@@ -185,10 +193,14 @@
// Checks if the mob has a modifier type.
/mob/living/proc/has_modifier_of_type(var/modifier_type)
return get_modifier_of_type(modifier_type) ? TRUE : FALSE
// Gets the first instance of a specific modifier type or subtype.
/mob/living/proc/get_modifier_of_type(var/modifier_type)
for(var/datum/modifier/M in modifiers)
if(istype(M, modifier_type))
return TRUE
return FALSE
return M
return null
// This displays the actual 'numbers' that a modifier is doing. Should only be shown in OOC contexts.
// When adding new effects, be sure to update this as well.
+30 -1
View File
@@ -397,4 +397,33 @@ the artifact triggers the rage.
/datum/modifier/outline_test/tick()
animate(filter_instance, size = 3, time = 0.25 SECONDS)
animate(size = 1, 0.25 SECONDS)
animate(size = 1, 0.25 SECONDS)
// Acts as a psuedo-godmode, yet probably is more reliable than the actual var for it nowdays.
// Can't protect from instantly killing things like singulos.
/datum/modifier/invulnerable
name = "invulnerable"
desc = "You are almost immune to harm, for a little while at least."
stacks = MODIFIER_STACK_EXTEND
disable_duration_percent = 0
incoming_damage_percent = 0
// bleeding_rate_percent = 0
pain_immunity = TRUE
armor_percent = list("melee" = 2000, "bullet" = 2000, "laser" = 2000, "bomb" = 2000, "energy" = 2000, "bio" = 2000, "rad" = 2000)
heat_protection = 1.0
cold_protection = 1.0
siemens_coefficient = 0.0
// Reduces resistance to "elements".
// Note that most things that do give resistance gives 100% protection,
// and due to multiplicitive stacking, this modifier won't do anything to change that.
/datum/modifier/elemental_vulnerability
name = "elemental vulnerability"
desc = "You're more vulnerable to extreme temperatures and electricity."
stacks = MODIFIER_STACK_EXTEND
heat_protection = -0.5
cold_protection = -0.5
siemens_coefficient = 1.5
+66 -47
View File
@@ -120,27 +120,32 @@
// People covered in blood is also bad.
// Feel free to trim down if its too expensive CPU wise.
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/H = thing
var/self_multiplier = H == holder ? 2 : 1
var/human_blood_fear_amount = 0
if(!H.gloves && H.bloody_hands && H.hand_blood_color != SYNTH_BLOOD_COLOUR)
human_blood_fear_amount += 1
if(!H.shoes && H.feet_blood_color && H.feet_blood_color != SYNTH_BLOOD_COLOUR)
human_blood_fear_amount += 1
if(isliving(thing))
var/mob/living/L = thing
if(L.alpha <= FAKE_INVIS_ALPHA_THRESHOLD) // Can't fear something you can't (easily) see.
continue
// List of slots. Some slots like pockets are omitted due to not being visible, if H isn't the holder.
var/list/clothing_slots = list(H.back, H.wear_mask, H.l_hand, H.r_hand, H.wear_id, H.glasses, H.gloves, H.head, H.shoes, H.belt, H.wear_suit, H.w_uniform, H.s_store, H.l_ear, H.r_ear)
if(H == holder)
clothing_slots += list(H.l_store, H.r_store)
for(var/obj/item/clothing/C in clothing_slots)
if(C.blood_DNA && C.blood_color && C.blood_color != SYNTH_BLOOD_COLOUR)
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/H = thing
var/self_multiplier = H == holder ? 2 : 1
var/human_blood_fear_amount = 0
if(!H.gloves && H.bloody_hands && H.hand_blood_color != SYNTH_BLOOD_COLOUR)
human_blood_fear_amount += 1
if(!H.shoes && H.feet_blood_color && H.feet_blood_color != SYNTH_BLOOD_COLOUR)
human_blood_fear_amount += 1
// This is divided, since humans can wear so many items at once.
human_blood_fear_amount = round( (human_blood_fear_amount * self_multiplier) / 3, 1)
fear_amount += human_blood_fear_amount
// List of slots. Some slots like pockets are omitted due to not being visible, if H isn't the holder.
var/list/clothing_slots = list(H.back, H.wear_mask, H.l_hand, H.r_hand, H.wear_id, H.glasses, H.gloves, H.head, H.shoes, H.belt, H.wear_suit, H.w_uniform, H.s_store, H.l_ear, H.r_ear)
if(H == holder)
clothing_slots += list(H.l_store, H.r_store)
for(var/obj/item/clothing/C in clothing_slots)
if(C.blood_DNA && C.blood_color && C.blood_color != SYNTH_BLOOD_COLOUR)
human_blood_fear_amount += 1
// This is divided, since humans can wear so many items at once.
human_blood_fear_amount = round( (human_blood_fear_amount * self_multiplier) / 3, 1)
fear_amount += human_blood_fear_amount
// Bloody objects are also bad.
if(istype(thing, /obj))
@@ -207,12 +212,18 @@
if(istype(thing, /obj/structure/snowman/spider)) //Snow spiders are also spooky so people can be assholes with those too.
fear_amount += 1
if(istype(thing, /mob/living/simple_mob/animal/giant_spider)) // Actual giant spiders are the scariest of them all.
var/mob/living/simple_mob/animal/giant_spider/S = thing
if(S.stat == DEAD) // Dead giant spiders are less scary than alive ones.
fear_amount += 4
else
fear_amount += 8
if(isliving(thing))
var/mob/living/L = thing
if(L.alpha <= FAKE_INVIS_ALPHA_THRESHOLD) // Can't fear something you can't (easily) see.
continue
if(istype(L, /mob/living/simple_mob/animal/giant_spider)) // Actual giant spiders are the scariest of them all.
var/mob/living/simple_mob/animal/giant_spider/S = L
if(S.stat == DEAD) // Dead giant spiders are less scary than alive ones.
fear_amount += 4
else
fear_amount += 8
return fear_amount
@@ -425,25 +436,29 @@
if(istype(thing, /obj/item/clothing/head/collectable/slime)) // Some hats are spooky so people can be assholes with them.
fear_amount += 1
if(istype(thing, /mob/living/simple_mob/slime)) // An actual predatory specimen!
var/mob/living/simple_mob/slime/S = thing
if(S.stat == DEAD) // Dead slimes are somewhat less spook.
fear_amount += 4
if(istype(S, /mob/living/simple_mob/slime/xenobio))
var/mob/living/simple_mob/slime/xenobio/X = S
if(X.is_adult == TRUE) //big boy
fear_amount += 8
if(isliving(thing))
var/mob/living/L = thing
if(L.alpha <= FAKE_INVIS_ALPHA_THRESHOLD) // Can't fear something you can't (easily) see.
continue
if(istype(L, /mob/living/simple_mob/slime)) // An actual predatory specimen!
var/mob/living/simple_mob/slime/S = L
if(S.stat == DEAD) // Dead slimes are somewhat less spook.
fear_amount += 4
if(istype(S, /mob/living/simple_mob/slime/xenobio))
var/mob/living/simple_mob/slime/xenobio/X = S
if(X.is_adult == TRUE) //big boy
fear_amount += 8
else
fear_amount += 6
else
fear_amount += 6
else
fear_amount += 10 // It's huge and feral.
fear_amount += 10 // It's huge and feral.
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/S = thing
if(istype(S.species, /datum/species/skrell)) //Skrell ARE slimey.
fear_amount += 1
if(istype(S.species, /datum/species/shapeshifter/promethean))
fear_amount += 4
if(istype(L, /mob/living/carbon/human))
var/mob/living/carbon/human/S = L
if(istype(S.species, /datum/species/skrell)) //Skrell ARE slimey.
fear_amount += 1
if(istype(S.species, /datum/species/shapeshifter/promethean))
fear_amount += 4
return fear_amount
@@ -525,13 +540,17 @@
if(istype(thing, /obj/item/weapon/gun/launcher/syringe))
fear_amount += 6
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/H = thing
if(H.l_hand && istype(H.l_hand, /obj/item/weapon/reagent_containers/syringe) || H.r_hand && istype(H.r_hand, /obj/item/weapon/reagent_containers/syringe))
fear_amount += 10
if(isliving(thing))
var/mob/living/L = thing
if(L.alpha <= FAKE_INVIS_ALPHA_THRESHOLD) // Can't fear something you can't (easily) see.
continue
if(istype(L, /mob/living/carbon/human))
var/mob/living/carbon/human/H = L
if(H.l_hand && istype(H.l_hand, /obj/item/weapon/reagent_containers/syringe) || H.r_hand && istype(H.r_hand, /obj/item/weapon/reagent_containers/syringe))
fear_amount += 10
if(H.l_ear && istype(H.l_ear, /obj/item/weapon/reagent_containers/syringe) || H.r_ear && istype(H.r_ear, /obj/item/weapon/reagent_containers/syringe))
fear_amount +=10
if(H.l_ear && istype(H.l_ear, /obj/item/weapon/reagent_containers/syringe) || H.r_ear && istype(H.r_ear, /obj/item/weapon/reagent_containers/syringe))
fear_amount +=10
return fear_amount
+3
View File
@@ -6,3 +6,6 @@
plane_holder.set_vis(VIS_CLOAKED, TRUE)
plane_holder.set_vis(VIS_AI_EYE, TRUE)
plane = PLANE_GHOSTS
if(cleanup_timer)
deltimer(cleanup_timer)
cleanup_timer = null
+2
View File
@@ -3,3 +3,5 @@
spawn(0)
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
qdel(src)
else
cleanup_timer = QDEL_IN(src, 10 MINUTES)
+91 -40
View File
@@ -86,6 +86,7 @@
"Beepsky" = "secbot"
)
var/last_revive_notification = null // world.time of last notification, used to avoid spamming players from defibs or cloners.
var/cleanup_timer // Refernece to a timer that will delete this mob if no client returns
/mob/observer/dead/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
@@ -129,6 +130,7 @@
if(!name) //To prevent nameless ghosts
name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
real_name = name
animate(src, pixel_y = 2, time = 10, loop = -1)
..()
/mob/observer/dead/Topic(href, href_list)
@@ -152,6 +154,13 @@
if(new_stat != DEAD)
CRASH("It is best if observers stay dead, thank you.")
/mob/observer/dead/examine_icon()
var/icon/I = get_cached_examine_icon(src)
if(!I)
I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE)
set_cached_examine_icon(src, I, 200 SECONDS)
return I
/*
Transfer_mind is there to check if mob is being deleted/not going to have a body.
Works together with spawning an observer, noted above.
@@ -220,6 +229,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/mob/observer/dead/ghost = ghostize(0) // 0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
if(ghost)
ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly.
ghost.set_respawn_timer()
announce_ghost_joinleave(ghost)
/mob/observer/dead/can_use_hands() return 0
@@ -290,6 +300,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No")
if(response == "No") return
can_reenter_corpse = FALSE
set_respawn_timer(-1) // Foreeeever
if(!has_enabled_antagHUD && !client.holder)
has_enabled_antagHUD = TRUE
@@ -306,6 +317,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(usr, "Not when you're not dead!")
return
if(!A)
A = input(usr, "Select an area:", "Ghost Teleport") as null|anything in return_sorted_areas()
if(!A)
return
usr.forceMove(pick(get_area_turfs(A)))
usr.on_mob_jump()
@@ -314,6 +330,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Follow" // "Haunt"
set desc = "Follow and haunt a mob."
if(!input)
input = input(usr, "Select a mob:", "Ghost Follow") as null|anything in getmobs()
if(!input)
return
var/target = getmobs()[input]
if(!target) return
ManualFollow(target)
@@ -347,6 +368,45 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
forceMove(T)
sleep(15)
var/icon/I = icon(target.icon,target.icon_state,target.dir)
var/orbitsize = (I.Width()+I.Height())*0.5
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
var/rot_seg
/* We don't have this pref yet
switch(ghost_orbit)
if(GHOST_ORBIT_TRIANGLE)
rot_seg = 3
if(GHOST_ORBIT_SQUARE)
rot_seg = 4
if(GHOST_ORBIT_PENTAGON)
rot_seg = 5
if(GHOST_ORBIT_HEXAGON)
rot_seg = 6
else //Circular
rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle
*/
orbit(target, orbitsize, FALSE, 20, rot_seg)
/mob/observer/dead/orbit()
set_dir(2) //reset dir so the right directional sprites show up
return ..()
/mob/observer/dead/stop_orbit(datum/component/orbiter/orbits)
. = ..()
//restart our floating animation after orbit is done.
pixel_y = 0
pixel_x = 0
transform = null
animate(src, pixel_y = 2, time = 10, loop = -1)
/mob/observer/dead/proc/stop_following()
following = null
stop_orbit()
/mob/proc/update_following()
. = get_turf(src)
for(var/mob/observer/dead/M in following_mobs)
@@ -361,7 +421,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/Destroy()
for(var/mob/observer/dead/M in following_mobs)
M.following = null
M.stop_following()
following_mobs = null
return ..()
@@ -369,7 +429,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(ismob(following))
var/mob/M = following
M.following_mobs -= src
following = null
stop_following()
return ..()
/mob/Moved(atom/old_loc, direction, forced = FALSE)
@@ -394,35 +454,28 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set category = "Ghost"
set name = "Jump to Mob"
set desc = "Teleport to a mob"
set popup_menu = FALSE
if(istype(usr, /mob/observer/dead)) //Make sure they're an observer!
var/target = getmobs()[input]
if (!target)//Make sure we actually have a target
return
else
var/mob/M = target //Destination mob
var/turf/T = get_turf(M) //Turf of the destination mob
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
forceMove(T)
following = null
else
to_chat(src, "This mob is not located in the game world.")
/*
/mob/observer/dead/verb/boo()
set category = "Ghost"
set name = "Boo!"
set desc= "Scare your crew members because of boredom!"
if(bootime > world.time) return
var/obj/machinery/light/L = locate(/obj/machinery/light) in view(1, src)
if(L)
L.flicker()
bootime = world.time + 600
if(!istype(usr, /mob/observer/dead)) //Make sure they're an observer!
return
//Maybe in the future we can add more <i>spooky</i> code here!
return
*/
if(!input)
input = input(usr, "Select a mob:", "Ghost Jump") as null|anything in getmobs()
if(!input)
return
var/target = getmobs()[input]
if (!target)//Make sure we actually have a target
return
else
var/mob/M = target //Destination mob
var/turf/T = get_turf(M) //Turf of the destination mob
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
forceMove(T)
stop_following()
else
to_chat(src, "This mob is not located in the game world.")
/mob/observer/dead/memory()
set hidden = 1
@@ -433,7 +486,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "<font color='red'>You are dead! You have no mind to store memory!</font>")
/mob/observer/dead/Post_Incorpmove()
following = null
stop_following()
/mob/observer/dead/verb/analyze_air()
set name = "Analyze Air"
@@ -801,13 +854,19 @@ mob/observer/dead/MayRespawn(var/feedback = 0)
set category = "Ghost"
set name = "Blank pAI alert"
set desc = "Flash an indicator light on available blank pAI devices for a smidgen of hope."
if(usr.client.prefs.be_special & BE_PAI)
if(usr.client.prefs?.be_special & BE_PAI)
var/count = 0
for(var/obj/item/device/paicard/p in all_pai_cards)
var/obj/item/device/paicard/PP = p
if(PP.pai == null)
count++
PP.overlays += "pai-ghostalert"
spawn(54)
PP.overlays.Cut()
to_chat(usr,"<span class='notice'>Flashing the displays of [count] unoccupied PAIs.</span>")
else
to_chat(usr,"<span class='warning'>You have 'Be pAI' disabled in your character prefs, so we can't help you.</span>")
/mob/observer/dead/speech_bubble_appearance()
return "ghost"
@@ -824,15 +883,7 @@ mob/observer/dead/MayRespawn(var/feedback = 0)
if(message)
to_chat(src, "<span class='ghostalert'><font size=4>[message]</font></span>")
if(source)
var/obj/screen/alert/A = throw_alert("\ref[source]_notify_revive", /obj/screen/alert/notify_cloning)
if(A)
if(client && client.prefs && client.prefs.UI_style)
A.icon = ui_style2icon(client.prefs.UI_style)
A.desc = message
var/old_layer = source.layer
source.layer = FLOAT_LAYER
A.overlays += source
source.layer = old_layer
throw_alert("\ref[source]_notify_revive", /obj/screen/alert/notify_cloning, new_master = source)
to_chat(src, "<span class='ghostalert'><a href=?src=[REF(src)];reenter=1>(Click to re-enter)</a></span>")
if(sound)
SEND_SOUND(src, sound(sound))
+2 -1
View File
@@ -100,7 +100,8 @@
if(mind) mind.store_memory("Time of death: [stationtime2text()]", 0)
living_mob_list -= src
dead_mob_list |= src
set_respawn_timer()
updateicon()
handle_regular_hud_updates()
handle_vision()
+10 -10
View File
@@ -241,20 +241,20 @@
M.Weaken(5)
..()
/mob/living/bot/mulebot/proc/runOver(var/mob/living/carbon/human/H)
if(istype(H)) // No safety checks - WILL run over lying humans. Stop ERPing in the maint!
visible_message("<span class='warning'>[src] drives over [H]!</span>")
/mob/living/bot/mulebot/proc/runOver(var/mob/living/M)
if(istype(M)) // At this point, MULEBot has somehow crossed over onto your tile with you still on it. CRRRNCH.
visible_message("<span class='warning'>[src] drives over [M]!</span>")
playsound(src, 'sound/effects/splat.ogg', 50, 1)
var/damage = rand(5, 7)
H.apply_damage(2 * damage, BRUTE, BP_HEAD)
H.apply_damage(2 * damage, BRUTE, BP_TORSO)
H.apply_damage(0.5 * damage, BRUTE, BP_L_LEG)
H.apply_damage(0.5 * damage, BRUTE, BP_R_LEG)
H.apply_damage(0.5 * damage, BRUTE, BP_L_ARM)
H.apply_damage(0.5 * damage, BRUTE, BP_R_ARM)
M.apply_damage(2 * damage, BRUTE, BP_HEAD)
M.apply_damage(2 * damage, BRUTE, BP_TORSO)
M.apply_damage(0.5 * damage, BRUTE, BP_L_LEG)
M.apply_damage(0.5 * damage, BRUTE, BP_R_LEG)
M.apply_damage(0.5 * damage, BRUTE, BP_L_ARM)
M.apply_damage(0.5 * damage, BRUTE, BP_R_ARM)
blood_splatter(src, H, 1)
blood_splatter(src, M, 1)
..()
/mob/living/bot/mulebot/relaymove(var/mob/user, var/direction)
+33 -12
View File
@@ -253,20 +253,14 @@
return
// called when something steps onto a human
// this handles mulebots and vehicles
// and now mobs on fire
// this handles mobs on fire - mulebot and vehicle code has been relocated to /mob/living/Crossed()
/mob/living/carbon/human/Crossed(var/atom/movable/AM)
if(AM.is_incorporeal())
return
if(istype(AM, /mob/living/bot/mulebot))
var/mob/living/bot/mulebot/MB = AM
MB.runOver(src)
if(istype(AM, /obj/vehicle))
var/obj/vehicle/V = AM
V.RunOver(src)
spread_fire(AM)
..() // call parent because we moved behavior to parent
// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc.
/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job")
@@ -1566,6 +1560,13 @@
else
layer = HIDING_LAYER
/mob/living/carbon/human/examine_icon()
var/icon/I = get_cached_examine_icon(src)
if(!I)
I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE)
set_cached_examine_icon(src, I, 50 SECONDS)
return I
/mob/living/carbon/human/proc/get_display_species()
//Shows species in tooltip
//Beepboops get special text if obviously beepboop
@@ -1637,8 +1638,8 @@
if(species?.flags & NO_BLOOD)
bloodtrail = 0
else
var/blood_volume = round((vessel.get_reagent_amount("blood")/species.blood_volume)*100)
if(blood_volume < BLOOD_VOLUME_SURVIVE)
var/blood_volume = vessel.get_reagent_amount("blood")
if(blood_volume < species?.blood_volume*species?.blood_level_fatal)
bloodtrail = 0 //Most of it's gone already, just leave it be
else
vessel.remove_reagent("blood", 1)
@@ -1646,4 +1647,24 @@
if(istype(loc, /turf/simulated))
var/turf/T = loc
T.add_blood(src)
. = ..()
. = ..()
// Tries to turn off item-based things that let you see through walls, like mesons.
// Certain stuff like genetic xray vision is allowed to be kept on.
/mob/living/carbon/human/disable_spoiler_vision()
// Glasses.
if(istype(glasses, /obj/item/clothing/glasses))
var/obj/item/clothing/glasses/goggles = glasses
if(goggles.active && (goggles.vision_flags & (SEE_TURFS|SEE_OBJS)))
goggles.toggle_active(src)
to_chat(src, span("warning", "Your [goggles.name] have suddenly turned off!"))
// RIGs.
var/obj/item/weapon/rig/rig = get_rig()
if(istype(rig) && rig.visor?.active && rig.visor.vision?.glasses)
var/obj/item/clothing/glasses/rig_goggles = rig.visor.vision.glasses
if(rig_goggles.vision_flags & (SEE_TURFS|SEE_OBJS))
rig.visor.deactivate()
to_chat(src, span("warning", "\The [rig]'s visor has shuddenly deactivated!"))
..()
@@ -133,6 +133,12 @@ emp_act
if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered?
siemens_coefficient *= C.siemens_coefficient
// Modifiers.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.siemens_coefficient))
siemens_coefficient *= M.siemens_coefficient
return siemens_coefficient
// Similar to above but is for the mob's overall protection, being the average of all slots.
@@ -150,11 +156,11 @@ emp_act
if(fire_stacks < 0) // Water makes you more conductive.
siemens_value *= 1.5
return (siemens_value/max(total, 1))
return (siemens_value / max(total, 1))
// Returns a number between 0 to 1, with 1 being total protection.
/mob/living/carbon/human/get_shock_protection()
return between(0, 1-get_siemens_coefficient_average(), 1)
return min(1 - get_siemens_coefficient_average(), 1) // Don't go above 1, but negatives are fine.
// Returns a list of clothing that is currently covering def_zone.
/mob/living/carbon/human/proc/get_clothing_list_organ(var/obj/item/organ/external/def_zone, var/type)
@@ -173,6 +179,13 @@ emp_act
var/list/protective_gear = def_zone.get_covering_clothing()
for(var/obj/item/clothing/gear in protective_gear)
protection += gear.armor[type]
for(var/thing in modifiers)
var/datum/modifier/M = thing
var/modifier_armor = LAZYACCESS(M.armor_percent, type)
if(modifier_armor)
protection += modifier_armor
return protection
/mob/living/carbon/human/proc/getsoak_organ(var/obj/item/organ/external/def_zone, var/type)
@@ -182,6 +195,13 @@ emp_act
var/list/protective_gear = def_zone.get_covering_clothing()
for(var/obj/item/clothing/gear in protective_gear)
soaked += gear.armorsoak[type]
for(var/thing in modifiers)
var/datum/modifier/M = thing
var/modifier_armor = LAZYACCESS(M.armor_flat, type)
if(modifier_armor)
soaked += modifier_armor
return soaked
// Checked in borer code
+38 -3
View File
@@ -682,10 +682,13 @@
if(bodytemperature >= species.heat_level_2)
if(bodytemperature >= species.heat_level_3)
burn_dam = HEAT_DAMAGE_LEVEL_3
throw_alert("temp", /obj/screen/alert/hot, 3)
else
burn_dam = HEAT_DAMAGE_LEVEL_2
throw_alert("temp", /obj/screen/alert/hot, 2)
else
burn_dam = HEAT_DAMAGE_LEVEL_1
throw_alert("temp", /obj/screen/alert/hot, 1)
take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature")
@@ -709,6 +712,8 @@
take_overall_damage(burn=cold_dam, used_weapon = "Low Body Temperature")
else clear_alert("temp")
// Account for massive pressure differences. Done by Polymorph
// Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense!
if(status_flags & GODMODE)
@@ -823,7 +828,19 @@
/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = get_heat_protection_flags(temperature)
return get_thermal_protection(thermal_protection_flags)
. = get_thermal_protection(thermal_protection_flags)
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.heat_protection))
. *= 1 - M.heat_protection
// Code that calls this expects 1 = immunity so we need to invert again.
. = 1 - .
. = min(., 1.0)
/mob/living/carbon/human/get_cold_protection(temperature)
if(COLD_RESISTANCE in mutations)
@@ -831,7 +848,20 @@
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
var/thermal_protection_flags = get_cold_protection_flags(temperature)
return get_thermal_protection(thermal_protection_flags)
. = get_thermal_protection(thermal_protection_flags)
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.cold_protection))
// Invert the modifier values so they align with the current working value.
. *= 1 - M.cold_protection
// Code that calls this expects 1 = immunity so we need to invert again.
. = 1 - .
. = min(., 1.0)
/mob/living/carbon/human/proc/get_thermal_protection(var/flags)
.=0
@@ -1298,6 +1328,11 @@
sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS)
see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : see_invisible_default
// Do this early so certain stuff gets turned off before vision is assigned.
var/area/A = get_area(src)
if(A?.no_spoilers)
disable_spoiler_vision()
if(XRAY in mutations)
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
see_in_dark = 8
@@ -1568,7 +1603,7 @@
if(Pump)
temp += Pump.standard_pulse_level - PULSE_NORM
if(round(vessel.get_reagent_amount("blood")) <= BLOOD_VOLUME_BAD) //how much blood do we have
if(round(vessel.get_reagent_amount("blood")) <= species.blood_volume*species.blood_level_danger) //how much blood do we have
temp = temp + 3 //not enough :(
if(status_flags & FAKEDEATH)
@@ -43,6 +43,10 @@
var/short_sighted // Permanent weldervision.
var/blood_volume = 560 // Initial blood volume.
var/bloodloss_rate = 1 // Multiplier for how fast a species bleeds out. Higher = Faster
var/blood_level_safe = 0.85 //"Safe" blood level; above this, you're OK
var/blood_level_warning = 0.75 //"Warning" blood level; above this, you're a bit woozy and will have low-level oxydamage (no more than 20, or 15 with inap)
var/blood_level_danger = 0.6 //"Danger" blood level; above this, you'll rapidly take up to 50 oxyloss, and it will then steadily accumulate at a lower rate
var/blood_level_fatal = 0.4 //"Fatal" blood level; below this, you take extremely high oxydamage
var/hunger_factor = 0.05 // Multiplier for hunger.
var/active_regen_mult = 1 // Multiplier for 'Regenerate' power speed, in human_powers.dm
@@ -84,8 +84,16 @@
heat_discomfort_strings = list(
"Your feathers prickle in the heat.",
"You feel uncomfortably warm.",
"Your hands and feet feel hot as your body tries to regulate heat",
)
cold_discomfort_level = 180
cold_discomfort_strings = list(
"You feel a bit chilly.",
"You fluff up your feathers against the cold.",
"You move your arms closer to your body to shield yourself from the cold.",
"You press your ears against your head to conserve heat",
"You start to feel the cold on your skin",
)
minimum_breath_pressure = 12 //Smaller, so needs less air
@@ -309,7 +309,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3]))
//Handle husk overlay.
if(husk && ("overlay_husk" in icon_states(species.icobase)))
if(husk && ("overlay_husk" in cached_icon_states(species.icobase)))
var/icon/mask = new(base_icon)
var/icon/husk_over = new(species.icobase,"overlay_husk")
mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)
+25 -1
View File
@@ -44,7 +44,10 @@
//Check if we're on fire
handle_fire()
// Handle re-running ambience to mobs if they've remained in an area.
handle_ambience()
//stuff in the stomach
handle_stomach()
@@ -88,6 +91,12 @@
/mob/living/proc/handle_stomach()
return
/mob/living/proc/handle_ambience() // If you're in an ambient area and have not moved out of it for x time, we're going to play ambience again to you, to help break up the silence.
if(world.time >= (lastareachange + 30 SECONDS)) // Every 30 seconds, we're going to run a 35% chance to play ambience.
var/area/A = get_area(src)
if(A)
A.play_ambience(src)
/mob/living/proc/update_pulling()
if(pulling)
if(incapacitated())
@@ -118,11 +127,17 @@
/mob/living/proc/handle_stunned()
if(stunned)
AdjustStunned(-1)
throw_alert("stunned", /obj/screen/alert/stunned)
else
clear_alert("stunned")
return stunned
/mob/living/proc/handle_weakened()
if(weakened)
AdjustWeakened(-1)
throw_alert("weakened", /obj/screen/alert/weakened)
else
clear_alert("weakened")
return weakened
/mob/living/proc/handle_stuttering()
@@ -138,6 +153,9 @@
/mob/living/proc/handle_drugged()
if(druggy)
druggy = max(druggy-1, 0)
throw_alert("high", /obj/screen/alert/high)
else
clear_alert("high")
return druggy
/mob/living/proc/handle_slurring()
@@ -148,11 +166,17 @@
/mob/living/proc/handle_paralysed()
if(paralysis)
AdjustParalysis(-1)
throw_alert("paralyzed", /obj/screen/alert/paralyzed)
else
clear_alert("paralyzed")
return paralysis
/mob/living/proc/handle_confused()
if(confused)
AdjustConfused(-1)
throw_alert("confused", /obj/screen/alert/confused)
else
clear_alert("confused")
return confused
/mob/living/proc/handle_disabilities()
+18
View File
@@ -196,6 +196,19 @@ default behaviour is:
return TRUE
return ..()
// Called when something steps onto us. This allows for mulebots and vehicles to run things over. <3
/mob/living/Crossed(var/atom/movable/AM) // Transplanting this from /mob/living/carbon/human/Crossed()
if(AM == src || AM.is_incorporeal()) // We're not going to run over ourselves or ghosts
return
if(istype(AM, /mob/living/bot/mulebot))
var/mob/living/bot/mulebot/MB = AM
MB.runOver(src)
if(istype(AM, /obj/vehicle))
var/obj/vehicle/V = AM
V.RunOver(src)
/mob/living/verb/succumb()
set hidden = 1
if ((src.health < 0 && src.health > (5-src.getMaxHealth()))) // Health below Zero but above 5-away-from-death, as before, but variable
@@ -1363,3 +1376,8 @@ default behaviour is:
clear_alert("weightless")
else
throw_alert("weightless", /obj/screen/alert/weightless)
// Tries to turn off things that let you see through walls, like mesons.
// Each mob does vision a bit differently so this is just for inheritence and also so overrided procs can make the vision apply instantly if they call `..()`.
/mob/living/proc/disable_spoiler_vision()
handle_vision()
@@ -29,4 +29,5 @@ var/global/list/empty_playable_ai_cores = list()
global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
//Handle job slot/tater cleanup.
set_respawn_timer()
clear_client()
@@ -34,6 +34,8 @@
scan_type = "robot"
else if(istype(M, /mob/living/carbon/human))
scan_type = "prosthetics"
else if(istype(M, /obj/mecha))
scan_type = "mecha"
else
to_chat(user, "<font color='red'>You can't analyze non-robotic things!</font>")
return
@@ -95,5 +97,37 @@
if(!organ_found)
to_chat(user, "No prosthetics located.")
if("mecha")
var/obj/mecha/Mecha = M
var/integrity = Mecha.health/initial(Mecha.health)*100
var/cell_charge = Mecha.get_charge()
var/tank_pressure = Mecha.internal_tank ? round(Mecha.internal_tank.return_pressure(),0.01) : "None"
var/tank_temperature = Mecha.internal_tank ? Mecha.internal_tank.return_temperature() : "Unknown"
var/cabin_pressure = round(Mecha.return_pressure(),0.01)
var/output = {"<span class='notice'>Analyzing Results for \the [Mecha]:</span><br>
<b>Chassis Integrity: </b> [integrity]%<br>
<b>Powercell charge: </b>[isnull(cell_charge)?"No powercell installed":"[Mecha.cell.percent()]%"]<br>
<b>Air source: </b>[Mecha.use_internal_tank?"Internal Airtank":"Environment"]<br>
<b>Airtank pressure: </b>[tank_pressure]kPa<br>
<b>Airtank temperature: </b>[tank_temperature]K|[tank_temperature - T0C]&deg;C<br>
<b>Cabin pressure: </b>[cabin_pressure>WARNING_HIGH_PRESSURE ? "<font color='red'>[cabin_pressure]</font>": cabin_pressure]kPa<br>
<b>Cabin temperature: </b> [Mecha.return_temperature()]K|[Mecha.return_temperature() - T0C]&deg;C<br>
<b>DNA Lock: </b> [Mecha.dna?"Mecha.dna":"Not Found"]<br>
"}
to_chat(user, output)
to_chat(user, "<hr>")
to_chat(user, "<span class='notice'>Internal Diagnostics:</span>")
for(var/slot in Mecha.internal_components)
var/obj/item/mecha_parts/component/MC = Mecha.internal_components[slot]
to_chat(user, "[MC?"[slot]: [MC] <span class='notice'>[round((MC.integrity / MC.max_integrity) * 100, 0.1)]%</span> integrity. [MC.get_efficiency() * 100] Operational capacity.":"<span class='warning'>[slot]: Component Not Found</span>"]")
to_chat(user, "<hr>")
to_chat(user, "<span class='notice'>General Statistics:</span>")
to_chat(user, "<span class='notice'>Movement Weight: [Mecha.get_step_delay()]</span><br>")
src.add_fingerprint(user)
return
@@ -153,7 +153,13 @@
/mob/living/silicon/robot/handle_regular_hud_updates()
var/fullbright = FALSE
var/seemeson = FALSE
if (src.stat == 2 || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
var/area/A = get_area(src)
if(A?.no_spoilers)
disable_spoiler_vision()
if (src.stat == DEAD || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
@@ -187,13 +193,14 @@
src.sight &= ~SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_NOLIGHTING
else if (src.stat != 2)
else if (src.stat != DEAD)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
src.see_in_dark = 8 // see_in_dark means you can FAINTLY see in the dark, humans have a range of 3 or so, tajaran have it at 8
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
plane_holder.set_vis(VIS_MESONS,seemeson)
..()
@@ -1099,3 +1099,19 @@
if(module_active && istype(module_active,/obj/item/weapon/gripper))
var/obj/item/weapon/gripper/G = module_active
G.drop_item_nm()
/mob/living/silicon/robot/disable_spoiler_vision()
if(sight_mode & (BORGMESON|BORGMATERIAL|BORGXRAY)) // Whyyyyyyyy have seperate defines.
var/i = 0
// Borg inventory code is very . . interesting and as such, unequiping a specific item requires jumping through some (for) loops.
var/current_selection_index = get_selected_module() // Will be 0 if nothing is selected.
for(var/thing in list(module_state_1, module_state_2, module_state_3))
i++
if(istype(thing, /obj/item/borg/sight))
var/obj/item/borg/sight/S = thing
if(S.sight_mode & (BORGMESON|BORGMATERIAL|BORGXRAY))
select_module(i)
uneq_active()
if(current_selection_index) // Select what the player had before if possible.
select_module(current_selection_index)
+56 -11
View File
@@ -140,7 +140,18 @@
// Cold stuff.
/mob/living/simple_mob/get_cold_protection()
return cold_resist
. = cold_resist
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.cold_protection))
. *= 1 - M.cold_protection
// Code that calls this expects 1 = immunity so we need to invert again.
. = 1 - .
. = min(., 1.0)
// Fire stuff. Not really exciting at the moment.
@@ -154,7 +165,18 @@
return
/mob/living/simple_mob/get_heat_protection()
return heat_resist
. = heat_resist
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.heat_protection))
. *= 1 - M.heat_protection
// Code that calls this expects 1 = immunity so we need to invert again.
. = 1 - .
. = min(., 1.0)
// Electricity
/mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null)
@@ -170,7 +192,18 @@
s.start()
/mob/living/simple_mob/get_shock_protection()
return shock_resist
. = shock_resist
. = 1 - . // Invert from 1 = immunity to 0 = immunity.
// Doing it this way makes multiplicative stacking not get out of hand, so two modifiers that give 0.5 protection will be combined to 0.75 in the end.
for(var/thing in modifiers)
var/datum/modifier/M = thing
if(!isnull(M.siemens_coefficient))
. *= M.siemens_coefficient
// Code that calls this expects 1 = immunity so we need to invert again.
. = 1 - .
. = min(., 1.0)
// Shot with taser/stunvolver
/mob/living/simple_mob/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null)
@@ -218,17 +251,29 @@
// Armor
/mob/living/simple_mob/getarmor(def_zone, attack_flag)
var/armorval = armor[attack_flag]
if(!armorval)
return 0
else
return armorval
if(isnull(armorval))
armorval = 0
for(var/thing in modifiers)
var/datum/modifier/M = thing
var/modifier_armor = LAZYACCESS(M.armor_percent, attack_flag)
if(modifier_armor)
armorval += modifier_armor
return armorval
/mob/living/simple_mob/getsoak(def_zone, attack_flag)
var/armorval = armor_soak[attack_flag]
if(!armorval)
return 0
else
return armorval
if(isnull(armorval))
armorval = 0
for(var/thing in modifiers)
var/datum/modifier/M = thing
var/modifier_armor = LAZYACCESS(M.armor_flat, attack_flag)
if(modifier_armor)
armorval += modifier_armor
return armorval
// Lightning
/mob/living/simple_mob/lightning_act()
@@ -1,6 +1,5 @@
/mob/living/simple_mob/instantiate_hud(var/datum/hud/hud)
if(!client)
return //Why bother.
/mob/living/simple_mob/create_mob_hud(datum/hud/HUD)
..()
var/ui_style = 'icons/mob/screen1_animal.dmi'
if(ui_icons)
@@ -14,9 +13,9 @@
var/list/hotkeybuttons = list()
var/list/slot_info = list()
hud.adding = adding
hud.other = other
hud.hotkeybuttons = hotkeybuttons
HUD.adding = adding
HUD.other = other
HUD.hotkeybuttons = hotkeybuttons
var/list/hud_elements = list()
var/obj/screen/using
@@ -65,8 +64,8 @@
using.screen_loc = ui_acti
using.color = ui_color
using.alpha = ui_alpha
hud.adding += using
hud.action_intent = using
HUD.adding += using
HUD.action_intent = using
hud_elements |= using
@@ -82,8 +81,8 @@
using.screen_loc = ui_acti
using.alpha = ui_alpha
using.layer = LAYER_HUD_ITEM //These sit on the intent box
hud.adding += using
hud.help_intent = using
HUD.adding += using
HUD.help_intent = using
ico = new(ui_style, "black")
ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
@@ -94,8 +93,8 @@
using.screen_loc = ui_acti
using.alpha = ui_alpha
using.layer = LAYER_HUD_ITEM
hud.adding += using
hud.disarm_intent = using
HUD.adding += using
HUD.disarm_intent = using
ico = new(ui_style, "black")
ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
@@ -106,8 +105,8 @@
using.screen_loc = ui_acti
using.alpha = ui_alpha
using.layer = LAYER_HUD_ITEM
hud.adding += using
hud.grab_intent = using
HUD.adding += using
HUD.grab_intent = using
ico = new(ui_style, "black")
ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
@@ -118,8 +117,8 @@
using.screen_loc = ui_acti
using.alpha = ui_alpha
using.layer = LAYER_HUD_ITEM
hud.adding += using
hud.hurt_intent = using
HUD.adding += using
HUD.hurt_intent = using
//Move intent (walk/run)
using = new /obj/screen()
@@ -129,8 +128,8 @@
using.screen_loc = ui_movi
using.color = ui_color
using.alpha = ui_alpha
hud.adding += using
hud.move_intent = using
HUD.adding += using
HUD.move_intent = using
//Resist button
using = new /obj/screen()
@@ -140,7 +139,7 @@
using.screen_loc = ui_pull_resist
using.color = ui_color
using.alpha = ui_alpha
hud.hotkeybuttons += using
HUD.hotkeybuttons += using
//Pull button
pullin = new /obj/screen()
@@ -148,7 +147,7 @@
pullin.icon_state = "pull0"
pullin.name = "pull"
pullin.screen_loc = ui_pull_resist
hud.hotkeybuttons += pullin
HUD.hotkeybuttons += pullin
hud_elements |= pullin
//Health status
@@ -159,8 +158,6 @@
healths.screen_loc = ui_health
hud_elements |= healths
pain = new /obj/screen( null )
zone_sel = new /obj/screen/zone_sel( null )
@@ -181,7 +178,7 @@
using.screen_loc = ui_drop_throw
using.color = ui_color
using.alpha = ui_alpha
hud.hotkeybuttons += using
HUD.hotkeybuttons += using
//Equip detail
using = new /obj/screen()
@@ -191,7 +188,7 @@
using.screen_loc = ui_equip
using.color = ui_color
using.alpha = ui_alpha
hud.adding += using
HUD.adding += using
//Hand slots themselves
inv_box = new /obj/screen/inventory/hand()
@@ -205,8 +202,8 @@
inv_box.slot_id = slot_r_hand
inv_box.color = ui_color
inv_box.alpha = ui_alpha
hud.r_hand_hud_object = inv_box
hud.adding += inv_box
HUD.r_hand_hud_object = inv_box
HUD.adding += inv_box
slot_info["[slot_r_hand]"] = inv_box.screen_loc
inv_box = new /obj/screen/inventory/hand()
@@ -220,8 +217,8 @@
inv_box.slot_id = slot_l_hand
inv_box.color = ui_color
inv_box.alpha = ui_alpha
hud.l_hand_hud_object = inv_box
hud.adding += inv_box
HUD.l_hand_hud_object = inv_box
HUD.adding += inv_box
slot_info["[slot_l_hand]"] = inv_box.screen_loc
//Swaphand titlebar
@@ -232,7 +229,7 @@
using.screen_loc = ui_swaphand1
using.color = ui_color
using.alpha = ui_alpha
hud.adding += using
HUD.adding += using
using = new /obj/screen/inventory()
using.name = "hand"
@@ -241,7 +238,7 @@
using.screen_loc = ui_swaphand2
using.color = ui_color
using.alpha = ui_alpha
hud.adding += using
HUD.adding += using
//Throw button
throw_icon = new /obj/screen()
@@ -251,15 +248,13 @@
throw_icon.screen_loc = ui_drop_throw
throw_icon.color = ui_color
throw_icon.alpha = ui_alpha
hud.hotkeybuttons += throw_icon
HUD.hotkeybuttons += throw_icon
hud_elements |= throw_icon
extra_huds(hud,ui_style,hud_elements)
extra_huds(HUD, HUD.ui_style, hud_elements)
client.screen = list()
client.screen += hud_elements
client.screen += adding + hotkeybuttons
client.screen += client.void
return
if(client)
client.screen = list()
client.screen += hud_elements
client.screen += adding + hotkeybuttons
client.screen += client.void
@@ -54,4 +54,4 @@
/obj/item/weapon/reagent_containers/food/snacks/meat/crab
name = "meat"
desc = "A chunk of meat."
icon_state = "crustacean-meat"
icon_state = "crustacean-meat"
@@ -31,6 +31,17 @@
/turf/simulated/floor/water
)
var/randomize_location = TRUE
/mob/living/simple_mob/animal/passive/fish/Initialize()
..()
if(!default_pixel_x && randomize_location)
default_pixel_x = rand(-12, 12)
if(!default_pixel_y && randomize_location)
default_pixel_y = rand(-6, 10)
// Makes the AI unable to willingly go on land.
/mob/living/simple_mob/animal/passive/fish/IMove(newloc)
if(is_type_in_list(newloc, suitable_turf_types))
@@ -39,6 +50,11 @@
// Take damage if we are not in water
/mob/living/simple_mob/animal/passive/fish/handle_breathing()
if(istype(loc, /obj/item/glass_jar/fish))
var/obj/item/glass_jar/fish/F = loc
if(F.filled)
return
var/turf/T = get_turf(src)
if(T && !is_type_in_list(T, suitable_turf_types))
if(prob(50))
@@ -178,8 +194,8 @@
dorsal_image.color = dorsal_color
belly_image.color = belly_color
overlays += dorsal_image
overlays += belly_image
add_overlay(dorsal_image)
add_overlay(belly_image)
/datum/category_item/catalogue/fauna/rockfish
name = "Sivian Fauna - Rock Puffer"
@@ -234,6 +250,7 @@
/mob/living/simple_mob/animal/passive/fish/rockfish/Initialize()
..()
head_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
update_icon()
/mob/living/simple_mob/animal/passive/fish/rockfish/update_icon()
overlays.Cut()
@@ -245,7 +262,7 @@
head_image.color = head_color
overlays += head_image
add_overlay(head_image)
/datum/category_item/catalogue/fauna/solarfish
name = "Sivian Fauna - Solar Fin"
@@ -231,4 +231,14 @@
name = "Spice"
real_name = "Spice" //Intended to hold the name without altering it.
gender = FEMALE
desc = "It's a tamaskan, the name Spice can be found on its collar."
desc = "It's a tamaskan, the name Spice can be found on its collar."
// Brittany Spaniel
/mob/living/simple_mob/animal/passive/dog/brittany
name = "brittany"
real_name = "brittany"
desc = "It's a brittany spaniel."
icon_state = "brittany"
icon_living = "brittany"
icon_dead = "brittany_dead"
@@ -167,3 +167,4 @@
holder.face_atom(A)
F.energy = max(0, F.energy - 1) // The AI will eventually flee.
@@ -0,0 +1,68 @@
// Complete chumps but a little bit hardier than mice.
/datum/category_item/catalogue/fauna/hare
name = "Sivian Fauna - Ice Hare"
desc = "Classification: S Lepus petropellis\
<br><br>\
Hard-skinned, horned herbivores common on the glacial regions of Sif. \
The Ice Hare lives in colonies of up to thirty individuals dug beneath thick ice sheets for protection from many burrowing predators. \
Their diet consists of mostly moss and lichens, though this is supplemented with the consumption of hard mineral pebbles, which it swallows whole, \
which form the small, hard, 'ice-like' scales of the animal. \
The Ice Hare is almost completely harmless to sapients, with relatively blunt claws and a weak jaw. Its main forms of self-defense are its speed, \
and two sharp head spikes whose 'ear-like' appearance gave the species its common name."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/passive/hare
name = "ice hare"
real_name = "ice hare"
desc = "A small horned herbivore with a tough 'ice-like' hide."
tt_desc = "S Lepus petropellis" //Sivian hare rockskin
catalogue_data = list(/datum/category_item/catalogue/fauna/hare)
icon_state = "hare"
icon_living = "hare"
icon_dead = "hare_dead"
icon_rest = "hare_rest"
maxHealth = 20
health = 20
armor = list(
"melee" = 30,
"bullet" = 5,
"laser" = 5,
"energy" = 0,
"bomb" = 10,
"bio" = 0,
"rad" = 0
)
armor_soak = list(
"melee" = 5,
"bullet" = 0,
"laser" = 0,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
movement_cooldown = 2
mob_size = MOB_SMALL
pass_flags = PASSTABLE
layer = MOB_LAYER
density = 0
response_help = "pets"
response_disarm = "nudges"
response_harm = "kicks"
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
say_list_type = /datum/say_list/hare
/datum/say_list/hare
speak = list("Snrf...","Crk!")
emote_hear = list("crackles","sniffles")
emote_see = list("stomps the ground", "sniffs the air", "chews on something")
@@ -0,0 +1,143 @@
//Very similar to frostflies, but with a non-lethal gas and less damaging, but less easy to protect from, projectiles.
/datum/category_item/catalogue/fauna/tymisian
name = "Binman Fauna - Tymisian Moth"
desc = "Classification: B Carabidae glacios \
<br><br>\
A meter-long fuzzy insect from the planet Binma. \
A native of the Binman contintents of Telarus and Dalomee, the Tymisian Moth usually lives in communal \
groups of upwards of thirty individuals, known as 'spuzzes', and typically breeds up to three times in its \
fifteen year natural lifespan. \
<br>\
Though strictly herbivorous, the moth has an acute sense of smell which it uses to detect potential predators. \
Impressively, the moth secretes an oily substance which it uses to coat collected material stored in 'soft pockets' \
beneath each wing, which in turn attracts colonies of pungent bacteria. \
When threatened, the moth will release this dust, which has a disorienting effect on most Binman species, as well as all known sapients. \
<br>\
The Tymisian Moth is considered an invasive species on Sif, and is believed to have been established from an illegally \
released pet collection. Though less dangerous than in its native environment, the moth has nonetheless established a \
similar symbiotic relationship with Sivian bacteria for its defense mechanism, and is still to be considered quite dangerous. \
<br>\
As an invasive species, individuals encountering the Tymisian Moth on Sif are requested to report the sighting to local wildlife \
services, and remove or destroy the creature if it is safe to do so."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/animal/sif/tymisian
name = "Tymisian Moth"
desc = "A huge, fuzzy insect with a disorienting dust."
tt_desc = "B Lepidoptera cinereus"
catalogue_data = list(/datum/category_item/catalogue/fauna/tymisian)
faction = "spiders" //Hostile to most mobs, not all.
icon_state = "moth"
icon_living = "moth"
icon_dead = "moth_dead"
icon_rest = "moth_dead"
icon = 'icons/mob/animal.dmi'
maxHealth = 80
health = 80
hovering = TRUE
movement_cooldown = 0.5
melee_damage_lower = 5
melee_damage_upper = 10
base_attack_cooldown = 1.5 SECONDS
attacktext = list("nipped", "bit", "pinched")
projectiletype = /obj/item/projectile/energy/blob
special_attack_cooldown = 10 SECONDS
special_attack_min_range = 0
special_attack_max_range = 6
var/energy = 100
var/max_energy = 100
var/datum/effect/effect/system/smoke_spread/mothspore/smoke_spore
say_list_type = /datum/say_list/tymisian
ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly //Uses frostfly AI, since so similar mechanically
/datum/say_list/tymisian
speak = list("Zzzz.", "Rrr...", "Zzt?")
emote_see = list("grooms itself","sprinkles dust from its wings", "rubs its mandibles")
emote_hear = list("chitters", "clicks", "rattles")
say_understood = list("Ssst.")
say_cannot = list("Zzrt.")
say_maybe_target = list("Rr?")
say_got_target = list("Rrrrt!")
say_threaten = list("Kszsz.","Kszzt...","Kzzi!")
say_stand_down = list("Sss.","Zt.","! clicks.")
say_escalate = list("Rszt!")
threaten_sound = 'sound/effects/spray3.ogg'
stand_down_sound = 'sound/effects/squelch1.ogg'
/obj/effect/effect/smoke/elemental/mothspore
name = "spore cloud"
desc = "A dust cloud filled with disorienting bacterial spores."
color = "#80AB82"
/obj/effect/effect/smoke/elemental/mothspore/affect(mob/living/L) //Similar to a very weak flash, but depends on breathing instead of eye protection.
if(iscarbon(L))
var/mob/living/carbon/C = L
if(C.stat != DEAD)
if(C.needs_to_breathe())
var/spore_strength = 5
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.Confuse(spore_strength)
H.eye_blurry = max(H.eye_blurry, spore_strength)
H.adjustHalLoss(10 * (spore_strength / 5))
/datum/effect/effect/system/smoke_spread/mothspore
smoke_type = /obj/effect/effect/smoke/elemental/mothspore
/mob/living/simple_mob/animal/sif/tymisian/do_special_attack(atom/A)
. = TRUE
switch(a_intent)
if(I_DISARM)
if(energy < 20)
return FALSE
energy -= 20
if(smoke_spore)
smoke_spore.set_up(7,0,src)
smoke_spore.start()
return TRUE
return FALSE
/mob/living/simple_mob/animal/sif/tymisian/Initialize()
..()
smoke_spore = new
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
/mob/living/simple_mob/animal/sif/tymisian/handle_special()
..()
if(energy < max_energy)
energy++
/mob/living/simple_mob/animal/sif/tymisian/Stat()
..()
if(client.statpanel == "Status")
statpanel("Status")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
stat(null, eta_status)
stat("Energy", energy)
/mob/living/simple_mob/animal/sif/tymisian/should_special_attack(atom/A)
if(energy >= 20)
return TRUE
return FALSE
@@ -0,0 +1,51 @@
/datum/category_item/catalogue/fauna/pillbug
name = "Sivian Fauna - Fire Bug"
desc = "Classification: S Armadillidiidae calidi \
<br><br>\
A 10 inch long, hard-shelled insect with a natural adaption to living around terrestrial lava vents. \
The fire bug's hard shell offers extremely effective protection against most threats, \
though the species is almost completely docile, and will prefer to continue grazing on its diet of volcanic micro-flora \
rather than defend itself in most situations.\
<br>\
The fire bug is a curiosity to most on the frontier, offering little in the way of meaningful food or resources, \
though at least one Sivian fashion designer has used their iridescent red shells to create striking, hand-made garments."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/passive/pillbug
name = "fire bug"
desc = "A tiny plated bug found in Sif's volcanic regions."
tt_desc = "S Armadillidiidae calidi"
catalogue_data = list(/datum/category_item/catalogue/fauna/pillbug)
icon_state = "pillbug"
icon_living = "pillbug"
icon_dead = "pillbug_dead"
health = 15
maxHealth = 15
mob_size = MOB_MINISCULE
response_help = "gently touches"
response_disarm = "rolls over"
response_harm = "stomps on"
armor = list(
"melee" = 30,
"bullet" = 10,
"laser" = 50,
"energy" = 50,
"bomb" = 30,
"bio" = 100,
"rad" = 100
)
// The frostfly's body is incredibly cold at all times, natural resistance to things trying to burn it.
armor_soak = list(
"melee" = 10,
"bullet" = 0,
"laser" = 10,
"energy" = 10,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
@@ -0,0 +1,61 @@
// Somewhere between a fox and a weasel. Doesn't mess with stuff significantly bigger than it, but you don't want to get on its bad side.
/datum/category_item/catalogue/fauna/siffet
name = "Sivian Fauna - Siffet"
desc = "Classification: S Pruinaeictis velocis\
<br><br>\
The Siffet, or Sivian Frost Weasel is a small, solitary predator known for its striking ability to take down prey up to twice their size. \
The majority of the Siffet's adult life is spent in isolation, prowling large territories in Sif's tundra regions, \
only seeking out other individuals during the summer mating season, when deadly battles for dominance are common. \
Though mostly docile towards adult humans and other large sapients, the Siffet has been known to target children and smaller species as prey, \
and a provoked Siffet can be a danger to even the most experienced handler due to its quick movement and surprisingly powerful jaws. \
The Siffet is sometimes hunted for its remarkably soft pelt, though most is obtained through fur farming."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/animal/sif/siffet
name = "siffet"
desc = "A small, solitary predator with silky fur. Despite its size, the Siffet is ferocious when provoked."
tt_desc = "S Pruinaeictis velocis" //Sivian frost weasel, fast
catalogue_data = list(/datum/category_item/catalogue/fauna/siffet)
faction = "siffet"
mob_size = MOB_SMALL
icon_state = "siffet"
icon_living = "siffet"
icon_dead = "siffet_dead"
icon = 'icons/mob/animal.dmi'
maxHealth = 60
health = 60
movement_cooldown = 0
melee_damage_lower = 10
melee_damage_upper = 15
base_attack_cooldown = 1 SECOND
attack_sharp = 1
attacktext = list("sliced", "snapped", "gnawed")
say_list_type = /datum/say_list/siffet
ai_holder_type = /datum/ai_holder/simple_mob/siffet
/datum/say_list/siffet
speak = list("Yap!", "Heh!", "Huff.")
emote_see = list("sniffs its surroundings","flicks its ears", "scratches the ground")
emote_hear = list("chatters", "huffs")
/datum/ai_holder/simple_mob/siffet
hostile = TRUE
retaliate = TRUE
/datum/ai_holder/simple_mob/siffet/post_melee_attack(atom/A) //Evasive
if(holder.Adjacent(A))
holder.IMove(get_step(holder, pick(alldirs)))
holder.face_atom(A)
/mob/living/simple_mob/animal/sif/siffet/IIsAlly(mob/living/L)
. = ..()
if(!. && L.mob_size > 10) //Attacks things it considers small enough to take on, otherwise only attacks if attacked.
return TRUE
+43 -33
View File
@@ -333,46 +333,56 @@
return
*/
/mob/proc/set_respawn_timer(var/time)
// Try to figure out what time to use
// Special cases, can never respawn
if(ticker?.mode?.deny_respawn)
time = -1
else if(!config.abandon_allowed)
time = -1
else if(!config.respawn)
time = -1
// Special case for observing before game start
else if(ticker?.current_state <= GAME_STATE_SETTING_UP)
time = 1 MINUTE
// Wasn't given a time, use the config time
else if(!time)
time = config.respawn_time
var/keytouse = ckey
// Try harder to find a key to use
if(!keytouse && key)
keytouse = ckey(key)
else if(!keytouse && mind?.key)
keytouse = ckey(mind.key)
GLOB.respawn_timers[keytouse] = world.time + time
/mob/observer/dead/set_respawn_timer()
if(config.antag_hud_restricted && has_enabled_antagHUD)
..(-1)
else
return // Don't set it, no need
/mob/verb/abandon_mob()
set name = "Respawn"
set name = "Return to Menu"
set category = "OOC"
if (!( config.abandon_allowed ))
to_chat(usr, "<span class='notice'>Respawn is disabled.</span>")
return
if ((stat != 2 || !( ticker )))
if(stat != DEAD || !ticker)
to_chat(usr, "<span class='notice'><B>You must be dead to use this!</B></span>")
return
if (ticker.mode && ticker.mode.deny_respawn) //BS12 EDIT
to_chat(usr, "<span class='notice'>Respawn is disabled for this roundtype.</span>")
return
else
var/deathtime = world.time - src.timeofdeath
if(istype(src,/mob/observer/dead))
var/mob/observer/dead/G = src
if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted)
to_chat(usr, "<font color='blue'><B>By using the antagHUD you forfeit the ability to join the round.</B></font>")
return
var/deathtimeminutes = round(deathtime / 600)
var/pluralcheck = "minute"
if(deathtimeminutes == 0)
pluralcheck = ""
else if(deathtimeminutes == 1)
pluralcheck = " [deathtimeminutes] minute and"
else if(deathtimeminutes > 1)
pluralcheck = " [deathtimeminutes] minutes and"
var/deathtimeseconds = round((deathtime - deathtimeminutes * 600) / 10,1)
to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
if ((deathtime < (5 * 600)) && (ticker && ticker.current_state > GAME_STATE_PREGAME))
to_chat(usr, "You must wait 5 minutes to respawn!")
// Final chance to abort "respawning"
if(mind && timeofdeath) // They had spawned before
var/choice = alert(usr, "Returning to the menu will prevent your character from being revived in-round. Are you sure?", "Confirmation", "No, wait", "Yes, leave")
if(choice == "No, wait")
return
else
to_chat(usr, "You can respawn now, enjoy your new life!")
log_game("[usr.name]/[usr.key] used abandon mob.")
to_chat(usr, "<font color='blue'><B>Make sure to play a different character, and please roleplay correctly!</B></font>")
// Beyond this point, you're going to respawn
to_chat(usr, config.respawn_message)
if(!client)
log_game("[usr.key] AM failed due to disconnect.")
+1
View File
@@ -181,6 +181,7 @@
var/status_flags = CANSTUN|CANWEAKEN|CANPARALYSE|CANPUSH //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc)
var/area/lastarea = null
var/lastareachange = null
var/digitalcamo = 0 // Can they be tracked by the AI?
+2 -2
View File
@@ -194,7 +194,7 @@
return result
// Can't control ourselves when drifting
if(isspace(loc) || my_mob.lastarea?.has_gravity == 0)
if((isspace(loc) || my_mob.lastarea?.has_gravity == 0) && !my_mob.in_enclosed_vehicle) //If(In space or last area had no gravity) or(you in vehicle)
if(!my_mob.Process_Spacemove(0))
return 0
@@ -292,7 +292,7 @@
// It's just us and another person
if(grablist.len == 1)
var/mob/M = grablist[1]
if(!my_mob.Adjacent(M)) //Oh no, we moved away
if(M && !my_mob.Adjacent(M)) //Oh no, we moved away
M.Move(pre_move_loc, get_dir(M, pre_move_loc), total_delay) //Have them step towards where we were
// It's a grab chain
+1 -1
View File
@@ -9,7 +9,7 @@ var/obj/effect/lobby_image = new /obj/effect/lobby_image
/obj/effect/lobby_image/Initialize()
icon = using_map.lobby_icon
var/known_icon_states = icon_states(icon)
var/known_icon_states = cached_icon_states(icon)
for(var/lobby_screen in using_map.lobby_screens)
if(!(lobby_screen in known_icon_states))
error("Lobby screen '[lobby_screen]' did not exist in the icon set [icon].")
+26 -2
View File
@@ -120,8 +120,9 @@
new_player_panel_proc()
if(href_list["observe"])
var/alert_time = ticker?.current_state <= GAME_STATE_SETTING_UP ? 1 : round(config.respawn_time/10/60)
if(alert(src,"Are you sure you wish to observe? You will have to wait 5 minutes before being able to respawn!","Player Setup","Yes","No") == "Yes")
if(alert(src,"Are you sure you wish to observe? You will have to wait up to [alert_time] minute\s before being able to spawn into the game!","Player Setup","Yes","No") == "Yes")
if(!client) return 1
//Make a new mannequin quickly, and allow the observer to take the appearance
@@ -143,7 +144,6 @@
observer.forceMove(O.loc)
else
to_chat(src, "<span class='danger'>Could not locate an observer spawn point. Use the Teleport verb to jump to the station map.</span>")
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
announce_ghost_joinleave(src)
@@ -154,6 +154,7 @@
if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
observer.verbs -= /mob/observer/dead/verb/toggle_antagHUD // Poor guys, don't know what they are missing!
observer.key = key
observer.set_respawn_timer(time_till_respawn()) // Will keep their existing time if any, or return 0 and pass 0 into set_respawn_timer which will use the defaults
qdel(src)
return 1
@@ -163,6 +164,12 @@
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, "<font color='red'>The round is either not ready, or has already finished...</font>")
return
var/time_till_respawn = time_till_respawn()
if(time_till_respawn == -1) // Special case, never allowed to respawn
to_chat(usr, "<span class='warning'>Respawning is not allowed!</span>")
else if(time_till_respawn) // Nonzero time to respawn
to_chat(usr, "<span class='warning'>You can't respawn yet! You need to wait another [round(time_till_respawn/10/60, 0.1)] minutes.</span>")
return
LateChoices()
if(href_list["manifest"])
@@ -331,6 +338,23 @@
popup.set_content(dat)
popup.open()
/mob/new_player/proc/time_till_respawn()
if(!ckey)
return -1 // What?
var/timer = GLOB.respawn_timers[ckey]
// No timer at all
if(!timer)
return 0
// Special case, infinite timer
if(timer == -1)
return -1
// Timer expired
if(timer <= world.time)
GLOB.respawn_timers -= ckey
return 0
// Timer still going
return timer - world.time
/mob/new_player/proc/IsJobAvailable(rank)
var/datum/job/job = job_master.GetJob(rank)
@@ -1126,23 +1126,23 @@
//Skrell 'hairstyles'
skr_tentacle_veryshort
name = "Skrell Very Short Tentacles"
icon_state = "skrell_hair_veryshort"
name = "Skrell Short Tentacles"
icon_state = "skrell_hair_short"
species_allowed = list(SPECIES_SKRELL)
gender = MALE
skr_tentacle_short
name = "Skrell Short Tentacles"
icon_state = "skrell_hair_short"
species_allowed = list(SPECIES_SKRELL)
skr_tentacle_average
name = "Skrell Average Tentacles"
icon_state = "skrell_hair_average"
species_allowed = list(SPECIES_SKRELL)
skr_tentacle_verylong
skr_tentacle_average
name = "Skrell Long Tentacles"
icon_state = "skrell_hair_long"
species_allowed = list(SPECIES_SKRELL)
skr_tentacle_verylong
name = "Skrell Very Long Tentacles"
icon_state = "skrell_hair_verylong"
species_allowed = list(SPECIES_SKRELL)
gender = FEMALE