Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit731
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+10
-7
@@ -25,35 +25,38 @@
|
||||
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
|
||||
|
||||
//subsystem does not initialize.
|
||||
#define SS_NO_INIT 1
|
||||
#define SS_NO_INIT (1<<0)
|
||||
|
||||
//subsystem does not fire.
|
||||
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
|
||||
// (Requires a MC restart to change)
|
||||
#define SS_NO_FIRE 2
|
||||
#define SS_NO_FIRE (1<<1)
|
||||
|
||||
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
|
||||
// SS_BACKGROUND has its own priority bracket
|
||||
#define SS_BACKGROUND 4
|
||||
#define SS_BACKGROUND (1<<2)
|
||||
|
||||
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
|
||||
#define SS_NO_TICK_CHECK 8
|
||||
#define SS_NO_TICK_CHECK (1<<3)
|
||||
|
||||
//Treat wait as a tick count, not DS, run every wait ticks.
|
||||
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
|
||||
// (implies all runlevels because of how it works)
|
||||
// (overrides SS_BACKGROUND)
|
||||
// This is designed for basically anything that works as a mini-mc (like SStimer)
|
||||
#define SS_TICKER 16
|
||||
#define SS_TICKER (1<<4)
|
||||
|
||||
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
|
||||
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
|
||||
#define SS_KEEP_TIMING 32
|
||||
#define SS_KEEP_TIMING (1<<5)
|
||||
|
||||
//Calculate its next fire after its fired.
|
||||
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
|
||||
// This flag overrides SS_KEEP_TIMING
|
||||
#define SS_POST_FIRE_TIMING 64
|
||||
#define SS_POST_FIRE_TIMING (1<<6)
|
||||
|
||||
/// Show in stat() by default even if SS_NO_FIRE
|
||||
#define SS_ALWAYS_SHOW_STAT (1<<7)
|
||||
|
||||
//SUBSYSTEM STATES
|
||||
#define SS_IDLE 0 //aint doing shit.
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define COLOR_RED_GRAY "#B4696A"
|
||||
#define COLOR_PALE_BLUE_GRAY "#98C5DF"
|
||||
#define COLOR_PALE_GREEN_GRAY "#B7D993"
|
||||
#define COLOR_PALE_ORANGE "#FFC066"
|
||||
#define COLOR_PALE_RED_GRAY "#D59998"
|
||||
#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
|
||||
#define COLOR_PURPLE_GRAY "#AE8CA8"
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
/// Default combat flags for those affected by ((stamina combat))
|
||||
#define COMBAT_FLAGS_DEFAULT NONE
|
||||
/// Default combat flags for everyone else (so literally everyone but humans)
|
||||
#define COMBAT_FLAGS_STAMSYSTEM_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_COMBAT_TOGGLED)
|
||||
#define COMBAT_FLAGS_STAMSYSTEM_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_COMBAT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_COMBAT_FORCED)
|
||||
/// Default combat flags for those only affected by sprint (so just silicons)
|
||||
#define COMBAT_FLAGS_STAMEXEMPT_YESSPRINT (COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_COMBAT_TOGGLED)
|
||||
#define COMBAT_FLAGS_STAMEXEMPT_YESSPRINT (COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_COMBAT_TOGGLED | COMBAT_FLAG_COMBAT_FORCED)
|
||||
|
||||
/// The user wants combat mode on
|
||||
#define COMBAT_FLAG_COMBAT_TOGGLED (1<<0)
|
||||
@@ -57,6 +57,10 @@
|
||||
#define COMBAT_FLAG_INTENTIONALLY_RESTING (1<<7)
|
||||
/// Currently stamcritted but not as violently
|
||||
#define COMBAT_FLAG_SOFT_STAMCRIT (1<<8)
|
||||
/// Force combat mode on at all times, overrides everything including combat disable traits.
|
||||
#define COMBAT_FLAG_COMBAT_FORCED (1<<9)
|
||||
/// Force sprint mode on at all times, overrides everything including sprint disable traits.
|
||||
#define COMBAT_FLAG_SPRINT_FORCED (1<<10)
|
||||
|
||||
// Helpers for getting someone's stamcrit state. Cast to living.
|
||||
#define NOT_STAMCRIT 0
|
||||
@@ -248,13 +252,32 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds.
|
||||
#define TOTAL_MASS_TOY_SWORD 1.5
|
||||
|
||||
//stamina cost defines.
|
||||
#define STAM_COST_ATTACK_OBJ_MULT 1.2
|
||||
#define STAM_COST_ATTACK_MOB_MULT 0.8
|
||||
#define STAM_COST_BATON_MOB_MULT 1
|
||||
#define STAM_COST_NO_COMBAT_MULT 1.25
|
||||
#define STAM_COST_W_CLASS_MULT 1.25
|
||||
#define STAM_COST_THROW_MULT 2
|
||||
|
||||
|
||||
//bullet_act() return values
|
||||
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
|
||||
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
|
||||
|
||||
/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
|
||||
/// Check whether or not we can block, without "triggering" a block. Basically run checks without effects like depleting shields.
|
||||
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
|
||||
#define mob_check_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
|
||||
do_run_block(FALSE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
|
||||
|
||||
/// Runs a block "sequence", effectively checking and then doing effects if necessary.
|
||||
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
|
||||
#define mob_run_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
|
||||
do_run_block(TRUE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
|
||||
|
||||
/// Bitflags for check_block() and run_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
|
||||
/// Attack was not blocked
|
||||
#define BLOCK_NONE NONE
|
||||
/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
|
||||
|
||||
@@ -183,7 +183,28 @@
|
||||
// #define SPEECH_FORCED 7
|
||||
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
|
||||
|
||||
#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //called from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
|
||||
#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
|
||||
|
||||
#define COMSIG_MOB_ACTION_SKILL_MOD "mob_action_skill_mod" //from base of /datum/skill_holder/action_skills_mod() : (proc args list, list/mod_values)
|
||||
#define ACTION_SKILL_MOD_SKILL 1 //redundancy.
|
||||
#define ACTION_SKILL_MOD_VALUE 2
|
||||
#define ACTION_SKILL_MOD_THRESHOLD 3
|
||||
#define ACTION_SKILL_MOD_IS_MULTI 4
|
||||
//other mod values, kept separate from the args
|
||||
#define MOD_VALUES_SKILL_MOD 1
|
||||
|
||||
#define COMSIG_MOB_ITEM_ACTION_SKILLS_MOD "mob_item_action_skills_mod" //from base of /datum/skill_holder/item_action_skills_mod() : (proc args list, mod_values)
|
||||
#define ITEM_SKILLS_MOD_ITEM 1 //redundancy
|
||||
#define ITEM_SKILLS_MOD_VALUE 2
|
||||
#define ITEM_SKILLS_MOD_FLAGS 3
|
||||
#define ITEM_SKILLS_MOD_BAD_FLAGS 4
|
||||
#define ITEM_SKILLS_MOD_IS_MULTI 5
|
||||
//other mod values, kept separate from the args
|
||||
#define MOD_VALUES_ITEM_SKILLS_SUM 1
|
||||
#define MOD_VALUES_ITEM_SKILLS_DIV 2
|
||||
#define MOD_VALUES_ITEM_SKILLS_CHECKED 3
|
||||
|
||||
#define COMSIG_MOB_SKILL_GET_AFFINITY "mob_skill_get_affinity" //from base of /datum/skill_holder/get_skill_affinity(): (skill_path, list/return_value)
|
||||
|
||||
// /mob/living signals
|
||||
#define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
|
||||
|
||||
@@ -3,5 +3,24 @@
|
||||
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
|
||||
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
|
||||
|
||||
#define LANGUAGE_KNOWN "language_known"
|
||||
#define LANGUAGE_SHADOWED "language_shadowed"
|
||||
// LANGUAGE SOURCE DEFINES
|
||||
#define LANGUAGE_ALL "all" // For use in full removal only.
|
||||
#define LANGUAGE_ATOM "atom"
|
||||
#define LANGUAGE_MIND "mind"
|
||||
|
||||
#define LANGUAGE_ABSORB "absorb"
|
||||
#define LANGUAGE_APHASIA "aphasia"
|
||||
#define LANGUAGE_BLOODSUCKER "bloodsucker"
|
||||
#define LANGUAGE_CLOCKIE "clockie"
|
||||
#define LANGUAGE_CULTIST "cultist"
|
||||
#define LANGUAGE_CURATOR "curator"
|
||||
#define LANGUAGE_DEVIL "devil"
|
||||
#define LANGUAGE_GLAND "gland"
|
||||
#define LANGUAGE_HAT "hat"
|
||||
#define LANGUAGE_HIGH "high"
|
||||
#define LANGUAGE_MALF "malf"
|
||||
#define LANGUAGE_MASTER "master"
|
||||
#define LANGUAGE_SOFTWARE "software"
|
||||
#define LANGUAGE_STONER "stoner"
|
||||
#define LANGUAGE_VASSAL "vassal"
|
||||
#define LANGUAGE_VOICECHANGE "voicechange"
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
#define MOOD_LEVEL_SAD4 -25
|
||||
|
||||
//Sanity levels for humans
|
||||
#define SANITY_AMAZING 150
|
||||
#define SANITY_GREAT 125
|
||||
#define SANITY_NEUTRAL 100
|
||||
#define SANITY_DISTURBED 75
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
/// true/false
|
||||
#define SKILL_PROGRESSION_BINARY 1
|
||||
/// numerical
|
||||
#define SKILL_PROGRESSION_NUMERICAL 2
|
||||
/// Enum
|
||||
#define SKILL_PROGRESSION_ENUM 3
|
||||
/// Levels
|
||||
#define SKILL_PROGRESSION_LEVEL 4
|
||||
|
||||
|
||||
/// 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
|
||||
|
||||
#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
|
||||
|
||||
#define SKILL_AFFINITY_MOOD_BONUS 1.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)
|
||||
#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage.
|
||||
#define SKILL_THROW_STAM_COST (1<<7)
|
||||
#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on.
|
||||
#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
|
||||
#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
|
||||
|
||||
///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
|
||||
|
||||
#define RPG_MAX_LVL 100
|
||||
|
||||
#define DORF_XP_LVL_UP 400
|
||||
#define DORF_XP_LVL_MULTI 100
|
||||
#define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5
|
||||
|
||||
//level up methods defines
|
||||
#define STANDARD_LEVEL_UP "standard_level_up"
|
||||
#define DWARFY_LEVEL_UP "dwarfy_level_up"
|
||||
|
||||
//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
|
||||
|
||||
//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
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
//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)
|
||||
@@ -1,28 +0,0 @@
|
||||
/// 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)
|
||||
@@ -255,6 +255,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
current_user = M.client
|
||||
//Blank
|
||||
menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = ABOVE_HUD_LAYER)
|
||||
menu_holder.plane = ABOVE_HUD_PLANE
|
||||
menu_holder.appearance_flags |= KEEP_APART
|
||||
menu_holder.vis_contents += elements + close_button
|
||||
current_user.images += menu_holder
|
||||
@@ -285,13 +286,16 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
Choices should be a list where list keys are movables or text used for element names and return value
|
||||
and list values are movables/icons/images used for element icons
|
||||
*/
|
||||
/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE)
|
||||
/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE)
|
||||
if(!user || !anchor || !length(choices))
|
||||
return
|
||||
if(!uniqueid)
|
||||
uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
|
||||
|
||||
if(GLOB.radial_menus[uniqueid])
|
||||
if(!no_repeat_close)
|
||||
var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid]
|
||||
menu.finished = TRUE
|
||||
return
|
||||
|
||||
var/datum/radial_menu/menu = new
|
||||
@@ -308,4 +312,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
var/answer = menu.selected_choice
|
||||
qdel(menu)
|
||||
GLOB.radial_menus -= uniqueid
|
||||
if(require_near && !in_range(anchor, user))
|
||||
return
|
||||
if(istype(custom_check))
|
||||
if(!custom_check.Invoke())
|
||||
return
|
||||
return answer
|
||||
@@ -91,7 +91,7 @@
|
||||
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
|
||||
add_fingerprint(user)
|
||||
|
||||
user.adjustStaminaLossBuffered(getweight()*0.8)//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_MOB_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
|
||||
//the equivalent of the standard version of attack() but for object targets.
|
||||
/obj/item/proc/attack_obj(obj/O, mob/living/user)
|
||||
@@ -102,7 +102,7 @@
|
||||
if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You're too exhausted.</span>") // CIT CHANGE - ditto
|
||||
return // CIT CHANGE - ditto
|
||||
user.adjustStaminaLossBuffered(getweight()*1.2)//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_OBJ_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(O)
|
||||
O.attacked_by(src, user)
|
||||
@@ -111,26 +111,32 @@
|
||||
return
|
||||
|
||||
/obj/attacked_by(obj/item/I, mob/living/user)
|
||||
if(I.force)
|
||||
var/totitemdamage = I.force
|
||||
var/bad_flag = NONE
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
totitemdamage *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(I.used_skills && user.mind)
|
||||
if(totitemdamage)
|
||||
totitemdamage = user.mind.skill_holder.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(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
|
||||
if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, null, null) & 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 +152,28 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = I.force
|
||||
var/bad_flag = NONE
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
. *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
. *= 0.5
|
||||
if(!user.mind || !I.used_skills)
|
||||
return
|
||||
if(.)
|
||||
. = user.mind.skill_holder.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain)
|
||||
|
||||
/mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = ..()
|
||||
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)
|
||||
@@ -179,22 +207,30 @@
|
||||
return 1
|
||||
|
||||
/// How much stamina this takes to swing this is not for realism purposes hecc off.
|
||||
/obj/item/proc/getweight()
|
||||
return total_mass || w_class * 1.25
|
||||
/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST)
|
||||
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
|
||||
if(!user)
|
||||
return
|
||||
var/bad_flag = NONE
|
||||
if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
. *= STAM_COST_NO_COMBAT_MULT
|
||||
bad_flag |= SKILL_COMBAT_MODE
|
||||
if(used_skills && user.mind)
|
||||
. = user.mind.skill_holder.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE)
|
||||
|
||||
/// 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)
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
name = "Initializing..."
|
||||
var/target
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
|
||||
/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
|
||||
/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical
|
||||
. = ..()
|
||||
name = text
|
||||
src.target = target
|
||||
@@ -33,6 +31,14 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
usr.client.debug_variables(target)
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].")
|
||||
|
||||
/obj/effect/statclick/misc_subsystems/Click()
|
||||
if(!usr.client.holder)
|
||||
return
|
||||
var/subsystem = input(usr, "Debug which subsystem?", "Debug nonprocessing subsystem") as null|anything in (Master.subsystems - Master.statworthy_subsystems)
|
||||
if(!subsystem)
|
||||
return
|
||||
usr.client.debug_variables(subsystem)
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [subsystem] subsystem.")
|
||||
|
||||
// Debug verbs.
|
||||
/client/proc/restart_controller(controller in list("Master", "Failsafe"))
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
/datum/config_entry/keyed_list/midround_antag/ValidateListEntry(key_name, key_value)
|
||||
return key_name in config.modes
|
||||
|
||||
/datum/config_entry/keyed_list/force_antag_count
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
|
||||
/datum/config_entry/keyed_list/force_antag_count/ValidateListEntry(key_name, key_value)
|
||||
return key_name in config.modes
|
||||
|
||||
/datum/config_entry/keyed_list/policy
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_TEXT
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
// List of subsystems to process().
|
||||
var/list/subsystems
|
||||
/// List of subsystems to include in the MC stat panel.
|
||||
var/list/statworthy_subsystems
|
||||
|
||||
// Vars for keeping track of tick drift.
|
||||
var/init_timeofday
|
||||
@@ -65,6 +67,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/// Statclick for misc subsystems
|
||||
var/obj/effect/statclick/misc_subsystems/misc_statclick
|
||||
|
||||
/datum/controller/master/New()
|
||||
if(!config)
|
||||
config = new
|
||||
@@ -87,6 +92,11 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
_subsystems += new I
|
||||
Master = src
|
||||
|
||||
// We want to see all subsystems during init.
|
||||
statworthy_subsystems = subsystems.Copy()
|
||||
|
||||
misc_statclick = new(null, "Debug")
|
||||
|
||||
if(!GLOB)
|
||||
new /datum/controller/global_vars
|
||||
|
||||
@@ -257,10 +267,14 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/list/tickersubsystems = list()
|
||||
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
|
||||
var/timer = world.time
|
||||
statworthy_subsystems = list()
|
||||
for (var/thing in subsystems)
|
||||
var/datum/controller/subsystem/SS = thing
|
||||
if (SS.flags & SS_NO_FIRE)
|
||||
if(SS.flags & SS_ALWAYS_SHOW_STAT)
|
||||
statworthy_subsystems += SS
|
||||
continue
|
||||
statworthy_subsystems += SS
|
||||
SS.queued_time = 0
|
||||
SS.queue_next = null
|
||||
SS.queue_prev = null
|
||||
@@ -603,7 +617,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)")
|
||||
stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"))
|
||||
|
||||
stat("Misc Subsystems", misc_statclick)
|
||||
|
||||
/datum/controller/master/StartLoadingMap()
|
||||
//disallow more than one map to load at once, multithreading it will just cause race conditions
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
|
||||
trauma = _trauma
|
||||
owner = trauma.owner
|
||||
copy_known_languages_from(owner, TRUE)
|
||||
|
||||
setup_friend()
|
||||
|
||||
|
||||
@@ -26,21 +26,15 @@
|
||||
scan_desc = "extensive damage to the brain's language center"
|
||||
gain_text = "<span class='warning'>You have trouble forming words in your head...</span>"
|
||||
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"
|
||||
var/datum/language_holder/prev_language
|
||||
var/datum/language_holder/mob_language
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_gain()
|
||||
mob_language = owner.get_language_holder()
|
||||
prev_language = mob_language.copy()
|
||||
mob_language.remove_all_languages()
|
||||
mob_language.grant_language(/datum/language/aphasia)
|
||||
owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA)
|
||||
owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_lose()
|
||||
mob_language.remove_language(/datum/language/aphasia)
|
||||
mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
|
||||
QDEL_NULL(prev_language)
|
||||
mob_language = null
|
||||
owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA)
|
||||
owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/blindness
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
|
||||
/datum/crafting_recipe/upgraded_gauze
|
||||
name = "Improved Gauze"
|
||||
result = /obj/item/stack/medical/gauze/adv
|
||||
result = /obj/item/stack/medical/gauze/adv/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/space_cleaner/sterilizine = 10)
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
/datum/crafting_recipe/bruise_pack
|
||||
name = "Bruise Pack"
|
||||
result = /obj/item/stack/medical/bruise_pack
|
||||
result = /obj/item/stack/medical/bruise_pack/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
@@ -134,8 +134,8 @@
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/burn_pack
|
||||
name = "Brun Ointment"
|
||||
result = /obj/item/stack/medical/ointment
|
||||
name = "Burn Ointment"
|
||||
result = /obj/item/stack/medical/ointment/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#define SLIGHT_INSANITY_PEN 1
|
||||
#define MINOR_INSANITY_PEN 5
|
||||
#define MAJOR_INSANITY_PEN 10
|
||||
#define MOOD_INSANITY_MALUS 0.0054 // per point of sanity below SANITY_DISTURBED, a 40% debuff to skills at rock bottom depression.
|
||||
|
||||
/datum/component/mood
|
||||
var/mood //Real happiness
|
||||
@@ -22,7 +24,6 @@
|
||||
RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event)
|
||||
RegisterSignal(parent, COMSIG_MODIFY_SANITY, .proc/modify_sanity)
|
||||
RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/on_revive)
|
||||
|
||||
RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud)
|
||||
var/mob/living/owner = parent
|
||||
if(owner.hud_used)
|
||||
@@ -150,7 +151,7 @@
|
||||
if(8)
|
||||
setSanity(sanity+0.25, maximum=SANITY_GREAT)
|
||||
if(9)
|
||||
setSanity(sanity+0.4, maximum=SANITY_GREAT)
|
||||
setSanity(sanity+0.4, maximum=SANITY_AMAZING)
|
||||
|
||||
HandleNutrition(owner)
|
||||
|
||||
@@ -166,6 +167,7 @@
|
||||
else if(sanity > maximum && amount > sanity - 0.5)
|
||||
amount = sanity - 0.5
|
||||
|
||||
var/old_sanity = sanity
|
||||
// Disturbed stops you from getting any more sane
|
||||
if(HAS_TRAIT(master, TRAIT_UNSTABLE))
|
||||
sanity = min(amount,sanity)
|
||||
@@ -182,7 +184,7 @@
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/crazy)
|
||||
sanity_level = 5
|
||||
if(SANITY_UNSTABLE to SANITY_DISTURBED)
|
||||
setInsanityEffect(0)
|
||||
setInsanityEffect(SLIGHT_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/disturbed)
|
||||
sanity_level = 4
|
||||
if(SANITY_DISTURBED to SANITY_NEUTRAL)
|
||||
@@ -197,6 +199,12 @@
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
sanity_level = 1
|
||||
|
||||
if(old_sanity > 1 && sanity == 1)
|
||||
RegisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY, .proc/on_get_skill_affinity)
|
||||
else if(old_sanity == 1 && sanity > 1)
|
||||
UnregisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY)
|
||||
|
||||
//update_mood_icon()
|
||||
|
||||
/datum/component/mood/proc/setInsanityEffect(newval)//More code so that the previous proc works
|
||||
@@ -204,9 +212,14 @@
|
||||
return
|
||||
//var/mob/living/master = parent
|
||||
//master.crit_threshold = (master.crit_threshold - insanity_effect) + newval
|
||||
if(!insanity_effect && newval)
|
||||
RegisterSignal(parent, COMSIG_MOB_ACTION_SKILL_MOD, .proc/on_mob_action_skill_mod)
|
||||
RegisterSignal(parent, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, .proc/on_item_action_skills_mod)
|
||||
else if(insanity_effect && !newval)
|
||||
UnregisterSignal(parent, list(COMSIG_MOB_ACTION_SKILL_MOD, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD))
|
||||
insanity_effect = newval
|
||||
|
||||
/datum/component/mood/proc/modify_sanity(datum/source, amount, minimum = -INFINITY, maximum = INFINITY)
|
||||
/datum/component/mood/proc/modify_sanity(datum/source, amount, minimum = SANITY_INSANE, maximum = SANITY_AMAZING)
|
||||
setSanity(sanity + amount, minimum, maximum)
|
||||
|
||||
/datum/component/mood/proc/add_event(datum/source, category, type, param) //Category will override any events in the same category, should be unique unless the event is based on the same thing like hunger.
|
||||
@@ -288,5 +301,40 @@
|
||||
remove_temp_moods()
|
||||
setSanity(initial(sanity))
|
||||
|
||||
/datum/component/mood/proc/on_mob_action_skill_mod(mob/source, list/skill_args, list/mod_values)
|
||||
var/datum/skill/S = GLOB.skill_datums[skill_args[ACTION_SKILL_MOD_SKILL]]
|
||||
if(!(S.skill_flags & SKILL_USE_MOOD))
|
||||
return
|
||||
var/debuff = 1 - (SANITY_DISTURBED - sanity) * MOOD_INSANITY_MALUS
|
||||
mod_values[MOD_VALUES_SKILL_MOD] *= skill_args[ACTION_SKILL_MOD_IS_MULTI] ? debuff : 1/debuff
|
||||
|
||||
/datum/component/mood/proc/on_item_action_skills_mod(mob/source, list/skill_args, list/mod_values)
|
||||
if(skill_args[ITEM_SKILLS_MOD_BAD_FLAGS] & SKILL_USE_MOOD)
|
||||
return
|
||||
var/divisor = mod_values[MOD_VALUES_ITEM_SKILLS_DIV]
|
||||
if(!divisor)
|
||||
return
|
||||
var/obj/item/I = skill_args[ITEM_SKILLS_MOD_ITEM]
|
||||
var/list/L = mod_values[MOD_VALUES_ITEM_SKILLS_CHECKED]
|
||||
var/skills_len = length(L)
|
||||
var/affected_skills = skills_len
|
||||
for(var/k in L)
|
||||
var/datum/skill/S = k
|
||||
var/our_flags = I.used_skills[S.type]|S.skill_flags
|
||||
if(!(our_flags & SKILL_USE_MOOD))
|
||||
affected_skills--
|
||||
if(!affected_skills)
|
||||
return
|
||||
var/debuff = 1 - (SANITY_DISTURBED - sanity) * MOOD_INSANITY_MALUS * (affected_skills/skills_len)
|
||||
mod_values[MOD_VALUES_ITEM_SKILLS_SUM] *= skill_args[ITEM_SKILLS_MOD_IS_MULTI] ? debuff : 1/debuff
|
||||
|
||||
/datum/component/mood/proc/on_get_skill_affinity(mob/source, skill_path, list/return_value)
|
||||
var/datum/skill/S = GLOB.skill_datums[skill_path]
|
||||
if(!S || !(S.skill_flags & SKILL_TRAIN_MOOD))
|
||||
return
|
||||
return_value[1] *= SKILL_AFFINITY_MOOD_BONUS
|
||||
|
||||
#undef SLIGHT_INSANITY_PEN
|
||||
#undef MINOR_INSANITY_PEN
|
||||
#undef MAJOR_INSANITY_PEN
|
||||
#undef MOOD_INSANITY_MALUS
|
||||
|
||||
@@ -208,13 +208,13 @@
|
||||
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(/datum/movespeed_modifier/human_carry)
|
||||
if(!fireman_carrying)
|
||||
M.Daze(25)
|
||||
REMOVE_TRAIT(M, TRAIT_MOBILITY_NOUSE, src)
|
||||
return ..()
|
||||
|
||||
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
|
||||
. = ..()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
var/mob/living/carbon/C = M
|
||||
if(prob(10))
|
||||
if(trauma_heal_severe)
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_SURGERY)
|
||||
else
|
||||
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ Bonus
|
||||
symptom_delay_max = 120
|
||||
var/scramble_language = FALSE
|
||||
var/datum/language/current_language
|
||||
var/datum/language_holder/original_language
|
||||
threshold_desc = list(
|
||||
"Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.",
|
||||
"Stage Speed 7" = "Changes voice more often.",
|
||||
@@ -48,9 +47,6 @@ Bonus
|
||||
symptom_delay_max = 85
|
||||
if(A.properties["transmittable"] >= 14) //random language
|
||||
scramble_language = TRUE
|
||||
var/mob/living/M = A.affected_mob
|
||||
var/datum/language_holder/mob_language = M.get_language_holder()
|
||||
original_language = mob_language.copy()
|
||||
|
||||
/datum/symptom/voice_change/Activate(datum/disease/advance/A)
|
||||
if(!..())
|
||||
@@ -64,12 +60,10 @@ Bonus
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
H.SetSpecialVoice(H.dna.species.random_name(H.gender))
|
||||
if(scramble_language)
|
||||
H.remove_language(current_language)
|
||||
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
|
||||
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
|
||||
H.grant_language(current_language)
|
||||
var/datum/language_holder/mob_language = H.get_language_holder()
|
||||
mob_language.only_speaks_language = current_language
|
||||
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
|
||||
H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE)
|
||||
|
||||
/datum/symptom/voice_change/End(datum/disease/advance/A)
|
||||
..()
|
||||
@@ -77,7 +71,5 @@ Bonus
|
||||
var/mob/living/carbon/human/H = A.affected_mob
|
||||
H.UnsetSpecialVoice()
|
||||
if(scramble_language)
|
||||
var/mob/living/M = A.affected_mob
|
||||
M.copy_known_languages_from(original_language, TRUE)
|
||||
current_language = null
|
||||
QDEL_NULL(original_language)
|
||||
A.affected_mob.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_VOICECHANGE)
|
||||
A.affected_mob.remove_all_languages(LANGUAGE_VOICECHANGE) // In case someone managed to get more than one anyway.
|
||||
|
||||
@@ -355,6 +355,11 @@
|
||||
var/datum/species/old_species = dna.species
|
||||
dna.species = new_race
|
||||
dna.species.on_species_gain(src, old_species, pref_load)
|
||||
if(ishuman(src))
|
||||
qdel(language_holder)
|
||||
var/species_holder = initial(mrace.species_language_holder)
|
||||
language_holder = new species_holder(src)
|
||||
update_atom_languages()
|
||||
|
||||
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE)
|
||||
..()
|
||||
|
||||
@@ -76,7 +76,9 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
//I would make this not ex_act the thing that triggered the explosion,
|
||||
//but everything that explodes gives us their loc or a get_turf()
|
||||
//and somethings expect us to ex_act them so they can qdel()
|
||||
stoplag() //tldr, let the calling proc call qdel(src) before we explode
|
||||
//stoplag() //tldr, let the calling proc call qdel(src) before we explode
|
||||
// no - use sleep. stoplag() results in quirky things like explosions taking too long to process and hanging mid-air for no reason.
|
||||
sleep(0)
|
||||
|
||||
EX_PREPROCESS_EXIT_CHECK
|
||||
|
||||
|
||||
+4
-6
@@ -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,12 +80,12 @@
|
||||
if(antag_datum.delete_on_mind_deletion)
|
||||
qdel(i)
|
||||
antag_datums = null
|
||||
QDEL_NULL(skill_holder)
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/get_language_holder()
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/L = current.get_language_holder(shadow=FALSE)
|
||||
language_holder = L.copy(src)
|
||||
language_holder = new (src)
|
||||
|
||||
return language_holder
|
||||
|
||||
@@ -100,9 +100,6 @@
|
||||
if(iscarbon(current))
|
||||
var/mob/living/carbon/C = current
|
||||
C.disable_intentional_combat_mode(TRUE)
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
|
||||
language_holder = mob_holder.copy(src)
|
||||
|
||||
if(key)
|
||||
if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours
|
||||
@@ -130,6 +127,7 @@
|
||||
transfer_martial_arts(new_character)
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
current.update_atom_languages()
|
||||
|
||||
//CIT CHANGE - makes arousal update when transfering bodies
|
||||
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
|
||||
|
||||
@@ -277,10 +277,10 @@
|
||||
|
||||
/datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner)
|
||||
..()
|
||||
owner.grant_language(/datum/language/beachbum)
|
||||
owner.remove_language(/datum/language/common)
|
||||
owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
|
||||
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
|
||||
|
||||
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
|
||||
..()
|
||||
owner.grant_language(/datum/language/common)
|
||||
owner.remove_language(/datum/language/beachbum)
|
||||
owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
|
||||
owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
|
||||
|
||||
@@ -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()
|
||||
@@ -9,16 +9,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -30,10 +27,18 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
var/name
|
||||
/// Our description
|
||||
var/desc
|
||||
/// Color of the name as shown in the html readout
|
||||
var/name_color = "#F0F0F0" // White on dark surface.
|
||||
/// Our progression type
|
||||
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)
|
||||
/// In which way this skil can affect or be affected through actions.
|
||||
var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
|
||||
|
||||
/**
|
||||
* Ensures what someone's setting as a value for this skill is valid.
|
||||
@@ -41,6 +46,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/proc/sanitize_value(new_value)
|
||||
return new_value
|
||||
|
||||
/**
|
||||
* 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_value(datum/skill_holder/H, value, mob/owner)
|
||||
H.skills[type] = value
|
||||
|
||||
/**
|
||||
* Checks if a value is greater
|
||||
*/
|
||||
@@ -52,7 +64,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/**
|
||||
* Standard value "render"
|
||||
*/
|
||||
/datum/skill/proc/standard_render_value(value)
|
||||
/datum/skill/proc/standard_render_value(value, level)
|
||||
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.
|
||||
@@ -61,11 +73,13 @@ 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
|
||||
|
||||
/datum/skill/binary/standard_render_value(value)
|
||||
/datum/skill/binary/standard_render_value(value, level)
|
||||
return value? "Yes" : "No"
|
||||
|
||||
/datum/skill/numerical
|
||||
@@ -81,7 +95,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
/datum/skill/numerical/standard_render_value(value)
|
||||
/datum/skill/numerical/standard_render_value(value, level)
|
||||
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
|
||||
|
||||
/datum/skill/enum
|
||||
@@ -93,3 +107,102 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/enum/sanitize_value(new_value)
|
||||
if(new_value in valid_values)
|
||||
return new_value
|
||||
|
||||
/**
|
||||
* Classing r p g styled skills, tiered by lvl, and current/nextlvl 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_MULTI //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.)
|
||||
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/level/New()
|
||||
. = ..()
|
||||
var/max_assoc = ""
|
||||
var/max_assoc_start = 1
|
||||
for(var/lvl in 1 to max_levels)
|
||||
var/value
|
||||
switch(level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
if(DWARFY_LEVEL_UP)
|
||||
value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
value = round(value, 1)
|
||||
if(!associative)
|
||||
levels += value
|
||||
continue
|
||||
if(max_assoc)
|
||||
levels["[max_assoc] +[max_assoc_start++]"] = value
|
||||
continue
|
||||
var/key = LAZYACCESS(levels, lvl)
|
||||
if(!key)
|
||||
if(lvl == 1) //You dun goof it.
|
||||
stack_trace("Skill datum [src] was set to have an associative levels list despite the latter having no key value.")
|
||||
associative = FALSE
|
||||
levels += value
|
||||
continue
|
||||
max_assoc = levels[lvl-1]
|
||||
levels["[max_assoc] +[max_assoc_start++]"] = value
|
||||
levels[key] = value
|
||||
|
||||
/datum/skill/level/sanitize_value(new_value)
|
||||
return max(new_value, 0)
|
||||
|
||||
/datum/skill/level/set_skill_value(datum/skill_holder/H, value, datum/mind/M, silent = FALSE)
|
||||
H.skills[type] = 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/level/standard_render_value(value, level)
|
||||
var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
var/current_lvl_xp_sum = 0
|
||||
if(level)
|
||||
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
|
||||
var/next_index = max(max_levels, level+1)
|
||||
var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
|
||||
if(next_lvl_xp > current_lvl_xp_sum)
|
||||
next_lvl_xp -= current_lvl_xp_sum
|
||||
|
||||
|
||||
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]"
|
||||
|
||||
/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/level/dwarfy
|
||||
abstract_type = /datum/skill/level/dwarfy
|
||||
standard_xp_lvl_up = DORF_XP_LVL_UP
|
||||
xp_lvl_multiplier = DORF_XP_LVL_MULTI
|
||||
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"
|
||||
|
||||
@@ -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.
|
||||
@@ -15,54 +23,139 @@
|
||||
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 LAZYACCESS(skills, skill)
|
||||
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, /datum/skill))
|
||||
CRASH("Invalid get_skill_value call. Use skill 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!!
|
||||
*/
|
||||
/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
|
||||
. = 1
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid get_skill_affinity call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/affinity = LAZYACCESS(skill_affinities, skill)
|
||||
if(isnull(affinity))
|
||||
return 1
|
||||
return affinity
|
||||
if(!isnull(affinity))
|
||||
. = affinity
|
||||
var/list/wrapped = list(.)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_SKILL_GET_AFFINITY, skill, wrapped)
|
||||
. = wrapped[1]
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
value = S.sanitize_value(value)
|
||||
if(!isnull(value))
|
||||
LAZYSET(skills, skill, value)
|
||||
LAZYINITLIST(skills)
|
||||
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)
|
||||
/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)
|
||||
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)
|
||||
if(!ispath(skill, /datum/skill/numerical))
|
||||
CRASH("You cannot auto increment a non numerical skill!")
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.")
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(S.progression_type != SKILL_PROGRESSION_NUMERICAL && S.progression_type != SKILL_PROGRESSION_LEVEL)
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
boost_skill_value_to(skill, current + (value * affinity))
|
||||
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)
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses one skill.
|
||||
* Args:
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * threshold : The difficulty of the action, in short. Refer to __DEFINES/skills/defines.dm for the defines.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/action_skills_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
|
||||
var/mod
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(!S)
|
||||
return
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
|
||||
|
||||
var/list/comsig_values = list(mod)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ACTION_SKILL_MOD, args, comsig_values)
|
||||
mod = comsig_values[MOD_VALUES_SKILL_MOD]
|
||||
|
||||
. = modifier_is_multiplier ? value*mod : value/mod
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses several skills, intended for items.
|
||||
* Args:
|
||||
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
|
||||
* * the value.
|
||||
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
|
||||
. = value
|
||||
var/sum = 0
|
||||
var/divisor = 0
|
||||
var/list/checked_skills
|
||||
for(var/k in I.used_skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[k]
|
||||
if(!S)
|
||||
continue
|
||||
var/our_flags = (I.used_skills[k]|S.skill_flags)
|
||||
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
|
||||
continue
|
||||
var/mod
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
|
||||
LAZYADD(checked_skills, S)
|
||||
|
||||
var/list/comsig_values = list(sum, divisor, checked_skills)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, args, comsig_values)
|
||||
sum = comsig_values[MOD_VALUES_ITEM_SKILLS_SUM]
|
||||
divisor = comsig_values[MOD_VALUES_ITEM_SKILLS_DIV]
|
||||
|
||||
if(divisor)
|
||||
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
|
||||
|
||||
/**
|
||||
* Generates a HTML readout of our skills.
|
||||
@@ -73,6 +166,6 @@
|
||||
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 += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]</td></tr>"
|
||||
out += "</table>"
|
||||
return out.Join("")
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/datum/skill/level/job/wiring
|
||||
name = "Wiring"
|
||||
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
|
||||
name_color = COLOR_PALE_ORANGE
|
||||
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
|
||||
@@ -1,3 +1,5 @@
|
||||
/datum/skill/numerical/surgery
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at doing surgery."
|
||||
name_color = COLOR_PALE_BLUE_GRAY
|
||||
competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
|
||||
|
||||
@@ -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,22 @@
|
||||
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)
|
||||
LAZYSET(current_users, user, TRUE)
|
||||
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))
|
||||
LAZYREMOVE(current_users, user)
|
||||
return FALSE
|
||||
LAZYREMOVE(current_users, user)
|
||||
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 +163,21 @@
|
||||
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)
|
||||
LAZYSET(current_users, user, TRUE)
|
||||
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))
|
||||
LAZYREMOVE(current_users, user)
|
||||
return FALSE
|
||||
LAZYREMOVE(current_users, user)
|
||||
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 +255,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 +290,16 @@
|
||||
if("cut")
|
||||
I = L.is_holding_tool_quality(TOOL_WIRECUTTER)
|
||||
if(I || IsAdminGhost(usr))
|
||||
if(I && holder)
|
||||
if(cut_color(target_wire, L) && 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,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(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/airlock
|
||||
holder_type = /obj/machinery/door/airlock
|
||||
proper_name = "Generic Airlock"
|
||||
req_skill = JOB_SKILL_UNTRAINED //Training wheel, as per request.
|
||||
var/wiretype
|
||||
|
||||
/datum/wires/airlock/secure
|
||||
@@ -52,10 +53,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,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,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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,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,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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,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(
|
||||
|
||||
+79
-73
@@ -11,7 +11,7 @@
|
||||
var/throw_range = 7
|
||||
var/mob/pulledby = null
|
||||
var/initial_language_holder = /datum/language_holder
|
||||
var/datum/language_holder/language_holder
|
||||
var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence.
|
||||
var/verb_say = "says"
|
||||
var/verb_ask = "asks"
|
||||
var/verb_exclaim = "exclaims"
|
||||
@@ -502,88 +502,94 @@
|
||||
animate(src, pixel_y = initial(pixel_y), time = 10)
|
||||
setMovetype(movement_type & ~FLOATING)
|
||||
|
||||
/* Language procs */
|
||||
/atom/movable/proc/get_language_holder(shadow=TRUE)
|
||||
if(language_holder)
|
||||
return language_holder
|
||||
else
|
||||
|
||||
/* Language procs
|
||||
* Unless you are doing something very specific, these are the ones you want to use.
|
||||
*/
|
||||
|
||||
/// Gets or creates the relevant language holder. For mindless atoms, gets the local one. For atom with mind, gets the mind one.
|
||||
/atom/movable/proc/get_language_holder(get_minds = TRUE)
|
||||
if(!language_holder)
|
||||
language_holder = new initial_language_holder(src)
|
||||
return language_holder
|
||||
return language_holder
|
||||
|
||||
/atom/movable/proc/grant_language(datum/language/dt, body = FALSE)
|
||||
var/datum/language_holder/H = get_language_holder(!body)
|
||||
H.grant_language(dt, body)
|
||||
/// Grants the supplied language and sets omnitongue true.
|
||||
/atom/movable/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ATOM)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.grant_language(language, understood, spoken, source)
|
||||
|
||||
/atom/movable/proc/grant_all_languages(omnitongue=FALSE)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.grant_all_languages(omnitongue)
|
||||
/// Grants every language.
|
||||
/atom/movable/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.grant_all_languages(understood, spoken, grant_omnitongue, source)
|
||||
|
||||
/// Removes a single language.
|
||||
/atom/movable/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.remove_language(language, understood, spoken, source)
|
||||
|
||||
/// Removes every language and sets omnitongue false.
|
||||
/atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.remove_all_languages(source, remove_omnitongue)
|
||||
|
||||
/// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later.
|
||||
/atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.add_blocked_language(language, source)
|
||||
|
||||
/// Removes a language from the blocked language list.
|
||||
/atom/movable/proc/remove_blocked_language(language, source = LANGUAGE_ATOM)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.remove_blocked_language(language, source)
|
||||
|
||||
/// Checks if atom has the language. If spoken is true, only checks if atom can speak the language.
|
||||
/atom/movable/proc/has_language(language, spoken = FALSE)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.has_language(language, spoken)
|
||||
|
||||
/// Checks if atom can speak the language.
|
||||
/atom/movable/proc/can_speak_language(language)
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.can_speak_language(language)
|
||||
|
||||
/// Returns the result of tongue specific limitations on spoken languages.
|
||||
/atom/movable/proc/could_speak_language(language)
|
||||
return TRUE
|
||||
|
||||
/// Returns selected language, if it can be spoken, or finds, sets and returns a new selected language if possible.
|
||||
/atom/movable/proc/get_selected_language()
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.get_selected_language()
|
||||
|
||||
/// Gets a random understood language, useful for hallucinations and such.
|
||||
/atom/movable/proc/get_random_understood_language()
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
. = H.get_random_understood_language()
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.get_random_understood_language()
|
||||
|
||||
/atom/movable/proc/remove_language(datum/language/dt, body = FALSE)
|
||||
var/datum/language_holder/H = get_language_holder(!body)
|
||||
H.remove_language(dt, body)
|
||||
/// Gets a random spoken language, useful for forced speech and such.
|
||||
/atom/movable/proc/get_random_spoken_language()
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.get_random_spoken_language()
|
||||
|
||||
/atom/movable/proc/remove_all_languages()
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.remove_all_languages()
|
||||
/// Copies all languages into the supplied atom/language holder. Source should be overridden when you
|
||||
/// do not want the language overwritten by later atom updates or want to avoid blocked languages.
|
||||
/atom/movable/proc/copy_languages(from_holder, source_override)
|
||||
if(isatom(from_holder))
|
||||
var/atom/movable/thing = from_holder
|
||||
from_holder = thing.get_language_holder()
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.copy_languages(from_holder, source_override)
|
||||
|
||||
/atom/movable/proc/has_language(datum/language/dt)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
. = H.has_language(dt)
|
||||
|
||||
/atom/movable/proc/copy_known_languages_from(thing, replace=FALSE)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
. = H.copy_known_languages_from(thing, replace)
|
||||
|
||||
// Whether an AM can speak in a language or not, independent of whether
|
||||
// it KNOWS the language
|
||||
/atom/movable/proc/could_speak_in_language(datum/language/dt)
|
||||
. = TRUE
|
||||
|
||||
/atom/movable/proc/can_speak_in_language(datum/language/dt)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
|
||||
if(!H.has_language(dt))
|
||||
return FALSE
|
||||
else if(H.omnitongue)
|
||||
return TRUE
|
||||
else if(could_speak_in_language(dt) && (!H.only_speaks_language || H.only_speaks_language == dt))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/get_default_language()
|
||||
// if no language is specified, and we want to say() something, which
|
||||
// language do we use?
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
|
||||
if(H.selected_default_language)
|
||||
if(can_speak_in_language(H.selected_default_language))
|
||||
return H.selected_default_language
|
||||
else
|
||||
H.selected_default_language = null
|
||||
|
||||
|
||||
var/datum/language/chosen_langtype
|
||||
var/highest_priority
|
||||
|
||||
for(var/lt in H.languages)
|
||||
var/datum/language/langtype = lt
|
||||
if(!can_speak_in_language(langtype))
|
||||
continue
|
||||
|
||||
var/pri = initial(langtype.default_priority)
|
||||
if(!highest_priority || (pri > highest_priority))
|
||||
chosen_langtype = langtype
|
||||
highest_priority = pri
|
||||
|
||||
H.selected_default_language = .
|
||||
. = chosen_langtype
|
||||
/// Empties out the atom specific languages and updates them according to the current atoms language holder.
|
||||
/// As a side effect, it also creates missing language holders in the process.
|
||||
/atom/movable/proc/update_atom_languages()
|
||||
var/datum/language_holder/LH = get_language_holder()
|
||||
return LH.update_atom_languages(src)
|
||||
|
||||
/* End language procs */
|
||||
|
||||
|
||||
/atom/movable/proc/ConveyorMove(movedir)
|
||||
set waitfor = FALSE
|
||||
if(!anchored && has_gravity())
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
if(player.assigned_role == job)
|
||||
candidates -= player
|
||||
|
||||
if(candidates.len < recommended_enemies)
|
||||
if(candidates.len < recommended_enemies && CONFIG_GET(keyed_list/force_antag_count)[config_tag])
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a separate list of people who don't want to be one
|
||||
|
||||
@@ -90,7 +90,10 @@
|
||||
sabotage_type = "cloner"
|
||||
|
||||
/datum/sabotage_objective/cloner/check_conditions()
|
||||
return !(locate(/obj/machinery/clonepod) in GLOB.machines)
|
||||
for(var/obj/machinery/clonepod/cloner in GLOB.machines)
|
||||
if(is_station_level(cloner.z))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/sabotage_objective/ai_law
|
||||
name = "Upload a hacked law to the AI."
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
var/list/L = list()
|
||||
var/list/LL = list()
|
||||
var/hacked = FALSE
|
||||
var/hackable = TRUE
|
||||
var/disabled = 0
|
||||
var/shocked = FALSE
|
||||
var/hack_wire
|
||||
@@ -32,7 +31,7 @@
|
||||
var/selected_category
|
||||
var/screen = 1
|
||||
|
||||
var/datum/techweb/stored_research = /datum/techweb/specialized/autounlocking/autolathe
|
||||
var/datum/techweb/specialized/autounlocking/stored_research = /datum/techweb/specialized/autounlocking/autolathe
|
||||
var/list/categories = list(
|
||||
"Tools",
|
||||
"Electronics",
|
||||
@@ -425,11 +424,11 @@
|
||||
|
||||
/obj/machinery/autolathe/proc/adjust_hacked(state)
|
||||
hacked = state
|
||||
if(!hackable && hacked)
|
||||
return
|
||||
for(var/id in SSresearch.techweb_designs)
|
||||
var/datum/design/D = SSresearch.techweb_design_by_id(id)
|
||||
if((D.build_type & AUTOLATHE) && ("hacked" in D.category))
|
||||
if(D.build_type & stored_research.design_autounlock_skip_types)
|
||||
continue
|
||||
if((D.build_type & stored_research.design_autounlock_buildtypes) && ("hacked" in D.category))
|
||||
if(hacked)
|
||||
stored_research.add_design(D)
|
||||
else
|
||||
@@ -441,8 +440,7 @@
|
||||
|
||||
/obj/machinery/autolathe/secure
|
||||
name = "secured autolathe"
|
||||
desc = "An autolathe reprogrammed with security protocols to prevent hacking."
|
||||
hackable = FALSE
|
||||
desc = "It produces items using metal and glass. This model was reprogrammed without some of the more hazardous designs."
|
||||
circuit = /obj/item/circuitboard/machine/autolathe/secure
|
||||
stored_research = /datum/techweb/specialized/autounlocking/autolathe/public
|
||||
base_print_speed = 20
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -396,7 +396,6 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.Impersonation = user
|
||||
|
||||
Hologram.copy_known_languages_from(user,replace = TRUE)
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
@@ -555,9 +554,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
Hologram.alpha = 170
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.dir = SOUTH //for now
|
||||
Hologram.grant_all_languages(omnitongue=TRUE)
|
||||
var/datum/language_holder/holder = Hologram.get_language_holder()
|
||||
holder.selected_default_language = record.language
|
||||
holder.selected_language = record.language
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
@@ -649,7 +647,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
return
|
||||
if(HOLORECORD_LANGUAGE)
|
||||
var/datum/language_holder/holder = replay_holo.get_language_holder()
|
||||
holder.selected_default_language = entry[2]
|
||||
holder.selected_language = entry[2]
|
||||
if(HOLORECORD_PRESET)
|
||||
var/preset_type = entry[2]
|
||||
var/datum/preset_holoimage/H = new preset_type
|
||||
@@ -672,6 +670,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
updateDialog()
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram
|
||||
initial_language_holder = /datum/language_holder/universal
|
||||
var/mob/living/Impersonation
|
||||
var/datum/holocall/HC
|
||||
|
||||
|
||||
@@ -114,7 +114,6 @@
|
||||
add_fingerprint(user)
|
||||
if(charging)
|
||||
charging.update_icon()
|
||||
charging.forceMove(drop_location())
|
||||
user.put_in_hands(charging)
|
||||
|
||||
/obj/machinery/recharger/attack_tk(mob/user)
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
obj/source, // the originating radio
|
||||
frequency, // the frequency the signal is taking place on
|
||||
atom/movable/virtualspeaker/speaker, // representation of the method's speaker
|
||||
datum/language/language, // the langauge of the message
|
||||
datum/language/language, // the language of the message
|
||||
message, // the text content of the message
|
||||
spans // the list of spans applied to the message
|
||||
)
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
////////////////////////////////
|
||||
/datum/component/construction/mecha
|
||||
var/base_icon
|
||||
var/looky_helpy = TRUE
|
||||
|
||||
/datum/component/construction/mecha/examine(mob/user)
|
||||
. = ..()
|
||||
if(looky_helpy)
|
||||
switch(steps[index]["key"])
|
||||
if(TOOL_WRENCH)
|
||||
. += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
|
||||
if(TOOL_SCREWDRIVER)
|
||||
. += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
|
||||
if(TOOL_WIRECUTTER)
|
||||
. += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
|
||||
if(/obj/item/stack/cable_coil)
|
||||
. += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
|
||||
if(/obj/item/circuitboard)
|
||||
. += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
|
||||
if(/obj/item/stock_parts/scanning_module)
|
||||
. += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/capacitor)
|
||||
. += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/cell)
|
||||
. += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
|
||||
if(/obj/item/stack/sheet/metal)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
|
||||
if(/obj/item/stack/sheet/plasteel)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
|
||||
if(/obj/item/bikehorn)
|
||||
. += "<span class='notice'>HONK IT!.</span>"
|
||||
if(/obj/item/clothing/mask/gas/clown_hat)
|
||||
. += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
|
||||
if(/obj/item/clothing/shoes/clown_shoes)
|
||||
. += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
|
||||
if(/obj/item/mecha_parts/part)
|
||||
. += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
|
||||
if(/obj/item/stack/ore/bluespace_crystal)
|
||||
. += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
|
||||
if(/obj/item/assembly/signaler/anomaly)
|
||||
. += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
|
||||
else
|
||||
return
|
||||
|
||||
/datum/component/construction/mecha/spawn_result()
|
||||
if(!result)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
|
||||
var/list/datum/skill/used_skills
|
||||
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)
|
||||
delay = user.mind.skill_holder.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
|
||||
|
||||
// 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,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
if(delay >= MIN_TOOL_SOUND_DELAY)
|
||||
play_tool_sound(target, volume)
|
||||
|
||||
if(user.mind && used_skills && skill_gain_mult)
|
||||
for(var/skill in used_skills)
|
||||
if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(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.
|
||||
|
||||
@@ -6,17 +6,42 @@
|
||||
icon_state = "cutout_basic"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
resistance_flags = FLAMMABLE
|
||||
// Possible restyles for the cutout;
|
||||
// add an entry in change_appearance() if you add to here
|
||||
var/list/possible_appearances = list("Assistant", "Clown", "Mime",
|
||||
"Traitor", "Nuke Op", "Cultist", "Brass Cultist", "Clockwork Cultist",
|
||||
"Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Xenomorph Maid", "Swarmer",
|
||||
"Ash Walker", "Deathsquad Officer", "Ian", "Slaughter Demon",
|
||||
"Laughter Demon", "Private Security Officer", "Securitron", "Gondola", "Monkey")
|
||||
var/pushed_over = FALSE //If the cutout is pushed over and has to be righted
|
||||
var/deceptive = FALSE //If the cutout actually appears as what it portray and not a discolored version
|
||||
/// Possible restyles for the cutout, add an entry in change_appearance() if you add to here
|
||||
var/static/list/possible_appearances
|
||||
/// If the cutout is pushed over and has to be righted
|
||||
var/pushed_over = FALSE
|
||||
/// If the cutout actually appears as what it portray and not a discolored version
|
||||
var/deceptive = FALSE
|
||||
|
||||
var/lastattacker = null
|
||||
/obj/item/cardboard_cutout/Initialize()
|
||||
. = ..()
|
||||
if(possible_appearances)
|
||||
return
|
||||
possible_appearances = sortList(list(
|
||||
"Assistant" = image(icon = src.icon, icon_state = "cutout_greytide"),
|
||||
"Clown" = image(icon = src.icon, icon_state = "cutout_clown"),
|
||||
"Mime" = image(icon = src.icon, icon_state = "cutout_mime"),
|
||||
"Traitor" = image(icon = src.icon, icon_state = "cutout_traitor"),
|
||||
"Nuke Op" = image(icon = src.icon, icon_state = "cutout_fluke"),
|
||||
"Cultist" = image(icon = src.icon, icon_state = "cutout_cultist"),
|
||||
"Brass Cultist" = image(icon = src.icon, icon_state = "cutout_servant"),
|
||||
"Clockwork Cultist" = image(icon = src.icon, icon_state = "cutout_new_servant"),
|
||||
"Revolutionary" = image(icon = src.icon, icon_state = "cutout_viva"),
|
||||
"Wizard" = image(icon = src.icon, icon_state = "cutout_wizard"),
|
||||
"Shadowling" = image(icon = src.icon, icon_state = "cutout_shadowling"),
|
||||
"Xenomorph" = image(icon = src.icon, icon_state = "cutout_fukken_xeno"),
|
||||
"Xenomorph Maid" = image(icon = src.icon, icon_state = "cutout_lusty"),
|
||||
"Swarmer" = image(icon = src.icon, icon_state = "cutout_swarmer"),
|
||||
"Ash Walker" = image(icon = src.icon, icon_state = "cutout_free_antag"),
|
||||
"Deathsquad Officer" = image(icon = src.icon, icon_state = "cutout_deathsquad"),
|
||||
"Ian" = image(icon = src.icon, icon_state = "cutout_ian"),
|
||||
"Slaughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "daemon"),
|
||||
"Laughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "bowmon"),
|
||||
"Private Security Officer" = image(icon = src.icon, icon_state = "cutout_ntsec"),
|
||||
"Securitron" = image(icon = src.icon, icon_state = "cutout_law"),
|
||||
"Gondola" = image(icon = src.icon, icon_state = "cutout_gondola"),
|
||||
"Monkey" = image(icon = src.icon, icon_state = "cutout_monky"),
|
||||
))
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/cardboard_cutout/attack_hand(mob/living/user)
|
||||
@@ -76,22 +101,21 @@
|
||||
push_over()
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/**
|
||||
* change_appearance: Changes a skin of the cardboard cutout based on a user's choice
|
||||
*
|
||||
* Arguments:
|
||||
* * crayon The crayon used to change and recolor the cardboard cutout
|
||||
* * user The mob choosing a skin of the cardboard cutout
|
||||
*/
|
||||
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
|
||||
if(!crayon || !user)
|
||||
return
|
||||
if(pushed_over)
|
||||
to_chat(user, "<span class='warning'>Right [src] first!</span>")
|
||||
return
|
||||
if(crayon.check_empty(user))
|
||||
return
|
||||
if(crayon.is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return
|
||||
var/new_appearance = input(user, "Choose a new appearance for [src].", "26th Century Deception") as null|anything in possible_appearances
|
||||
if(!new_appearance || !crayon || !user.canUseTopic(src))
|
||||
var/new_appearance = show_radial_menu(user, src, possible_appearances, custom_check = CALLBACK(src, .proc/check_menu, user, crayon), radius = 36, require_near = TRUE)
|
||||
if(!new_appearance)
|
||||
return
|
||||
if(!do_after(user, 10, FALSE, src, TRUE))
|
||||
return
|
||||
return FALSE
|
||||
if(!check_menu(user, crayon))
|
||||
return FALSE
|
||||
user.visible_message("<span class='notice'>[user] gives [src] a new look.</span>", "<span class='notice'>Voila! You give [src] a new look.</span>")
|
||||
crayon.use_charges(1)
|
||||
crayon.check_empty(user)
|
||||
@@ -196,7 +220,33 @@
|
||||
name = "monkey ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a monkey."
|
||||
icon_state = "cutout_monky"
|
||||
return 1
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
* * crayon The crayon used to interact with a menu
|
||||
*/
|
||||
/obj/item/cardboard_cutout/proc/check_menu(mob/living/user, obj/item/toy/crayon/crayon)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(pushed_over)
|
||||
to_chat(user, "<span class='warning'>Right [src] first!</span>")
|
||||
return FALSE
|
||||
if(!crayon || !user.is_holding(crayon))
|
||||
return FALSE
|
||||
if(crayon.check_empty(user))
|
||||
return FALSE
|
||||
if(crayon.is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/cardboard_cutout/setDir(newdir)
|
||||
dir = SOUTH
|
||||
|
||||
@@ -199,7 +199,7 @@
|
||||
if(!spans)
|
||||
spans = list(M.speech_span)
|
||||
if(!language)
|
||||
language = M.get_default_language()
|
||||
language = M.get_selected_language()
|
||||
INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
custom_materials = list(/datum/material/iron=150, /datum/material/glass=75)
|
||||
breakouttime = 300 //Deciseconds = 30s
|
||||
cuffsound = 'sound/weapons/cablecuff.ogg'
|
||||
cuffsound = 'sound/weapons/cablecuff.ogg'
|
||||
|
||||
/obj/item/restraints/handcuffs/cable/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You start unwinding the cable restraints back into coil</span>")
|
||||
@@ -130,7 +130,7 @@
|
||||
user.put_in_hands(coil)
|
||||
coil.color = color
|
||||
to_chat(user, "<span class='notice'>You unwind the cable restraints back into coil</span>")
|
||||
|
||||
|
||||
/obj/item/restraints/handcuffs/cable/red
|
||||
color = "#ff0000"
|
||||
|
||||
@@ -225,7 +225,6 @@
|
||||
/obj/item/restraints/handcuffs/fake/kinky
|
||||
name = "kinky handcuffs"
|
||||
desc = "Fake handcuffs meant for erotic roleplay."
|
||||
icon = 'modular_citadel/icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "handcuffgag"
|
||||
item_state = "kinkycuff"
|
||||
|
||||
@@ -252,7 +251,7 @@
|
||||
throw_range = 1
|
||||
icon_state = "beartrap"
|
||||
desc = "A trap used to catch bears and other legged creatures."
|
||||
var/armed = 0
|
||||
var/armed = FALSE
|
||||
var/trap_damage = 20
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/Initialize()
|
||||
@@ -275,14 +274,14 @@
|
||||
if(armed && isturf(src.loc))
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
var/snap = 0
|
||||
var/snap = FALSE
|
||||
var/def_zone = BODY_ZONE_CHEST
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
snap = 1
|
||||
if(!C.lying)
|
||||
def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
if(!C.legcuffed && C.get_num_legs(FALSE) >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
|
||||
snap = TRUE
|
||||
C.legcuffed = src
|
||||
forceMove(C)
|
||||
C.update_equipment_speed_mods()
|
||||
@@ -291,21 +290,21 @@
|
||||
else if(isanimal(L))
|
||||
var/mob/living/simple_animal/SA = L
|
||||
if(SA.mob_size > MOB_SIZE_TINY)
|
||||
snap = 1
|
||||
if(L.movement_type & FLYING)
|
||||
snap = 0
|
||||
snap = TRUE
|
||||
if(L.movement_type & (FLYING | FLOATING))
|
||||
snap = FALSE
|
||||
if(snap)
|
||||
armed = 0
|
||||
armed = FALSE
|
||||
icon_state = "[initial(icon_state)][armed]"
|
||||
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
L.visible_message("<span class='danger'>[L] triggers \the [src].</span>", \
|
||||
"<span class='userdanger'>You trigger \the [src]!</span>")
|
||||
L.apply_damage(trap_damage,BRUTE, def_zone)
|
||||
L.apply_damage(trap_damage, BRUTE, def_zone)
|
||||
..()
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/energy
|
||||
name = "energy snare"
|
||||
armed = 1
|
||||
armed = TRUE
|
||||
icon_state = "e_snare"
|
||||
trap_damage = 0
|
||||
item_flags = DROPDEL
|
||||
|
||||
@@ -519,7 +519,9 @@
|
||||
S.name = name
|
||||
S.ckey = C.ckey
|
||||
S.status_flags |= GODMODE
|
||||
S.language_holder = user.language_holder.copy(S)
|
||||
S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user.
|
||||
S.update_atom_languages()
|
||||
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
|
||||
S.AddElement(/datum/element/ghost_role_eligibility,penalize_on_ghost = TRUE)
|
||||
START_PROCESSING(SSprocessing,src)
|
||||
var/input = stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN)
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
return
|
||||
else
|
||||
if(cooldown_check < world.time)
|
||||
if(target.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS)
|
||||
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS)
|
||||
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return
|
||||
if(ishuman(target))
|
||||
@@ -325,7 +325,7 @@
|
||||
else
|
||||
target.LAssailant = WEAKREF(user)
|
||||
cooldown_check = world.time + cooldown
|
||||
user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes swinging batons cost stamina
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT))
|
||||
else
|
||||
var/wait_desc = get_wait_description()
|
||||
if(wait_desc)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/charge_cost = 30
|
||||
|
||||
/obj/item/borg/stun/attack(mob/living/M, mob/living/user)
|
||||
if(M.run_block(src, 0, "[M]'s [name]", ATTACK_TYPE_MELEE, 0, user, ran_zone(user.zone_selected)) & BLOCK_SUCCESS)
|
||||
if(M.mob_run_block(src, 0, "[M]'s [name]", ATTACK_TYPE_MELEE, 0, user, ran_zone(user.zone_selected), null) & BLOCK_SUCCESS)
|
||||
playsound(M, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
if(iscyborg(user))
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
self_delay = 20
|
||||
grind_results = list(/datum/reagent/medicine/styptic_powder = 10)
|
||||
|
||||
/obj/item/stack/medical/bruise_pack/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/bruise_pack/heal(mob/living/M, mob/user)
|
||||
if(M.stat == DEAD)
|
||||
to_chat(user, "<span class='notice'> [M] is dead. You can not help [M.p_them()]!</span>")
|
||||
@@ -134,6 +137,9 @@
|
||||
singular_name = "sterilized medical gauze"
|
||||
self_delay = 5
|
||||
|
||||
/obj/item/stack/medical/gauze/adv/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/gauze/cyborg
|
||||
custom_materials = null
|
||||
is_cyborg = 1
|
||||
@@ -151,6 +157,9 @@
|
||||
self_delay = 20
|
||||
grind_results = list(/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
|
||||
/obj/item/stack/medical/ointment/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
|
||||
if(M.stat == DEAD)
|
||||
to_chat(user, "<span class='notice'> [M] is dead. You can not help [M.p_them()]!</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)
|
||||
|
||||
@@ -850,12 +850,6 @@
|
||||
|
||||
|
||||
|
||||
#define NODESIGN "None"
|
||||
#define NANOTRASEN "NanotrasenStandard"
|
||||
#define SYNDI "SyndiSnacks"
|
||||
#define HEART "Heart"
|
||||
#define SMILEY "SmileyFace"
|
||||
|
||||
/obj/item/storage/box/papersack
|
||||
name = "paper sack"
|
||||
desc = "A sack neatly crafted out of paper."
|
||||
@@ -863,7 +857,18 @@
|
||||
item_state = "paperbag_None"
|
||||
resistance_flags = FLAMMABLE
|
||||
foldable = null
|
||||
var/design = NODESIGN
|
||||
/// A list of all available papersack reskins
|
||||
var/list/papersack_designs = list()
|
||||
|
||||
/obj/item/storage/box/papersack/Initialize(mapload)
|
||||
. = ..()
|
||||
papersack_designs = sortList(list(
|
||||
"None" = image(icon = src.icon, icon_state = "paperbag_None"),
|
||||
"NanotrasenStandard" = image(icon = src.icon, icon_state = "paperbag_NanotrasenStandard"),
|
||||
"SyndiSnacks" = image(icon = src.icon, icon_state = "paperbag_SyndiSnacks"),
|
||||
"Heart" = image(icon = src.icon, icon_state = "paperbag_Heart"),
|
||||
"SmileyFace" = image(icon = src.icon, icon_state = "paperbag_SmileyFace")
|
||||
))
|
||||
|
||||
/obj/item/storage/box/papersack/update_icon_state()
|
||||
if(contents.len == 0)
|
||||
@@ -871,55 +876,64 @@
|
||||
else
|
||||
icon_state = "[item_state]_closed"
|
||||
|
||||
|
||||
/obj/item/storage/box/papersack/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/pen))
|
||||
//if a pen is used on the sack, dialogue to change its design appears
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='warning'>You can't modify [src] with items still inside!</span>")
|
||||
return
|
||||
var/list/designs = list(NODESIGN, NANOTRASEN, SYNDI, HEART, SMILEY, "Cancel")
|
||||
var/switchDesign = input("Select a Design:", "Paper Sack Design", designs[1]) in designs
|
||||
if(get_dist(usr, src) > 1)
|
||||
to_chat(usr, "<span class='warning'>You have moved too far away!</span>")
|
||||
return
|
||||
var/choice = designs.Find(switchDesign)
|
||||
if(design == designs[choice] || designs[choice] == "Cancel")
|
||||
return 0
|
||||
to_chat(usr, "<span class='notice'>You make some modifications to [src] using your pen.</span>")
|
||||
design = designs[choice]
|
||||
icon_state = "paperbag_[design]"
|
||||
item_state = "paperbag_[design]"
|
||||
switch(designs[choice])
|
||||
if(NODESIGN)
|
||||
var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, .proc/check_menu, user, W), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
if(icon_state == "paperbag_[choice]")
|
||||
return FALSE
|
||||
switch(choice)
|
||||
if("None")
|
||||
desc = "A sack neatly crafted out of paper."
|
||||
if(NANOTRASEN)
|
||||
if("NanotrasenStandard")
|
||||
desc = "A standard Nanotrasen paper lunch sack for loyal employees on the go."
|
||||
if(SYNDI)
|
||||
if("SyndiSnacks")
|
||||
desc = "The design on this paper sack is a remnant of the notorious 'SyndieSnacks' program."
|
||||
if(HEART)
|
||||
if("Heart")
|
||||
desc = "A paper sack with a heart etched onto the side."
|
||||
if(SMILEY)
|
||||
if("SmileyFace")
|
||||
desc = "A paper sack with a crude smile etched onto the side."
|
||||
return 0
|
||||
else
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You make some modifications to [src] using your pen.</span>")
|
||||
icon_state = "paperbag_[choice]"
|
||||
item_state = "paperbag_[choice]"
|
||||
return FALSE
|
||||
else if(W.get_sharpness())
|
||||
if(!contents.len)
|
||||
if(item_state == "paperbag_None")
|
||||
user.show_message("<span class='notice'>You cut eyeholes into [src].</span>", MSG_VISUAL)
|
||||
new /obj/item/clothing/head/papersack(user.loc)
|
||||
qdel(src)
|
||||
return 0
|
||||
return FALSE
|
||||
else if(item_state == "paperbag_SmileyFace")
|
||||
user.show_message("<span class='notice'>You cut eyeholes into [src] and modify the design.</span>", MSG_VISUAL)
|
||||
new /obj/item/clothing/head/papersack/smiley(user.loc)
|
||||
qdel(src)
|
||||
return 0
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
#undef NODESIGN
|
||||
#undef NANOTRASEN
|
||||
#undef SYNDI
|
||||
#undef HEART
|
||||
#undef SMILEY
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
* * P The pen used to interact with a menu
|
||||
*/
|
||||
/obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='warning'>You can't modify [src] with items still inside!</span>")
|
||||
return FALSE
|
||||
if(!P || !user.is_holding(P))
|
||||
to_chat(user, "<span class='warning'>You need a pen to modify [src]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist.
|
||||
name = "ingredients box"
|
||||
|
||||
@@ -163,14 +163,14 @@
|
||||
if(status)
|
||||
if(baton_stun(M, user, disarming))
|
||||
user.do_attack_animation(M)
|
||||
user.adjustStaminaLossBuffered(getweight()) //CIT CHANGE - makes stunbatonning others cost stamina
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT))
|
||||
else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc.
|
||||
M.visible_message("<span class='warning'>[user] has prodded [M] with [src]. Luckily it was off.</span>", \
|
||||
"<span class='warning'>[user] has prodded you with [src]. Luckily it was off</span>")
|
||||
return disarming || (user.a_intent != INTENT_HARM)
|
||||
|
||||
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE)
|
||||
if(L.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; check_shields() handles that
|
||||
if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; check_shields() handles that
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
var/stunpwr = stamforce
|
||||
@@ -232,11 +232,8 @@
|
||||
/obj/item/melee/baton/stunsword
|
||||
name = "stunsword"
|
||||
desc = "not actually sharp, this sword is functionally identical to a stunbaton"
|
||||
icon = 'modular_citadel/icons/obj/stunsword.dmi'
|
||||
icon_state = "stunsword"
|
||||
item_state = "sword"
|
||||
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
|
||||
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
|
||||
|
||||
/obj/item/melee/baton/stunsword/get_belt_overlay()
|
||||
if(istype(loc, /obj/item/storage/belt/sabre))
|
||||
|
||||
@@ -241,11 +241,13 @@
|
||||
playsound(user, activation_sound, transform_volume, 1)
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
AddElement(/datum/element/sword_point)
|
||||
total_mass = total_mass_on
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[deactivation_message]</span>")
|
||||
playsound(user, deactivation_sound, transform_volume, 1)
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
RemoveElement(/datum/element/sword_point)
|
||||
total_mass = initial(total_mass)
|
||||
|
||||
update_icon()
|
||||
add_fingerprint(user)
|
||||
@@ -287,9 +289,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/sword/getweight()
|
||||
return (active ? total_mass_on : total_mass) || w_class *1.25
|
||||
|
||||
/obj/item/toy/sword/cx
|
||||
name = "\improper DX Non-Euplastic LightSword"
|
||||
desc = "A deluxe toy replica of an energy sword. Realistic visuals and sounds! Ages 8 and up."
|
||||
@@ -903,79 +902,57 @@
|
||||
name = "hand of cards"
|
||||
desc = "A number of cards not in a deck, customarily held in ones hand."
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "nanotrasen_hand2"
|
||||
icon_state = "none"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/list/currenthand = list()
|
||||
var/choice = null
|
||||
|
||||
|
||||
/obj/item/toy/cards/cardhand/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/list/handradial = list()
|
||||
interact(user)
|
||||
|
||||
/obj/item/toy/cards/cardhand/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat = "You have:<BR>"
|
||||
for(var/t in currenthand)
|
||||
dat += "<A href='?src=[REF(src)];pick=[t]'>A [t].</A><BR>"
|
||||
dat += "Which card will you remove next?"
|
||||
var/datum/browser/popup = new(user, "cardhand", "Hand of Cards", 400, 240)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
handradial[t] = image(icon = src.icon, icon_state = "sc_[t]_[deckstyle]")
|
||||
|
||||
|
||||
/obj/item/toy/cards/cardhand/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(usr.stat || !ishuman(usr))
|
||||
return
|
||||
var/mob/living/carbon/human/cardUser = usr
|
||||
var/O = src
|
||||
if(href_list["pick"])
|
||||
if (cardUser.is_holding(src))
|
||||
var/choice = href_list["pick"]
|
||||
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
|
||||
src.currenthand -= choice
|
||||
C.parentdeck = src.parentdeck
|
||||
C.cardname = choice
|
||||
C.apply_card_vars(C,O)
|
||||
C.pickup(cardUser)
|
||||
cardUser.put_in_hands(C)
|
||||
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
|
||||
|
||||
interact(cardUser)
|
||||
if(src.currenthand.len < 3)
|
||||
src.icon_state = "[deckstyle]_hand2"
|
||||
else if(src.currenthand.len < 4)
|
||||
src.icon_state = "[deckstyle]_hand3"
|
||||
else if(src.currenthand.len < 5)
|
||||
src.icon_state = "[deckstyle]_hand4"
|
||||
if(src.currenthand.len == 1)
|
||||
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(src.loc)
|
||||
N.parentdeck = src.parentdeck
|
||||
N.cardname = src.currenthand[1]
|
||||
N.apply_card_vars(N,O)
|
||||
qdel(src)
|
||||
N.pickup(cardUser)
|
||||
cardUser.put_in_hands(N)
|
||||
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
|
||||
cardUser << browse(null, "window=cardhand")
|
||||
if(!(cardUser.mobility_flags & MOBILITY_USE))
|
||||
return
|
||||
var/O = src
|
||||
var/choice = show_radial_menu(usr,src, handradial, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
|
||||
currenthand -= choice
|
||||
handradial -= choice
|
||||
C.parentdeck = parentdeck
|
||||
C.cardname = choice
|
||||
C.apply_card_vars(C,O)
|
||||
C.pickup(cardUser)
|
||||
cardUser.put_in_hands(C)
|
||||
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
|
||||
|
||||
interact(cardUser)
|
||||
update_sprite()
|
||||
if(length(currenthand) == 1)
|
||||
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(loc)
|
||||
N.parentdeck = parentdeck
|
||||
N.cardname = currenthand[1]
|
||||
N.apply_card_vars(N,O)
|
||||
qdel(src)
|
||||
N.pickup(cardUser)
|
||||
cardUser.put_in_hands(N)
|
||||
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
|
||||
|
||||
/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params)
|
||||
if(istype(C))
|
||||
if(C.parentdeck == src.parentdeck)
|
||||
src.currenthand += C.cardname
|
||||
user.visible_message("[user] adds a card to [user.p_their()] hand.", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
|
||||
user.visible_message("<span class='notice'>[user] adds a card to [user.p_their()] hand.</span>", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
|
||||
qdel(C)
|
||||
interact(user)
|
||||
if(currenthand.len > 4)
|
||||
src.icon_state = "[deckstyle]_hand5"
|
||||
else if(currenthand.len > 3)
|
||||
src.icon_state = "[deckstyle]_hand4"
|
||||
else if(currenthand.len > 2)
|
||||
src.icon_state = "[deckstyle]_hand3"
|
||||
update_sprite(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
else
|
||||
@@ -984,7 +961,7 @@
|
||||
/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj)
|
||||
..()
|
||||
newobj.deckstyle = sourceobj.deckstyle
|
||||
newobj.icon_state = "[deckstyle]_hand2" // Another dumb hack, without this the hand is invisible (or has the default deckstyle) until another card is added.
|
||||
update_sprite()
|
||||
newobj.card_hitsound = sourceobj.card_hitsound
|
||||
newobj.card_force = sourceobj.card_force
|
||||
newobj.card_throwforce = sourceobj.card_throwforce
|
||||
@@ -993,6 +970,31 @@
|
||||
newobj.card_attack_verb = sourceobj.card_attack_verb
|
||||
newobj.resistance_flags = sourceobj.resistance_flags
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
*/
|
||||
/obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* This proc updates the sprite for when you create a hand of cards
|
||||
*/
|
||||
/obj/item/toy/cards/cardhand/proc/update_sprite()
|
||||
cut_overlays()
|
||||
var/overlay_cards = currenthand.len
|
||||
|
||||
var/k = overlay_cards == 2 ? 1 : overlay_cards - 2
|
||||
for(var/i = k; i <= overlay_cards; i++)
|
||||
var/card_overlay = image(icon=src.icon,icon_state="sc_[currenthand[i]]_[deckstyle]",pixel_x=(1-i+k)*3,pixel_y=(1-i+k)*3)
|
||||
add_overlay(card_overlay)
|
||||
|
||||
/obj/item/toy/cards/singlecard
|
||||
name = "card"
|
||||
desc = "a card"
|
||||
|
||||
@@ -1182,7 +1182,7 @@
|
||||
if(iscyborg(target))
|
||||
..()
|
||||
return
|
||||
if(target.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; run_block() handles that
|
||||
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; run_block() handles that
|
||||
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
if(user.a_intent != INTENT_HARM)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
new_spawn.undershirt = "Nude" //changing underwear/shirt/socks doesn't seem to function correctly right now because of some bug elsewhere?
|
||||
new_spawn.socks = "Nude"
|
||||
new_spawn.update_body(TRUE)
|
||||
new_spawn.language_holder.selected_language = /datum/language/sylvan
|
||||
|
||||
//Ash walker eggs: Spawns in ash walker dens in lavaland. Ghosts become unbreathing lizards that worship the Necropolis and are advised to retrieve corpses to create more ash walkers.
|
||||
|
||||
@@ -63,10 +64,6 @@
|
||||
else
|
||||
to_chat(new_spawn, "<span class='userdanger'>You have been born outside of your natural home! Whether you decide to return home, or make due with your new home is your own decision.</span>")
|
||||
|
||||
new_spawn.grant_language(/datum/language/draconic)
|
||||
var/datum/language_holder/holder = new_spawn.get_language_holder()
|
||||
holder.selected_default_language = /datum/language/draconic
|
||||
|
||||
//Ash walkers on birth understand how to make bone bows, bone arrows and ashen arrows
|
||||
|
||||
new_spawn.mind.teach_crafting_recipe(/datum/crafting_recipe/bone_arrow)
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
/obj/structure/janitorialcart/proc/put_in_cart(obj/item/I, mob/user)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
updateUsrDialog()
|
||||
to_chat(user, "<span class='notice'>You put [I] into [src].</span>")
|
||||
return
|
||||
|
||||
@@ -96,70 +95,82 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
|
||||
var/list/items = list()
|
||||
if(mybag)
|
||||
dat += "<a href='?src=[REF(src)];garbage=1'>[mybag.name]</a><br>"
|
||||
items += list("Trash bag" = image(icon = mybag.icon, icon_state = mybag.icon_state))
|
||||
if(mymop)
|
||||
dat += "<a href='?src=[REF(src)];mop=1'>[mymop.name]</a><br>"
|
||||
items += list("Mop" = image(icon = mymop.icon, icon_state = mymop.icon_state))
|
||||
if(mybroom)
|
||||
dat += "<a href='?src=[REF(src)];broom=1'>[mybroom.name]</a><br>"
|
||||
items += list("Broom" = image(icon = mybroom.icon, icon_state = mybroom.icon_state))
|
||||
if(myspray)
|
||||
dat += "<a href='?src=[REF(src)];spray=1'>[myspray.name]</a><br>"
|
||||
items += list("Spray bottle" = image(icon = myspray.icon, icon_state = myspray.icon_state))
|
||||
if(myreplacer)
|
||||
dat += "<a href='?src=[REF(src)];replacer=1'>[myreplacer.name]</a><br>"
|
||||
if(signs)
|
||||
dat += "<a href='?src=[REF(src)];sign=1'>[signs] sign\s</a><br>"
|
||||
var/datum/browser/popup = new(user, "janicart", name, 240, 160)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
items += list("Light replacer" = image(icon = myreplacer.icon, icon_state = myreplacer.icon_state))
|
||||
var/obj/item/caution/sign = locate() in src
|
||||
if(sign)
|
||||
items += list("Sign" = image(icon = sign.icon, icon_state = sign.icon_state))
|
||||
|
||||
|
||||
/obj/structure/janitorialcart/Topic(href, href_list)
|
||||
if(!in_range(src, usr))
|
||||
if(!length(items))
|
||||
return
|
||||
if(!isliving(usr))
|
||||
items = sortList(items)
|
||||
var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 38, require_near = TRUE)
|
||||
if(!pick)
|
||||
return
|
||||
var/mob/living/user = usr
|
||||
if(href_list["garbage"])
|
||||
if(mybag)
|
||||
switch(pick)
|
||||
if("Trash bag")
|
||||
if(!mybag)
|
||||
return
|
||||
user.put_in_hands(mybag)
|
||||
to_chat(user, "<span class='notice'>You take [mybag] from [src].</span>")
|
||||
mybag = null
|
||||
if(href_list["mop"])
|
||||
if(mymop)
|
||||
if("Mop")
|
||||
if(!mymop)
|
||||
return
|
||||
user.put_in_hands(mymop)
|
||||
to_chat(user, "<span class='notice'>You take [mymop] from [src].</span>")
|
||||
mymop = null
|
||||
if(href_list["broom"])
|
||||
if(mybroom)
|
||||
if("Broom")
|
||||
if(!mybroom)
|
||||
return
|
||||
user.put_in_hands(mybroom)
|
||||
to_chat(user, "<span class='notice'>You take [mybroom] from [src].</span>")
|
||||
mybroom = null
|
||||
if(href_list["spray"])
|
||||
if(myspray)
|
||||
if("Spray bottle")
|
||||
if(!myspray)
|
||||
return
|
||||
user.put_in_hands(myspray)
|
||||
to_chat(user, "<span class='notice'>You take [myspray] from [src].</span>")
|
||||
myspray = null
|
||||
if(href_list["replacer"])
|
||||
if(myreplacer)
|
||||
if("Light replacer")
|
||||
if(!myreplacer)
|
||||
return
|
||||
user.put_in_hands(myreplacer)
|
||||
to_chat(user, "<span class='notice'>You take [myreplacer] from [src].</span>")
|
||||
myreplacer = null
|
||||
if(href_list["sign"])
|
||||
if(signs)
|
||||
var/obj/item/caution/Sign = locate() in src
|
||||
if(Sign)
|
||||
user.put_in_hands(Sign)
|
||||
to_chat(user, "<span class='notice'>You take \a [Sign] from [src].</span>")
|
||||
signs--
|
||||
else
|
||||
WARNING("Signs ([signs]) didn't match contents")
|
||||
signs = 0
|
||||
if("Sign")
|
||||
if(signs <= 0)
|
||||
return
|
||||
user.put_in_hands(sign)
|
||||
to_chat(user, "<span class='notice'>You take \a [sign] from [src].</span>")
|
||||
signs--
|
||||
else
|
||||
return
|
||||
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
*/
|
||||
/obj/structure/janitorialcart/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/janitorialcart/update_overlays()
|
||||
. = ..()
|
||||
|
||||
@@ -91,8 +91,13 @@
|
||||
if (!is_ghost && !in_range(src, user))
|
||||
return
|
||||
|
||||
var/list/tool_list = list(
|
||||
"Up" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH),
|
||||
"Down" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH)
|
||||
)
|
||||
|
||||
if (up && down)
|
||||
var/result = alert("Go up or down [src]?", "Ladder", "Up", "Down", "Cancel")
|
||||
var/result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
|
||||
if (!is_ghost && !in_range(src, user))
|
||||
return // nice try
|
||||
switch(result)
|
||||
@@ -112,6 +117,11 @@
|
||||
if(!is_ghost)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/structure/ladder/proc/check_menu(mob/user)
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ladder/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
|
||||
@@ -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>")
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
return
|
||||
spans |= speech_span
|
||||
if(!language)
|
||||
language = get_default_language()
|
||||
language = get_selected_language()
|
||||
send_speech(message, 7, src, , spans, message_language=language)
|
||||
|
||||
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
|
||||
user.do_attack_animation(L)
|
||||
|
||||
if(L.run_block(src, 0, "[user]'s [src]", ATTACK_TYPE_MELEE, 0, user, check_zone(user.zone_selected)) & BLOCK_SUCCESS)
|
||||
if(L.mob_run_block(src, 0, "[user]'s [src]", ATTACK_TYPE_MELEE, 0, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS)
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
owner.faction |= "slime"
|
||||
owner.grant_language(/datum/language/slime)
|
||||
owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
owner.faction -= "slime"
|
||||
owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel nauseated!</span>")
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
/obj/item/organ/heart/gland/trauma/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel a spike of pain in your head.</span>")
|
||||
if(prob(33))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_SURGERY))
|
||||
else
|
||||
if(prob(20))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_SURGERY))
|
||||
else
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
|
||||
owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_SURGERY))
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
var/poweron_feed = FALSE // Am I feeding?
|
||||
var/poweron_masquerade = FALSE
|
||||
// STATS
|
||||
var/bloodsucker_level
|
||||
var/bloodsucker_level
|
||||
var/bloodsucker_level_unspent = 1
|
||||
var/regen_rate = 0.3 // How fast do I regenerate?
|
||||
var/additional_regen // How much additional blood regen we gain from bonuses such as high blood.
|
||||
@@ -209,7 +209,7 @@
|
||||
// Physiology
|
||||
CheckVampOrgans() // Heart, Eyes
|
||||
// Language
|
||||
owner.current.grant_language(/datum/language/vampiric)
|
||||
owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
|
||||
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
|
||||
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
|
||||
// Disabilities
|
||||
@@ -246,7 +246,7 @@
|
||||
// Update Health
|
||||
owner.current.setMaxHealth(100)
|
||||
// Language
|
||||
owner.current.remove_language(/datum/language/vampiric)
|
||||
owner.current.remove_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
|
||||
// Soul
|
||||
if (owner.soulOwner == owner) // Return soul, if *I* own it.
|
||||
owner.hasSoul = TRUE
|
||||
@@ -649,10 +649,10 @@
|
||||
return TRUE
|
||||
// Check 3) If I am a BLOODSUCKER, then are they my Vassal?
|
||||
if (mob_B && atom_V && (atom_V in mob_B.vassals))
|
||||
return TRUE
|
||||
return TRUE
|
||||
// Check 4) If we are both VASSAL, then do we have the same master?
|
||||
if (atom_V && mob_V && atom_V.master == mob_V.master)
|
||||
return TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -710,7 +710,7 @@
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/bloodsucker/proc/update_counter(value, valuecolor)
|
||||
invisibility = 0
|
||||
invisibility = 0
|
||||
|
||||
/obj/screen/bloodsucker/blood_counter
|
||||
icon = 'icons/mob/actions/bloodsucker.dmi'
|
||||
@@ -758,7 +758,7 @@
|
||||
|
||||
/obj/screen/bloodsucker/sunlight_counter/update_counter(value, valuecolor)
|
||||
..()
|
||||
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
|
||||
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/count_vassals(datum/mind/master)
|
||||
var/datum/antagonist/bloodsucker/B = master.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
objectives += vassal_objective
|
||||
objectives_given += vassal_objective
|
||||
give_thrall_eyes()
|
||||
owner.current.grant_language(/datum/language/vampiric)
|
||||
owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_VASSAL)
|
||||
// Add Antag HUD
|
||||
update_vassal_icons_added(owner.current, "vassal")
|
||||
. = ..()
|
||||
@@ -81,7 +81,7 @@
|
||||
qdel(O)
|
||||
objectives_given = list()
|
||||
remove_thrall_eyes()
|
||||
owner.current.remove_language(/datum/language/vampiric)
|
||||
owner.current.remove_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_VASSAL)
|
||||
// Clear Antag HUD
|
||||
update_vassal_icons_removed(owner.current)
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
create_initial_profile()
|
||||
if(give_objectives)
|
||||
forge_objectives()
|
||||
owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all.
|
||||
remove_clownmut()
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_languages(target, LANGUAGE_ABSORB)
|
||||
|
||||
if(target.mind && user.mind)//if the victim and user have minds
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
|
||||
//Recover from stuns.
|
||||
/obj/effect/proc_holder/changeling/adrenaline/sting_action(mob/living/user)
|
||||
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/drug/methamphetamine/changeling = 10, /datum/reagent/medicine/mannitol = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/changelingadrenaline = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
|
||||
return TRUE
|
||||
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/drug/methamphetamine/changeling = 10, /datum/reagent/medicine/changelingadrenaline = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
|
||||
return TRUE
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if(!active)
|
||||
E.sight_flags |= SEE_MOBS | SEE_OBJS | SEE_TURFS //Add sight flags to the user's eyes
|
||||
ADD_TRAIT(user, TRAIT_THERMAL_VISION, CHANGELING_TRAIT)
|
||||
E.flash_protect = -1 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to sense prey through walls.")
|
||||
active = TRUE //Defined in code/modules/spells/spell.dm
|
||||
else
|
||||
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS //Remove sight flags from the user's eyes
|
||||
REMOVE_TRAIT(user, TRAIT_THERMAL_VISION, CHANGELING_TRAIT)
|
||||
E.flash_protect = 2 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to protect them from bright lights.")
|
||||
active = FALSE
|
||||
@@ -47,10 +47,8 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/on_refund(mob/user) //Get rid of X-ray vision and flash protection when the user refunds this ability
|
||||
action.Remove(user)
|
||||
REMOVE_TRAIT(user, TRAIT_THERMAL_VISION, CHANGELING_TRAIT)
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if (active)
|
||||
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
else
|
||||
E.flash_protect = 0
|
||||
user.update_sight()
|
||||
E.flash_protect = initial(E.flash_protect)
|
||||
user.update_sight()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Biodegrade"
|
||||
desc = "Dissolves restraints or other objects preventing free movement."
|
||||
helptext = "This is obvious to nearby people, and can destroy standard restraints and closets. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
chemical_cost = 30 //High cost to prevent spam
|
||||
chemical_cost = 15 //High cost to prevent spam
|
||||
loudness = 1
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
desc = "Our skin pigmentation rapidly changes to suit our current environment."
|
||||
helptext = "Allows us to become invisible after a few seconds of standing still. Can be toggled on and off."
|
||||
dna_cost = 2
|
||||
chemical_cost = 25
|
||||
req_human = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_camouflage"
|
||||
@@ -23,4 +22,4 @@
|
||||
action.Remove(user)
|
||||
if(user.has_dna())
|
||||
var/mob/living/carbon/C = user
|
||||
C.dna.remove_mutation(CHAMELEON)
|
||||
C.dna.remove_mutation(CHAMELEON)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/obj/effect/proc_holder/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath. Functions while unconscious."
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath. Functions while unconscious. This ability is loud, and might cause our blood to react violently to heat."
|
||||
helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood."
|
||||
chemical_cost = 20
|
||||
loudness = 2
|
||||
dna_cost = 2
|
||||
req_stat = UNCONSCIOUS
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
name = "Arm Blade"
|
||||
desc = "We reform one of our arms into a deadly blade."
|
||||
helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
chemical_cost = 20
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
loudness = 2
|
||||
req_human = 1
|
||||
@@ -410,7 +410,7 @@
|
||||
desc = "We reform one of our arms into a hard shield."
|
||||
helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
req_human = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
@@ -522,12 +522,12 @@
|
||||
/obj/effect/proc_holder/changeling/suit/armor
|
||||
name = "Chitinous Armor"
|
||||
desc = "We turn our skin into tough chitin to protect us from damage."
|
||||
helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
helptext = "Upkeep of the armor requires a constant expenditure of chemicals, resulting in a reduced chemical generation. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
loudness = 2
|
||||
req_human = 1
|
||||
recharge_slowdown = 0.25
|
||||
recharge_slowdown = 0.5
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_armor"
|
||||
action_background_icon_state = "bg_ling"
|
||||
@@ -543,7 +543,7 @@
|
||||
icon_state = "lingarmor"
|
||||
item_flags = DROPDEL
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
armor = list("melee" = 40, "bullet" = 40, "laser" = 40, "energy" = 20, "bomb" = 10, "bio" = 4, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
armor = list("melee" = 70, "bullet" = 60, "laser" = 30, "energy" = 40, "bomb" = 10, "bio" = 4, "rad" = 0, "fire" = 50, "acid" = 90)
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
cold_protection = 0
|
||||
heat_protection = 0
|
||||
@@ -559,7 +559,7 @@
|
||||
desc = "A tough, hard covering of black chitin with transparent chitin in front."
|
||||
icon_state = "lingarmorhelmet"
|
||||
item_flags = DROPDEL
|
||||
armor = list("melee" = 40, "bullet" = 40, "laser" = 40, "energy" = 20, "bomb" = 10, "bio" = 4, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
armor = list("melee" = 70, "bullet" = 60, "laser" = 30, "energy" = 40, "bomb" = 10, "bio" = 4, "rad" = 0, "fire" = 50, "acid" = 90)
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE
|
||||
|
||||
/obj/item/clothing/head/helmet/changeling/Initialize()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
|
||||
helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
req_human = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
@@ -37,7 +37,7 @@
|
||||
desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
|
||||
helptext = "Emits a high-frequency sound that overloads nearby electronics. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
dna_cost = 2
|
||||
loudness = 1
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_dissonant"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
name = "Strained Muscles"
|
||||
desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster."
|
||||
helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form."
|
||||
chemical_cost = 15
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
var/stacks = 0 //Increments every 5 seconds; damage increases over time
|
||||
@@ -15,16 +14,13 @@
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
active = !active
|
||||
if(active)
|
||||
to_chat(user, "<span class='notice'>Our muscles tense and strengthen.</span>")
|
||||
changeling.chem_recharge_slowdown += 0.5
|
||||
else
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
to_chat(user, "<span class='notice'>Our muscles relax.</span>")
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
if(stacks >= 20)
|
||||
if(stacks >= 10)
|
||||
to_chat(user, "<span class='danger'>We collapse in exhaustion.</span>")
|
||||
user.DefaultCombatKnockdown(60)
|
||||
user.emote("gasp")
|
||||
@@ -34,7 +30,6 @@
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/proc/muscle_loop(mob/living/carbon/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
while(active)
|
||||
user.add_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
if(user.stat != CONSCIOUS || user.staminaloss >= 90)
|
||||
@@ -42,18 +37,17 @@
|
||||
to_chat(user, "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>")
|
||||
user.DefaultCombatKnockdown(40)
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
break
|
||||
|
||||
stacks++
|
||||
//user.take_bodypart_damage(stacks * 0.03, 0)
|
||||
user.adjustStaminaLoss(stacks*1.3) //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
|
||||
user.adjustStaminaLoss(stacks*1.5) //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
|
||||
|
||||
if(stacks == 10) //Warning message that the stacks are getting too high
|
||||
if(stacks == 5) //Warning message that the stacks are getting too high
|
||||
to_chat(user, "<span class='warning'>Our legs are really starting to hurt...</span>")
|
||||
|
||||
sleep(40)
|
||||
|
||||
while(!active && stacks) //Damage stacks decrease fairly rapidly while not in sanic mode
|
||||
while(!active && stacks) //Damage stacks decrease slowly while not in sanic mode
|
||||
stacks--
|
||||
sleep(20)
|
||||
sleep(100)
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
laws = new /datum/ai_laws/ratvar()
|
||||
braintype = picked_name
|
||||
GLOB.all_clockwork_objects += src
|
||||
brainmob.add_blocked_language(subtypesof(/datum/language) - /datum/language/ratvar, LANGUAGE_CLOCKIE)
|
||||
|
||||
/obj/item/mmi/posibrain/soul_vessel/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
current = mob_override
|
||||
GLOB.all_clockwork_mobs += current
|
||||
current.faction |= "ratvar"
|
||||
current.grant_language(/datum/language/ratvar)
|
||||
current.grant_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CLOCKIE)
|
||||
current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
|
||||
if(issilicon(current))
|
||||
var/mob/living/silicon/S = current
|
||||
@@ -102,6 +102,7 @@
|
||||
R.module.rebuild_modules()
|
||||
else if(isAI(S))
|
||||
var/mob/living/silicon/ai/A = S
|
||||
A.add_blocked_language(subtypesof(/datum/language) - /datum/language/ratvar, LANGUAGE_CLOCKIE)
|
||||
A.can_be_carded = FALSE
|
||||
A.requires_power = POWER_REQ_CLOCKCULT
|
||||
var/list/AI_frame = list(mutable_appearance('icons/mob/clockwork_mobs.dmi', "aiframe")) //make the AI's cool frame
|
||||
@@ -142,7 +143,7 @@
|
||||
current = mob_override
|
||||
GLOB.all_clockwork_mobs -= current
|
||||
current.faction -= "ratvar"
|
||||
current.remove_language(/datum/language/ratvar)
|
||||
current.remove_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CLOCKIE)
|
||||
current.clear_alert("clockinfo")
|
||||
for(var/datum/action/innate/clockwork_armaments/C in owner.current.actions) //Removes any bound clockwork armor
|
||||
qdel(C)
|
||||
@@ -152,6 +153,7 @@
|
||||
var/mob/living/silicon/S = current
|
||||
if(isAI(S))
|
||||
var/mob/living/silicon/ai/A = S
|
||||
A.remove_blocked_language(subtypesof(/datum/language) - /datum/language/ratvar, LANGUAGE_CLOCKIE)
|
||||
A.can_be_carded = initial(A.can_be_carded)
|
||||
A.requires_power = initial(A.requires_power)
|
||||
A.cut_overlays()
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction |= "cult"
|
||||
current.grant_language(/datum/language/narsie)
|
||||
current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
|
||||
if(!cult_team?.cult_master)
|
||||
vote.Grant(current)
|
||||
communion.Grant(current)
|
||||
@@ -134,7 +134,7 @@
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction -= "cult"
|
||||
current.remove_language(/datum/language/narsie)
|
||||
current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
|
||||
vote.Remove(current)
|
||||
communion.Remove(current)
|
||||
magic.Remove(current)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user