Merge branch 'master' into 91-files-changed-fml

This commit is contained in:
Detective-Google
2020-04-30 18:42:38 -05:00
committed by GitHub
26 changed files with 1623 additions and 1073 deletions
+28
View File
@@ -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)
+3
View File
@@ -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)
+4
View File
@@ -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
+16
View File
@@ -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()
+95
View File
@@ -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
+78
View File
@@ -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("")
+3
View File
@@ -0,0 +1,3 @@
/datum/skill/numerical/surgery
name = "Surgery"
desc = "How proficient you are at doing surgery."
@@ -77,6 +77,7 @@
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/storage/box/emptysandbags(src)
new /obj/item/cartridge/engineering(src)
/obj/structure/closet/secure_closet/atmospherics
name = "\proper atmospheric technician's locker"
@@ -97,6 +98,7 @@
new /obj/item/clothing/head/hardhat/atmos(src)
new /obj/item/clothing/glasses/meson/engine/tray(src)
new /obj/item/extinguisher/advanced(src)
new /obj/item/cartridge/atmos(src)
/*
* Empty lockers
+16 -1
View File
@@ -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"
+3
View File
@@ -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
+3
View File
@@ -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
@@ -392,6 +392,8 @@
character.update_parallax_teleport()
job.standard_assign_skills(character.mind)
SSticker.minds += character.mind
var/mob/living/carbon/human/humanc
@@ -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)
@@ -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
+2
View File
@@ -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))
+5 -1
View File
@@ -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))