Merge branch 'master' into typing_indicators
This commit is contained in:
+10
-7
@@ -25,35 +25,38 @@
|
||||
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
|
||||
|
||||
//subsystem does not initialize.
|
||||
#define SS_NO_INIT 1
|
||||
#define SS_NO_INIT (1<<0)
|
||||
|
||||
//subsystem does not fire.
|
||||
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
|
||||
// (Requires a MC restart to change)
|
||||
#define SS_NO_FIRE 2
|
||||
#define SS_NO_FIRE (1<<1)
|
||||
|
||||
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
|
||||
// SS_BACKGROUND has its own priority bracket
|
||||
#define SS_BACKGROUND 4
|
||||
#define SS_BACKGROUND (1<<2)
|
||||
|
||||
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
|
||||
#define SS_NO_TICK_CHECK 8
|
||||
#define SS_NO_TICK_CHECK (1<<3)
|
||||
|
||||
//Treat wait as a tick count, not DS, run every wait ticks.
|
||||
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
|
||||
// (implies all runlevels because of how it works)
|
||||
// (overrides SS_BACKGROUND)
|
||||
// This is designed for basically anything that works as a mini-mc (like SStimer)
|
||||
#define SS_TICKER 16
|
||||
#define SS_TICKER (1<<4)
|
||||
|
||||
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
|
||||
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
|
||||
#define SS_KEEP_TIMING 32
|
||||
#define SS_KEEP_TIMING (1<<5)
|
||||
|
||||
//Calculate its next fire after its fired.
|
||||
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
|
||||
// This flag overrides SS_KEEP_TIMING
|
||||
#define SS_POST_FIRE_TIMING 64
|
||||
#define SS_POST_FIRE_TIMING (1<<6)
|
||||
|
||||
/// Show in stat() by default even if SS_NO_FIRE
|
||||
#define SS_ALWAYS_SHOW_STAT (1<<7)
|
||||
|
||||
//SUBSYSTEM STATES
|
||||
#define SS_IDLE 0 //aint doing shit.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define COLOR_RED_GRAY "#B4696A"
|
||||
#define COLOR_PALE_BLUE_GRAY "#98C5DF"
|
||||
#define COLOR_PALE_GREEN_GRAY "#B7D993"
|
||||
#define COLOR_PALE_ORANGE "#FFC066"
|
||||
#define COLOR_PALE_RED_GRAY "#D59998"
|
||||
#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
|
||||
#define COLOR_PURPLE_GRAY "#AE8CA8"
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
/// Default combat flags for those affected by ((stamina combat))
|
||||
#define COMBAT_FLAGS_DEFAULT NONE
|
||||
/// Default combat flags for everyone else (so literally everyone but humans)
|
||||
#define COMBAT_FLAGS_STAMSYSTEM_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_COMBAT_TOGGLED)
|
||||
#define COMBAT_FLAGS_STAMSYSTEM_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_COMBAT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_COMBAT_FORCED)
|
||||
/// Default combat flags for those only affected by sprint (so just silicons)
|
||||
#define COMBAT_FLAGS_STAMEXEMPT_YESSPRINT (COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_COMBAT_TOGGLED)
|
||||
#define COMBAT_FLAGS_STAMEXEMPT_YESSPRINT (COMBAT_FLAG_COMBAT_ACTIVE | COMBAT_FLAG_COMBAT_TOGGLED | COMBAT_FLAG_COMBAT_FORCED)
|
||||
|
||||
/// The user wants combat mode on
|
||||
#define COMBAT_FLAG_COMBAT_TOGGLED (1<<0)
|
||||
@@ -57,6 +57,10 @@
|
||||
#define COMBAT_FLAG_INTENTIONALLY_RESTING (1<<7)
|
||||
/// Currently stamcritted but not as violently
|
||||
#define COMBAT_FLAG_SOFT_STAMCRIT (1<<8)
|
||||
/// Force combat mode on at all times, overrides everything including combat disable traits.
|
||||
#define COMBAT_FLAG_COMBAT_FORCED (1<<9)
|
||||
/// Force sprint mode on at all times, overrides everything including sprint disable traits.
|
||||
#define COMBAT_FLAG_SPRINT_FORCED (1<<10)
|
||||
|
||||
// Helpers for getting someone's stamcrit state. Cast to living.
|
||||
#define NOT_STAMCRIT 0
|
||||
@@ -248,13 +252,32 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds.
|
||||
#define TOTAL_MASS_TOY_SWORD 1.5
|
||||
|
||||
//stamina cost defines.
|
||||
#define STAM_COST_ATTACK_OBJ_MULT 1.2
|
||||
#define STAM_COST_ATTACK_MOB_MULT 0.8
|
||||
#define STAM_COST_BATON_MOB_MULT 1
|
||||
#define STAM_COST_NO_COMBAT_MULT 1.25
|
||||
#define STAM_COST_W_CLASS_MULT 1.25
|
||||
#define STAM_COST_THROW_MULT 2
|
||||
|
||||
|
||||
//bullet_act() return values
|
||||
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
|
||||
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
|
||||
|
||||
/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
|
||||
/// Check whether or not we can block, without "triggering" a block. Basically run checks without effects like depleting shields.
|
||||
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
|
||||
#define mob_check_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
|
||||
do_run_block(FALSE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
|
||||
|
||||
/// Runs a block "sequence", effectively checking and then doing effects if necessary.
|
||||
/// Wrapper for do_run_block(). The arguments on that means the same as for this.
|
||||
#define mob_run_block(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)\
|
||||
do_run_block(TRUE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
|
||||
|
||||
/// Bitflags for check_block() and run_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
|
||||
/// Attack was not blocked
|
||||
#define BLOCK_NONE NONE
|
||||
/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -183,7 +183,28 @@
|
||||
// #define SPEECH_FORCED 7
|
||||
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
|
||||
|
||||
#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //called from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
|
||||
#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
|
||||
|
||||
#define COMSIG_MOB_ACTION_SKILL_MOD "mob_action_skill_mod" //from base of /datum/skill_holder/action_skills_mod() : (proc args list, list/mod_values)
|
||||
#define ACTION_SKILL_MOD_SKILL 1 //redundancy.
|
||||
#define ACTION_SKILL_MOD_VALUE 2
|
||||
#define ACTION_SKILL_MOD_THRESHOLD 3
|
||||
#define ACTION_SKILL_MOD_IS_MULTI 4
|
||||
//other mod values, kept separate from the args
|
||||
#define MOD_VALUES_SKILL_MOD 1
|
||||
|
||||
#define COMSIG_MOB_ITEM_ACTION_SKILLS_MOD "mob_item_action_skills_mod" //from base of /datum/skill_holder/item_action_skills_mod() : (proc args list, mod_values)
|
||||
#define ITEM_SKILLS_MOD_ITEM 1 //redundancy
|
||||
#define ITEM_SKILLS_MOD_VALUE 2
|
||||
#define ITEM_SKILLS_MOD_FLAGS 3
|
||||
#define ITEM_SKILLS_MOD_BAD_FLAGS 4
|
||||
#define ITEM_SKILLS_MOD_IS_MULTI 5
|
||||
//other mod values, kept separate from the args
|
||||
#define MOD_VALUES_ITEM_SKILLS_SUM 1
|
||||
#define MOD_VALUES_ITEM_SKILLS_DIV 2
|
||||
#define MOD_VALUES_ITEM_SKILLS_CHECKED 3
|
||||
|
||||
#define COMSIG_MOB_SKILL_GET_AFFINITY "mob_skill_get_affinity" //from base of /datum/skill_holder/get_skill_affinity(): (skill_path, list/return_value)
|
||||
|
||||
// /mob/living signals
|
||||
#define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
|
||||
|
||||
@@ -3,5 +3,24 @@
|
||||
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
|
||||
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
|
||||
|
||||
#define LANGUAGE_KNOWN "language_known"
|
||||
#define LANGUAGE_SHADOWED "language_shadowed"
|
||||
// LANGUAGE SOURCE DEFINES
|
||||
#define LANGUAGE_ALL "all" // For use in full removal only.
|
||||
#define LANGUAGE_ATOM "atom"
|
||||
#define LANGUAGE_MIND "mind"
|
||||
|
||||
#define LANGUAGE_ABSORB "absorb"
|
||||
#define LANGUAGE_APHASIA "aphasia"
|
||||
#define LANGUAGE_BLOODSUCKER "bloodsucker"
|
||||
#define LANGUAGE_CLOCKIE "clockie"
|
||||
#define LANGUAGE_CULTIST "cultist"
|
||||
#define LANGUAGE_CURATOR "curator"
|
||||
#define LANGUAGE_DEVIL "devil"
|
||||
#define LANGUAGE_GLAND "gland"
|
||||
#define LANGUAGE_HAT "hat"
|
||||
#define LANGUAGE_HIGH "high"
|
||||
#define LANGUAGE_MALF "malf"
|
||||
#define LANGUAGE_MASTER "master"
|
||||
#define LANGUAGE_SOFTWARE "software"
|
||||
#define LANGUAGE_STONER "stoner"
|
||||
#define LANGUAGE_VASSAL "vassal"
|
||||
#define LANGUAGE_VOICECHANGE "voicechange"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/// cm3 of material matter per sheet
|
||||
#define MINERAL_MATERIAL_AMOUNT 2000
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
/// true/false
|
||||
#define SKILL_PROGRESSION_BINARY 1
|
||||
/// numerical
|
||||
#define SKILL_PROGRESSION_NUMERICAL 2
|
||||
/// Enum
|
||||
#define SKILL_PROGRESSION_ENUM 3
|
||||
/// Levels
|
||||
#define SKILL_PROGRESSION_LEVEL 4
|
||||
|
||||
|
||||
/// Max value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MAX 100
|
||||
/// Min value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MIN 0
|
||||
|
||||
// Standard values for job starting skills
|
||||
|
||||
#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX
|
||||
|
||||
// Standard values for job starting skill affinities
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO 1.2
|
||||
|
||||
// Standard values for skill gain (this is multiplied by affinity)
|
||||
|
||||
#define DEF_SKILL_GAIN 1
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
|
||||
#define SKILL_AFFINITY_MOOD_BONUS 1.25
|
||||
|
||||
///Items skill_flags and other defines
|
||||
#define SKILL_USE_TOOL (1<<0)
|
||||
#define SKILL_TRAINING_TOOL (1<<1)
|
||||
#define SKILL_ATTACK_MOB (1<<2)
|
||||
#define SKILL_TRAIN_ATTACK_MOB (1<<3)
|
||||
#define SKILL_ATTACK_OBJ (1<<4)
|
||||
#define SKILL_TRAIN_ATTACK_OBJ (1<<5)
|
||||
#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage.
|
||||
#define SKILL_THROW_STAM_COST (1<<7)
|
||||
#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on.
|
||||
#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
|
||||
#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
|
||||
|
||||
///competency_threshold index defines
|
||||
#define THRESHOLD_COMPETENT 1
|
||||
#define THRESHOLD_EXPERT 2
|
||||
#define THRESHOLD_MASTER 3
|
||||
|
||||
/// Level/Experience skills defines.
|
||||
#define STD_XP_LVL_UP 100
|
||||
#define STD_XP_LVL_MULTI 2
|
||||
#define STD_MAX_LVL 4
|
||||
|
||||
#define RPG_MAX_LVL 100
|
||||
|
||||
#define DORF_XP_LVL_UP 400
|
||||
#define DORF_XP_LVL_MULTI 100
|
||||
#define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5
|
||||
|
||||
//level up methods defines
|
||||
#define STANDARD_LEVEL_UP "standard_level_up"
|
||||
#define DWARFY_LEVEL_UP "dwarfy_level_up"
|
||||
|
||||
//job skill level defines
|
||||
#define JOB_SKILL_UNTRAINED 0
|
||||
#define JOB_SKILL_BASIC 1
|
||||
#define JOB_SKILL_TRAINED 2
|
||||
#define JOB_SKILL_EXPERT 3
|
||||
#define JOB_SKILL_MASTER 4
|
||||
|
||||
//other skill level defines, not an exhaustive catalogue, only contains be most relevant ones.
|
||||
#define DORF_SKILL_COMPETENT 3
|
||||
#define DORF_SKILL_EXPERT 8
|
||||
#define DORF_SKILL_MASTER 12
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
//How experience levels are calculated.
|
||||
#define XP_LEVEL(std, multi, lvl) (std*((multi**lvl)/(multi-1))-std/(multi-1)) //don't use 1 as multi, you'll get division by zero errors
|
||||
#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5)))
|
||||
|
||||
//More experience value getter macros
|
||||
#define GET_STANDARD_LVL(lvl) XP_LEVEL(STD_XP_LVL_UP, STD_XP_LVL_MULTI, lvl)
|
||||
#define GET_DORF_LVL(lvl) DORF_XP_LEVEL(DORF_XP_LVL_UP, DORF_XP_LVL_MULTI, lvl)
|
||||
@@ -1,28 +0,0 @@
|
||||
/// true/false
|
||||
#define SKILL_PROGRESSION_BINARY 1
|
||||
/// numerical
|
||||
#define SKILL_PROGRESSION_NUMERICAL 2
|
||||
/// Enum
|
||||
#define SKILL_PROGRESSION_ENUM 3
|
||||
|
||||
/// Max value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MAX 100
|
||||
/// Min value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MIN 0
|
||||
|
||||
// Standard values for job starting skills
|
||||
|
||||
#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX
|
||||
|
||||
// Standard values for job starting skill affinities
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2
|
||||
|
||||
// Standard values for skill gain (this is multiplied by affinity)
|
||||
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
|
||||
// Misc
|
||||
|
||||
/// 40% speedup at 100 skill
|
||||
#define SURGERY_SKILL_SPEEDUP_NUMERICAL_SCALE(number) clamp(number / 250, 1, 2)
|
||||
@@ -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",
|
||||
|
||||
@@ -255,6 +255,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
current_user = M.client
|
||||
//Blank
|
||||
menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = ABOVE_HUD_LAYER)
|
||||
menu_holder.plane = ABOVE_HUD_PLANE
|
||||
menu_holder.appearance_flags |= KEEP_APART
|
||||
menu_holder.vis_contents += elements + close_button
|
||||
current_user.images += menu_holder
|
||||
@@ -285,13 +286,16 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
Choices should be a list where list keys are movables or text used for element names and return value
|
||||
and list values are movables/icons/images used for element icons
|
||||
*/
|
||||
/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE)
|
||||
/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE)
|
||||
if(!user || !anchor || !length(choices))
|
||||
return
|
||||
if(!uniqueid)
|
||||
uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
|
||||
|
||||
if(GLOB.radial_menus[uniqueid])
|
||||
if(!no_repeat_close)
|
||||
var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid]
|
||||
menu.finished = TRUE
|
||||
return
|
||||
|
||||
var/datum/radial_menu/menu = new
|
||||
@@ -308,4 +312,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
var/answer = menu.selected_choice
|
||||
qdel(menu)
|
||||
GLOB.radial_menus -= uniqueid
|
||||
if(require_near && !in_range(anchor, user))
|
||||
return
|
||||
if(istype(custom_check))
|
||||
if(!custom_check.Invoke())
|
||||
return
|
||||
return answer
|
||||
@@ -91,7 +91,7 @@
|
||||
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
|
||||
add_fingerprint(user)
|
||||
|
||||
user.adjustStaminaLossBuffered(getweight()*0.8)//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_MOB_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
|
||||
//the equivalent of the standard version of attack() but for object targets.
|
||||
/obj/item/proc/attack_obj(obj/O, mob/living/user)
|
||||
@@ -102,7 +102,7 @@
|
||||
if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You're too exhausted.</span>") // CIT CHANGE - ditto
|
||||
return // CIT CHANGE - ditto
|
||||
user.adjustStaminaLossBuffered(getweight()*1.2)//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_OBJ_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(O)
|
||||
O.attacked_by(src, user)
|
||||
@@ -111,26 +111,32 @@
|
||||
return
|
||||
|
||||
/obj/attacked_by(obj/item/I, mob/living/user)
|
||||
if(I.force)
|
||||
var/totitemdamage = I.force
|
||||
var/bad_flag = NONE
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
totitemdamage *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(I.used_skills && user.mind)
|
||||
if(totitemdamage)
|
||||
totitemdamage = user.mind.skill_holder.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain)
|
||||
if(totitemdamage)
|
||||
visible_message("<span class='danger'>[user] has hit [src] with [I]!</span>", null, null, COMBAT_MESSAGE_RANGE)
|
||||
//only witnesses close by and the victim see a hit message.
|
||||
log_combat(user, src, "attacked", I)
|
||||
take_damage(I.force, I.damtype, "melee", 1)
|
||||
take_damage(totitemdamage, I.damtype, "melee", 1)
|
||||
|
||||
/mob/living/attacked_by(obj/item/I, mob/living/user)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
totitemdamage *= 0.5
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
totitemdamage *= 0.5
|
||||
//CIT CHANGES END HERE
|
||||
if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, null, null) & BLOCK_SUCCESS)
|
||||
return FALSE
|
||||
send_item_attack_message(I, user)
|
||||
I.do_stagger_action(src, user)
|
||||
I.do_stagger_action(src, user, totitemdamage)
|
||||
if(I.force)
|
||||
apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
apply_damage(totitemdamage, I.damtype)
|
||||
if(I.damtype == BRUTE)
|
||||
if(prob(33))
|
||||
I.add_mob_blood(src)
|
||||
@@ -146,6 +152,28 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = I.force
|
||||
var/bad_flag = NONE
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
. *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
. *= 0.5
|
||||
if(!user.mind || !I.used_skills)
|
||||
return
|
||||
if(.)
|
||||
. = user.mind.skill_holder.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain)
|
||||
|
||||
/mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = ..()
|
||||
if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
. *= 1.5
|
||||
|
||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
@@ -179,22 +207,30 @@
|
||||
return 1
|
||||
|
||||
/// How much stamina this takes to swing this is not for realism purposes hecc off.
|
||||
/obj/item/proc/getweight()
|
||||
return total_mass || w_class * 1.25
|
||||
/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST)
|
||||
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
|
||||
if(!user)
|
||||
return
|
||||
var/bad_flag = NONE
|
||||
if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
. *= STAM_COST_NO_COMBAT_MULT
|
||||
bad_flag |= SKILL_COMBAT_MODE
|
||||
if(used_skills && user.mind)
|
||||
. = user.mind.skill_holder.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE)
|
||||
|
||||
/// How long this staggers for. 0 and negatives supported.
|
||||
/obj/item/proc/melee_stagger_duration()
|
||||
/obj/item/proc/melee_stagger_duration(force_override)
|
||||
if(!isnull(stagger_force))
|
||||
return stagger_force
|
||||
/// totally not an untested, arbitrary equation.
|
||||
return clamp((1.5 + (w_class/7.5)) * (force / 2), 0, 10 SECONDS)
|
||||
return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS)
|
||||
|
||||
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user)
|
||||
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override)
|
||||
if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER))
|
||||
return FALSE
|
||||
if(target.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
|
||||
target.do_staggered_animation()
|
||||
var/duration = melee_stagger_duration()
|
||||
var/duration = melee_stagger_duration(force_override)
|
||||
if(!duration) //0
|
||||
return FALSE
|
||||
else if(duration > 0)
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
name = "Initializing..."
|
||||
var/target
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
|
||||
/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
|
||||
/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical
|
||||
. = ..()
|
||||
name = text
|
||||
src.target = target
|
||||
@@ -33,6 +31,14 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
usr.client.debug_variables(target)
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].")
|
||||
|
||||
/obj/effect/statclick/misc_subsystems/Click()
|
||||
if(!usr.client.holder)
|
||||
return
|
||||
var/subsystem = input(usr, "Debug which subsystem?", "Debug nonprocessing subsystem") as null|anything in (Master.subsystems - Master.statworthy_subsystems)
|
||||
if(!subsystem)
|
||||
return
|
||||
usr.client.debug_variables(subsystem)
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [subsystem] subsystem.")
|
||||
|
||||
// Debug verbs.
|
||||
/client/proc/restart_controller(controller in list("Master", "Failsafe"))
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
/datum/config_entry/keyed_list/midround_antag/ValidateListEntry(key_name, key_value)
|
||||
return key_name in config.modes
|
||||
|
||||
/datum/config_entry/keyed_list/force_antag_count
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
|
||||
/datum/config_entry/keyed_list/force_antag_count/ValidateListEntry(key_name, key_value)
|
||||
return key_name in config.modes
|
||||
|
||||
/datum/config_entry/keyed_list/policy
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_TEXT
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
// List of subsystems to process().
|
||||
var/list/subsystems
|
||||
/// List of subsystems to include in the MC stat panel.
|
||||
var/list/statworthy_subsystems
|
||||
|
||||
// Vars for keeping track of tick drift.
|
||||
var/init_timeofday
|
||||
@@ -65,6 +67,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/// Statclick for misc subsystems
|
||||
var/obj/effect/statclick/misc_subsystems/misc_statclick
|
||||
|
||||
/datum/controller/master/New()
|
||||
if(!config)
|
||||
config = new
|
||||
@@ -87,6 +92,11 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
_subsystems += new I
|
||||
Master = src
|
||||
|
||||
// We want to see all subsystems during init.
|
||||
statworthy_subsystems = subsystems.Copy()
|
||||
|
||||
misc_statclick = new(null, "Debug")
|
||||
|
||||
if(!GLOB)
|
||||
new /datum/controller/global_vars
|
||||
|
||||
@@ -257,10 +267,14 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/list/tickersubsystems = list()
|
||||
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
|
||||
var/timer = world.time
|
||||
statworthy_subsystems = list()
|
||||
for (var/thing in subsystems)
|
||||
var/datum/controller/subsystem/SS = thing
|
||||
if (SS.flags & SS_NO_FIRE)
|
||||
if(SS.flags & SS_ALWAYS_SHOW_STAT)
|
||||
statworthy_subsystems += SS
|
||||
continue
|
||||
statworthy_subsystems += SS
|
||||
SS.queued_time = 0
|
||||
SS.queue_next = null
|
||||
SS.queue_prev = null
|
||||
@@ -603,7 +617,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)")
|
||||
stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"))
|
||||
|
||||
stat("Misc Subsystems", misc_statclick)
|
||||
|
||||
/datum/controller/master/StartLoadingMap()
|
||||
//disallow more than one map to load at once, multithreading it will just cause race conditions
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
|
||||
trauma = _trauma
|
||||
owner = trauma.owner
|
||||
copy_known_languages_from(owner, TRUE)
|
||||
|
||||
setup_friend()
|
||||
|
||||
|
||||
@@ -26,21 +26,15 @@
|
||||
scan_desc = "extensive damage to the brain's language center"
|
||||
gain_text = "<span class='warning'>You have trouble forming words in your head...</span>"
|
||||
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"
|
||||
var/datum/language_holder/prev_language
|
||||
var/datum/language_holder/mob_language
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_gain()
|
||||
mob_language = owner.get_language_holder()
|
||||
prev_language = mob_language.copy()
|
||||
mob_language.remove_all_languages()
|
||||
mob_language.grant_language(/datum/language/aphasia)
|
||||
owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA)
|
||||
owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_lose()
|
||||
mob_language.remove_language(/datum/language/aphasia)
|
||||
mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
|
||||
QDEL_NULL(prev_language)
|
||||
mob_language = null
|
||||
owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA)
|
||||
owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/blindness
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
|
||||
/datum/crafting_recipe/upgraded_gauze
|
||||
name = "Improved Gauze"
|
||||
result = /obj/item/stack/medical/gauze/adv
|
||||
result = /obj/item/stack/medical/gauze/adv/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/space_cleaner/sterilizine = 10)
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
/datum/crafting_recipe/bruise_pack
|
||||
name = "Bruise Pack"
|
||||
result = /obj/item/stack/medical/bruise_pack
|
||||
result = /obj/item/stack/medical/bruise_pack/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
@@ -134,8 +134,8 @@
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/burn_pack
|
||||
name = "Brun Ointment"
|
||||
result = /obj/item/stack/medical/ointment
|
||||
name = "Burn Ointment"
|
||||
result = /obj/item/stack/medical/ointment/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
..()
|
||||
|
||||
@@ -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] = ""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -67,7 +67,7 @@
|
||||
var/datum/skill_holder/skill_holder
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
skill_holder = new
|
||||
skill_holder = new(src)
|
||||
src.key = key
|
||||
soulOwner = src
|
||||
martial_art = default_martial_art
|
||||
@@ -80,12 +80,12 @@
|
||||
if(antag_datum.delete_on_mind_deletion)
|
||||
qdel(i)
|
||||
antag_datums = null
|
||||
QDEL_NULL(skill_holder)
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/get_language_holder()
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/L = current.get_language_holder(shadow=FALSE)
|
||||
language_holder = L.copy(src)
|
||||
language_holder = new (src)
|
||||
|
||||
return language_holder
|
||||
|
||||
@@ -100,9 +100,6 @@
|
||||
if(iscarbon(current))
|
||||
var/mob/living/carbon/C = current
|
||||
C.disable_intentional_combat_mode(TRUE)
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
|
||||
language_holder = mob_holder.copy(src)
|
||||
|
||||
if(key)
|
||||
if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours
|
||||
@@ -130,6 +127,7 @@
|
||||
transfer_martial_arts(new_character)
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
current.update_atom_languages()
|
||||
|
||||
//CIT CHANGE - makes arousal update when transfering bodies
|
||||
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
|
||||
|
||||
@@ -277,10 +277,10 @@
|
||||
|
||||
/datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner)
|
||||
..()
|
||||
owner.grant_language(/datum/language/beachbum)
|
||||
owner.remove_language(/datum/language/common)
|
||||
owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
|
||||
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
|
||||
|
||||
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
|
||||
..()
|
||||
owner.grant_language(/datum/language/common)
|
||||
owner.remove_language(/datum/language/beachbum)
|
||||
owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
|
||||
owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
|
||||
/proc/init_skill_datums()
|
||||
. = list()
|
||||
@@ -9,16 +9,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
S = new path
|
||||
.[S.type] = S
|
||||
|
||||
/proc/get_skill_datum(path)
|
||||
return GLOB.skill_datums[path]
|
||||
|
||||
/proc/sanitize_skill_value(path, value)
|
||||
var/datum/skill/S = get_skill_datum(path)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
// don't check, if we runtime let it happen.
|
||||
return S.sanitize_value(value)
|
||||
|
||||
/proc/is_skill_value_greater(path, existing, new_value)
|
||||
var/datum/skill/S = get_skill_datum(path)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
// don't check, if we runtime let it happen.
|
||||
return S.is_value_greater(existing, new_value)
|
||||
|
||||
@@ -30,10 +27,18 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
var/name
|
||||
/// Our description
|
||||
var/desc
|
||||
/// Color of the name as shown in the html readout
|
||||
var/name_color = "#F0F0F0" // White on dark surface.
|
||||
/// Our progression type
|
||||
var/progression_type
|
||||
/// Abstract type
|
||||
var/abstract_type = /datum/skill
|
||||
/// skill threshold used in generic skill modifiers calculations.
|
||||
var/list/competency_thresholds = list(0, 0, 0)
|
||||
/// Multiplier of the difference of the holder skill value and the selected threshold.
|
||||
var/list/competency_mults = list(0, 0, 0)
|
||||
/// In which way this skil can affect or be affected through actions.
|
||||
var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
|
||||
|
||||
/**
|
||||
* Ensures what someone's setting as a value for this skill is valid.
|
||||
@@ -41,6 +46,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/proc/sanitize_value(new_value)
|
||||
return new_value
|
||||
|
||||
/**
|
||||
* Sets the new value of this skill in the holder skills list.
|
||||
* As well as possible feedback messages or secondary effects on value change, that's on you.
|
||||
*/
|
||||
/datum/skill/proc/set_skill_value(datum/skill_holder/H, value, mob/owner)
|
||||
H.skills[type] = value
|
||||
|
||||
/**
|
||||
* Checks if a value is greater
|
||||
*/
|
||||
@@ -52,7 +64,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/**
|
||||
* Standard value "render"
|
||||
*/
|
||||
/datum/skill/proc/standard_render_value(value)
|
||||
/datum/skill/proc/standard_render_value(value, level)
|
||||
return value
|
||||
|
||||
// Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context.
|
||||
@@ -61,11 +73,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/binary
|
||||
abstract_type = /datum/skill/binary
|
||||
progression_type = SKILL_PROGRESSION_BINARY
|
||||
competency_thresholds = list(FALSE, TRUE, TRUE)
|
||||
competency_mults = list(0.5, 0.5, 0.5)
|
||||
|
||||
/datum/skill/binary/sanitize_value(new_value)
|
||||
return new_value? TRUE : FALSE
|
||||
|
||||
/datum/skill/binary/standard_render_value(value)
|
||||
/datum/skill/binary/standard_render_value(value, level)
|
||||
return value? "Yes" : "No"
|
||||
|
||||
/datum/skill/numerical
|
||||
@@ -81,7 +95,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
/datum/skill/numerical/standard_render_value(value)
|
||||
/datum/skill/numerical/standard_render_value(value, level)
|
||||
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
|
||||
|
||||
/datum/skill/enum
|
||||
@@ -93,3 +107,102 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums())
|
||||
/datum/skill/enum/sanitize_value(new_value)
|
||||
if(new_value in valid_values)
|
||||
return new_value
|
||||
|
||||
/**
|
||||
* Classing r p g styled skills, tiered by lvl, and current/nextlvl experience.
|
||||
*/
|
||||
/datum/skill/level
|
||||
abstract_type = /datum/skill/level
|
||||
progression_type = SKILL_PROGRESSION_LEVEL
|
||||
var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100
|
||||
var/xp_lvl_multiplier = STD_XP_LVL_MULTI //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.)
|
||||
var/max_levels = STD_MAX_LVL
|
||||
var/level_up_method = STANDARD_LEVEL_UP //how levels are calculated.
|
||||
var/list/levels = list() //level thresholds, if associative, these will be preceded by tiers such as "novice" or "trained"
|
||||
var/associative = FALSE //See above.
|
||||
var/unskilled_tier = "Unskilled" //Only relevant for associative experience levels
|
||||
|
||||
//Builds the levels list.
|
||||
/datum/skill/level/New()
|
||||
. = ..()
|
||||
var/max_assoc = ""
|
||||
var/max_assoc_start = 1
|
||||
for(var/lvl in 1 to max_levels)
|
||||
var/value
|
||||
switch(level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
if(DWARFY_LEVEL_UP)
|
||||
value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
value = round(value, 1)
|
||||
if(!associative)
|
||||
levels += value
|
||||
continue
|
||||
if(max_assoc)
|
||||
levels["[max_assoc] +[max_assoc_start++]"] = value
|
||||
continue
|
||||
var/key = LAZYACCESS(levels, lvl)
|
||||
if(!key)
|
||||
if(lvl == 1) //You dun goof it.
|
||||
stack_trace("Skill datum [src] was set to have an associative levels list despite the latter having no key value.")
|
||||
associative = FALSE
|
||||
levels += value
|
||||
continue
|
||||
max_assoc = levels[lvl-1]
|
||||
levels["[max_assoc] +[max_assoc_start++]"] = value
|
||||
levels[key] = value
|
||||
|
||||
/datum/skill/level/sanitize_value(new_value)
|
||||
return max(new_value, 0)
|
||||
|
||||
/datum/skill/level/set_skill_value(datum/skill_holder/H, value, datum/mind/M, silent = FALSE)
|
||||
H.skills[type] = value
|
||||
var/new_level
|
||||
for(var/k in levels)
|
||||
if(value < (associative ? levels[k] : k))
|
||||
break
|
||||
new_level++
|
||||
var/old_level = LAZYACCESS(H.skill_levels, type)
|
||||
LAZYSET(H.skill_levels, type, new_level)
|
||||
. = new_level - old_level
|
||||
if(silent || !(M?.current))
|
||||
return
|
||||
if(. > 0)
|
||||
to_chat(M.current, "<span class='nicegreen'>I feel like I've become more proficient at [name]!</span>")
|
||||
else if(. < 0)
|
||||
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
|
||||
|
||||
/datum/skill/level/standard_render_value(value, level)
|
||||
var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
var/current_lvl_xp_sum = 0
|
||||
if(level)
|
||||
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
|
||||
var/next_index = max(max_levels, level+1)
|
||||
var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
|
||||
if(next_lvl_xp > current_lvl_xp_sum)
|
||||
next_lvl_xp -= current_lvl_xp_sum
|
||||
|
||||
|
||||
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]"
|
||||
|
||||
/datum/skill/level/job
|
||||
levels = list("Basic", "Trained", "Experienced", "Master")
|
||||
competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
competency_mults = list(0.15, 0.1, 0.1)
|
||||
associative = TRUE
|
||||
|
||||
//quite the reference, no?
|
||||
/datum/skill/level/dwarfy
|
||||
abstract_type = /datum/skill/level/dwarfy
|
||||
standard_xp_lvl_up = DORF_XP_LVL_UP
|
||||
xp_lvl_multiplier = DORF_XP_LVL_MULTI
|
||||
max_levels = DORF_MAX_LVL
|
||||
level_up_method = DWARFY_LEVEL_UP
|
||||
levels = list("Novice", "Adequate", "Competent", "Skilled",
|
||||
"Proficient", "Talented", "Adept", "Expert",
|
||||
"Professional", "Accomplished", "Great", "Master",
|
||||
"High Master", "Grand Master", "Legendary")
|
||||
competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER)
|
||||
competency_mults = list(0.15, 0.1, 0.08)
|
||||
associative = TRUE
|
||||
unskilled_tier = "Dabbling"
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
* Skill holder datums
|
||||
*/
|
||||
/datum/skill_holder
|
||||
var/datum/mind/owner
|
||||
/// Our list of skills and values. Lazylist. Associative. Keys are datum typepaths to the skill.
|
||||
var/list/skills
|
||||
/// Same as [skills] but affinities, which are multiplied to increase amount when gaining skills.
|
||||
var/list/skill_affinities
|
||||
/// Let's say we want to get a specific skill "level" without looping through a proc everytime.
|
||||
/// Only supported by skills with tiers or levels.
|
||||
var/list/skill_levels
|
||||
|
||||
/datum/skill_holder/New(datum/mind/M)
|
||||
. = ..()
|
||||
owner = M
|
||||
|
||||
/**
|
||||
* Grabs the value of a skill.
|
||||
@@ -15,54 +23,139 @@
|
||||
CRASH("Invalid get_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
if(!skills)
|
||||
return null
|
||||
return LAZYACCESS(skills, skill)
|
||||
return skills[skill]
|
||||
|
||||
/**
|
||||
* Grabs the level of a skill. Only supported by skills with tiers or levels.
|
||||
*/
|
||||
/datum/skill_holder/proc/get_skill_level(skill)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid get_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
if(!skill_levels)
|
||||
return 0
|
||||
return skill_levels[skill]
|
||||
|
||||
/**
|
||||
* Grabs our affinity for a skill. !!This is a multiplier!!
|
||||
*/
|
||||
/datum/skill_holder/proc/get_skill_affinity(skill)
|
||||
if(!ispath(skill))
|
||||
CRASH("Invalid get_skill_affinity call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
if(!skills)
|
||||
return 1
|
||||
. = 1
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid get_skill_affinity call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/affinity = LAZYACCESS(skill_affinities, skill)
|
||||
if(isnull(affinity))
|
||||
return 1
|
||||
return affinity
|
||||
if(!isnull(affinity))
|
||||
. = affinity
|
||||
var/list/wrapped = list(.)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_SKILL_GET_AFFINITY, skill, wrapped)
|
||||
. = wrapped[1]
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of a skill.
|
||||
*/
|
||||
/datum/skill_holder/proc/set_skill_value(skill, value)
|
||||
if(!ispath(skill))
|
||||
CRASH("Invalid set_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
LAZYINITLIST(skills)
|
||||
value = sanitize_skill_value(skill, value)
|
||||
/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
value = S.sanitize_value(value)
|
||||
if(!isnull(value))
|
||||
LAZYSET(skills, skill, value)
|
||||
LAZYINITLIST(skills)
|
||||
S.set_skill_value(src, value, owner, silent)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Boosts a skill to a value if not aobve
|
||||
*/
|
||||
/datum/skill_holder/proc/boost_skill_value_to(skill, value)
|
||||
/datum/skill_holder/proc/boost_skill_value_to(skill, value, silent = FALSE)
|
||||
var/current = get_skill_value(skill)
|
||||
if(!is_skill_value_greater(skill, current, value))
|
||||
return FALSE
|
||||
set_skill_value(skill, value)
|
||||
set_skill_value(skill, value, silent)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Automatic skill increase, multiplied by skill affinity if existing.
|
||||
* Only works if skill is numerical.
|
||||
*/
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value)
|
||||
if(!ispath(skill, /datum/skill/numerical))
|
||||
CRASH("You cannot auto increment a non numerical skill!")
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.")
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(S.progression_type != SKILL_PROGRESSION_NUMERICAL && S.progression_type != SKILL_PROGRESSION_LEVEL)
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
boost_skill_value_to(skill, current + (value * affinity))
|
||||
var/target_value = current + (value * affinity)
|
||||
if(maximum)
|
||||
target_value = max(target_value, maximum)
|
||||
if(target_value == maximum) //no more experience to gain, early return.
|
||||
return
|
||||
boost_skill_value_to(skill, target_value, silent)
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses one skill.
|
||||
* Args:
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * threshold : The difficulty of the action, in short. Refer to __DEFINES/skills/defines.dm for the defines.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/action_skills_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
|
||||
var/mod
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(!S)
|
||||
return
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
|
||||
|
||||
var/list/comsig_values = list(mod)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ACTION_SKILL_MOD, args, comsig_values)
|
||||
mod = comsig_values[MOD_VALUES_SKILL_MOD]
|
||||
|
||||
. = modifier_is_multiplier ? value*mod : value/mod
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses several skills, intended for items.
|
||||
* Args:
|
||||
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
|
||||
* * the value.
|
||||
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
|
||||
. = value
|
||||
var/sum = 0
|
||||
var/divisor = 0
|
||||
var/list/checked_skills
|
||||
for(var/k in I.used_skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[k]
|
||||
if(!S)
|
||||
continue
|
||||
var/our_flags = (I.used_skills[k]|S.skill_flags)
|
||||
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
|
||||
continue
|
||||
var/mod
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
|
||||
LAZYADD(checked_skills, S)
|
||||
|
||||
var/list/comsig_values = list(sum, divisor, checked_skills)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, args, comsig_values)
|
||||
sum = comsig_values[MOD_VALUES_ITEM_SKILLS_SUM]
|
||||
divisor = comsig_values[MOD_VALUES_ITEM_SKILLS_DIV]
|
||||
|
||||
if(divisor)
|
||||
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
|
||||
|
||||
/**
|
||||
* Generates a HTML readout of our skills.
|
||||
@@ -73,6 +166,6 @@
|
||||
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
|
||||
for(var/path in skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
out += "<tr><td>[S.name]</td><td>[S.standard_render_value(skills[path])]</td></tr>"
|
||||
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]</td></tr>"
|
||||
out += "</table>"
|
||||
return out.Join("")
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/datum/skill/level/job/wiring
|
||||
name = "Wiring"
|
||||
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
|
||||
name_color = COLOR_PALE_ORANGE
|
||||
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
|
||||
@@ -1,3 +1,5 @@
|
||||
/datum/skill/numerical/surgery
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at doing surgery."
|
||||
name_color = COLOR_PALE_BLUE_GRAY
|
||||
competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
var/list/assemblies = list() // List of attached assemblies.
|
||||
var/randomize = 0 // If every instance of these wires should be random.
|
||||
// Prevents wires from showing up in station blueprints
|
||||
var/req_knowledge = INFINITY //wiring skill level on which the functions are revealed.
|
||||
var/req_skill = JOB_SKILL_BASIC //used in user's cutting/pulsing/mending speed calculations.
|
||||
var/list/current_users //list of untrained people currently interacting with this set of wires.
|
||||
|
||||
/datum/wires/New(atom/holder)
|
||||
..()
|
||||
@@ -130,8 +133,22 @@
|
||||
cut_wires += wire
|
||||
on_cut(wire, mend = FALSE)
|
||||
|
||||
/datum/wires/proc/cut_color(color)
|
||||
/datum/wires/proc/cut_color(color, mob/living/user)
|
||||
LAZYINITLIST(current_users)
|
||||
if(current_users[user])
|
||||
return FALSE
|
||||
if(req_skill && user?.mind)
|
||||
var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring)
|
||||
if(level_diff > 0)
|
||||
LAZYSET(current_users, user, TRUE)
|
||||
to_chat(user, "<span class='notice'>You begin cutting [holder]'s [color] wire...</span>")
|
||||
if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user))
|
||||
LAZYREMOVE(current_users, user)
|
||||
return FALSE
|
||||
LAZYREMOVE(current_users, user)
|
||||
to_chat(user, "<span class='notice'>You cut [holder]'s [color] wire.</span>")
|
||||
cut(get_wire(color))
|
||||
return TRUE
|
||||
|
||||
/datum/wires/proc/cut_random()
|
||||
cut(wires[rand(1, wires.len)])
|
||||
@@ -146,7 +163,21 @@
|
||||
on_pulse(wire, user)
|
||||
|
||||
/datum/wires/proc/pulse_color(color, mob/living/user)
|
||||
LAZYINITLIST(current_users)
|
||||
if(current_users[user])
|
||||
return FALSE
|
||||
if(req_skill && user?.mind)
|
||||
var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring)
|
||||
if(level_diff > 0)
|
||||
LAZYSET(current_users, user, TRUE)
|
||||
to_chat(user, "<span class='notice'>You begin pulsing [holder]'s [color] wire...</span>")
|
||||
if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user))
|
||||
LAZYREMOVE(current_users, user)
|
||||
return FALSE
|
||||
LAZYREMOVE(current_users, user)
|
||||
to_chat(user, "<span class='notice'>You pulse [holder]'s [color] wire.</span>")
|
||||
pulse(get_wire(color), user)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/proc/pulse_assembly(obj/item/assembly/S)
|
||||
for(var/color in assemblies)
|
||||
@@ -224,7 +255,7 @@
|
||||
var/reveal_wires = FALSE
|
||||
|
||||
// Admin ghost can see a purpose of each wire.
|
||||
if(IsAdminGhost(user))
|
||||
if(IsAdminGhost(user) || user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) >= req_knowledge)
|
||||
reveal_wires = TRUE
|
||||
|
||||
// Same for anyone with an abductor multitool.
|
||||
@@ -259,18 +290,16 @@
|
||||
if("cut")
|
||||
I = L.is_holding_tool_quality(TOOL_WIRECUTTER)
|
||||
if(I || IsAdminGhost(usr))
|
||||
if(I && holder)
|
||||
if(cut_color(target_wire, L) && I && holder)
|
||||
I.play_tool_sound(holder, 20)
|
||||
cut_color(target_wire)
|
||||
. = TRUE
|
||||
else
|
||||
to_chat(L, "<span class='warning'>You need wirecutters!</span>")
|
||||
if("pulse")
|
||||
I = L.is_holding_tool_quality(TOOL_MULTITOOL)
|
||||
if(I || IsAdminGhost(usr))
|
||||
if(I && holder)
|
||||
if(pulse_color(target_wire, L) && I && holder)
|
||||
I.play_tool_sound(holder, 20)
|
||||
pulse_color(target_wire, L)
|
||||
. = TRUE
|
||||
else
|
||||
to_chat(L, "<span class='warning'>You need a multitool!</span>")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/airalarm
|
||||
holder_type = /obj/machinery/airalarm
|
||||
proper_name = "Air Alarm"
|
||||
req_knowledge = JOB_SKILL_MASTER
|
||||
|
||||
/datum/wires/airalarm/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/airlock
|
||||
holder_type = /obj/machinery/door/airlock
|
||||
proper_name = "Generic Airlock"
|
||||
req_skill = JOB_SKILL_UNTRAINED //Training wheel, as per request.
|
||||
var/wiretype
|
||||
|
||||
/datum/wires/airlock/secure
|
||||
@@ -52,10 +53,11 @@
|
||||
|
||||
/datum/wires/airlock/interactable(mob/user)
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
if(!A.panel_open)
|
||||
return FALSE
|
||||
if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100))
|
||||
return FALSE
|
||||
if(A.panel_open)
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/wires/airlock/get_status()
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/apc
|
||||
holder_type = /obj/machinery/power/apc
|
||||
proper_name = "APC"
|
||||
req_knowledge = JOB_SKILL_MASTER
|
||||
|
||||
/datum/wires/apc/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/autolathe
|
||||
holder_type = /obj/machinery/autolathe
|
||||
proper_name = "Autolathe"
|
||||
req_knowledge = JOB_SKILL_EXPERT
|
||||
|
||||
/datum/wires/autolathe/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
/datum/wires/emitter
|
||||
holder_type = /obj/machinery/power/emitter
|
||||
req_knowledge = JOB_SKILL_TRAINED
|
||||
req_skill = JOB_SKILL_UNTRAINED
|
||||
|
||||
/datum/wires/emitter/New(atom/holder)
|
||||
wires = list(WIRE_ZAP,WIRE_HACK)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/datum/wires/explosive/c4
|
||||
holder_type = /obj/item/grenade/plastic/c4
|
||||
randomize = TRUE //Same behaviour since no wire actually disarms it
|
||||
req_skill = JOB_SKILL_UNTRAINED
|
||||
|
||||
/datum/wires/explosive/c4/interactable(mob/user)
|
||||
var/obj/item/grenade/plastic/c4/P = holder
|
||||
@@ -29,6 +30,7 @@
|
||||
/datum/wires/explosive/pizza
|
||||
holder_type = /obj/item/pizzabox
|
||||
randomize = TRUE
|
||||
req_skill = JOB_SKILL_MASTER
|
||||
|
||||
/datum/wires/explosive/pizza/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/microwave
|
||||
holder_type = /obj/machinery/microwave
|
||||
proper_name = "Microwave"
|
||||
req_knowledge = JOB_SKILL_TRAINED
|
||||
req_skill = JOB_SKILL_UNTRAINED
|
||||
|
||||
/datum/wires/microwave/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/mulebot
|
||||
holder_type = /mob/living/simple_animal/bot/mulebot
|
||||
randomize = TRUE
|
||||
req_knowledge = JOB_SKILL_MASTER
|
||||
|
||||
/datum/wires/mulebot/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/particle_accelerator/control_box
|
||||
holder_type = /obj/machinery/particle_accelerator/control_box
|
||||
proper_name = "Particle Accelerator"
|
||||
req_knowledge = JOB_SKILL_EXPERT
|
||||
req_skill = JOB_SKILL_TRAINED
|
||||
|
||||
/datum/wires/particle_accelerator/control_box/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/rnd
|
||||
holder_type = /obj/machinery/rnd
|
||||
randomize = TRUE
|
||||
req_knowledge = JOB_SKILL_EXPERT
|
||||
|
||||
/datum/wires/rnd/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/radio
|
||||
holder_type = /obj/item/radio
|
||||
proper_name = "Radio"
|
||||
req_knowledge = JOB_SKILL_TRAINED
|
||||
req_skill = JOB_SKILL_UNTRAINED
|
||||
|
||||
/datum/wires/radio/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/robot
|
||||
holder_type = /mob/living/silicon/robot
|
||||
randomize = TRUE
|
||||
req_knowledge = JOB_SKILL_MASTER
|
||||
req_skill = JOB_SKILL_TRAINED
|
||||
|
||||
/datum/wires/robot/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/suit_storage_unit
|
||||
holder_type = /obj/machinery/suit_storage_unit
|
||||
proper_name = "Suit Storage Unit"
|
||||
req_knowledge = JOB_SKILL_TRAINED
|
||||
req_skill = JOB_SKILL_UNTRAINED
|
||||
|
||||
/datum/wires/suit_storage_unit/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/wires/syndicatebomb
|
||||
holder_type = /obj/machinery/syndicatebomb
|
||||
randomize = TRUE
|
||||
req_skill = JOB_SKILL_EXPERT //good luck, wannabe hero.
|
||||
|
||||
|
||||
/datum/wires/syndicatebomb/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/wires/tesla_coil
|
||||
randomize = 1 //Only one wire don't need blueprints
|
||||
holder_type = /obj/machinery/power/tesla_coil
|
||||
req_knowledge = JOB_SKILL_TRAINED
|
||||
|
||||
/datum/wires/tesla_coil/New(atom/holder)
|
||||
wires = list(WIRE_ZAP)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/wires/vending
|
||||
holder_type = /obj/machinery/vending
|
||||
proper_name = "Vending Unit"
|
||||
req_knowledge = JOB_SKILL_EXPERT
|
||||
|
||||
/datum/wires/vending/New(atom/holder)
|
||||
wires = list(
|
||||
|
||||
+83
-73
@@ -11,7 +11,7 @@
|
||||
var/throw_range = 7
|
||||
var/mob/pulledby = null
|
||||
var/initial_language_holder = /datum/language_holder
|
||||
var/datum/language_holder/language_holder
|
||||
var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence.
|
||||
var/verb_say = "says"
|
||||
var/verb_ask = "asks"
|
||||
var/verb_exclaim = "exclaims"
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
if(player.assigned_role == job)
|
||||
candidates -= player
|
||||
|
||||
if(candidates.len < recommended_enemies)
|
||||
if(candidates.len < recommended_enemies && CONFIG_GET(keyed_list/force_antag_count)[config_tag])
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a separate list of people who don't want to be one
|
||||
|
||||
@@ -90,7 +90,10 @@
|
||||
sabotage_type = "cloner"
|
||||
|
||||
/datum/sabotage_objective/cloner/check_conditions()
|
||||
return !(locate(/obj/machinery/clonepod) in GLOB.machines)
|
||||
for(var/obj/machinery/clonepod/cloner in GLOB.machines)
|
||||
if(is_station_level(cloner.z))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/sabotage_objective/ai_law
|
||||
name = "Upload a hacked law to the AI."
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
var/list/L = list()
|
||||
var/list/LL = list()
|
||||
var/hacked = FALSE
|
||||
var/hackable = TRUE
|
||||
var/disabled = 0
|
||||
var/shocked = FALSE
|
||||
var/hack_wire
|
||||
@@ -32,7 +31,7 @@
|
||||
var/selected_category
|
||||
var/screen = 1
|
||||
|
||||
var/datum/techweb/stored_research = /datum/techweb/specialized/autounlocking/autolathe
|
||||
var/datum/techweb/specialized/autounlocking/stored_research = /datum/techweb/specialized/autounlocking/autolathe
|
||||
var/list/categories = list(
|
||||
"Tools",
|
||||
"Electronics",
|
||||
@@ -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>")
|
||||
|
||||
@@ -400,12 +400,11 @@
|
||||
"<span class='notice'>You begin adding wires to [src]...</span>")
|
||||
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
|
||||
if(do_after(user, 60, target = src))
|
||||
if(constructionStep != CONSTRUCTION_GUTTED || B.get_amount() < 5 || !B)
|
||||
if(constructionStep != CONSTRUCTION_GUTTED || !B.use_tool(src, user, 0, 5))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] adds wires to [src].</span>", \
|
||||
"<span class='notice'>You wire [src].</span>")
|
||||
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
|
||||
B.use(5)
|
||||
constructionStep = CONSTRUCTION_WIRES_EXPOSED
|
||||
update_icon()
|
||||
return
|
||||
|
||||
@@ -205,11 +205,9 @@
|
||||
return
|
||||
if(1)
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if(coil.get_amount() < 5)
|
||||
if(!W.use_tool(src, user, 0, 5))
|
||||
to_chat(user, "<span class='warning'>You need more cable for this!</span>")
|
||||
else
|
||||
coil.use(5)
|
||||
buildstage = 2
|
||||
to_chat(user, "<span class='notice'>You wire \the [src].</span>")
|
||||
update_icon()
|
||||
|
||||
@@ -396,7 +396,6 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.Impersonation = user
|
||||
|
||||
Hologram.copy_known_languages_from(user,replace = TRUE)
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
@@ -555,9 +554,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
Hologram.alpha = 170
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.dir = SOUTH //for now
|
||||
Hologram.grant_all_languages(omnitongue=TRUE)
|
||||
var/datum/language_holder/holder = Hologram.get_language_holder()
|
||||
holder.selected_default_language = record.language
|
||||
holder.selected_language = record.language
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
@@ -649,7 +647,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
return
|
||||
if(HOLORECORD_LANGUAGE)
|
||||
var/datum/language_holder/holder = replay_holo.get_language_holder()
|
||||
holder.selected_default_language = entry[2]
|
||||
holder.selected_language = entry[2]
|
||||
if(HOLORECORD_PRESET)
|
||||
var/preset_type = entry[2]
|
||||
var/datum/preset_holoimage/H = new preset_type
|
||||
@@ -672,6 +670,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
updateDialog()
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram
|
||||
initial_language_holder = /datum/language_holder/universal
|
||||
var/mob/living/Impersonation
|
||||
var/datum/holocall/HC
|
||||
|
||||
|
||||
@@ -114,7 +114,6 @@
|
||||
add_fingerprint(user)
|
||||
if(charging)
|
||||
charging.update_icon()
|
||||
charging.forceMove(drop_location())
|
||||
user.put_in_hands(charging)
|
||||
|
||||
/obj/machinery/recharger/attack_tk(mob/user)
|
||||
|
||||
@@ -160,10 +160,7 @@
|
||||
to_chat(user, "<span class='warning'>You need one length of cable to repair [src]!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You begin to replace the wires...</span>")
|
||||
if(do_after(user, 30, target = src))
|
||||
if(coil.get_amount() < 1)
|
||||
return
|
||||
coil.use(1)
|
||||
if(W.use_tool(src, user, 30, 1))
|
||||
obj_integrity = max_integrity
|
||||
stat &= ~BROKEN
|
||||
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
obj/source, // the originating radio
|
||||
frequency, // the frequency the signal is taking place on
|
||||
atom/movable/virtualspeaker/speaker, // representation of the method's speaker
|
||||
datum/language/language, // the langauge of the message
|
||||
datum/language/language, // the language of the message
|
||||
message, // the text content of the message
|
||||
spans // the list of spans applied to the message
|
||||
)
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
////////////////////////////////
|
||||
/datum/component/construction/mecha
|
||||
var/base_icon
|
||||
var/looky_helpy = TRUE
|
||||
|
||||
/datum/component/construction/mecha/examine(mob/user)
|
||||
. = ..()
|
||||
if(looky_helpy)
|
||||
switch(steps[index]["key"])
|
||||
if(TOOL_WRENCH)
|
||||
. += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
|
||||
if(TOOL_SCREWDRIVER)
|
||||
. += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
|
||||
if(TOOL_WIRECUTTER)
|
||||
. += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
|
||||
if(/obj/item/stack/cable_coil)
|
||||
. += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
|
||||
if(/obj/item/circuitboard)
|
||||
. += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
|
||||
if(/obj/item/stock_parts/scanning_module)
|
||||
. += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/capacitor)
|
||||
. += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/cell)
|
||||
. += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
|
||||
if(/obj/item/stack/sheet/metal)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
|
||||
if(/obj/item/stack/sheet/plasteel)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
|
||||
if(/obj/item/bikehorn)
|
||||
. += "<span class='notice'>HONK IT!.</span>"
|
||||
if(/obj/item/clothing/mask/gas/clown_hat)
|
||||
. += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
|
||||
if(/obj/item/clothing/shoes/clown_shoes)
|
||||
. += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
|
||||
if(/obj/item/mecha_parts/part)
|
||||
. += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
|
||||
if(/obj/item/stack/ore/bluespace_crystal)
|
||||
. += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
|
||||
if(/obj/item/assembly/signaler/anomaly)
|
||||
. += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
|
||||
else
|
||||
return
|
||||
|
||||
/datum/component/construction/mecha/spawn_result()
|
||||
if(!result)
|
||||
|
||||
@@ -220,8 +220,7 @@
|
||||
return
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT))
|
||||
var/obj/item/stack/cable_coil/CC = W
|
||||
if(CC.use(2))
|
||||
if(W.use_tool(src, user, 0, 2))
|
||||
clearInternalDamage(MECHA_INT_SHORT_CIRCUIT)
|
||||
to_chat(user, "<span class='notice'>You replace the fused wires.</span>")
|
||||
else
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -132,6 +132,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
|
||||
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
|
||||
|
||||
///Skills vars
|
||||
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
|
||||
var/list/datum/skill/used_skills
|
||||
var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
|
||||
var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.
|
||||
|
||||
/obj/item/Initialize()
|
||||
|
||||
if (attack_verb)
|
||||
@@ -783,7 +789,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
|
||||
// Called when a mob tries to use the item as a tool.
|
||||
// Handles most checks.
|
||||
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
|
||||
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = 1, max_level = INFINITY)
|
||||
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
|
||||
// Run the start check here so we wouldn't have to call it manually.
|
||||
if(!delay && !tool_start_check(user, amount))
|
||||
@@ -795,6 +801,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
play_tool_sound(target, volume)
|
||||
|
||||
if(delay)
|
||||
if(user.mind && used_skills)
|
||||
delay = user.mind.skill_holder.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
|
||||
|
||||
// Create a callback with checks that would be called every tick by do_after.
|
||||
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
|
||||
|
||||
@@ -819,6 +828,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
if(delay >= MIN_TOOL_SOUND_DELAY)
|
||||
play_tool_sound(target, volume)
|
||||
|
||||
if(user.mind && used_skills && skill_gain_mult)
|
||||
for(var/skill in used_skills)
|
||||
if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
|
||||
continue
|
||||
user.mind.skill_holder.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
|
||||
|
||||
return TRUE
|
||||
|
||||
// Called before use_tool if there is a delay, or by use_tool if there isn't.
|
||||
|
||||
@@ -6,17 +6,42 @@
|
||||
icon_state = "cutout_basic"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
resistance_flags = FLAMMABLE
|
||||
// Possible restyles for the cutout;
|
||||
// add an entry in change_appearance() if you add to here
|
||||
var/list/possible_appearances = list("Assistant", "Clown", "Mime",
|
||||
"Traitor", "Nuke Op", "Cultist", "Brass Cultist", "Clockwork Cultist",
|
||||
"Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Xenomorph Maid", "Swarmer",
|
||||
"Ash Walker", "Deathsquad Officer", "Ian", "Slaughter Demon",
|
||||
"Laughter Demon", "Private Security Officer", "Securitron", "Gondola", "Monkey")
|
||||
var/pushed_over = FALSE //If the cutout is pushed over and has to be righted
|
||||
var/deceptive = FALSE //If the cutout actually appears as what it portray and not a discolored version
|
||||
/// Possible restyles for the cutout, add an entry in change_appearance() if you add to here
|
||||
var/static/list/possible_appearances
|
||||
/// If the cutout is pushed over and has to be righted
|
||||
var/pushed_over = FALSE
|
||||
/// If the cutout actually appears as what it portray and not a discolored version
|
||||
var/deceptive = FALSE
|
||||
|
||||
var/lastattacker = null
|
||||
/obj/item/cardboard_cutout/Initialize()
|
||||
. = ..()
|
||||
if(possible_appearances)
|
||||
return
|
||||
possible_appearances = sortList(list(
|
||||
"Assistant" = image(icon = src.icon, icon_state = "cutout_greytide"),
|
||||
"Clown" = image(icon = src.icon, icon_state = "cutout_clown"),
|
||||
"Mime" = image(icon = src.icon, icon_state = "cutout_mime"),
|
||||
"Traitor" = image(icon = src.icon, icon_state = "cutout_traitor"),
|
||||
"Nuke Op" = image(icon = src.icon, icon_state = "cutout_fluke"),
|
||||
"Cultist" = image(icon = src.icon, icon_state = "cutout_cultist"),
|
||||
"Brass Cultist" = image(icon = src.icon, icon_state = "cutout_servant"),
|
||||
"Clockwork Cultist" = image(icon = src.icon, icon_state = "cutout_new_servant"),
|
||||
"Revolutionary" = image(icon = src.icon, icon_state = "cutout_viva"),
|
||||
"Wizard" = image(icon = src.icon, icon_state = "cutout_wizard"),
|
||||
"Shadowling" = image(icon = src.icon, icon_state = "cutout_shadowling"),
|
||||
"Xenomorph" = image(icon = src.icon, icon_state = "cutout_fukken_xeno"),
|
||||
"Xenomorph Maid" = image(icon = src.icon, icon_state = "cutout_lusty"),
|
||||
"Swarmer" = image(icon = src.icon, icon_state = "cutout_swarmer"),
|
||||
"Ash Walker" = image(icon = src.icon, icon_state = "cutout_free_antag"),
|
||||
"Deathsquad Officer" = image(icon = src.icon, icon_state = "cutout_deathsquad"),
|
||||
"Ian" = image(icon = src.icon, icon_state = "cutout_ian"),
|
||||
"Slaughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "daemon"),
|
||||
"Laughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "bowmon"),
|
||||
"Private Security Officer" = image(icon = src.icon, icon_state = "cutout_ntsec"),
|
||||
"Securitron" = image(icon = src.icon, icon_state = "cutout_law"),
|
||||
"Gondola" = image(icon = src.icon, icon_state = "cutout_gondola"),
|
||||
"Monkey" = image(icon = src.icon, icon_state = "cutout_monky"),
|
||||
))
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/cardboard_cutout/attack_hand(mob/living/user)
|
||||
@@ -76,22 +101,21 @@
|
||||
push_over()
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/**
|
||||
* change_appearance: Changes a skin of the cardboard cutout based on a user's choice
|
||||
*
|
||||
* Arguments:
|
||||
* * crayon The crayon used to change and recolor the cardboard cutout
|
||||
* * user The mob choosing a skin of the cardboard cutout
|
||||
*/
|
||||
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
|
||||
if(!crayon || !user)
|
||||
return
|
||||
if(pushed_over)
|
||||
to_chat(user, "<span class='warning'>Right [src] first!</span>")
|
||||
return
|
||||
if(crayon.check_empty(user))
|
||||
return
|
||||
if(crayon.is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return
|
||||
var/new_appearance = input(user, "Choose a new appearance for [src].", "26th Century Deception") as null|anything in possible_appearances
|
||||
if(!new_appearance || !crayon || !user.canUseTopic(src))
|
||||
var/new_appearance = show_radial_menu(user, src, possible_appearances, custom_check = CALLBACK(src, .proc/check_menu, user, crayon), radius = 36, require_near = TRUE)
|
||||
if(!new_appearance)
|
||||
return
|
||||
if(!do_after(user, 10, FALSE, src, TRUE))
|
||||
return
|
||||
return FALSE
|
||||
if(!check_menu(user, crayon))
|
||||
return FALSE
|
||||
user.visible_message("<span class='notice'>[user] gives [src] a new look.</span>", "<span class='notice'>Voila! You give [src] a new look.</span>")
|
||||
crayon.use_charges(1)
|
||||
crayon.check_empty(user)
|
||||
@@ -196,7 +220,33 @@
|
||||
name = "monkey ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a monkey."
|
||||
icon_state = "cutout_monky"
|
||||
return 1
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
* * crayon The crayon used to interact with a menu
|
||||
*/
|
||||
/obj/item/cardboard_cutout/proc/check_menu(mob/living/user, obj/item/toy/crayon/crayon)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(pushed_over)
|
||||
to_chat(user, "<span class='warning'>Right [src] first!</span>")
|
||||
return FALSE
|
||||
if(!crayon || !user.is_holding(crayon))
|
||||
return FALSE
|
||||
if(crayon.check_empty(user))
|
||||
return FALSE
|
||||
if(crayon.is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/cardboard_cutout/setDir(newdir)
|
||||
dir = SOUTH
|
||||
|
||||
@@ -199,7 +199,7 @@
|
||||
if(!spans)
|
||||
spans = list(M.speech_span)
|
||||
if(!language)
|
||||
language = M.get_default_language()
|
||||
language = M.get_selected_language()
|
||||
INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
|
||||
@@ -97,8 +97,7 @@
|
||||
to_chat(user, "<span class='notice'>You add [A] to the [initial(name)] assembly.</span>")
|
||||
|
||||
else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/C = I
|
||||
if (C.use(1))
|
||||
if (I.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC))
|
||||
det_time = 50 // In case the cable_coil was removed and readded.
|
||||
stage_change(WIRED)
|
||||
to_chat(user, "<span class='notice'>You rig the [initial(name)] assembly.</span>")
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
custom_materials = list(/datum/material/iron=150, /datum/material/glass=75)
|
||||
breakouttime = 300 //Deciseconds = 30s
|
||||
cuffsound = 'sound/weapons/cablecuff.ogg'
|
||||
cuffsound = 'sound/weapons/cablecuff.ogg'
|
||||
|
||||
/obj/item/restraints/handcuffs/cable/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You start unwinding the cable restraints back into coil</span>")
|
||||
@@ -130,7 +130,7 @@
|
||||
user.put_in_hands(coil)
|
||||
coil.color = color
|
||||
to_chat(user, "<span class='notice'>You unwind the cable restraints back into coil</span>")
|
||||
|
||||
|
||||
/obj/item/restraints/handcuffs/cable/red
|
||||
color = "#ff0000"
|
||||
|
||||
@@ -225,7 +225,6 @@
|
||||
/obj/item/restraints/handcuffs/fake/kinky
|
||||
name = "kinky handcuffs"
|
||||
desc = "Fake handcuffs meant for erotic roleplay."
|
||||
icon = 'modular_citadel/icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "handcuffgag"
|
||||
item_state = "kinkycuff"
|
||||
|
||||
@@ -252,7 +251,7 @@
|
||||
throw_range = 1
|
||||
icon_state = "beartrap"
|
||||
desc = "A trap used to catch bears and other legged creatures."
|
||||
var/armed = 0
|
||||
var/armed = FALSE
|
||||
var/trap_damage = 20
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/Initialize()
|
||||
@@ -275,14 +274,14 @@
|
||||
if(armed && isturf(src.loc))
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
var/snap = 0
|
||||
var/snap = FALSE
|
||||
var/def_zone = BODY_ZONE_CHEST
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
snap = 1
|
||||
if(!C.lying)
|
||||
def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
if(!C.legcuffed && C.get_num_legs(FALSE) >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
|
||||
snap = TRUE
|
||||
C.legcuffed = src
|
||||
forceMove(C)
|
||||
C.update_equipment_speed_mods()
|
||||
@@ -291,21 +290,21 @@
|
||||
else if(isanimal(L))
|
||||
var/mob/living/simple_animal/SA = L
|
||||
if(SA.mob_size > MOB_SIZE_TINY)
|
||||
snap = 1
|
||||
if(L.movement_type & FLYING)
|
||||
snap = 0
|
||||
snap = TRUE
|
||||
if(L.movement_type & (FLYING | FLOATING))
|
||||
snap = FALSE
|
||||
if(snap)
|
||||
armed = 0
|
||||
armed = FALSE
|
||||
icon_state = "[initial(icon_state)][armed]"
|
||||
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
L.visible_message("<span class='danger'>[L] triggers \the [src].</span>", \
|
||||
"<span class='userdanger'>You trigger \the [src]!</span>")
|
||||
L.apply_damage(trap_damage,BRUTE, def_zone)
|
||||
L.apply_damage(trap_damage, BRUTE, def_zone)
|
||||
..()
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/energy
|
||||
name = "energy snare"
|
||||
armed = 1
|
||||
armed = TRUE
|
||||
icon_state = "e_snare"
|
||||
trap_damage = 0
|
||||
item_flags = DROPDEL
|
||||
|
||||
@@ -519,7 +519,9 @@
|
||||
S.name = name
|
||||
S.ckey = C.ckey
|
||||
S.status_flags |= GODMODE
|
||||
S.language_holder = user.language_holder.copy(S)
|
||||
S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user.
|
||||
S.update_atom_languages()
|
||||
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
|
||||
S.AddElement(/datum/element/ghost_role_eligibility,penalize_on_ghost = TRUE)
|
||||
START_PROCESSING(SSprocessing,src)
|
||||
var/input = stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN)
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
return
|
||||
else
|
||||
if(cooldown_check < world.time)
|
||||
if(target.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS)
|
||||
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS)
|
||||
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return
|
||||
if(ishuman(target))
|
||||
@@ -325,7 +325,7 @@
|
||||
else
|
||||
target.LAssailant = WEAKREF(user)
|
||||
cooldown_check = world.time + cooldown
|
||||
user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes swinging batons cost stamina
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT))
|
||||
else
|
||||
var/wait_desc = get_wait_description()
|
||||
if(wait_desc)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/charge_cost = 30
|
||||
|
||||
/obj/item/borg/stun/attack(mob/living/M, mob/living/user)
|
||||
if(M.run_block(src, 0, "[M]'s [name]", ATTACK_TYPE_MELEE, 0, user, ran_zone(user.zone_selected)) & BLOCK_SUCCESS)
|
||||
if(M.mob_run_block(src, 0, "[M]'s [name]", ATTACK_TYPE_MELEE, 0, user, ran_zone(user.zone_selected), null) & BLOCK_SUCCESS)
|
||||
playsound(M, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
if(iscyborg(user))
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
self_delay = 20
|
||||
grind_results = list(/datum/reagent/medicine/styptic_powder = 10)
|
||||
|
||||
/obj/item/stack/medical/bruise_pack/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/bruise_pack/heal(mob/living/M, mob/user)
|
||||
if(M.stat == DEAD)
|
||||
to_chat(user, "<span class='notice'> [M] is dead. You can not help [M.p_them()]!</span>")
|
||||
@@ -134,6 +137,9 @@
|
||||
singular_name = "sterilized medical gauze"
|
||||
self_delay = 5
|
||||
|
||||
/obj/item/stack/medical/gauze/adv/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/gauze/cyborg
|
||||
custom_materials = null
|
||||
is_cyborg = 1
|
||||
@@ -151,6 +157,9 @@
|
||||
self_delay = 20
|
||||
grind_results = list(/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
|
||||
/obj/item/stack/medical/ointment/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
|
||||
if(M.stat == DEAD)
|
||||
to_chat(user, "<span class='notice'> [M] is dead. You can not help [M.p_them()]!</span>")
|
||||
|
||||
@@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
|
||||
if (get_amount() < 1 || CC.get_amount() < 5)
|
||||
to_chat(user, "<span class='warning>You need five lengths of coil and one sheet of glass to make wired glass!</span>")
|
||||
return
|
||||
CC.use(5)
|
||||
CC.use_tool(src, user, 0, 5, max_level = JOB_SKILL_BASIC)
|
||||
use(1)
|
||||
to_chat(user, "<span class='notice'>You attach wire to the [name].</span>")
|
||||
var/obj/item/stack/light_w/new_tile = new(user.loc)
|
||||
|
||||
@@ -850,12 +850,6 @@
|
||||
|
||||
|
||||
|
||||
#define NODESIGN "None"
|
||||
#define NANOTRASEN "NanotrasenStandard"
|
||||
#define SYNDI "SyndiSnacks"
|
||||
#define HEART "Heart"
|
||||
#define SMILEY "SmileyFace"
|
||||
|
||||
/obj/item/storage/box/papersack
|
||||
name = "paper sack"
|
||||
desc = "A sack neatly crafted out of paper."
|
||||
@@ -863,7 +857,18 @@
|
||||
item_state = "paperbag_None"
|
||||
resistance_flags = FLAMMABLE
|
||||
foldable = null
|
||||
var/design = NODESIGN
|
||||
/// A list of all available papersack reskins
|
||||
var/list/papersack_designs = list()
|
||||
|
||||
/obj/item/storage/box/papersack/Initialize(mapload)
|
||||
. = ..()
|
||||
papersack_designs = sortList(list(
|
||||
"None" = image(icon = src.icon, icon_state = "paperbag_None"),
|
||||
"NanotrasenStandard" = image(icon = src.icon, icon_state = "paperbag_NanotrasenStandard"),
|
||||
"SyndiSnacks" = image(icon = src.icon, icon_state = "paperbag_SyndiSnacks"),
|
||||
"Heart" = image(icon = src.icon, icon_state = "paperbag_Heart"),
|
||||
"SmileyFace" = image(icon = src.icon, icon_state = "paperbag_SmileyFace")
|
||||
))
|
||||
|
||||
/obj/item/storage/box/papersack/update_icon_state()
|
||||
if(contents.len == 0)
|
||||
@@ -871,55 +876,64 @@
|
||||
else
|
||||
icon_state = "[item_state]_closed"
|
||||
|
||||
|
||||
/obj/item/storage/box/papersack/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/pen))
|
||||
//if a pen is used on the sack, dialogue to change its design appears
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='warning'>You can't modify [src] with items still inside!</span>")
|
||||
return
|
||||
var/list/designs = list(NODESIGN, NANOTRASEN, SYNDI, HEART, SMILEY, "Cancel")
|
||||
var/switchDesign = input("Select a Design:", "Paper Sack Design", designs[1]) in designs
|
||||
if(get_dist(usr, src) > 1)
|
||||
to_chat(usr, "<span class='warning'>You have moved too far away!</span>")
|
||||
return
|
||||
var/choice = designs.Find(switchDesign)
|
||||
if(design == designs[choice] || designs[choice] == "Cancel")
|
||||
return 0
|
||||
to_chat(usr, "<span class='notice'>You make some modifications to [src] using your pen.</span>")
|
||||
design = designs[choice]
|
||||
icon_state = "paperbag_[design]"
|
||||
item_state = "paperbag_[design]"
|
||||
switch(designs[choice])
|
||||
if(NODESIGN)
|
||||
var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, .proc/check_menu, user, W), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
if(icon_state == "paperbag_[choice]")
|
||||
return FALSE
|
||||
switch(choice)
|
||||
if("None")
|
||||
desc = "A sack neatly crafted out of paper."
|
||||
if(NANOTRASEN)
|
||||
if("NanotrasenStandard")
|
||||
desc = "A standard Nanotrasen paper lunch sack for loyal employees on the go."
|
||||
if(SYNDI)
|
||||
if("SyndiSnacks")
|
||||
desc = "The design on this paper sack is a remnant of the notorious 'SyndieSnacks' program."
|
||||
if(HEART)
|
||||
if("Heart")
|
||||
desc = "A paper sack with a heart etched onto the side."
|
||||
if(SMILEY)
|
||||
if("SmileyFace")
|
||||
desc = "A paper sack with a crude smile etched onto the side."
|
||||
return 0
|
||||
else
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You make some modifications to [src] using your pen.</span>")
|
||||
icon_state = "paperbag_[choice]"
|
||||
item_state = "paperbag_[choice]"
|
||||
return FALSE
|
||||
else if(W.get_sharpness())
|
||||
if(!contents.len)
|
||||
if(item_state == "paperbag_None")
|
||||
user.show_message("<span class='notice'>You cut eyeholes into [src].</span>", MSG_VISUAL)
|
||||
new /obj/item/clothing/head/papersack(user.loc)
|
||||
qdel(src)
|
||||
return 0
|
||||
return FALSE
|
||||
else if(item_state == "paperbag_SmileyFace")
|
||||
user.show_message("<span class='notice'>You cut eyeholes into [src] and modify the design.</span>", MSG_VISUAL)
|
||||
new /obj/item/clothing/head/papersack/smiley(user.loc)
|
||||
qdel(src)
|
||||
return 0
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
#undef NODESIGN
|
||||
#undef NANOTRASEN
|
||||
#undef SYNDI
|
||||
#undef HEART
|
||||
#undef SMILEY
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
* * P The pen used to interact with a menu
|
||||
*/
|
||||
/obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='warning'>You can't modify [src] with items still inside!</span>")
|
||||
return FALSE
|
||||
if(!P || !user.is_holding(P))
|
||||
to_chat(user, "<span class='warning'>You need a pen to modify [src]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist.
|
||||
name = "ingredients box"
|
||||
|
||||
@@ -163,14 +163,14 @@
|
||||
if(status)
|
||||
if(baton_stun(M, user, disarming))
|
||||
user.do_attack_animation(M)
|
||||
user.adjustStaminaLossBuffered(getweight()) //CIT CHANGE - makes stunbatonning others cost stamina
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT))
|
||||
else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc.
|
||||
M.visible_message("<span class='warning'>[user] has prodded [M] with [src]. Luckily it was off.</span>", \
|
||||
"<span class='warning'>[user] has prodded you with [src]. Luckily it was off</span>")
|
||||
return disarming || (user.a_intent != INTENT_HARM)
|
||||
|
||||
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE)
|
||||
if(L.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; check_shields() handles that
|
||||
if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; check_shields() handles that
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
var/stunpwr = stamforce
|
||||
@@ -232,11 +232,8 @@
|
||||
/obj/item/melee/baton/stunsword
|
||||
name = "stunsword"
|
||||
desc = "not actually sharp, this sword is functionally identical to a stunbaton"
|
||||
icon = 'modular_citadel/icons/obj/stunsword.dmi'
|
||||
icon_state = "stunsword"
|
||||
item_state = "sword"
|
||||
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
|
||||
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
|
||||
|
||||
/obj/item/melee/baton/stunsword/get_belt_overlay()
|
||||
if(istype(loc, /obj/item/storage/belt/sabre))
|
||||
|
||||
@@ -241,11 +241,13 @@
|
||||
playsound(user, activation_sound, transform_volume, 1)
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
AddElement(/datum/element/sword_point)
|
||||
total_mass = total_mass_on
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[deactivation_message]</span>")
|
||||
playsound(user, deactivation_sound, transform_volume, 1)
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
RemoveElement(/datum/element/sword_point)
|
||||
total_mass = initial(total_mass)
|
||||
|
||||
update_icon()
|
||||
add_fingerprint(user)
|
||||
@@ -287,9 +289,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/sword/getweight()
|
||||
return (active ? total_mass_on : total_mass) || w_class *1.25
|
||||
|
||||
/obj/item/toy/sword/cx
|
||||
name = "\improper DX Non-Euplastic LightSword"
|
||||
desc = "A deluxe toy replica of an energy sword. Realistic visuals and sounds! Ages 8 and up."
|
||||
@@ -903,79 +902,57 @@
|
||||
name = "hand of cards"
|
||||
desc = "A number of cards not in a deck, customarily held in ones hand."
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "nanotrasen_hand2"
|
||||
icon_state = "none"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/list/currenthand = list()
|
||||
var/choice = null
|
||||
|
||||
|
||||
/obj/item/toy/cards/cardhand/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/list/handradial = list()
|
||||
interact(user)
|
||||
|
||||
/obj/item/toy/cards/cardhand/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat = "You have:<BR>"
|
||||
for(var/t in currenthand)
|
||||
dat += "<A href='?src=[REF(src)];pick=[t]'>A [t].</A><BR>"
|
||||
dat += "Which card will you remove next?"
|
||||
var/datum/browser/popup = new(user, "cardhand", "Hand of Cards", 400, 240)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
handradial[t] = image(icon = src.icon, icon_state = "sc_[t]_[deckstyle]")
|
||||
|
||||
|
||||
/obj/item/toy/cards/cardhand/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(usr.stat || !ishuman(usr))
|
||||
return
|
||||
var/mob/living/carbon/human/cardUser = usr
|
||||
var/O = src
|
||||
if(href_list["pick"])
|
||||
if (cardUser.is_holding(src))
|
||||
var/choice = href_list["pick"]
|
||||
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
|
||||
src.currenthand -= choice
|
||||
C.parentdeck = src.parentdeck
|
||||
C.cardname = choice
|
||||
C.apply_card_vars(C,O)
|
||||
C.pickup(cardUser)
|
||||
cardUser.put_in_hands(C)
|
||||
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
|
||||
|
||||
interact(cardUser)
|
||||
if(src.currenthand.len < 3)
|
||||
src.icon_state = "[deckstyle]_hand2"
|
||||
else if(src.currenthand.len < 4)
|
||||
src.icon_state = "[deckstyle]_hand3"
|
||||
else if(src.currenthand.len < 5)
|
||||
src.icon_state = "[deckstyle]_hand4"
|
||||
if(src.currenthand.len == 1)
|
||||
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(src.loc)
|
||||
N.parentdeck = src.parentdeck
|
||||
N.cardname = src.currenthand[1]
|
||||
N.apply_card_vars(N,O)
|
||||
qdel(src)
|
||||
N.pickup(cardUser)
|
||||
cardUser.put_in_hands(N)
|
||||
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
|
||||
cardUser << browse(null, "window=cardhand")
|
||||
if(!(cardUser.mobility_flags & MOBILITY_USE))
|
||||
return
|
||||
var/O = src
|
||||
var/choice = show_radial_menu(usr,src, handradial, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
|
||||
currenthand -= choice
|
||||
handradial -= choice
|
||||
C.parentdeck = parentdeck
|
||||
C.cardname = choice
|
||||
C.apply_card_vars(C,O)
|
||||
C.pickup(cardUser)
|
||||
cardUser.put_in_hands(C)
|
||||
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
|
||||
|
||||
interact(cardUser)
|
||||
update_sprite()
|
||||
if(length(currenthand) == 1)
|
||||
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(loc)
|
||||
N.parentdeck = parentdeck
|
||||
N.cardname = currenthand[1]
|
||||
N.apply_card_vars(N,O)
|
||||
qdel(src)
|
||||
N.pickup(cardUser)
|
||||
cardUser.put_in_hands(N)
|
||||
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
|
||||
|
||||
/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params)
|
||||
if(istype(C))
|
||||
if(C.parentdeck == src.parentdeck)
|
||||
src.currenthand += C.cardname
|
||||
user.visible_message("[user] adds a card to [user.p_their()] hand.", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
|
||||
user.visible_message("<span class='notice'>[user] adds a card to [user.p_their()] hand.</span>", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
|
||||
qdel(C)
|
||||
interact(user)
|
||||
if(currenthand.len > 4)
|
||||
src.icon_state = "[deckstyle]_hand5"
|
||||
else if(currenthand.len > 3)
|
||||
src.icon_state = "[deckstyle]_hand4"
|
||||
else if(currenthand.len > 2)
|
||||
src.icon_state = "[deckstyle]_hand3"
|
||||
update_sprite(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
|
||||
else
|
||||
@@ -984,7 +961,7 @@
|
||||
/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj)
|
||||
..()
|
||||
newobj.deckstyle = sourceobj.deckstyle
|
||||
newobj.icon_state = "[deckstyle]_hand2" // Another dumb hack, without this the hand is invisible (or has the default deckstyle) until another card is added.
|
||||
update_sprite()
|
||||
newobj.card_hitsound = sourceobj.card_hitsound
|
||||
newobj.card_force = sourceobj.card_force
|
||||
newobj.card_throwforce = sourceobj.card_throwforce
|
||||
@@ -993,6 +970,31 @@
|
||||
newobj.card_attack_verb = sourceobj.card_attack_verb
|
||||
newobj.resistance_flags = sourceobj.resistance_flags
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
*/
|
||||
/obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* This proc updates the sprite for when you create a hand of cards
|
||||
*/
|
||||
/obj/item/toy/cards/cardhand/proc/update_sprite()
|
||||
cut_overlays()
|
||||
var/overlay_cards = currenthand.len
|
||||
|
||||
var/k = overlay_cards == 2 ? 1 : overlay_cards - 2
|
||||
for(var/i = k; i <= overlay_cards; i++)
|
||||
var/card_overlay = image(icon=src.icon,icon_state="sc_[currenthand[i]]_[deckstyle]",pixel_x=(1-i+k)*3,pixel_y=(1-i+k)*3)
|
||||
add_overlay(card_overlay)
|
||||
|
||||
/obj/item/toy/cards/singlecard
|
||||
name = "card"
|
||||
desc = "a card"
|
||||
|
||||
@@ -1182,7 +1182,7 @@
|
||||
if(iscyborg(target))
|
||||
..()
|
||||
return
|
||||
if(target.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; run_block() handles that
|
||||
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; run_block() handles that
|
||||
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
if(user.a_intent != INTENT_HARM)
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
if(C.get_amount() >= 5)
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
|
||||
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5))
|
||||
if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use_tool(src, user, 0, 5))
|
||||
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
|
||||
state = CABLED_CORE
|
||||
update_icon()
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
panel_open = FALSE
|
||||
|
||||
else if(istype(I, /obj/item/stack/cable_coil) && panel_open)
|
||||
var/obj/item/stack/cable_coil/C = I
|
||||
if(obj_flags & EMAGGED) //Emagged, not broken by EMP
|
||||
to_chat(user, "<span class='warning'>Sign has been damaged beyond repair!</span>")
|
||||
return
|
||||
@@ -92,7 +91,7 @@
|
||||
to_chat(user, "<span class='warning'>This sign is functioning properly!</span>")
|
||||
return
|
||||
|
||||
if(C.use(2))
|
||||
if(I.use_tool(src, user, 0, 2))
|
||||
to_chat(user, "<span class='notice'>You replace the burnt wiring.</span>")
|
||||
broken = FALSE
|
||||
else
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
new_spawn.undershirt = "Nude" //changing underwear/shirt/socks doesn't seem to function correctly right now because of some bug elsewhere?
|
||||
new_spawn.socks = "Nude"
|
||||
new_spawn.update_body(TRUE)
|
||||
new_spawn.language_holder.selected_language = /datum/language/sylvan
|
||||
|
||||
//Ash walker eggs: Spawns in ash walker dens in lavaland. Ghosts become unbreathing lizards that worship the Necropolis and are advised to retrieve corpses to create more ash walkers.
|
||||
|
||||
@@ -63,10 +64,6 @@
|
||||
else
|
||||
to_chat(new_spawn, "<span class='userdanger'>You have been born outside of your natural home! Whether you decide to return home, or make due with your new home is your own decision.</span>")
|
||||
|
||||
new_spawn.grant_language(/datum/language/draconic)
|
||||
var/datum/language_holder/holder = new_spawn.get_language_holder()
|
||||
holder.selected_default_language = /datum/language/draconic
|
||||
|
||||
//Ash walkers on birth understand how to make bone bows, bone arrows and ashen arrows
|
||||
|
||||
new_spawn.mind.teach_crafting_recipe(/datum/crafting_recipe/bone_arrow)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
/obj/structure/janitorialcart/proc/put_in_cart(obj/item/I, mob/user)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
updateUsrDialog()
|
||||
to_chat(user, "<span class='notice'>You put [I] into [src].</span>")
|
||||
return
|
||||
|
||||
@@ -96,70 +95,82 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
|
||||
var/list/items = list()
|
||||
if(mybag)
|
||||
dat += "<a href='?src=[REF(src)];garbage=1'>[mybag.name]</a><br>"
|
||||
items += list("Trash bag" = image(icon = mybag.icon, icon_state = mybag.icon_state))
|
||||
if(mymop)
|
||||
dat += "<a href='?src=[REF(src)];mop=1'>[mymop.name]</a><br>"
|
||||
items += list("Mop" = image(icon = mymop.icon, icon_state = mymop.icon_state))
|
||||
if(mybroom)
|
||||
dat += "<a href='?src=[REF(src)];broom=1'>[mybroom.name]</a><br>"
|
||||
items += list("Broom" = image(icon = mybroom.icon, icon_state = mybroom.icon_state))
|
||||
if(myspray)
|
||||
dat += "<a href='?src=[REF(src)];spray=1'>[myspray.name]</a><br>"
|
||||
items += list("Spray bottle" = image(icon = myspray.icon, icon_state = myspray.icon_state))
|
||||
if(myreplacer)
|
||||
dat += "<a href='?src=[REF(src)];replacer=1'>[myreplacer.name]</a><br>"
|
||||
if(signs)
|
||||
dat += "<a href='?src=[REF(src)];sign=1'>[signs] sign\s</a><br>"
|
||||
var/datum/browser/popup = new(user, "janicart", name, 240, 160)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
items += list("Light replacer" = image(icon = myreplacer.icon, icon_state = myreplacer.icon_state))
|
||||
var/obj/item/caution/sign = locate() in src
|
||||
if(sign)
|
||||
items += list("Sign" = image(icon = sign.icon, icon_state = sign.icon_state))
|
||||
|
||||
|
||||
/obj/structure/janitorialcart/Topic(href, href_list)
|
||||
if(!in_range(src, usr))
|
||||
if(!length(items))
|
||||
return
|
||||
if(!isliving(usr))
|
||||
items = sortList(items)
|
||||
var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 38, require_near = TRUE)
|
||||
if(!pick)
|
||||
return
|
||||
var/mob/living/user = usr
|
||||
if(href_list["garbage"])
|
||||
if(mybag)
|
||||
switch(pick)
|
||||
if("Trash bag")
|
||||
if(!mybag)
|
||||
return
|
||||
user.put_in_hands(mybag)
|
||||
to_chat(user, "<span class='notice'>You take [mybag] from [src].</span>")
|
||||
mybag = null
|
||||
if(href_list["mop"])
|
||||
if(mymop)
|
||||
if("Mop")
|
||||
if(!mymop)
|
||||
return
|
||||
user.put_in_hands(mymop)
|
||||
to_chat(user, "<span class='notice'>You take [mymop] from [src].</span>")
|
||||
mymop = null
|
||||
if(href_list["broom"])
|
||||
if(mybroom)
|
||||
if("Broom")
|
||||
if(!mybroom)
|
||||
return
|
||||
user.put_in_hands(mybroom)
|
||||
to_chat(user, "<span class='notice'>You take [mybroom] from [src].</span>")
|
||||
mybroom = null
|
||||
if(href_list["spray"])
|
||||
if(myspray)
|
||||
if("Spray bottle")
|
||||
if(!myspray)
|
||||
return
|
||||
user.put_in_hands(myspray)
|
||||
to_chat(user, "<span class='notice'>You take [myspray] from [src].</span>")
|
||||
myspray = null
|
||||
if(href_list["replacer"])
|
||||
if(myreplacer)
|
||||
if("Light replacer")
|
||||
if(!myreplacer)
|
||||
return
|
||||
user.put_in_hands(myreplacer)
|
||||
to_chat(user, "<span class='notice'>You take [myreplacer] from [src].</span>")
|
||||
myreplacer = null
|
||||
if(href_list["sign"])
|
||||
if(signs)
|
||||
var/obj/item/caution/Sign = locate() in src
|
||||
if(Sign)
|
||||
user.put_in_hands(Sign)
|
||||
to_chat(user, "<span class='notice'>You take \a [Sign] from [src].</span>")
|
||||
signs--
|
||||
else
|
||||
WARNING("Signs ([signs]) didn't match contents")
|
||||
signs = 0
|
||||
if("Sign")
|
||||
if(signs <= 0)
|
||||
return
|
||||
user.put_in_hands(sign)
|
||||
to_chat(user, "<span class='notice'>You take \a [sign] from [src].</span>")
|
||||
signs--
|
||||
else
|
||||
return
|
||||
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/**
|
||||
* check_menu: Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with a menu
|
||||
*/
|
||||
/obj/structure/janitorialcart/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/janitorialcart/update_overlays()
|
||||
. = ..()
|
||||
|
||||
@@ -91,8 +91,13 @@
|
||||
if (!is_ghost && !in_range(src, user))
|
||||
return
|
||||
|
||||
var/list/tool_list = list(
|
||||
"Up" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH),
|
||||
"Down" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH)
|
||||
)
|
||||
|
||||
if (up && down)
|
||||
var/result = alert("Go up or down [src]?", "Ladder", "Up", "Down", "Cancel")
|
||||
var/result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
|
||||
if (!is_ghost && !in_range(src, user))
|
||||
return // nice try
|
||||
switch(result)
|
||||
@@ -112,6 +117,11 @@
|
||||
if(!is_ghost)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/structure/ladder/proc/check_menu(mob/user)
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/ladder/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user