Merge branch 'master' into typing_indicators

This commit is contained in:
kevinz000
2020-05-11 05:00:23 -07:00
committed by GitHub
315 changed files with 4253 additions and 3235 deletions
+10 -7
View File
@@ -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.
+4 -2
View File
@@ -259,10 +259,10 @@
//HELPERS
#define PIPING_LAYER_SHIFT(T, PipingLayer) \
if(T.dir & NORTH || T.dir & SOUTH) { \
if(T.dir & (NORTH|SOUTH)) { \
T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
} \
if(T.dir & WEST || T.dir & EAST) { \
if(T.dir & (WEST|EAST)) { \
T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;\
}
@@ -298,6 +298,8 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
#define ARCHIVE_TEMPERATURE(gas) gas.temperature_archived = gas.temperature
#define ARCHIVE(gas) gas.temperature_archived = gas.temperature; gas.gas_archive = gas.gases.Copy();
GLOBAL_LIST_INIT(pipe_paint_colors, list(
"amethyst" = rgb(130,43,255), //supplymain
"blue" = rgb(0,0,255),
+1
View File
@@ -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"
+26 -3
View File
@@ -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!
-2
View File
@@ -59,8 +59,6 @@
//let's just pretend fulltile windows being children of border windows is fine
#define FULLTILE_WINDOW_DIR NORTHEAST
//The amount of materials you get from a sheet of mineral like iron/diamond/glass etc
#define MINERAL_MATERIAL_AMOUNT 2000
//The maximum size of a stack object.
#define MAX_STACK_SIZE 50
//maximum amount of cable in a coil
+22 -1
View File
@@ -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)
+21 -2
View File
@@ -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"
+2
View File
@@ -0,0 +1,2 @@
/// cm3 of material matter per sheet
#define MINERAL_MATERIAL_AMOUNT 2000
+5
View File
@@ -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
@@ -291,4 +292,8 @@
#define TYPING_INDICATOR_TIMEOUT 5 MINUTES
#define GRAB_PIXEL_SHIFT_PASSIVE 6
#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
#define GRAB_PIXEL_SHIFT_NECK 16
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
+5
View File
@@ -0,0 +1,5 @@
// the clamps are just sanity checks.
/// Efficiency scaling for stock part level to material usage. All code concerning lathing and production from raw material sheet should be using this.
#define STANDARD_PART_LEVEL_LATHE_COEFFICIENT(level) clamp(1 - (level * 0.1), 0, 1)
/// Efficiency scaling for stock part level to ore factor. All code concerning lathing and production from raw ores to raw material sheets should be using this.
#define STANDARD_PART_LEVEL_ORE_COEFFICIENT(level) clamp(1 + (level * 0.125), 1, 10)
+77
View File
@@ -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
+8
View File
@@ -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)
-28
View File
@@ -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)
+4 -2
View File
@@ -163,9 +163,11 @@
"tail_lizard" = pick(GLOB.tails_list_lizard),
"tail_human" = "None",
"wings" = "None",
"wings_color" = "FFF",
"deco_wings" = "None",
"snout" = pick(GLOB.snouts_list),
"horns" = pick(GLOB.horns_list),
"horns" = "None",
"horns_color" = "85615a",
"ears" = "None",
"frills" = pick(GLOB.frills_list),
"spines" = pick(GLOB.spines_list),
@@ -174,7 +176,7 @@
"caps" = pick(GLOB.caps_list),
"insect_wings" = pick(GLOB.insect_wings_list),
"insect_fluff" = "None",
"insect_markings" = pick(GLOB.insect_markings_list),
"insect_markings" = pick(GLOB.insect_markings_list),
"taur" = "None",
"mam_body_markings" = snowflake_markings_list.len ? pick(snowflake_markings_list) : "None",
"mam_ears" = snowflake_ears_list ? pick(snowflake_ears_list) : "None",
+10 -1
View File
@@ -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
+56 -20
View File
@@ -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)
+9 -3
View File
@@ -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
+15 -1
View File
@@ -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()
+4 -10
View File
@@ -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)
@@ -413,15 +413,6 @@
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/paperwork
name = "Filed Paper Work"
result = /obj/item/folder/paperwork_correct
time = 10 //Takes time for people to file and complete paper work!
tools = list(/obj/item/pen)
reqs = list(/obj/item/folder/paperwork = 1)
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/coconut_bong
name = "Coconut Bong"
result = /obj/item/bong/coconut
+52 -4
View File
@@ -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
+8 -1
View File
@@ -20,6 +20,8 @@
var/ride_check_ridden_incapacitated = FALSE
var/list/offhands = list() // keyed list containing all the current riding offsets associated by mob
var/del_on_unbuckle_all = FALSE
/datum/component/riding/Initialize()
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
@@ -28,8 +30,11 @@
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
var/atom/movable/AM = parent
restore_position(M)
unequip_buckle_inhands(M)
if(del_on_unbuckle_all && !AM.has_buckled_mobs())
qdel(src)
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
handle_vehicle_offsets()
@@ -194,6 +199,7 @@
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
del_on_unbuckle_all = TRUE
var/fireman_carrying = FALSE
/datum/component/riding/human/Initialize()
@@ -202,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)
. = ..()
@@ -261,6 +267,7 @@
user.visible_message("<span class='warning'>[AM] pushes [user] off of [AM.p_them()]!</span>")
/datum/component/riding/cyborg
del_on_unbuckle_all = TRUE
/datum/component/riding/cyborg/Initialize()
. = ..()
@@ -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.
+5
View File
@@ -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)
..()
+23 -11
View File
@@ -5,12 +5,16 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
id_arg_index = 3
var/flavor_name = "Flavor Text"
var/list/texts_by_atom = list()
var/addendum = "This can also be used for OOC notes and preferences!"
var/addendum = ""
var/always_show = FALSE
var/max_len = MAX_FLAVOR_LEN
var/can_edit = TRUE
/// For preference/DNA saving/loading. Null to prevent. Prefs are only loaded from obviously if it exists in preferences.features.
var/save_key
/// Do not attempt to render a preview on examine. If this is on, it will display as \[flavor_name\]
var/examine_no_preview = FALSE
/datum/element/flavor_text/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE)
/datum/element/flavor_text/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key, _examine_no_preview = FALSE)
. = ..()
if(. == ELEMENT_INCOMPATIBLE || !isatom(target)) //no reason why this shouldn't work on atoms too.
@@ -25,6 +29,8 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
addendum = _addendum
always_show = _always_show
can_edit = _edit
save_key = _save_key
examine_no_preview = _examine_no_preview
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/show_flavor)
@@ -33,9 +39,12 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
LAZYOR(GLOB.mobs_with_editable_flavor_text[M], src)
M.verbs |= /mob/proc/manage_flavor_tests
if(save_key && ishuman(target))
RegisterSignal(target, COMSIG_HUMAN_PREFS_COPIED_TO, .proc/update_prefs_flavor_text)
/datum/element/flavor_text/Detach(atom/A)
. = ..()
UnregisterSignal(A, COMSIG_PARENT_EXAMINE)
UnregisterSignal(A, list(COMSIG_PARENT_EXAMINE, COMSIG_HUMAN_PREFS_COPIED_TO))
texts_by_atom -= A
if(can_edit && ismob(A))
var/mob/M = A
@@ -58,6 +67,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
var/text = texts_by_atom[target]
if(!text)
return
if(examine_no_preview)
examine_list += "<span class='notice'><a href='?src=[REF(src)];show_flavor=[REF(target)]'>\[[flavor_name]\]</a></span>"
return
var/msg = replacetext(text, "\n", " ")
if(length_char(msg) <= 40)
examine_list += "<span class='notice'>[msg]</span>"
@@ -112,13 +124,17 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
return TRUE
return FALSE
/datum/element/flavor_text/proc/update_prefs_flavor_text(mob/living/carbon/human/H, datum/preferences/P, icon_updates = TRUE, roundstart_checks = TRUE)
if(P.features.Find(save_key))
texts_by_atom[H] = P.features[save_key]
//subtypes with additional hooks for DNA and preferences.
/datum/element/flavor_text/carbon
//list of antagonists etcetera that should have nothing to do with people's snowflakes.
var/static/list/i_dont_even_know_who_you_are = typecacheof(list(/datum/antagonist/abductor, /datum/antagonist/ert,
/datum/antagonist/nukeop, /datum/antagonist/wizard))
/datum/element/flavor_text/carbon/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE)
/datum/element/flavor_text/carbon/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key = "flavor_text", _examine_no_preview = FALSE)
if(!iscarbon(target))
return ELEMENT_INCOMPATIBLE
. = ..()
@@ -127,7 +143,6 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
RegisterSignal(target, COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, .proc/update_dna_flavor_text)
RegisterSignal(target, COMSIG_MOB_ANTAG_ON_GAIN, .proc/on_antag_gain)
if(ishuman(target))
RegisterSignal(target, COMSIG_HUMAN_PREFS_COPIED_TO, .proc/update_prefs_flavor_text)
RegisterSignal(target, COMSIG_HUMAN_HARDSET_DNA, .proc/update_dna_flavor_text)
RegisterSignal(target, COMSIG_HUMAN_ON_RANDOMIZE, .proc/unset_flavor)
@@ -136,15 +151,12 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
UnregisterSignal(C, list(COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, COMSIG_MOB_ANTAG_ON_GAIN, COMSIG_HUMAN_PREFS_COPIED_TO, COMSIG_HUMAN_HARDSET_DNA, COMSIG_HUMAN_ON_RANDOMIZE))
/datum/element/flavor_text/carbon/proc/update_dna_flavor_text(mob/living/carbon/C)
texts_by_atom[C] = C.dna.features["flavor_text"]
/datum/element/flavor_text/carbon/proc/update_prefs_flavor_text(mob/living/carbon/human/H, datum/preferences/P, icon_updates = TRUE, roundstart_checks = TRUE)
texts_by_atom[H] = P.features["flavor_text"]
texts_by_atom[C] = C.dna.features[save_key]
/datum/element/flavor_text/carbon/set_flavor(mob/living/carbon/user)
. = ..()
if(. && user.dna)
user.dna.features["flavor_text"] = texts_by_atom[user]
user.dna.features[save_key] = texts_by_atom[user]
/datum/element/flavor_text/carbon/proc/unset_flavor(mob/living/carbon/user)
texts_by_atom[user] = ""
@@ -153,4 +165,4 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
if(is_type_in_typecache(antag, i_dont_even_know_who_you_are))
texts_by_atom[user] = ""
if(user.dna)
user.dna.features["flavor_text"] = ""
user.dna.features[save_key] = ""
+3 -1
View File
@@ -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
+1 -1
View File
@@ -72,7 +72,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
/datum/material/uranium/on_applied(atom/source, amount, material_flags)
. = ..()
source.AddComponent(/datum/component/radioactive, amount / 20, source, 0) //half-life of 0 because we keep on going.
source.AddComponent(/datum/component/radioactive, amount / 60, source, 0) //half-life of 0 because we keep on going.
/datum/material/uranium/on_removed(atom/source, material_flags)
. = ..()
+4 -6
View File
@@ -67,7 +67,7 @@
var/datum/skill_holder/skill_holder
/datum/mind/New(var/key)
skill_holder = new
skill_holder = new(src)
src.key = key
soulOwner = src
martial_art = default_martial_art
@@ -80,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.
+4 -4
View File
@@ -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)
+122 -9
View File
@@ -1,4 +1,4 @@
GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/proc/init_skill_datums()
. = list()
@@ -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"
+114 -21
View File
@@ -2,10 +2,18 @@
* Skill holder datums
*/
/datum/skill_holder
var/datum/mind/owner
/// Our list of skills and values. Lazylist. Associative. Keys are datum typepaths to the skill.
var/list/skills
/// Same as [skills] but affinities, which are multiplied to increase amount when gaining skills.
var/list/skill_affinities
/// Let's say we want to get a specific skill "level" without looping through a proc everytime.
/// Only supported by skills with tiers or levels.
var/list/skill_levels
/datum/skill_holder/New(datum/mind/M)
. = ..()
owner = M
/**
* Grabs the value of a skill.
@@ -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("")
+6
View File
@@ -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
+2
View File
@@ -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.
+35 -6
View File
@@ -33,6 +33,9 @@
var/list/assemblies = list() // List of attached assemblies.
var/randomize = 0 // If every instance of these wires should be random.
// Prevents wires from showing up in station blueprints
var/req_knowledge = INFINITY //wiring skill level on which the functions are revealed.
var/req_skill = JOB_SKILL_BASIC //used in user's cutting/pulsing/mending speed calculations.
var/list/current_users //list of untrained people currently interacting with this set of wires.
/datum/wires/New(atom/holder)
..()
@@ -130,8 +133,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
View File
@@ -1,6 +1,7 @@
/datum/wires/airalarm
holder_type = /obj/machinery/airalarm
proper_name = "Air Alarm"
req_knowledge = JOB_SKILL_MASTER
/datum/wires/airalarm/New(atom/holder)
wires = list(
+4 -2
View File
@@ -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
View File
@@ -1,6 +1,7 @@
/datum/wires/apc
holder_type = /obj/machinery/power/apc
proper_name = "APC"
req_knowledge = JOB_SKILL_MASTER
/datum/wires/apc/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/autolathe
holder_type = /obj/machinery/autolathe
proper_name = "Autolathe"
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/autolathe/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/emitter
holder_type = /obj/machinery/power/emitter
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/emitter/New(atom/holder)
wires = list(WIRE_ZAP,WIRE_HACK)
+2
View File
@@ -15,6 +15,7 @@
/datum/wires/explosive/c4
holder_type = /obj/item/grenade/plastic/c4
randomize = TRUE //Same behaviour since no wire actually disarms it
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/explosive/c4/interactable(mob/user)
var/obj/item/grenade/plastic/c4/P = holder
@@ -29,6 +30,7 @@
/datum/wires/explosive/pizza
holder_type = /obj/item/pizzabox
randomize = TRUE
req_skill = JOB_SKILL_MASTER
/datum/wires/explosive/pizza/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/microwave
holder_type = /obj/machinery/microwave
proper_name = "Microwave"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/microwave/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/mulebot
holder_type = /mob/living/simple_animal/bot/mulebot
randomize = TRUE
req_knowledge = JOB_SKILL_MASTER
/datum/wires/mulebot/New(atom/holder)
wires = list(
@@ -1,6 +1,8 @@
/datum/wires/particle_accelerator/control_box
holder_type = /obj/machinery/particle_accelerator/control_box
proper_name = "Particle Accelerator"
req_knowledge = JOB_SKILL_EXPERT
req_skill = JOB_SKILL_TRAINED
/datum/wires/particle_accelerator/control_box/New(atom/holder)
wires = list(
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/rnd
holder_type = /obj/machinery/rnd
randomize = TRUE
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/rnd/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/radio
holder_type = /obj/item/radio
proper_name = "Radio"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/radio/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/robot
holder_type = /mob/living/silicon/robot
randomize = TRUE
req_knowledge = JOB_SKILL_MASTER
req_skill = JOB_SKILL_TRAINED
/datum/wires/robot/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/suit_storage_unit
holder_type = /obj/machinery/suit_storage_unit
proper_name = "Suit Storage Unit"
req_knowledge = JOB_SKILL_TRAINED
req_skill = JOB_SKILL_UNTRAINED
/datum/wires/suit_storage_unit/New(atom/holder)
wires = list(
+2
View File
@@ -1,6 +1,8 @@
/datum/wires/syndicatebomb
holder_type = /obj/machinery/syndicatebomb
randomize = TRUE
req_skill = JOB_SKILL_EXPERT //good luck, wannabe hero.
/datum/wires/syndicatebomb/New(atom/holder)
wires = list(
+1
View File
@@ -2,6 +2,7 @@
/datum/wires/tesla_coil
randomize = 1 //Only one wire don't need blueprints
holder_type = /obj/machinery/power/tesla_coil
req_knowledge = JOB_SKILL_TRAINED
/datum/wires/tesla_coil/New(atom/holder)
wires = list(WIRE_ZAP)
+1
View File
@@ -1,6 +1,7 @@
/datum/wires/vending
holder_type = /obj/machinery/vending
proper_name = "Vending Unit"
req_knowledge = JOB_SKILL_EXPERT
/datum/wires/vending/New(atom/holder)
wires = list(
+83 -73
View File
@@ -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"
@@ -25,6 +25,7 @@
var/inertia_move_delay = 5
var/pass_flags = 0
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before.
var/list/client_mobs_in_contents // This contains all the client mobs within this container
var/list/acted_explosions //for explosion dodging
glide_size = 8
@@ -207,6 +208,7 @@
if(!Process_Spacemove(get_dir(pulling.loc, A)))
return
step(pulling, get_dir(pulling.loc, A))
return TRUE
/atom/movable/proc/check_pulling()
if(pulling)
@@ -224,6 +226,8 @@
if(pulling.anchored || pulling.move_resist > move_force)
stop_pulling()
return
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
@@ -498,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())
+5 -13
View File
@@ -54,13 +54,8 @@
/atom/movable/Move(atom/newloc, direct)
var/atom/movable/pullee = pulling
var/turf/T = loc
if(pulling)
if(pullee && get_dist(src, pullee) > 1)
stop_pulling()
if(pullee && pullee.loc != loc && !isturf(pullee.loc) ) //to be removed once all code that changes an object's loc uses forceMove().
log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
stop_pulling()
if(!moving_from_pull)
check_pulling()
if(!loc || !newloc)
return FALSE
var/atom/oldloc = loc
@@ -133,19 +128,16 @@
if(has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
return FALSE
if(pulling && pulling == pullee) //we were pulling a thing and didn't lose it during our move.
if(pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move.
if(pulling.anchored)
stop_pulling()
else
var/pull_dir = get_dir(src, pulling)
//puller and pullee more than one tile away or in diagonal position
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir)))
pulling.moving_from_pull = src
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up
stop_pulling()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
pulling.moving_from_pull = null
Moved(oldloc, direct)
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
+1 -1
View File
@@ -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
+4 -1
View File
@@ -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."
+15 -11
View File
@@ -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",
@@ -62,6 +61,9 @@
/datum/material/mythril
)
/// Base print speed
var/base_print_speed = 10
/obj/machinery/autolathe/Initialize()
AddComponent(/datum/component/material_container, allowed_materials, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
@@ -206,7 +208,7 @@
busy = TRUE
use_power(power)
icon_state = "autolathe_n"
var/time = is_stack ? 32 : 32*coeff*multiplier
var/time = is_stack ? 10 : base_print_speed * coeff * multiplier
addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack), time)
else
to_chat(usr, "<span class=\"alert\">Not enough materials for this operation.</span>")
@@ -254,10 +256,12 @@
T += MB.rating*75000
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = T
T=1.2
var/manips = 0
var/total_manip_rating = 0
for(var/obj/item/stock_parts/manipulator/M in component_parts)
T -= M.rating*0.2
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
total_manip_rating += M.rating
manips++
prod_coeff = STANDARD_PART_LEVEL_LATHE_COEFFICIENT(total_manip_rating / (manips? manips : 1))
/obj/machinery/autolathe/examine(mob/user)
. += ..()
@@ -420,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
@@ -436,10 +440,10 @@
/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
/obj/machinery/autolathe/toy
name = "autoylathe"
@@ -48,8 +48,7 @@
if(2)
// State 2
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.use(2))
if(W.use_tool(src, user, 0, 2))
to_chat(user, "<span class='notice'>You add wires to the assembly.</span>")
state = 3
else
@@ -83,7 +83,6 @@
if(istype(P, /obj/item/stack/cable_coil))
if(!P.tool_start_check(user, amount=5))
return
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
if(P.use_tool(src, user, 20, volume=50, amount=5))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
+1 -2
View File
@@ -400,12 +400,11 @@
"<span class='notice'>You begin adding wires to [src]...</span>")
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
if(do_after(user, 60, target = src))
if(constructionStep != CONSTRUCTION_GUTTED || B.get_amount() < 5 || !B)
if(constructionStep != CONSTRUCTION_GUTTED || !B.use_tool(src, user, 0, 5))
return
user.visible_message("<span class='notice'>[user] adds wires to [src].</span>", \
"<span class='notice'>You wire [src].</span>")
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
B.use(5)
constructionStep = CONSTRUCTION_WIRES_EXPOSED
update_icon()
return
+1 -3
View File
@@ -205,11 +205,9 @@
return
if(1)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = W
if(coil.get_amount() < 5)
if(!W.use_tool(src, user, 0, 5))
to_chat(user, "<span class='warning'>You need more cable for this!</span>")
else
coil.use(5)
buildstage = 2
to_chat(user, "<span class='notice'>You wire \the [src].</span>")
update_icon()
+3 -4
View File
@@ -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
-1
View File
@@ -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)
+1 -4
View File
@@ -160,10 +160,7 @@
to_chat(user, "<span class='warning'>You need one length of cable to repair [src]!</span>")
return
to_chat(user, "<span class='notice'>You begin to replace the wires...</span>")
if(do_after(user, 30, target = src))
if(coil.get_amount() < 1)
return
coil.use(1)
if(W.use_tool(src, user, 30, 1))
obj_integrity = max_integrity
stat &= ~BROKEN
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
@@ -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)
+1 -2
View File
@@ -220,8 +220,7 @@
return
else if(istype(W, /obj/item/stack/cable_coil))
if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT))
var/obj/item/stack/cable_coil/CC = W
if(CC.use(2))
if(W.use_tool(src, user, 0, 2))
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
to_chat(user, "<span class='notice'>You replace the fused wires.</span>")
else
+9 -2
View File
@@ -55,8 +55,12 @@
M.buckling = null
return FALSE
if(M.pulledby && buckle_prevents_pull)
M.pulledby.stop_pulling()
if(M.pulledby)
if(buckle_prevents_pull)
M.pulledby.stop_pulling()
else if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
L.reset_pull_offsets(M, TRUE)
if(!check_loc && M.loc != loc)
M.forceMove(loc)
@@ -137,4 +141,7 @@
"<span class='notice'>You unbuckle yourself from [src].</span>",\
"<span class='italics'>You hear metal clanking.</span>")
add_fingerprint(user)
if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
L.set_pull_offsets(M, L.grab_state)
return M
+2 -2
View File
@@ -7,7 +7,7 @@
if(log)
message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
if(heavy_range >= 1)
new /obj/effect/temp_visual/emp/pulse(epicenter)
@@ -29,4 +29,4 @@
T.emp_act(EMP_LIGHT)
else if(distance <= light_range)
T.emp_act(EMP_LIGHT)
return 1
return 1
+16 -1
View File
@@ -132,6 +132,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
///Skills vars
//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.
+74 -24
View File
@@ -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>")
+11 -12
View File
@@ -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
+3 -1
View File
@@ -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)
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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)
+51 -37
View File
@@ -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"
+2 -5
View File
@@ -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))
+59 -57
View File
@@ -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"
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -131,7 +131,7 @@
if(C.get_amount() >= 5)
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5))
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use_tool(src, user, 0, 5))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
state = CABLED_CORE
update_icon()
+1 -2
View File
@@ -84,7 +84,6 @@
panel_open = FALSE
else if(istype(I, /obj/item/stack/cable_coil) && panel_open)
var/obj/item/stack/cable_coil/C = I
if(obj_flags & EMAGGED) //Emagged, not broken by EMP
to_chat(user, "<span class='warning'>Sign has been damaged beyond repair!</span>")
return
@@ -92,7 +91,7 @@
to_chat(user, "<span class='warning'>This sign is functioning properly!</span>")
return
if(C.use(2))
if(I.use_tool(src, user, 0, 2))
to_chat(user, "<span class='notice'>You replace the burnt wiring.</span>")
broken = FALSE
else
@@ -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)
@@ -176,3 +176,4 @@ GLOBAL_LIST_INIT(ore_probability, list(/obj/item/stack/ore/uranium = 50,
new /obj/item/book/granter/spell/sacredflame(loc)
if(28)
new /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom(loc)
qdel(src)
+50 -39
View File
@@ -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()
. = ..()
+11 -1
View File
@@ -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(.)
-3
View File
@@ -38,7 +38,4 @@
user.show_message("<span class='notice'>You weave \the [S.name] into a workable fabric.</span>", MSG_VISUAL)
return TRUE
/obj/structure/loom/unanchored
anchored = FALSE
#undef FABRIC_PER_SHEET
@@ -152,8 +152,8 @@
pod_moving = 0
if(!QDELETED(pod))
var/datum/gas_mixture/floor_mixture = loc.return_air()
ARCHIVE_TEMPERATURE(floor_mixture)
ARCHIVE_TEMPERATURE(pod.air_contents)
ARCHIVE(floor_mixture)
ARCHIVE(pod.air_contents)
pod.air_contents.share(floor_mixture, 1) //mix the pod's gas mixture with the tile it's on
air_update_turf()
@@ -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
View File
@@ -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)
@@ -203,8 +203,7 @@
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/wolf = 50, /obj/structure/spawner/ice_moon = 3, \
/mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon/polarbear = 3, \
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10)
flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/grass/both = 12)
flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/grass/both = 12, /obj/structure/flora/rock/icy = 6, /obj/structure/flora/rock/pile/icy = 6)
data_having_type = /turf/open/floor/plating/asteroid/airless/cave/snow/has_data
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
choose_turf_type = list(/turf/open/floor/plating/asteroid/snow/icemoon = 19, /turf/open/floor/plating/ice/icemoon = 1)
+3 -2
View File
@@ -8,8 +8,9 @@ GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
if(fexists("byond-extools.dll"))
call("byond-extools.dll", "maptick_initialize")()
var/extools = world.GetConfig("env", "EXTOOLS_DLL") || "./byond-extools.dll"
if (fexists(extools))
call(extools, "maptick_initialize")()
enable_debugger()
world.Profile(PROFILE_START)
@@ -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)

Some files were not shown because too many files have changed in this diff Show More