Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit697
This commit is contained in:
@@ -171,7 +171,7 @@
|
||||
if(!..())
|
||||
return 0
|
||||
var/mob/M = target
|
||||
M.ghostize(1)
|
||||
M.ghostize(can_reenter_corpse = TRUE, voluntary = TRUE)
|
||||
|
||||
/datum/action/proc/OnUpdatedIcon()
|
||||
UpdateButtonIcon()
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
var/datum/ai_laws/lawtype
|
||||
var/list/law_weights = CONFIG_GET(keyed_list/law_weight)
|
||||
while(!lawtype && law_weights.len)
|
||||
var/possible_id = pickweightAllowZero(law_weights)
|
||||
var/possible_id = pickweight(law_weights, 0)
|
||||
lawtype = lawid_to_type(possible_id)
|
||||
if(!lawtype)
|
||||
law_weights -= possible_id
|
||||
|
||||
@@ -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
|
||||
|
||||
88
code/datums/components/identification.dm
Normal file
88
code/datums/components/identification.dm
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Identification components
|
||||
*/
|
||||
/datum/component/identification
|
||||
/// General flags for how we should work.
|
||||
var/identification_flags = NONE
|
||||
/// General flags for what we should do.
|
||||
var/identification_effect_flags = NONE
|
||||
/// General flags for how we can be identified.
|
||||
var/identification_method_flags = NONE
|
||||
/// If this is set, show this on examine to the examiner if they know how to use it.
|
||||
var/additional_examine_text = "<span class='notice'>You seem to know more about this item than others..</span>"
|
||||
/// Added to deconstructive analyzer say on success if set
|
||||
var/deconstructor_reveal_text = "item operation instructions"
|
||||
|
||||
/datum/component/identification/Initialize(id_flags, id_effect_flags, id_method_flags)
|
||||
if(!isobj(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
if(. & COMPONENT_INCOMPATIBLE)
|
||||
return
|
||||
identification_flags = id_flags
|
||||
identification_effect_flags = id_effect_flags
|
||||
identification_method_flags = id_method_flags
|
||||
|
||||
/datum/component/identification/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
|
||||
if(identification_effect_flags & ID_COMPONENT_EFFECT_NO_ACTIONS)
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
if(identification_method_flags & ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN, .proc/on_deconstructor_deepscan)
|
||||
|
||||
/datum/component/identification/UnregisterFromParent()
|
||||
var/list/unregister = list(COMSIG_PARENT_EXAMINE)
|
||||
if(identification_effect_flags & ID_COMPONENT_EFFECT_NO_ACTIONS)
|
||||
unregister += COMSIG_ITEM_EQUIPPED
|
||||
if(identification_method_flags & ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR)
|
||||
unregister += COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN
|
||||
UnregisterSignal(parent, unregister)
|
||||
|
||||
/datum/component/identification/proc/on_examine(datum/source, mob/user, list/returnlist)
|
||||
if(check_knowledge(user) != ID_COMPONENT_KNOWLEDGE_FULL)
|
||||
return
|
||||
if(!additional_examine_text)
|
||||
return
|
||||
returnlist += additional_examine_text
|
||||
|
||||
/datum/component/identification/vv_edit_var(var_name, var_value)
|
||||
// since i care SOOO much about memory optimization, we only register signals we need to
|
||||
// so when someone vv's us, we should probably make sure we have the ones we need to with an update.
|
||||
if((var_value == NAMEOF(src, identification_flags)) || (var_value == NAMEOF(src, identification_effect_flags)) || (var_value == NAMEOF(src, identification_method_flags)))
|
||||
UnregisterFromParent()
|
||||
. = ..()
|
||||
if((var_value == NAMEOF(src, identification_flags)) || (var_value == NAMEOF(src, identification_effect_flags)) || (var_value == NAMEOF(src, identification_method_flags)))
|
||||
RegisterWithParent()
|
||||
|
||||
/datum/component/identification/proc/on_equip(datum/source, mob/user)
|
||||
if(check_knowledge(user) == ID_COMPONENT_KNOWLEDGE_FULL)
|
||||
return
|
||||
if(identification_method_flags & ID_COMPONENT_EFFECT_NO_ACTIONS)
|
||||
return COMPONENT_NO_GRANT_ACTIONS
|
||||
|
||||
/datum/component/identification/proc/check_knowledge(mob/user)
|
||||
return ID_COMPONENT_KNOWLEDGE_NONE
|
||||
|
||||
/datum/component/identification/proc/on_identify(mob/user)
|
||||
if(identification_flags & ID_COMPONENT_DEL_ON_IDENTIFY)
|
||||
qdel(src)
|
||||
|
||||
/datum/component/identification/proc/on_deconstructor_deepscan(datum/source, obj/machinery/rnd/destructive_analyzer/analyzer, mob/user, list/information = list())
|
||||
if((identification_method_flags & ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR) && !(identification_flags & ID_COMPONENT_DECONSTRUCTOR_DEEPSCANNED))
|
||||
identification_flags |= ID_COMPONENT_DECONSTRUCTOR_DEEPSCANNED
|
||||
on_identify(user)
|
||||
if(deconstructor_reveal_text)
|
||||
information += deconstructor_reveal_text
|
||||
return COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION
|
||||
|
||||
/**
|
||||
* Identification component subtype - Syndicate
|
||||
*
|
||||
* Checks if the user is a traitor.
|
||||
*/
|
||||
/datum/component/identification/syndicate
|
||||
|
||||
/datum/component/identification/syndicate/check_knowledge(mob/user)
|
||||
. = ..()
|
||||
if(user?.mind?.has_antag_datum(/datum/antagonist/traitor))
|
||||
. = max(., ID_COMPONENT_KNOWLEDGE_FULL)
|
||||
@@ -175,27 +175,27 @@
|
||||
switch(sanity)
|
||||
if(-INFINITY to SANITY_CRAZY)
|
||||
setInsanityEffect(MAJOR_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=1.5) //Did we change something ? movetypes is runtiming, movetypes=(~FLYING))
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/insane)
|
||||
sanity_level = 6
|
||||
if(SANITY_CRAZY to SANITY_UNSTABLE)
|
||||
setInsanityEffect(MINOR_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=1)//, movetypes=(~FLYING))
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/crazy)
|
||||
sanity_level = 5
|
||||
if(SANITY_UNSTABLE to SANITY_DISTURBED)
|
||||
setInsanityEffect(0)
|
||||
master.add_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE, 100, override=TRUE, multiplicative_slowdown=0.5)//, movetypes=(~FLYING))
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/disturbed)
|
||||
sanity_level = 4
|
||||
if(SANITY_DISTURBED to SANITY_NEUTRAL)
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
sanity_level = 3
|
||||
if(SANITY_NEUTRAL+1 to SANITY_GREAT+1) //shitty hack but +1 to prevent it from responding to super small differences
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
sanity_level = 2
|
||||
if(SANITY_GREAT+1 to INFINITY)
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY, TRUE)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
sanity_level = 1
|
||||
//update_mood_icon()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
var/list/datum/nanite_program/programs = list()
|
||||
var/max_programs = NANITE_PROGRAM_LIMIT
|
||||
|
||||
var/list/datum/nanite_program/protocol/protocols = list() ///Separate list of protocol programs, to avoid looping through the whole programs list when cheking for conflicts
|
||||
var/list/datum/nanite_program/protocol/protocols = list() ///Separate list of protocol programs, to avoid looping through the whole programs list when checking for conflicts
|
||||
var/start_time = 0 ///Timestamp to when the nanites were first inserted in the host
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
|
||||
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
|
||||
|
||||
@@ -198,13 +198,14 @@
|
||||
|
||||
/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)
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = parent
|
||||
if(!length(H.buckled_mobs))
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/human_carry)
|
||||
if(!fireman_carrying)
|
||||
M.Daze(25)
|
||||
REMOVE_TRAIT(M, TRAIT_MOBILITY_NOUSE, src)
|
||||
@@ -213,7 +214,7 @@
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = parent
|
||||
if(length(H.buckled_mobs))
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = fireman_carrying? FIREMAN_CARRY_SLOWDOWN : PIGGYBACK_CARRY_SLOWDOWN)
|
||||
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/human_carry, TRUE, fireman_carrying? FIREMAN_CARRY_SLOWDOWN : PIGGYBACK_CARRY_SLOWDOWN)
|
||||
if(fireman_carrying)
|
||||
ADD_TRAIT(M, TRAIT_MOBILITY_NOUSE, src)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
parent_atom.opacity = 0
|
||||
if(isliving(parent_atom))
|
||||
var/mob/living/L = parent_atom
|
||||
L.add_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY, update=TRUE, priority=100, multiplicative_slowdown=4)
|
||||
L.add_movespeed_modifier(/datum/movespeed_modifier/shrink_ray)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.unequip_everything()
|
||||
@@ -35,7 +35,7 @@
|
||||
parent_atom.opacity = oldopac
|
||||
if(isliving(parent_atom))
|
||||
var/mob/living/L = parent_atom
|
||||
L.remove_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY)
|
||||
L.remove_movespeed_modifier(/datum/movespeed_modifier/shrink_ray)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.physiology.damage_resistance += 100
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
var/datum/component/storage/concrete/master //If not null, all actions act on master and this is just an access point.
|
||||
|
||||
var/list/can_hold //if this is set, only things in this typecache will fit.
|
||||
var/list/can_hold_extra //if this is set, it will also be able to hold these.
|
||||
var/list/cant_hold //if this is set, anything in this typecache will not be able to fit.
|
||||
|
||||
var/list/mob/is_using //lazy list of mobs looking at the contents of this storage.
|
||||
@@ -493,26 +494,25 @@
|
||||
if(M && !stop_messages)
|
||||
host.add_fingerprint(M)
|
||||
return FALSE
|
||||
if(length(can_hold))
|
||||
if(!is_type_in_typecache(I, can_hold))
|
||||
if(!length(can_hold_extra) || !is_type_in_typecache(I, can_hold_extra))
|
||||
if(length(can_hold) && !is_type_in_typecache(I, can_hold))
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(is_type_in_typecache(I, cant_hold)) //Check for specific items which this container can't hold.
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
// STORAGE LIMITS
|
||||
if(is_type_in_typecache(I, cant_hold)) //Check for specific items which this container can't hold.
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_W_CLASS && I.w_class > max_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too long for [host]!</span>")
|
||||
return FALSE
|
||||
// STORAGE LIMITS
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_ITEMS)
|
||||
if(real_location.contents.len >= max_items)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] has too many things in it, make some space!</span>")
|
||||
return FALSE //Storage item is full
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_W_CLASS)
|
||||
if(I.w_class > max_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too long for [host]!</span>")
|
||||
return FALSE
|
||||
if(storage_flags & STORAGE_LIMIT_COMBINED_W_CLASS)
|
||||
var/sum_w_class = I.w_class
|
||||
for(var/obj/item/_I in real_location)
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object")
|
||||
VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete")
|
||||
VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player")
|
||||
// VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits")
|
||||
VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element")
|
||||
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits")
|
||||
|
||||
//This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks!
|
||||
//href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables!
|
||||
@@ -37,8 +38,8 @@
|
||||
/datum/proc/vv_do_topic(list/href_list)
|
||||
if(!usr || !usr.client || !usr.client.holder || !check_rights(NONE))
|
||||
return FALSE //This is VV, not to be called by anything else.
|
||||
// if(href_list[VV_HK_MODIFY_TRAITS])
|
||||
// usr.client.holder.modify_traits(src)
|
||||
if(href_list[VV_HK_MODIFY_TRAITS])
|
||||
usr.client.holder.modify_traits(src)
|
||||
return TRUE
|
||||
|
||||
/datum/proc/vv_get_header()
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
unique_enzymes = generate_unique_enzymes()
|
||||
uni_identity = generate_uni_identity()
|
||||
generate_dna_blocks()
|
||||
features = random_features(species?.id)
|
||||
features = random_features(species?.id, holder?.gender)
|
||||
|
||||
|
||||
/datum/dna/stored //subtype used by brain mob's stored_dna
|
||||
@@ -662,6 +662,6 @@
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
if(features["body_size"] < danger)
|
||||
var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE, TRUE, 100, NONE, TRUE, slowdown, ALL, FLOATING|CRAWLING)
|
||||
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
|
||||
else if(old_size < danger)
|
||||
holder.remove_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE)
|
||||
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride)
|
||||
|
||||
@@ -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
code/datums/skills/_check_skills.dm
Normal file
16
code/datums/skills/_check_skills.dm
Normal 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
code/datums/skills/_skill.dm
Normal file
95
code/datums/skills/_skill.dm
Normal 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
code/datums/skills/_skill_holder.dm
Normal file
78
code/datums/skills/_skill_holder.dm
Normal 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
code/datums/skills/medical.dm
Normal file
3
code/datums/skills/medical.dm
Normal file
@@ -0,0 +1,3 @@
|
||||
/datum/skill/numerical/surgery
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at doing surgery."
|
||||
@@ -120,12 +120,12 @@
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.add_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]", TRUE, priority = 64, override = TRUE, multiplicative_slowdown = 5, blacklisted_movetypes = FALSE? NONE : CRAWLING)
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
|
||||
|
||||
/datum/status_effect/mesmerize/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.remove_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]")
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
|
||||
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
if(isnum(set_duration))
|
||||
@@ -141,9 +141,7 @@
|
||||
/datum/status_effect/electrode
|
||||
id = "tased"
|
||||
alert_type = null
|
||||
var/slowdown = 1.5
|
||||
var/slowdown_priority = 50 //to make sure the stronger effect overrides
|
||||
var/affect_crawl = FALSE
|
||||
var/movespeed_mod = /datum/movespeed_modifier/status_effect/tased
|
||||
var/nextmove_modifier = 1
|
||||
var/stamdmg_per_ds = 0 //a 20 duration would do 20 stamdmg, disablers do 24 or something
|
||||
var/last_tick = 0 //fastprocess processing speed is a goddamn sham, don't trust it.
|
||||
@@ -155,12 +153,12 @@
|
||||
last_tick = world.time
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
C.add_movespeed_modifier("[MOVESPEED_ID_TASED_STATUS]_[id]", TRUE, priority = slowdown_priority, override = TRUE, multiplicative_slowdown = slowdown, blacklisted_movetypes = affect_crawl? NONE : CRAWLING)
|
||||
C.add_movespeed_modifier(movespeed_mod)
|
||||
|
||||
/datum/status_effect/electrode/on_remove()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
C.remove_movespeed_modifier("[MOVESPEED_ID_TASED_STATUS]_[id]")
|
||||
C.remove_movespeed_modifier(movespeed_mod)
|
||||
. = ..()
|
||||
|
||||
/datum/status_effect/electrode/tick()
|
||||
@@ -178,8 +176,7 @@
|
||||
|
||||
/datum/status_effect/electrode/no_combat_mode
|
||||
id = "tased_strong"
|
||||
slowdown = 8
|
||||
slowdown_priority = 100
|
||||
movespeed_mod = /datum/movespeed_modifier/status_effect/tased/no_combat_mode
|
||||
nextmove_modifier = 2
|
||||
blocks_combatmode = TRUE
|
||||
stamdmg_per_ds = 1
|
||||
@@ -650,11 +647,11 @@
|
||||
if(isnum(set_duration))
|
||||
duration = set_duration
|
||||
. = ..()
|
||||
owner.add_movespeed_modifier(MOVESPEED_ID_ELECTROSTAFF, multiplicative_slowdown = 1, movetypes = GROUND)
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/electrostaff)
|
||||
|
||||
/datum/status_effect/electrostaff/on_remove()
|
||||
. = ..()
|
||||
owner.remove_movespeed_modifier(MOVESPEED_ID_ELECTROSTAFF)
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/electrostaff)
|
||||
|
||||
//GOLEM GANG
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
.["real_mode"] = SSticker.mode.name
|
||||
// Key-authed callers may know the truth behind the "secret"
|
||||
|
||||
.["security_level"] = get_security_level()
|
||||
.["security_level"] = NUM2SECLEVEL(GLOB.security_level)
|
||||
.["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0
|
||||
// Amount of world's ticks in seconds, useful for calculating round duration
|
||||
|
||||
|
||||
Reference in New Issue
Block a user