Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit685
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
#define TICK_LIMIT_RUNNING 80
|
||||
/// Percentage of tick to leave for master controller to run
|
||||
#define MAPTICK_MC_MIN_RESERVE 70
|
||||
/// internal_tick_usage is updated every tick by extools
|
||||
#define MAPTICK_LAST_INTERNAL_TICK_USAGE ((GLOB.internal_tick_usage / world.tick_lag) * 100)
|
||||
/// Tick limit while running normally
|
||||
#define TICK_BYOND_RESERVE 2
|
||||
#define TICK_LIMIT_RUNNING (max(100 - TICK_BYOND_RESERVE - MAPTICK_LAST_INTERNAL_TICK_USAGE, MAPTICK_MC_MIN_RESERVE))
|
||||
/// Tick limit used to resume things in stoplag
|
||||
#define TICK_LIMIT_TO_RUN 70
|
||||
/// Tick limit for MC while running
|
||||
#define TICK_LIMIT_MC 70
|
||||
#define TICK_LIMIT_MC_INIT_DEFAULT 98
|
||||
/// Tick limit while initializing
|
||||
#define TICK_LIMIT_MC_INIT_DEFAULT (100 - TICK_BYOND_RESERVE)
|
||||
|
||||
#define TICK_USAGE world.tick_usage //for general usage
|
||||
#define TICK_USAGE_REAL world.tick_usage //to be used where the result isn't checked
|
||||
/// for general usage of tick_usage
|
||||
#define TICK_USAGE world.tick_usage
|
||||
/// to be used where the result isn't checked
|
||||
#define TICK_USAGE_REAL world.tick_usage
|
||||
|
||||
/// Returns true if tick_usage is above the limit
|
||||
#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit )
|
||||
/// runs stoplag if tick_usage is above the limit
|
||||
#define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 )
|
||||
|
||||
/// Returns true if tick usage is above 95, for high priority usage
|
||||
#define TICK_CHECK_HIGH_PRIORITY ( TICK_USAGE > 95 )
|
||||
/// runs stoplag if tick_usage is above 95, for high priority usage
|
||||
#define CHECK_TICK_HIGH_PRIORITY ( TICK_CHECK_HIGH_PRIORITY? stoplag() : 0 )
|
||||
|
||||
@@ -161,10 +161,14 @@
|
||||
#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
|
||||
#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
|
||||
#define ATMOS_TANK_AIRMIX "o2=2644;n2=10580;TEMP=293.15"
|
||||
|
||||
//LAVALAND
|
||||
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
|
||||
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
|
||||
|
||||
//SNOSTATION
|
||||
#define ICEMOON_DEFAULT_ATMOS "o2=17;n2=63;TEMP=180"
|
||||
|
||||
//ATMOSIA GAS MONITOR TAGS
|
||||
#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"
|
||||
#define ATMOS_GAS_MONITOR_OUTPUT_O2 "o2_out"
|
||||
@@ -255,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;\
|
||||
}
|
||||
|
||||
@@ -294,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
|
||||
|
||||
@@ -110,7 +110,8 @@
|
||||
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" //from base of turf/New(): (turf/source, direction)
|
||||
|
||||
// /atom/movable signals
|
||||
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" //from base of atom/movable/Moved(): (/atom)
|
||||
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" ///from base of atom/movable/Moved(): (/atom)
|
||||
#define COMPONENT_MOVABLE_BLOCK_PRE_MOVE 1
|
||||
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
|
||||
#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
|
||||
@@ -182,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)
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
#define FEMALE_UNIFORM_FULL 1
|
||||
#define FEMALE_UNIFORM_TOP 2
|
||||
|
||||
//flags for outfits that have mutantrace variants: These are hard sprited too.
|
||||
//flags for outfits that have mutant race variants: Most of these require additional sprites to work.
|
||||
#define STYLE_DIGITIGRADE (1<<0) //jumpsuits, suits and shoes
|
||||
#define STYLE_MUZZLE (1<<1) //hats or masks
|
||||
#define STYLE_SNEK_TAURIC (1<<2) //taur-friendly suits
|
||||
@@ -140,6 +140,9 @@
|
||||
#define STYLE_HOOF_TAURIC (1<<4)
|
||||
#define STYLE_ALL_TAURIC (STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC|STYLE_HOOF_TAURIC)
|
||||
#define STYLE_NO_ANTHRO_ICON (1<<5) //When digis fit the default sprite fine and need no copypasted states. This is the case of skirts and winter coats, for example.
|
||||
#define USE_SNEK_CLIP_MASK (1<<6)
|
||||
#define USE_QUADRUPED_CLIP_MASK (1<<7)
|
||||
#define USE_TAUR_CLIP_MASK (USE_SNEK_CLIP_MASK|USE_QUADRUPED_CLIP_MASK)
|
||||
|
||||
//digitigrade legs settings.
|
||||
#define NOT_DIGITIGRADE 0
|
||||
|
||||
@@ -174,7 +174,10 @@ GLOBAL_LIST_INIT(clawfootmob, typecacheof(list(
|
||||
/mob/living/simple_animal/pet/fox,
|
||||
/mob/living/simple_animal/chicken,
|
||||
/mob/living/simple_animal/hostile/bear,
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid
|
||||
/mob/living/simple_animal/hostile/jungle/mega_arachnid,
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_whelp,
|
||||
/mob/living/simple_animal/hostile/asteroid/wolf,
|
||||
/mob/living/simple_animal/hostile/asteroid/polarbear
|
||||
)))
|
||||
|
||||
GLOBAL_LIST_INIT(barefootmob, typecacheof(list(
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//Defines for atom layers and planes
|
||||
//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE
|
||||
|
||||
#define PLANE_VOID -100
|
||||
|
||||
#define CLICKCATCHER_PLANE -99
|
||||
|
||||
#define PLANE_SPACE -95
|
||||
@@ -89,6 +91,8 @@
|
||||
#define MASSIVE_OBJ_LAYER 11
|
||||
#define POINT_LAYER 12
|
||||
|
||||
#define CHAT_LAYER 12.1
|
||||
|
||||
#define EMISSIVE_BLOCKER_PLANE 12
|
||||
#define EMISSIVE_BLOCKER_LAYER 12
|
||||
#define EMISSIVE_BLOCKER_RENDER_TARGET "*EMISSIVE_BLOCKER_PLANE"
|
||||
|
||||
3
code/__DEFINES/mapping/maploader.dm
Normal file
3
code/__DEFINES/mapping/maploader.dm
Normal file
@@ -0,0 +1,3 @@
|
||||
//map template annihilate_bounds
|
||||
#define MAP_TEMPLATE_ANNIHILATE_PRELOAD 1 //annihilate bounds before starting loading
|
||||
#define MAP_TEMPLATE_ANNIHILATE_LOADING 2 //"sweeping" delete during loading
|
||||
@@ -38,9 +38,16 @@ require only minor tweaks.
|
||||
#define ZTRAIT_VR "Virtual Reality"
|
||||
#define ZTRAIT_SPACE_RUINS "Space Ruins"
|
||||
#define ZTRAIT_LAVA_RUINS "Lava Ruins"
|
||||
#define ZTRAIT_ICE_RUINS "Ice Ruins"
|
||||
#define ZTRAIT_ICE_RUINS_UNDERGROUND "Ice Ruins Underground"
|
||||
#define ZTRAIT_ISOLATED_RUINS "Isolated Ruins" //Placing ruins on z levels with this trait will use turf reservation instead of usual placement.
|
||||
#define ZTRAIT_VIRTUAL_REALITY "Virtual Reality"
|
||||
|
||||
//boolean - weather types that occur on the level
|
||||
#define ZTRAIT_SNOWSTORM "Weather_Snowstorm"
|
||||
#define ZTRAIT_ASHSTORM "Weather_Ashstorm"
|
||||
#define ZTRAIT_ACIDRAIN "Weather_Acidrain"
|
||||
|
||||
// number - bombcap is multiplied by this before being applied to bombs
|
||||
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
|
||||
|
||||
@@ -69,6 +76,7 @@ require only minor tweaks.
|
||||
#define ZTRAITS_SPACE list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_SPACE_RUINS = TRUE)
|
||||
#define ZTRAITS_LAVALAND list(\
|
||||
ZTRAIT_MINING = TRUE, \
|
||||
ZTRAIT_ASHSTORM = TRUE, \
|
||||
ZTRAIT_LAVA_RUINS = TRUE, \
|
||||
ZTRAIT_BOMBCAP_MULTIPLIER = 5, \
|
||||
ZTRAIT_BASETURF = /turf/open/lava/smooth/lava_land_surface)
|
||||
|
||||
2
code/__DEFINES/material/worth.dm
Normal file
2
code/__DEFINES/material/worth.dm
Normal file
@@ -0,0 +1,2 @@
|
||||
/// cm3 of material matter per sheet
|
||||
#define MINERAL_MATERIAL_AMOUNT 2000
|
||||
@@ -7,5 +7,5 @@
|
||||
/// Flag for atoms, this flag ensures it isn't re-colored by materials. Useful for snowflake icons such as default toolboxes.
|
||||
#define MATERIAL_COLOR (1<<0)
|
||||
#define MATERIAL_ADD_PREFIX (1<<1)
|
||||
#define MATERIAL_NO_EFFECTS (1<<2)
|
||||
#define MATERIAL_EFFECTS (1<<2)
|
||||
#define MATERIAL_AFFECT_STATISTICS (1<<3)
|
||||
@@ -35,15 +35,15 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
#define BODY_ADJ_LAYER 27 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define GENITALS_FRONT_LAYER 26 //Draws some genitalia above clothes and the TAUR body if need be.
|
||||
#define BODY_LAYER 25 //underwear, undershirts, socks, eyes, lips(makeup)
|
||||
#define FRONT_MUTATIONS_LAYER 24 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 23 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 22
|
||||
#define ID_LAYER 21
|
||||
#define HANDS_PART_LAYER 20
|
||||
#define SHOES_LAYER 19
|
||||
#define GLOVES_LAYER 18
|
||||
#define EARS_LAYER 17
|
||||
#define BODY_TAUR_LAYER 16
|
||||
#define BODY_ADJ_UPPER_LAYER 24
|
||||
#define FRONT_MUTATIONS_LAYER 23 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 22 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 21
|
||||
#define ID_LAYER 20
|
||||
#define HANDS_PART_LAYER 19
|
||||
#define SHOES_LAYER 18
|
||||
#define GLOVES_LAYER 17
|
||||
#define EARS_LAYER 16
|
||||
#define SUIT_LAYER 15
|
||||
#define GENITALS_EXPOSED_LAYER 14
|
||||
#define GLASSES_LAYER 13
|
||||
@@ -515,3 +515,17 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
|
||||
#define NIGHTSHIFT_AREA_NONE 4 //default/highest.
|
||||
|
||||
#define UNTIL(X) while(!(X)) stoplag()
|
||||
|
||||
|
||||
//Scavenging element defines for special loot "events".
|
||||
#define SCAVENGING_FOUND_NOTHING "found_nothing"
|
||||
#define SCAVENGING_SPAWN_MOUSE "spawn_mouse"
|
||||
#define SCAVENGING_SPAWN_MICE "spawn_mice"
|
||||
#define SCAVENGING_SPAWN_TOM "spawn_tom_the_mouse"
|
||||
|
||||
//Scavenging element defines for ckey/mind restrictions.
|
||||
#define NO_LOOT_RESTRICTION 0
|
||||
#define LOOT_RESTRICTION_MIND 1
|
||||
#define LOOT_RESTRICTION_CKEY 2
|
||||
#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile.
|
||||
#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem
|
||||
|
||||
@@ -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
|
||||
@@ -265,6 +266,7 @@
|
||||
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
|
||||
#define APPRENTICE_AGE_MIN 29 //youngest an apprentice can be
|
||||
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
|
||||
#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement
|
||||
#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
|
||||
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
|
||||
|
||||
@@ -288,10 +290,8 @@
|
||||
|
||||
#define HUMAN_FIRE_STACK_ICON_NUM 3
|
||||
|
||||
#define PULL_PRONE_SLOWDOWN 0.6
|
||||
#define FIREMAN_CARRY_SLOWDOWN 0
|
||||
#define PIGGYBACK_CARRY_SLOWDOWN 1
|
||||
//slowdown when in softcrit. Note that crawling slowdown will also apply at the same time!
|
||||
#define SOFTCRIT_ADD_SLOWDOWN 2
|
||||
//slowdown when crawling
|
||||
#define CRAWLING_ADD_SLOWDOWN 4
|
||||
#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;
|
||||
|
||||
10
code/__DEFINES/mobs/slowdowns.dm
Normal file
10
code/__DEFINES/mobs/slowdowns.dm
Normal file
@@ -0,0 +1,10 @@
|
||||
/// How much someone is slowed from pulling a prone human
|
||||
#define PULL_PRONE_SLOWDOWN 0.6
|
||||
/// How much someone is slowed from fireman carrying a human
|
||||
#define FIREMAN_CARRY_SLOWDOWN 0
|
||||
/// How much someone is slowed by piggybacking a human
|
||||
#define PIGGYBACK_CARRY_SLOWDOWN 1
|
||||
/// slowdown when in softcrit. Note that crawling slowdown will also apply at the same time!
|
||||
#define SOFTCRIT_ADD_SLOWDOWN 2
|
||||
/// slowdown when crawling
|
||||
#define CRAWLING_ADD_SLOWDOWN 4
|
||||
@@ -38,11 +38,12 @@
|
||||
#define BLOCK_GAS_SMOKE_EFFECT (1<<2) //blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
|
||||
#define ALLOWINTERNALS (1<<3) //mask allows internals
|
||||
#define NOSLIP (1<<4) //prevents from slipping on wet floors, in space etc
|
||||
#define THICKMATERIAL (1<<5) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
|
||||
#define VOICEBOX_TOGGLABLE (1<<6) //The voicebox in this clothing can be toggled.
|
||||
#define VOICEBOX_DISABLED (1<<7) //The voicebox is currently turned off.
|
||||
#define IGNORE_HAT_TOSS (1<<8) //Hats with negative effects when worn (i.e the tinfoil hat).
|
||||
#define SCAN_REAGENTS (1<<9) // Allows helmets and glasses to scan reagents.
|
||||
#define NOSLIP_ICE (1<<5) //prevents from slipping on frozen floors
|
||||
#define THICKMATERIAL (1<<6) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
|
||||
#define VOICEBOX_TOGGLABLE (1<<7) //The voicebox in this clothing can be toggled.
|
||||
#define VOICEBOX_DISABLED (1<<8) //The voicebox is currently turned off.
|
||||
#define IGNORE_HAT_TOSS (1<<9) //Hats with negative effects when worn (i.e the tinfoil hat).
|
||||
#define SCAN_REAGENTS (1<<10) // Allows helmets and glasses to scan reagents.
|
||||
|
||||
// Flags for the organ_flags var on /obj/item/organ
|
||||
|
||||
@@ -52,3 +53,4 @@
|
||||
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
|
||||
#define ORGAN_VITAL (1<<4) //Currently only the brain
|
||||
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
|
||||
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
|
||||
#define FREQ_SECURITY 1359 // Security comms frequency, red
|
||||
|
||||
#define FREQ_HOLOGRID_SOLUTION 1433
|
||||
#define FREQ_STATUS_DISPLAYS 1435
|
||||
#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers
|
||||
#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers
|
||||
|
||||
5
code/__DEFINES/research/stock_parts.dm
Normal file
5
code/__DEFINES/research/stock_parts.dm
Normal file
@@ -0,0 +1,5 @@
|
||||
// the clamps are just sanity checks.
|
||||
/// Efficiency scaling for stock part level to material usage. All code concerning lathing and production from raw material sheet should be using this.
|
||||
#define STANDARD_PART_LEVEL_LATHE_COEFFICIENT(level) clamp(1 - (level * 0.1), 0, 1)
|
||||
/// Efficiency scaling for stock part level to ore factor. All code concerning lathing and production from raw ores to raw material sheets should be using this.
|
||||
#define STANDARD_PART_LEVEL_ORE_COEFFICIENT(level) clamp(1 + (level * 0.125), 1, 10)
|
||||
77
code/__DEFINES/skills/defines.dm
Normal file
77
code/__DEFINES/skills/defines.dm
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
/// true/false
|
||||
#define SKILL_PROGRESSION_BINARY 1
|
||||
/// numerical
|
||||
#define SKILL_PROGRESSION_NUMERICAL 2
|
||||
/// Enum
|
||||
#define SKILL_PROGRESSION_ENUM 3
|
||||
/// Levels
|
||||
#define SKILL_PROGRESSION_LEVEL 4
|
||||
|
||||
|
||||
/// Max value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MAX 100
|
||||
/// Min value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MIN 0
|
||||
|
||||
// Standard values for job starting skills
|
||||
|
||||
#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX
|
||||
|
||||
// Standard values for job starting skill affinities
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2
|
||||
|
||||
#define STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO 1.2
|
||||
|
||||
// Standard values for skill gain (this is multiplied by affinity)
|
||||
|
||||
#define DEF_SKILL_GAIN 1
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
|
||||
#define SKILL_AFFINITY_MOOD_BONUS 1.25
|
||||
|
||||
///Items skill_flags and other defines
|
||||
#define SKILL_USE_TOOL (1<<0)
|
||||
#define SKILL_TRAINING_TOOL (1<<1)
|
||||
#define SKILL_ATTACK_MOB (1<<2)
|
||||
#define SKILL_TRAIN_ATTACK_MOB (1<<3)
|
||||
#define SKILL_ATTACK_OBJ (1<<4)
|
||||
#define SKILL_TRAIN_ATTACK_OBJ (1<<5)
|
||||
#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage.
|
||||
#define SKILL_THROW_STAM_COST (1<<7)
|
||||
#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on.
|
||||
#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
|
||||
#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
|
||||
|
||||
///competency_threshold index defines
|
||||
#define THRESHOLD_COMPETENT 1
|
||||
#define THRESHOLD_EXPERT 2
|
||||
#define THRESHOLD_MASTER 3
|
||||
|
||||
/// Level/Experience skills defines.
|
||||
#define STD_XP_LVL_UP 100
|
||||
#define STD_XP_LVL_MULTI 2
|
||||
#define STD_MAX_LVL 4
|
||||
|
||||
#define RPG_MAX_LVL 100
|
||||
|
||||
#define DORF_XP_LVL_UP 400
|
||||
#define DORF_XP_LVL_MULTI 100
|
||||
#define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5
|
||||
|
||||
//level up methods defines
|
||||
#define STANDARD_LEVEL_UP "standard_level_up"
|
||||
#define DWARFY_LEVEL_UP "dwarfy_level_up"
|
||||
|
||||
//job skill level defines
|
||||
#define JOB_SKILL_UNTRAINED 0
|
||||
#define JOB_SKILL_BASIC 1
|
||||
#define JOB_SKILL_TRAINED 2
|
||||
#define JOB_SKILL_EXPERT 3
|
||||
#define JOB_SKILL_MASTER 4
|
||||
|
||||
//other skill level defines, not an exhaustive catalogue, only contains be most relevant ones.
|
||||
#define DORF_SKILL_COMPETENT 3
|
||||
#define DORF_SKILL_EXPERT 8
|
||||
#define DORF_SKILL_MASTER 12
|
||||
8
code/__DEFINES/skills/helpers.dm
Normal file
8
code/__DEFINES/skills/helpers.dm
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
//How experience levels are calculated.
|
||||
#define XP_LEVEL(std, multi, lvl) (std*((multi**lvl)/(multi-1))-std/(multi-1)) //don't use 1 as multi, you'll get division by zero errors
|
||||
#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5)))
|
||||
|
||||
//More experience value getter macros
|
||||
#define GET_STANDARD_LVL(lvl) XP_LEVEL(STD_XP_LVL_UP, STD_XP_LVL_MULTI, lvl)
|
||||
#define GET_DORF_LVL(lvl) DORF_XP_LEVEL(DORF_XP_LVL_UP, DORF_XP_LVL_MULTI, lvl)
|
||||
@@ -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)
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
#define STATUS_EFFECT_HIPPOCRATIC_OATH /datum/status_effect/hippocraticOath //Gives you an aura of healing as well as regrowing the Rod of Asclepius if lost
|
||||
|
||||
#define STATUS_EFFECT_REGENERATIVE_CORE /datum/status_effect/regenerative_core //removes damage slowdown while giving a slow regenerating effect
|
||||
|
||||
/////////////
|
||||
// DEBUFFS //
|
||||
/////////////
|
||||
@@ -78,7 +80,7 @@
|
||||
|
||||
#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage
|
||||
|
||||
#define STATUS_EFFECT_SAWBLEED /datum/status_effect/saw_bleed //if the bleed builds up enough, takes a ton of damage
|
||||
#define STATUS_EFFECT_SAWBLEED /datum/status_effect/stacking/saw_bleed //if the bleed builds up enough, takes a ton of damage
|
||||
|
||||
#define STATUS_EFFECT_NECKSLICE /datum/status_effect/neck_slice //Creates the flavor messages for the neck-slice
|
||||
|
||||
|
||||
@@ -133,8 +133,15 @@
|
||||
|
||||
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
|
||||
|
||||
|
||||
|
||||
// SSair run section
|
||||
#define SSAIR_PIPENETS 1
|
||||
#define SSAIR_ATMOSMACHINERY 2
|
||||
#define SSAIR_REACTQUEUE 3
|
||||
#define SSAIR_EXCITEDGROUPS 4
|
||||
#define SSAIR_HIGHPRESSURE 5
|
||||
#define SSAIR_HOTSPOTS 6
|
||||
#define SSAIR_SUPERCONDUCTIVITY 7
|
||||
#define SSAIR_REBUILD_PIPENETS 8
|
||||
|
||||
#define COMPILE_OVERLAYS(A)\
|
||||
if (TRUE) {\
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
#define TRAIT_MONKEYLIKE "monkeylike" //sets IsAdvancedToolUser to FALSE
|
||||
#define TRAIT_PACIFISM "pacifism"
|
||||
#define TRAIT_IGNORESLOWDOWN "ignoreslow"
|
||||
#define TRAIT_IGNOREDAMAGESLOWDOWN "ignoredamageslowdown"
|
||||
#define TRAIT_DEATHCOMA "deathcoma" //Causes death-like unconsciousness
|
||||
#define TRAIT_FAKEDEATH "fakedeath" //Makes the owner appear as dead to most forms of medical examination
|
||||
#define TRAIT_DISFIGURED "disfigured"
|
||||
@@ -187,7 +188,7 @@
|
||||
#define TRAIT_NO_INTERNALS "no-internals"
|
||||
#define TRAIT_NO_ALCOHOL "alcohol_intolerance"
|
||||
#define TRAIT_MUTATION_STASIS "mutation_stasis" //Prevents processed genetics mutations from processing.
|
||||
#define TRAIT_FAST_PUMP "fast_pump"
|
||||
#define TRAIT_FAST_PUMP "fast_pump"
|
||||
|
||||
// mobility flag traits
|
||||
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
|
||||
|
||||
@@ -58,6 +58,11 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
else if(isarea(areatype))
|
||||
var/area/areatemp = areatype
|
||||
areatype = areatemp.type
|
||||
else if(islist(areatype))
|
||||
var/list/turfs = list()
|
||||
for(var/A in areatype)
|
||||
turfs += get_area_turfs(A)
|
||||
return turfs
|
||||
else if(!ispath(areatype))
|
||||
return null
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
|
||||
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL()
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /proc/setupGenetics)
|
||||
|
||||
//creates every subtype of prototype (excluding prototype) and adds it to list L.
|
||||
//if no list/L is provided, one is created.
|
||||
@@ -113,3 +114,25 @@
|
||||
UNTIL(C.flags_1 & INITIALIZED_1) //we want to make sure the value is calculated and not null.
|
||||
GLOB.coin_values[path] = C.value
|
||||
qdel(C)
|
||||
|
||||
/proc/setupGenetics()
|
||||
var/list/mutations = subtypesof(/datum/mutation/human)
|
||||
shuffle_inplace(mutations)
|
||||
for(var/A in subtypesof(/datum/generecipe))
|
||||
var/datum/generecipe/GR = A
|
||||
GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
|
||||
for(var/i in 1 to LAZYLEN(mutations))
|
||||
var/path = mutations[i] //byond gets pissy when we do it in one line
|
||||
var/datum/mutation/human/B = new path ()
|
||||
B.alias = "Mutation #[i]"
|
||||
GLOB.all_mutations[B.type] = B
|
||||
GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
|
||||
if(B.locked)
|
||||
continue
|
||||
if(B.quality == POSITIVE)
|
||||
GLOB.good_mutations |= B
|
||||
else if(B.quality == NEGATIVE)
|
||||
GLOB.bad_mutations |= B
|
||||
else if(B.quality == MINOR_NEGATIVE)
|
||||
GLOB.not_good_mutations |= B
|
||||
CHECK_TICK
|
||||
@@ -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",
|
||||
@@ -317,7 +319,7 @@ GLOBAL_LIST_EMPTY(species_list)
|
||||
else
|
||||
return "unknown"
|
||||
|
||||
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = 0)
|
||||
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = FALSE, resume_time = 0 SECONDS)
|
||||
if(!user || !target)
|
||||
return 0
|
||||
var/user_loc = user.loc
|
||||
@@ -336,10 +338,10 @@ GLOBAL_LIST_EMPTY(species_list)
|
||||
var/endtime = world.time+time
|
||||
var/starttime = world.time
|
||||
. = 1
|
||||
while (world.time < endtime)
|
||||
while (world.time + resume_time < endtime)
|
||||
stoplag(1)
|
||||
if (progress)
|
||||
progbar.update(world.time - starttime)
|
||||
progbar.update(world.time - starttime + resume_time)
|
||||
if(QDELETED(user) || QDELETED(target))
|
||||
. = 0
|
||||
break
|
||||
@@ -371,7 +373,7 @@ GLOBAL_LIST_EMPTY(species_list)
|
||||
checked_health["health"] = health
|
||||
return ..()
|
||||
|
||||
/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE))
|
||||
/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE), resume_time = 0 SECONDS)
|
||||
if(!user)
|
||||
return 0
|
||||
var/atom/Tloc = null
|
||||
@@ -400,10 +402,10 @@ GLOBAL_LIST_EMPTY(species_list)
|
||||
var/starttime = world.time
|
||||
. = 1
|
||||
var/mob/living/L = isliving(user) && user //evals to last thing eval'd
|
||||
while (world.time < endtime)
|
||||
while (world.time + resume_time < endtime)
|
||||
stoplag(1)
|
||||
if (progress)
|
||||
progbar.update(world.time - starttime)
|
||||
progbar.update(world.time - starttime + resume_time)
|
||||
|
||||
if(drifting && !user.inertia_dir)
|
||||
drifting = 0
|
||||
|
||||
@@ -434,6 +434,29 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
|
||||
return locate(x,y,A.z)
|
||||
|
||||
/**
|
||||
* Get ranged target turf, but with direct targets as opposed to directions
|
||||
*
|
||||
* Starts at atom A and gets the exact angle between A and target
|
||||
* Moves from A with that angle, Range amount of times, until it stops, bound to map size
|
||||
* Arguments:
|
||||
* * A - Initial Firer / Position
|
||||
* * target - Target to aim towards
|
||||
* * range - Distance of returned target turf from A
|
||||
* * offset - Angle offset, 180 input would make the returned target turf be in the opposite direction
|
||||
*/
|
||||
/proc/get_ranged_target_turf_direct(atom/A, atom/target, range, offset)
|
||||
var/angle = arctan(target.x - A.x, target.y - A.y)
|
||||
if(offset)
|
||||
angle += offset
|
||||
var/turf/T = get_turf(A)
|
||||
for(var/i in 1 to range)
|
||||
var/turf/check = locate(A.x + cos(angle) * i, A.y + sin(angle) * i, A.z)
|
||||
if(!check)
|
||||
break
|
||||
T = check
|
||||
|
||||
return T
|
||||
|
||||
// returns turf relative to A offset in dx and dy tiles
|
||||
// bound to map limits
|
||||
|
||||
@@ -266,6 +266,16 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"STORAGE_LIMIT_COMBINED_W_CLASS" = STORAGE_LIMIT_COMBINED_W_CLASS,
|
||||
"STORAGE_LIMIT_VOLUME" = STORAGE_LIMIT_VOLUME
|
||||
),
|
||||
"mutantrace_variation" = list(
|
||||
"STYLE_DIGITIGRADE" = STYLE_DIGITIGRADE,
|
||||
"STYLE_MUZZLE" = STYLE_MUZZLE,
|
||||
"STYLE_SNEK_TAURIC" = STYLE_SNEK_TAURIC,
|
||||
"STYLE_PAW_TAURIC" = STYLE_PAW_TAURIC,
|
||||
"STYLE_HOOF_TAURIC" = STYLE_HOOF_TAURIC,
|
||||
"STYLE_NO_ANTHRO_ICON" = STYLE_NO_ANTHRO_ICON,
|
||||
"USE_SNEK_CLIP_MASK" = USE_SNEK_CLIP_MASK,
|
||||
"USE_QUADRUPED_CLIP_MASK" = USE_QUADRUPED_CLIP_MASK
|
||||
),
|
||||
"vis_flags" = list(
|
||||
"VIS_INHERIT_ICON" = VIS_INHERIT_ICON,
|
||||
"VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE,
|
||||
|
||||
@@ -137,8 +137,8 @@ GLOBAL_LIST_INIT(jumpsuitlist, list(PREF_SUIT, PREF_SKIRT))
|
||||
#define UPLINK_PEN "Pen" //like a real spy!
|
||||
GLOBAL_LIST_INIT(uplink_spawn_loc_list, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN))
|
||||
|
||||
//Female Uniforms
|
||||
GLOBAL_LIST_EMPTY(female_clothing_icons)
|
||||
//List of cached alpha masked icons.
|
||||
GLOBAL_LIST_EMPTY(alpha_masked_worn_icons)
|
||||
|
||||
//radical shit
|
||||
GLOBAL_LIST_INIT(hit_appends, list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF"))
|
||||
|
||||
@@ -33,3 +33,5 @@ GLOBAL_VAR(bible_icon_state)
|
||||
GLOBAL_VAR(bible_item_state)
|
||||
GLOBAL_VAR(holy_weapon_type)
|
||||
GLOBAL_VAR(holy_armor_type)
|
||||
|
||||
GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag)
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
|
||||
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
|
||||
#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
|
||||
#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
|
||||
#define ui_ghost_spawners "SOUTH: 6, CENTER+2:24"
|
||||
|
||||
|
||||
//UI position overrides for 1:1 screen layout. (default is 7:5)
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
var/mob/dead/observer/G = usr
|
||||
G.dead_tele()
|
||||
|
||||
/obj/screen/ghost/pai
|
||||
name = "pAI Candidate"
|
||||
icon_state = "pai"
|
||||
/obj/screen/ghost/spawners
|
||||
name = "Ghost role spawners"
|
||||
icon_state = "spawners"
|
||||
|
||||
/obj/screen/ghost/pai/Click()
|
||||
/obj/screen/ghost/spawners/Click()
|
||||
var/mob/dead/observer/G = usr
|
||||
G.register_pai()
|
||||
G.open_spawners_menu()
|
||||
|
||||
/datum/hud/ghost/New(mob/owner)
|
||||
..()
|
||||
@@ -68,8 +68,8 @@
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ghost/pai()
|
||||
using.screen_loc = ui_ghost_pai
|
||||
using = new /obj/screen/ghost/spawners()
|
||||
using.screen_loc = ui_ghost_spawners
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -350,6 +357,11 @@
|
||||
config_entry_value = 16
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/icemoon_budget
|
||||
config_entry_value = 90
|
||||
integer = FALSE
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/station_space_budget
|
||||
config_entry_value = 10
|
||||
min_val = 0
|
||||
|
||||
@@ -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
|
||||
@@ -36,6 +38,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
var/sleep_delta = 1
|
||||
|
||||
///Only run ticker subsystems for the next n ticks.
|
||||
var/skip_ticks = 0
|
||||
|
||||
var/make_runtime = 0
|
||||
|
||||
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
|
||||
@@ -62,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
|
||||
@@ -84,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
|
||||
|
||||
@@ -254,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
|
||||
@@ -335,7 +352,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
new/datum/controller/failsafe() // (re)Start the failsafe.
|
||||
|
||||
//now do the actual stuff
|
||||
if (!queue_head || !(iteration % 3))
|
||||
if (!skip_ticks)
|
||||
var/checking_runlevel = current_runlevel
|
||||
if(cached_runlevel != checking_runlevel)
|
||||
//resechedule subsystems
|
||||
@@ -381,6 +398,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
iteration++
|
||||
last_run = world.time
|
||||
if (skip_ticks)
|
||||
skip_ticks--
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
if (processing * sleep_delta <= world.tick_lag)
|
||||
@@ -444,10 +463,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
while (queue_node)
|
||||
if (ran && TICK_USAGE > TICK_LIMIT_RUNNING)
|
||||
break
|
||||
|
||||
queue_node_flags = queue_node.flags
|
||||
queue_node_priority = queue_node.queued_priority
|
||||
|
||||
if (!(queue_node_flags & SS_TICKER) && skip_ticks)
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
//super special case, subsystems where we can't make them pause mid way through
|
||||
//if we can't run them this tick (without going over a tick)
|
||||
//we bump up their priority and attempt to run them next tick
|
||||
@@ -455,14 +476,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
// in those cases, so we just let them run)
|
||||
if (queue_node_flags & SS_NO_TICK_CHECK)
|
||||
if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker)
|
||||
queue_node.queued_priority += queue_priority_count * 0.1
|
||||
queue_priority_count -= queue_node_priority
|
||||
queue_priority_count += queue_node.queued_priority
|
||||
current_tick_budget -= queue_node_priority
|
||||
queue_node = queue_node.queue_next
|
||||
if (!(queue_node_flags & SS_BACKGROUND))
|
||||
queue_node.queued_priority += queue_priority_count * 0.1
|
||||
queue_priority_count -= queue_node_priority
|
||||
queue_priority_count += queue_node.queued_priority
|
||||
current_tick_budget -= queue_node_priority
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
|
||||
if ((queue_node_flags & SS_BACKGROUND) && !bg_calc)
|
||||
if (!bg_calc && (queue_node_flags & SS_BACKGROUND))
|
||||
current_tick_budget = queue_priority_count_bg
|
||||
bg_calc = TRUE
|
||||
|
||||
@@ -515,7 +537,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
queue_node.paused_ticks = 0
|
||||
queue_node.paused_tick_usage = 0
|
||||
|
||||
if (queue_node_flags & SS_BACKGROUND) //update our running total
|
||||
if (bg_calc) //update our running total
|
||||
queue_priority_count_bg -= queue_node_priority
|
||||
else
|
||||
queue_priority_count -= queue_node_priority
|
||||
@@ -583,14 +605,19 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
log_world("MC: SoftReset: Finished.")
|
||||
. = 1
|
||||
|
||||
/// Warns us that the end of tick byond map_update will be laggier then normal, so that we can just skip running subsystems this tick.
|
||||
/datum/controller/master/proc/laggy_byond_map_update_incoming()
|
||||
if (!skip_ticks)
|
||||
skip_ticks = 1
|
||||
|
||||
|
||||
/datum/controller/master/stat_entry()
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
|
||||
|
||||
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)]%))")
|
||||
stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])"))
|
||||
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
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
#define SSAIR_PIPENETS 1
|
||||
#define SSAIR_ATMOSMACHINERY 2
|
||||
#define SSAIR_REACTQUEUE 3
|
||||
#define SSAIR_EXCITEDGROUPS 4
|
||||
#define SSAIR_HIGHPRESSURE 5
|
||||
#define SSAIR_HOTSPOTS 6
|
||||
#define SSAIR_SUPERCONDUCTIVITY 7
|
||||
|
||||
SUBSYSTEM_DEF(air)
|
||||
name = "Atmospherics"
|
||||
init_order = INIT_ORDER_AIR
|
||||
@@ -20,6 +12,7 @@ SUBSYSTEM_DEF(air)
|
||||
var/cost_hotspots = 0
|
||||
var/cost_superconductivity = 0
|
||||
var/cost_pipenets = 0
|
||||
var/cost_rebuilds = 0
|
||||
var/cost_atmos_machinery = 0
|
||||
|
||||
var/list/excited_groups = list()
|
||||
@@ -27,6 +20,7 @@ SUBSYSTEM_DEF(air)
|
||||
var/list/turf_react_queue = list()
|
||||
var/list/hotspots = list()
|
||||
var/list/networks = list()
|
||||
var/list/pipenets_needing_rebuilt = list()
|
||||
var/list/obj/machinery/atmos_machinery = list()
|
||||
var/list/pipe_init_dirs_cache = list()
|
||||
|
||||
@@ -39,7 +33,7 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/currentpart = SSAIR_PIPENETS
|
||||
var/currentpart = SSAIR_REBUILD_PIPENETS
|
||||
|
||||
var/map_loading = TRUE
|
||||
var/list/queued_for_activation
|
||||
@@ -52,6 +46,7 @@ SUBSYSTEM_DEF(air)
|
||||
msg += "HS:[round(cost_hotspots,1)]|"
|
||||
msg += "SC:[round(cost_superconductivity,1)]|"
|
||||
msg += "PN:[round(cost_pipenets,1)]|"
|
||||
msg += "RB:[round(cost_rebuilds,1)]|"
|
||||
msg += "AM:[round(cost_atmos_machinery,1)]"
|
||||
msg += "} "
|
||||
msg += "AT:[active_turfs.len]|"
|
||||
@@ -77,6 +72,18 @@ SUBSYSTEM_DEF(air)
|
||||
/datum/controller/subsystem/air/fire(resumed = 0)
|
||||
var/timer = TICK_USAGE_REAL
|
||||
|
||||
if(currentpart == SSAIR_REBUILD_PIPENETS)
|
||||
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
|
||||
for(var/thing in pipenet_rebuilds)
|
||||
var/obj/machinery/atmospherics/AT = thing
|
||||
AT.build_network()
|
||||
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
pipenets_needing_rebuilt.Cut()
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_PIPENETS
|
||||
|
||||
if(currentpart == SSAIR_PIPENETS || !resumed)
|
||||
process_pipenets(resumed)
|
||||
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
@@ -137,9 +144,7 @@ SUBSYSTEM_DEF(air)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_PIPENETS
|
||||
|
||||
|
||||
currentpart = SSAIR_REBUILD_PIPENETS
|
||||
|
||||
/datum/controller/subsystem/air/proc/process_pipenets(resumed = 0)
|
||||
if (!resumed)
|
||||
@@ -156,6 +161,9 @@ SUBSYSTEM_DEF(air)
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/air/proc/add_to_rebuild_queue(atmos_machine)
|
||||
if(istype(atmos_machine, /obj/machinery/atmospherics))
|
||||
pipenets_needing_rebuilt += atmos_machine
|
||||
|
||||
/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
|
||||
var/seconds = wait * 0.1
|
||||
|
||||
@@ -16,7 +16,6 @@ SUBSYSTEM_DEF(atoms)
|
||||
|
||||
/datum/controller/subsystem/atoms/Initialize(timeofday)
|
||||
GLOB.fire_overlay.appearance_flags = RESET_COLOR
|
||||
setupGenetics() //to set the mutations' sequence.
|
||||
initialized = INITIALIZATION_INNEW_MAPLOAD
|
||||
InitializeAtoms()
|
||||
return ..()
|
||||
@@ -107,28 +106,6 @@ SUBSYSTEM_DEF(atoms)
|
||||
old_initialized = SSatoms.old_initialized
|
||||
BadInitializeCalls = SSatoms.BadInitializeCalls
|
||||
|
||||
/datum/controller/subsystem/atoms/proc/setupGenetics()
|
||||
var/list/mutations = subtypesof(/datum/mutation/human)
|
||||
shuffle_inplace(mutations)
|
||||
for(var/A in subtypesof(/datum/generecipe))
|
||||
var/datum/generecipe/GR = A
|
||||
GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result)
|
||||
for(var/i in 1 to LAZYLEN(mutations))
|
||||
var/path = mutations[i] //byond gets pissy when we do it in one line
|
||||
var/datum/mutation/human/B = new path ()
|
||||
B.alias = "Mutation #[i]"
|
||||
GLOB.all_mutations[B.type] = B
|
||||
GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks)
|
||||
if(B.locked)
|
||||
continue
|
||||
if(B.quality == POSITIVE)
|
||||
GLOB.good_mutations |= B
|
||||
else if(B.quality == NEGATIVE)
|
||||
GLOB.bad_mutations |= B
|
||||
else if(B.quality == MINOR_NEGATIVE)
|
||||
GLOB.not_good_mutations |= B
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/atoms/proc/InitLog()
|
||||
. = ""
|
||||
for(var/path in BadInitializeCalls)
|
||||
|
||||
@@ -16,6 +16,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/ruins_templates = list()
|
||||
var/list/space_ruins_templates = list()
|
||||
var/list/lava_ruins_templates = list()
|
||||
var/list/ice_ruins_templates = list()
|
||||
var/list/ice_ruins_underground_templates = list()
|
||||
var/list/station_ruins_templates = list()
|
||||
var/datum/space_level/isolated_ruins_z //Created on demand during ruin loading.
|
||||
|
||||
@@ -42,6 +44,13 @@ SUBSYSTEM_DEF(mapping)
|
||||
|
||||
var/stat_map_name = "Loading..."
|
||||
|
||||
/// Lookup list for random generated IDs.
|
||||
var/list/random_generated_ids_by_original = list()
|
||||
/// next id for separating obfuscated ids.
|
||||
var/obfuscation_next_id = 1
|
||||
/// "secret" key
|
||||
var/obfuscation_secret
|
||||
|
||||
//dlete dis once #39770 is resolved
|
||||
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
|
||||
if(!config)
|
||||
@@ -52,6 +61,10 @@ SUBSYSTEM_DEF(mapping)
|
||||
#endif
|
||||
stat_map_name = config.map_name
|
||||
|
||||
/datum/controller/subsystem/mapping/PreInit()
|
||||
if(!obfuscation_secret)
|
||||
obfuscation_secret = md5(GUID()) //HAH! Guess this!
|
||||
|
||||
/datum/controller/subsystem/mapping/Initialize(timeofday)
|
||||
HACK_LoadMapConfig()
|
||||
if(initialized)
|
||||
@@ -91,19 +104,32 @@ SUBSYSTEM_DEF(mapping)
|
||||
loading_ruins = TRUE
|
||||
var/list/lava_ruins = levels_by_trait(ZTRAIT_LAVA_RUINS)
|
||||
if (lava_ruins.len)
|
||||
seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
|
||||
seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), list(/area/lavaland/surface/outdoors/unexplored), lava_ruins_templates)
|
||||
for (var/lava_z in lava_ruins)
|
||||
spawn_rivers(lava_z)
|
||||
|
||||
var/list/ice_ruins = levels_by_trait(ZTRAIT_ICE_RUINS)
|
||||
if (ice_ruins.len)
|
||||
// needs to be whitelisted for underground too so place_below ruins work
|
||||
seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), ice_ruins_templates)
|
||||
for (var/ice_z in ice_ruins)
|
||||
spawn_rivers(ice_z, 4, /turf/open/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers)
|
||||
|
||||
var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND)
|
||||
if (ice_ruins_underground.len)
|
||||
seedRuins(ice_ruins_underground, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/underground/unexplored), ice_ruins_underground_templates)
|
||||
for (var/ice_z in ice_ruins_underground)
|
||||
spawn_rivers(ice_z, 4, level_trait(ice_z, ZTRAIT_BASETURF), /area/icemoon/underground/unexplored/rivers)
|
||||
|
||||
// Generate deep space ruins
|
||||
var/list/space_ruins = levels_by_trait(ZTRAIT_SPACE_RUINS)
|
||||
if (space_ruins.len)
|
||||
seedRuins(space_ruins, CONFIG_GET(number/space_budget), /area/space, space_ruins_templates)
|
||||
seedRuins(space_ruins, CONFIG_GET(number/space_budget), list(/area/space), space_ruins_templates)
|
||||
|
||||
// Generate station space ruins
|
||||
var/list/station_ruins = levels_by_trait(ZTRAIT_STATION)
|
||||
if (station_ruins.len)
|
||||
seedRuins(station_ruins, CONFIG_GET(number/station_space_budget), /area/space/station_ruins, station_ruins_templates)
|
||||
seedRuins(station_ruins, (SSmapping.config.station_ruin_budget < 0) ? CONFIG_GET(number/station_space_budget) : SSmapping.config.station_ruin_budget, list(/area/space/station_ruins), station_ruins_templates)
|
||||
SSmapping.seedStation()
|
||||
loading_ruins = FALSE
|
||||
#endif
|
||||
@@ -171,6 +197,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
ruins_templates = SSmapping.ruins_templates
|
||||
space_ruins_templates = SSmapping.space_ruins_templates
|
||||
lava_ruins_templates = SSmapping.lava_ruins_templates
|
||||
ice_ruins_templates = SSmapping.ice_ruins_templates
|
||||
ice_ruins_underground_templates = SSmapping.ice_ruins_underground_templates
|
||||
station_ruins_templates = SSmapping.station_ruins_templates
|
||||
shuttle_templates = SSmapping.shuttle_templates
|
||||
shelter_templates = SSmapping.shelter_templates
|
||||
@@ -185,7 +213,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
|
||||
z_list = SSmapping.z_list
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE)
|
||||
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, orientation = SOUTH)
|
||||
. = list()
|
||||
var/start_time = REALTIMEOFDAY
|
||||
|
||||
@@ -225,7 +253,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// load the maps
|
||||
for (var/P in parsed_maps)
|
||||
var/datum/parsed_map/pm = P
|
||||
if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE))
|
||||
if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE, orientation = orientation))
|
||||
errorList |= pm.original_path
|
||||
if(!silent)
|
||||
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
|
||||
@@ -241,7 +269,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// load the station
|
||||
station_start = world.maxz + 1
|
||||
INIT_ANNOUNCE("Loading [config.map_name]...")
|
||||
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION)
|
||||
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION, FALSE, config.orientation)
|
||||
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
|
||||
@@ -257,7 +285,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// load mining
|
||||
if(config.minetype == "lavaland")
|
||||
LoadGroup(FailedZs, "Lavaland", "map_files/Mining", "Lavaland.dmm", default_traits = ZTRAITS_LAVALAND)
|
||||
else if (!isnull(config.minetype))
|
||||
else if (!isnull(config.minetype) && config.minetype != "none")
|
||||
INIT_ANNOUNCE("WARNING: An unknown minetype '[config.minetype]' was set! This is being ignored! Update the maploader code!")
|
||||
#endif
|
||||
|
||||
@@ -361,6 +389,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
// Still supporting bans by filename
|
||||
var/list/banned = generateMapList("[global.config.directory]/lavaruinblacklist.txt")
|
||||
banned += generateMapList("[global.config.directory]/spaceruinblacklist.txt")
|
||||
banned += generateMapList("[global.config.directory]/iceruinblacklist.txt")
|
||||
banned += generateMapList("[global.config.directory]/stationruinblacklist.txt")
|
||||
|
||||
for(var/item in sortList(subtypesof(/datum/map_template/ruin), /proc/cmp_ruincost_priority))
|
||||
@@ -378,6 +407,10 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
|
||||
if(istype(R, /datum/map_template/ruin/lavaland))
|
||||
lava_ruins_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/icemoon/underground))
|
||||
ice_ruins_underground_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/icemoon))
|
||||
ice_ruins_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/space))
|
||||
space_ruins_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/station))
|
||||
@@ -568,3 +601,15 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
LM.load()
|
||||
if(GLOB.stationroom_landmarks.len)
|
||||
seedStation() //I'm sure we can trust everyone not to insert a 1x1 rooms which loads a landmark which loads a landmark which loads a la...
|
||||
|
||||
/**
|
||||
* Generates an obfuscated but constant id for an original id for cases where you don't want players codediving for an id.
|
||||
* WARNING: MAKE SURE PLAYERS ARE NOT ABLE TO ACCESS THIS. To save performance, it's just secret + an incrementing number. Very guessable if you know what the secret is.
|
||||
*/
|
||||
/datum/controller/subsystem/mapping/proc/get_obfuscated_id(original, id_type = "GENERAL")
|
||||
if(!original)
|
||||
return //no.
|
||||
var/key = "[original]%[id_type]"
|
||||
if(random_generated_ids_by_original[key])
|
||||
return random_generated_ids_by_original[key]
|
||||
. = random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next_id++]"
|
||||
|
||||
@@ -3,7 +3,6 @@ PROCESSING_SUBSYSTEM_DEF(projectiles)
|
||||
wait = 1
|
||||
stat_tag = "PP"
|
||||
flags = SS_NO_INIT|SS_TICKER
|
||||
var/global_max_tick_moves = 10
|
||||
var/global_pixel_speed = 2
|
||||
var/global_iterations_per_move = 16
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
|
||||
trauma = _trauma
|
||||
owner = trauma.owner
|
||||
copy_known_languages_from(owner, TRUE)
|
||||
|
||||
setup_friend()
|
||||
|
||||
@@ -150,6 +149,8 @@
|
||||
friend_talk(message)
|
||||
|
||||
/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
|
||||
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
|
||||
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source))
|
||||
|
||||
/mob/camera/imaginary_friend/proc/friend_talk(message)
|
||||
|
||||
@@ -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
|
||||
|
||||
236
code/datums/chatmessage.dm
Normal file
236
code/datums/chatmessage.dm
Normal file
@@ -0,0 +1,236 @@
|
||||
#define CHAT_MESSAGE_SPAWN_TIME 0.2 SECONDS
|
||||
#define CHAT_MESSAGE_LIFESPAN 5 SECONDS
|
||||
#define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS
|
||||
#define CHAT_MESSAGE_EXP_DECAY 0.7 // Messages decay at pow(factor, idx in stack)
|
||||
#define CHAT_MESSAGE_HEIGHT_DECAY 0.9 // Increase message decay based on the height of the message
|
||||
#define CHAT_MESSAGE_APPROX_LHEIGHT 11 // Approximate height in pixels of an 'average' line, used for height decay
|
||||
#define CHAT_MESSAGE_WIDTH 96 // pixels
|
||||
#define CHAT_MESSAGE_MAX_LENGTH 110 // characters
|
||||
#define WXH_TO_HEIGHT(x) text2num(copytext((x), findtextEx((x), "x") + 1)) // thanks lummox
|
||||
|
||||
/**
|
||||
* # Chat Message Overlay
|
||||
*
|
||||
* Datum for generating a message overlay on the map
|
||||
*/
|
||||
/datum/chatmessage
|
||||
/// The visual element of the chat messsage
|
||||
var/image/message
|
||||
/// The location in which the message is appearing
|
||||
var/atom/message_loc
|
||||
/// The client who heard this message
|
||||
var/client/owned_by
|
||||
/// Contains the scheduled destruction time
|
||||
var/scheduled_destruction
|
||||
/// Contains the approximate amount of lines for height decay
|
||||
var/approx_lines
|
||||
|
||||
/**
|
||||
* Constructs a chat message overlay
|
||||
*
|
||||
* Arguments:
|
||||
* * text - The text content of the overlay
|
||||
* * target - The target atom to display the overlay at
|
||||
* * owner - The mob that owns this overlay, only this mob will be able to view it
|
||||
* * extra_classes - Extra classes to apply to the span that holds the text
|
||||
* * lifespan - The lifespan of the message in deciseconds
|
||||
*/
|
||||
/datum/chatmessage/New(text, atom/target, mob/owner, list/extra_classes = null, lifespan = CHAT_MESSAGE_LIFESPAN)
|
||||
. = ..()
|
||||
if (!istype(target))
|
||||
CRASH("Invalid target given for chatmessage")
|
||||
if(QDELETED(owner) || !istype(owner) || !owner.client)
|
||||
stack_trace("/datum/chatmessage created with [isnull(owner) ? "null" : "invalid"] mob owner")
|
||||
qdel(src)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/generate_image, text, target, owner, extra_classes, lifespan)
|
||||
|
||||
/datum/chatmessage/Destroy()
|
||||
if (owned_by)
|
||||
if (owned_by.seen_messages)
|
||||
LAZYREMOVEASSOC(owned_by.seen_messages, message_loc, src)
|
||||
owned_by.images.Remove(message)
|
||||
owned_by = null
|
||||
message_loc = null
|
||||
message = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Generates a chat message image representation
|
||||
*
|
||||
* Arguments:
|
||||
* * text - The text content of the overlay
|
||||
* * target - The target atom to display the overlay at
|
||||
* * owner - The mob that owns this overlay, only this mob will be able to view it
|
||||
* * extra_classes - Extra classes to apply to the span that holds the text
|
||||
* * lifespan - The lifespan of the message in deciseconds
|
||||
*/
|
||||
/datum/chatmessage/proc/generate_image(text, atom/target, mob/owner, list/extra_classes, lifespan)
|
||||
// Register client who owns this message
|
||||
owned_by = owner.client
|
||||
RegisterSignal(owned_by, COMSIG_PARENT_QDELETING, .proc/qdel, src)
|
||||
|
||||
// Clip message
|
||||
var/maxlen = owned_by.prefs.max_chat_length
|
||||
if (length_char(text) > maxlen)
|
||||
text = copytext_char(text, 1, maxlen + 1) + "..." // BYOND index moment
|
||||
|
||||
// Calculate target color if not already present
|
||||
if (!target.chat_color || target.chat_color_name != target.name)
|
||||
target.chat_color = colorize_string(target.name)
|
||||
target.chat_color_darkened = colorize_string(target.name, 0.85, 0.85)
|
||||
target.chat_color_name = target.name
|
||||
|
||||
// Get rid of any URL schemes that might cause BYOND to automatically wrap something in an anchor tag
|
||||
var/static/regex/url_scheme = new(@"[A-Za-z][A-Za-z0-9+-\.]*:\/\/", "g")
|
||||
text = replacetext(text, url_scheme, "")
|
||||
|
||||
// Reject whitespace
|
||||
var/static/regex/whitespace = new(@"^\s*$")
|
||||
if (whitespace.Find(text))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// Non mobs speakers can be small
|
||||
if (!ismob(target))
|
||||
extra_classes |= "small"
|
||||
|
||||
// Append radio icon if from a virtual speaker
|
||||
if (extra_classes.Find("virtual-speaker"))
|
||||
var/image/r_icon = image('icons/UI_Icons/chat/chat_icons.dmi', icon_state = "radio")
|
||||
text = "\icon[r_icon] " + text
|
||||
|
||||
// We dim italicized text to make it more distinguishable from regular text
|
||||
var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color
|
||||
|
||||
// Approximate text height
|
||||
// Note we have to replace HTML encoded metacharacters otherwise MeasureText will return a zero height
|
||||
// BYOND Bug #2563917
|
||||
// Construct text
|
||||
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
|
||||
var/complete_text = "<span class='center maptext [extra_classes != null ? extra_classes.Join(" ") : ""]' style='color: [tgt_color]'>[text]</span>"
|
||||
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
|
||||
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
|
||||
|
||||
// Translate any existing messages upwards, apply exponential decay factors to timers
|
||||
message_loc = target
|
||||
if (owned_by.seen_messages)
|
||||
var/idx = 1
|
||||
var/combined_height = approx_lines
|
||||
for(var/msg in owned_by.seen_messages[message_loc])
|
||||
var/datum/chatmessage/m = msg
|
||||
animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME)
|
||||
combined_height += m.approx_lines
|
||||
var/sched_remaining = m.scheduled_destruction - world.time
|
||||
if (sched_remaining > CHAT_MESSAGE_SPAWN_TIME)
|
||||
var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height)
|
||||
m.scheduled_destruction = world.time + remaining_time
|
||||
addtimer(CALLBACK(m, .proc/end_of_life), remaining_time, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
|
||||
// Build message image
|
||||
message = image(loc = message_loc, layer = CHAT_LAYER)
|
||||
message.plane = GAME_PLANE
|
||||
message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
|
||||
message.alpha = 0
|
||||
message.pixel_y = owner.bound_height * 0.95
|
||||
message.maptext_width = CHAT_MESSAGE_WIDTH
|
||||
message.maptext_height = mheight
|
||||
message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5
|
||||
message.maptext = complete_text
|
||||
|
||||
// View the message
|
||||
LAZYADDASSOC(owned_by.seen_messages, message_loc, src)
|
||||
owned_by.images |= message
|
||||
animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME)
|
||||
|
||||
// Prepare for destruction
|
||||
scheduled_destruction = world.time + (lifespan - CHAT_MESSAGE_EOL_FADE)
|
||||
addtimer(CALLBACK(src, .proc/end_of_life), lifespan - CHAT_MESSAGE_EOL_FADE, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
|
||||
/**
|
||||
* Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion
|
||||
*/
|
||||
/datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE)
|
||||
animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL)
|
||||
QDEL_IN(src, fadetime)
|
||||
|
||||
/**
|
||||
* Creates a message overlay at a defined location for a given speaker
|
||||
*
|
||||
* Arguments:
|
||||
* * speaker - The atom who is saying this message
|
||||
* * message_language - The language that the message is said in
|
||||
* * raw_message - The text content of the message
|
||||
* * spans - Additional classes to be added to the message
|
||||
* * message_mode - Bitflags relating to the mode of the message
|
||||
*/
|
||||
/mob/proc/create_chat_message(atom/movable/speaker, datum/language/message_language, raw_message, list/spans, message_mode)
|
||||
// Ensure the list we are using, if present, is a copy so we don't modify the list provided to us
|
||||
spans = spans?.Copy()
|
||||
|
||||
// Check for virtual speakers (aka hearing a message through a radio)
|
||||
var/atom/movable/originalSpeaker = speaker
|
||||
if (istype(speaker, /atom/movable/virtualspeaker))
|
||||
var/atom/movable/virtualspeaker/v = speaker
|
||||
speaker = v.source
|
||||
spans |= "virtual-speaker"
|
||||
|
||||
// Ignore virtual speaker (most often radio messages) from ourself
|
||||
if (originalSpeaker != src && speaker == src)
|
||||
return
|
||||
|
||||
// Display visual above source
|
||||
new /datum/chatmessage(lang_treat(speaker, message_language, raw_message, spans, null, TRUE), speaker, src, spans)
|
||||
|
||||
|
||||
// Tweak these defines to change the available color ranges
|
||||
#define CM_COLOR_SAT_MIN 0.6
|
||||
#define CM_COLOR_SAT_MAX 0.7
|
||||
#define CM_COLOR_LUM_MIN 0.65
|
||||
#define CM_COLOR_LUM_MAX 0.75
|
||||
|
||||
/**
|
||||
* Gets a color for a name, will return the same color for a given string consistently within a round.atom
|
||||
*
|
||||
* Note that this proc aims to produce pastel-ish colors using the HSL colorspace. These seem to be favorable for displaying on the map.
|
||||
*
|
||||
* Arguments:
|
||||
* * name - The name to generate a color for
|
||||
* * sat_shift - A value between 0 and 1 that will be multiplied against the saturation
|
||||
* * lum_shift - A value between 0 and 1 that will be multiplied against the luminescence
|
||||
*/
|
||||
/datum/chatmessage/proc/colorize_string(name, sat_shift = 1, lum_shift = 1)
|
||||
// seed to help randomness
|
||||
var/static/rseed = rand(1,26)
|
||||
|
||||
// get hsl using the selected 6 characters of the md5 hash
|
||||
var/hash = copytext(md5(name + GLOB.round_id), rseed, rseed + 6)
|
||||
var/h = hex2num(copytext(hash, 1, 3)) * (360 / 255)
|
||||
var/s = (hex2num(copytext(hash, 3, 5)) >> 2) * ((CM_COLOR_SAT_MAX - CM_COLOR_SAT_MIN) / 63) + CM_COLOR_SAT_MIN
|
||||
var/l = (hex2num(copytext(hash, 5, 7)) >> 2) * ((CM_COLOR_LUM_MAX - CM_COLOR_LUM_MIN) / 63) + CM_COLOR_LUM_MIN
|
||||
|
||||
// adjust for shifts
|
||||
s *= clamp(sat_shift, 0, 1)
|
||||
l *= clamp(lum_shift, 0, 1)
|
||||
|
||||
// convert to rgb
|
||||
var/h_int = round(h/60) // mapping each section of H to 60 degree sections
|
||||
var/c = (1 - abs(2 * l - 1)) * s
|
||||
var/x = c * (1 - abs((h / 60) % 2 - 1))
|
||||
var/m = l - c * 0.5
|
||||
x = (x + m) * 255
|
||||
c = (c + m) * 255
|
||||
m *= 255
|
||||
switch(h_int)
|
||||
if(0)
|
||||
return "#[num2hex(c, 2)][num2hex(x, 2)][num2hex(m, 2)]"
|
||||
if(1)
|
||||
return "#[num2hex(x, 2)][num2hex(c, 2)][num2hex(m, 2)]"
|
||||
if(2)
|
||||
return "#[num2hex(m, 2)][num2hex(c, 2)][num2hex(x, 2)]"
|
||||
if(3)
|
||||
return "#[num2hex(m, 2)][num2hex(x, 2)][num2hex(c, 2)]"
|
||||
if(4)
|
||||
return "#[num2hex(x, 2)][num2hex(m, 2)][num2hex(c, 2)]"
|
||||
if(5)
|
||||
return "#[num2hex(c, 2)][num2hex(m, 2)][num2hex(x, 2)]"
|
||||
@@ -1,95 +0,0 @@
|
||||
/datum/component/archaeology
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
var/list/archdrops = list(/obj/item/bikehorn = list(ARCH_PROB = 100, ARCH_MAXDROP = 1)) // honk~
|
||||
var/prob2drop
|
||||
var/dug
|
||||
var/datum/callback/callback
|
||||
|
||||
/datum/component/archaeology/Initialize(list/_archdrops = list(), datum/callback/_callback)
|
||||
archdrops = _archdrops
|
||||
for(var/i in archdrops)
|
||||
if(isnull(archdrops[i][ARCH_MAXDROP]))
|
||||
archdrops[i][ARCH_MAXDROP] = 1
|
||||
stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null max_drop value in [i].")
|
||||
if(isnull(archdrops[i][ARCH_PROB]))
|
||||
archdrops[i][ARCH_PROB] = 100
|
||||
stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null probability value in [i].")
|
||||
callback = _callback
|
||||
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY,.proc/Dig)
|
||||
RegisterSignal(parent, COMSIG_ATOM_EX_ACT, .proc/BombDig)
|
||||
RegisterSignal(parent, COMSIG_ATOM_SING_PULL, .proc/SingDig)
|
||||
|
||||
/datum/component/archaeology/InheritComponent(datum/component/archaeology/A, i_am_original)
|
||||
var/list/other_archdrops = A.archdrops
|
||||
var/list/_archdrops = archdrops
|
||||
for(var/I in other_archdrops)
|
||||
_archdrops[I] += other_archdrops[I]
|
||||
|
||||
/datum/component/archaeology/proc/Dig(datum/source, obj/item/I, mob/living/user)
|
||||
if(dug)
|
||||
to_chat(user, "<span class='notice'>Looks like someone has dug here already.</span>")
|
||||
return
|
||||
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
|
||||
if(I.tool_behaviour == TOOL_SHOVEL || I.tool_behaviour == TOOL_MINING)
|
||||
to_chat(user, "<span class='notice'>You start digging...</span>")
|
||||
|
||||
if(I.use_tool(parent, user, 40, volume=50))
|
||||
to_chat(user, "<span class='notice'>You dig a hole.</span>")
|
||||
gets_dug()
|
||||
dug = TRUE
|
||||
SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/datum/component/archaeology/proc/gets_dug()
|
||||
if(dug)
|
||||
return
|
||||
else
|
||||
var/turf/open/OT = get_turf(parent)
|
||||
for(var/thing in archdrops)
|
||||
var/maxtodrop = archdrops[thing][ARCH_MAXDROP]
|
||||
for(var/i in 1 to maxtodrop)
|
||||
if(prob(archdrops[thing][ARCH_PROB])) // can't win them all!
|
||||
new thing(OT)
|
||||
|
||||
if(isopenturf(OT))
|
||||
if(OT.postdig_icon_change)
|
||||
if(istype(OT, /turf/open/floor/plating/asteroid/) && !OT.postdig_icon)
|
||||
var/turf/open/floor/plating/asteroid/AOT = parent
|
||||
AOT.icon_plating = "[AOT.environment_type]_dug"
|
||||
AOT.icon_state = "[AOT.environment_type]_dug"
|
||||
else
|
||||
if(isplatingturf(OT))
|
||||
var/turf/open/floor/plating/POT = parent
|
||||
POT.icon_plating = "[POT.postdig_icon]"
|
||||
POT.icon_state = "[OT.postdig_icon]"
|
||||
|
||||
if(OT.slowdown) //Things like snow slow you down until you dig them.
|
||||
OT.slowdown = 0
|
||||
dug = TRUE
|
||||
if(callback)
|
||||
callback.Invoke()
|
||||
|
||||
/datum/component/archaeology/proc/SingDig(datum/source, S, current_size)
|
||||
switch(current_size)
|
||||
if(STAGE_THREE)
|
||||
if(prob(30))
|
||||
gets_dug()
|
||||
if(STAGE_FOUR)
|
||||
if(prob(50))
|
||||
gets_dug()
|
||||
else
|
||||
if(current_size >= STAGE_FIVE && prob(70))
|
||||
gets_dug()
|
||||
|
||||
/datum/component/archaeology/proc/BombDig(datum/source, severity, target)
|
||||
switch(severity)
|
||||
if(3)
|
||||
return
|
||||
if(2)
|
||||
if(prob(20))
|
||||
gets_dug()
|
||||
if(1)
|
||||
gets_dug()
|
||||
@@ -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)
|
||||
@@ -260,6 +260,15 @@
|
||||
subcategory = CAT_TOOL
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/electrochromatic_kit
|
||||
name = "Electrochromatic Kit"
|
||||
result = /obj/item/electronics/electrochromatic_kit
|
||||
reqs = list(/obj/item/stack/sheet/metal = 1,
|
||||
/obj/item/stack/cable_coil = 1)
|
||||
time = 5
|
||||
subcategory = CAT_TOOL
|
||||
category = CAT_MISC
|
||||
|
||||
////////////
|
||||
//Vehicles//
|
||||
////////////
|
||||
@@ -404,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,13 +1,18 @@
|
||||
/datum/component/knockback
|
||||
/// distance the atom will be thrown
|
||||
var/throw_distance
|
||||
/// whether this can throw anchored targets (tables, etc)
|
||||
var/throw_anchored
|
||||
/// whether this is a gentle throw (default false means people thrown into walls are stunned / take damage)
|
||||
var/throw_gentle
|
||||
|
||||
/datum/component/knockback/Initialize(throw_distance=1)
|
||||
/datum/component/knockback/Initialize(throw_distance=1, throw_gentle=FALSE)
|
||||
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.throw_distance = throw_distance
|
||||
src.throw_anchored = throw_anchored
|
||||
src.throw_gentle = throw_gentle
|
||||
|
||||
/datum/component/knockback/RegisterWithParent()
|
||||
. = ..()
|
||||
@@ -22,17 +27,29 @@
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
|
||||
|
||||
/// triggered after an item attacks something
|
||||
/datum/component/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
|
||||
if(!proximity_flag)
|
||||
return
|
||||
do_knockback(target, user, get_dir(source, target))
|
||||
|
||||
/// triggered after a hostile simplemob attacks something
|
||||
/datum/component/knockback/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
|
||||
do_knockback(target, attacker, get_dir(attacker, target))
|
||||
|
||||
/// triggered after a projectile hits something
|
||||
/datum/component/knockback/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
do_knockback(target, null, angle2dir(Angle))
|
||||
|
||||
|
||||
/**
|
||||
* Throw a target in a direction
|
||||
*
|
||||
* Arguments:
|
||||
* * target - Target atom to throw
|
||||
* * thrower - Thing that caused this atom to be thrown
|
||||
* * throw_dir - Direction to throw the atom
|
||||
*/
|
||||
/datum/component/knockback/proc/do_knockback(atom/target, mob/thrower, throw_dir)
|
||||
if(!ismovable(target) || throw_dir == null)
|
||||
return
|
||||
@@ -43,4 +60,4 @@
|
||||
throw_dir = turn(throw_dir, 180)
|
||||
throw_distance *= -1
|
||||
var/atom/throw_target = get_edge_target_turf(throwee, throw_dir)
|
||||
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower)
|
||||
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower) //, gentle = throw_gentle)
|
||||
|
||||
@@ -39,4 +39,5 @@
|
||||
/obj/effect/abstract/mirage_holder
|
||||
name = "Mirage holder"
|
||||
anchored = TRUE
|
||||
plane = PLANE_SPACE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -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)
|
||||
..()
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
/datum/element/dusts_on_leaving_area
|
||||
element_flags = ELEMENT_DETACH | ELEMENT_BESPOKE
|
||||
id_arg_index = 2
|
||||
var/list/attached_mobs = list()
|
||||
var/list/area_types = list()
|
||||
|
||||
/datum/element/dusts_on_leaving_area/Attach(datum/target,types)
|
||||
. = ..()
|
||||
if(!ismob(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
attached_mobs += target
|
||||
area_types = types
|
||||
START_PROCESSING(SSprocessing,src)
|
||||
RegisterSignal(target,COMSIG_ENTER_AREA,.proc/check_dust)
|
||||
|
||||
/datum/element/dusts_on_leaving_area/Detach(mob/M)
|
||||
. = ..()
|
||||
if(M in attached_mobs)
|
||||
attached_mobs -= M
|
||||
if(!attached_mobs.len)
|
||||
STOP_PROCESSING(SSprocessing,src)
|
||||
UnregisterSignal(M,COMSIG_ENTER_AREA)
|
||||
|
||||
/datum/element/dusts_on_leaving_area/process()
|
||||
for(var/m in attached_mobs)
|
||||
var/mob/M = m
|
||||
var/area/A = get_area(M)
|
||||
if(!(A.type in area_types))
|
||||
M.dust(force = TRUE)
|
||||
Detach(M)
|
||||
/datum/element/dusts_on_leaving_area/proc/check_dust(datum/source, area/A)
|
||||
var/mob/M = source
|
||||
if(istype(M) && !(A.type in area_types))
|
||||
M.dust(force = TRUE)
|
||||
|
||||
@@ -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] = ""
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
release()
|
||||
|
||||
/obj/item/clothing/head/mob_holder/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
|
||||
if(!ishuman(M)) //monkeys holding monkeys holding monkeys...
|
||||
if(M == held_mob || !ishuman(M)) //monkeys holding monkeys holding monkeys...
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
215
code/datums/elements/scavenging.dm
Normal file
215
code/datums/elements/scavenging.dm
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Scavenging element. Its scope shouldn't elude your imagination.
|
||||
* Basically loot piles that can be searched through for some items.
|
||||
* In my opinion, these are more engaging than normal maintenance loot spawners.
|
||||
* The loot doesn't have to be strictly made of items and objects, you could also use it to invoke some "events"
|
||||
* such as mice, rats, an halloween spook, persistent relics, traps, etcetera, go wild.
|
||||
*/
|
||||
/datum/element/scavenging
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 3
|
||||
|
||||
var/list/loot_left_per_atom = list() //loot left per attached atom.
|
||||
var/list/loot_table //pickweight list of available loot.
|
||||
var/list/unique_loot //limited loot, once the associated value reaches zero, its key is removed from loot_table
|
||||
var/scavenge_time = 12 SECONDS //how much time it takes
|
||||
var/can_use_hands = TRUE //bare handed scavenge time multiplier. If set to zero, only tools are usable.
|
||||
var/list/tool_types //which tool types the player can use instead of scavenging by hand, associated value is their speed.
|
||||
var/del_atom_on_depletion = FALSE //Will the atom be deleted when there is no loot left?
|
||||
var/list/search_texts = list("starts searching through", "start searching through", "You hear rummaging...")
|
||||
var/loot_restriction = NO_LOOT_RESTRICTION
|
||||
var/maximum_loot_per_player = 1 //only relevant if there is a restriction.
|
||||
var/list/scavenger_restriction_list //used for restrictions.
|
||||
|
||||
var/mean_loot_weight = 0
|
||||
var/list/progress_per_atom = list() //seconds of ditched progress per atom, used to resume the work instead of starting over.
|
||||
var/static/list/players_busy_scavenging = list() //players already busy scavenging.
|
||||
|
||||
/datum/element/scavenging/Attach(atom/target, amount = 5, list/loot, list/unique, time = 12 SECONDS, hands = TRUE, list/tools, list/texts, \
|
||||
del_deplete = FALSE, restriction = NO_LOOT_RESTRICTION, max_per_player = 1)
|
||||
. = ..()
|
||||
if(. == ELEMENT_INCOMPATIBLE || !length(loot) || !amount || !istype(target) || isarea(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
loot_left_per_atom[target] = amount
|
||||
if(!loot_table)
|
||||
loot_table = loot
|
||||
for(var/A in loot_table) //tally the list weights
|
||||
mean_loot_weight += loot_table[A]
|
||||
mean_loot_weight /= length(loot_table)
|
||||
if(!unique_loot)
|
||||
unique_loot = unique || list()
|
||||
scavenge_time = time
|
||||
can_use_hands = hands
|
||||
tool_types = tools
|
||||
if(texts)
|
||||
search_texts = texts
|
||||
del_atom_on_depletion = del_deplete
|
||||
loot_restriction = restriction
|
||||
maximum_loot_per_player = max_per_player
|
||||
if(can_use_hands)
|
||||
RegisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), .proc/scavenge_barehanded)
|
||||
if(tool_types)
|
||||
RegisterSignal(target, COMSIG_PARENT_ATTACKBY, .proc/scavenge_tool)
|
||||
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
|
||||
|
||||
/datum/element/scavenging/Detach(atom/target)
|
||||
. = ..()
|
||||
loot_left_per_atom -= target
|
||||
progress_per_atom -= target
|
||||
if(maximum_loot_per_player == LOOT_RESTRICTION_MIND_PILE || maximum_loot_per_player == LOOT_RESTRICTION_CKEY_PILE)
|
||||
maximum_loot_per_player -= target
|
||||
UnregisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
|
||||
|
||||
/datum/element/scavenging/proc/on_examine(atom/source, mob/user, list/examine_list)
|
||||
var/methods = tool_types.Copy()
|
||||
if(can_use_hands)
|
||||
methods += list("bare handed")
|
||||
if(!length(methods))
|
||||
return
|
||||
var/text = english_list(methods, "", " or ")
|
||||
examine_list += "<span class='notice'>Looks like [source.p_they()] can be scavenged [length(tool_types) ? "with" : ""][length(methods == 1) ? "" : "either "][length(tool_types) ? "a " : ""][text]</span>"
|
||||
|
||||
/datum/element/scavenging/proc/scavenge_barehanded(atom/source, mob/user)
|
||||
scavenge(source, user, 1)
|
||||
return COMPONENT_NO_ATTACK_HAND
|
||||
|
||||
/datum/element/scavenging/proc/scavenge_tool(atom/source, obj/item/I, mob/user, params)
|
||||
if(user.a_intent == INTENT_HARM || !I.tool_behaviour) //Robust trash disposal techniques!
|
||||
return
|
||||
var/speed_multi = tool_types[I.tool_behaviour]
|
||||
if(!speed_multi)
|
||||
return
|
||||
scavenge(source, user, speed_multi)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/// This proc has to be asynced (cough cough, do_after) in order to return the comsig values in time to stop the attack chain.
|
||||
/datum/element/scavenging/proc/scavenge(atom/source, mob/user, speed_multi = 1)
|
||||
set waitfor = FALSE
|
||||
|
||||
if(players_busy_scavenging[user])
|
||||
return
|
||||
players_busy_scavenging[user] = TRUE
|
||||
var/progress_done = progress_per_atom[source]
|
||||
var/len_messages = length(search_texts)
|
||||
var/msg_first_person
|
||||
if(len_messages >= 2)
|
||||
msg_first_person = "<span class='notice'>You [progress_done ? ", resume a ditched task and " : ""][search_texts[2]] [source].</span>"
|
||||
var/msg_blind
|
||||
if(len_messages >= 3)
|
||||
msg_blind = "<span class='italic'>[search_texts[3]]</span>"
|
||||
user.visible_message("<span class='notice'>[user] [search_texts[1]] [source].</span>", msg_first_person, msg_blind)
|
||||
if(do_after(user, scavenge_time * speed_multi, TRUE, source, TRUE, CALLBACK(src, .proc/set_progress, source, world.time), resume_time = progress_done * speed_multi))
|
||||
spawn_loot(source, user)
|
||||
players_busy_scavenging -= user
|
||||
|
||||
/datum/element/scavenging/proc/set_progress(atom/source, start_time)
|
||||
progress_per_atom[source] = world.time - start_time
|
||||
return TRUE
|
||||
|
||||
/datum/element/scavenging/proc/spawn_loot(atom/source, mob/user)
|
||||
progress_per_atom -= source
|
||||
|
||||
var/loot = pickweight(loot_table)
|
||||
var/special = TRUE
|
||||
var/free = FALSE
|
||||
if(!loot_left_per_atom[source])
|
||||
to_chat(user, "<span class='warning'>Looks likes there is nothing worth of interest left in [source], what a shame...</span>")
|
||||
return
|
||||
|
||||
var/num_times = 0
|
||||
switch(loot_restriction)
|
||||
if(LOOT_RESTRICTION_MIND)
|
||||
num_times = LAZYACCESS(scavenger_restriction_list, user.mind)
|
||||
if(LOOT_RESTRICTION_CKEY)
|
||||
num_times = LAZYACCESS(scavenger_restriction_list, user.ckey)
|
||||
if(LOOT_RESTRICTION_MIND_PILE)
|
||||
var/list/L = LAZYACCESS(scavenger_restriction_list, source)
|
||||
if(L)
|
||||
num_times = LAZYACCESS(L, user.mind)
|
||||
if(LOOT_RESTRICTION_CKEY_PILE)
|
||||
var/list/L = LAZYACCESS(scavenger_restriction_list, source)
|
||||
if(L)
|
||||
num_times = LAZYACCESS(L, user.ckey)
|
||||
if(num_times >= maximum_loot_per_player)
|
||||
to_chat(user, "<span class='warning'>You can't find anything else vaguely useful in [source]. Another set of eyes might, however.</span>")
|
||||
return
|
||||
|
||||
switch(loot) // TODO: datumize these out.
|
||||
if(SCAVENGING_FOUND_NOTHING)
|
||||
to_chat(user, "<span class='notice'>You found nothing, better luck next time.</span>")
|
||||
free = TRUE //doesn't consume the loot pile.
|
||||
if(SCAVENGING_SPAWN_MOUSE)
|
||||
var/nasty_rodent = pick("mouse", "rodent", "squeaky critter", "stupid pest", "annoying cable chewer", "nasty, ugly, evil, disease-ridden rodent")
|
||||
to_chat(user, "<span class='notice'>You found something in [source]... no wait, that's just another [nasty_rodent].</span>")
|
||||
new /mob/living/simple_animal/mouse(source.loc)
|
||||
if(SCAVENGING_SPAWN_MICE)
|
||||
user.visible_message("<span class='notice'>A small gang of mice emerges from [source].</span>", \
|
||||
"<span class='notice'>You found something in [source]... no wait, that's just another- <b>no wait, that's a lot of damn mice.</b></span>")
|
||||
for(var/i in 1 to rand(4, 6))
|
||||
new /mob/living/simple_animal/mouse(source.loc)
|
||||
if(SCAVENGING_SPAWN_TOM)
|
||||
if(GLOB.tom_existed) //There can only be one.
|
||||
to_chat(user, "<span class='notice'>You found nothing, better luck next time.</span>")
|
||||
free = TRUE
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You found something in [source]... no wait, that's Tom, the mouse! What is he doing here?</span>")
|
||||
new /mob/living/simple_animal/mouse/brown/Tom(source.loc)
|
||||
else
|
||||
special = FALSE
|
||||
|
||||
if(!special) //generic loot. Nothing too strange like more loot spawners anyway.
|
||||
var/atom/A = new loot(source.loc)
|
||||
if(isitem(A) && !user.get_active_held_item())
|
||||
user.put_in_hands(A)
|
||||
var/rarity_append = "."
|
||||
switch(loot_table[loot]/mean_loot_weight*100)
|
||||
if(0 to 1)
|
||||
rarity_append = "! <b>AMAZING!</b>"
|
||||
if(1 to 2)
|
||||
rarity_append = "! Woah!"
|
||||
if(2 to 5)
|
||||
rarity_append = ". Rare!"
|
||||
if(5 to 10)
|
||||
rarity_append = ". Great."
|
||||
if(10 to 25)
|
||||
rarity_append = ". Nice."
|
||||
if(20 to 50)
|
||||
rarity_append = ". Not bad."
|
||||
to_chat(user, "You found something in [source]... it's \a [A][rarity_append]")
|
||||
|
||||
if(unique_loot[loot])
|
||||
var/loot_left = --unique_loot[loot]
|
||||
if(!loot_left)
|
||||
loot_table -= loot
|
||||
unique_loot -= loot
|
||||
mean_loot_weight = 0
|
||||
for(var/A in loot_table) //re-tally the list weights
|
||||
mean_loot_weight += loot_table[A]
|
||||
mean_loot_weight /= length(loot_table)
|
||||
|
||||
if(free)
|
||||
return
|
||||
|
||||
--loot_left_per_atom[source]
|
||||
if(del_atom_on_depletion && !loot_left_per_atom[source])
|
||||
source.visible_message("<span class='warning'>[source] has been looted clean.</span>")
|
||||
qdel(source)
|
||||
return
|
||||
|
||||
if(!loot_restriction)
|
||||
return
|
||||
|
||||
LAZYINITLIST(scavenger_restriction_list)
|
||||
switch(loot_restriction)
|
||||
if(LOOT_RESTRICTION_MIND)
|
||||
scavenger_restriction_list[user.mind]++
|
||||
if(LOOT_RESTRICTION_CKEY)
|
||||
scavenger_restriction_list[user.ckey]++
|
||||
if(LOOT_RESTRICTION_MIND_PILE)
|
||||
LAZYINITLIST(scavenger_restriction_list[source])
|
||||
var/list/L = scavenger_restriction_list[source]
|
||||
L[user.mind]++
|
||||
if(LOOT_RESTRICTION_CKEY_PILE)
|
||||
LAZYINITLIST(scavenger_restriction_list[source])
|
||||
var/list/L = scavenger_restriction_list[source]
|
||||
L[user.ckey]++
|
||||
31
code/datums/elements/snail_crawl.dm
Normal file
31
code/datums/elements/snail_crawl.dm
Normal file
@@ -0,0 +1,31 @@
|
||||
/datum/element/snailcrawl
|
||||
element_flags = ELEMENT_DETACH
|
||||
|
||||
/datum/element/snailcrawl/Attach(datum/target)
|
||||
. = ..()
|
||||
if(!ismovable(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
var/P
|
||||
if(iscarbon(target))
|
||||
P = .proc/snail_crawl
|
||||
else
|
||||
P = .proc/lubricate
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, P)
|
||||
|
||||
/datum/element/snailcrawl/Detach(mob/living/carbon/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
||||
if(istype(target))
|
||||
target.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
|
||||
|
||||
/datum/element/snailcrawl/proc/snail_crawl(mob/living/carbon/snail)
|
||||
if(snail.resting && !snail.buckled && lubricate(snail))
|
||||
snail.add_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
|
||||
else
|
||||
snail.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
|
||||
|
||||
/datum/element/snailcrawl/proc/lubricate(atom/movable/snail)
|
||||
var/turf/open/OT = get_turf(snail)
|
||||
if(istype(OT))
|
||||
OT.MakeSlippery(TURF_WET_LUBE, 20)
|
||||
return TRUE
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
112
code/datums/ruins/icemoon.dm
Normal file
112
code/datums/ruins/icemoon.dm
Normal file
@@ -0,0 +1,112 @@
|
||||
// Hey! Listen! Update \config\iceruinblacklist.txt with your new ruins!
|
||||
|
||||
/datum/map_template/ruin/icemoon
|
||||
prefix = "_maps/RandomRuins/IceRuins/"
|
||||
allow_duplicates = FALSE
|
||||
cost = 5
|
||||
|
||||
// above ground only
|
||||
|
||||
/datum/map_template/ruin/icemoon/lust
|
||||
name = "Ruin of Lust"
|
||||
id = "lust"
|
||||
description = "Not exactly what you expected."
|
||||
suffix = "icemoon_surface_lust.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/asteroid
|
||||
name = "Asteroid Site"
|
||||
id = "asteroidsite"
|
||||
description = "Surprised to see us here?"
|
||||
suffix = "icemoon_surface_asteroid.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/hotsprings
|
||||
name = "Hot Springs"
|
||||
id = "hotsprings"
|
||||
description = "Just relax and take a dip, nothing will go wrong, I swear!"
|
||||
suffix = "icemoon_surface_hotsprings.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/engioutpost
|
||||
name = "Engineer Outpost"
|
||||
id = "engioutpost"
|
||||
description = "Blown up by an unfortunate accident."
|
||||
suffix = "icemoon_surface_engioutpost.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/fountain
|
||||
name = "Fountain Hall"
|
||||
id = "fountain"
|
||||
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
|
||||
prefix = "_maps/RandomRuins/AnywhereRuins/"
|
||||
suffix = "fountain_hall.dmm"
|
||||
|
||||
// above and below ground together
|
||||
|
||||
/datum/map_template/ruin/icemoon/mining_site
|
||||
name = "Mining Site"
|
||||
id = "miningsite"
|
||||
description = "Ruins of a site where people once mined with primitive tools for ore."
|
||||
suffix = "icemoon_surface_mining_site.dmm"
|
||||
always_place = TRUE
|
||||
always_spawn_with = list(/datum/map_template/ruin/icemoon/underground/mining_site_below = PLACE_BELOW)
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/mining_site_below
|
||||
name = "Mining Site Underground"
|
||||
id = "miningsite-underground"
|
||||
description = "Who knew ladders could be so useful?"
|
||||
suffix = "icemoon_underground_mining_site.dmm"
|
||||
unpickable = TRUE
|
||||
|
||||
// below ground only
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground
|
||||
name = "underground ruin"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/abandonedvillage
|
||||
name = "Abandoned Village"
|
||||
id = "abandonedvillage"
|
||||
description = "Who knows what lies within?"
|
||||
suffix = "icemoon_underground_abandoned_village.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/library
|
||||
name = "Buried Library"
|
||||
id = "buriedlibrary"
|
||||
description = "A once grand library, now lost to the confines of the Ice Moon."
|
||||
suffix = "icemoon_underground_library.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/wrath
|
||||
name = "Ruin of Wrath"
|
||||
id = "wrath"
|
||||
description = "You'll fight and fight and just keep fighting."
|
||||
suffix = "icemoon_underground_wrath.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/lavaland
|
||||
name = "Lavaland Site"
|
||||
id = "lavalandsite"
|
||||
description = "I guess we never really left you huh?"
|
||||
suffix = "icemoon_underground_lavaland.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/puzzle
|
||||
name = "Ancient Puzzle"
|
||||
id = "puzzle"
|
||||
description = "Mystery to be solved."
|
||||
suffix = "icemoon_underground_puzzle.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/bathhouse
|
||||
name = "Bath House"
|
||||
id = "bathhouse"
|
||||
description = "A taste of paradise, locked in the hell of the Ice Moon."
|
||||
suffix = "icemoon_underground_bathhouse.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/wendigo_cave
|
||||
name = "Wendigo Cave"
|
||||
id = "wendigocave"
|
||||
description = "Into the jaws of the beast."
|
||||
suffix = "icemoon_underground_wendigo_cave.dmm"
|
||||
|
||||
/datum/map_template/ruin/icemoon/underground/free_golem
|
||||
name = "Free Golem Ship"
|
||||
id = "golem-ship"
|
||||
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
|
||||
Seem very intent on research and individual liberty, and also geology-based naming?"
|
||||
prefix = "_maps/RandomRuins/AnywhereRuins/"
|
||||
suffix = "golem_ship.dmm"
|
||||
allow_duplicates = FALSE
|
||||
@@ -67,7 +67,8 @@
|
||||
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
|
||||
Seem very intent on research and individual liberty, and also geology based naming?"
|
||||
cost = 20
|
||||
suffix = "lavaland_surface_golem_ship.dmm"
|
||||
prefix = "_maps/RandomRuins/AnywhereRuins/"
|
||||
suffix = "golem_ship.dmm"
|
||||
allow_duplicates = FALSE
|
||||
|
||||
/datum/map_template/ruin/lavaland/animal_hospital
|
||||
@@ -175,7 +176,8 @@
|
||||
name = "Fountain Hall"
|
||||
id = "fountain"
|
||||
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
|
||||
suffix = "lavaland_surface_fountain_hall.dmm"
|
||||
prefix = "_maps/RandomRuins/AnywhereRuins/"
|
||||
suffix = "fountain_hall.dmm"
|
||||
cost = 5
|
||||
allow_duplicates = FALSE
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
mappath = "[prefix][shuttle_id].dmm"
|
||||
. = ..()
|
||||
|
||||
/datum/map_template/shuttle/preload_size(path, cache)
|
||||
/datum/map_template/shuttle/preload_size(path = mappath, force_cache = FALSE)
|
||||
. = ..(path, TRUE) // Done this way because we still want to know if someone actualy wanted to cache the map
|
||||
if(!cached_map)
|
||||
return
|
||||
|
||||
discover_port_offset()
|
||||
|
||||
if(!cache)
|
||||
if(!cached_map)
|
||||
cached_map = null
|
||||
|
||||
/datum/map_template/shuttle/proc/discover_port_offset()
|
||||
@@ -53,12 +53,11 @@
|
||||
++xcrd
|
||||
--ycrd
|
||||
|
||||
/datum/map_template/shuttle/load(turf/T, centered, register=TRUE)
|
||||
/datum/map_template/shuttle/load(turf/T, centered = FALSE, orientation = SOUTH, annihilate = default_annihilate, force_cache = FALSE, rotate_placement_to_orientation = FALSE, register = TRUE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/list/turfs = block( locate(.[MAP_MINX], .[MAP_MINY], .[MAP_MINZ]),
|
||||
locate(.[MAP_MAXX], .[MAP_MAXY], .[MAP_MAXZ]))
|
||||
var/list/turfs = get_last_loaded_turf_block()
|
||||
for(var/i in 1 to turfs.len)
|
||||
var/turf/place = turfs[i]
|
||||
if(istype(place, /turf/open/space)) // This assumes all shuttles are loaded in a single spot then moved to their real destination.
|
||||
|
||||
@@ -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.
|
||||
@@ -17,52 +25,137 @@
|
||||
return null
|
||||
return skills[skill]
|
||||
|
||||
/**
|
||||
* Grabs the level of a skill. Only supported by skills with tiers or levels.
|
||||
*/
|
||||
/datum/skill_holder/proc/get_skill_level(skill)
|
||||
if(!ispath(skill, /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
|
||||
var/affinity = skill_affinities[skill]
|
||||
if(isnull(affinity))
|
||||
return 1
|
||||
return affinity
|
||||
. = 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))
|
||||
. = 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))
|
||||
skills[skill] = value
|
||||
LAZYINITLIST(skills)
|
||||
S.set_skill_value(src, value, owner, silent)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Boosts a skill to a value if not aobve
|
||||
*/
|
||||
/datum/skill_holder/proc/boost_skill_value_to(skill, value)
|
||||
/datum/skill_holder/proc/boost_skill_value_to(skill, value, silent = FALSE)
|
||||
var/current = get_skill_value(skill)
|
||||
if(!is_skill_value_greater(skill, current, value))
|
||||
return FALSE
|
||||
set_skill_value(skill, value)
|
||||
set_skill_value(skill, value, silent)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Automatic skill increase, multiplied by skill affinity if existing.
|
||||
* Only works if skill is numerical.
|
||||
*/
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value)
|
||||
if(!ispath(skill, /datum/skill/numerical))
|
||||
CRASH("You cannot auto increment a non numerical skill!")
|
||||
/datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE)
|
||||
if(!ispath(skill, /datum/skill))
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.")
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(S.progression_type != SKILL_PROGRESSION_NUMERICAL && S.progression_type != SKILL_PROGRESSION_LEVEL)
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
boost_skill_value_to(skill, current + (value * affinity))
|
||||
var/target_value = current + (value * affinity)
|
||||
if(maximum)
|
||||
target_value = max(target_value, maximum)
|
||||
if(target_value == maximum) //no more experience to gain, early return.
|
||||
return
|
||||
boost_skill_value_to(skill, target_value, silent)
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses one skill.
|
||||
* Args:
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * threshold : The difficulty of the action, in short. Refer to __DEFINES/skills/defines.dm for the defines.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/action_skills_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
|
||||
var/mod
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(!S)
|
||||
return
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
|
||||
|
||||
var/list/comsig_values = list(mod)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ACTION_SKILL_MOD, args, comsig_values)
|
||||
mod = comsig_values[MOD_VALUES_SKILL_MOD]
|
||||
|
||||
. = modifier_is_multiplier ? value*mod : value/mod
|
||||
|
||||
/**
|
||||
* Generic value modifier proc that uses several skills, intended for items.
|
||||
* Args:
|
||||
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
|
||||
* * the value.
|
||||
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/skill_holder/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
|
||||
. = value
|
||||
var/sum = 0
|
||||
var/divisor = 0
|
||||
var/list/checked_skills
|
||||
for(var/k in I.used_skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[k]
|
||||
if(!S)
|
||||
continue
|
||||
var/our_flags = (I.used_skills[k]|S.skill_flags)
|
||||
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
|
||||
continue
|
||||
var/mod
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = LAZYACCESS(skill_levels, S.type)
|
||||
else
|
||||
mod = LAZYACCESS(skills, S.type)
|
||||
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
|
||||
LAZYADD(checked_skills, S)
|
||||
|
||||
var/list/comsig_values = list(sum, divisor, checked_skills)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, args, comsig_values)
|
||||
sum = comsig_values[MOD_VALUES_ITEM_SKILLS_SUM]
|
||||
divisor = comsig_values[MOD_VALUES_ITEM_SKILLS_DIV]
|
||||
|
||||
if(divisor)
|
||||
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
|
||||
|
||||
/**
|
||||
* Generates a HTML readout of our skills.
|
||||
@@ -73,6 +166,6 @@
|
||||
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
|
||||
for(var/path in skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
out += "<tr><td>[S.name]</td><td>[S.standard_render_value(skills[path])]</td></tr>"
|
||||
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]</td></tr>"
|
||||
out += "</table>"
|
||||
return out.Join("")
|
||||
|
||||
6
code/datums/skills/engineering.dm
Normal file
6
code/datums/skills/engineering.dm
Normal file
@@ -0,0 +1,6 @@
|
||||
/datum/skill/level/job/wiring
|
||||
name = "Wiring"
|
||||
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
|
||||
name_color = COLOR_PALE_ORANGE
|
||||
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
|
||||
@@ -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.
|
||||
|
||||
@@ -550,3 +550,30 @@
|
||||
else if(isanimal(L))
|
||||
var/mob/living/simple_animal/SM = L
|
||||
SM.adjustHealth(-3.5, forced = TRUE)
|
||||
|
||||
/obj/screen/alert/status_effect/regenerative_core
|
||||
name = "Reinforcing Tendrils"
|
||||
desc = "You can move faster than your broken body could normally handle!"
|
||||
icon_state = "regenerative_core"
|
||||
name = "Regenerative Core Tendrils"
|
||||
|
||||
/datum/status_effect/regenerative_core
|
||||
id = "Regenerative Core"
|
||||
duration = 1 MINUTES
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = /obj/screen/alert/status_effect/regenerative_core
|
||||
|
||||
/datum/status_effect/regenerative_core/on_apply()
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
|
||||
owner.adjustBruteLoss(-25)
|
||||
if(!AmBloodsucker(owner)) //use your coffin you lazy bastard
|
||||
owner.adjustFireLoss(-25)
|
||||
owner.remove_CC()
|
||||
owner.bodytemperature = BODYTEMP_NORMAL
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/regenerative_core/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
|
||||
owner.updatehealth()
|
||||
@@ -391,78 +391,34 @@
|
||||
owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
|
||||
..()
|
||||
|
||||
/datum/status_effect/saw_bleed
|
||||
/datum/status_effect/stacking/saw_bleed
|
||||
id = "saw_bleed"
|
||||
duration = -1 //removed under specific conditions
|
||||
tick_interval = 6
|
||||
alert_type = null
|
||||
var/mutable_appearance/bleed_overlay
|
||||
var/mutable_appearance/bleed_underlay
|
||||
var/bleed_amount = 3
|
||||
var/bleed_buildup = 3
|
||||
var/delay_before_decay = 5
|
||||
delay_before_decay = 5
|
||||
stack_threshold = 10
|
||||
max_stacks = 10
|
||||
overlay_file = 'icons/effects/bleed.dmi'
|
||||
underlay_file = 'icons/effects/bleed.dmi'
|
||||
overlay_state = "bleed"
|
||||
underlay_state = "bleed"
|
||||
var/bleed_damage = 200
|
||||
var/needs_to_bleed = FALSE
|
||||
|
||||
/datum/status_effect/saw_bleed/Destroy()
|
||||
if(owner)
|
||||
owner.cut_overlay(bleed_overlay)
|
||||
owner.underlays -= bleed_underlay
|
||||
QDEL_NULL(bleed_overlay)
|
||||
return ..()
|
||||
/datum/status_effect/stacking/saw_bleed/fadeout_effect()
|
||||
new /obj/effect/temp_visual/bleed(get_turf(owner))
|
||||
|
||||
/datum/status_effect/saw_bleed/on_apply()
|
||||
if(owner.stat == DEAD)
|
||||
return FALSE
|
||||
bleed_overlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
|
||||
bleed_underlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
|
||||
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
|
||||
var/icon_height = I.Height()
|
||||
bleed_overlay.pixel_x = -owner.pixel_x
|
||||
bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
|
||||
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
|
||||
bleed_underlay.pixel_x = -owner.pixel_x
|
||||
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
|
||||
bleed_underlay.alpha = 40
|
||||
owner.add_overlay(bleed_overlay)
|
||||
owner.underlays += bleed_underlay
|
||||
return ..()
|
||||
/datum/status_effect/stacking/saw_bleed/threshold_cross_effect()
|
||||
owner.adjustBruteLoss(bleed_damage)
|
||||
var/turf/T = get_turf(owner)
|
||||
new /obj/effect/temp_visual/bleed/explode(T)
|
||||
for(var/d in GLOB.alldirs)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
|
||||
playsound(T, "desceration", 100, TRUE, -1)
|
||||
|
||||
/datum/status_effect/saw_bleed/tick()
|
||||
if(owner.stat == DEAD)
|
||||
qdel(src)
|
||||
else
|
||||
add_bleed(-1)
|
||||
|
||||
/datum/status_effect/saw_bleed/proc/add_bleed(amount)
|
||||
owner.cut_overlay(bleed_overlay)
|
||||
owner.underlays -= bleed_underlay
|
||||
bleed_amount += amount
|
||||
if(bleed_amount)
|
||||
if(bleed_amount >= 10)
|
||||
needs_to_bleed = TRUE
|
||||
qdel(src)
|
||||
else
|
||||
if(amount > 0)
|
||||
tick_interval += delay_before_decay
|
||||
bleed_overlay.icon_state = "bleed[bleed_amount]"
|
||||
bleed_underlay.icon_state = "bleed[bleed_amount]"
|
||||
owner.add_overlay(bleed_overlay)
|
||||
owner.underlays += bleed_underlay
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/saw_bleed/on_remove()
|
||||
. = ..()
|
||||
if(needs_to_bleed)
|
||||
var/turf/T = get_turf(owner)
|
||||
new /obj/effect/temp_visual/bleed/explode(T)
|
||||
for(var/d in GLOB.alldirs)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
|
||||
playsound(T, "desceration", 200, 1, -1)
|
||||
owner.adjustBruteLoss(bleed_damage)
|
||||
else
|
||||
new /obj/effect/temp_visual/bleed(get_turf(owner))
|
||||
/datum/status_effect/stacking/saw_bleed/bloodletting
|
||||
id = "bloodletting"
|
||||
stack_threshold = 7
|
||||
max_stacks = 7
|
||||
bleed_damage = 20
|
||||
|
||||
/datum/status_effect/neck_slice
|
||||
id = "neck_slice"
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
|
||||
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
|
||||
var/mob/living/owner //The mob affected by the status effect.
|
||||
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
|
||||
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
|
||||
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
|
||||
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
|
||||
@@ -16,6 +15,8 @@
|
||||
/// If this is TRUE, the user will have sprint forcefully disabled while this is active.
|
||||
var/blocks_sprint = FALSE
|
||||
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
|
||||
/// How many of the effect can be on one mob, and what happens when you try to add another
|
||||
var/status_type = STATUS_EFFECT_UNIQUE
|
||||
|
||||
/datum/status_effect/New(list/arguments)
|
||||
on_creation(arglist(arguments))
|
||||
@@ -67,6 +68,9 @@
|
||||
|
||||
/datum/status_effect/proc/tick() //Called every tick.
|
||||
|
||||
/datum/status_effect/proc/before_remove() //! Called before being removed; returning FALSE will cancel removal
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
@@ -123,12 +127,13 @@
|
||||
S1 = new effect(arguments)
|
||||
. = S1
|
||||
|
||||
/mob/living/proc/remove_status_effect(effect) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
|
||||
/mob/living/proc/remove_status_effect(effect, ...) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
|
||||
. = FALSE
|
||||
var/list/arguments = args.Copy(2)
|
||||
if(status_effects)
|
||||
var/datum/status_effect/S1 = effect
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(initial(S1.id) == S.id)
|
||||
if(initial(S1.id) == S.id && S.before_remove(arguments))
|
||||
qdel(S)
|
||||
. = TRUE
|
||||
|
||||
@@ -147,3 +152,129 @@
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(initial(S1.id) == S.id)
|
||||
. += S
|
||||
|
||||
//////////////////////
|
||||
// STACKING EFFECTS //
|
||||
//////////////////////
|
||||
|
||||
/datum/status_effect/stacking
|
||||
id = "stacking_base"
|
||||
duration = -1 //removed under specific conditions
|
||||
alert_type = null
|
||||
var/stacks = 0 //how many stacks are accumulated, also is # of stacks that target will have when first applied
|
||||
var/delay_before_decay //deciseconds until ticks start occuring, which removes stacks (first stack will be removed at this time plus tick_interval)
|
||||
tick_interval = 10 //deciseconds between decays once decay starts
|
||||
var/stack_decay = 1 //how many stacks are lost per tick (decay trigger)
|
||||
var/stack_threshold //special effects trigger when stacks reach this amount
|
||||
var/max_stacks //stacks cannot exceed this amount
|
||||
var/consumed_on_threshold = TRUE //if status should be removed once threshold is crossed
|
||||
var/threshold_crossed = FALSE //set to true once the threshold is crossed, false once it falls back below
|
||||
var/overlay_file
|
||||
var/underlay_file
|
||||
var/overlay_state // states in .dmi must be given a name followed by a number which corresponds to a number of stacks. put the state name without the number in these state vars
|
||||
var/underlay_state // the number is concatonated onto the string based on the number of stacks to get the correct state name
|
||||
var/mutable_appearance/status_overlay
|
||||
var/mutable_appearance/status_underlay
|
||||
|
||||
/datum/status_effect/stacking/proc/threshold_cross_effect() //what happens when threshold is crossed
|
||||
|
||||
/datum/status_effect/stacking/proc/stacks_consumed_effect() //runs if status is deleted due to threshold being crossed
|
||||
|
||||
/datum/status_effect/stacking/proc/fadeout_effect() //runs if status is deleted due to being under one stack
|
||||
|
||||
/datum/status_effect/stacking/proc/stack_decay_effect() //runs every time tick() causes stacks to decay
|
||||
|
||||
/datum/status_effect/stacking/proc/on_threshold_cross()
|
||||
threshold_cross_effect()
|
||||
if(consumed_on_threshold)
|
||||
stacks_consumed_effect()
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/stacking/proc/on_threshold_drop()
|
||||
|
||||
/datum/status_effect/stacking/proc/can_have_status()
|
||||
return owner.stat != DEAD
|
||||
|
||||
/datum/status_effect/stacking/proc/can_gain_stacks()
|
||||
return owner.stat != DEAD
|
||||
|
||||
/datum/status_effect/stacking/tick()
|
||||
if(!can_have_status())
|
||||
qdel(src)
|
||||
else
|
||||
add_stacks(-stack_decay)
|
||||
stack_decay_effect()
|
||||
|
||||
/datum/status_effect/stacking/proc/add_stacks(stacks_added)
|
||||
if(stacks_added > 0 && !can_gain_stacks())
|
||||
return FALSE
|
||||
owner.cut_overlay(status_overlay)
|
||||
owner.underlays -= status_underlay
|
||||
stacks += stacks_added
|
||||
if(stacks > 0)
|
||||
if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
|
||||
threshold_crossed = TRUE
|
||||
on_threshold_cross()
|
||||
if(consumed_on_threshold)
|
||||
return
|
||||
else if(stacks < stack_threshold && threshold_crossed)
|
||||
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
|
||||
on_threshold_drop()
|
||||
if(stacks_added > 0)
|
||||
tick_interval += delay_before_decay //refreshes time until decay
|
||||
stacks = min(stacks, max_stacks)
|
||||
status_overlay.icon_state = "[overlay_state][stacks]"
|
||||
status_underlay.icon_state = "[underlay_state][stacks]"
|
||||
owner.add_overlay(status_overlay)
|
||||
owner.underlays += status_underlay
|
||||
else
|
||||
fadeout_effect()
|
||||
qdel(src) //deletes status if stacks fall under one
|
||||
|
||||
/datum/status_effect/stacking/on_creation(mob/living/new_owner, stacks_to_apply)
|
||||
. = ..()
|
||||
if(.)
|
||||
add_stacks(stacks_to_apply)
|
||||
|
||||
/datum/status_effect/stacking/on_apply()
|
||||
if(!can_have_status())
|
||||
return FALSE
|
||||
status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]")
|
||||
status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]")
|
||||
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
|
||||
var/icon_height = I.Height()
|
||||
status_overlay.pixel_x = -owner.pixel_x
|
||||
status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
|
||||
status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size
|
||||
status_underlay.pixel_x = -owner.pixel_x
|
||||
status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
|
||||
status_underlay.alpha = 40
|
||||
owner.add_overlay(status_overlay)
|
||||
owner.underlays += status_underlay
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/stacking/Destroy()
|
||||
if(owner)
|
||||
owner.cut_overlay(status_overlay)
|
||||
owner.underlays -= status_underlay
|
||||
QDEL_NULL(status_overlay)
|
||||
return ..()
|
||||
|
||||
/// Status effect from multiple sources, when all sources are removed, so is the effect
|
||||
/datum/status_effect/grouped
|
||||
status_type = STATUS_EFFECT_MULTIPLE //! Adds itself to sources and destroys itself if one exists already, there are never multiple
|
||||
var/list/sources = list()
|
||||
|
||||
/datum/status_effect/grouped/on_creation(mob/living/new_owner, source)
|
||||
var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type)
|
||||
if(existing)
|
||||
existing.sources |= source
|
||||
qdel(src)
|
||||
return FALSE
|
||||
else
|
||||
sources |= source
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/grouped/before_remove(source)
|
||||
sources -= source
|
||||
return !length(sources)
|
||||
|
||||
@@ -1,49 +1,96 @@
|
||||
//The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
|
||||
/**
|
||||
* Causes weather to occur on a z level in certain area types
|
||||
*
|
||||
* The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
|
||||
* Weather always occurs on different z levels at different times, regardless of weather type.
|
||||
* Can have custom durations, targets, and can automatically protect indoor areas.
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/weather
|
||||
/// name of weather
|
||||
var/name = "space wind"
|
||||
/// description of weather
|
||||
var/desc = "Heavy gusts of wind blanket the area, periodically knocking down anyone caught in the open."
|
||||
|
||||
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>" //The message displayed in chat to foreshadow the weather's beginning
|
||||
var/telegraph_duration = 300 //In deciseconds, how long from the beginning of the telegraph until the weather begins
|
||||
var/telegraph_sound //The sound file played to everyone on an affected z-level
|
||||
var/telegraph_overlay //The overlay applied to all tiles on the z-level
|
||||
/// The message displayed in chat to foreshadow the weather's beginning
|
||||
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>"
|
||||
|
||||
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>" //Displayed in chat once the weather begins in earnest
|
||||
var/weather_duration = 1200 //In deciseconds, how long the weather lasts once it begins
|
||||
var/weather_duration_lower = 1200 //See above - this is the lowest possible duration
|
||||
var/weather_duration_upper = 1500 //See above - this is the highest possible duration
|
||||
/// In deciseconds, how long from the beginning of the telegraph until the weather begins
|
||||
var/telegraph_duration = 300
|
||||
/// The sound file played to everyone on an affected z-level
|
||||
var/telegraph_sound
|
||||
/// The overlay applied to all tiles on the z-level
|
||||
var/telegraph_overlay
|
||||
/// Displayed in chat once the weather begins in earnest
|
||||
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>"
|
||||
///In deciseconds, how long the weather lasts once it begins
|
||||
var/weather_duration = 1200
|
||||
///See above - this is the lowest possible duration
|
||||
var/weather_duration_lower = 1200
|
||||
///See above - this is the highest possible duration
|
||||
var/weather_duration_upper = 1500
|
||||
/// Looping sound while weather is occuring
|
||||
var/weather_sound
|
||||
/// Area overlay while the weather is occuring
|
||||
var/weather_overlay
|
||||
/// Color to apply to the area while weather is occuring
|
||||
var/weather_color = null
|
||||
|
||||
var/end_message = "<span class='danger'>The wind relents its assault.</span>" //Displayed once the weather is over
|
||||
var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
|
||||
/// Displayed once the weather is over
|
||||
var/end_message = "<span class='danger'>The wind relents its assault.</span>"
|
||||
/// In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
|
||||
var/end_duration = 300
|
||||
/// Sound that plays while weather is ending
|
||||
var/end_sound
|
||||
/// Area overlay while weather is ending
|
||||
var/end_overlay
|
||||
|
||||
var/area_type = /area/space //Types of area to affect
|
||||
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
|
||||
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
|
||||
var/impacted_z_levels // The list of z-levels that this weather is actively affecting
|
||||
/// Types of area to affect
|
||||
var/area_type = /area/space
|
||||
/// TRUE value protects areas with outdoors marked as false, regardless of area type
|
||||
var/protect_indoors = FALSE
|
||||
/// Areas to be affected by the weather, calculated when the weather begins
|
||||
var/list/impacted_areas = list()
|
||||
|
||||
var/overlay_layer = AREA_LAYER //Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
|
||||
var/aesthetic = FALSE //If the weather has no purpose other than looks
|
||||
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
|
||||
/// Areas that are protected and excluded from the affected areas.
|
||||
var/list/protected_areas = list()
|
||||
/// The list of z-levels that this weather is actively affecting
|
||||
var/impacted_z_levels
|
||||
|
||||
var/stage = END_STAGE //The stage of the weather, from 1-4
|
||||
/// Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
|
||||
var/overlay_layer = AREA_LAYER
|
||||
/// Plane for the overlay
|
||||
var/overlay_plane = BLACKNESS_PLANE
|
||||
/// If the weather has no purpose but aesthetics.
|
||||
var/aesthetic = FALSE
|
||||
/// Used by mobs to prevent them from being affected by the weather
|
||||
var/immunity_type = "storm"
|
||||
|
||||
// These are read by the weather subsystem and used to determine when and where to run the weather.
|
||||
var/probability = 0 // Weight amongst other eligible weather. If zero, will never happen randomly.
|
||||
var/target_trait = ZTRAIT_STATION // The z-level trait to affect when run randomly or when not overridden.
|
||||
/// The stage of the weather, from 1-4
|
||||
var/stage = END_STAGE
|
||||
|
||||
/// Weight amongst other eligible weather. if zero, will never happen randomly.
|
||||
var/probability = 0
|
||||
/// The z-level trait to affect when run randomly or when not overridden.
|
||||
var/target_trait = ZTRAIT_STATION
|
||||
|
||||
/// Whether a barometer can predict when the weather will happen
|
||||
var/barometer_predictable = FALSE
|
||||
var/next_hit_time = 0 //For barometers to know when the next storm will hit
|
||||
/// For barometers to know when the next storm will hit
|
||||
var/next_hit_time = 0
|
||||
|
||||
/datum/weather/New(z_levels)
|
||||
..()
|
||||
impacted_z_levels = z_levels
|
||||
|
||||
/**
|
||||
* Telegraphs the beginning of the weather on the impacted z levels
|
||||
*
|
||||
* Sends sounds and details to mobs in the area
|
||||
* Calculates duration and hit areas, and makes a callback for the actual weather to start
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/telegraph()
|
||||
if(stage == STARTUP_STAGE)
|
||||
return
|
||||
@@ -58,6 +105,8 @@
|
||||
affectareas -= get_areas(V)
|
||||
for(var/V in affectareas)
|
||||
var/area/A = V
|
||||
if(protect_indoors && !A.outdoors)
|
||||
continue
|
||||
if(A.z in impacted_z_levels)
|
||||
impacted_areas |= A
|
||||
weather_duration = rand(weather_duration_lower, weather_duration_upper)
|
||||
@@ -72,6 +121,13 @@
|
||||
SEND_SOUND(M, sound(telegraph_sound))
|
||||
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
|
||||
|
||||
/**
|
||||
* Starts the actual weather and effects from it
|
||||
*
|
||||
* Updates area overlays and sends sounds and messages to mobs to notify them
|
||||
* Begins dealing effects from weather to mobs in the area
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/start()
|
||||
if(stage >= MAIN_STAGE)
|
||||
return
|
||||
@@ -86,6 +142,13 @@
|
||||
SEND_SOUND(M, sound(weather_sound))
|
||||
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
|
||||
|
||||
/**
|
||||
* Weather enters the winding down phase, stops effects
|
||||
*
|
||||
* Updates areas to be in the winding down phase
|
||||
* Sends sounds and messages to mobs to notify them
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/wind_down()
|
||||
if(stage >= WIND_DOWN_STAGE)
|
||||
return
|
||||
@@ -100,6 +163,13 @@
|
||||
SEND_SOUND(M, sound(end_sound))
|
||||
addtimer(CALLBACK(src, .proc/end), end_duration)
|
||||
|
||||
/**
|
||||
* Fully ends the weather
|
||||
*
|
||||
* Effects no longer occur and area overlays are removed
|
||||
* Removes weather from processing completely
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/end()
|
||||
if(stage == END_STAGE)
|
||||
return 1
|
||||
@@ -115,7 +185,11 @@
|
||||
if(can_weather_act(L))
|
||||
weather_act(L)
|
||||
|
||||
/datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob?
|
||||
/**
|
||||
* Returns TRUE if the living mob can be affected by the weather
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/can_weather_act(mob/living/L)
|
||||
var/turf/mob_turf = get_turf(L)
|
||||
if(mob_turf && !(mob_turf.z in impacted_z_levels))
|
||||
return
|
||||
@@ -123,11 +197,19 @@
|
||||
return
|
||||
if(!(get_area(L) in impacted_areas))
|
||||
return
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/weather/proc/weather_act(mob/living/L) //What effect does this weather have on the hapless mob?
|
||||
/**
|
||||
* Affects the mob with whatever the weather does
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/weather_act(mob/living/L)
|
||||
return
|
||||
|
||||
/**
|
||||
* Updates the overlays on impacted areas
|
||||
*
|
||||
*/
|
||||
/datum/weather/proc/update_areas()
|
||||
for(var/V in impacted_areas)
|
||||
var/area/N = V
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
end_message = "<span class='boldannounce'>The downpour gradually slows to a light shower. It should be safe outside now.</span>"
|
||||
end_sound = 'sound/ambience/acidrain_end.ogg'
|
||||
|
||||
area_type = /area/lavaland/surface/outdoors
|
||||
target_trait = ZTRAIT_MINING
|
||||
area_type = /area
|
||||
protect_indoors = TRUE
|
||||
target_trait = ZTRAIT_ACIDRAIN
|
||||
|
||||
immunity_type = "acid" // temp
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
end_duration = 300
|
||||
end_overlay = "light_ash"
|
||||
|
||||
area_type = /area/lavaland/surface/outdoors
|
||||
target_trait = ZTRAIT_MINING
|
||||
area_type = /area
|
||||
protect_indoors = TRUE
|
||||
target_trait = ZTRAIT_ASHSTORM
|
||||
|
||||
immunity_type = "ash"
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
end_duration = 100
|
||||
end_message = "<span class='boldannounce'>The snowfall dies down, it should be safe to go outside again.</span>"
|
||||
|
||||
area_type = /area/awaymission/snowdin/outside
|
||||
target_trait = ZTRAIT_AWAY
|
||||
area_type = /area
|
||||
protect_indoors = TRUE
|
||||
target_trait = ZTRAIT_SNOWSTORM
|
||||
|
||||
immunity_type = "snow"
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -11,13 +11,27 @@
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
invisibility = INVISIBILITY_LIGHTING
|
||||
|
||||
var/map_name // Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
|
||||
/// Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
|
||||
var/map_name
|
||||
|
||||
var/valid_territory = TRUE // If it's a valid territory for gangs to claim
|
||||
var/blob_allowed = TRUE // Does it count for blobs score? By default, all areas count.
|
||||
var/clockwork_warp_allowed = TRUE // Can servants warp into this area from Reebe?
|
||||
/// If it's valid territory for gangs/cults to summon
|
||||
var/valid_territory = TRUE
|
||||
/// if blobs can spawn there and if it counts towards their score.
|
||||
var/blob_allowed = TRUE
|
||||
/// whether servants can warp into this area from Reebe
|
||||
var/clockwork_warp_allowed = TRUE
|
||||
/// Message to display when the clockwork warp fails
|
||||
var/clockwork_warp_fail = "The structure there is too dense for warping to pierce. (This is normal in high-security areas.)"
|
||||
|
||||
/// If mining tunnel generation is allowed in this area
|
||||
var/tunnel_allowed = FALSE
|
||||
/// If flora are allowed to spawn in this area randomly through tunnel generation
|
||||
var/flora_allowed = FALSE
|
||||
/// if mobs can be spawned by natural random generation
|
||||
var/mob_spawn_allowed = FALSE
|
||||
/// If megafauna can be spawned by natural random generation
|
||||
var/megafauna_spawn_allowed = FALSE
|
||||
|
||||
var/fire = null
|
||||
var/atmos = TRUE
|
||||
var/atmosalm = FALSE
|
||||
@@ -25,11 +39,14 @@
|
||||
var/lightswitch = TRUE
|
||||
|
||||
var/requires_power = TRUE
|
||||
var/always_unpowered = FALSE // This gets overridden to 1 for space in area/Initialize().
|
||||
/// This gets overridden to 1 for space in area/Initialize().
|
||||
var/always_unpowered = FALSE
|
||||
|
||||
var/outdoors = FALSE //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
|
||||
/// For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
|
||||
var/outdoors = FALSE
|
||||
|
||||
var/areasize = 0 //Size of the area in open turfs, only calculated for indoors areas.
|
||||
/// Size of the area in open turfs, only calculated for indoors areas.
|
||||
var/areasize = 0
|
||||
|
||||
var/power_equip = TRUE
|
||||
var/power_light = TRUE
|
||||
@@ -43,9 +60,12 @@
|
||||
var/static_environ
|
||||
|
||||
var/has_gravity = 0
|
||||
var/noteleport = FALSE //Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
|
||||
var/hidden = FALSE //Hides area from player Teleport function.
|
||||
var/safe = FALSE //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
|
||||
/// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
|
||||
var/noteleport = FALSE
|
||||
/// Hides area from player Teleport function.
|
||||
var/hidden = FALSE
|
||||
/// Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
|
||||
var/safe = FALSE
|
||||
/// If false, loading multiple maps with this area type will create multiple instances.
|
||||
var/unique = TRUE
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/area/mine
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flora_allowed = TRUE
|
||||
|
||||
/area/mine/explored
|
||||
name = "Mine"
|
||||
@@ -17,6 +18,7 @@
|
||||
outdoors = TRUE
|
||||
flags_1 = NONE
|
||||
ambientsounds = MINING
|
||||
flora_allowed = FALSE
|
||||
|
||||
/area/mine/unexplored
|
||||
name = "Mine"
|
||||
@@ -31,6 +33,7 @@
|
||||
outdoors = TRUE
|
||||
flags_1 = NONE
|
||||
ambientsounds = MINING
|
||||
tunnel_allowed = TRUE
|
||||
|
||||
/area/mine/lobby
|
||||
name = "Mining Station"
|
||||
@@ -82,6 +85,7 @@
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
flora_allowed = TRUE
|
||||
|
||||
/area/lavaland/surface
|
||||
name = "Lavaland"
|
||||
@@ -114,9 +118,79 @@
|
||||
|
||||
/area/lavaland/surface/outdoors/unexplored //monsters and ruins spawn here
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
|
||||
/area/lavaland/surface/outdoors/unexplored/danger //megafauna will also spawn here
|
||||
icon_state = "danger"
|
||||
megafauna_spawn_allowed = TRUE
|
||||
|
||||
/area/lavaland/surface/outdoors/explored
|
||||
name = "Lavaland Labor Camp"
|
||||
flora_allowed = FALSE
|
||||
|
||||
|
||||
|
||||
/**********************Ice Moon Areas**************************/
|
||||
|
||||
/area/icemoon
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
flora_allowed = TRUE
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/icemoon/surface
|
||||
name = "Icemoon"
|
||||
icon_state = "explored"
|
||||
always_unpowered = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
requires_power = TRUE
|
||||
ambientsounds = MINING
|
||||
|
||||
/area/icemoon/underground
|
||||
name = "Icemoon Caves"
|
||||
outdoors = TRUE
|
||||
always_unpowered = TRUE
|
||||
requires_power = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
ambientsounds = MINING
|
||||
|
||||
/area/icemoon/underground/unexplored // mobs and megafauna and ruins spawn here
|
||||
name = "Icemoon Caves"
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
megafauna_spawn_allowed = TRUE
|
||||
|
||||
/area/icemoon/underground/unexplored/rivers // rivers spawn here
|
||||
icon_state = "danger"
|
||||
|
||||
/area/icemoon/underground/explored
|
||||
name = "Icemoon Underground"
|
||||
flora_allowed = FALSE
|
||||
|
||||
/area/icemoon/surface/outdoors
|
||||
name = "Icemoon Wastes"
|
||||
outdoors = TRUE
|
||||
|
||||
/area/icemoon/surface/outdoors/labor_camp
|
||||
name = "Icemoon Labor Camp"
|
||||
flora_allowed = FALSE
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored //monsters and ruins spawn here
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers // rivers spawn here
|
||||
icon_state = "danger"
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters
|
||||
mob_spawn_allowed = FALSE
|
||||
|
||||
9
code/game/area/areas/ruins/icemoon.dm
Normal file
9
code/game/area/areas/ruins/icemoon.dm
Normal file
@@ -0,0 +1,9 @@
|
||||
// Icemoon Ruins
|
||||
|
||||
/area/ruin/unpowered/buried_library
|
||||
name = "Buried Library"
|
||||
icon_state = "dk_yellow"
|
||||
|
||||
/area/ruin/powered/bathhouse
|
||||
name = "Bath House"
|
||||
icon_state = "dk_yellow"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user