Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into ilowkeydespiseatmospherics
# Conflicts: # _maps/map_files/BoxStation/BoxStation.dmm
This commit is contained in:
@@ -61,7 +61,9 @@
|
||||
|
||||
#define BELOW_MOB_LAYER 3.7
|
||||
#define LYING_MOB_LAYER 3.8
|
||||
#define MOB_LOWER_LAYER 3.95
|
||||
//#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define
|
||||
#define MOB_UPPER_LAYER 4.05
|
||||
#define ABOVE_MOB_LAYER 4.1
|
||||
#define WALL_OBJ_LAYER 4.25
|
||||
#define EDGED_TURF_LAYER 4.3
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/// true/false
|
||||
#define SKILL_PROGRESSION_BINARY 1
|
||||
/// numerical
|
||||
#define SKILL_PROGRESSION_NUMERICAL 2
|
||||
/// Enum
|
||||
#define SKILL_PROGRESSION_ENUM 3
|
||||
|
||||
/// Max value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MAX 100
|
||||
/// Min value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MIN 0
|
||||
|
||||
// Standard values for job starting skills
|
||||
|
||||
#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX
|
||||
|
||||
// Standard values for job starting skill affinities
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2
|
||||
|
||||
// Standard values for skill gain (this is multiplied by affinity)
|
||||
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
|
||||
// Misc
|
||||
|
||||
/// 40% speedup at 100 skill
|
||||
#define SURGERY_SKILL_SPEEDUP_NUMERICAL_SCALE(number) clamp(number / 250, 1, 2)
|
||||
@@ -387,6 +387,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
for(var/mob/dead/new_player/N in GLOB.player_list)
|
||||
var/mob/living/carbon/human/player = N.new_character
|
||||
if(istype(player) && player.mind && player.mind.assigned_role)
|
||||
var/datum/job/J = SSjob.GetJob(player.mind.assigned_role)
|
||||
if(J)
|
||||
J.standard_assign_skills(player.mind)
|
||||
if(player.mind.assigned_role == "Captain")
|
||||
captainless=0
|
||||
if(player.mind.assigned_role != player.mind.special_role)
|
||||
|
||||
@@ -352,7 +352,6 @@ SUBSYSTEM_DEF(vote)
|
||||
if("dynamic")
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
||||
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
GLOB.master_mode = "dynamic"
|
||||
var/list/runnable_storytellers = config.get_runnable_storytellers()
|
||||
var/datum/dynamic_storyteller/picked
|
||||
for(var/T in runnable_storytellers)
|
||||
@@ -489,6 +488,7 @@ SUBSYSTEM_DEF(vote)
|
||||
modes_to_add -= "traitor" // makes it so that traitor is always available
|
||||
choices.Add(modes_to_add)
|
||||
if("dynamic")
|
||||
GLOB.master_mode = "dynamic"
|
||||
var/list/probabilities = CONFIG_GET(keyed_list/storyteller_weight)
|
||||
for(var/T in config.storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
|
||||
@@ -115,6 +115,33 @@
|
||||
//Tools & Storage//
|
||||
///////////////////
|
||||
|
||||
/datum/crafting_recipe/upgraded_gauze
|
||||
name = "Improved Gauze"
|
||||
result = /obj/item/stack/medical/gauze/adv
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/space_cleaner/sterilizine = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/bruise_pack
|
||||
name = "Bruise Pack"
|
||||
result = /obj/item/stack/medical/bruise_pack
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/burn_pack
|
||||
name = "Brun Ointment"
|
||||
result = /obj/item/stack/medical/ointment
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/ghettojetpack
|
||||
name = "Improvised Jetpack"
|
||||
result = /obj/item/tank/jetpack/improvised
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
|
||||
/datum/component/riding/human/Initialize()
|
||||
. = ..()
|
||||
directional_vehicle_layers = list(TEXT_NORTH = MOB_LOWER_LAYER, TEXT_SOUTH = MOB_UPPER_LAYER, TEXT_EAST = MOB_UPPER_LAYER, TEXT_WEST = MOB_UPPER_LAYER)
|
||||
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
|
||||
|
||||
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
|
||||
@@ -261,6 +262,10 @@
|
||||
|
||||
/datum/component/riding/cyborg
|
||||
|
||||
/datum/component/riding/cyborg/Initialize()
|
||||
. = ..()
|
||||
directional_vehicle_layers = list(TEXT_NORTH = MOB_LOWER_LAYER, TEXT_SOUTH = MOB_UPPER_LAYER, TEXT_EAST = MOB_UPPER_LAYER, TEXT_WEST = MOB_UPPER_LAYER)
|
||||
|
||||
/datum/component/riding/cyborg/ride_check(mob/user)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
|
||||
@@ -63,7 +63,11 @@
|
||||
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
|
||||
var/list/learned_recipes //List of learned recipe TYPES.
|
||||
|
||||
/// Our skill holder.
|
||||
var/datum/skill_holder/skill_holder
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
skill_holder = new
|
||||
src.key = key
|
||||
soulOwner = src
|
||||
martial_art = default_martial_art
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// yeah yeah verbs suck whatever I suck at this fix this someone please - kevinz000
|
||||
|
||||
/mob/verb/check_skills()
|
||||
set name = "Check Skills"
|
||||
set category = "IC"
|
||||
set desc = "Check your skills (if you have any..)"
|
||||
|
||||
if(!mind)
|
||||
to_chat(usr, "<span class='warning'>How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without a mind?</span>")
|
||||
return
|
||||
if(!mind.skill_holder)
|
||||
to_chat(usr, "<span class='warning'>How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)</span>")
|
||||
return
|
||||
var/datum/browser/B = new(usr, "skilldisplay_[REF(src)]", "Skills of [src]")
|
||||
B.set_content(mind.skill_holder.html_readout())
|
||||
B.open()
|
||||
@@ -0,0 +1,95 @@
|
||||
GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
|
||||
/proc/init_skill_datums()
|
||||
. = list()
|
||||
for(var/path in subtypesof(/datum/skill))
|
||||
var/datum/skill/S = path
|
||||
if(initial(S.abstract_type) == path)
|
||||
continue
|
||||
S = new path
|
||||
.[S.type] = S
|
||||
|
||||
/proc/get_skill_datum(path)
|
||||
return GLOB.skill_datums[path]
|
||||
|
||||
/proc/sanitize_skill_value(path, value)
|
||||
var/datum/skill/S = get_skill_datum(path)
|
||||
// don't check, if we runtime let it happen.
|
||||
return S.sanitize_value(value)
|
||||
|
||||
/proc/is_skill_value_greater(path, existing, new_value)
|
||||
var/datum/skill/S = get_skill_datum(path)
|
||||
// don't check, if we runtime let it happen.
|
||||
return S.is_value_greater(existing, new_value)
|
||||
|
||||
/**
|
||||
* Skill datums
|
||||
*/
|
||||
/datum/skill
|
||||
/// Our name
|
||||
var/name
|
||||
/// Our description
|
||||
var/desc
|
||||
/// Our progression type
|
||||
var/progression_type
|
||||
/// Abstract type
|
||||
var/abstract_type = /datum/skill
|
||||
|
||||
/**
|
||||
* Ensures what someone's setting as a value for this skill is valid.
|
||||
*/
|
||||
/datum/skill/proc/sanitize_value(new_value)
|
||||
return new_value
|
||||
|
||||
/**
|
||||
* Checks if a value is greater
|
||||
*/
|
||||
/datum/skill/proc/is_value_greater(existing, new_value)
|
||||
if(!existing)
|
||||
return TRUE
|
||||
return new_value > existing
|
||||
|
||||
/**
|
||||
* Standard value "render"
|
||||
*/
|
||||
/datum/skill/proc/standard_render_value(value)
|
||||
return value
|
||||
|
||||
// Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context.
|
||||
// Aka: So people don't forget to change checks if they change a skill's progression type.
|
||||
|
||||
/datum/skill/binary
|
||||
abstract_type = /datum/skill/binary
|
||||
progression_type = SKILL_PROGRESSION_BINARY
|
||||
|
||||
/datum/skill/binary/sanitize_value(new_value)
|
||||
return new_value? TRUE : FALSE
|
||||
|
||||
/datum/skill/binary/standard_render_value(value)
|
||||
return value? "Yes" : "No"
|
||||
|
||||
/datum/skill/numerical
|
||||
abstract_type = /datum/skill/numerical
|
||||
progression_type = SKILL_PROGRESSION_NUMERICAL
|
||||
/// Max value of this skill
|
||||
var/max_value = 100
|
||||
/// Min value of this skill
|
||||
var/min_value = 0
|
||||
/// Display as a percent in standard_render_value?
|
||||
var/display_as_percent = FALSE
|
||||
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
/datum/skill/numerical/standard_render_value(value)
|
||||
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
|
||||
|
||||
/datum/skill/enum
|
||||
abstract_type = /datum/skill/enum
|
||||
progression_type = SKILL_PROGRESSION_ENUM
|
||||
/// Valid values for the skill
|
||||
var/list/valid_values = list()
|
||||
|
||||
/datum/skill/enum/sanitize_value(new_value)
|
||||
if(new_value in valid_values)
|
||||
return new_value
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Skill holder datums
|
||||
*/
|
||||
/datum/skill_holder
|
||||
/// Our list of skills and values. Lazylist. Associative. Keys are datum typepaths to the skill.
|
||||
var/list/skills
|
||||
/// Same as [skills] but affinities, which are multiplied to increase amount when gaining skills.
|
||||
var/list/skill_affinities
|
||||
|
||||
/**
|
||||
* Grabs the value of a skill.
|
||||
*/
|
||||
/datum/skill_holder/proc/get_skill_value(skill)
|
||||
if(!ispath(skill))
|
||||
CRASH("Invalid get_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
if(!skills)
|
||||
return null
|
||||
return skills[skill]
|
||||
|
||||
/**
|
||||
* Grabs our affinity for a skill. !!This is a multiplier!!
|
||||
*/
|
||||
/datum/skill_holder/proc/get_skill_affinity(skill)
|
||||
if(!ispath(skill))
|
||||
CRASH("Invalid get_skill_affinity call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
if(!skills)
|
||||
return 1
|
||||
var/affinity = skill_affinities[skill]
|
||||
if(isnull(affinity))
|
||||
return 1
|
||||
return affinity
|
||||
|
||||
/**
|
||||
* Sets the value of a skill.
|
||||
*/
|
||||
/datum/skill_holder/proc/set_skill_value(skill, value)
|
||||
if(!ispath(skill))
|
||||
CRASH("Invalid set_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
LAZYINITLIST(skills)
|
||||
value = sanitize_skill_value(skill, value)
|
||||
if(!isnull(value))
|
||||
skills[skill] = value
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Boosts a skill to a value if not aobve
|
||||
*/
|
||||
/datum/skill_holder/proc/boost_skill_value_to(skill, value)
|
||||
var/current = get_skill_value(skill)
|
||||
if(!is_skill_value_greater(skill, current, value))
|
||||
return FALSE
|
||||
set_skill_value(skill, value)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Automatic skill increase, multiplied by skill affinity if existing.
|
||||
* Only works if skill is numerical.
|
||||
*/
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value)
|
||||
if(!ispath(skill, /datum/skill/numerical))
|
||||
CRASH("You cannot auto increment a non numerical skill!")
|
||||
var/current = get_skill_value(skill)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
boost_skill_value_to(skill, current + (value * affinity))
|
||||
|
||||
/**
|
||||
* Generates a HTML readout of our skills.
|
||||
* Port to tgui-next when?
|
||||
*/
|
||||
/datum/skill_holder/proc/html_readout()
|
||||
var/list/out = list("<center><h1>Skills</h1></center><hr>")
|
||||
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
|
||||
for(var/path in skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
out += "<tr><td>[S.name]</td><td>[S.standard_render_value(skills[path])]</td></tr>"
|
||||
out += "</table>"
|
||||
return out.Join("")
|
||||
@@ -0,0 +1,3 @@
|
||||
/datum/skill/numerical/surgery
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at doing surgery."
|
||||
@@ -40,8 +40,10 @@ GLOBAL_VAR_INIT(dynamic_stacking_limit, 90)
|
||||
GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
// Storyteller picked by the voting.
|
||||
GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
|
||||
// Storyteller forced by admins during voting--will be used instead of above.
|
||||
GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
|
||||
/datum/game_mode/dynamic
|
||||
name = "dynamic mode"
|
||||
@@ -252,7 +254,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
|
||||
/datum/game_mode/dynamic/send_intercept()
|
||||
. = "<b><i>Central Command Status Summary</i></b><hr>"
|
||||
switch(round(threat_level))
|
||||
if(0 to 20)
|
||||
if(-INFINITY to 20)
|
||||
. += "<b>Peaceful Waypoint</b></center><BR>"
|
||||
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive. However, even deep in our territory there may be subversive elements, especially for such a high-value target as your station. Keep an eye out, but don't expect much trouble."
|
||||
set_security_level(SEC_LEVEL_GREEN)
|
||||
@@ -284,7 +286,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
|
||||
. += "<b>Black Orbit</b></center><BR>"
|
||||
. += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece."
|
||||
set_security_level(SEC_LEVEL_AMBER)
|
||||
if(96 to 100)
|
||||
if(96 to INFINITY)
|
||||
. += "<b>Impending Doom</b></center><BR>"
|
||||
. += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.<BR>"
|
||||
. += "Good luck."
|
||||
@@ -355,6 +357,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",peaceful_percentage,"Percent of same-vote rounds that are more peaceful")
|
||||
|
||||
/datum/game_mode/dynamic/can_start()
|
||||
if(GLOB.dynamic_forced_storyteller)
|
||||
GLOB.dynamic_storyteller_type = GLOB.dynamic_forced_storyteller
|
||||
storyteller = new GLOB.dynamic_storyteller_type // this is where all the initialization happens
|
||||
storyteller.on_start()
|
||||
SSblackbox.record_feedback("text","dynamic_storyteller",1,storyteller.name)
|
||||
|
||||
@@ -393,7 +393,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
qdel(src)
|
||||
item_flags &= ~IN_INVENTORY
|
||||
if(SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) & COMPONENT_DROPPED_RELOCATION)
|
||||
return ITEM_RELOCATED_BY_DROPPED
|
||||
. = ITEM_RELOCATED_BY_DROPPED
|
||||
user.update_equipment_speed_mods()
|
||||
|
||||
// called just as an item is picked up (loc is not yet changed)
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
if(!H.bleedsuppress && H.bleed_rate) //so you can't stack bleed suppression
|
||||
H.suppress_bloodloss(stop_bleeding)
|
||||
to_chat(user, "<span class='notice'>You stop the bleeding of [M]!</span>")
|
||||
H.adjustBruteLoss(-(heal_brute))
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You can not use \the [src] on [M]!</span>")
|
||||
|
||||
@@ -127,6 +128,12 @@
|
||||
stop_bleeding = 900
|
||||
heal_brute = 0
|
||||
|
||||
/obj/item/stack/medical/gauze/adv
|
||||
name = "sterilized medical gauze"
|
||||
desc = "A roll of elastic sterilized cloth that is extremely effective at stopping bleeding, heals minor wounds and cleans them."
|
||||
singular_name = "sterilized medical gauze"
|
||||
self_delay = 5
|
||||
|
||||
/obj/item/stack/medical/gauze/cyborg
|
||||
custom_materials = null
|
||||
is_cyborg = 1
|
||||
|
||||
@@ -695,7 +695,10 @@
|
||||
/obj/item/gun/ballistic/revolver,
|
||||
/obj/item/ammo_box,
|
||||
/obj/item/toy/gun,
|
||||
/obj/item/gun/energy/e_gun/mini
|
||||
/obj/item/gun/energy/e_gun/mini,
|
||||
/obj/item/gun/ballistic/automatic/magrifle/pistol,
|
||||
/obj/item/gun/energy/disabler,
|
||||
/obj/item/gun/energy/taser
|
||||
))
|
||||
|
||||
/obj/item/storage/belt/holster/full/PopulateContents()
|
||||
|
||||
@@ -429,6 +429,10 @@
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_storyteller=1'>(Force Storyteller)</A><br>"
|
||||
if (GLOB.dynamic_forced_storyteller)
|
||||
var/datum/dynamic_storyteller/S = GLOB.dynamic_forced_storyteller
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_storyteller_clear=1'>-> [initial(S.name)] <-</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
|
||||
else if (SSticker.IsRoundInProgress())
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin=1'>(Force Next Latejoin Ruleset)</A><br>"
|
||||
@@ -690,7 +694,7 @@
|
||||
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
||||
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
||||
if (!prev_dynamic_voting)
|
||||
to_chat(world, "<B>Vote is now a ranked choice of dynamic storytellers.</B>")
|
||||
to_chat(world, "<B>Vote is now between dynamic storytellers.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
||||
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
||||
|
||||
@@ -1394,6 +1394,32 @@
|
||||
log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.")
|
||||
message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_storyteller"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null)
|
||||
var/list/choices = list()
|
||||
for(var/T in config.storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
choices[initial(S.name)] = T
|
||||
var/choice = choices[input("Select storyteller:", "Storyteller", "Classic") as null|anything in choices]
|
||||
if(choice)
|
||||
GLOB.dynamic_forced_storyteller = choice
|
||||
log_admin("[key_name(usr)] forced the storyteller to [GLOB.dynamic_forced_storyteller].")
|
||||
message_admins("[key_name(usr)] forced the storyteller to [GLOB.dynamic_forced_storyteller].")
|
||||
Game()
|
||||
|
||||
else if(href_list["f_dynamic_storyteller_clear"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
GLOB.dynamic_forced_storyteller = null
|
||||
Game()
|
||||
log_admin("[key_name(usr)] cleared the forced storyteller. The mode will pick one as normal.")
|
||||
message_admins("[key_name(usr)] cleared the forced storyteller. The mode will pick one as normal.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_latejoin"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
status = ORGAN_ROBOTIC
|
||||
beating = TRUE
|
||||
organ_flags = ORGAN_NO_SPOIL
|
||||
no_pump = TRUE
|
||||
var/true_name = "baseline placebo referencer"
|
||||
var/cooldown_low = 300
|
||||
var/cooldown_high = 300
|
||||
@@ -92,6 +93,7 @@
|
||||
update_gland_hud()
|
||||
|
||||
/obj/item/organ/heart/gland/on_life()
|
||||
. = ..()
|
||||
if(!beating)
|
||||
// alien glands are immune to stopping.
|
||||
beating = TRUE
|
||||
|
||||
@@ -66,6 +66,11 @@
|
||||
// How much threat this job is worth in dynamic. Is subtracted if the player's not an antag, added if they are.
|
||||
var/threat = 0
|
||||
|
||||
/// Starting skill levels.
|
||||
var/list/starting_skills
|
||||
/// Skill affinities to set
|
||||
var/list/skill_affinities
|
||||
|
||||
//Only override this proc
|
||||
//H is usually a human unless an /equip override transformed it
|
||||
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
|
||||
@@ -142,7 +147,6 @@
|
||||
return TRUE //Available in 0 days = available right now = player is old enough to play.
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/job/proc/available_in_days(client/C)
|
||||
if(!C)
|
||||
return 0
|
||||
@@ -166,6 +170,17 @@
|
||||
/datum/job/proc/radio_help_message(mob/M)
|
||||
to_chat(M, "<b>Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.</b>")
|
||||
|
||||
/datum/job/proc/standard_assign_skills(datum/mind/M)
|
||||
if(!starting_skills)
|
||||
return
|
||||
for(var/skill in starting_skills)
|
||||
M.skill_holder.boost_skill_value_to(skill, starting_skills[skill])
|
||||
// do wipe affinities though
|
||||
M.skill_holder.skill_affinities = list()
|
||||
for(var/skill in skill_affinities)
|
||||
M.skill_holder.skill_affinities[skill] = skill_affinities[skill]
|
||||
UNSETEMPTY(M.skill_holder.skill_affinities) //if we didn't set any.
|
||||
|
||||
/datum/outfit/job
|
||||
name = "Standard Gear"
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
display_order = JOB_DISPLAY_ORDER_CHEMIST
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/chemist
|
||||
name = "Chemist"
|
||||
jobtype = /datum/job/chemist
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
|
||||
threat = 2
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/cmo
|
||||
name = "Chief Medical Officer"
|
||||
jobtype = /datum/job/cmo
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
display_order = JOB_DISPLAY_ORDER_GENETICIST
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/geneticist
|
||||
name = "Geneticist"
|
||||
jobtype = /datum/job/geneticist
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR
|
||||
threat = 0.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/doctor
|
||||
name = "Medical Doctor"
|
||||
jobtype = /datum/job/doctor
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
threat = 0.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/paramedic
|
||||
name = "Paramedic"
|
||||
jobtype = /datum/job/paramedic
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/virologist
|
||||
name = "Virologist"
|
||||
jobtype = /datum/job/virologist
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/organ/regenerative_core/on_life()
|
||||
..()
|
||||
. = ..()
|
||||
if(owner.health < owner.crit_threshold)
|
||||
ui_action_click()
|
||||
|
||||
|
||||
@@ -392,6 +392,8 @@
|
||||
|
||||
character.update_parallax_teleport()
|
||||
|
||||
job.standard_assign_skills(character.mind)
|
||||
|
||||
SSticker.minds += character.mind
|
||||
|
||||
var/mob/living/carbon/human/humanc
|
||||
|
||||
@@ -245,23 +245,17 @@
|
||||
. = adjusted_amount
|
||||
*/
|
||||
|
||||
/obj/item/organ/brain/on_life()
|
||||
if(damage >= BRAIN_DAMAGE_DEATH) //rip
|
||||
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
|
||||
owner.death()
|
||||
brain_death = TRUE
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/organ/brain/on_death()
|
||||
if(damage <= BRAIN_DAMAGE_DEATH) //rip
|
||||
brain_death = FALSE
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
|
||||
..()
|
||||
|
||||
. = ..()
|
||||
if(!. || !owner)
|
||||
return
|
||||
if(damage >= BRAIN_DAMAGE_DEATH) //rip
|
||||
if(owner.stat != DEAD)
|
||||
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
|
||||
owner.death()
|
||||
brain_death = TRUE
|
||||
else
|
||||
brain_death = FALSE
|
||||
|
||||
/obj/item/organ/brain/check_damage_thresholds(mob/M)
|
||||
. = ..()
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/transfer)
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/on_life()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
//If there are alien weeds on the ground then heal if needed or give some plasma
|
||||
if(locate(/obj/structure/alien/weeds) in owner.loc)
|
||||
if(owner.health >= owner.maxHealth)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/on_life()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
switch(stage)
|
||||
if(2, 3)
|
||||
if(prob(2))
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
adjustCloneLoss(damage_amount, forced = forced)
|
||||
if(STAMINA)
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount)))
|
||||
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount), FALSE, FALSE))
|
||||
update_damage_overlays()
|
||||
else
|
||||
adjustStaminaLoss(damage_amount, forced = forced)
|
||||
|
||||
@@ -101,12 +101,11 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
|
||||
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
|
||||
. = ..()
|
||||
dwarf_cycle_ticker()
|
||||
if(!owner || owner.stat == DEAD)
|
||||
dwarf_cycle_ticker()
|
||||
|
||||
//Handles the delayed tick cycle by just adding on increments per each on_life() tick
|
||||
/obj/item/organ/dwarfgland/proc/dwarf_cycle_ticker()
|
||||
if(owner.stat == DEAD)
|
||||
return //We make sure they are not dead, so they don't increment any tickers.
|
||||
dwarf_eth_ticker++
|
||||
dwarf_filth_ticker++
|
||||
|
||||
|
||||
@@ -91,4 +91,9 @@
|
||||
if((C.dna.features["spines"] != "None" ) && (C.dna.features["tail_lizard"] == "None")) //tbh, it's kinda ugly for them not to have a tail yet have floating spines
|
||||
C.dna.features["tail_lizard"] = "Smooth"
|
||||
C.update_body()
|
||||
if(C.dna.features["legs"] != "digitigrade")
|
||||
C.dna.features["legs"] = "digitigrade"
|
||||
for(var/obj/item/bodypart/leggie in C.bodyparts)
|
||||
if(leggie.body_zone == BODY_ZONE_L_LEG || leggie.body_zone == BODY_ZONE_R_LEG)
|
||||
leggie.update_limb(FALSE, C)
|
||||
return ..()
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
path_image_color = "#993299"
|
||||
weather_immunities = list("lava","ash")
|
||||
|
||||
var/clean_time = 50 //How long do we take to clean?
|
||||
var/broom = FALSE //Do we have an speed buff from a broom?
|
||||
var/adv_mop = FALSE //Do we have a cleaning buff from a better mop?
|
||||
|
||||
|
||||
var/blood = 1
|
||||
var/trash = 0
|
||||
var/pests = 0
|
||||
@@ -75,6 +80,26 @@
|
||||
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
|
||||
|
||||
if(istype(W, /obj/item/mop/advanced))
|
||||
if(bot_core.allowed(user) && open && adv_mop == TRUE)
|
||||
to_chat(user, "<span class='notice'>You replace \the [src] old mop with a new better one!</span>")
|
||||
adv_mop = TRUE
|
||||
clean_time = 20 //2.5 the speed!
|
||||
window_name = "Automatic Station Cleaner v2.1 BETA" //New!
|
||||
qdel(W)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\the [src] already has this mop!</span>")
|
||||
|
||||
if(istype(W, /obj/item/twohanded/broom))
|
||||
if(bot_core.allowed(user) && open && broom == TRUE)
|
||||
to_chat(user, "<span class='notice'>You add to \the [src] a broom speeding it up!</span>")
|
||||
broom = TRUE
|
||||
base_speed = 1 //2x faster!
|
||||
qdel(W)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\the [src] already has a broom!</span>")
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -221,7 +246,7 @@
|
||||
icon_state = "cleanbot-c"
|
||||
visible_message("<span class='notice'>[src] begins to clean up [A].</span>")
|
||||
mode = BOT_CLEANING
|
||||
spawn(50)
|
||||
spawn(clean_time)
|
||||
if(mode == BOT_CLEANING)
|
||||
if(A && isturf(A.loc))
|
||||
var/atom/movable/AM = A
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
select_name = "ion"
|
||||
fire_sound = 'sound/weapons/ionrifle.ogg'
|
||||
|
||||
/obj/item/ammo_casing/energy/ion/hos
|
||||
projectile_type = /obj/item/projectile/ion/weak
|
||||
e_cost = 300
|
||||
|
||||
/obj/item/ammo_casing/energy/declone
|
||||
projectile_type = /obj/item/projectile/energy/declone
|
||||
select_name = "declone"
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
fire_sound = 'sound/weapons/gunshot.ogg'
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/hos
|
||||
projectile_type = /obj/item/projectile/energy/electrode/security/hos
|
||||
e_cost = 200
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/old
|
||||
e_cost = 1000
|
||||
|
||||
@@ -52,13 +52,16 @@
|
||||
|
||||
/obj/item/gun/energy/e_gun/hos
|
||||
name = "\improper X-01 MultiPhase Energy Gun"
|
||||
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time."
|
||||
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding."
|
||||
icon_state = "hoslaser"
|
||||
force = 10
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos)
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos)
|
||||
ammo_x_offset = 4
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/gun/energy/e_gun/hos/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/item/gun/energy/e_gun/dragnet
|
||||
name = "\improper DRAGnet"
|
||||
desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology."
|
||||
|
||||
@@ -315,6 +315,8 @@
|
||||
objs += O
|
||||
var/obj/O = safepick(objs)
|
||||
if(O)
|
||||
if(length(O.buckled_mobs))
|
||||
return pick(O.buckled_mobs)
|
||||
return O
|
||||
//Nothing else is here that we can hit, hit the turf if we haven't.
|
||||
if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
icon_state = "ion"
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
nodamage = 1
|
||||
nodamage = TRUE
|
||||
flag = "energy"
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/ion
|
||||
var/emp_radius = 1
|
||||
@@ -14,4 +14,4 @@
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/obj/item/projectile/ion/weak
|
||||
emp_radius = 0
|
||||
emp_radius = 0
|
||||
@@ -246,6 +246,13 @@
|
||||
metabolization_rate = 5 * REAGENTS_METABOLISM
|
||||
overdose_threshold = 50
|
||||
|
||||
/datum/reagent/medicine/silver_sulfadiazine/reaction_obj(obj/O, reac_volume)
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
reac_volume = min((reac_volume / 10), G.amount)
|
||||
new/obj/item/stack/medical/ointment(get_turf(G), reac_volume)
|
||||
G.use(reac_volume)
|
||||
|
||||
/datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
|
||||
if(iscarbon(M) && M.stat != DEAD)
|
||||
if(method in list(INGEST, VAPOR, INJECT))
|
||||
@@ -321,6 +328,12 @@
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
|
||||
..()
|
||||
|
||||
/datum/reagent/medicine/styptic_powder/reaction_obj(obj/O, reac_volume)
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
reac_volume = min((reac_volume / 10), G.amount)
|
||||
new/obj/item/stack/medical/bruise_pack(get_turf(G), reac_volume)
|
||||
G.use(reac_volume)
|
||||
|
||||
/datum/reagent/medicine/styptic_powder/on_mob_life(mob/living/carbon/M)
|
||||
M.adjustBruteLoss(-2*REM, 0)
|
||||
|
||||
@@ -1045,6 +1045,14 @@
|
||||
// +20% success propability on each step, useful while operating in less-than-perfect conditions
|
||||
..()
|
||||
|
||||
/datum/reagent/space_cleaner/sterilizine/reaction_obj(obj/O, reac_volume)
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
reac_volume = min((reac_volume / 10), G.amount)
|
||||
new/obj/item/stack/medical/gauze/adv(get_turf(G), reac_volume)
|
||||
G.use(reac_volume)
|
||||
|
||||
|
||||
/datum/reagent/iron
|
||||
name = "Iron"
|
||||
description = "Pure iron is a metal."
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
var/inflamed
|
||||
|
||||
/obj/item/organ/appendix/on_life()
|
||||
..()
|
||||
if(!(organ_flags & ORGAN_FAILING))
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/mob/living/carbon/M = owner
|
||||
if(M)
|
||||
M.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person
|
||||
owner.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person
|
||||
|
||||
/obj/item/organ/appendix/update_icon_state()
|
||||
if(inflamed)
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
slot = ORGAN_SLOT_STOMACH_AID
|
||||
|
||||
/obj/item/organ/cyberimp/chest/nutriment/on_life()
|
||||
if(synthesizing)
|
||||
. = ..()
|
||||
if(!. || synthesizing)
|
||||
return
|
||||
|
||||
if(owner.nutrition <= hunger_threshold)
|
||||
@@ -59,23 +60,25 @@
|
||||
var/convalescence_time = 0
|
||||
|
||||
/obj/item/organ/cyberimp/chest/reviver/on_life()
|
||||
. = ..()
|
||||
if(reviving)
|
||||
var/do_heal = world.time < convalescence_time
|
||||
var/do_heal = . && world.time < convalescence_time
|
||||
if(revive_cost >= MAX_HEAL_COOLDOWN)
|
||||
do_heal = FALSE
|
||||
else if(owner.stat && owner.stat != DEAD)
|
||||
else if(owner?.stat && owner.stat != DEAD)
|
||||
do_heal = TRUE
|
||||
else if(!do_heal)
|
||||
convalescence_time = world.time + DEF_CONVALESCENCE_TIME
|
||||
if(do_heal)
|
||||
if(. && (do_heal || world.time < convalescence_time))
|
||||
addtimer(CALLBACK(src, .proc/heal), 3 SECONDS)
|
||||
else
|
||||
cooldown = revive_cost + world.time
|
||||
reviving = FALSE
|
||||
to_chat(owner, "<span class='notice'>Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].</span>")
|
||||
if(owner)
|
||||
to_chat(owner, "<span class='notice'>Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].</span>")
|
||||
return
|
||||
|
||||
if(cooldown > world.time || owner.stat == CONSCIOUS || owner.stat == DEAD || owner.suiciding)
|
||||
if(!. || cooldown > world.time || owner.stat == CONSCIOUS || owner.stat == DEAD || owner.suiciding)
|
||||
return
|
||||
|
||||
revive_cost = 0
|
||||
|
||||
@@ -102,8 +102,8 @@
|
||||
slot = ORGAN_SLOT_BRAIN_ANTISTUN
|
||||
|
||||
/obj/item/organ/cyberimp/brain/anti_stun/on_life()
|
||||
..()
|
||||
if(crit_fail || !(organ_flags & ORGAN_FAILING))
|
||||
. = ..()
|
||||
if(!. || crit_fail)
|
||||
return
|
||||
owner.adjustStaminaLoss(-3.5, FALSE) //Citadel edit, makes it more useful in Stamina based combat
|
||||
owner.HealAllImmobilityUpTo(STUN_SET_AMOUNT)
|
||||
|
||||
@@ -29,22 +29,17 @@
|
||||
var/damage_multiplier = 1
|
||||
|
||||
/obj/item/organ/ears/on_life()
|
||||
if(!iscarbon(owner))
|
||||
return
|
||||
..()
|
||||
var/mob/living/carbon/C = owner
|
||||
if((damage < maxHealth) && (organ_flags & ORGAN_FAILING)) //ear damage can be repaired from the failing condition
|
||||
organ_flags &= ~ORGAN_FAILING
|
||||
. = ..()
|
||||
// genetic deafness prevents the body from using the ears, even if healthy
|
||||
if(HAS_TRAIT(C, TRAIT_DEAF))
|
||||
if(owner && HAS_TRAIT(owner, TRAIT_DEAF))
|
||||
deaf = max(deaf, 1)
|
||||
else if(!(organ_flags & ORGAN_FAILING)) // if this organ is failing, do not clear deaf stacks.
|
||||
else if(.) // if this organ is failing, do not clear deaf stacks.
|
||||
deaf = max(deaf - 1, 0)
|
||||
if(prob(damage / 20) && (damage > low_threshold))
|
||||
adjustEarDamage(0, 4)
|
||||
SEND_SOUND(C, sound('sound/weapons/flash_ring.ogg'))
|
||||
to_chat(C, "<span class='warning'>The ringing in your ears grows louder, blocking out any external noises for a moment.</span>")
|
||||
else if((organ_flags & ORGAN_FAILING) && (deaf == 0))
|
||||
SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg'))
|
||||
to_chat(owner, "<span class='warning'>The ringing in your ears grows louder, blocking out any external noises for a moment.</span>")
|
||||
else if(!. && !deaf)
|
||||
deaf = 1 //stop being not deaf you deaf idiot
|
||||
|
||||
/obj/item/organ/ears/proc/restoreEars()
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#define BLURRY_VISION_ONE 1
|
||||
#define BLURRY_VISION_TWO 2
|
||||
#define BLIND_VISION_THREE 3
|
||||
|
||||
/obj/item/organ/eyes
|
||||
name = BODY_ZONE_PRECISE_EYES
|
||||
icon_state = "eyeballs"
|
||||
@@ -10,7 +14,7 @@
|
||||
decay_factor = STANDARD_ORGAN_DECAY
|
||||
maxHealth = 0.5 * STANDARD_ORGAN_THRESHOLD //half the normal health max since we go blind at 30, a permanent blindness at 50 therefore makes sense unless medicine is administered
|
||||
high_threshold = 0.3 * STANDARD_ORGAN_THRESHOLD //threshold at 30
|
||||
low_threshold = 0.15 * STANDARD_ORGAN_THRESHOLD //threshold at 15
|
||||
low_threshold = 0.2 * STANDARD_ORGAN_THRESHOLD //threshold at 15
|
||||
|
||||
low_threshold_passed = "<span class='info'>Distant objects become somewhat less tangible.</span>"
|
||||
high_threshold_passed = "<span class='info'>Everything starts to look a lot less clear.</span>"
|
||||
@@ -27,14 +31,17 @@
|
||||
var/flash_protect = 0
|
||||
var/see_invisible = SEE_INVISIBLE_LIVING
|
||||
var/lighting_alpha
|
||||
var/damaged = FALSE //damaged indicates that our eyes are undergoing some level of negative effect
|
||||
var/eye_damaged = FALSE //indicates that our eyes are undergoing some level of negative effect
|
||||
|
||||
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(damage == initial(damage))
|
||||
clear_eye_trauma()
|
||||
switch(eye_damaged)
|
||||
if(BLURRY_VISION_ONE, BLURRY_VISION_TWO)
|
||||
owner.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, eye_damaged)
|
||||
if(BLIND_VISION_THREE)
|
||||
owner.become_blind(EYE_DAMAGE)
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
old_eye_color = H.eye_color
|
||||
@@ -48,46 +55,49 @@
|
||||
owner.update_sight()
|
||||
|
||||
/obj/item/organ/eyes/Remove(special = FALSE)
|
||||
clear_eye_trauma()
|
||||
. = ..()
|
||||
var/mob/living/carbon/C = .
|
||||
if(!QDELETED(C))
|
||||
if(ishuman(C) && eye_color)
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.eye_color = old_eye_color
|
||||
if(!special)
|
||||
H.dna.species.handle_body(H)
|
||||
if(QDELETED(C))
|
||||
return
|
||||
switch(eye_damaged)
|
||||
if(BLURRY_VISION_ONE, BLURRY_VISION_TWO)
|
||||
C.clear_fullscreen("eye_damage")
|
||||
if(BLIND_VISION_THREE)
|
||||
C.cure_blind(EYE_DAMAGE)
|
||||
if(ishuman(C) && eye_color)
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.eye_color = old_eye_color
|
||||
if(!special)
|
||||
C.update_tint()
|
||||
C.update_sight()
|
||||
H.dna.species.handle_body(H)
|
||||
if(!special)
|
||||
C.update_tint()
|
||||
C.update_sight()
|
||||
|
||||
/obj/item/organ/eyes/on_life()
|
||||
..()
|
||||
var/mob/living/carbon/C = owner
|
||||
//since we can repair fully damaged eyes, check if healing has occurred
|
||||
if((organ_flags & ORGAN_FAILING) && (damage < maxHealth))
|
||||
organ_flags &= ~ORGAN_FAILING
|
||||
C.cure_blind(EYE_DAMAGE)
|
||||
//various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
|
||||
if(damage > 20)
|
||||
damaged = TRUE
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
C.become_blind(EYE_DAMAGE)
|
||||
else if(damage > 30)
|
||||
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
|
||||
|
||||
/obj/item/organ/eyes/applyOrganDamage(d, maximum = maxHealth)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/old_damaged = eye_damaged
|
||||
switch(damage)
|
||||
if(INFINITY to maxHealth)
|
||||
eye_damaged = BLIND_VISION_THREE
|
||||
if(maxHealth to high_threshold)
|
||||
eye_damaged = BLURRY_VISION_TWO
|
||||
if(high_threshold to low_threshold)
|
||||
eye_damaged = BLURRY_VISION_ONE
|
||||
else
|
||||
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
|
||||
//called once since we don't want to keep clearing the screen of eye damage for people who are below 20 damage
|
||||
else if(damaged)
|
||||
damaged = FALSE
|
||||
C.clear_fullscreen("eye_damage")
|
||||
return
|
||||
|
||||
/obj/item/organ/eyes/proc/clear_eye_trauma()
|
||||
var/mob/living/carbon/C = owner
|
||||
C.clear_fullscreen("eye_damage")
|
||||
C.cure_blind(EYE_DAMAGE)
|
||||
damaged = FALSE
|
||||
eye_damaged = FALSE
|
||||
if(eye_damaged == old_damaged || !owner)
|
||||
return
|
||||
if(old_damaged == BLIND_VISION_THREE)
|
||||
owner.cure_blind(EYE_DAMAGE)
|
||||
else if(eye_damaged == BLIND_VISION_THREE)
|
||||
owner.become_blind(EYE_DAMAGE)
|
||||
if(eye_damaged && eye_damaged != BLIND_VISION_THREE)
|
||||
owner.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, eye_damaged)
|
||||
else
|
||||
owner.clear_fullscreen("eye_damage")
|
||||
|
||||
/obj/item/organ/eyes/night_vision
|
||||
name = "shadow eyes"
|
||||
@@ -382,4 +392,8 @@
|
||||
|
||||
/obj/item/organ/eyes/ipc
|
||||
name = "ipc eyes"
|
||||
icon_state = "cybernetic_eyeballs"
|
||||
icon_state = "cybernetic_eyeballs"
|
||||
|
||||
#undef BLURRY_VISION_ONE
|
||||
#undef BLURRY_VISION_TWO
|
||||
#undef BLIND_VISION_THREE
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
|
||||
var/beating = 1
|
||||
var/no_pump = FALSE
|
||||
var/icon_base = "heart"
|
||||
attack_verb = list("beat", "thumped")
|
||||
var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which?
|
||||
@@ -66,27 +67,28 @@
|
||||
return S
|
||||
|
||||
/obj/item/organ/heart/on_life()
|
||||
..()
|
||||
. = ..()
|
||||
if(!owner || no_pump)
|
||||
return
|
||||
if(owner.client && beating)
|
||||
failed = FALSE
|
||||
var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE)
|
||||
var/sound/fastbeat = sound('sound/health/fastbeat.ogg', repeat = TRUE)
|
||||
var/mob/living/carbon/H = owner
|
||||
|
||||
if(H.health <= H.crit_threshold && beat != BEAT_SLOW)
|
||||
if(owner.health <= owner.crit_threshold && beat != BEAT_SLOW)
|
||||
beat = BEAT_SLOW
|
||||
H.playsound_local(get_turf(H), slowbeat,40,0, channel = CHANNEL_HEARTBEAT)
|
||||
owner.playsound_local(get_turf(owner), slowbeat,40,0, channel = CHANNEL_HEARTBEAT)
|
||||
to_chat(owner, "<span class = 'notice'>You feel your heart slow down...</span>")
|
||||
if(beat == BEAT_SLOW && H.health > H.crit_threshold)
|
||||
H.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
if(beat == BEAT_SLOW && owner.health > owner.crit_threshold)
|
||||
owner.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
beat = BEAT_NONE
|
||||
|
||||
if(H.jitteriness)
|
||||
if(H.health > HEALTH_THRESHOLD_FULLCRIT && (!beat || beat == BEAT_SLOW))
|
||||
H.playsound_local(get_turf(H),fastbeat,40,0, channel = CHANNEL_HEARTBEAT)
|
||||
if(owner.jitteriness)
|
||||
if(owner.health > HEALTH_THRESHOLD_FULLCRIT && (!beat || beat == BEAT_SLOW))
|
||||
owner.playsound_local(get_turf(owner),fastbeat,40,0, channel = CHANNEL_HEARTBEAT)
|
||||
beat = BEAT_FAST
|
||||
else if(beat == BEAT_FAST)
|
||||
H.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
owner.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
beat = BEAT_NONE
|
||||
|
||||
if(organ_flags & ORGAN_FAILING) //heart broke, stopped beating, death imminent
|
||||
@@ -107,6 +109,7 @@ obj/item/organ/heart/slime
|
||||
icon_state = "cursedheart-off"
|
||||
icon_base = "cursedheart"
|
||||
decay_factor = 0
|
||||
no_pump = TRUE
|
||||
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
|
||||
var/last_pump = 0
|
||||
var/add_colour = TRUE //So we're not constantly recreating colour datums
|
||||
@@ -128,6 +131,9 @@ obj/item/organ/heart/slime
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/heart/cursed/on_life()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
if(world.time > (last_pump + pump_delay))
|
||||
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
|
||||
var/mob/living/carbon/human/H = owner
|
||||
@@ -208,6 +214,8 @@ obj/item/organ/heart/slime
|
||||
|
||||
obj/item/organ/heart/cybernetic/upgraded/on_life()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(dose_available && owner.health <= owner.crit_threshold && !owner.reagents.has_reagent(rid))
|
||||
owner.reagents.add_reagent(rid, ramount)
|
||||
used_dose()
|
||||
@@ -233,7 +241,7 @@ obj/item/organ/heart/cybernetic/upgraded/on_life()
|
||||
|
||||
/obj/item/organ/heart/freedom/on_life()
|
||||
. = ..()
|
||||
if(owner.health < 5 && world.time > min_next_adrenaline)
|
||||
if(. && owner.health < 5 && world.time > min_next_adrenaline)
|
||||
min_next_adrenaline = world.time + rand(250, 600) //anywhere from 4.5 to 10 minutes
|
||||
to_chat(owner, "<span class='userdanger'>You feel yourself dying, but you refuse to give up!</span>")
|
||||
owner.heal_overall_damage(15, 15)
|
||||
|
||||
@@ -25,25 +25,24 @@
|
||||
var/cachedmoveCalc = 1
|
||||
|
||||
/obj/item/organ/liver/on_life()
|
||||
var/mob/living/carbon/C = owner
|
||||
. = ..()
|
||||
if(!.)//can't process reagents with a failing liver
|
||||
return
|
||||
|
||||
if(istype(C))
|
||||
if(!(organ_flags & ORGAN_FAILING))//can't process reagents with a failing liver
|
||||
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
|
||||
//handle liver toxin filtration
|
||||
for(var/datum/reagent/toxin/T in owner.reagents.reagent_list)
|
||||
var/thisamount = owner.reagents.get_reagent_amount(T.type)
|
||||
if (thisamount && thisamount <= toxTolerance)
|
||||
owner.reagents.remove_reagent(T.type, 1)
|
||||
else
|
||||
damage += (thisamount*toxLethality)
|
||||
|
||||
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
|
||||
//handle liver toxin filtration
|
||||
for(var/datum/reagent/toxin/T in C.reagents.reagent_list)
|
||||
var/thisamount = C.reagents.get_reagent_amount(T.type)
|
||||
if (thisamount && thisamount <= toxTolerance)
|
||||
C.reagents.remove_reagent(T.type, 1)
|
||||
else
|
||||
damage += (thisamount*toxLethality)
|
||||
//metabolize reagents
|
||||
owner.reagents.metabolize(owner, can_overdose=TRUE)
|
||||
|
||||
//metabolize reagents
|
||||
C.reagents.metabolize(C, can_overdose=TRUE)
|
||||
|
||||
if(damage > 10 && prob(damage/3))//the higher the damage the higher the probability
|
||||
to_chat(C, "<span class='warning'>You feel a dull pain in your abdomen.</span>")
|
||||
if(damage > 10 && prob(damage/3))//the higher the damage the higher the probability
|
||||
to_chat(owner, "<span class='warning'>You feel a dull pain in your abdomen.</span>")
|
||||
|
||||
/obj/item/organ/liver/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
|
||||
@@ -446,17 +446,17 @@
|
||||
if(prob(20))
|
||||
to_chat(H, "<span class='warning'>You feel [hot_message] in your [name]!</span>")
|
||||
|
||||
|
||||
/obj/item/organ/lungs/on_life()
|
||||
..()
|
||||
if((!failed) && ((organ_flags & ORGAN_FAILING)))
|
||||
if(owner.stat == CONSCIOUS)
|
||||
/obj/item/organ/lungs/applyOrganDamage(d, maximum = maxHealth)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!failed && organ_flags & ORGAN_FAILING)
|
||||
if(owner && owner.stat == CONSCIOUS)
|
||||
owner.visible_message("<span class='danger'>[owner] grabs [owner.p_their()] throat, struggling for breath!</span>", \
|
||||
"<span class='userdanger'>You suddenly feel like you can't breathe!</span>")
|
||||
failed = TRUE
|
||||
else if(!(organ_flags & ORGAN_FAILING))
|
||||
failed = FALSE
|
||||
return
|
||||
|
||||
/obj/item/organ/lungs/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
@@ -547,5 +547,6 @@
|
||||
color = "#68e83a"
|
||||
|
||||
/obj/item/organ/lungs/yamerol/on_life()
|
||||
..()
|
||||
damage += 2 //Yamerol lungs are temporary
|
||||
. = ..()
|
||||
if(.)
|
||||
applyOrganDamage(2) //Yamerol lungs are temporary
|
||||
|
||||
@@ -134,18 +134,19 @@
|
||||
organ_flags &= ~ORGAN_FROZEN
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
return
|
||||
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing or synthetic
|
||||
if(organ_flags & ORGAN_FAILING || !owner)
|
||||
return FALSE
|
||||
if(is_cold())
|
||||
return
|
||||
///Damage decrements by a percent of its maxhealth
|
||||
var/healing_amount = -(maxHealth * healing_factor)
|
||||
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
|
||||
healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
|
||||
if(healing_amount)
|
||||
applyOrganDamage(healing_amount) //to FERMI_TWEAK
|
||||
//Make it so each threshold is stuck.
|
||||
return FALSE
|
||||
if(damage)
|
||||
///Damage decrements by a percent of its maxhealth
|
||||
var/healing_amount = -(maxHealth * healing_factor)
|
||||
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's satiety
|
||||
healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
|
||||
if(healing_amount)
|
||||
applyOrganDamage(healing_amount) //to FERMI_TWEAK
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -205,9 +206,7 @@
|
||||
|
||||
///Adjusts an organ's damage by the amount "d", up to a maximum amount, which is by default max damage
|
||||
/obj/item/organ/proc/applyOrganDamage(var/d, var/maximum = maxHealth) //use for damaging effects
|
||||
if(!d) //Micro-optimization.
|
||||
return FALSE
|
||||
if(maximum < damage)
|
||||
if(!d || maximum < damage) //Micro-optimization.
|
||||
return FALSE
|
||||
damage = clamp(damage + d, 0, maximum)
|
||||
var/mess = check_damage_thresholds()
|
||||
|
||||
@@ -17,33 +17,24 @@
|
||||
low_threshold_cleared = "<span class='info'>The last bouts of pain in your stomach have died out.</span>"
|
||||
|
||||
/obj/item/organ/stomach/on_life()
|
||||
..()
|
||||
var/datum/reagent/consumable/nutriment/Nutri
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!(organ_flags & ORGAN_FAILING))
|
||||
if(.)
|
||||
H.dna.species.handle_digestion(H)
|
||||
handle_disgust(H)
|
||||
Nutri = locate(/datum/reagent/consumable/nutriment) in H.reagents.reagent_list
|
||||
|
||||
if(Nutri)
|
||||
if(prob((damage/40) * Nutri.volume * Nutri.volume))
|
||||
H.vomit(damage)
|
||||
to_chat(H, "<span class='warning'>Your stomach reels in pain as you're incapable of holding down all that food!</span>")
|
||||
|
||||
else if(Nutri && damage > high_threshold)
|
||||
if(prob((damage/10) * Nutri.volume * Nutri.volume))
|
||||
H.vomit(damage)
|
||||
to_chat(H, "<span class='warning'>Your stomach reels in pain as you're incapable of holding down all that food!</span>")
|
||||
|
||||
|
||||
else if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
Nutri = locate(/datum/reagent/consumable/nutriment) in C.reagents.reagent_list
|
||||
|
||||
if(damage < low_threshold)
|
||||
if(!damage)
|
||||
return
|
||||
|
||||
var/datum/reagent/consumable/nutriment/Nutri = locate(/datum/reagent/consumable/nutriment) in owner.reagents.reagent_list
|
||||
if(!Nutri)
|
||||
return
|
||||
var/prob_divisor = damage > high_threshold ? 10 : 40
|
||||
if(prob((damage/prob_divisor) * (Nutri.volume**2)))
|
||||
owner.vomit(damage)
|
||||
to_chat(owner, "<span class='warning'>Your stomach reels in pain as you're incapable of holding down all that food!</span>")
|
||||
|
||||
/obj/item/organ/stomach/proc/handle_disgust(mob/living/carbon/human/H)
|
||||
if(H.disgust)
|
||||
|
||||
@@ -58,7 +58,10 @@
|
||||
return FALSE
|
||||
if(tool)
|
||||
speed_mod = tool.toolspeed
|
||||
if(do_after(user, time * speed_mod, target = target))
|
||||
var/skill_mod = 1
|
||||
if(user?.mind?.skill_holder)
|
||||
skill_mod = SURGERY_SKILL_SPEEDUP_NUMERICAL_SCALE(user.mind.skill_holder.get_skill_value(/datum/skill/numerical/surgery))
|
||||
if(do_after(user, time * speed_mod * skill_mod, target = target))
|
||||
var/prob_chance = 100
|
||||
if(implement_type) //this means it isn't a require hand or any item step.
|
||||
prob_chance = implements[implement_type]
|
||||
@@ -66,6 +69,7 @@
|
||||
|
||||
if((prob(prob_chance) || (iscyborg(user) && !silicons_obey_prob)) && chem_check(target) && !try_to_fail)
|
||||
if(success(user, target, target_zone, tool, surgery))
|
||||
user?.mind?.skill_holder?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP)
|
||||
advance = TRUE
|
||||
else
|
||||
if(failure(user, target, target_zone, tool, surgery))
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/obj/item/clothing/head/helmet/blueshirt = 1,
|
||||
/obj/item/clothing/suit/armor/vest/blueshirt = 1,
|
||||
/obj/item/clothing/under/rank/security/officer/blueshirt = 1,
|
||||
/obj/item/clothing/gloves/tackler = 5,
|
||||
/obj/item/clothing/gloves/tackler = 5,
|
||||
/obj/item/ssword_kit = 1)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
Reference in New Issue
Block a user