Macros, generic skill implementations.

This commit is contained in:
Ghommie
2020-05-05 04:42:34 +02:00
parent 87389243e6
commit 643ef48f0e
64 changed files with 358 additions and 178 deletions
@@ -1,4 +1,3 @@
#define GET_SKILL_DATUM(path) GLOB.skill_datums[path]
/// true/false
#define SKILL_PROGRESSION_BINARY 1
@@ -6,6 +5,8 @@
#define SKILL_PROGRESSION_NUMERICAL 2
/// Enum
#define SKILL_PROGRESSION_ENUM 3
/// Levels
#define SKILL_PROGRESSION_LEVEL 4
/// Max value of skill for numerical skills
@@ -13,7 +14,35 @@
/// Min value of skill for numerical skills
#define SKILL_NUMERICAL_MIN 0
// Values for experience skills
// 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
#define STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO 1.2
// Standard values for skill gain (this is multiplied by affinity)
#define DEF_SKILL_GAIN 1
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
///Items skill_flags and other defines
#define SKILL_USE_TOOL (1<<0)
#define SKILL_TRAINING_TOOL (1<<1)
#define SKILL_ATTACK_MOB (1<<2)
#define SKILL_TRAIN_ATTACK_MOB (1<<3)
#define SKILL_ATTACK_OBJ (1<<4)
#define SKILL_TRAIN_ATTACK_OBJ (1<<5)
///competency_threshold index defines
#define THRESHOLD_COMPETENT 1
#define THRESHOLD_EXPERT 2
#define THRESHOLD_MASTER 3
/// Level/Experience skills defines.
#define STD_XP_LVL_UP 100
#define STD_XP_LVL_MULTI 2
#define STD_MAX_LVL 4
@@ -24,27 +53,18 @@
#define DORF_XP_LVL_MULTI 100
#define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5
//How experience levels are calculated.
#define XP_LEVEL(std, multi, lvl) (std * (multi**lvl))
#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5)))
//level up methods defines
#define STANDARD_LEVEL_UP "standard_level_up"
#define DWARFY_LEVEL_UP "dwarfy_level_up"
// Standard values for job starting skills
//job skill level defines
#define JOB_SKILL_UNTRAINED 0
#define JOB_SKILL_BASIC 1
#define JOB_SKILL_TRAINED 2
#define JOB_SKILL_EXPERT 3
#define JOB_SKILL_MASTER 4
#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)
//other skill level defines, not an exhaustive catalogue, only contains be most relevant ones.
#define DORF_SKILL_COMPETENT 3
#define DORF_SKILL_EXPERT 8
#define DORF_SKILL_MASTER 12
+44
View File
@@ -0,0 +1,44 @@
/**
*Generic delay calculation macro for various delayed actions.
*The skill to check must be an instance, not a path or list.
*/
#define SKILL_MODIFIER(to_check, holder, target, threshold) \
var/___value;\
switch(to_check.progression_type){\
if(SKILL_PROGRESSION_LEVEL){\
___value = LAZYACCESS(holder.skill_levels, to_check.type)\
} else {\
___value = LAZYACCESS(holder.skills, to_check.type)\
}\
}\
target /= (1+(___value-to_check.competency_thresholds[threshold])*to_check.competency_mults[threshold])
/// This is the one that accepts typepaths and lists.
#define LIST_SKILL_MODIFIER(to_check, holder, target, threshold) \
if(!islist(to_check)){\
SKILL_MODIFIER(GLOB.skill_datums[to_check], holder, target, threshold)\
} else {\
var/___sum = 0;\
var/list/___L = to_check;\
for(var/_S in ___L){\
var/___value;\
var/datum/skill/___S = GLOB.skill_datums[_S];\
switch(___S.progression_type){\
if(SKILL_PROGRESSION_LEVEL){\
___value = LAZYACCESS(holder.skill_levels, ___S.type)\
} else {\
___value = LAZYACCESS(holder.skills, ___S.type)\
}\
}\
___sum += (1+(___value - ___S.competency_thresholds[threshold])*___S.competency_mults[threshold])\
}\
target /= (___sum/length(___L))\
}
//How experience levels are calculated.
#define XP_LEVEL(std, multi, lvl) (std*((multi**lvl)/(multi-1))-std/(multi-1)) //don't use 1 as multi, you'll get division by zero errors
#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5)))
//More experience value getter macros
#define GET_STANDARD_LVL(lvl) XP_LEVEL(STD_XP_LVL_UP, STD_XP_LVL_MULTI, lvl)
#define GET_DORF_LVL(lvl) DORF_XP_LEVEL(DORF_XP_LVL_UP, DORF_XP_LVL_MULTI, lvl)
+41 -15
View File
@@ -111,26 +111,30 @@
return
/obj/attacked_by(obj/item/I, mob/living/user)
if(I.force)
var/totitemdamage = I.force
if(I.used_skills && user.mind)
if(I.skill_flags & SKILL_ATTACK_OBJ)
LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty)
if(I.skill_flags & SKILL_TRAIN_ATTACK_OBJ)
if(!islist(I.used_skills))
user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain)
else
for(var/skill in used_skills)
user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain)
if(totitemdamage)
visible_message("<span class='danger'>[user] has hit [src] with [I]!</span>", null, null, COMBAT_MESSAGE_RANGE)
//only witnesses close by and the victim see a hit message.
log_combat(user, src, "attacked", I)
take_damage(I.force, I.damtype, "melee", 1)
take_damage(totitemdamage, I.damtype, "melee", 1)
/mob/living/attacked_by(obj/item/I, mob/living/user)
//CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
totitemdamage *= 0.5
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
totitemdamage *= 0.5
//CIT CHANGES END HERE
var/totitemdamage = calculate_item_force(I, user, TRUE)
if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS)
return FALSE
send_item_attack_message(I, user)
I.do_stagger_action(src, user)
I.do_stagger_action(src, user, totitemdamage)
if(I.force)
apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage
apply_damage(totitemdamage, I.damtype)
if(I.damtype == BRUTE)
if(prob(33))
I.add_mob_blood(src)
@@ -146,6 +150,28 @@
else
return ..()
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE)
. = I.force
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
. *= 0.5
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
. *= 0.5
if(!pre_attack || !user.mind || !I.used_skills)
return
if(. && I.skill_flags & SKILL_ATTACK_MOB)
LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., I.skill_difficulty)
if(I.skill_flags & SKILL_TRAIN_ATTACK_MOB)
if(!islist(I.used_skills))
user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain)
else
for(var/skill in used_skills)
user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain)
/mob/living/carbon/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE)
. = ..()
if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
. *= 1.5
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
@@ -183,18 +209,18 @@
return total_mass || w_class * 1.25
/// How long this staggers for. 0 and negatives supported.
/obj/item/proc/melee_stagger_duration()
/obj/item/proc/melee_stagger_duration(force_override)
if(!isnull(stagger_force))
return stagger_force
/// totally not an untested, arbitrary equation.
return clamp((1.5 + (w_class/7.5)) * (force / 2), 0, 10 SECONDS)
return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS)
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user)
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override)
if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER))
return FALSE
if(target.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
target.do_staggered_animation()
var/duration = melee_stagger_duration()
var/duration = melee_stagger_duration(force_override)
if(!duration) //0
return FALSE
else if(duration > 0)
+2 -1
View File
@@ -67,7 +67,7 @@
var/datum/skill_holder/skill_holder
/datum/mind/New(var/key)
skill_holder = new
skill_holder = new(src)
src.key = key
soulOwner = src
martial_art = default_martial_art
@@ -80,6 +80,7 @@
if(antag_datum.delete_on_mind_deletion)
qdel(i)
antag_datums = null
QDEL_NULL(skill_holder)
return ..()
/datum/mind/proc/get_language_holder()
+46 -23
View File
@@ -1,4 +1,4 @@
GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/proc/init_skill_datums()
. = list()
@@ -10,12 +10,12 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
.[S.type] = S
/proc/sanitize_skill_value(path, value)
var/datum/skill/S = GET_SKILL_DATUM(path)
var/datum/skill/S = GLOB.skill_datums[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)
var/datum/skill/S = GLOB.skill_datums[path]
// don't check, if we runtime let it happen.
return S.is_value_greater(existing, new_value)
@@ -33,6 +33,10 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
var/progression_type
/// Abstract type
var/abstract_type = /datum/skill
/// skill threshold used in generic skill modifiers calculations.
var/list/competency_thresholds = list(0, 0, 0)
/// Multiplier of the difference of the holder skill value and the selected threshold.
var/list/competency_mults = list(0, 0, 0)
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -44,7 +48,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
* Sets the new value of this skill in the holder skills list.
* As well as possible feedback messages or secondary effects on value change, that's on you.
*/
/datum/skill/proc/set_skill(datum/skill_holder/H, value, mob/owner)
/datum/skill/proc/set_skill_value(datum/skill_holder/H, value, mob/owner)
H.skills[type] = value
/**
@@ -67,6 +71,8 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
/datum/skill/binary
abstract_type = /datum/skill/binary
progression_type = SKILL_PROGRESSION_BINARY
competency_thresholds = list(FALSE, TRUE, TRUE)
competency_mults = list(0.5, 0.5, 0.5)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
@@ -103,22 +109,23 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
/**
* Classing r p g styled skills, tiered by lvl, and current/nextlvl experience.
*/
/datum/skill/experience
abstract_type = /datum/skill/experience
/datum/skill/level
abstract_type = /datum/skill/level
progression_type = SKILL_PROGRESSION_LEVEL
var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100
var/xp_lvl_multiplier = STD_XP_LVL_UP //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.)
var/max_lvl = STD_MAX_LVL
var/max_levels = STD_MAX_LVL
var/level_up_method = STANDARD_LEVEL_UP //how levels are calculated.
var/list/levels = list() //level thresholds, if associative, these will be preceded by tiers such as "novice" or "trained"
var/associative = FALSE //See above.
var/unskilled_tier = "Unskilled" //Only relevant for associative experience levels
//Builds the levels list.
/datum/skill/experience/New()
/datum/skill/level/New()
. = ..()
var/max_assoc = ""
var/max_assoc_start = 1
for(var/lvl in 1 to max_lvl)
for(var/lvl in 1 to max_levels)
var/value
switch(level_up_method)
if(STANDARD_LEVEL_UP)
@@ -143,41 +150,57 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
levels["[max_assoc] +[max_assoc_start++]"] = value
levels[key] = value
/datum/skill/level/sanitize_value(new_value)
return max(new_value, 0)
/datum/skill/experience/sanitize_value(new_value)
return round(max(new_value, 0))
/datum/skill/experience/set_skill(datum/skill_holder/H, value, mob/owner)
var/old_value = H.skills[type]
/datum/skill/level/set_skill_value(datum/skill_holder/H, value, datum/mind/M, silent = FALSE)
H.skills[type] = value
if(value > old_value)
var/new_level
for(var/k in levels)
if(value < (associative ? levels[k] : k))
break
new_level++
var/old_level = LAZYACCESS(H.skill_levels, type)
LAZYSET(H.skill_levels, type, new_level)
. = new_level - old_level
if(silent || !(M?.current))
return
if(. > 0)
to_chat(M.current, "<span class='nicegreen'>I feel like I've become more proficient at [name]!</span>")
else if(. < 0)
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
/datum/skill/experience/standard_render_value(value)
/datum/skill/level/standard_render_value(value)
var/current_lvl = associative ? unskilled_tier : 0
var/current_lvl_xp_sum = 0
var/next_lvl_xp_sum
for(var/lvl in 1 to max_lvl)
for(var/lvl in 1 to max_levels)
next_lvl_xp_sum = associative ? levels[levels[lvl]] : levels[lvl]
if(value < next_lvl_xp_sum)
break
current_lvl_xp_sum = next_lvl_xp_sum
current_lvl = associative ? levels[lvl] : current_lvl+1
current_lvl = associative ? levels[lvl] : lvl+1
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp_sum])[value > next_lvl_xp_sum ? " \[MAX!\]" : ""]"
/datum/skill/experience/job
levels = ("Basic", "Trained", "Experienced", "Master")
/datum/skill/level/job
levels = list("Basic", "Trained", "Experienced", "Master")
competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
competency_mults = list(0.15, 0.1, 0.1)
associative = TRUE
//quite the reference, no?
/datum/skill/experience/dwarfy
abstract_type = /datum/skill/experience/dwarfy
/datum/skill/level/dwarfy
abstract_type = /datum/skill/level/dwarfy
standard_xp_lvl_up = DORF_XP_LVL_UP
xp_lvl_multiplier = DORF_XP_LVL_MULTI
max_lvl = DORF_MAX_LVL
max_levels = DORF_MAX_LVL
level_up_method = DWARFY_LEVEL_UP
levels = list("Novice", "Adequate", "Competent", "Skilled",
"Proficient", "Talented", "Adept", "Expert",
"Professional", "Accomplished", "Great", "Master",
"High Master", "Grand Master", "Legendary")
competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER)
competency_mults = list(0.15, 0.1, 0.08)
associative = TRUE
unskilled_tier = "Dabbling"
+30 -7
View File
@@ -2,10 +2,18 @@
* Skill holder datums
*/
/datum/skill_holder
var/datum/mind/owner
/// 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
/// Let's say we want to get a specific skill "level" without looping through a proc everytime.
/// Only supported by skills with tiers or levels.
var/list/skill_levels
/datum/skill_holder/New(datum/mind/M)
. = ..()
owner = M
/**
* Grabs the value of a skill.
@@ -17,6 +25,16 @@
return null
return skills[skill]
/**
* Grabs the level of a skill. Only supported by skills with tiers or levels.
*/
/datum/skill_holder/proc/get_skill_level(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(!skill_levels)
return 0
return skill_levels[skill]
/**
* Grabs our affinity for a skill. !!This is a multiplier!!
*/
@@ -33,37 +51,42 @@
/**
* Sets the value of a skill.
*/
/datum/skill_holder/proc/set_skill_value(skill, value, owner)
/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE)
if(!ispath(skill, /datum/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.
var/datum/skill/S = GET_SKILL_DATUM(path)
var/datum/skill/S = GLOB.skill_datums[skill]
value = S.sanitize_value(value)
if(!isnull(value))
LAZYINITLIST(skills)
S.set_skill(src, value, owner)
S.set_skill_value(src, value, owner, silent)
return TRUE
return FALSE
/**
* Boosts a skill to a value if not aobve
*/
/datum/skill_holder/proc/boost_skill_value_to(skill, value, mob/owner)
/datum/skill_holder/proc/boost_skill_value_to(skill, value, silent = FALSE)
var/current = get_skill_value(skill)
if(!is_skill_value_greater(skill, current, value))
return FALSE
set_skill_value(skill, value, owner)
set_skill_value(skill, value, silent)
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, mob/owner)
/datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
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), owner)
var/target_value = current + (value * affinity)
if(maximum)
target_value = max(target_value, maximum)
if(target_value == maximum) //no more experience to gain, early return.
return
boost_skill_value_to(skill, target_value, silent)
/**
* Generates a HTML readout of our skills.
+2 -1
View File
@@ -1,3 +1,4 @@
/datum/skill/experience/job/wiring
/datum/skill/level/job/wiring
name = "Wiring"
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
+1
View File
@@ -1,3 +1,4 @@
/datum/skill/numerical/surgery
name = "Surgery"
desc = "How proficient you are at doing surgery."
competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
+31 -6
View File
@@ -33,6 +33,9 @@
var/list/assemblies = list() // List of attached assemblies.
var/randomize = 0 // If every instance of these wires should be random.
// Prevents wires from showing up in station blueprints
var/req_knowledge = INFINITY //wiring skill level on which the functions are revealed.
var/req_skill = JOB_SKILL_BASIC //used in user's cutting/pulsing/mending speed calculations.
var/list/current_users //list of untrained people currently interacting with this set of wires.
/datum/wires/New(atom/holder)
..()
@@ -130,8 +133,20 @@
cut_wires += wire
on_cut(wire, mend = FALSE)
/datum/wires/proc/cut_color(color)
/datum/wires/proc/cut_color(color, mob/living/user)
LAZYINITLIST(current_users)
if(current_users[user])
return FALSE
if(req_skill && user?.mind)
var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring)
if(level_diff > 0)
to_chat(user, "<span class='notice'>You begin cutting [holder]'s [color] wire...</span>")
if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user))
return FALSE
user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff)
to_chat(user, "<span class='notice'>You cut [holder]'s [color] wire.</span>")
cut(get_wire(color))
return TRUE
/datum/wires/proc/cut_random()
cut(wires[rand(1, wires.len)])
@@ -146,7 +161,19 @@
on_pulse(wire, user)
/datum/wires/proc/pulse_color(color, mob/living/user)
LAZYINITLIST(current_users)
if(current_users[user])
return FALSE
if(req_skill && user?.mind)
var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring)
if(level_diff > 0)
to_chat(user, "<span class='notice'>You begin pulsing [holder]'s [color] wire...</span>")
if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user))
return FALSE
user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff)
to_chat(user, "<span class='notice'>You pulse [holder]'s [color] wire.</span>")
pulse(get_wire(color), user)
return TRUE
/datum/wires/proc/pulse_assembly(obj/item/assembly/S)
for(var/color in assemblies)
@@ -224,7 +251,7 @@
var/reveal_wires = FALSE
// Admin ghost can see a purpose of each wire.
if(IsAdminGhost(user))
if(IsAdminGhost(user) || user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) >= req_knowledge)
reveal_wires = TRUE
// Same for anyone with an abductor multitool.
@@ -259,18 +286,16 @@
if("cut")
I = L.is_holding_tool_quality(TOOL_WIRECUTTER)
if(I || IsAdminGhost(usr))
if(I && holder)
if(cut_color(target_wire) && I && holder)
I.play_tool_sound(holder, 20)
cut_color(target_wire)
. = TRUE
else
to_chat(L, "<span class='warning'>You need wirecutters!</span>")
if("pulse")
I = L.is_holding_tool_quality(TOOL_MULTITOOL)
if(I || IsAdminGhost(usr))
if(I && holder)
if(pulse_color(target_wire, L) && I && holder)
I.play_tool_sound(holder, 20)
pulse_color(target_wire, L)
. = TRUE
else
to_chat(L, "<span class='warning'>You need a multitool!</span>")
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/airalarm
holder_type = /obj/machinery/airalarm
proper_name = "Air Alarm"
req_knowledge = JOB_SKILL_MASTER
/datum/wires/airalarm/New(atom/holder)
wires = list(
+3 -2
View File
@@ -52,10 +52,11 @@
/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
if(!A.panel_open)
return FALSE
if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100))
return FALSE
if(A.panel_open)
return TRUE
return TRUE
/datum/wires/airlock/get_status()
var/obj/machinery/door/airlock/A = holder
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/apc
holder_type = /obj/machinery/power/apc
proper_name = "APC"
req_knowledge = JOB_SKILL_MASTER
/datum/wires/apc/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/autolathe
holder_type = /obj/machinery/autolathe
proper_name = "Autolathe"
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/autolathe/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/emitter
holder_type = /obj/machinery/power/emitter
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/emitter/New(atom/holder)
wires = list(WIRE_ZAP,WIRE_HACK)
+2
View File
@@ -15,6 +15,7 @@
/datum/wires/explosive/c4
holder_type = /obj/item/grenade/plastic/c4
randomize = TRUE //Same behaviour since no wire actually disarms it
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/explosive/c4/interactable(mob/user)
var/obj/item/grenade/plastic/c4/P = holder
@@ -29,6 +30,7 @@
/datum/wires/explosive/pizza
holder_type = /obj/item/pizzabox
randomize = TRUE
req_skill = JOB_SKILL_MASTER
/datum/wires/explosive/pizza/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/microwave
holder_type = /obj/machinery/microwave
proper_name = "Microwave"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/microwave/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/mulebot
holder_type = /mob/living/simple_animal/bot/mulebot
randomize = TRUE
req_knowledge = JOB_SKILL_MASTER
/datum/wires/mulebot/New(atom/holder)
wires = list(
@@ -1,6 +1,8 @@
/datum/wires/particle_accelerator/control_box
holder_type = /obj/machinery/particle_accelerator/control_box
proper_name = "Particle Accelerator"
req_knowledge = JOB_SKILL_EXPERT
req_skill = JOB_SKILL_TRAINED
/datum/wires/particle_accelerator/control_box/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/rnd
holder_type = /obj/machinery/rnd
randomize = TRUE
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/rnd/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/radio
holder_type = /obj/item/radio
proper_name = "Radio"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/radio/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/robot
holder_type = /mob/living/silicon/robot
randomize = TRUE
req_knowledge = JOB_SKILL_MASTER
req_skill = JOB_SKILL_TRAINED
/datum/wires/robot/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/suit_storage_unit
holder_type = /obj/machinery/suit_storage_unit
proper_name = "Suit Storage Unit"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/suit_storage_unit/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/syndicatebomb
holder_type = /obj/machinery/syndicatebomb
randomize = TRUE
req_skill = JOB_SKILL_EXPERT //good luck, wannabe hero.
/datum/wires/syndicatebomb/New(atom/holder)
wires = list(
+1
View File
@@ -2,6 +2,7 @@
/datum/wires/tesla_coil
randomize = 1 //Only one wire don't need blueprints
holder_type = /obj/machinery/power/tesla_coil
req_knowledge = JOB_SKILL_TRAINED
/datum/wires/tesla_coil/New(atom/holder)
wires = list(WIRE_ZAP)
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/vending
holder_type = /obj/machinery/vending
proper_name = "Vending Unit"
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/vending/New(atom/holder)
wires = list(
@@ -48,8 +48,7 @@
if(2)
// State 2
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.use(2))
if(W.use_tool(src, user, 0, 2))
to_chat(user, "<span class='notice'>You add wires to the assembly.</span>")
state = 3
else
@@ -83,7 +83,6 @@
if(istype(P, /obj/item/stack/cable_coil))
if(!P.tool_start_check(user, amount=5))
return
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
if(P.use_tool(src, user, 20, volume=50, amount=5))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
+1 -2
View File
@@ -400,12 +400,11 @@
"<span class='notice'>You begin adding wires to [src]...</span>")
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
if(do_after(user, 60, target = src))
if(constructionStep != CONSTRUCTION_GUTTED || B.get_amount() < 5 || !B)
if(constructionStep != CONSTRUCTION_GUTTED || !B.use_tool(src, user, 0, 5))
return
user.visible_message("<span class='notice'>[user] adds wires to [src].</span>", \
"<span class='notice'>You wire [src].</span>")
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
B.use(5)
constructionStep = CONSTRUCTION_WIRES_EXPOSED
update_icon()
return
+1 -3
View File
@@ -205,11 +205,9 @@
return
if(1)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = W
if(coil.get_amount() < 5)
if(!W.use_tool(src, user, 0, 5))
to_chat(user, "<span class='warning'>You need more cable for this!</span>")
else
coil.use(5)
buildstage = 2
to_chat(user, "<span class='notice'>You wire \the [src].</span>")
update_icon()
+1 -4
View File
@@ -160,10 +160,7 @@
to_chat(user, "<span class='warning'>You need one length of cable to repair [src]!</span>")
return
to_chat(user, "<span class='notice'>You begin to replace the wires...</span>")
if(do_after(user, 30, target = src))
if(coil.get_amount() < 1)
return
coil.use(1)
if(W.use_tool(src, user, 30, 1))
obj_integrity = max_integrity
stat &= ~BROKEN
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
+1 -2
View File
@@ -220,8 +220,7 @@
return
else if(istype(W, /obj/item/stack/cable_coil))
if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT))
var/obj/item/stack/cable_coil/CC = W
if(CC.use(2))
if(W.use_tool(src, user, 0, 2))
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
to_chat(user, "<span class='notice'>You replace the fused wires.</span>")
else
+17 -1
View File
@@ -132,6 +132,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
///Skills vars
var/used_skills //path/s of skill/s exercised when using this item.
var/skill_flags = NONE //better defines which tasks the the skill/s is/are exercised on.
var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.
/obj/item/Initialize()
if (attack_verb)
@@ -783,7 +789,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// Called when a mob tries to use the item as a tool.
// Handles most checks.
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = 1, max_level = INFINITY)
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
// Run the start check here so we wouldn't have to call it manually.
if(!delay && !tool_start_check(user, amount))
@@ -795,6 +801,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
play_tool_sound(target, volume)
if(delay)
if(user.mind && used_skills && skill_flags & SKILL_USE_TOOL)
LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, delay, skill_difficulty)
// Create a callback with checks that would be called every tick by do_after.
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
@@ -819,6 +828,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay >= MIN_TOOL_SOUND_DELAY)
play_tool_sound(target, volume)
if(user.mind && used_skills && skill_flags & SKILL_TRAINING_TOOL && skill_gain_mult)
if(!islist(used_skills))
user.mind.skill_holder.boost_skill_value_to(used_skills, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
else
for(var/skill in used_skills)
user.mind.skill_holder.boost_skill_value_to(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
return TRUE
// Called before use_tool if there is a delay, or by use_tool if there isn't.
@@ -97,8 +97,7 @@
to_chat(user, "<span class='notice'>You add [A] to the [initial(name)] assembly.</span>")
else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
if (C.use(1))
if (I.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC))
det_time = 50 // In case the cable_coil was removed and readded.
stage_change(WIRED)
to_chat(user, "<span class='notice'>You rig the [initial(name)] assembly.</span>")
@@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
if (get_amount() < 1 || CC.get_amount() < 5)
to_chat(user, "<span class='warning>You need five lengths of coil and one sheet of glass to make wired glass!</span>")
return
CC.use(5)
CC.use_tool(src, user, 0, 5, max_level = JOB_SKILL_BASIC)
use(1)
to_chat(user, "<span class='notice'>You attach wire to the [name].</span>")
var/obj/item/stack/light_w/new_tile = new(user.loc)
+1 -1
View File
@@ -131,7 +131,7 @@
if(C.get_amount() >= 5)
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5))
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use_tool(src, user, 0, 5))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
state = CABLED_CORE
update_icon()
+1 -2
View File
@@ -84,7 +84,6 @@
panel_open = FALSE
else if(istype(I, /obj/item/stack/cable_coil) && panel_open)
var/obj/item/stack/cable_coil/C = I
if(obj_flags & EMAGGED) //Emagged, not broken by EMP
to_chat(user, "<span class='warning'>Sign has been damaged beyond repair!</span>")
return
@@ -92,7 +91,7 @@
to_chat(user, "<span class='warning'>This sign is functioning properly!</span>")
return
if(C.use(2))
if(I.use_tool(src, user, 0, 2))
to_chat(user, "<span class='notice'>You replace the burnt wiring.</span>")
broken = FALSE
else
@@ -169,8 +169,7 @@
if(do_after(user, 40, target = src))
if(!src || !anchored || src.state != "01")
return
var/obj/item/stack/cable_coil/CC = W
if(!CC.use(1))
if(!W.use_tool(src, user, 0, 1))
to_chat(user, "<span class='warning'>You need more cable to do this!</span>")
return
to_chat(user, "<span class='notice'>You wire the windoor.</span>")
@@ -786,9 +786,8 @@
return
user.visible_message("[user.name] wires the air alarm.", \
"<span class='notice'>You start wiring the air alarm...</span>")
if (do_after(user, 20, target = src))
if (cable.get_amount() >= 5 && buildstage == 1)
cable.use(5)
if (W.use_tool(src, user, 20, 5))
if (buildstage == 1)
to_chat(user, "<span class='notice'>You wire the air alarm.</span>")
wires.repair()
aidisabled = 0
+1 -1
View File
@@ -32,7 +32,7 @@
/obj/item/clothing/under/attackby(obj/item/I, mob/user, params)
if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
C.use(1)
I.use_tool(src, user, 0, 1)
has_sensor = HAS_SENSORS
to_chat(user,"<span class='notice'>You repair the suit sensors on [src] with [C].</span>")
return 1
+1 -2
View File
@@ -392,8 +392,7 @@
/datum/plant_gene/trait/battery/on_attackby(obj/item/reagent_containers/food/snacks/grown/G, obj/item/I, mob/user)
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
if(C.use(5))
if(I.use_tool(src, user, 0, 5, max_level = JOB_SKILL_EXPERT))
to_chat(user, "<span class='notice'>You add some cable to [G] and slide it inside the battery encasing.</span>")
var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc)
pocell.icon_state = G.icon_state
+1 -1
View File
@@ -174,7 +174,7 @@
if(!starting_skills)
return
for(var/skill in starting_skills)
M.skill_holder.boost_skill_value_to(skill, starting_skills[skill])
M.skill_holder.boost_skill_value_to(skill, starting_skills[skill], TRUE) //silent
// do wipe affinities though
M.skill_holder.skill_affinities = list()
for(var/skill in skill_affinities)
+2
View File
@@ -17,6 +17,8 @@
var/do_special_check = TRUE
threat = 5
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null)
if(visualsOnly)
CRASH("dynamic preview is unsupported")
@@ -17,6 +17,10 @@
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ENGINE,
ACCESS_ENGINE_EQUIP, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM)
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN
threat = 0.5
@@ -27,6 +27,9 @@
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
threat = 2
+2
View File
@@ -12,6 +12,8 @@
exp_requirements = 120
exp_type = EXP_TYPE_CREW
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
display_order = JOB_DISPLAY_ORDER_CYBORG
/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source = null)
@@ -16,6 +16,10 @@
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS)
minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
display_order = JOB_DISPLAY_ORDER_ROBOTICIST
threat = 1
@@ -18,6 +18,9 @@
minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER
threat = 1
+1 -2
View File
@@ -364,12 +364,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/coin/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/CC = W
if(string_attached)
to_chat(user, "<span class='warning'>There already is a string attached to this coin!</span>")
return
if (CC.use(1))
if (W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC))
add_overlay("coin_string_overlay")
string_attached = 1
to_chat(user, "<span class='notice'>You attach a string to the coin.</span>")
@@ -9,7 +9,7 @@
if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
var/obj/item/clothing/glasses/GFP = src.glasses
number += GFP.flash_protect
if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
var/obj/item/clothing/mask/MFP = src.wear_mask
number += MFP.flash_protect
@@ -77,15 +77,13 @@
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
//CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
var/totitemdamage = pre_attacked_by(I, user, TRUE)
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
totitemdamage *= 0.5
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
totitemdamage *= 0.5
if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
totitemdamage *= 1.5
//CIT CHANGES END HERE
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
if((user != src) && (run_block(I, totitemdamage, "the [I]", ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone) & BLOCK_SUCCESS))
return FALSE
@@ -1712,9 +1712,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
disarm(M, H, attacker_style)
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
var/totitemdamage = H.pre_attacked_by(I, user, TRUE)
// Allows you to put in item-specific reactions based on species
if(user != H)
if(H.run_block(I, I.force, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS)
if(H.run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS)
return 0
if(H.check_martial_melee_block())
H.visible_message("<span class='warning'>[H] blocks [I]!</span>")
@@ -1730,16 +1731,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/armor_block = H.run_armor_check(affecting, "melee", "<span class='notice'>Your armor has protected your [hit_area].</span>", "<span class='notice'>Your armor has softened a hit to your [hit_area].</span>",I.armour_penetration)
armor_block = min(90,armor_block) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
//CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
totitemdamage *= 0.5
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
totitemdamage *= 0.5
if(istype(H))
if(!(H.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
totitemdamage *= 1.5
//CIT CHANGES END HERE
var/weakness = H.check_weakness(I, user)
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage
@@ -1747,7 +1738,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
I.do_stagger_action(H, user)
if(!I.force)
if(!totitemdamage)
return 0 //item force is zero
//dismemberment
@@ -427,24 +427,23 @@
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
user.changeNext_move(CLICK_CD_MELEE)
var/obj/item/stack/cable_coil/coil = W
if (getFireLoss() > 0 || getToxLoss() > 0)
if(src == user && coil.use(1))
if(src == user)
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
if(!do_after(user, 50, target = src))
if(!W.use_tool(src, user, 50, 1, max_level = JOB_SKILL_TRAINED))
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
return
adjustFireLoss(-10)
adjustToxLoss(-10)
if (coil.use(1))
else
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
if(!do_after(user, 30, target = src))
if(!W.use_tool(src, user, 30, 1))
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
return
adjustFireLoss(-30)
adjustToxLoss(-30)
updatehealth()
user.visible_message("[user] has fixed some of the burnt wires on [src].", "<span class='notice'>You fix some of the burnt wires on [src].</span>")
else
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
else
to_chat(user, "The wires seem fine, there's no need to fix them.")
@@ -147,9 +147,8 @@
to_chat(user, "<span class='warning'>You need one length of cable to wire the ED-209!</span>")
return
to_chat(user, "<span class='notice'>You start to wire [src]...</span>")
if(do_after(user, 40, target = src))
if(coil.get_amount() >= 1 && build_step == 6)
coil.use(1)
if(coil.use_tool(src, user, 40, 1))
if(build_step == 6)
to_chat(user, "<span class='notice'>You wire [src].</span>")
name = "wired ED-209 assembly"
build_step++
@@ -41,11 +41,10 @@
// Cable coil. Works as repair method, but will probably require multiple applications and more cable.
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/S = I
if(obj_integrity == max_integrity)
to_chat(user, "<span class='warning'>\The [src] doesn't seem to require repairs.</span>")
return 1
if(S.use(1))
if(I.use_tool(src, user, 0, 1))
to_chat(user, "<span class='notice'>You patch up \the [src] with a bit of \the [I].</span>")
obj_integrity = min(obj_integrity + 10, max_integrity)
return 1
+8 -12
View File
@@ -593,19 +593,15 @@
user.visible_message("[user.name] adds cables to the APC frame.", \
"<span class='notice'>You start adding cables to the APC frame...</span>")
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
if(do_after(user, 20, target = src))
if (C.get_amount() < 10 || !C)
if(C.use_tool(src, user, 20, 10) && !terminal && opened && has_electronics)
var/turf/T = get_turf(src)
var/obj/structure/cable/N = T.get_cable_node()
if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE))
do_sparks(5, TRUE, src)
return
if (C.get_amount() >= 10 && !terminal && opened && has_electronics)
var/turf/T = get_turf(src)
var/obj/structure/cable/N = T.get_cable_node()
if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE))
do_sparks(5, TRUE, src)
return
C.use(10)
to_chat(user, "<span class='notice'>You add cables to the APC frame.</span>")
make_terminal()
terminal.connect_to_network()
to_chat(user, "<span class='notice'>You add cables to the APC frame.</span>")
make_terminal()
terminal.connect_to_network()
else if (istype(W, /obj/item/electronics/apc) && opened)
if (has_electronics)
to_chat(user, "<span class='warning'>There is already a board inside the [src]!</span>")
+2 -2
View File
@@ -495,6 +495,8 @@ By design, d1 is the smallest direction and d2 is the highest
full_w_class = WEIGHT_CLASS_SMALL
grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil
usesound = 'sound/items/deconstruct.ogg'
used_skills = /datum/skill/level/job/wiring
skill_flags = SKILL_USE_TOOL|SKILL_TRAINING_TOOL
/obj/item/stack/cable_coil/cyborg
is_cyborg = 1
@@ -576,8 +578,6 @@ By design, d1 is the smallest direction and d2 is the highest
amount += extra
update_icon()
///////////////////////////////////////////////
// Cable laying procedures
//////////////////////////////////////////////
+1 -2
View File
@@ -15,8 +15,7 @@
state = FLOODLIGHT_NEEDS_WIRES
desc = "A bare metal frame looking vaguely like a floodlight. Requires wiring."
else if(istype(O, /obj/item/stack/cable_coil) && (state == FLOODLIGHT_NEEDS_WIRES))
var/obj/item/stack/S = O
if(S.use(5))
if(O.use_tool(src, user, 0, 5))
to_chat(user, "<span class='notice'>You wire [src].</span>")
name = "wired [name]"
desc = "A bare metal frame looking vaguely like a floodlight. Requires securing with a screwdriver."
+1 -2
View File
@@ -118,8 +118,7 @@
return
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = W
if(coil.use(1))
if(W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_TRAINED))
icon_state = "[fixture_type]-construct-stage2"
stage = 2
user.visible_message("[user.name] adds wires to [src].", \
@@ -79,8 +79,7 @@
construction_state = PA_CONSTRUCTION_UNSECURED
did_something = TRUE
else if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/CC = W
if(CC.use(1))
if(W.use_tool(src, user, 0, 1))
user.visible_message("[user.name] adds wires to the [name].", \
"You add some wires.")
construction_state = PA_CONSTRUCTION_PANEL_OPEN
@@ -288,8 +288,7 @@
construction_state = PA_CONSTRUCTION_UNSECURED
did_something = TRUE
else if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/CC = W
if(CC.use(1))
if(W.use_tool(src, user, 0, 1))
user.visible_message("[user.name] adds wires to the [name].", \
"You add some wires.")
construction_state = PA_CONSTRUCTION_PANEL_OPEN
+1 -4
View File
@@ -125,15 +125,12 @@
to_chat(user, "<span class='notice'>You start building the power terminal...</span>")
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
if(do_after(user, 20, target = src) && C.get_amount() >= 10)
if(C.get_amount() < 10 || !C)
return
if(C.use_tool(src, user, 20, 10))
var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one
if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) //animate the electrocution if uncautious and unlucky
do_sparks(5, TRUE, src)
return
C.use(10)
user.visible_message(\
"[user.name] has built a power terminal.",\
"<span class='notice'>You build the power terminal.</span>")
@@ -331,8 +331,7 @@
/obj/item/gun/ballistic/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params)
..()
if(istype(A, /obj/item/stack/cable_coil) && !sawn_off)
var/obj/item/stack/cable_coil/C = A
if(C.use(10))
if(A.use_tool(src, user, 0, 10, max_level = JOB_SKILL_BASIC))
slot_flags = ITEM_SLOT_BACK
to_chat(user, "<span class='notice'>You tie the lengths of cable to the shotgun, making a sling.</span>")
slung = TRUE
@@ -19,7 +19,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_l_arm"
status = BODYPART_ROBOTIC
brute_reduction = 2
burn_reduction = 1
@@ -40,7 +40,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_r_arm"
status = BODYPART_ROBOTIC
brute_reduction = 2
burn_reduction = 1
@@ -61,7 +61,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_l_leg"
status = BODYPART_ROBOTIC
brute_reduction = 2
burn_reduction = 1
@@ -82,7 +82,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_r_leg"
status = BODYPART_ROBOTIC
brute_reduction = 2
burn_reduction = 1
@@ -102,7 +102,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_chest"
status = BODYPART_ROBOTIC
brute_reduction = 2
burn_reduction = 1
@@ -131,8 +131,7 @@
if(src.wired)
to_chat(user, "<span class='warning'>You have already inserted wire!</span>")
return
var/obj/item/stack/cable_coil/coil = W
if (coil.use(1))
if (W.use_tool(src, user, 0, 1))
src.wired = 1
to_chat(user, "<span class='notice'>You insert the wire.</span>")
else
@@ -164,7 +163,7 @@
flags_1 = CONDUCT_1
icon_state = "borg_head"
status = BODYPART_ROBOTIC
brute_reduction = 5
burn_reduction = 4
+4 -5
View File
@@ -58,10 +58,9 @@
return FALSE
if(tool)
speed_mod = tool.toolspeed
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))
if(user.mind)
SKILL_MODIFIER(GLOB.skill_datums[/datum/skill/numerical/surgery], user.mind.skill_holder, speed_mod, THRESHOLD_COMPETENT)
if(do_after(user, time * speed_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]
@@ -69,7 +68,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)
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))