Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into radiationsuitsareugly

# Conflicts:
#	icons/mob/clothing/hands.dmi
#	icons/mob/clothing/head.dmi
#	icons/obj/clothing/gloves.dmi
#	icons/obj/clothing/hats.dmi
This commit is contained in:
zerothebigboy
2020-07-22 01:03:55 -04:00
1565 changed files with 47759 additions and 50316 deletions
+3 -1
View File
@@ -108,6 +108,8 @@
#define TR_KEEPSE (1<<5) // changelings shouldn't edit the DNA's SE when turning into a monkey
#define TR_DEFAULTMSG (1<<6)
#define TR_KEEPORGANS (1<<8)
#define TR_KEEPREAGENTS (1<<10)
#define TR_KEEPSTUNS (1<<9)
#define CLONER_FRESH_CLONE "fresh"
@@ -184,4 +186,4 @@
#define G_MALE 1
#define G_FEMALE 2
#define G_PLURAL 3
#define G_NEUTER 4
#define G_NEUTER 4
+4
View File
@@ -142,6 +142,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
/// The attack is from a parry counterattack.
#define ATTACKCHAIN_PARRY_COUNTERATTACK (1<<0)
// UnarmedAttack() flags
/// Attack is from a parry counterattack
#define UNARMED_ATTACK_PARRY (1<<0)
/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
/// If the thing can reflect matter (bullets/bomb shrapnel)
+2
View File
@@ -74,6 +74,8 @@
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
#define ADMIN_PUNISHMENT_PIE "Cream Pie"
#define ADMIN_PUNISHMENT_CUSTOM_PIE "Custom Cream Pie"
#define ADMIN_PUNISHMENT_PICKLE "Pickle-ify"
#define ADMIN_PUNISHMENT_FRY "Fry"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
+14 -12
View File
@@ -136,7 +136,7 @@
#define TANK_FRAGMENT_SCALE (6.*ONE_ATMOSPHERE) //+1 for each SCALE kPa aboe threshold
#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
#define TANK_MIN_RELEASE_PRESSURE 0
#define TANK_DEFAULT_RELEASE_PRESSURE 16
#define TANK_DEFAULT_RELEASE_PRESSURE 17
//CANATMOSPASS
#define ATMOS_PASS_YES 1
@@ -270,16 +270,9 @@
T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;
#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
#define QUANTIZE(variable) (round(variable,0.0000001))/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that
once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
//prefer this to gas_mixture/total_moles in performance critical areas
#define TOTAL_MOLES(cached_gases, out_var)\
out_var = 0;\
for(var/total_moles_id in cached_gases){\
out_var += cached_gases[total_moles_id];\
}
#ifdef TESTING
GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
@@ -288,6 +281,19 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
#define CALCULATE_ADJACENT_TURFS(T) SSadjacent_air.queue[T] = 1
#endif
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
GLOBAL_VAR(atmos_extools_initialized) // this must be an uninitialized (null) one or init_monstermos will be called twice because reasons
#define ATMOS_EXTOOLS_CHECK if(!GLOB.atmos_extools_initialized){\
GLOB.atmos_extools_initialized=TRUE;\
if(fexists(EXTOOLS)){\
var/result = call(EXTOOLS,"init_monstermos")();\
if(result != "ok") {CRASH(result);}\
} else {\
CRASH("[EXTOOLS] does not exist!");\
}\
}
//Unomos - So for whatever reason, garbage collection actually drastically decreases the cost of atmos later in the round. Turning this into a define yields massively improved performance.
#define GAS_GARBAGE_COLLECT(GASGASGAS)\
var/list/CACHE_GAS = GASGASGAS;\
@@ -296,10 +302,6 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
CACHE_GAS -= id;\
}
#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),
+4
View File
@@ -0,0 +1,4 @@
// Reaction priorities, higher makes it checked first. Otherwise, it goes based on reaction temperature requirements.
#define CHEMICAL_REACTION_PRIORITY_DEFAULT 100
#define CHEMICAL_REACTION_PRIORITY_SMOKE 1000
+8 -1
View File
@@ -269,11 +269,12 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
//stamina cost defines.
#define STAM_COST_ATTACK_OBJ_MULT 1.2
#define STAM_COST_ATTACK_MOB_MULT 0.8
#define STAM_COST_ATTACK_MOB_MULT 1
#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
#define STAM_COST_THROW_MOB 2.5 //multiplied by (mob size + 1)^2.
///Multiplier of the (STAMINA_NEAR_CRIT - user current stamina loss) : (STAMINA_NEAR_CRIT - STAMINA_SOFTCRIT) ratio used in damage penalties when stam soft-critted.
#define STAM_CRIT_ITEM_ATTACK_PENALTY 0.66
@@ -284,6 +285,12 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
#define STAM_CRIT_GUN_DELAY 2.75
//stamina recovery defines. Blocked if combat mode is on.
#define STAM_RECOVERY_STAM_CRIT -7.5
#define STAM_RECOVERY_RESTING -6
#define STAM_RECOVERY_NORMAL -3
#define STAM_RECOVERY_LIMB 4 //limbs recover stamina separately from handle_status_effects(), and aren't blocked by combat mode.
/**
* should the current-attack-damage be lower than the item force multiplied by this value,
* a "inefficiently" prefix will be added to the message.
+9
View File
@@ -8,3 +8,12 @@
//flags
#define CONFIG_ENTRY_LOCKED 1 //can't edit
#define CONFIG_ENTRY_HIDDEN 2 //can't see value
// Policy config keys
// MAKE SURE THESE ARE UPPERCASE
/// Displayed to cloned patients
#define POLICYCONFIG_ON_CLONE "ON_CLONE"
/// Displayed to defibbed/revival surgery'd patients before the memory loss time threshold
#define POLICYCONFIG_ON_DEFIB_INTACT "ON_DEFIB_INTACT"
/// Displayed to defibbed/revival surgery'd patients after the memory loss time threshold
#define POLICYCONFIG_ON_DEFIB_LATE "ON_DEFIB_LATE"
+71
View File
@@ -0,0 +1,71 @@
//// COOLDOWN SYSTEMS
/*
* We have 2 cooldown systems: timer cooldowns (divided between stoppable and regular) and world.time cooldowns.
*
* When to use each?
*
* * Adding a commonly-checked cooldown, like on a subsystem to check for processing
* * * Use the world.time ones, as they are cheaper.
*
* * Adding a rarely-used one for special situations, such as giving an uncommon item a cooldown on a target.
* * * Timer cooldown, as adding a new variable on each mob to track the cooldown of said uncommon item is going too far.
*
* * Triggering events at the end of a cooldown.
* * * Timer cooldown, registering to its signal.
*
* * Being able to check how long left for the cooldown to end.
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
*
* * Being able to stop the timer before it ends.
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
*/
/*
* Cooldown system based on an datum-level associative lazylist using timers.
*/
//INDEXES
#define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet"
//TIMER COOLDOWN MACROS
#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]"
#define COMSIG_CD_RESET(cd_index) "cd_reset_[cd_index]"
#define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time))
#define TIMER_COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index)
#define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index)
/*
* Stoppable timer cooldowns.
* Use indexes the same as the regular tiemr cooldowns.
* They make use of the TIMER_COOLDOWN_CHECK() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one.
* A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked.
*/
#define S_TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time, TIMER_STOPPABLE))
#define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index)
#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_index)))
/*
* Cooldown system based on storing world.time on a variable, plus the cooldown time.
* Better performance over timer cooldowns, lower control. Same functionality.
*/
#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0
#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + cd_time)
//Returns true if the cooldown has run its course, false otherwise
#define COOLDOWN_FINISHED(cd_source, cd_index) (cd_source.cd_index < world.time)
#define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0
#define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time))
+30 -5
View File
@@ -32,17 +32,21 @@
#define COMSIG_ELEMENT_DETACH "element_detach"
// /atom signals
//from base of atom/proc/Initialize(): sent any time a new atom is created
#define COMSIG_ATOM_CREATED "atom_created"
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/animal_attack(): (/mob/user)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, list/examine_return_text)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
///from base of atom/get_examine_name(): (/mob, list/overrides)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name"
#define COMSIG_PARENT_EXAMINE_MORE "atom_examine_more" ///from base of atom/examine_more(): (/mob)
//Positions for overrides list
#define EXAMINE_POSITION_ARTICLE 1
#define EXAMINE_POSITION_BEFORE 2
#define EXAMINE_POSITION_ARTICLE (1<<0)
#define EXAMINE_POSITION_BEFORE (1<<1)
//End positions
#define COMPONENT_EXNAME_CHANGED 1
#define COMPONENT_EXNAME_CHANGED (1<<0)
#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon" //from base of atom/update_icon(): ()
#define COMSIG_ATOM_NO_UPDATE_ICON_STATE 1
#define COMSIG_ATOM_NO_UPDATE_OVERLAYS 2
@@ -179,6 +183,10 @@
#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
#define COMSIG_MOB_KEY_CHANGE "mob_key_change" //from base of /mob/transfer_ckey(): (new_character, old_character)
#define COMSIG_MOB_PRE_PLAYER_CHANGE "mob_pre_player_change" //sent to the target mob from base of /mob/transfer_ckey() and /mind/transfer_to(): (our_character, their_character)
///from /mob/living/handle_eye_contact(): (mob/living/other_mob)
#define COMSIG_MOB_EYECONTACT "mob_eyecontact"
/// return this if you want to block printing this message to this person, if you want to print your own (does not affect the other person's message)
#define COMSIG_BLOCK_EYECONTACT (1<<0)
// #define COMPONENT_STOP_MIND_TRANSFER 1
#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): ()
#define COMSIG_MOB_ON_NEW_MIND "mob_on_new_mind" //called when a new mind is assigned to a mob: ()
@@ -198,6 +206,8 @@
#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" //from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" //from base of mob/swap_hand(): (obj/item)
#define COMPONENT_BLOCK_SWAP 1
// /client signals
#define COMSIG_MOB_CLIENT_LOGIN "mob_client_login" //sent when a mob/login() finishes: (client)
@@ -222,6 +232,11 @@
#define COMSIG_LIVING_RUN_BLOCK "living_do_run_block" //from base of mob/living/do_run_block(): (real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone)
#define COMSIG_LIVING_GET_BLOCKING_ITEMS "get_blocking_items" //from base of mob/living/get_blocking_items(): (list/items)
#define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items)
#define COMPONENT_PREVENT_BLOCK_START 1
#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items)
#define COMPONENT_PREVENT_PARRY_START 1
//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
#define COMSIG_LIVING_STATUS_STUN "living_stun" //from base of mob/living/Stun() (amount, update, ignore)
#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown" //from base of mob/living/Knockdown() (amount, update, ignore)
@@ -283,7 +298,12 @@
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act" //from base of item/sharpener/attackby(): (amount, max)
#define COMPONENT_BLOCK_SHARPEN_APPLIED 1
#define COMPONENT_BLOCK_SHARPEN_BLOCKED 2
#define COMPONENT_BLOCK_SHARPEN_ALREADY 4
#define COMPONENT_BLOCK_SHARPEN_MAXED 8
#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
@@ -419,6 +439,11 @@
#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory" //(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip" //(obj/item/insertion_candidate, mob/user, silent) - returns bool
// /datum/component/two_handed signals
#define COMSIG_TWOHANDED_WIELD "twohanded_wield" //from base of datum/component/two_handed/proc/wield(mob/living/carbon/user): (/mob/user)
#define COMPONENT_TWOHANDED_BLOCK_WIELD 1
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield" //from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
// /datum/action signals
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
+1 -1
View File
@@ -216,7 +216,7 @@ GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
#define isgun(A) (istype(A, /obj/item/gun))
#define isfood(A) (istype(A, /obj/item/reagent_containers/food))
#define isfood(A) (istype(A, /obj/item/reagent_containers/food/snacks))
//Assemblies
#define isassembly(O) (istype(O, /obj/item/assembly))
+1
View File
@@ -38,6 +38,7 @@
#define LOG_ADMIN_PRIVATE (1 << 14)
#define LOG_ASAY (1 << 15)
#define LOG_VIRUS (1 << 16)
#define LOG_SHUTTLE (1 << 18)
//Individual logging panel pages
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK)
+4
View File
@@ -115,3 +115,7 @@
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
#define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1)
#define CLONEPOD_GET_MIND 1
#define CLONEPOD_POLL_MIND 2
#define CLONEPOD_NO_MIND 3
+3 -1
View File
@@ -462,7 +462,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")
// list of all null rod weapons
#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/twohanded/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/clothing/gloves/fingerless/pugilist/chaplain, /obj/item/melee/baseball_bat/chaplain
#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/clothing/gloves/fingerless/pugilist/chaplain, /obj/item/melee/baseball_bat/chaplain
// Used by PDA and cartridge code to reduce repetitiveness of spritesheets
#define PDAIMG(what) {"<span class="pda16x16 [#what]"></span>"}
@@ -534,3 +534,5 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define LOOT_RESTRICTION_CKEY 2
#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile.
#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem
#define WANTED_FILE "wanted_message.json"
+6
View File
@@ -310,3 +310,9 @@
#define FOV_90_DEGREES 90
#define FOV_180_DEGREES 180
#define FOV_270_DEGREES 270
/// How far away you can be to make eye contact with someone while examining
#define EYE_CONTACT_RANGE 5
/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
#define EXAMINE_MORE_TIME 1 SECONDS
+2 -4
View File
@@ -6,7 +6,7 @@
#define RUSTG_JOB_ERROR "JOB PANICKED"
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data)
#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data)
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
@@ -14,14 +14,12 @@
#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
// RUST-G defines & procs for HTTP component
#define RUSTG_HTTP_METHOD_GET "get"
#define RUSTG_HTTP_METHOD_POST "post"
#define RUSTG_HTTP_METHOD_PUT "put"
#define RUSTG_HTTP_METHOD_DELETE "delete"
#define RUSTG_HTTP_METHOD_PATCH "patch"
#define RUSTG_HTTP_METHOD_HEAD "head"
#define RUSTG_HTTP_METHOD_POST "post"
#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
+7 -6
View File
@@ -8,12 +8,6 @@
/// 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
@@ -26,6 +20,13 @@
#define DEF_SKILL_GAIN 1
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
#define STD_USE_TOOL_MULT 1
#define EASY_USE_TOOL_MULT 0.75
#define TRIVIAL_USE_TOOL_MULT 0.5
#define BARE_USE_TOOL_MULT 0.25
//multiplier of the difference of max_value and min_value. Mostly for balance purposes between numerical and level-based skills.
#define STD_NUM_SKILL_ITEM_GAIN_MULTI 0.002
//An extra point for each few seconds of delay when using a tool. Before the multiplier.
#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS
+2 -3
View File
@@ -29,6 +29,5 @@
#endif
/world/proc/enable_debugger()
var/dll = world.GetConfig("env", "EXTOOLS_DLL")
if (dll)
call(dll, "debug_initialize")()
if (fexists(EXTOOLS))
call(EXTOOLS, "debug_initialize")()
+7 -6
View File
@@ -137,12 +137,13 @@
// 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 SSAIR_EXCITEDGROUPS 3
#define SSAIR_HIGHPRESSURE 4
#define SSAIR_HOTSPOTS 5
#define SSAIR_SUPERCONDUCTIVITY 6
#define SSAIR_REBUILD_PIPENETS 7
#define SSAIR_EQUALIZE 8
#define SSAIR_ACTIVETURFS 9
#define COMPILE_OVERLAYS(A)\
if (TRUE) {\
+7
View File
@@ -76,6 +76,13 @@
#define VV_HK_ADDCOMPONENT "addcomponent"
#define VV_HK_MODIFY_TRAITS "modtraits"
// /datum/gas_mixture
#define VV_HK_SET_MOLES "set_moles"
#define VV_HK_EMPTY "empty"
#define VV_HK_SET_TEMPERATURE "set_temp"
#define VV_HK_PARSE_GASSTRING "parse_gasstring"
#define VV_HK_SET_VOLUME "set_volume"
// /atom
#define VV_HK_MODIFY_TRANSFORM "atom_transform"
#define VV_HK_ADD_REAGENT "addreagent"
+7
View File
@@ -118,6 +118,9 @@
//reusing the PDA option because I really don't think news comments are worth a config option
WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]")
/proc/log_paper(text)
WRITE_LOG(GLOB.world_paper_log, "PAPER: [text]")
/proc/log_telecomms(text)
if (CONFIG_GET(flag/log_telecomms))
WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]")
@@ -131,6 +134,10 @@
if (CONFIG_GET(flag/log_vote))
WRITE_LOG(GLOB.world_game_log, "VOTE: [text]")
/proc/log_shuttle(text)
if (CONFIG_GET(flag/log_shuttle))
WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [text]")
/proc/log_craft(text)
if (CONFIG_GET(flag/log_craft))
WRITE_LOG(GLOB.world_crafting_log, "CRAFT: [text]")
+1
View File
@@ -1,4 +1,5 @@
#define pick_list(FILE, KEY) (pick(strings(FILE, KEY)))
#define pick_list_weighted(FILE, KEY) (pickweight(strings(FILE, KEY)))
#define pick_list_replacements(FILE, KEY) (strings_replacement(FILE, KEY))
#define json_load(FILE) (json_decode(file2text(FILE)))
+8
View File
@@ -125,3 +125,11 @@ GLOBAL_VAR_INIT(cmp_field, "name")
if(A.ui_category == B.ui_category)
return sorttext(A.name, B.name)
return sorttext(A.ui_category, B.ui_category)
/proc/cmp_chemical_reactions_default(datum/chemical_reaction/A, datum/chemical_reaction/B)
if(A.priority != B.priority)
return B.priority - A.priority
else if(A.is_cold_recipe)
return A.required_temp - B.required_temp //return coldest
else
return B.required_temp - A.required_temp //return hottest
+2 -1
View File
@@ -5,8 +5,9 @@
#define GET_INITIALIZED_MUTATION(A) GLOB.all_mutations[A]
#define GET_GENE_STRING(A, B) (B.mutation_index[A])
#define GET_SEQUENCE(A) (GLOB.full_sequences[A])
#define GET_MUTATION_TYPE_FROM_ALIAS(A) (GLOB.alias_mutations[A])
#define GET_MUTATION_STABILIZER(A) ((A.stabilizer_coeff < 0) ? 1 : A.stabilizer_coeff)
#define GET_MUTATION_SYNCHRONIZER(A) ((A.synchronizer_coeff < 0) ? 1 : A.synchronizer_coeff)
#define GET_MUTATION_POWER(A) ((A.power_coeff < 0) ? 1 : A.power_coeff)
#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff)
#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff)
+21
View File
@@ -53,6 +53,27 @@
for(var/I in adjacent_turfs)
. |= get_area(I)
/**
* Get a bounding box of a list of atoms.
*
* Arguments:
* - atoms - List of atoms. Can accept output of view() and range() procs.
*
* Returns: list(x1, y1, x2, y2)
*/
/proc/get_bbox_of_atoms(list/atoms)
var/list/list_x = list()
var/list/list_y = list()
for(var/_a in atoms)
var/atom/a = _a
list_x += a.x
list_y += a.y
return list(
min(list_x),
min(list_y),
max(list_x),
max(list_y))
// Like view but bypasses luminosity check
/proc/get_hear(range, atom/source)
-22
View File
@@ -90,7 +90,6 @@
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.
@@ -117,24 +116,3 @@
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
+6 -4
View File
@@ -1136,9 +1136,10 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
if (!isicon(I))
if (isfile(thing)) //special snowflake
var/name = sanitize_filename("[generate_asset_name(thing)].png")
register_asset(name, thing)
if(!SSassets.cache[name])
register_asset(name, thing)
for (var/thing2 in targets)
send_asset(thing2, key, FALSE)
send_asset(thing2, key)
return "<img class='icon icon-misc' src=\"[url_encode(name)]\">"
var/atom/A = thing
if (isnull(dir))
@@ -1160,9 +1161,10 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
I = icon(I, icon_state, dir, frame, moving)
key = "[generate_asset_name(I)].png"
register_asset(key, I)
if(!SSassets.cache[key])
register_asset(key, I)
for (var/thing2 in targets)
send_asset(thing2, key, FALSE)
send_asset(thing2, key)
return "<img class='icon icon-[icon_state]' src=\"[url_encode(key)]\">"
+2 -1
View File
@@ -1437,7 +1437,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/obj/item/reagent_containers/food/snacks/grown,
/obj/item/reagent_containers/food/snacks/grown/mushroom,
/obj/item/reagent_containers/food/snacks/grown/nettle, // base type
/obj/item/reagent_containers/food/snacks/deepfryholder,
/obj/item/reagent_containers/food/snacks/grown/shell,
/obj/item/reagent_containers/food/snacks/clothing,
/obj/item/reagent_containers/food/snacks/store/bread
@@ -1509,6 +1508,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
set waitfor = FALSE
return call(source, proctype)(arglist(arguments))
#define TURF_FROM_COORDS_LIST(List) (locate(List[1], List[2], List[3]))
/proc/num2sign(numeric)
if(numeric > 0)
return 1
+2 -1
View File
@@ -27,5 +27,6 @@ GLOBAL_LIST_EMPTY(full_sequences)
GLOBAL_LIST_EMPTY(bad_mutations)
GLOBAL_LIST_EMPTY(good_mutations)
GLOBAL_LIST_EMPTY(not_good_mutations)
GLOBAL_LIST_EMPTY(alias_mutations) //alias = type
GLOBAL_LIST_EMPTY(mutation_recipes)
GLOBAL_LIST_EMPTY(mutation_recipes)
+7 -6
View File
@@ -116,15 +116,16 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
//Backpacks
#define GBACKPACK "Grey Backpack"
#define GSATCHEL "Grey Satchel"
#define GDUFFELBAG "Grey Duffel Bag"
#define LSATCHEL "Leather Satchel"
//Backpacks
#define DBACKPACK "Department Backpack"
#define DSATCHEL "Department Satchel"
#define DDUFFELBAG "Department Duffel Bag"
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, GBACKPACK, GSATCHEL, GDUFFELBAG, LSATCHEL))
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, //everything after this point is a non-department backpack
"Grey Backpack" = /obj/item/storage/backpack,
"Grey Satchel" = /obj/item/storage/backpack/satchel,
"Grey Duffel Bag" = /obj/item/storage/backpack/duffelbag,
"Leather Satchel" = /obj/item/storage/backpack/satchel/leather,
"Snail Shell" = /obj/item/storage/backpack/snail))
//Suit/Skirt
#define PREF_SUIT "Jumpsuit"
+1 -2
View File
@@ -38,8 +38,7 @@ GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here
GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here
GLOBAL_LIST_EMPTY(ruin_landmarks)
//away missions
GLOBAL_LIST_EMPTY(awaydestinations) //a list of landmarks that the warpgate can take you to
//away missions
GLOBAL_LIST_EMPTY(vr_spawnpoints)
//used by jump-to-area etc. Updated by area/updateName()
+1
View File
@@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game a
GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtypes
GLOBAL_LIST_EMPTY(carbon_list) //all instances of /mob/living/carbon and subtypes, notably does not contain brains or simple animals
GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and subtypes
GLOBAL_LIST_EMPTY(ai_list)
GLOBAL_LIST_EMPTY(pai_list)
GLOBAL_LIST_EMPTY(available_ai_shells)
+4 -2
View File
@@ -32,6 +32,8 @@ GLOBAL_VAR(world_asset_log)
GLOBAL_PROTECT(world_asset_log)
GLOBAL_VAR(world_map_error_log)
GLOBAL_PROTECT(world_map_error_log)
GLOBAL_VAR(world_paper_log)
GLOBAL_PROTECT(world_paper_log)
GLOBAL_VAR(subsystem_log)
GLOBAL_PROTECT(subsystem_log)
GLOBAL_VAR(reagent_log)
@@ -49,10 +51,10 @@ GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src]
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_PROTECT(lawchanges)
GLOBAL_VAR(tgui_log)
GLOBAL_PROTECT(tgui_log)
GLOBAL_VAR(world_shuttle_log)
GLOBAL_PROTECT(world_shuttle_log)
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(combatlog)
GLOBAL_LIST_EMPTY(IClog)
+2 -1
View File
@@ -94,8 +94,9 @@
The below is only really for safety, or you can alter the way
it functions and re-insert it above.
*/
/mob/living/silicon/ai/UnarmedAttack(atom/A)
/mob/living/silicon/ai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_ai(src)
/mob/living/silicon/ai/RangedAttack(atom/A)
A.attack_ai(src)
+1 -2
View File
@@ -269,10 +269,9 @@
proximity_flag is not currently passed to attack_hand, and is instead used
in human click code to allow glove touches only at melee range.
*/
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
/mob/proc/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
return
/*
Ranged unarmed attack:
+2 -1
View File
@@ -175,8 +175,9 @@
clicks, you can do so here, but you will have to
change attack_robot() above to the proper function
*/
/mob/living/silicon/robot/UnarmedAttack(atom/A)
/mob/living/silicon/robot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_robot(src)
/mob/living/silicon/robot/RangedAttack(atom/A)
A.attack_robot(src)
+165
View File
@@ -0,0 +1,165 @@
/client
/**
* Assoc list with all the active maps - when a screen obj is added to
* a map, it's put in here as well.
*
* Format: list(<mapname> = list(/obj/screen))
*/
var/list/screen_maps = list()
/**
* A screen object, which acts as a container for turfs and other things
* you want to show on the map, which you usually attach to "vis_contents".
*/
/obj/screen
/**
* Map name assigned to this object.
* Automatically set by /client/proc/add_obj_to_map.
*/
var/assigned_map
/**
* Mark this object as garbage-collectible after you clean the map
* it was registered on.
*
* This could probably be changed to be a proc, for conditional removal.
* But for now, this works.
*/
var/del_on_map_removal = TRUE
/**
* A generic background object.
* It is also implicitly used to allocate a rectangle on the map, which will
* be used for auto-scaling the map.
*/
/obj/screen/background
name = "background"
icon = 'icons/mob/map_backgrounds.dmi'
icon_state = "clear"
layer = GAME_PLANE
plane = GAME_PLANE
/**
* Sets screen_loc of this screen object, in form of point coordinates,
* with optional pixel offset (px, py).
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/set_position(x, y, px = 0, py = 0)
if(assigned_map)
screen_loc = "[assigned_map]:[x]:[px],[y]:[py]"
else
screen_loc = "[x]:[px],[y]:[py]"
/**
* Sets screen_loc to fill a rectangular area of the map.
*
* If applicable, "assigned_map" has to be assigned before this proc call.
*/
/obj/screen/proc/fill_rect(x1, y1, x2, y2)
if(assigned_map)
screen_loc = "[assigned_map]:[x1],[y1] to [x2],[y2]"
else
screen_loc = "[x1],[y1] to [x2],[y2]"
/**
* Registers screen obj with the client, which makes it visible on the
* assigned map, and becomes a part of the assigned map's lifecycle.
*/
/client/proc/register_map_obj(obj/screen/screen_obj)
if(!screen_obj.assigned_map)
CRASH("Can't register [screen_obj] without 'assigned_map' property.")
if(!screen_maps[screen_obj.assigned_map])
screen_maps[screen_obj.assigned_map] = list()
// NOTE: Possibly an expensive operation
var/list/screen_map = screen_maps[screen_obj.assigned_map]
if(!screen_map.Find(screen_obj))
screen_map += screen_obj
if(!screen.Find(screen_obj))
screen += screen_obj
/**
* Clears the map of registered screen objects.
*
* Not really needed most of the time, as the client's screen list gets reset
* on relog. any of the buttons are going to get caught by garbage collection
* anyway. they're effectively qdel'd.
*/
/client/proc/clear_map(map_name)
if(!map_name || !(map_name in screen_maps))
return FALSE
for(var/obj/screen/screen_obj in screen_maps[map_name])
screen_maps[map_name] -= screen_obj
if(screen_obj.del_on_map_removal)
qdel(screen_obj)
screen_maps -= map_name
/**
* Clears all the maps of registered screen objects.
*/
/client/proc/clear_all_maps()
for(var/map_name in screen_maps)
clear_map(map_name)
/**
* Creates a popup window with a basic map element in it, without any
* further initialization.
*
* Ratio is how many pixels by how many pixels (keep it simple).
*
* Returns a map name.
*/
/client/proc/create_popup(name, ratiox = 100, ratioy = 100)
winclone(src, "popupwindow", name)
var/list/winparams = list()
winparams["size"] = "[ratiox]x[ratioy]"
winparams["on-close"] = "handle-popup-close [name]"
winset(src, "[name]", list2params(winparams))
winshow(src, "[name]", 1)
var/list/params = list()
params["parent"] = "[name]"
params["type"] = "map"
params["size"] = "[ratiox]x[ratioy]"
params["anchor1"] = "0,0"
params["anchor2"] = "[ratiox],[ratioy]"
winset(src, "[name]_map", list2params(params))
return "[name]_map"
/**
* Create the popup, and get it ready for generic use by giving
* it a background.
*
* Width and height are multiplied by 64 by default.
*/
/client/proc/setup_popup(popup_name, width = 9, height = 9, \
tilesize = 2, bg_icon)
if(!popup_name)
return
clear_map("[popup_name]_map")
var/x_value = world.icon_size * tilesize * width
var/y_value = world.icon_size * tilesize * height
var/map_name = create_popup(popup_name, x_value, y_value)
var/obj/screen/background/background = new
background.assigned_map = map_name
background.fill_rect(1, 1, width, height)
if(bg_icon)
background.icon_state = bg_icon
register_map_obj(background)
return map_name
/**
* Closes a popup.
*/
/client/proc/close_popup(popup)
winshow(src, popup, 0)
handle_popup_close(popup)
/**
* When the popup closes in any way (player or proc call) it calls this.
*/
/client/verb/handle_popup_close(window_id as text)
set hidden = TRUE
clear_map("[window_id]_map")
+1 -1
View File
@@ -153,7 +153,7 @@
var/image/item_overlay = image(holding)
item_overlay.alpha = 92
if(!user.can_equip(holding, slot_id, TRUE))
if(!user.can_equip(holding, slot_id, TRUE, TRUE, TRUE))
item_overlay.color = "#FF0000"
else
item_overlay.color = "#00ff00"
+4 -3
View File
@@ -123,7 +123,7 @@
if(totitemdamage)
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill]))
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
@@ -192,9 +192,10 @@
if(.)
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
if(!(SKILL_TRAIN_ATTACK_MOB in I.used_skills[skill]))
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
var/datum/skill/S = GLOB.skill_datums[skill]
user.mind.auto_gain_experience(skill, I.skill_gain*S.item_skill_gain_multi)
// 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.
+3 -12
View File
@@ -63,18 +63,9 @@
// And here are some good things for free:
// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
if(awaygate)
user.forceMove(awaygate.loc)
else
to_chat(user, "[src] has no destination.")
return ..()
/obj/machinery/gateway/centeraway/attack_ghost(mob/user)
if(stationgate)
user.forceMove(stationgate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/effect/gateway_portal_bumper/attack_ghost(mob/user)
if(gateway)
gateway.Transfer(user)
return ..()
/obj/machinery/teleport/hub/attack_ghost(mob/user)
+24 -35
View File
@@ -4,7 +4,7 @@
Otherwise pretty standard.
*/
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity)
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!has_active_hand()) //can't attack without a hand.
to_chat(src, "<span class='notice'>You look at your arm and sigh.</span>")
@@ -20,16 +20,16 @@
var/override = 0
for(var/datum/mutation/human/HM in dna.mutations)
override += HM.on_attack_hand(A, proximity)
override += HM.on_attack_hand(A, proximity, intent, flags)
if(override)
return
SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A)
A.attack_hand(src)
A.attack_hand(src, intent, flags)
//Return TRUE to cancel other attack hand effects that respect it.
/atom/proc/attack_hand(mob/user)
/atom/proc/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = FALSE
if(!(interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND))
add_fingerprint(user)
@@ -104,8 +104,8 @@
/*
Animals & All Unspecified
*/
/mob/living/UnarmedAttack(atom/A)
A.attack_animal(src)
/mob/living/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_animal(src, intent, flags)
/atom/proc/attack_animal(mob/user)
SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
@@ -116,8 +116,8 @@
/*
Monkeys
*/
/mob/living/carbon/monkey/UnarmedAttack(atom/A)
A.attack_paw(src)
/mob/living/carbon/monkey/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_paw(src, intent, flags)
/atom/proc/attack_paw(mob/user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_NO_ATTACK_HAND)
@@ -162,8 +162,8 @@
Aliens
Defaults to same as monkey in most places
*/
/mob/living/carbon/alien/UnarmedAttack(atom/A)
A.attack_alien(src)
/mob/living/carbon/alien/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_alien(src, intent, flags)
/atom/proc/attack_alien(mob/living/carbon/alien/user)
attack_paw(user)
@@ -173,29 +173,29 @@
return
// Babby aliens
/mob/living/carbon/alien/larva/UnarmedAttack(atom/A)
A.attack_larva(src)
/mob/living/carbon/alien/larva/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_larva(src, intent, flags)
/atom/proc/attack_larva(mob/user)
return
/*
Slimes
Nothing happening here
*/
/mob/living/simple_animal/slime/UnarmedAttack(atom/A)
A.attack_slime(src)
/mob/living/simple_animal/slime/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_slime(src, intent, flags)
/atom/proc/attack_slime(mob/user)
return
/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
/*
Drones
*/
/mob/living/simple_animal/drone/UnarmedAttack(atom/A)
A.attack_drone(src)
/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_drone(src, intent, flags)
/atom/proc/attack_drone(mob/living/simple_animal/drone/user)
attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans.
@@ -203,55 +203,44 @@
/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
/*
True Devil
*/
/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity)
/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
A.attack_hand(src)
/*
Brain
*/
/mob/living/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
/mob/living/brain/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
return
/*
pAI
*/
/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
/mob/living/silicon/pai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
return
/*
Simple animals
*/
/mob/living/simple_animal/UnarmedAttack(atom/A, proximity)
/mob/living/simple_animal/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!dextrous)
return ..()
if(!ismob(A))
A.attack_hand(src)
A.attack_hand(src, intent, flags)
update_inv_hands()
/*
Hostile animals
*/
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A)
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
target = A
if(dextrous && !ismob(A))
..()
else
AttackingTarget()
/*
New Players:
Have no reason to click on anything at all.
+1 -2
View File
@@ -102,9 +102,8 @@
//stops TK grabs being equipped anywhere but into hands
/obj/item/tk_grab/equipped(mob/user, slot)
if(slot == SLOT_HANDS)
return
return ..()
qdel(src)
return
/obj/item/tk_grab/examine(user)
if (focus)
+11 -3
View File
@@ -83,7 +83,7 @@
var/auto_trim = TRUE
/datum/config_entry/string/vv_edit_var(var_name, var_value)
return var_name != "auto_trim" && ..()
return var_name != NAMEOF(src, auto_trim) && ..()
/datum/config_entry/string/ValidateAndSet(str_val, during_load)
if(!VASProcCallGuard(str_val))
@@ -110,7 +110,7 @@
return FALSE
/datum/config_entry/number/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("max_val", "min_val", "integer")
var/static/list/banned_edits = list(NAMEOF(src, max_val), NAMEOF(src, min_val), NAMEOF(src, integer))
return !(var_name in banned_edits) && ..()
/datum/config_entry/flag
@@ -209,12 +209,20 @@
new_value = new_list
continue_check_value = new_list.len
if(continue_check_value && continue_check_key && ValidateListEntry(new_key, new_value))
new_key = preprocess_key(new_key)
new_value = preprocess_value(new_value)
config_entry_value[new_key] = new_value
return TRUE
return FALSE
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
return var_name != NAMEOF(src, splitter) && ..()
/datum/config_entry/keyed_list/proc/preprocess_key(key)
return key
/datum/config_entry/keyed_list/proc/preprocess_value(value)
return value
//snowflake for donator things being on one line smh
/datum/config_entry/multi_keyed_flag
@@ -14,6 +14,7 @@
var/list/modes // allowed modes
var/list/gamemode_cache
var/list/votable_modes // votable modes
// var/list/ic_filter_regex
var/list/storyteller_cache
var/list/mode_names
var/list/mode_reports
@@ -414,3 +415,21 @@
continue
runnable_modes[M] = probabilities[M.config_tag]
return runnable_modes
/*
/datum/controller/configuration/proc/LoadChatFilter()
var/list/in_character_filter = list()
if(!fexists("[directory]/in_character_filter.txt"))
return
log_config("Loading config file in_character_filter.txt...")
for(var/line in world.file2list("[directory]/in_character_filter.txt"))
if(!line)
continue
if(findtextEx(line,"#",1,2))
continue
in_character_filter += REGEX_QUOTE(line)
ic_filter_regex = in_character_filter.len ? regex("\\b([jointext(in_character_filter, "|")])\\b", "i") : null
syncChatRegexes()
*/
@@ -25,4 +25,23 @@
/datum/config_entry/string/medal_hub_address
/datum/config_entry/string/medal_hub_password
protection = CONFIG_ENTRY_HIDDEN
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/keyed_list/cross_server_bunker_override
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_TEXT
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/keyed_list/cross_server_bunker_override/ValidateAndSet(str_val)
. = ..()
if(.)
var/list/newv = list()
for(var/I in config_entry_value)
newv[replacetext(I, "+", " ")] = config_entry_value[I]
config_entry_value = newv
/datum/config_entry/keyed_list/cross_server_bunker_override/ValidateListEntry(key_name, key_value)
return key_value != "byond:\\address:port" && ..()
/datum/config_entry/flag/allow_cross_server_bunker_override
protection = CONFIG_ENTRY_LOCKED
@@ -56,6 +56,8 @@
/datum/config_entry/flag/log_adminchat // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console
/datum/config_entry/flag/log_pda // log pda messages
/datum/config_entry/flag/log_telecomms // log telecomms messages
@@ -0,0 +1,11 @@
/// Seconds for CMD on defib-with-memory-loss policy config to display instead of defib-intact config
/datum/config_entry/number/defib_cmd_time_limit
config_entry_value = 300
integer = TRUE
/datum/config_entry/keyed_list/policyconfig
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_TEXT
/datum/config_entry/keyed_list/policyconfig/preprocess_key(key)
return uppertext(..())
+3 -3
View File
@@ -210,10 +210,10 @@
/datum/controller/subsystem/vv_edit_var(var_name, var_value)
switch (var_name)
if ("can_fire")
if (NAMEOF(src, can_fire))
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
if (var_value)
next_fire = world.time + wait
if ("queued_priority") //editing this breaks things.
return 0
if (NAMEOF(src, queued_priority)) //editing this breaks things.
return FALSE
. = ..()
+87 -54
View File
@@ -6,7 +6,7 @@ SUBSYSTEM_DEF(air)
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/cost_turf_reactions = 0
var/cost_turfs = 0
var/cost_groups = 0
var/cost_highpressure = 0
var/cost_hotspots = 0
@@ -14,10 +14,9 @@ SUBSYSTEM_DEF(air)
var/cost_pipenets = 0
var/cost_rebuilds = 0
var/cost_atmos_machinery = 0
var/cost_equalize = 0
var/list/excited_groups = list()
var/list/active_turfs = list()
var/list/turf_react_queue = list()
var/list/hotspots = list()
var/list/networks = list()
var/list/pipenets_needing_rebuilt = list()
@@ -38,20 +37,25 @@ SUBSYSTEM_DEF(air)
var/map_loading = TRUE
var/list/queued_for_activation
var/log_explosive_decompression = TRUE // If things get spammy, admemes can turn this off.
var/monstermos_turf_limit = 10
var/monstermos_hard_turf_limit = 2000
var/monstermos_enabled = TRUE
/datum/controller/subsystem/air/stat_entry(msg)
msg += "C:{"
msg += "RQ:[round(cost_turf_reactions,1)]|"
msg += "EQ:[round(cost_equalize,1)]|"
msg += "AT:[round(cost_turfs,1)]|"
msg += "EG:[round(cost_groups,1)]|"
msg += "HP:[round(cost_highpressure,1)]|"
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]|"
msg += "RQ:[turf_react_queue.len]|"
msg += "EG:[excited_groups.len]|"
msg += "EG:[get_amt_excited_groups()]|"
msg += "HS:[hotspots.len]|"
msg += "PN:[networks.len]|"
msg += "HP:[high_pressure_delta.len]|"
@@ -59,8 +63,8 @@ SUBSYSTEM_DEF(air)
msg += "AT/MS:[round((cost ? active_turfs.len/cost : 0),0.1)]"
..(msg)
/datum/controller/subsystem/air/Initialize(timeofday)
extools_update_ssair()
map_loading = FALSE
setup_allturfs()
setup_atmos_machinery()
@@ -68,6 +72,7 @@ SUBSYSTEM_DEF(air)
gas_reactions = init_gas_reactions()
return ..()
/datum/controller/subsystem/air/proc/extools_update_ssair()
/datum/controller/subsystem/air/fire(resumed = 0)
var/timer = TICK_USAGE_REAL
@@ -101,12 +106,21 @@ SUBSYSTEM_DEF(air)
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSAIR_REACTQUEUE
currentpart = monstermos_enabled ? SSAIR_EQUALIZE : SSAIR_ACTIVETURFS
if(currentpart == SSAIR_REACTQUEUE)
if(currentpart == SSAIR_EQUALIZE)
timer = TICK_USAGE_REAL
process_react_queue(resumed)
cost_turf_reactions = MC_AVERAGE(cost_turf_reactions, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
process_turf_equalize(resumed)
cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSAIR_ACTIVETURFS
if(currentpart == SSAIR_ACTIVETURFS)
timer = TICK_USAGE_REAL
process_active_turfs(resumed)
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
if(state != SS_RUNNING)
return
resumed = 0
@@ -148,6 +162,8 @@ SUBSYSTEM_DEF(air)
resumed = 0
currentpart = SSAIR_REBUILD_PIPENETS
/datum/controller/subsystem/air/proc/process_pipenets(resumed = 0)
if (!resumed)
src.currentrun = networks.Copy()
@@ -182,19 +198,6 @@ SUBSYSTEM_DEF(air)
return
/datum/controller/subsystem/air/proc/process_react_queue(resumed = 0)
if(!resumed)
src.currentrun = turf_react_queue.Copy()
var/list/currentrun = src.currentrun
while(currentrun.len)
var/turf/open/T = currentrun[currentrun.len]
currentrun.len--
if(T)
T.process_cell_reaction()
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/air/proc/process_super_conductivity(resumed = 0)
if (!resumed)
src.currentrun = active_super_conductivity.Copy()
@@ -229,10 +232,45 @@ SUBSYSTEM_DEF(air)
high_pressure_delta.len--
T.high_pressure_movements()
T.pressure_difference = 0
T.pressure_specific_target = null
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0)
//cache for sanic speed
var/fire_count = times_fired
if (!resumed)
src.currentrun = active_turfs.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/turf/open/T = currentrun[currentrun.len]
currentrun.len--
if (T)
T.equalize_pressure_in_zone(fire_count)
//equalize_pressure_in_zone(T, fire_count)
if (MC_TICK_CHECK)
return
/datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0)
//cache for sanic speed
var/fire_count = times_fired
if (!resumed)
src.currentrun = active_turfs.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/turf/open/T = currentrun[currentrun.len]
currentrun.len--
if (T)
T.process_cell(fire_count)
if (MC_TICK_CHECK)
return
/datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0)
if(process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag))
sleep()
/*
if (!resumed)
src.currentrun = excited_groups.Copy()
//cache for sanic speed (lists are references anyways)
@@ -248,29 +286,33 @@ SUBSYSTEM_DEF(air)
EG.dismantle()
if (MC_TICK_CHECK)
return
*/
/datum/controller/subsystem/air/proc/process_excited_groups_extools()
/datum/controller/subsystem/air/proc/get_amt_excited_groups()
/datum/controller/subsystem/air/proc/remove_from_active(turf/open/T)
active_turfs -= T
SSair_turfs.currentrun -= T
if(currentpart == SSAIR_ACTIVETURFS)
currentrun -= T
#ifdef VISUALIZE_ACTIVE_TURFS
T.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#00ff00")
#endif
if(istype(T))
T.excited = 0
if(T.excited_group)
T.excited_group.garbage_collect()
remove_from_react_queue(T)
T.set_excited(FALSE)
T.eg_garbage_collect()
/datum/controller/subsystem/air/proc/add_to_active(turf/open/T, blockchanges = 1)
if(istype(T) && T.air)
#ifdef VISUALIZE_ACTIVE_TURFS
T.add_atom_colour("#00ff00", TEMPORARY_COLOUR_PRIORITY)
#endif
T.excited = TRUE
active_turfs[T] = SSair_turfs.currentrun[T] = TRUE
if(blockchanges && T.excited_group)
T.excited_group.garbage_collect()
add_to_react_queue(T)
T.set_excited(TRUE)
active_turfs |= T
if(currentpart == SSAIR_ACTIVETURFS)
currentrun |= T
if(blockchanges)
T.eg_garbage_collect()
else if(T.flags_1 & INITIALIZED_1)
for(var/turf/S in T.atmos_adjacent_turfs)
add_to_active(S)
@@ -281,17 +323,6 @@ SUBSYSTEM_DEF(air)
else
T.requires_activation = TRUE
/datum/controller/subsystem/air/proc/add_to_react_queue(turf/open/T)
if(istype(T) && T.air)
turf_react_queue[T] = TRUE
if(currentpart == SSAIR_REACTQUEUE)
currentrun[T] = TRUE
/datum/controller/subsystem/air/proc/remove_from_react_queue(turf/open/T)
turf_react_queue -= T
if(currentpart == SSAIR_REACTQUEUE)
currentrun -= T
/datum/controller/subsystem/air/StartLoadingMap()
LAZYINITLIST(queued_for_activation)
map_loading = TRUE
@@ -339,11 +370,11 @@ SUBSYSTEM_DEF(air)
while (turfs_to_check.len)
var/ending_ats = active_turfs.len
for(var/thing in excited_groups)
/*for(var/thing in excited_groups)
var/datum/excited_group/EG = thing
EG.self_breakdown(space_is_all_consuming = 1)
EG.dismantle()
CHECK_TICK
//EG.self_breakdown(space_is_all_consuming = 1)
//EG.dismantle()
CHECK_TICK*/
var/msg = "HEY! LISTEN! [DisplayTimeText(world.timeofday - timer)] were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
to_chat(world, "<span class='boldannounce'>[msg]</span>")
@@ -351,6 +382,7 @@ SUBSYSTEM_DEF(air)
/turf/open/proc/resolve_active_graph()
. = list()
/*
var/datum/excited_group/EG = excited_group
if (blocks_air || !air)
return
@@ -371,7 +403,8 @@ SUBSYSTEM_DEF(air)
EG.add_turf(ET)
if (!ET.excited)
ET.excited = 1
. += ET
. += ET*/
/turf/open/space/resolve_active_graph()
return list()
@@ -389,9 +422,8 @@ SUBSYSTEM_DEF(air)
CHECK_TICK
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
if(!initialized)
return
if(!initialized) // yogs - fixes randomized bars
return // yogs
for(var/A in atmos_machines)
var/obj/machinery/atmospherics/AM = A
AM.atmosinit()
@@ -415,6 +447,7 @@ SUBSYSTEM_DEF(air)
#undef SSAIR_PIPENETS
#undef SSAIR_ATMOSMACHINERY
#undef SSAIR_ACTIVETURFS
#undef SSAIR_EXCITEDGROUPS
#undef SSAIR_HIGHPRESSURE
#undef SSAIR_HOTSPOTS
+2 -1
View File
@@ -1,5 +1,5 @@
//WHAT IF WE TAKE THE ACTIVE TURF PROCESSING AND PUSH IT SOMEWHERE ELSE!!!
/*
SUBSYSTEM_DEF(air_turfs)
name = "Atmospherics - Turfs"
init_order = INIT_ORDER_AIR_TURFS
@@ -24,3 +24,4 @@ SUBSYSTEM_DEF(air_turfs)
return
resumed = 0
return
*/
+24
View File
@@ -16,6 +16,7 @@ SUBSYSTEM_DEF(atoms)
/datum/controller/subsystem/atoms/Initialize(timeofday)
GLOB.fire_overlay.appearance_flags = RESET_COLOR
setupGenetics()
initialized = INITIALIZATION_INNEW_MAPLOAD
InitializeAtoms()
return ..()
@@ -106,6 +107,29 @@ 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)
GLOB.alias_mutations[B.alias] = B.type
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)
+2 -2
View File
@@ -60,9 +60,9 @@ SUBSYSTEM_DEF(blackbox)
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
switch(var_name)
if("feedback")
if(NAMEOF(src, feedback))
return FALSE
if("sealed")
if(NAMEOF(src, sealed))
if(var_value)
return Seal()
return FALSE
+5 -4
View File
@@ -4,6 +4,7 @@ SUBSYSTEM_DEF(chat)
wait = 1
priority = FIRE_PRIORITY_CHAT
init_order = INIT_ORDER_CHAT
var/list/payload = list()
@@ -17,7 +18,7 @@ SUBSYSTEM_DEF(chat)
return
/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE)
/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = TRUE)
if(!target || !message)
return
@@ -35,8 +36,8 @@ SUBSYSTEM_DEF(chat)
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
message += "<br>"
if (trailing_newline)
message += "<br>"
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
//Do the double-encoding here to save nanoseconds
@@ -47,7 +48,7 @@ SUBSYSTEM_DEF(chat)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C)
return
continue
//Send it to the old style output window.
SEND_TEXT(C, original_message)
+15 -26
View File
@@ -334,6 +334,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
for (var/map in mapvotes)
if (!map)
mapvotes.Remove(map)
continue
if (!(map in global.config.maplist))
mapvotes.Remove(map)
continue
@@ -468,9 +469,9 @@ GLOBAL_LIST_EMPTY(the_station_areas)
else
return
possible_options += "Custom"
var/lvl_name
var/datum/space_level/level
possible_options = "Custom"
var/away_name
var/datum/space_level/away_level
var/answer = input("What kind ? ","Away/VR") as null|anything in possible_options
switch(answer)
@@ -480,34 +481,22 @@ GLOBAL_LIST_EMPTY(the_station_areas)
var/mapfile = input("Pick file:", "File") as null|file
if(!mapfile)
return
lvl_name = "[mapfile] custom"
to_chat(usr,"<span class='notice'>Loading [lvl_name]...</span>")
away_name = "[mapfile] custom"
to_chat(usr,"<span class='notice'>Loading [away_name]...</span>")
var/datum/map_template/template = new(mapfile, choice, ztraits)
level = template.load_new_z(ztraits)
away_level = template.load_new_z(ztraits)
else
lvl_name = answer
to_chat(usr,"<span class='notice'>Loading [lvl_name]...</span>")
var/datum/map_template/template = new(lvl_name, choice)
level = template.load_new_z(ztraits)
away_name = answer
to_chat(usr,"<span class='notice'>Loading [away_name]...</span>")
var/datum/map_template/template = new(away_name, choice)
away_level = template.load_new_z(ztraits)
message_admins("Admin [key_name_admin(usr)] has loaded [lvl_name] [choice].")
log_admin("Admin [key_name(usr)] has loaded [lvl_name] [choice].")
if(!level)
message_admins("Loading [lvl_name] failed!")
message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.")
log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.")
if(!away_level)
message_admins("Loading [away_name] failed!")
return
if(choice == AWAY_MISSION_NAME && GLOB.the_gateway)
//Link any found away gate with station gate
var/obj/machinery/gateway/centeraway/new_gate
for(var/obj/machinery/gateway/centeraway/G in GLOB.machines)
if(G.z == level.z_value) //I'll have to refactor gateway shitcode before multi-away support.
new_gate = G
break
//Link station gate with away gate and remove wait time.
GLOB.the_gateway.awaygate = new_gate
GLOB.the_gateway.wait = world.time
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override)
UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type
+310 -39
View File
@@ -7,10 +7,9 @@ SUBSYSTEM_DEF(shuttle)
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME
var/obj/machinery/shuttle_manipulator/manipulator
var/list/mobile = list()
var/list/stationary = list()
var/list/beacons = list()
var/list/transit = list()
var/list/transit_requesters = list()
@@ -57,6 +56,15 @@ SUBSYSTEM_DEF(shuttle)
var/realtimeofstart = 0
var/datum/map_template/shuttle/selected
var/obj/docking_port/mobile/existing_shuttle
var/obj/docking_port/mobile/preview_shuttle
var/datum/map_template/shuttle/preview_template
var/datum/turf_reservation/preview_reservation
/datum/controller/subsystem/shuttle/Initialize(timeofday)
ordernum = rand(1, 9000)
@@ -76,13 +84,10 @@ SUBSYSTEM_DEF(shuttle)
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
if(!supply)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
realtimeofstart = world.realtime
realtimeofstart = world.realtime
return ..()
/datum/controller/subsystem/shuttle/proc/initial_load()
if(!istype(manipulator))
CRASH("No shuttle manipulator found.")
for(var/s in stationary)
var/obj/docking_port/stationary/S = s
S.load_roundstart()
@@ -143,11 +148,13 @@ SUBSYSTEM_DEF(shuttle)
++alive
var/total = GLOB.joined_player_list.len
if(total <= 0)
return //no players no autoevac
if(alive / total <= threshold)
var/msg = "Automatically dispatching shuttle due to crew death."
var/msg = "Automatically dispatching emergency shuttle due to crew death."
message_admins(msg)
log_game("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]")
log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]")
emergencyNoRecall = TRUE
priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.")
if(emergency.timeLeft(1) > emergencyCallTime * 0.4)
@@ -172,6 +179,34 @@ SUBSYSTEM_DEF(shuttle)
return S
WARNING("couldn't find dock with id: [id]")
/datum/controller/subsystem/shuttle/proc/canEvac(mob/user)
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "<span class='alert'>The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.</span>")
return FALSE
switch(emergency.mode)
if(SHUTTLE_RECALL)
to_chat(user, "<span class='alert'>The emergency shuttle may not be called while returning to CentCom.</span>")
return FALSE
if(SHUTTLE_CALL)
to_chat(user, "<span class='alert'>The emergency shuttle is already on its way.</span>")
return FALSE
if(SHUTTLE_DOCKED)
to_chat(user, "<span class='alert'>The emergency shuttle is already here.</span>")
return FALSE
if(SHUTTLE_IGNITING)
to_chat(user, "<span class='alert'>The emergency shuttle is firing its engines to leave.</span>")
return FALSE
if(SHUTTLE_ESCAPE)
to_chat(user, "<span class='alert'>The emergency shuttle is moving away to a safe distance.</span>")
return FALSE
if(SHUTTLE_STRANDED)
to_chat(user, "<span class='alert'>The emergency shuttle has been disabled by CentCom.</span>")
return FALSE
return TRUE
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
if(!emergency)
WARNING("requestEvac(): There is no emergency shuttle, but the \
@@ -185,35 +220,14 @@ SUBSYSTEM_DEF(shuttle)
manually, and then calling register() on the mobile docking port. \
Good luck.")
emergency = backup_shuttle
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.")
return
switch(emergency.mode)
if(SHUTTLE_RECALL)
to_chat(user, "The emergency shuttle may not be called while returning to CentCom.")
return
if(SHUTTLE_CALL)
to_chat(user, "The emergency shuttle is already on its way.")
return
if(SHUTTLE_DOCKED)
to_chat(user, "The emergency shuttle is already here.")
return
if(SHUTTLE_IGNITING)
to_chat(user, "The emergency shuttle is firing its engines to leave.")
return
if(SHUTTLE_ESCAPE)
to_chat(user, "The emergency shuttle is moving away to a safe distance.")
return
if(SHUTTLE_STRANDED)
to_chat(user, "The emergency shuttle has been disabled by CentCom.")
return
if(!canEvac(user))
return
call_reason = trim(html_encode(call_reason))
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && GLOB.security_level > SEC_LEVEL_GREEN)
to_chat(user, "You must provide a reason.")
to_chat(user, "<span class='alert'>You must provide a reason.</span>")
return
var/area/signal_origin = get_area(user)
@@ -235,11 +249,11 @@ SUBSYSTEM_DEF(shuttle)
var/area/A = get_area(user)
log_game("[key_name(user)] has called the shuttle.")
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> has called the shuttle at <span class='name'>[A.name]</span>.</span>", user)
log_shuttle("[key_name(user)] has called the emergency shuttle.")
deadchat_broadcast(" has called the shuttle at <span class='name'>[A.name]</span>.", "<span class='name'>[user.real_name]</span>", user)
if(call_reason)
SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]")
log_game("Shuttle call reason: [call_reason]")
log_shuttle("Shuttle call reason: [call_reason]")
message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (<A HREF='?_src_=holder;[HrefToken()];trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)")
/datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message)
@@ -272,9 +286,9 @@ SUBSYSTEM_DEF(shuttle)
/datum/controller/subsystem/shuttle/proc/cancelEvac(mob/user)
if(canRecall())
emergency.cancel(get_area(user))
log_game("[key_name(user)] has recalled the shuttle.")
log_shuttle("[key_name(user)] has recalled the shuttle.")
message_admins("[ADMIN_LOOKUPFLW(user)] has recalled the shuttle.")
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> has recalled the shuttle from <span class='name'>[get_area_name(user, TRUE)]</span>.</span>", user)
deadchat_broadcast(" has recalled the shuttle from <span class='name'>[get_area_name(user, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
return 1
/datum/controller/subsystem/shuttle/proc/canRecall()
@@ -294,7 +308,7 @@ SUBSYSTEM_DEF(shuttle)
else
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
return
return 1
return TRUE
/datum/controller/subsystem/shuttle/proc/autoEvac()
if (!SSticker.IsRoundInProgress())
@@ -322,7 +336,7 @@ SUBSYSTEM_DEF(shuttle)
if(callShuttle)
if(EMERGENCY_IDLE_OR_RECALLED)
emergency.request(null, set_coefficient = 2.5)
log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.")
log_shuttle("There is no means of calling the emergency shuttle anymore. Shuttle automatically called.")
message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.")
/datum/controller/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad)
@@ -559,6 +573,14 @@ SUBSYSTEM_DEF(shuttle)
shuttle_purchased = SSshuttle.shuttle_purchased
lockdown = SSshuttle.lockdown
selected = SSshuttle.selected
existing_shuttle = SSshuttle.existing_shuttle
preview_shuttle = SSshuttle.preview_shuttle
preview_template = SSshuttle.preview_template
preview_reservation = SSshuttle.preview_reservation
/datum/controller/subsystem/shuttle/proc/is_in_shuttle_bounds(atom/A)
var/area/current = get_area(A)
@@ -641,3 +663,252 @@ SUBSYSTEM_DEF(shuttle)
message_admins("Round end vote passed. Shuttle has been auto-called.")
emergencyNoRecall = TRUE
endvote_passed = TRUE
/datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port)
// Check for an existing preview
if(preview_shuttle && (loading_template != preview_template))
preview_shuttle.jumpToNullSpace()
preview_shuttle = null
preview_template = null
QDEL_NULL(preview_reservation)
if(!preview_shuttle)
if(load_template(loading_template))
preview_shuttle.linkup(loading_template, destination_port)
preview_template = loading_template
// get the existing shuttle information, if any
var/timer = 0
var/mode = SHUTTLE_IDLE
var/obj/docking_port/stationary/D
if(istype(destination_port))
D = destination_port
else if(existing_shuttle)
timer = existing_shuttle.timer
mode = existing_shuttle.mode
D = existing_shuttle.get_docked()
if(!D)
D = generate_transit_dock(preview_shuttle)
if(!D)
CRASH("No dock found for preview shuttle ([preview_template.name]), aborting.")
var/result = preview_shuttle.canDock(D)
// truthy value means that it cannot dock for some reason
// but we can ignore the someone else docked error because we'll
// be moving into their place shortly
if((result != SHUTTLE_CAN_DOCK) && (result != SHUTTLE_SOMEONE_ELSE_DOCKED))
WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).")
return
if(existing_shuttle)
existing_shuttle.jumpToNullSpace()
var/list/force_memory = preview_shuttle.movement_force
preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
preview_shuttle.initiate_docking(D)
preview_shuttle.movement_force = force_memory
. = preview_shuttle
// Shuttle state involves a mode and a timer based on world.time, so
// plugging the existing shuttles old values in works fine.
preview_shuttle.timer = timer
preview_shuttle.mode = mode
preview_shuttle.register()
// TODO indicate to the user that success happened, rather than just
// blanking the modification tab
preview_shuttle = null
preview_template = null
existing_shuttle = null
selected = null
QDEL_NULL(preview_reservation)
/datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/S)
. = FALSE
// load shuttle template, centred at shuttle import landmark,
preview_reservation = SSmapping.RequestBlockReservation(S.width, S.height, SSmapping.transit.z_value, /datum/turf_reservation/transit)
if(!preview_reservation)
CRASH("failed to reserve an area for shuttle template loading")
var/turf/BL = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords)
S.load(BL, centered = FALSE, register = FALSE)
var/affected = S.get_affected_turfs(BL, centered=FALSE)
var/found = 0
// Search the turfs for docking ports
// - We need to find the mobile docking port because that is the heart of
// the shuttle.
// - We need to check that no additional ports have slipped in from the
// template, because that causes unintended behaviour.
for(var/T in affected)
for(var/obj/docking_port/P in T)
if(istype(P, /obj/docking_port/mobile))
found++
if(found > 1)
qdel(P, force=TRUE)
log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.")
else
preview_shuttle = P
if(istype(P, /obj/docking_port/stationary))
log_world("Map warning: Shuttle Template [S.mappath] has a stationary docking port.")
if(!found)
var/msg = "load_template(): Shuttle Template [S.mappath] has no mobile docking port. Aborting import."
for(var/T in affected)
var/turf/T0 = T
T0.empty()
message_admins(msg)
WARNING(msg)
return
//Everything fine
S.post_load(preview_shuttle)
return TRUE
/datum/controller/subsystem/shuttle/proc/unload_preview()
if(preview_shuttle)
preview_shuttle.jumpToNullSpace()
preview_shuttle = null
/datum/controller/subsystem/shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ShuttleManipulator", name, 800, 600, master_ui, state)
ui.open()
/datum/controller/subsystem/shuttle/ui_data(mob/user)
var/list/data = list()
data["tabs"] = list("Status", "Templates", "Modification")
// Templates panel
data["templates"] = list()
var/list/templates = data["templates"]
data["templates_tabs"] = list()
data["selected"] = list()
for(var/shuttle_id in SSmapping.shuttle_templates)
var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id]
if(!templates[S.port_id])
data["templates_tabs"] += S.port_id
templates[S.port_id] = list(
"port_id" = S.port_id,
"templates" = list())
var/list/L = list()
L["name"] = S.name
L["shuttle_id"] = S.shuttle_id
L["port_id"] = S.port_id
L["description"] = S.description
L["admin_notes"] = S.admin_notes
if(selected == S)
data["selected"] = L
templates[S.port_id]["templates"] += list(L)
data["templates_tabs"] = sortList(data["templates_tabs"])
data["existing_shuttle"] = null
// Status panel
data["shuttles"] = list()
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
var/timeleft = M.timeLeft(1)
var/list/L = list()
L["name"] = M.name
L["id"] = M.id
L["timer"] = M.timer
L["timeleft"] = M.getTimerStr()
if (timeleft > 1 HOURS)
L["timeleft"] = "Infinity"
L["can_fast_travel"] = M.timer && timeleft >= 50
L["can_fly"] = TRUE
if(istype(M, /obj/docking_port/mobile/emergency))
L["can_fly"] = FALSE
else if(!M.destination)
L["can_fast_travel"] = FALSE
if (M.mode != SHUTTLE_IDLE)
L["mode"] = capitalize(M.mode)
L["status"] = M.getDbgStatusText()
if(M == existing_shuttle)
data["existing_shuttle"] = L
data["shuttles"] += list(L)
return data
/datum/controller/subsystem/shuttle/ui_act(action, params)
if(..())
return
var/mob/user = usr
// Preload some common parameters
var/shuttle_id = params["shuttle_id"]
var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id]
switch(action)
if("select_template")
if(S)
existing_shuttle = getShuttle(S.port_id)
selected = S
. = TRUE
if("jump_to")
if(params["type"] == "mobile")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"])
user.forceMove(get_turf(M))
. = TRUE
break
if("fly")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"])
. = TRUE
M.admin_fly_shuttle(user)
break
if("fast_travel")
for(var/i in mobile)
var/obj/docking_port/mobile/M = i
if(M.id == params["id"] && M.timer && M.timeLeft(1) >= 50)
M.setTimer(50)
. = TRUE
message_admins("[key_name_admin(usr)] fast travelled [M]")
log_admin("[key_name(usr)] fast travelled [M]")
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]")
break
if("preview")
if(S)
. = TRUE
unload_preview()
load_template(S)
if(preview_shuttle)
preview_template = S
user.forceMove(get_turf(preview_shuttle))
if("load")
if(existing_shuttle == backup_shuttle)
// TODO make the load button disabled
WARNING("The shuttle that the selected shuttle will replace \
is the backup shuttle. Backup shuttle is required to be \
intact for round sanity.")
else if(S)
. = TRUE
// If successful, returns the mobile docking port
var/obj/docking_port/mobile/mdp = action_load(S)
if(mdp)
user.forceMove(get_turf(mdp))
message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.")
log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.</span>")
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]")
+1 -1
View File
@@ -11,7 +11,7 @@ SUBSYSTEM_DEF(tgui)
var/basehtml // The HTML base used for all UIs.
/datum/controller/subsystem/tgui/PreInit()
basehtml = file2text('tgui-next/packages/tgui/public/tgui-main.html')
basehtml = file2text('tgui/packages/tgui/public/tgui.html')
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
+2 -2
View File
@@ -47,7 +47,7 @@ SUBSYSTEM_DEF(title)
. = ..()
if(.)
switch(var_name)
if("icon")
if(NAMEOF(src, icon))
if(splash_turf)
splash_turf.icon = icon
@@ -66,4 +66,4 @@ SUBSYSTEM_DEF(title)
icon = SStitle.icon
splash_turf = SStitle.splash_turf
file_path = SStitle.file_path
previous_icon = SStitle.previous_icon
previous_icon = SStitle.previous_icon
+5 -5
View File
@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/pda/clown, /obj/item/grown/bananapeel)),
"greytide" = typecacheof(list(/obj/item/clothing/under/color/grey, /obj/item/melee/baton/cattleprod,
/obj/item/twohanded/spear, /obj/item/clothing/mask/gas)),
/obj/item/spear, /obj/item/clothing/mask/gas)),
"lizards" = typecacheof(list(/obj/item/toy/plush/lizardplushie, /obj/item/reagent_containers/food/snacks/kebab/tail,
/obj/item/organ/tail/lizard, /obj/item/reagent_containers/food/drinks/bottle/lizardwine)),
@@ -120,7 +120,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/card/id/captains_spare, /obj/item/card/id/centcom, /obj/machinery/door/airlock/command)),
"the supernatural" = typecacheof(list(/obj/structure/destructible/cult, /obj/item/tome,
/obj/item/melee/cultblade, /obj/item/twohanded/required/cult_bastard, /obj/item/restraints/legcuffs/bola/cult,
/obj/item/melee/cultblade, /obj/item/cult_bastard, /obj/item/restraints/legcuffs/bola/cult,
/obj/item/clothing/suit/cultrobes, /obj/item/clothing/suit/space/hardsuit/cult,
/obj/item/clothing/suit/hooded/cultrobes, /obj/item/clothing/head/hooded/cult_hoodie, /obj/effect/rune,
/obj/item/stack/sheet/runed_metal, /obj/machinery/door/airlock/cult, /obj/singularity/narsie,
@@ -151,7 +151,7 @@ SUBSYSTEM_DEF(traumas)
"anime" = typecacheof(list(/obj/item/clothing/under/costume/schoolgirl, /obj/item/katana, /obj/item/reagent_containers/food/snacks/sashimi, /obj/item/reagent_containers/food/snacks/chawanmushi,
/obj/item/reagent_containers/food/drinks/bottle/sake, /obj/item/throwing_star, /obj/item/clothing/head/kitty/genuine, /obj/item/clothing/suit/space/space_ninja,
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/twohanded/vibro_weapon,
/obj/item/clothing/mask/gas/space_ninja, /obj/item/clothing/shoes/space_ninja, /obj/item/clothing/gloves/space_ninja, /obj/item/vibro_weapon,
/obj/item/nullrod/scythe/vibro, /obj/item/energy_katana, /obj/item/toy/katana, /obj/item/nullrod/claymore/katana, /obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe)),
"mimes" = typecacheof(list(/obj/item/pda/mime, /obj/item/clothing/under/rank/civilian/mime, /obj/item/clothing/mask/gas/mime,
@@ -168,7 +168,7 @@ SUBSYSTEM_DEF(traumas)
/obj/machinery/porta_turret/syndicate, /obj/structure/closet/syndicate, /obj/machinery/suit_storage_unit/syndicate, /obj/item/clothing/under/syndicate, /obj/item/folder/syndicate, /obj/item/documents/syndicate, /obj/item/clothing/glasses/phantomthief/syndicate, /obj/item/antag_spawner/nuke_ops, /obj/item/storage/box/syndicate,
/obj/structure/fluff/empty_sleeper/syndicate, /obj/item/implant/radio/syndicate, /obj/item/clothing/head/helmet/space/syndicate, /obj/machinery/nuclearbomb/syndicate, /obj/item/grenade/syndieminibomb, /obj/item/storage/backpack/duffelbag/syndie, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver,
/obj/item/gun/ballistic/automatic/shotgun/bulldog, /obj/item/gun/ballistic/automatic/c20r, /obj/item/gun/ballistic/automatic/m90, /obj/item/gun/ballistic/automatic/l6_saw, /obj/item/storage/belt/grenade/full, /obj/item/gun/ballistic/automatic/sniper_rifle/syndicate, /obj/item/gun/energy/kinetic_accelerator/crossbow,
/obj/item/melee/transforming/energy/sword/saber, /obj/item/twohanded/dualsaber, /obj/item/melee/powerfist, /obj/item/storage/box/syndie_kit, /obj/item/grenade/spawnergrenade/manhacks, /obj/item/grenade/chem_grenade/bioterrorfoam, /obj/item/reagent_containers/spray/chemsprayer/bioterror, /obj/item/ammo_box/magazine/m10mm,
/obj/item/melee/transforming/energy/sword/saber, /obj/item/dualsaber, /obj/item/melee/powerfist, /obj/item/storage/box/syndie_kit, /obj/item/grenade/spawnergrenade/manhacks, /obj/item/grenade/chem_grenade/bioterrorfoam, /obj/item/reagent_containers/spray/chemsprayer/bioterror, /obj/item/ammo_box/magazine/m10mm,
/obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/mecha/combat/gygax/dark, /obj/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate,
/obj/item/cartridge/virus/frame, /obj/item/chameleon, /obj/item/storage/box/syndie_kit/cutouts, /obj/item/clothing/suit/space/hardsuit/syndi, /obj/item/card/emag, /obj/item/storage/toolbox/syndicate, /obj/item/storage/book/bible/syndicate, /obj/item/encryptionkey/binary, /obj/item/encryptionkey/syndicate, /obj/item/aiModule/syndicate,
/obj/item/clothing/shoes/magboots/syndie, /obj/item/powersink, /obj/item/sbeacondrop, /obj/item/sbeacondrop/bomb, /obj/item/syndicatedetonator, /obj/item/shield/energy, /obj/item/assault_pod, /obj/item/slimepotion/slime/sentience/nuclear, /obj/item/stack/telecrystal, /obj/item/jammer, /obj/item/codespeak_manual/unlimited,
@@ -176,7 +176,7 @@ SUBSYSTEM_DEF(traumas)
/obj/machinery/computer/pod/old/syndicate, /obj/machinery/vending/medical/syndicate_access, /obj/item/mmi/syndie, /obj/item/target/syndicate, /obj/machinery/vending/cigarette/syndicate, /obj/item/robot_module/syndicate, /obj/item/clothing/mask/gas/syndicate, /obj/machinery/power/singularity_beacon/syndicate, /obj/item/clothing/head/syndicatefake,
/obj/item/radio/headset/syndicate, /obj/item/gun/ballistic/automatic/pistol/antitank/syndicate, /obj/item/pda/syndicate, /obj/item/clothing/suit/armor/vest/capcarapace/syndicate, /obj/item/gun/ballistic/automatic/flechette, /obj/item/ammo_box/magazine/flechette, /obj/item/clothing/suit/toggle/lawyer/black/syndie, /obj/item/melee/transforming/energy/sword/cx/traitor,
/obj/structure/sign/poster/contraband/syndicate_pistol, /obj/structure/sign/poster/contraband/syndicate_recruitment, /obj/item/bedsheet/syndie, /obj/item/borg/upgrade/syndicate, /obj/item/tank/jetpack/oxygen/harness, /obj/item/firing_pin/implant/pindicate, /obj/item/reagent_containers/glass/bottle/traitor, /obj/item/storage/belt/military,
/obj/item/twohanded/shockpaddles/syndicate, /obj/item/clothing/mask/cigarette/syndicate, /obj/item/toy/plush/nukeplushie)),
/obj/item/shockpaddles/syndicate, /obj/item/clothing/mask/cigarette/syndicate, /obj/item/toy/plush/nukeplushie)),
"eye" = typecacheof(list(/obj/item/organ/eyes, /obj/item/reagent_containers/syringe))
)
+52 -1
View File
@@ -15,6 +15,8 @@ SUBSYSTEM_DEF(vote)
var/vote_system = PLURALITY_VOTING
var/question = null
var/list/choices = list()
/// List of choice = object for statclick objects for statpanel voting
var/list/choice_statclicks = list()
var/list/scores = list()
var/list/choice_descs = list() // optional descriptions
var/list/voted = list()
@@ -47,7 +49,33 @@ SUBSYSTEM_DEF(vote)
client_popup.open(0)
next_pop = world.time+VOTE_COOLDOWN
/**
* Renders a statpanel. Directly uses statpanel/stat calls since this is called from base of mob/Stat().
*/
/datum/controller/subsystem/vote/proc/render_statpanel(mob/M)
if(!mode) // check if vote is running
return
if(!statpanel("Status")) // don't bother if they're not focused on this panel
return
var/static/list/supported = list(PLURALITY_VOTING, APPROVAL_VOTING)
stat("Vote active!", "There is currently a vote running. Question: [question]")
if(!(vote_system in supported))
stat("<STATPANEL VOTING DISABLED>", "The current vote system is not supported by statpanel rendering. Please vote manually by opening the vote popup using the action button or chat link.")
return
stat("Time Left:", "[round(end_time - world.time)] seconds")
stat(null, null)
stat("Choices:", null)
stat(null, null)
for(var/i in 1 to choice_statclicks.len)
var/choice = choice_statclicks[i]
var/ivotedforthis = FALSE
switch(vote_system)
if(APPROVAL_VOTING)
ivotedforthis = voted[usr.ckey] && (i in voted[usr.ckey])
if(PLURALITY_VOTING)
ivotedforthis = voted[usr.ckey] == i
stat(ivotedforthis? "\[X\]" : "\[ \]", choice_statclicks[choice])
stat(null, null)
/datum/controller/subsystem/vote/proc/reset()
initiator = null
@@ -59,9 +87,26 @@ SUBSYSTEM_DEF(vote)
voted.Cut()
voting.Cut()
scores.Cut()
cleanup_statclicks()
display_votes = initial(display_votes) //CIT CHANGE - obfuscated votes
remove_action_buttons()
/datum/controller/subsystem/vote/proc/cleanup_statclicks()
for(var/choice in choice_statclicks)
qdel(choice_statclicks[choice])
choice_statclicks = list()
/obj/effect/statclick/vote
name = "ERROR"
var/choice
/obj/effect/statclick/vote/Click()
SSvote.submit_vote(choice)
/obj/effect/statclick/vote/New(loc, choice, name)
src.choice = choice
src.name = name
/datum/controller/subsystem/vote/proc/get_result()
//get the highest number of votes
var/greatest_votes = 0
@@ -536,6 +581,12 @@ SUBSYSTEM_DEF(vote)
vp = CONFIG_GET(number/vote_period)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=[REF(src)]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
end_time = started_time+vp
// generate statclick list
cleanup_statclicks()
for(var/i in 1 to choices.len)
var/choice = choices[i]
choice_statclicks[choice] = new /obj/effect/statclick/vote(null, i, choice)
//
for(var/c in GLOB.clients)
SEND_SOUND(c, sound('sound/misc/server-ready.ogg'))
var/client/C = c
+1 -1
View File
@@ -104,7 +104,7 @@
QDEL_IN(src, 300)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user)
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(user != seer || !linked_to)
return
var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\
+463
View File
@@ -0,0 +1,463 @@
/datum/component/personal_crafting/Initialize()
if(ismob(parent))
RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button)
/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL)
var/datum/hud/H = user.hud_used
var/obj/screen/craft/C = new()
C.icon = H.ui_style
H.static_inventory += C
CL.screen += C
RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact)
/datum/component/personal_crafting
var/busy
var/viewing_category = 1 //typical powergamer starting on the Weapons tab
var/viewing_subcategory = 1
var/list/categories = list(
CAT_WEAPONRY = list(
CAT_WEAPON,
CAT_AMMO,
),
CAT_ROBOT = CAT_NONE,
CAT_MISC = list(
CAT_MISCELLANEOUS,
CAT_TOOL,
CAT_FURNITURE,
),
CAT_PRIMAL = CAT_NONE,
CAT_FOOD = list(
CAT_BREAD,
CAT_BURGER,
CAT_CAKE,
CAT_DONUT,
CAT_EGG,
CAT_ICE,
CAT_MEAT,
CAT_MEXICAN,
CAT_MISCFOOD,
CAT_PASTRY,
CAT_PIE,
CAT_PIZZA,
CAT_SEAFOOD,
CAT_SALAD,
CAT_SANDWICH,
CAT_SOUP,
CAT_SPAGHETTI,
),
CAT_DRINK = CAT_NONE,
CAT_CLOTHING = CAT_NONE,
)
var/cur_category = CAT_NONE
var/cur_subcategory = CAT_NONE
var/datum/action/innate/crafting/button
var/display_craftable_only = FALSE
var/display_compact = TRUE
/* This is what procs do:
get_environment - gets a list of things accessable for crafting by user
get_surroundings - takes a list of things and makes a list of key-types to values-amounts of said type in the list
check_contents - takes a recipe and a key-type list and checks if said recipe can be done with available stuff
check_tools - takes recipe, a key-type list, and a user and checks if there are enough tools to do the stuff, checks bugs one level deep
construct_item - takes a recipe and a user, call all the checking procs, calls do_after, checks all the things again, calls del_reqs, creates result, calls CheckParts of said result with argument being list returned by deel_reqs
del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list
*/
/**
* Check that the contents of the recipe meet the requirements.
*
* user: The /mob that initated the crafting.
* R: The /datum/crafting_recipe being attempted.
* contents: List of items to search for R's reqs.
*/
/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents)
var/list/item_instances = contents["instances"]
contents = contents["other"]
var/list/requirements_list = list()
// Process all requirements
for(var/requirement_path in R.reqs)
// Check we have the appropriate amount available in the contents list
var/needed_amount = R.reqs[requirement_path]
for(var/content_item_path in contents)
// Right path and not blacklisted
if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path))
continue
needed_amount -= contents[content_item_path]
if(needed_amount <= 0)
break
if(needed_amount > 0)
return FALSE
// Store the instances of what we will use for R.check_requirements() for requirement_path
var/list/instances_list = list()
for(var/instance_path in item_instances)
if(ispath(instance_path, requirement_path))
instances_list += item_instances[instance_path]
requirements_list[requirement_path] = instances_list
for(var/requirement_path in R.chem_catalysts)
if(contents[requirement_path] < R.chem_catalysts[requirement_path])
return FALSE
return R.check_requirements(a, requirements_list)
/datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1)
. = list()
if(!isturf(a.loc))
return
for(var/atom/movable/AM in range(radius_range, a))
if(AM.flags_1 & HOLOGRAM_1)
continue
. += AM
/datum/component/personal_crafting/proc/get_surroundings(atom/a)
. = list()
.["tool_behaviour"] = list()
.["other"] = list()
.["instances"] = list()
for(var/obj/item/I in get_environment(a))
if(I.flags_1 & HOLOGRAM_1)
continue
if(.["instances"][I.type])
.["instances"][I.type] += I
else
.["instances"][I.type] = list(I)
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
.["other"][I.type] += S.amount
else if(I.tool_behaviour)
.["tool_behaviour"] += I.tool_behaviour
.["other"][I.type] += 1
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.is_drainable())
for(var/datum/reagent/A in RC.reagents.reagent_list)
.["other"][A.type] += A.volume
.["other"][I.type] += 1
/datum/component/personal_crafting/proc/check_tools(atom/a, datum/crafting_recipe/R, list/contents)
if(!R.tools.len)
return TRUE
var/list/possible_tools = list()
var/list/present_qualities = list()
present_qualities |= contents["tool_behaviour"]
for(var/obj/item/I in a.contents)
if(istype(I, /obj/item/storage))
for(var/obj/item/SI in I.contents)
possible_tools += SI.type
if(SI.tool_behaviour)
present_qualities.Add(SI.tool_behaviour)
possible_tools += I.type
if(I.tool_behaviour)
present_qualities.Add(I.tool_behaviour)
possible_tools |= contents["other"]
main_loop:
for(var/A in R.tools)
if(A in present_qualities)
continue
else
for(var/I in possible_tools)
if(ispath(I, A))
continue main_loop
return FALSE
return TRUE
/datum/component/personal_crafting/proc/construct_item(atom/a, datum/crafting_recipe/R)
var/list/contents = get_surroundings(a)
var/send_feedback = 1
if(check_contents(a, R, contents))
if(check_tools(a, R, contents))
//If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
if(ismob(a) && !do_after(a, R.time, target = a))
return "."
contents = get_surroundings(a)
if(!check_contents(a, R, contents))
return ", missing component."
if(!check_tools(a, R, contents))
return ", missing tool."
var/list/parts = del_reqs(R, a)
var/atom/movable/I = new R.result (get_turf(a.loc))
I.CheckParts(parts, R)
if(send_feedback)
SSblackbox.record_feedback("tally", "object_crafted", 1, I.type)
return I //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
return ", missing tool."
return ", missing component."
/*Del reqs works like this:
Loop over reqs var of the recipe
Set var amt to the value current cycle req is pointing to, its amount of type we need to delete
Get var/surroundings list of things accessable to crafting by get_environment()
Check the type of the current cycle req
If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings
If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list
If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one
If its stack check if it has enough amount
If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack
If no put all of the stack in the deletion list, substract its amount from amt and keep searching
While doing above stuff check deletion list if it already has such stack type, if yes try to merge them instead of adding new one
If its anything else just locate() in in the list in a while loop, each find --s the amt var and puts the found stuff in deletion loop
Then do a loop over parts var of the recipe
Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return
After its done loop over deletion list and delete all the shit that wasnt taken by parts loop
del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already
*/
/datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, atom/a)
var/list/surroundings
var/list/Deletion = list()
. = list()
var/data
var/amt
main_loop:
for(var/A in R.reqs)
amt = R.reqs[A]
surroundings = get_environment(a, R.blacklist)
surroundings -= Deletion
if(ispath(A, /datum/reagent))
var/datum/reagent/RG = new A
var/datum/reagent/RGNT
while(amt > 0)
var/obj/item/reagent_containers/RC = locate() in surroundings
RG = RC.reagents.get_reagent(A)
if(RG)
if(!locate(RG.type) in Deletion)
Deletion += new RG.type()
if(RG.volume > amt)
RG.volume -= amt
data = RG.data
RC.reagents.conditional_update(RC)
RG = locate(RG.type) in Deletion
RG.volume = amt
RG.data += data
continue main_loop
else
surroundings -= RC
amt -= RG.volume
RC.reagents.reagent_list -= RG
RC.reagents.conditional_update(RC)
RGNT = locate(RG.type) in Deletion
RGNT.volume += RG.volume
RGNT.data += RG.data
qdel(RG)
RC.on_reagent_change()
else
surroundings -= RC
else if(ispath(A, /obj/item/stack))
var/obj/item/stack/S
var/obj/item/stack/SD
while(amt > 0)
S = locate(A) in surroundings
if(S.amount >= amt)
if(!locate(S.type) in Deletion)
SD = new S.type()
Deletion += SD
S.use(amt)
SD = locate(S.type) in Deletion
SD.amount += amt
continue main_loop
else
amt -= S.amount
if(!locate(S.type) in Deletion)
Deletion += S
else
data = S.amount
S = locate(S.type) in Deletion
S.add(data)
surroundings -= S
else
var/atom/movable/I
while(amt > 0)
I = locate(A) in surroundings
Deletion += I
surroundings -= I
amt--
var/list/partlist = list(R.parts.len)
for(var/M in R.parts)
partlist[M] = R.parts[M]
for(var/A in R.parts)
if(istype(A, /datum/reagent))
var/datum/reagent/RG = locate(A) in Deletion
if(RG.volume > partlist[A])
RG.volume = partlist[A]
. += RG
Deletion -= RG
continue
else if(istype(A, /obj/item/stack))
var/obj/item/stack/ST = locate(A) in Deletion
if(ST.amount > partlist[A])
ST.amount = partlist[A]
. += ST
Deletion -= ST
continue
else
while(partlist[A] > 0)
var/atom/movable/AM = locate(A) in Deletion
. += AM
Deletion -= AM
partlist[A] -= 1
while(Deletion.len)
var/DL = Deletion[Deletion.len]
Deletion.Cut(Deletion.len)
qdel(DL)
/datum/component/personal_crafting/proc/component_ui_interact(obj/screen/craft/image, location, control, params, user)
if(user == parent)
ui_interact(user)
//For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom
/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
cur_category = categories[1]
if(islist(categories[cur_category]))
var/list/subcats = categories[cur_category]
cur_subcategory = subcats[1]
else
cur_subcategory = CAT_NONE
ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state)
ui.open()
/datum/component/personal_crafting/ui_data(mob/user)
var/list/data = list()
data["busy"] = busy
data["category"] = cur_category
data["subcategory"] = cur_subcategory
data["display_craftable_only"] = display_craftable_only
data["display_compact"] = display_compact
var/list/surroundings = get_surroundings(user)
var/list/craftability = list()
for(var/rec in GLOB.crafting_recipes)
var/datum/crafting_recipe/R = rec
if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
continue
if((R.category != cur_category) || (R.subcategory != cur_subcategory))
continue
craftability["[REF(R)]"] = check_contents(user, R, surroundings)
data["craftability"] = craftability
return data
/datum/component/personal_crafting/ui_static_data(mob/user)
var/list/data = list()
var/list/crafting_recipes = list()
for(var/rec in GLOB.crafting_recipes)
var/datum/crafting_recipe/R = rec
if(R.name == "") //This is one of the invalid parents that sneaks in
continue
if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
continue
if(isnull(crafting_recipes[R.category]))
crafting_recipes[R.category] = list()
if(R.subcategory == CAT_NONE)
crafting_recipes[R.category] += list(build_recipe_data(R))
else
if(isnull(crafting_recipes[R.category][R.subcategory]))
crafting_recipes[R.category][R.subcategory] = list()
crafting_recipes[R.category]["has_subcats"] = TRUE
crafting_recipes[R.category][R.subcategory] += list(build_recipe_data(R))
data["crafting_recipes"] = crafting_recipes
return data
/datum/component/personal_crafting/ui_act(action, params)
if(..())
return
switch(action)
if("make")
var/mob/user = usr
var/datum/crafting_recipe/TR = locate(params["recipe"]) in GLOB.crafting_recipes
busy = TRUE
ui_interact(user)
var/atom/movable/result = construct_item(user, TR)
if(!istext(result)) //We made an item and didn't get a fail message
if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine
user.put_in_hands(result)
else
result.forceMove(user.drop_location())
to_chat(user, "<span class='notice'>[TR.name] constructed.</span>")
else
to_chat(user, "<span class='warning'>Construction failed[result]</span>")
busy = FALSE
if("toggle_recipes")
display_craftable_only = !display_craftable_only
. = TRUE
if("toggle_compact")
display_compact = !display_compact
. = TRUE
if("set_category")
if(!isnull(params["category"]))
cur_category = params["category"]
if(!isnull(params["subcategory"]))
if(params["subcategory"] == "0")
cur_subcategory = ""
else
cur_subcategory = params["subcategory"]
. = TRUE
/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
var/list/data = list()
data["name"] = R.name
data["ref"] = "[REF(R)]"
var/req_text = ""
var/tool_text = ""
var/catalyst_text = ""
for(var/a in R.reqs)
//We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var)
//Also these are typepaths so sadly we can't just do "[a]"
var/atom/A = a
req_text += " [R.reqs[A]] [initial(A.name)],"
req_text = replacetext(req_text,",","",-1)
data["req_text"] = req_text
for(var/a in R.chem_catalysts)
var/atom/A = a //cheat-typecast
catalyst_text += " [R.chem_catalysts[A]] [initial(A.name)],"
catalyst_text = replacetext(catalyst_text,",","",-1)
data["catalyst_text"] = catalyst_text
for(var/a in R.tools)
if(ispath(a, /obj/item))
var/obj/item/b = a
tool_text += " [initial(b.name)],"
else
tool_text += " [a],"
tool_text = replacetext(tool_text,",","",-1)
data["tool_text"] = tool_text
return data
//Mind helpers
/datum/mind/proc/teach_crafting_recipe(R)
if(!learned_recipes)
learned_recipes = list()
learned_recipes |= R
+11 -51
View File
@@ -1,4 +1,4 @@
k// PARTS //
// PARTS //
/obj/item/weaponcrafting
icon = 'icons/obj/improvised.dmi'
@@ -8,61 +8,33 @@ k// PARTS //
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 6)
icon_state = "riflestock"
/obj/item/weaponcrafting/durathread_string
name = "durathread string"
desc = "A long piece of durathread with some resemblance to cable coil."
/obj/item/weaponcrafting/string
name = "wound thread"
desc = "A long piece of thread with some resemblance to cable coil."
icon_state = "durastring"
////////////////////////////////
// KAT IMPROVISED WEAPON PARTS//
// IMPROVISED WEAPON PARTS//
////////////////////////////////
/obj/item/weaponcrafting/improvised_parts
name = "Eerie bunch of coloured dots."
desc = "You feel the urge to report to Central that the parent type of guncrafting, which should never appear in this reality, has appeared. Whatever that means."
name = "Debug Improvised Gun Part"
desc = "A badly coded gun part. You should report coders if you see this."
icon = 'icons/obj/guns/gun_parts.dmi'
icon_state = "palette"
// BARRELS
/obj/item/weaponcrafting/improvised_parts/barrel_rifle
name = "rifle barrel"
desc = "A pipe with a diameter just the right size to fire 7.62 rounds out of."
icon_state = "barrel_rifle"
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun
name = "shotgun barrel"
desc = "A twenty bore shotgun barrel."
icon_state = "barrel_shotgun"
/obj/item/weaponcrafting/improvised_parts/barrel_pistol
name = "pistol barrel"
desc = "A pipe with a small diameter and some holes finely cut into it. It fits .32 ACP bullets. Probably."
icon_state = "barrel_pistol"
w_class = WEIGHT_CLASS_SMALL
// RECEIVERS
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
name = "bolt action receiver"
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle. It's generic enough to modify to create other rifles, potentially."
name = "rifle receiver"
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle." // removed some text implying that the item had more uses than it does
icon_state = "receiver_rifle"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/pistol_receiver
name = "pistol receiver"
desc = "A receiver to connect house and connects all the parts to make an improvised pistol."
icon_state = "receiver_pistol"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/laser_receiver
name = "energy emitter assembly"
desc = "A mixture of components haphazardly wired together to form an energy emitter."
icon_state = "laser_assembly"
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
name = "break-action assembly"
desc = "An improvised receiver to create a break-action breechloaded shotgun. Parts of this are still useful if you want to make another type of shotgun, however."
name = "shotgun reciever"
desc = "An improvised receiver to create a break-action breechloaded shotgun." // removed some text implying that the item had more uses than it does
icon_state = "receiver_shotgun"
w_class = WEIGHT_CLASS_SMALL
@@ -78,15 +50,3 @@ k// PARTS //
name = "wooden firearm body"
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
icon_state = "wooden_body"
/obj/item/weaponcrafting/improvised_parts/wooden_grip
name = "wooden pistol grip"
desc = "A nice wooden grip hollowed out for pistol magazines."
icon_state = "wooden_pistolgrip"
w_class = WEIGHT_CLASS_SMALL
/obj/item/weaponcrafting/improvised_parts/makeshift_lens
name = "makeshift focusing lens"
desc = "A properly made lens made with actual glassworking tools would perform much better, but this will have to do."
icon_state = "focusing_lens"
w_class = WEIGHT_CLASS_TINY
@@ -244,7 +244,7 @@
/datum/crafting_recipe/rcl
name = "Makeshift Rapid Cable Layer"
result = /obj/item/twohanded/rcl/ghetto
result = /obj/item/rcl/ghetto
time = 40
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
reqs = list(/obj/item/stack/sheet/metal = 15)
@@ -50,7 +50,7 @@
/datum/crafting_recipe/bonespear
name = "Bone Spear"
result = /obj/item/twohanded/bonespear
result = /obj/item/spear/bonespear
time = 30
reqs = list(/obj/item/stack/sheet/bone = 4,
/obj/item/stack/sheet/sinew = 1)
@@ -58,7 +58,7 @@
/datum/crafting_recipe/boneaxe
name = "Bone Axe"
result = /obj/item/twohanded/fireaxe/boneaxe
result = /obj/item/fireaxe/boneaxe
time = 50
reqs = list(/obj/item/stack/sheet/bone = 6,
/obj/item/stack/sheet/sinew = 3)
@@ -74,20 +74,20 @@
/datum/crafting_recipe/headpike
name = "Spike Head (Glass Spear)"
time = 65
reqs = list(/obj/item/twohanded/spear = 1,
reqs = list(/obj/item/spear = 1,
/obj/item/bodypart/head = 1)
parts = list(/obj/item/bodypart/head = 1,
/obj/item/twohanded/spear = 1)
/obj/item/spear = 1)
result = /obj/structure/headpike
category = CAT_PRIMAL
/datum/crafting_recipe/headpikebone
name = "Spike Head (Bone Spear)"
time = 65
reqs = list(/obj/item/twohanded/bonespear = 1,
reqs = list(/obj/item/spear/bonespear = 1,
/obj/item/bodypart/head = 1)
parts = list(/obj/item/bodypart/head = 1,
/obj/item/twohanded/bonespear = 1)
/obj/item/spear/bonespear = 1)
result = /obj/structure/headpike/bone
category = CAT_PRIMAL
@@ -103,7 +103,7 @@
/datum/crafting_recipe/bone_bow
name = "Bone Bow"
result = /obj/item/gun/ballistic/bow/ashen
time = 200
time = 120 // 80+120 = 200
always_availible = FALSE
reqs = list(/obj/item/stack/sheet/bone = 8,
/obj/item/stack/sheet/sinew = 4)
@@ -112,7 +112,7 @@
/datum/crafting_recipe/bow_tablet
name = "Sandstone Bow Making Manual"
result = /obj/item/book/granter/crafting_recipe/bone_bow
time = 600 //Scribing
time = 200 //Scribing // don't care
always_availible = FALSE
reqs = list(/obj/item/stack/rods = 1,
/obj/item/stack/sheet/mineral/sandstone = 4)
@@ -42,7 +42,7 @@
/datum/crafting_recipe/spear
name = "Spear"
result = /obj/item/twohanded/spear
result = /obj/item/spear
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
/obj/item/shard = 1,
/obj/item/stack/rods = 1)
@@ -110,7 +110,7 @@
/datum/crafting_recipe/chainsaw
name = "Chainsaw"
result = /obj/item/twohanded/required/chainsaw
result = /obj/item/chainsaw
reqs = list(/obj/item/circular_saw = 1,
/obj/item/stack/cable_coil = 3,
/obj/item/stack/sheet/plasteel = 5)
@@ -141,7 +141,7 @@
result = /obj/item/bombcore/chemical
reqs = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/twohanded/required/gibtonite = 1,
/obj/item/gibtonite = 1,
/obj/item/grenade/chem_grenade = 2
)
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
@@ -173,10 +173,10 @@
/datum/crafting_recipe/lance
name = "Explosive Lance (Grenade)"
result = /obj/item/twohanded/spear
reqs = list(/obj/item/twohanded/spear = 1,
result = /obj/item/spear
reqs = list(/obj/item/spear = 1,
/obj/item/grenade = 1)
parts = list(/obj/item/twohanded/spear = 1,
parts = list(/obj/item/spear = 1,
/obj/item/grenade = 1)
time = 15
category = CAT_WEAPONRY
@@ -192,8 +192,8 @@
result = /obj/item/gun/ballistic/bow/pipe
reqs = list(/obj/item/pipe = 5,
/obj/item/stack/sheet/plastic = 15,
/obj/item/weaponcrafting/durathread_string = 5)
time = 450
/obj/item/weaponcrafting/string = 5)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
@@ -248,10 +248,10 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ishotgun
/datum/crafting_recipe/ishotgun // smaller and more versatile gun requires some better materials
name = "Improvised Shotgun"
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 1,
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
@@ -262,10 +262,10 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/irifle
/datum/crafting_recipe/irifle // larger and less versatile gun, but a bit easier to make
name = "Improvised Rifle (7.62mm)"
result = /obj/item/gun/ballistic/shotgun/boltaction/improvised
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 1,
reqs = list(/obj/item/pipe = 2, // above
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
@@ -276,49 +276,6 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ipistol
name = "Improvised Pistol (.32)"
result = /obj/item/gun/ballistic/automatic/pistol/improvised/nomag
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 1,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/wooden_grip = 1,
/obj/item/stack/sheet/plastic = 15,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_WIRECUTTER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ilaser
name = "Improvised Energy Gun"
result = /obj/item/gun/energy/e_gun/old/improvised
reqs = list(/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 1,
/obj/item/stock_parts/cell = 1,
/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 5,
/obj/item/stack/cable_coil = 10)
tools = list(TOOL_SCREWDRIVER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
/datum/crafting_recipe/ilaser/upgraded
name = "Improvised Energy Gun Upgrade"
result = /obj/item/gun/energy/e_gun/old/improvised/upgraded
reqs = list(/obj/item/gun/energy/e_gun/old/improvised = 1,
/obj/item/glasswork/glass_base/lens = 1,
/obj/item/stock_parts/capacitor/quadratic = 2,
/obj/item/stock_parts/micro_laser/ultra = 1,
/obj/item/stock_parts/cell/bluespace = 1,
/obj/item/stack/cable_coil = 5)
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
//////////////////
///AMMO CRAFTING//
//////////////////
@@ -326,9 +283,9 @@
/datum/crafting_recipe/arrow
name = "Arrow"
result = /obj/item/ammo_casing/caseless/arrow/wood
time = 30
time = 5 // these only do 15 damage
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
/obj/item/stack/sheet/durathread = 1,
/obj/item/stack/sheet/cloth = 1,
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
category = CAT_WEAPONRY
subcategory = CAT_AMMO
@@ -336,7 +293,7 @@
/datum/crafting_recipe/bone_arrow
name = "Bone Arrow"
result = /obj/item/ammo_casing/caseless/arrow/bone
time = 30
time = 5
always_availible = FALSE
reqs = list(/obj/item/stack/sheet/bone = 1,
/obj/item/stack/sheet/sinew = 1,
@@ -348,7 +305,7 @@
name = "Ashen Arrow"
result = /obj/item/ammo_casing/caseless/arrow/ash
tools = list(TOOL_WELDER)
time = 30
time = 10 // 1.5 seconds minimum per actually worthwhile arrow excluding interface lag
always_availible = FALSE
reqs = list(/obj/item/ammo_casing/caseless/arrow/wood = 1)
category = CAT_WEAPONRY
@@ -442,92 +399,28 @@
category = CAT_WEAPONRY
subcategory = CAT_AMMO
/datum/crafting_recipe/m32acp
name = ".32ACP Empty Magazine"
result = /obj/item/ammo_box/magazine/m32acp/empty
reqs = list(/obj/item/stack/sheet/metal = 3,
/obj/item/stack/sheet/plasteel = 1,
/obj/item/stack/packageWrap = 1)
tools = list(TOOL_WELDER,TOOL_SCREWDRIVER)
time = 5
category = CAT_WEAPONRY
subcategory = CAT_AMMO
////////////////////
// PARTS CRAFTING //
////////////////////
// BARRELS
/datum/crafting_recipe/rifle_barrel
name = "Improvised Rifle Barrel"
result = /obj/item/weaponcrafting/improvised_parts/barrel_rifle
reqs = list(/obj/item/pipe = 2)
tools = list(TOOL_WELDER,TOOL_SAW)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/shotgun_barrel
name = "Improvised Shotgun Barrel"
result = /obj/item/weaponcrafting/improvised_parts/barrel_shotgun
reqs = list(/obj/item/pipe = 2)
tools = list(TOOL_WELDER,TOOL_SAW)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/pistol_barrel
name = "Improvised Pistol Barrel"
result = /obj/item/weaponcrafting/improvised_parts/barrel_pistol
reqs = list(/obj/item/pipe = 1,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_WELDER,TOOL_SAW)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
// RECEIVERS
/datum/crafting_recipe/rifle_receiver
name = "Improvised Rifle Receiver"
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 1)
reqs = list(/obj/item/stack/sheet/metal = 15) // you can carry multiple shotguns
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
time = 50
time = 25
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/shotgun_receiver
name = "Improvised Shotgun Receiver"
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Dual wielding has been removed, plasteel is a soft timesink to obtain for most to make mass production harder.
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/pistol_receiver
name = "Improvised Pistol Receiver"
result = /obj/item/weaponcrafting/improvised_parts/pistol_receiver
reqs = list(/obj/item/stack/sheet/metal = 5,
/obj/item/stack/sheet/plasteel = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_SAW)
time = 50
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/laser_receiver
name = "Energy Weapon Assembly"
result = /obj/item/weaponcrafting/improvised_parts/laser_receiver
reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stock_parts/capacitor = 2,
/obj/item/stock_parts/micro_laser = 1,
/obj/item/assembly/prox_sensor = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WELDER) // Prox sensor and multitool for the circuit board, welder for extremely ghetto soldering.
time = 150
reqs = list(/obj/item/stack/sheet/metal = 15,
/obj/item/stack/sheet/plasteel = 1) // requires access or hacking since shotgun is better
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
time = 25
category = CAT_WEAPONRY
subcategory = CAT_PARTS
@@ -539,16 +432,6 @@
reqs = list(/obj/item/stack/sheet/metal = 3,
/obj/item/assembly/igniter = 1)
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
time = 150
category = CAT_WEAPONRY
subcategory = CAT_PARTS
/datum/crafting_recipe/makeshift_lens
name = "Makeshift Lens"
result = /obj/item/weaponcrafting/improvised_parts/makeshift_lens
reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/sheet/glass = 2)
tools = list(TOOL_WELDER) // Glassmaking lets you make non-makeshift lenses.
time = 50
time = 25
category = CAT_WEAPONRY
subcategory = CAT_PARTS
+2 -1
View File
@@ -51,7 +51,8 @@ Behavior that's still missing from this component that original food items had t
var/atom/owner = parent
owner.create_reagents(volume, INJECTABLE)
if(!owner.reagents) //we don't want to override what's in the item if it possibly contains reagents already
owner.create_reagents(volume, INJECTABLE)
if(initial_reagents)
for(var/rid in initial_reagents)
+107
View File
@@ -0,0 +1,107 @@
/*!
This component essentially encapsulates frying and utilizes the edible component
This means fried items can work like regular ones, and generally the code is far less messy
*/
/datum/component/fried
var/fry_power //how powerfully was this item fried
var/atom/owner //the atom it is owned by
var/stored_name //name of the owner when the component was first added
var/frying_examine_text = "the coders messed frying code up, report this!"
/datum/component/fried/Initialize(frying_power)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/restore) //basically, unfry people who are being cleaned (badmemes fried someone)
fry_power = frying_power
owner = parent
stored_name = owner.name
setup_fried_item()
//some stuff to do with the contents of fried junk
GLOBAL_VAR_INIT(frying_hardmode, TRUE)
GLOBAL_VAR_INIT(frying_bad_chem_add_volume, TRUE)
GLOBAL_LIST_INIT(frying_bad_chems, list(
/datum/reagent/toxin/bad_food = 1,
/datum/reagent/toxin = 1,
/datum/reagent/lithium = 1,
/datum/reagent/mercury = 1,
))
/datum/component/fried/proc/examine(datum/source, mob/user, list/examine_list)
examine_list += "[parent] has been [frying_examine_text]"
/datum/component/fried/proc/setup_fried_item() //sets the name, colour and examine text and edibility up
//first we do some checks depending on the type of item being fried
var/list/fried_tastes = list("crispy")
var/fried_foodtypes = FRIED
var/fried_junk = FALSE
if(!isfood(owner) && GLOB.frying_hardmode && GLOB.frying_bad_chems.len && !owner.reagents) //you fried some junk, it's not gonna taste great
fried_junk = TRUE
fried_foodtypes |= TOXIC // junk tastes toxic too
else
if(isfood(owner))
var/obj/item/reagent_containers/food/snacks/food_item = owner
fried_tastes += food_item.tastes
fried_foodtypes |= food_item.foodtype
var/fried_eat_time = 0
if(isturf(owner))
fried_eat_time = 30 //we want turfs to be eaten slowly
var/colour_priority = FIXED_COLOUR_PRIORITY
if(ismob(owner))
colour_priority = WASHABLE_COLOUR_PRIORITY //badmins fried someone and we want to let them wash the fry colour off
//lets heavily hint at how to undo their frying
to_chat(owner, "<span class='warning'>You've been coated in hot cooking oil! You should probably go wash it off at the showers.</span>")
else
owner.AddComponent(/datum/component/edible, foodtypes = fried_tastes, tastes = fried_tastes, eat_time = fried_eat_time) //we don't want mobs to get the edible component
switch(fry_power)
if(0 to 15)
owner.name = "lightly fried [owner.name]"
owner.add_atom_colour(rgb(166,103,54), colour_priority)
frying_examine_text = "lightly fried"
if(16 to 49)
owner.name = "fried [owner.name]"
owner.add_atom_colour(rgb(103,63,24), colour_priority)
frying_examine_text = "moderately fried"
if(50 to 59)
owner.name = "deep fried [owner.name]"
owner.add_atom_colour(rgb(63,23,4), colour_priority)
frying_examine_text = "deeply fried"
else
owner.name = "the physical manifestation of fried foods"
owner.add_atom_colour(rgb(33,19,9), colour_priority)
frying_examine_text = "incomprehensibly fried to a crisp"
//adding the edible component gives it reagents meaning we can now add the bad frying reagents if it's junk
if(fried_junk && owner.reagents) //check again just incase
var/R = rand(1, GLOB.frying_bad_chems.len)
var/bad_chem = GLOB.frying_bad_chems[R]
var/bad_chem_amount = max(4,GLOB.frying_bad_chems[bad_chem] * (fry_power/12.5)) //4u of bad chem reached when deeply fried
owner.reagents.add_reagent(bad_chem, bad_chem_amount)
/datum/component/fried/proc/restore_name() //restore somethings name
//we do string manipulation and not restoring their name to real_name because some things hide your real_name and we want to maintain that
if(copytext(owner.name,1,14) == "lightly fried ")
owner.name = copytext(owner.name,15)
else
if(copytext(owner.name,1,6) == "fried ")
owner.name = copytext(owner.name,7)
else
if(copytext(owner.name,1,11) == "deep fried ")
owner.name = copytext(owner.name, 12)
else
if(owner.name == "the physical manifestation of fried foods") //if the name is still this, their name hasn't changed, so we can safely restore their stored name
owner.name = stored_name
/datum/component/fried/proc/restore() //restore a fried mob to being not-fried
if(ismob(owner))
//restore the name, the colour should wash off itself, and then remove the component
restore_name()
RemoveComponent()
+153
View File
@@ -0,0 +1,153 @@
///Global GPS_list. All GPS components get saved in here for easy reference.
GLOBAL_LIST_EMPTY(GPS_list)
///GPS component. Atoms that have this show up on gps. Pretty simple stuff.
/datum/component/gps
var/gpstag = "COM0"
var/tracking = TRUE
var/emped = FALSE
/datum/component/gps/Initialize(_gpstag = "COM0")
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
gpstag = _gpstag
GLOB.GPS_list += src
/datum/component/gps/Destroy()
GLOB.GPS_list -= src
return ..()
///GPS component subtype. Only gps/item's can be used to open the UI.
/datum/component/gps/item
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE)
. = ..()
if(. == COMPONENT_INCOMPATIBLE || !isitem(parent))
return COMPONENT_INCOMPATIBLE
var/atom/A = parent
A.add_overlay("working")
A.name = "[initial(A.name)] ([gpstag])"
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
if(!emp_proof)
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick)
///Called on COMSIG_ITEM_ATTACK_SELF
/datum/component/gps/item/proc/interact(datum/source, mob/user)
if(user)
ui_interact(user)
///Called on COMSIG_PARENT_EXAMINE
/datum/component/gps/item/proc/on_examine(datum/source, mob/user, list/examine_list)
examine_list += "<span class='notice'>Alt-click to switch it [tracking ? "off":"on"].</span>"
///Called on COMSIG_ATOM_EMP_ACT
/datum/component/gps/item/proc/on_emp_act(datum/source, severity)
emped = TRUE
var/atom/A = parent
A.cut_overlay("working")
A.add_overlay("emp")
addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
SStgui.close_uis(src) //Close the UI control if it is open.
///Restarts the GPS after getting turned off by an EMP.
/datum/component/gps/item/proc/reboot()
emped = FALSE
var/atom/A = parent
A.cut_overlay("emp")
A.add_overlay("working")
///Calls toggletracking
/datum/component/gps/item/proc/on_AltClick(datum/source, mob/user)
toggletracking(user)
///Toggles the tracking for the gps
/datum/component/gps/item/proc/toggletracking(mob/user)
if(!user.canUseTopic(parent, BE_CLOSE))
return //user not valid to use gps
if(emped)
to_chat(user, "<span class='warning'>It's busted!</span>")
return
var/atom/A = parent
if(tracking)
A.cut_overlay("working")
to_chat(user, "<span class='notice'>[parent] is no longer tracking, or visible to other GPS devices.</span>")
tracking = FALSE
else
A.add_overlay("working")
to_chat(user, "<span class='notice'>[parent] is now tracking, and visible to other GPS devices.</span>")
tracking = TRUE
/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
if(emped)
to_chat(user, "<span class='hear'>[parent] fizzles weakly.</span>")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// Variable window height, depending on how many GPS units there are
// to show, clamped to relatively safe range.
var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700)
ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
ui.open()
ui.set_autoupdate(state = updating)
/datum/component/gps/item/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(parent)
data["currentArea"] = "[get_area_name(curr, TRUE)]"
data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
var/list/signals = list()
data["signals"] = list()
for(var/gps in GLOB.GPS_list)
var/datum/component/gps/G = gps
if(G.emped || !G.tracking || G == src)
continue
var/turf/pos = get_turf(G.parent)
if(!pos || !global_mode && pos.z != curr.z)
continue
var/list/signal = list()
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
signal["coords"] = "[pos.x], [pos.y], [pos.z]"
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/datum/component/gps/item/ui_act(action, params)
if(..())
return
switch(action)
if("rename")
var/atom/parentasatom = parent
var/a = stripped_input(usr, "Please enter desired tag.", parentasatom.name, gpstag, 20)
if (!a)
return
gpstag = a
. = TRUE
parentasatom.name = "global positioning system ([gpstag])"
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE
+1 -1
View File
@@ -105,7 +105,7 @@
/// Proc specifically for inserting items, returns the amount of materials entered.
/datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1, stack_amt)
if(!I)
if(QDELETED(I))
return FALSE
multiplier = CEILING(multiplier, 0.01)
@@ -34,3 +34,8 @@
qdel(A)
return
. = ..()
/datum/component/storage/concrete/bluespace/bag_of_holding/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
if(I.GetComponent(/datum/component/storage/concrete/bluespace/bag_of_holding))
return TRUE
return ..()
+311
View File
@@ -0,0 +1,311 @@
/**
* Two Handed Component
*
* When applied to an item it will make it two handed
*
*/
/datum/component/two_handed
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item
var/wielded = FALSE /// Are we holding the two handed item properly
var/force_multiplier = 0 /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded
var/force_wielded = 0 /// The force of the item when weilded
var/force_unwielded = 0 /// The force of the item when unweilded
var/wieldsound = FALSE /// Play sound when wielded
var/unwieldsound = FALSE /// Play sound when unwielded
var/attacksound = FALSE /// Play sound on attack when wielded
var/require_twohands = FALSE /// Does it have to be held in both hands
var/icon_wielded = FALSE /// The icon that will be used when wielded
var/obj/item/offhand/offhand_item = null /// Reference to the offhand created for the item
var/sharpened_increase = 0 /// The amount of increase recived from sharpening the item
/**
* Two Handed component
*
* vars:
* * require_twohands (optional) Does the item need both hands to be carried
* * wieldsound (optional) The sound to play when wielded
* * unwieldsound (optional) The sound to play when unwielded
* * attacksound (optional) The sound to play when wielded and attacking
* * force_multiplier (optional) The force multiplier when wielded, do not use with force_wielded, and force_unwielded
* * force_wielded (optional) The force setting when the item is wielded, do not use with force_multiplier
* * force_unwielded (optional) The force setting when the item is unwielded, do not use with force_multiplier
* * icon_wielded (optional) The icon to be used when wielded
*/
/datum/component/two_handed/Initialize(require_twohands=FALSE, wieldsound=FALSE, unwieldsound=FALSE, attacksound=FALSE, \
force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
src.require_twohands = require_twohands
src.wieldsound = wieldsound
src.unwieldsound = unwieldsound
src.attacksound = attacksound
src.force_multiplier = force_multiplier
src.force_wielded = force_wielded
src.force_unwielded = force_unwielded
src.icon_wielded = icon_wielded
// Inherit the new values passed to the component
/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, \
force_multiplier, force_wielded, force_unwielded, icon_wielded)
if(!original)
return
if(require_twohands)
src.require_twohands = require_twohands
if(wieldsound)
src.wieldsound = wieldsound
if(unwieldsound)
src.unwieldsound = unwieldsound
if(attacksound)
src.attacksound = attacksound
if(force_multiplier)
src.force_multiplier = force_multiplier
if(force_wielded)
src.force_wielded = force_wielded
if(force_unwielded)
src.force_unwielded = force_unwielded
if(icon_wielded)
src.icon_wielded = icon_wielded
// register signals withthe parent item
/datum/component/two_handed/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/on_attack_self)
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/on_attack)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON, .proc/on_update_icon)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_moved)
RegisterSignal(parent, COMSIG_ITEM_SHARPEN_ACT, .proc/on_sharpen)
// Remove all siginals registered to the parent item
/datum/component/two_handed/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED,
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_ATTACK_SELF,
COMSIG_ITEM_ATTACK,
COMSIG_ATOM_UPDATE_ICON,
COMSIG_MOVABLE_MOVED,
COMSIG_ITEM_SHARPEN_ACT))
/// Triggered on equip of the item containing the component
/datum/component/two_handed/proc/on_equip(datum/source, mob/user, slot)
if(require_twohands && slot == SLOT_HANDS) // force equip the item
wield(user)
if(!user.is_holding(parent) && wielded && !require_twohands)
unwield(user)
/// Triggered on drop of item containing the component
/datum/component/two_handed/proc/on_drop(datum/source, mob/user)
if(require_twohands)
unwield(user, show_message=TRUE)
if(wielded)
unwield(user)
if(source == offhand_item && !QDELETED(src))
qdel(src)
/// Triggered on attack self of the item containing the component
/datum/component/two_handed/proc/on_attack_self(datum/source, mob/user)
if(wielded)
unwield(user)
else
wield(user)
/**
* Wield the two handed item in both hands
*
* vars:
* * user The mob/living/carbon that is wielding the item
*/
/datum/component/two_handed/proc/wield(mob/living/carbon/user)
if(wielded)
return
if(ismonkey(user))
to_chat(user, "<span class='warning'>It's too heavy for you to wield fully.</span>")
return
if(user.get_inactive_held_item())
if(require_twohands)
to_chat(user, "<span class='notice'>[parent] is too cumbersome to carry in one hand!</span>")
user.dropItemToGround(parent, force=TRUE)
else
to_chat(user, "<span class='warning'>You need your other hand to be empty!</span>")
return
if(user.get_num_arms() < 2)
if(require_twohands)
user.dropItemToGround(parent, force=TRUE)
to_chat(user, "<span class='warning'>You don't have enough intact hands.</span>")
return
// wield update status
if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELD, user) & COMPONENT_TWOHANDED_BLOCK_WIELD)
return // blocked wield from item
wielded = TRUE
RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands)
// update item stats and name
var/obj/item/parent_item = parent
if(force_multiplier)
parent_item.force *= force_multiplier
else if(force_wielded)
parent_item.force = force_wielded
if(sharpened_increase)
parent_item.force += sharpened_increase
parent_item.name = "[parent_item.name] (Wielded)"
parent_item.update_icon()
if(iscyborg(user))
to_chat(user, "<span class='notice'>You dedicate your module to [parent].</span>")
else
to_chat(user, "<span class='notice'>You grab [parent] with both hands.</span>")
// Play sound if one is set
if(wieldsound)
playsound(parent_item.loc, wieldsound, 50, TRUE)
// Let's reserve the other hand
offhand_item = new(user)
offhand_item.name = "[parent_item.name] - offhand"
offhand_item.desc = "Your second grip on [parent_item]."
offhand_item.wielded = TRUE
RegisterSignal(offhand_item, COMSIG_ITEM_DROPPED, .proc/on_drop)
user.put_in_inactive_hand(offhand_item)
/**
* Unwield the two handed item
*
* vars:
* * user The mob/living/carbon that is unwielding the item
* * show_message (option) show a message to chat on unwield
*/
/datum/component/two_handed/proc/unwield(mob/living/carbon/user, show_message=TRUE)
if(!wielded || !user)
return
// wield update status
wielded = FALSE
UnregisterSignal(user, COMSIG_MOB_SWAP_HANDS)
SEND_SIGNAL(parent, COMSIG_TWOHANDED_UNWIELD, user)
// update item stats
var/obj/item/parent_item = parent
if(sharpened_increase)
parent_item.force -= sharpened_increase
if(force_multiplier)
parent_item.force /= force_multiplier
else if(force_unwielded)
parent_item.force = force_unwielded
// update the items name to remove the wielded status
var/sf = findtext(parent_item.name, " (Wielded)", -10) // 10 == length(" (Wielded)")
if(sf)
parent_item.name = copytext(parent_item.name, 1, sf)
else
parent_item.name = "[initial(parent_item.name)]"
// Update icons
parent_item.update_icon()
if(user.get_item_by_slot(ITEM_SLOT_BACK) == parent)
user.update_inv_back()
else
user.update_inv_hands()
// if the item requires two handed drop the item on unwield
if(require_twohands)
user.dropItemToGround(parent, force=TRUE)
// Show message if requested
if(show_message)
if(iscyborg(user))
to_chat(user, "<span class='notice'>You free up your module.</span>")
else if(require_twohands)
to_chat(user, "<span class='notice'>You drop [parent].</span>")
else
to_chat(user, "<span class='notice'>You are now carrying [parent] with one hand.</span>")
// Play sound if set
if(unwieldsound)
playsound(parent_item.loc, unwieldsound, 50, TRUE)
// Remove the object in the offhand
if(offhand_item)
UnregisterSignal(offhand_item, COMSIG_ITEM_DROPPED)
qdel(offhand_item)
// Clear any old refrence to an item that should be gone now
offhand_item = null
/**
* on_attack triggers on attack with the parent item
*/
/datum/component/two_handed/proc/on_attack(obj/item/source, mob/living/target, mob/living/user)
if(wielded && attacksound)
var/obj/item/parent_item = parent
playsound(parent_item.loc, attacksound, 50, TRUE)
/**
* on_update_icon triggers on call to update parent items icon
*
* Updates the icon using icon_wielded if set
*/
/datum/component/two_handed/proc/on_update_icon(datum/source)
if(icon_wielded && wielded)
var/obj/item/parent_item = parent
if(parent_item)
parent_item.icon_state = icon_wielded
return COMSIG_ATOM_NO_UPDATE_ICON_STATE
/**
* on_moved Triggers on item moved
*/
/datum/component/two_handed/proc/on_moved(datum/source, mob/user, dir)
unwield(user)
/**
* on_swap_hands Triggers on swapping hands, blocks swap if the other hand is busy
*/
/datum/component/two_handed/proc/on_swap_hands(mob/user, obj/item/held_item)
if(!held_item)
return
if(held_item == parent)
return COMPONENT_BLOCK_SWAP
/**
* on_sharpen Triggers on usage of a sharpening stone on the item
*/
/datum/component/two_handed/proc/on_sharpen(obj/item/item, amount, max_amount)
if(!item)
return COMPONENT_BLOCK_SHARPEN_BLOCKED
if(sharpened_increase)
return COMPONENT_BLOCK_SHARPEN_ALREADY
var/wielded_val = 0
if(force_multiplier)
var/obj/item/parent_item = parent
if(wielded)
wielded_val = parent_item.force
else
wielded_val = parent_item.force * force_multiplier
else
wielded_val = force_wielded
if(wielded_val > max_amount)
return COMPONENT_BLOCK_SHARPEN_MAXED
sharpened_increase = min(amount, (max_amount - wielded_val))
return COMPONENT_BLOCK_SHARPEN_APPLIED
/**
* The offhand dummy item for two handed items
*
*/
/obj/item/offhand
name = "offhand"
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/wielded = FALSE // Off Hand tracking of wielded status
/obj/item/offhand/Destroy()
wielded = FALSE
return ..()
/obj/item/offhand/equipped(mob/user, slot)
. = ..()
if(wielded && !user.is_holding(src) && !QDELETED(src))
qdel(src)
+20 -23
View File
@@ -24,16 +24,17 @@ GLOBAL_LIST_EMPTY(uplinks)
var/unlock_note
var/unlock_code
var/failsafe_code
var/datum/ui_state/checkstate
var/compact_mode = FALSE
var/debug = FALSE
var/saved_player_population = 0
var/list/filters = list()
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
if(istype(parent, /obj/item/implant))
@@ -65,7 +66,6 @@ GLOBAL_LIST_EMPTY(uplinks)
active = _enabled
gamemode = _gamemode
telecrystals = starting_tc
checkstate = _checkstate
if(!lockable)
active = TRUE
locked = FALSE
@@ -136,13 +136,13 @@ GLOBAL_LIST_EMPTY(uplinks)
/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
state = checkstate ? checkstate : state
active = TRUE
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "uplink", name, 620, 580, master_ui, state)
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
ui.set_style("syndicate")
ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state)
// This UI is only ever opened by one person,
// and never is updated outside of user input.
ui.set_autoupdate(FALSE)
ui.open()
/datum/component/uplink/ui_host(mob/user)
@@ -157,8 +157,7 @@ GLOBAL_LIST_EMPTY(uplinks)
var/list/data = list()
data["telecrystals"] = telecrystals
data["lockable"] = lockable
data["compact_mode"] = compact_mode
data["compactMode"] = compact_mode
return data
/datum/component/uplink/ui_static_data(mob/user)
@@ -192,21 +191,16 @@ GLOBAL_LIST_EMPTY(uplinks)
/datum/component/uplink/ui_act(action, params)
if(!active)
return
switch(action)
if("buy")
var/item = params["item"]
var/item_name = params["name"]
var/list/buyable_items = list()
for(var/category in uplink_items)
buyable_items += uplink_items[category]
if(item in buyable_items)
var/datum/uplink_item/I = buyable_items[item]
//check to make sure people cannot buy items when the player pop is below the requirement
if(GLOB.joined_player_list.len >= I.player_minimum)
MakePurchase(usr, I)
. = TRUE
if(item_name in buyable_items)
var/datum/uplink_item/I = buyable_items[item_name]
MakePurchase(usr, I)
return TRUE
if("lock")
active = FALSE
locked = TRUE
@@ -215,9 +209,10 @@ GLOBAL_LIST_EMPTY(uplinks)
SStgui.close_uis(src)
if("select")
selected_cat = params["category"]
return TRUE
if("compact_toggle")
compact_mode = !compact_mode
return TRUE
return TRUE
/datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U)
if(!istype(U))
@@ -262,12 +257,12 @@ GLOBAL_LIST_EMPTY(uplinks)
var/obj/item/pda/master = parent
if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code)))
if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code)))
failsafe()
failsafe(user)
return COMPONENT_STOP_RINGTONE_CHANGE
return
locked = FALSE
interact(null, user)
to_chat(user, "The PDA softly beeps.")
to_chat(user, "<span class='hear'>The PDA softly beeps.</span>")
user << browse(null, "window=pda")
master.mode = 0
return COMPONENT_STOP_RINGTONE_CHANGE
@@ -279,7 +274,7 @@ GLOBAL_LIST_EMPTY(uplinks)
var/frequency = arguments[1]
if(frequency != unlock_code)
if(frequency == failsafe_code)
failsafe()
failsafe(master.loc)
return
locked = FALSE
if(ismob(master.loc))
@@ -316,11 +311,13 @@ GLOBAL_LIST_EMPTY(uplinks)
else if(istype(parent,/obj/item/pen))
return rand(1, 360)
/datum/component/uplink/proc/failsafe()
/datum/component/uplink/proc/failsafe(mob/living/carbon/user)
if(!parent)
return
var/turf/T = get_turf(parent)
if(!T)
return
message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
log_game("[key_name(user)] triggered an uplink failsafe explosion. The owner of the uplink was [key_name(owner)].")
explosion(T,1,2,3)
qdel(parent) //Alternatively could brick the uplink.
+1 -1
View File
@@ -121,7 +121,7 @@
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
decrease = ((T.air.return_temperature() - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
if(T0C + 100 to INFINITY)
decrease = INFINITY
decrease = max(0, decrease)
+4 -4
View File
@@ -81,7 +81,7 @@
if(N.new_character)
log_manifest(N.ckey,N.new_character.mind,N.new_character)
if(ishuman(N.new_character))
manifest_inject(N.new_character, N.client)
manifest_inject(N.new_character, N.client, N.client.prefs)
CHECK_TICK
/datum/datacore/proc/manifest_modify(name, assignment)
@@ -197,7 +197,7 @@
return dat
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C)
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C, datum/preferences/prefs)
set waitfor = FALSE
var/static/list/show_directions = list(SOUTH, WEST)
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
@@ -260,7 +260,7 @@
M.fields["alg_d"] = "No allergies have been detected in this patient."
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = H.get_trait_string(medical)
M.fields["notes"] = "Trait information as of shift start: [H.get_trait_string(medical)]<br>[prefs.medical_records]"
medical += M
//Security Record
@@ -270,7 +270,7 @@
S.fields["criminal"] = "None"
S.fields["mi_crim"] = list()
S.fields["ma_crim"] = list()
S.fields["notes"] = "No notes."
S.fields["notes"] = prefs.security_records || "No notes."
security += S
//Locked Record
+34
View File
@@ -39,6 +39,9 @@
/// A weak reference to another datum
var/datum/weakref/weak_reference
///Lazy associative list of currently active cooldowns.
var/list/cooldowns
#ifdef TESTING
var/running_find_references
var/last_find_references = 0
@@ -201,3 +204,34 @@
qdel(D)
else
return returned
/**
* Callback called by a timer to end an associative-list-indexed cooldown.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end.
*/
/proc/end_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
TIMER_COOLDOWN_END(source, index)
/**
* Proc used by stoppable timers to end a cooldown before the time has ran out.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end, passing the time left as an argument.
*/
/proc/reset_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
TIMER_COOLDOWN_END(source, index)
@@ -404,7 +404,7 @@
if(M.loc)
environment = M.loc.return_air()
if(environment)
plasmamount = environment.gases[/datum/gas/plasma]
plasmamount = environment.get_moles(/datum/gas/plasma)
if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
. += power * 0.5
if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
+16 -3
View File
@@ -15,6 +15,7 @@
var/mob/living/holder
var/delete_species = TRUE //Set to FALSE when a body is scanned by a cloner to fix #38875
var/mutation_index[DNA_MUTATION_BLOCKS] //List of which mutations this carbon has and its assigned block
var/default_mutation_genes[DNA_MUTATION_BLOCKS] //List of the default genes from this mutation to allow DNA Scanner highlighting
var/stability = 100
var/scrambled = FALSE //Did we take something like mutagen? In that case we cant get our genes scanned to instantly cheese all the powers.
var/skin_tone_override //because custom skin tones are not found in the skin_tones global list.
@@ -58,6 +59,7 @@
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
if(transfer_SE)
destination.dna.mutation_index = mutation_index
destination.dna.default_mutation_genes = default_mutation_genes
destination.dna.update_body_size(old_size)
@@ -66,6 +68,7 @@
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.mutation_index = mutation_index
new_dna.default_mutation_genes = default_mutation_genes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.skin_tone_override = skin_tone_override
@@ -160,15 +163,18 @@
if(!LAZYLEN(mutations_temp))
return
mutation_index.Cut()
default_mutation_genes.Cut()
shuffle_inplace(mutations_temp)
if(ismonkey(holder))
mutations |= new RACEMUT(MUT_NORMAL)
mutation_index[RACEMUT] = GET_SEQUENCE(RACEMUT)
else
mutation_index[RACEMUT] = create_sequence(RACEMUT, FALSE)
default_mutation_genes[RACEMUT] = mutation_index[RACEMUT]
for(var/i in 2 to DNA_MUTATION_BLOCKS)
var/datum/mutation/human/M = mutations_temp[i]
mutation_index[M.type] = create_sequence(M.type, FALSE,M.difficulty)
mutation_index[M.type] = create_sequence(M.type, FALSE, M.difficulty)
default_mutation_genes[M.type] = mutation_index[M.type]
shuffle_inplace(mutation_index)
//Used to generate original gene sequences for every mutation
@@ -389,7 +395,7 @@
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures)
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/default_mutation_genes)
if(newreal_name)
real_name = newreal_name
@@ -414,6 +420,10 @@
if(LAZYLEN(mutation_index))
dna.mutation_index = mutation_index.Copy()
if(LAZYLEN(default_mutation_genes))
dna.default_mutation_genes = default_mutation_genes.Copy()
else
dna.default_mutation_genes = mutation_index.Copy()
domutcheck()
SEND_SIGNAL(src, COMSIG_HUMAN_HARDSET_DNA, ui, mutation_index, newreal_name, newblood_type, mrace, newfeatures)
@@ -505,8 +515,11 @@
. = TRUE
if(on)
mutation_index[HM.type] = GET_SEQUENCE(HM.type)
default_mutation_genes[HM.type] = mutation_index[HM.type]
else if(GET_SEQUENCE(HM.type) == mutation_index[HM.type])
mutation_index[HM.type] = create_sequence(HM.type, FALSE, HM.difficulty)
default_mutation_genes[HM.type] = mutation_index[HM.type]
/datum/dna/proc/activate_mutation(mutation) //note that this returns a boolean and not a new mob
if(!mutation)
@@ -678,7 +691,7 @@
holder.update_transform()
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
if(features["body_size"] < danger)
var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier)
var/slowdown = (1 - round(features["body_size"] / danger, 0.1)) * CONFIG_GET(number/body_size_slowdown_multiplier)
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
else if(old_size < danger)
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride)
+2 -1
View File
@@ -82,9 +82,10 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
return
if(href_list["show_flavor"])
var/atom/target = locate(href_list["show_flavor"])
var/mob/living/L = target
var/text = texts_by_atom[target]
if(text)
usr << browse("<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[target.name];size=500x200")
usr << browse("<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[isliving(target) ? L.get_visible_name() : target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[isliving(target) ? L.get_visible_name() : target.name];size=500x200")
onclose(usr, "[target.name]")
return TRUE
+5 -6
View File
@@ -117,9 +117,8 @@
continue
var/datum/gas_mixture/A = F.air
var/list/A_gases = A.gases
var/trace_gases
for(var/id in A_gases)
for(var/id in A.get_gases())
if(id in GLOB.hardcoded_gases)
continue
trace_gases = TRUE
@@ -128,15 +127,15 @@
// Can most things breathe?
if(trace_gases)
continue
if(A_gases[/datum/gas/oxygen] <= 16)
if(A.get_moles(/datum/gas/oxygen) < 16)
continue
if(A_gases[/datum/gas/plasma])
if(A.get_moles(/datum/gas/plasma))
continue
if(A_gases[/datum/gas/carbon_dioxide] >= 10)
if(A.get_moles(/datum/gas/carbon_dioxide) >= 10)
continue
// Aim for goldilocks temperatures and pressure
if((A.temperature <= 270) || (A.temperature >= 360))
if((A.return_temperature() <= 270) || (A.return_temperature() >= 360))
continue
var/pressure = A.return_pressure()
if((pressure <= 20) || (pressure >= 550))
+2 -4
View File
@@ -58,12 +58,10 @@
var/datum/martial_art/boxing/style = new
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
if(!ishuman(user))
return
if(slot == SLOT_GLOVES)
. = ..()
if(ishuman(user) && slot == SLOT_GLOVES)
var/mob/living/carbon/human/H = user
style.teach(H,TRUE)
return
/obj/item/clothing/gloves/boxing/dropped(mob/user)
. = ..()
+2 -3
View File
@@ -196,9 +196,8 @@
var/datum/martial_art/krav_maga/style = new
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
if(!ishuman(user))
return
if(slot == SLOT_GLOVES)
. = ..()
if(ishuman(user) && slot == SLOT_GLOVES)
var/mob/living/carbon/human/H = user
style.teach(H,1)
+23 -7
View File
@@ -180,14 +180,12 @@
to_chat(usr, "<span class='notice'>Keelhaul</span>: Harm Grab. Kick opponents to the floor. Against prone targets, deal additional stamina damage and disarm them.")
to_chat(usr, "<span class='notice'>In addition, your body has become incredibly resilient to most forms of attack. Weapons cannot readily pierce your hardened skin, and you are highly resistant to stuns and knockdowns, and can block all projectiles in Throw Mode. However, you are not invincible, and sustained damage will take it's toll. Avoid heat at all costs!</span>")
/obj/item/twohanded/bostaff
/obj/item/staff/bostaff
name = "bo staff"
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
force = 10
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
force_unwielded = 10
force_wielded = 24
throwforce = 20
throw_speed = 2
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
@@ -196,11 +194,29 @@
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
block_chance = 50
var/wielded = FALSE // track wielded status on item
/obj/item/twohanded/bostaff/update_icon_state()
icon_state = "bostaff[wielded]"
/obj/item/staff/bostaff/Initialize()
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
/obj/item/staff/bostaff/ComponentInitialize()
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=10, force_wielded=24, icon_wielded="bostaff1")
/// triggered on wield of two handed item
/obj/item/staff/bostaff/proc/on_wield(obj/item/source, mob/user)
wielded = TRUE
/// triggered on unwield of two handed item
/obj/item/staff/bostaff/proc/on_unwield(obj/item/source, mob/user)
wielded = FALSE
/obj/item/staff/bostaff/update_icon_state()
icon_state = "bostaff0"
/obj/item/staff/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
@@ -249,7 +265,7 @@
else
return ..()
/obj/item/twohanded/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
/obj/item/staff/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!wielded)
return BLOCK_NONE
return ..()
+17 -7
View File
@@ -215,11 +215,17 @@
/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D)
set waitfor = FALSE
var/transform_before
var/laying_before
if (D)
transform_before = D.transform
laying_before = D.lying
animate(D, transform = matrix(180, MATRIX_ROTATE), time = 1, loop = 0)
sleep(15)
if (D)
animate(D, transform = null, time = 1, loop = 0)
if(transform_before && laying_before == D.lying) //animate calls sleep so this should be fine and stop a bug with transforms
D.transform = transform_before
animate(D, transform = null, time = 1, loop = 0)
/datum/martial_art/wrestling/proc/slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D)
@@ -377,7 +383,7 @@
var/turf/ST = null
var/falling = 0
var/damage = damage_roll(A,D)
for (var/obj/O in oview(1, A))
if (O.density == 1)
if (O == A)
@@ -415,11 +421,17 @@
to_chat(A, "You can't drop onto [D] from here!")
return FALSE
var/transform_before
var/laying_before
if(A)
transform_before = A.transform
laying_before = A.lying
animate(A, transform = matrix(90, MATRIX_ROTATE), time = 1, loop = 0)
sleep(10)
if(A)
animate(A, transform = null, time = 1, loop = 0)
if(transform_before && laying_before == A.lying) //if they suddenly dropped to the floor between this period, don't revert their animation
animate(A, transform = null, time = 1, loop = 0)
A.transform = transform_before
A.forceMove(D.loc)
@@ -472,12 +484,10 @@
var/datum/martial_art/wrestling/style = new
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
if(!ishuman(user))
return
if(slot == SLOT_BELT)
. = ..()
if(ishuman(user) && slot == SLOT_BELT)
var/mob/living/carbon/human/H = user
style.teach(H,1)
return
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
. = ..()
+2
View File
@@ -124,6 +124,8 @@
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
if(new_character.client)
LAZYCLEARLIST(new_character.client.recent_examines)
current.update_atom_languages()
//CIT CHANGE - makes arousal update when transfering bodies
+23 -1
View File
@@ -42,6 +42,7 @@
var/synchronizer_coeff = -1 //makes the mutation hurt the user less
var/power_coeff = -1 //boosts mutation strength
var/energy_coeff = -1 //lowers mutation cooldown
var/list/valid_chrom_list = list() //List of strings of valid chromosomes this mutation can accept.
/datum/mutation/human/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
. = ..()
@@ -90,7 +91,7 @@
/datum/mutation/human/proc/get_visual_indicator()
return
/datum/mutation/human/proc/on_attack_hand(atom/target, proximity)
/datum/mutation/human/proc/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags)
return
/datum/mutation/human/proc/on_ranged_attack(atom/target, mouseparams)
@@ -167,6 +168,7 @@
energy_coeff = HM.energy_coeff
mutadone_proof = HM.mutadone_proof
can_chromosome = HM.can_chromosome
valid_chrom_list = HM.valid_chrom_list
/datum/mutation/human/proc/remove_chromosome()
stabilizer_coeff = initial(stabilizer_coeff)
@@ -192,3 +194,23 @@
power.panel = "Genetic"
owner.AddSpell(power)
return TRUE
// Runs through all the coefficients and uses this to determine which chromosomes the
// mutation can take. Stores these as text strings in a list.
/datum/mutation/human/proc/update_valid_chromosome_list()
valid_chrom_list.Cut()
if(can_chromosome == CHROMOSOME_NEVER)
valid_chrom_list += "none"
return
valid_chrom_list += "Reinforcement"
if(stabilizer_coeff != -1)
valid_chrom_list += "Stabilizer"
if(synchronizer_coeff != -1)
valid_chrom_list += "Synchronizer"
if(power_coeff != -1)
valid_chrom_list += "Power"
if(energy_coeff != -1)
valid_chrom_list += "Energetic"
+1 -2
View File
@@ -226,9 +226,8 @@
/obj/effect/proc_holder/spell/targeted/olfaction/cast(list/targets, mob/living/user = usr)
//can we sniff? is there miasma in the air?
var/datum/gas_mixture/air = user.loc.return_air()
var/list/cached_gases = air.gases
if(cached_gases[/datum/gas/miasma])
if(air.get_moles(/datum/gas/miasma))
user.adjust_disgust(sensitivity * 45)
to_chat(user, "<span class='warning'>With your overly sensitive nose, you get a whiff of stench and feel sick! Try moving to a cleaner area!</span>")
return
+2 -2
View File
@@ -19,8 +19,8 @@
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk)
RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech)
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity)
if(proximity) //no telekinetic hulk attack
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags)
if(proximity && (act_intent == INTENT_HARM)) //no telekinetic hulk attack
return target.attack_hulk(owner)
/datum/mutation/human/hulk/on_life()
+1 -1
View File
@@ -14,7 +14,7 @@
/datum/mutation/human/wacky
name = "Wacky"
desc = "<span class='sans'>Unknown.</span>"
desc = "Unknown."
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='sans'>You feel an off sensation in your voicebox.</span>"
text_lose_indication = "<span class='notice'>The off sensation passes.</span>"
+3
View File
@@ -104,6 +104,9 @@
rack.AddComponent(/datum/component/magnetic_catch)
//Whatever special stuff you want
/datum/map_template/shuttle/proc/post_load(obj/docking_port/mobile/M)
return
/datum/map_template/shuttle/proc/on_bought()
return
+2 -2
View File
@@ -17,7 +17,7 @@
/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
ui = new(user, src, ui_key, "SkillPanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
ui.open()
else if(need_static_data_update)
@@ -40,7 +40,7 @@
. = list()
.["playername"] = owner.name
.["see_skill_mods"] = see_skill_mods
.["admin"] = check_rights(R_DEBUG)
.["admin"] = check_rights(R_DEBUG, FALSE)
/datum/skill_holder/ui_act(action, params)
. = ..()
+8
View File
@@ -33,6 +33,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/base_multiplier = 1
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
var/competency_multiplier = 1
/// Experience gain multiplier gained from using items.
var/item_skill_gain_multi = 1
/// Skill gain quantisation
var/skill_gain_quantisation = 0.1
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/// Index of this skill in the UI
@@ -108,6 +112,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/// Min value of this skill
var/min_value = 0
/datum/skill/numerical/New()
..()
skill_gain_quantisation = item_skill_gain_multi = item_skill_gain_multi * (max_value - min_value) * STD_NUM_SKILL_ITEM_GAIN_MULTI
/datum/skill/numerical/sanitize_value(new_value)
return clamp(new_value, min_value, max_value)
+4 -6
View File
@@ -91,10 +91,10 @@
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)
skill_holder.need_static_data_update = TRUE
if(!isnull(value))
LAZYINITLIST(skill_holder.skills)
S.set_skill_value(skill_holder, value, src, silent)
skill_holder.need_static_data_update = TRUE
return TRUE
return FALSE
@@ -120,11 +120,9 @@
CRASH("You cannot auto increment a non numerical(experience skill!")
var/current = get_skill_value(skill, FALSE)
var/affinity = get_skill_affinity(skill)
var/target_value = current + (value * affinity)
if(maximum)
target_value = min(target_value, maximum)
if(target_value == maximum) //no more experience to gain, early return.
return
var/target_value = round(current + (value * affinity), S.skill_gain_quantisation)
if(maximum && target_value >= maximum) //no more experience to gain, early return.
return
boost_skill_value_to(skill, target_value, silent, current)
/**
+1 -1
View File
@@ -9,7 +9,7 @@
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "spawners_menu", "Spawners Menu", 700, 600, master_ui, state)
ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state)
ui.open()
/datum/spawners_menu/ui_data(mob/user)
+2 -2
View File
@@ -365,9 +365,9 @@
status_type = STATUS_EFFECT_REPLACE
alert_type = null
var/mutable_appearance/marked_underlay
var/obj/item/twohanded/kinetic_crusher/hammer_synced
var/obj/item/kinetic_crusher/hammer_synced
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/kinetic_crusher/new_hammer_synced)
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/kinetic_crusher/new_hammer_synced)
. = ..()
if(.)
hammer_synced = new_hammer_synced
+64
View File
@@ -314,6 +314,13 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
medical_record_text = "Patient is usually anxious in social encounters and prefers to avoid them."
var/dumb_thing = TRUE
/datum/quirk/social_anxiety/add()
RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, .proc/eye_contact)
RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, .proc/looks_at_floor)
/datum/quirk/social_anxiety/remove()
UnregisterSignal(quirk_holder, list(COMSIG_MOB_EYECONTACT, COMSIG_MOB_EXAMINATE))
/datum/quirk/social_anxiety/on_process()
var/nearby_people = 0
for(var/mob/living/carbon/human/H in oview(3, quirk_holder))
@@ -330,6 +337,45 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
dumb_thing = FALSE //only once per life
if(prob(1))
new/obj/item/reagent_containers/food/snacks/pastatomato(get_turf(H)) //now that's what I call spaghetti code
// small chance to make eye contact with inanimate objects/mindless mobs because of nerves
/datum/quirk/social_anxiety/proc/looks_at_floor(datum/source, atom/A)
var/mob/living/mind_check = A
if(prob(85) || (istype(mind_check) && mind_check.mind))
return
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, quirk_holder, "<span class='smallnotice'>You make eye contact with [A].</span>"), 3)
/datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner)
if(prob(75))
return
var/msg
if(triggering_examiner)
msg = "You make eye contact with [other_mob], "
else
msg = "[other_mob] makes eye contact with you, "
switch(rand(1,3))
if(1)
quirk_holder.Jitter(10)
msg += "causing you to start fidgeting!"
if(2)
quirk_holder.stuttering = max(3, quirk_holder.stuttering)
msg += "causing you to start stuttering!"
if(3)
quirk_holder.Stun(2 SECONDS)
msg += "causing you to freeze up!"
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "anxiety_eyecontact", /datum/mood_event/anxiety_eyecontact)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, quirk_holder, "<span class='userdanger'>[msg]</span>"), 3) // so the examine signal has time to fire and this will print after
return COMSIG_BLOCK_EYECONTACT
/datum/mood_event/anxiety_eyecontact
description = "<span class='warning'>Sometimes eye contact makes me so nervous...</span>\n"
mood_change = -5
timeout = 3 MINUTES
/datum/quirk/phobia
name = "Phobia"
@@ -406,3 +452,21 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
mob_trait = TRAIT_COLDBLOODED
gain_text = "<span class='notice'>You feel cold-blooded.</span>"
lose_text = "<span class='notice'>You feel more warm-blooded.</span>"
/datum/quirk/monophobia
name = "Monophobia"
desc = "You will become increasingly stressed when not in company of others, triggering panic reactions ranging from sickness to heart attacks."
value = -3 // Might change it to 4.
gain_text = "<span class='danger'>You feel really lonely...</span>"
lose_text = "<span class='notice'>You feel like you could be safe on your own.</span>"
medical_record_text = "Patient feels sick and distressed when not around other people, leading to potentially lethal levels of stress."
/datum/quirk/monophobia/post_add()
. = ..()
var/mob/living/carbon/human/H = quirk_holder
H.gain_trauma(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/monophobia/remove()
. = ..()
var/mob/living/carbon/human/H = quirk_holder
H?.cure_trauma_type(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
+2 -2
View File
@@ -242,8 +242,8 @@
/datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state)
if (!ui)
ui = new(user, src, ui_key, "Wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state)
ui.open()
/datum/wires/ui_data(mob/user)
+2 -2
View File
@@ -75,8 +75,8 @@
/datum/wires/explosive/gibtonite
holder_type = /obj/item/twohanded/required/gibtonite
holder_type = /obj/item/gibtonite
/datum/wires/explosive/gibtonite/explode()
var/obj/item/twohanded/required/gibtonite/P = holder
var/obj/item/gibtonite/P = holder
P.GibtoniteReaction(null, 2)
+19
View File
@@ -74,6 +74,25 @@
for(var/client/C in GLOB.clients)
C.AnnouncePR(final_composed)
/datum/world_topic/auto_bunker_passthrough
keyword = "auto_bunker_override"
require_comms_key = TRUE
/datum/world_topic/auto_bunker_passthrough/Run(list/input)
if(!CONFIG_GET(flag/allow_cross_server_bunker_override))
return "Function Disabled"
var/ckeytobypass = input["ckey"]
var/is_new_ckey = !(ckey(ckeytobypass) in GLOB.bunker_passthrough)
var/sender = input["source"] || "UNKNOWN"
GLOB.bunker_passthrough |= ckey(ckeytobypass)
GLOB.bunker_passthrough[ckey(ckeytobypass)] = world.realtime
SSpersistence.SavePanicBunker() //we can do this every time, it's okay
if(!is_new_ckey)
log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
return "Success"
/datum/world_topic/ahelp_relay
keyword = "Ahelp"
require_comms_key = TRUE
+6 -1
View File
@@ -516,7 +516,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
used_environ += amount
/area/Entered(atom/movable/M)
/area/Entered(atom/movable/M, atom/OldLoc)
set waitfor = FALSE
SEND_SIGNAL(src, COMSIG_AREA_ENTERED, M)
SEND_SIGNAL(M, COMSIG_ENTER_AREA, src) //The atom that enters the area
@@ -524,6 +524,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return
var/mob/living/L = M
var/turf/oldTurf = get_turf(OldLoc)
var/area/A = oldTurf?.loc
if(A && (A.has_gravity != has_gravity))
L.update_gravity(L.mob_has_gravity())
if(!L.ckey)
return

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