Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into ninjasarecum
# Conflicts: # code/modules/ninja/suit/ninjaDrainAct.dm
This commit is contained in:
@@ -52,14 +52,46 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
#define BLOCK_FACE_ATOM_1 (1<<17)
|
||||
|
||||
//turf-only flags
|
||||
#define NOJAUNT_1 (1<<0)
|
||||
#define UNUSED_RESERVATION_TURF_1 (1<<1)
|
||||
///If a turf can be made dirty at roundstart. This is also used in areas.
|
||||
#define CAN_BE_DIRTY_1 (1<<2)
|
||||
///Blocks lava rivers being generated on the turf.
|
||||
#define NO_LAVA_GEN_1 (1<<6)
|
||||
///Blocks ruins spawning on the turf.
|
||||
#define NO_RUINS_1 (1<<10)
|
||||
#define NOJAUNT_1 (1<<0)
|
||||
#define UNUSED_RESERVATION_TURF_1 (1<<1)
|
||||
/// If a turf can be made dirty at roundstart. This is also used in areas.
|
||||
#define CAN_BE_DIRTY_1 (1<<2)
|
||||
/// If blood cultists can draw runes or build structures on this turf
|
||||
#define CULT_PERMITTED_1 (1<<3)
|
||||
/// Blocks lava rivers being generated on the turf
|
||||
#define NO_LAVA_GEN_1 (1<<6)
|
||||
/// Blocks ruins spawning on the turf
|
||||
#define NO_RUINS_1 (1<<10)
|
||||
/// Should this tile be cleaned up and reinserted into an excited group?
|
||||
#define EXCITED_CLEANUP_1 (1 << 13)
|
||||
|
||||
////////////////Area flags\\\\\\\\\\\\\\
|
||||
/// If it's a valid territory for cult summoning or the CRAB-17 phone to spawn
|
||||
#define VALID_TERRITORY (1<<0)
|
||||
/// If blobs can spawn there and if it counts towards their score.
|
||||
#define BLOBS_ALLOWED (1<<1)
|
||||
/// If mining tunnel generation is allowed in this area
|
||||
#define CAVES_ALLOWED (1<<2)
|
||||
/// If flora are allowed to spawn in this area randomly through tunnel generation
|
||||
#define FLORA_ALLOWED (1<<3)
|
||||
/// If mobs can be spawned by natural random generation
|
||||
#define MOB_SPAWN_ALLOWED (1<<4)
|
||||
/// If megafauna can be spawned by natural random generation
|
||||
#define MEGAFAUNA_SPAWN_ALLOWED (1<<5)
|
||||
/// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
|
||||
#define NOTELEPORT (1<<6)
|
||||
/// Hides area from player Teleport function.
|
||||
#define HIDDEN_AREA (1<<7)
|
||||
/// If false, loading multiple maps with this area type will create multiple instances.
|
||||
#define UNIQUE_AREA (1<<8)
|
||||
/// If people are allowed to suicide in it. Mostly for OOC stuff like minigames
|
||||
#define BLOCK_SUICIDE (1<<9)
|
||||
/// Can the Xenobio management console transverse this area by default?
|
||||
#define XENOBIOLOGY_COMPATIBLE (1<<10)
|
||||
/// If Abductors are unable to teleport in with their observation console
|
||||
#define ABDUCTOR_PROOF (1<<11)
|
||||
/// If an area should be hidden from power consoles, power/atmosphere alerts, etc.
|
||||
#define NO_ALERTS (1<<12)
|
||||
|
||||
/*
|
||||
These defines are used specifically with the atom/pass_flags bitmask
|
||||
|
||||
@@ -51,3 +51,4 @@
|
||||
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
|
||||
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
|
||||
#define ORGAN_EDIBLE (1<<7) //is a snack? :D
|
||||
#define ORGAN_SYNTHETIC_EMP (1<<6) //Synthetic organ affected by an EMP. Deteriorates over time.
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
/// Integrity defines for clothing (not flags but close enough)
|
||||
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
|
||||
#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart and can be equipped
|
||||
#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first
|
||||
#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart
|
||||
#define CLOTHING_SHREDDED 2 // The clothing is near useless and has their sensors broken
|
||||
|
||||
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
|
||||
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
/// Transparent, let beams pass
|
||||
#define SHIELD_TRANSPARENT (1<<0)
|
||||
|
||||
/// Flammable, takes more damage from fire
|
||||
#define SHIELD_ENERGY_WEAK (1<<1)
|
||||
/// Fragile, takes more damage from brute
|
||||
#define SHIELD_KINETIC_WEAK (1<<2)
|
||||
/// Strong against kinetic, weak against energy
|
||||
#define SHIELD_KINETIC_STRONG (1<<3)
|
||||
/// Strong against energy, weak against kinetic
|
||||
#define SHIELD_ENERGY_STRONG (1<<4)
|
||||
/// Disabler and other stamina based energy weapons boost the damage done to the sheld
|
||||
#define SHIELD_DISABLER_DISRUPTED (1<<5)
|
||||
|
||||
/// Doesn't block ranged attacks whatsoever
|
||||
#define SHIELD_NO_RANGED (1<<6)
|
||||
/// Doesn't block melee attacks whatsoever
|
||||
#define SHIELD_NO_MELEE (1<<7)
|
||||
|
||||
/// Can shield bash
|
||||
#define SHIELD_CAN_BASH (1<<1)
|
||||
#define SHIELD_CAN_BASH (1<<8)
|
||||
/// Shield bash knockdown on wall hit
|
||||
#define SHIELD_BASH_WALL_KNOCKDOWN (1<<2)
|
||||
#define SHIELD_BASH_WALL_KNOCKDOWN (1<<9)
|
||||
/// Shield bash always knockdown
|
||||
#define SHIELD_BASH_ALWAYS_KNOCKDOWN (1<<3)
|
||||
#define SHIELD_BASH_ALWAYS_KNOCKDOWN (1<<10)
|
||||
/// Shield bash disarm on wall hit
|
||||
#define SHIELD_BASH_WALL_DISARM (1<<4)
|
||||
#define SHIELD_BASH_WALL_DISARM (1<<11)
|
||||
/// Shield bash always disarm
|
||||
#define SHIELD_BASH_ALWAYS_DISARM (1<<5)
|
||||
#define SHIELD_BASH_ALWAYS_DISARM (1<<12)
|
||||
/// You can shieldbash target someone on the ground for ground slam
|
||||
#define SHIELD_BASH_GROUND_SLAM (1<<6)
|
||||
#define SHIELD_BASH_GROUND_SLAM (1<<13)
|
||||
/// Shield bashing someone on the ground will disarm
|
||||
#define SHIELD_BASH_GROUND_SLAM_DISARM (1<<7)
|
||||
#define SHIELD_BASH_GROUND_SLAM_DISARM (1<<14)
|
||||
|
||||
#define SHIELD_FLAGS_DEFAULT (SHIELD_CAN_BASH | SHIELD_BASH_WALL_KNOCKDOWN | SHIELD_BASH_WALL_DISARM | SHIELD_BASH_GROUND_SLAM)
|
||||
|
||||
@@ -281,6 +281,9 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
|
||||
#define CALCULATE_ADJACENT_TURFS(T) SSadjacent_air.queue[T] = 1
|
||||
#endif
|
||||
|
||||
//If you're doing spreading things related to atmos, DO NOT USE CANATMOSPASS, IT IS NOT CHEAP. use this instead, the info is cached after all. it's tweaked just a bit to allow for circular checks
|
||||
#define TURFS_CAN_SHARE(T1, T2) (LAZYACCESS(T2.atmos_adjacent_turfs, T1) || LAZYLEN(T1.atmos_adjacent_turfs & T2.atmos_adjacent_turfs))
|
||||
|
||||
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;\
|
||||
|
||||
@@ -60,6 +60,5 @@ GLOBAL_LIST_INIT(podstyles, list(\
|
||||
))
|
||||
|
||||
//cit
|
||||
#define PACK_GOODY_NONE 0
|
||||
#define PACK_GOODY_PUBLIC 1 //can be bought by both privates and cargo
|
||||
#define PACK_GOODY_PRIVATE 2 //can be bought only by privates
|
||||
#define PACK_GOODY_NONE 0 // can be bought by cargo and privates
|
||||
#define PACK_GOODY_PRIVATE 1 // can be bought only by privates
|
||||
|
||||
@@ -159,9 +159,6 @@
|
||||
#define SHOVE_STAGGER_DURATION 35
|
||||
/// how long they're off balance for
|
||||
#define SHOVE_OFFBALANCE_DURATION 30
|
||||
//Shove disarming item list
|
||||
GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
/obj/item/gun)))
|
||||
|
||||
|
||||
//Embedded objects
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
// signals from globally accessible objects
|
||||
/// from SSsun when the sun changes position : (primary_sun, suns)
|
||||
#define COMSIG_SUN_MOVED "sun_moved"
|
||||
|
||||
/// from SSactivity for things that add threat but aren't "global" (e.g. phylacteries)
|
||||
#define COMSIG_THREAT_CALC "threat_calculation"
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// /datum signals
|
||||
@@ -166,9 +170,15 @@
|
||||
#define COMSIG_AREA_EXITED "area_exited" //from base of area/Exited(): (atom/movable/M)
|
||||
|
||||
// /turf signals
|
||||
#define COMSIG_TURF_CHANGE "turf_change" //from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
|
||||
#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" //from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
|
||||
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" //from base of turf/New(): (turf/source, direction)
|
||||
|
||||
///from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
|
||||
#define COMSIG_TURF_CHANGE "turf_change"
|
||||
///from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
|
||||
#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity"
|
||||
///from base of turf/multiz_turf_del(): (turf/source, direction)
|
||||
#define COMSIG_TURF_MULTIZ_DEL "turf_multiz_del"
|
||||
///from base of turf/multiz_turf_new: (turf/source, direction)
|
||||
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new"
|
||||
|
||||
// /atom/movable signals
|
||||
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" ///from base of atom/movable/Moved(): (/atom)
|
||||
@@ -256,6 +266,7 @@
|
||||
#define COMSIG_MOB_GET_VISIBLE_MESSAGE "mob_get_visible_message" //from base of atom/visible_message(): (atom/A, msg, range, ignored_mobs)
|
||||
#define COMPONENT_NO_VISIBLE_MESSAGE 1 //exactly what's said on the tin.
|
||||
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
|
||||
#define COMSIG_MOB_APPLY_DAMAGE "mob_apply_damage" //from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness)
|
||||
|
||||
#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)
|
||||
@@ -293,6 +304,10 @@
|
||||
#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, list/override)
|
||||
#define COMPONENT_PREVENT_PARRY_START 1
|
||||
|
||||
#define COMSIG_LIVING_ATTACKER_SET "living_attacker_set" // from base of /mob/living/set_last_attacker(): (attacker)
|
||||
|
||||
#define COMSIG_LIVING_SET_AS_ATTACKER "living_set_as_attacker" // from base of /mob/living/set_last_attacker(): (target)
|
||||
|
||||
//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)
|
||||
@@ -347,7 +362,6 @@
|
||||
|
||||
// /obj/item signals
|
||||
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
|
||||
#define COMSIG_MOB_APPLY_DAMGE "mob_apply_damage" //from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
|
||||
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
|
||||
#define COMPONENT_NO_INTERACT 1
|
||||
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
|
||||
@@ -445,6 +459,10 @@
|
||||
// /datum/mutation signals
|
||||
#define COMSIG_HUMAN_MUTATION_LOSS "human_mutation_loss" //from datum/mutation/human/on_losing(): (datum/mutation/human/lost_mutation)
|
||||
|
||||
///from base of mob/living/death(): (gibbed)
|
||||
// Sent before any of the other death code has run, mob is still alive.
|
||||
#define COMSIG_LIVING_PREDEATH "living_predeath"
|
||||
|
||||
/*******Component Specific Signals*******/
|
||||
//Janitor
|
||||
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
|
||||
|
||||
@@ -17,7 +17,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
/turf/open/chasm,
|
||||
/turf/open/lava,
|
||||
/turf/open/water,
|
||||
/turf/open/transparent/openspace
|
||||
/turf/open/openspace
|
||||
)))
|
||||
|
||||
#define isgroundlessturf(A) (is_type_in_typecache(A, GLOB.turfs_without_ground))
|
||||
@@ -44,7 +44,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
|
||||
#define isplatingturf(A) (istype(A, /turf/open/floor/plating))
|
||||
|
||||
#define istransparentturf(A) (istype(A, /turf/open/transparent)||istype(A, /turf/open/space/transparent))
|
||||
#define istransparentturf(A) (istype(A, /turf/open/openspace))
|
||||
|
||||
//Mobs
|
||||
#define isliving(A) (istype(A, /mob/living))
|
||||
|
||||
@@ -82,3 +82,12 @@
|
||||
#define LOADOUT_CAN_NAME (1<<0) //renaming items
|
||||
#define LOADOUT_CAN_DESCRIPTION (1<<1) //adding a custom description to items
|
||||
#define LOADOUT_CAN_COLOR_POLYCHROMIC (1<<2)
|
||||
|
||||
//the names of the customization tabs
|
||||
#define SETTINGS_TAB 0
|
||||
#define GAME_PREFERENCES_TAB 1
|
||||
#define APPEARANCE_TAB 2
|
||||
#define SPEECH_TAB 3
|
||||
#define LOADOUT_TAB 4
|
||||
#define CONTENT_PREFERENCES_TAB 5
|
||||
#define KEYBINDINGS_TAB 6
|
||||
|
||||
@@ -107,6 +107,23 @@ require only minor tweaks.
|
||||
#define PLACE_LAVA_RUIN "lavaland" //On lavaland ruin z levels(s)
|
||||
#define PLACE_BELOW "below" //On z levl below - centered on same tile
|
||||
#define PLACE_ISOLATED "isolated" //On isolated ruin z level
|
||||
|
||||
|
||||
///Map generation defines
|
||||
#define PERLIN_LAYER_HEIGHT "perlin_height"
|
||||
#define PERLIN_LAYER_HUMIDITY "perlin_humidity"
|
||||
#define PERLIN_LAYER_HEAT "perlin_heat"
|
||||
|
||||
#define BIOME_LOW_HEAT "low_heat"
|
||||
#define BIOME_LOWMEDIUM_HEAT "lowmedium_heat"
|
||||
#define BIOME_HIGHMEDIUM_HEAT "highmedium_heat"
|
||||
#define BIOME_HIGH_HEAT "high_heat"
|
||||
|
||||
#define BIOME_LOW_HUMIDITY "low_humidity"
|
||||
#define BIOME_LOWMEDIUM_HUMIDITY "lowmedium_humidity"
|
||||
#define BIOME_HIGHMEDIUM_HUMIDITY "highmedium_humidity"
|
||||
#define BIOME_HIGH_HUMIDITY "high_humidity"
|
||||
|
||||
//Map type stuff.
|
||||
#define MAP_TYPE_STATION "station"
|
||||
|
||||
|
||||
+16
-5
@@ -30,7 +30,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
|
||||
//Human Overlays Indexes/////////
|
||||
//LOTS OF CIT CHANGES HERE. BE CAREFUL WHEN UPSTREAM ADDS MORE LAYERS
|
||||
#define MUTATIONS_LAYER 33 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define MUTATIONS_LAYER 34 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define ANTAG_LAYER 33 //stuff for things like cultism indicators (clock cult glow, cultist red halos, whatever else new that comes up)
|
||||
#define GENITALS_BEHIND_LAYER 32 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
|
||||
#define BODY_BEHIND_LAYER 31 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 30 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
@@ -63,7 +64,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
#define HANDS_LAYER 3
|
||||
#define BODY_FRONT_LAYER 2
|
||||
#define FIRE_LAYER 1 //If you're on fire
|
||||
#define TOTAL_LAYERS 33 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
|
||||
#define TOTAL_LAYERS 34 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
|
||||
|
||||
//Human Overlay Index Shortcuts for alternate_worn_layer, layers
|
||||
//Because I *KNOW* somebody will think layer+1 means "above"
|
||||
@@ -158,7 +159,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
#define BLOOD_COLOR_SLIME "#00ff90"
|
||||
#define BLOOD_COLOR_LIZARD "#db004D"
|
||||
#define BLOOD_COLOR_UNIVERSAL "#db3300"
|
||||
#define BLOOD_COLOR_BUG "#a37c0f"
|
||||
#define BLOOD_COLOR_BUG "#ffc933"
|
||||
#define BLOOD_COLOR_PLANT "#3d610e"
|
||||
|
||||
|
||||
@@ -173,8 +174,18 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
|
||||
#define BROKEN_SENSORS -1
|
||||
#define NO_SENSORS 0
|
||||
#define HAS_SENSORS 1
|
||||
#define LOCKED_SENSORS 2
|
||||
#define DAMAGED_SENSORS_LIVING 1
|
||||
#define DAMAGED_SENSORS_VITALS 2
|
||||
#define HAS_SENSORS 3
|
||||
|
||||
//suit sensor flags: sensor_flag defines
|
||||
#define SENSOR_RANDOM (1<<0)
|
||||
#define SENSOR_LOCKED (1<<1)
|
||||
|
||||
//suit sensor integrity percentage threshold defines
|
||||
#define SENSOR_INTEGRITY_COORDS 0.2
|
||||
#define SENSOR_INTEGRITY_VITALS 0.6
|
||||
#define SENSOR_INTEGRITY_BINARY 1
|
||||
|
||||
//Wet floor type flags. Stronger ones should be higher in number.
|
||||
#define TURF_DRY (0)
|
||||
|
||||
@@ -340,3 +340,6 @@
|
||||
#define EXAMINE_MORE_TIME 1 SECONDS
|
||||
|
||||
#define SILENCE_RANGED_MESSAGE (1<<0)
|
||||
|
||||
///Define for spawning megafauna instead of a mob for cave gen
|
||||
#define SPAWN_MEGAFAUNA "bluh bluh huge boss"
|
||||
|
||||
@@ -41,11 +41,13 @@
|
||||
#define ROLE_GHOSTCAFE "ghostcafe"
|
||||
#define ROLE_MINOR_ANTAG "minorantag"
|
||||
#define ROLE_RESPAWN "respawnsystem"
|
||||
/// Not an actual antag. Lets players force all antags off.
|
||||
#define ROLE_NO_ANTAGONISM "NO_ANTAGS"
|
||||
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
|
||||
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
|
||||
//(in game days played) to play that role
|
||||
GLOBAL_LIST_INIT(special_roles, list(
|
||||
ROLE_SYNDICATE,
|
||||
ROLE_NO_ANTAGONISM,
|
||||
ROLE_TRAITOR = /datum/game_mode/traitor,
|
||||
ROLE_BROTHER = /datum/game_mode/traitor/bros,
|
||||
ROLE_OPERATIVE = /datum/game_mode/nuclear,
|
||||
|
||||
@@ -152,6 +152,7 @@
|
||||
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
|
||||
|
||||
#define FIRE_PRIORITY_VORE 5
|
||||
#define FIRE_PRIORITY_ACTIVITY 10
|
||||
#define FIRE_PRIORITY_IDLE_NPC 10
|
||||
#define FIRE_PRIORITY_SERVER_MAINT 10
|
||||
#define FIRE_PRIORITY_RESEARCH 10
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" /// Prevents stamina buffer regeneration
|
||||
#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" /// Prevents stamina regeneration
|
||||
#define TRAIT_ARMOR_BROKEN "armor_broken" //acts as if you are wearing no clothing when taking damage, does not affect non-clothing sources of protection
|
||||
#define TRAIT_IWASBATONED "iwasbatoned" //some dastardly fellow has struck you with a baton and thought to use another to strike you again, the rogue
|
||||
/// forces update_density to make us not dense
|
||||
#define TRAIT_LIVING_NO_DENSITY "living_no_density"
|
||||
/// forces us to not render our overlays
|
||||
@@ -283,6 +284,7 @@
|
||||
#define SHOES_TRAIT "shoes" //inherited from your sweet kicks
|
||||
#define GLOVE_TRAIT "glove" //inherited by your cool gloves
|
||||
#define BOOK_TRAIT "granter (book)" // knowledge is power
|
||||
#define TURF_TRAIT "turf"
|
||||
|
||||
// unique trait sources, still defines
|
||||
#define STATUE_TRAIT "statue"
|
||||
@@ -330,6 +332,8 @@
|
||||
#define DEATHSQUAD_TRAIT "deathsquad"
|
||||
#define SLIMEPUDDLE_TRAIT "slimepuddle"
|
||||
#define CORRUPTED_SYSTEM "corrupted-system"
|
||||
///Turf trait for when a turf is transparent
|
||||
#define TURF_Z_TRANSPARENT_TRAIT "turf_z_transparent"
|
||||
/// This trait is added by the active directional block system.
|
||||
#define ACTIVE_BLOCK_TRAIT "active_block"
|
||||
/// This trait is added by the parry system.
|
||||
|
||||
@@ -136,3 +136,6 @@
|
||||
|
||||
// paintings
|
||||
#define VV_HK_REMOVE_PAINTING "remove_painting"
|
||||
|
||||
//outfits
|
||||
#define VV_HK_TO_OUTFIT_EDITOR "outfit_editor"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYOR(L, I) if(!L) { L = list(); } L |= I;
|
||||
#define LAZYFIND(L, V) L ? L.Find(V) : 0
|
||||
#define LAZYFIND(L, V) (L ? L.Find(V) : 0)
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
|
||||
#define LAZYLEN(L) length(L)
|
||||
|
||||
+14
-16
@@ -1,8 +1,8 @@
|
||||
#define BP_MAX_ROOM_SIZE 300
|
||||
|
||||
GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/engineering, \
|
||||
/area/engine/supermatter, \
|
||||
/area/engine/atmospherics_engine, \
|
||||
GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engineering/main, \
|
||||
/area/engineering/supermatter, \
|
||||
/area/engineering/atmospherics_engine, \
|
||||
/area/ai_monitored/turret_protected/ai))
|
||||
|
||||
//Repopulates sortedAreas list
|
||||
@@ -85,13 +85,12 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
if(target_z == 0 || target_z == T.z)
|
||||
turfs += T
|
||||
return turfs
|
||||
|
||||
// Gets an atmos isolated contained space
|
||||
// Returns an associative list of turf|dirs pairs
|
||||
// The dirs are connected turfs in the same space
|
||||
// break_if_found is a typecache of turf/area types to return false if found
|
||||
// Please keep this proc type agnostic. If you need to restrict it do it elsewhere or add an arg.
|
||||
/proc/detect_room(turf/origin, list/break_if_found)
|
||||
/proc/detect_room(turf/origin, list/break_if_found, max_size=INFINITY)
|
||||
if(origin.blocks_air)
|
||||
return list(origin)
|
||||
|
||||
@@ -103,6 +102,8 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
found_turfs.Cut(1, 2)
|
||||
var/dir_flags = checked_turfs[sourceT]
|
||||
for(var/dir in GLOB.alldirs)
|
||||
if(length(.) > max_size)
|
||||
return
|
||||
if(dir_flags & dir) // This means we've checked this dir before, probably from the other turf
|
||||
continue
|
||||
var/turf/checkT = get_step(sourceT, dir)
|
||||
@@ -115,7 +116,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
if(break_if_found[checkT.type] || break_if_found[checkT.loc.type])
|
||||
return FALSE
|
||||
var/static/list/cardinal_cache = list("[NORTH]"=TRUE, "[EAST]"=TRUE, "[SOUTH]"=TRUE, "[WEST]"=TRUE)
|
||||
if(!cardinal_cache["[dir]"] || checkT.blocks_air || !CANATMOSPASS(sourceT, checkT))
|
||||
if(!cardinal_cache["[dir]"] || checkT.blocks_air || !TURFS_CAN_SHARE(sourceT, checkT))
|
||||
continue
|
||||
found_turfs += checkT // Since checkT is connected, add it to the list to be processed
|
||||
|
||||
@@ -130,25 +131,24 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
/area/space,
|
||||
))
|
||||
|
||||
if(creator)
|
||||
if(creator.create_area_cooldown >= world.time)
|
||||
to_chat(creator, "<span class='warning'>You're trying to create a new area a little too fast.</span>")
|
||||
return
|
||||
creator.create_area_cooldown = world.time + 10
|
||||
if(creator?.create_area_cooldown >= world.time)
|
||||
to_chat(creator, "<span class='warning'>You're trying to create a new area a little too fast.</span>")
|
||||
return
|
||||
creator.create_area_cooldown = world.time + 10
|
||||
|
||||
var/list/turfs = detect_room(get_turf(creator), area_or_turf_fail_types)
|
||||
var/list/turfs = detect_room(get_turf(creator), area_or_turf_fail_types, BP_MAX_ROOM_SIZE*2)
|
||||
if(!turfs)
|
||||
to_chat(creator, "<span class='warning'>The new area must be completely airtight and not a part of a shuttle.</span>")
|
||||
return
|
||||
if(turfs.len > BP_MAX_ROOM_SIZE)
|
||||
to_chat(creator, "<span class='warning'>The room you're in is too big. It is [((turfs.len / BP_MAX_ROOM_SIZE)-1)*100]% larger than allowed.</span>")
|
||||
to_chat(creator, "<span class='warning'>The room you're in is too big. It is [turfs.len >= BP_MAX_ROOM_SIZE *2 ? "more than 100" : ((turfs.len / BP_MAX_ROOM_SIZE)-1)*100]% larger than allowed.</span>")
|
||||
return
|
||||
var/list/areas = list("New Area" = /area)
|
||||
for(var/i in 1 to turfs.len)
|
||||
var/area/place = get_area(turfs[i])
|
||||
if(blacklisted_areas[place.type])
|
||||
continue
|
||||
if(!place.requires_power || place.noteleport || place.hidden)
|
||||
if(!place.requires_power || (place.area_flags & NOTELEPORT) || (place.area_flags & HIDDEN_AREA))
|
||||
continue // No expanding powerless rooms etc
|
||||
areas[place.name] = place
|
||||
var/area_choice = input(creator, "Choose an area to expand or make a new area.", "Area Expansion") as null|anything in areas
|
||||
@@ -170,7 +170,6 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
newA.setup(str)
|
||||
newA.set_dynamic_lighting()
|
||||
newA.has_gravity = oldA.has_gravity
|
||||
newA.noteleport = oldA.noteleport
|
||||
else
|
||||
newA = area_choice
|
||||
|
||||
@@ -190,7 +189,6 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
to_chat(creator, "<span class='notice'>You have created a new area, named [newA.name]. It is now weather proof, and constructing an APC will allow it to be powered.</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base area the target is located in if there is one.
|
||||
* Alternatively, returns the area as is.
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
for(var/spath in subtypesof(/datum/species))
|
||||
var/datum/species/S = new spath()
|
||||
GLOB.species_list[S.id] = spath
|
||||
GLOB.species_datums[S.id] = S
|
||||
|
||||
//Surgeries
|
||||
for(var/path in subtypesof(/datum/surgery))
|
||||
|
||||
@@ -1051,7 +1051,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
return 0
|
||||
|
||||
//For creating consistent icons for human looking simple animals
|
||||
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null)
|
||||
/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null, no_anim = FALSE)
|
||||
var/static/list/humanoid_icon_cache = list()
|
||||
if(!icon_id || !humanoid_icon_cache[icon_id])
|
||||
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
|
||||
@@ -1065,10 +1065,9 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
|
||||
|
||||
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
|
||||
COMPILE_OVERLAYS(body)
|
||||
for(var/D in showDirs)
|
||||
body.setDir(D)
|
||||
COMPILE_OVERLAYS(body)
|
||||
var/icon/partial = getFlatIcon(body)
|
||||
var/icon/partial = getFlatIcon(body, defdir = D, no_anim = no_anim)
|
||||
out_icon.Insert(partial,dir=D)
|
||||
|
||||
humanoid_icon_cache[icon_id] = out_icon
|
||||
|
||||
@@ -320,6 +320,8 @@ GLOBAL_LIST_INIT(nonstandard_skin_tones, list("orange"))
|
||||
|
||||
GLOBAL_LIST_EMPTY(species_list)
|
||||
|
||||
GLOBAL_LIST_EMPTY(species_datums)
|
||||
|
||||
/proc/age2agedescription(age)
|
||||
switch(age)
|
||||
if(0 to 1)
|
||||
|
||||
@@ -95,3 +95,9 @@
|
||||
if("I'm feeling lucky")
|
||||
chosen_id = pick(subtypesof(/datum/reagent))
|
||||
return chosen_id
|
||||
|
||||
/proc/find_reagent_object_from_type(input)
|
||||
if(GLOB.chemical_reagents_list[input]) //prefer IDs!
|
||||
return GLOB.chemical_reagents_list[input]
|
||||
else
|
||||
return null
|
||||
|
||||
@@ -386,12 +386,15 @@
|
||||
//ignore this comment, it fixes the broken sytax parsing caused by the " above
|
||||
else
|
||||
parts += "[FOURSPACES]<i>Nobody died this shift!</i>"
|
||||
var/avg_threat = SSactivity.get_average_threat()
|
||||
var/max_threat = SSactivity.get_max_threat()
|
||||
parts += "[FOURSPACES]Threat at round end: [SSactivity.current_threat]"
|
||||
parts += "[FOURSPACES]Average threat: [avg_threat]"
|
||||
parts += "[FOURSPACES]Max threat: [max_threat]"
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.update_playercounts() // ?
|
||||
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
|
||||
parts += "[FOURSPACES]Threat left: [mode.threat]"
|
||||
parts += "[FOURSPACES]Average threat: [mode.threat_average]"
|
||||
parts += "[FOURSPACES]Target threat: [mode.threat_level]"
|
||||
parts += "[FOURSPACES]Executed rules:"
|
||||
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
|
||||
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
|
||||
@@ -400,8 +403,10 @@
|
||||
parts += "[FOURSPACES][FOURSPACES][str]"
|
||||
for(var/entry in mode.threat_tallies)
|
||||
parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]"
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",mode.threat_level,"Final threat level")
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",mode.threat,"Final Threat")
|
||||
SSblackbox.record_feedback("tally","threat",mode.threat_level,"Target threat")
|
||||
SSblackbox.record_feedback("tally","threat",SSactivity.current_threat,"Final Threat")
|
||||
SSblackbox.record_feedback("tally","threat",avg_threat,"Average Threat")
|
||||
SSblackbox.record_feedback("tally","threat",max_threat,"Max Threat")
|
||||
return parts.Join("<br>")
|
||||
|
||||
/client/proc/roundend_report_file()
|
||||
|
||||
@@ -1030,17 +1030,19 @@ B --><-- A
|
||||
A.cut_overlay(O)
|
||||
|
||||
/proc/get_random_station_turf()
|
||||
return safepick(get_area_turfs(pick(GLOB.the_station_areas)))
|
||||
var/list/turfs = get_area_turfs(pick(GLOB.the_station_areas))
|
||||
if (length(turfs))
|
||||
return pick(turfs)
|
||||
|
||||
/proc/get_safe_random_station_turf() //excludes dense turfs (like walls) and areas that have valid_territory set to FALSE
|
||||
/proc/get_safe_random_station_turf(list/areas_to_pick_from = GLOB.the_station_areas) //excludes dense turfs (like walls) and areas that have valid_territory set to FALSE
|
||||
for (var/i in 1 to 5)
|
||||
var/list/L = get_area_turfs(pick(GLOB.the_station_areas))
|
||||
var/list/L = get_area_turfs(pick(areas_to_pick_from))
|
||||
var/turf/target
|
||||
while (L.len && !target)
|
||||
var/I = rand(1, L.len)
|
||||
var/turf/T = L[I]
|
||||
var/area/X = get_area(T)
|
||||
if(!T.density && X.valid_territory)
|
||||
if(!T.density && (X.area_flags & VALID_TERRITORY))
|
||||
var/clear = TRUE
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
|
||||
@@ -11,6 +11,23 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"TILE_BOUND" = TILE_BOUND,
|
||||
"PIXEL_SCALE" = PIXEL_SCALE
|
||||
),
|
||||
"area_flags" = list(
|
||||
"ABDUCTOR_PROOF" = ABDUCTOR_PROOF,
|
||||
"BLOBS_ALLOWED" = BLOBS_ALLOWED,
|
||||
"BLOCK_SUICIDE" = BLOCK_SUICIDE,
|
||||
// "CULT_PERMITTED" = CULT_PERMITTED,
|
||||
"FLORA_ALLOWED" = FLORA_ALLOWED,
|
||||
"HIDDEN_AREA" = HIDDEN_AREA,
|
||||
"MEGAFAUNA_SPAWN_ALLOWED" = MEGAFAUNA_SPAWN_ALLOWED,
|
||||
"MOB_SPAWN_ALLOWED" = MOB_SPAWN_ALLOWED,
|
||||
"NO_ALERTS" = NO_ALERTS,
|
||||
"NOTELEPORT" = NOTELEPORT,
|
||||
"CAVES_ALLOWED" = CAVES_ALLOWED,
|
||||
"UNIQUE_AREA" = UNIQUE_AREA,
|
||||
"VALID_TERRITORY" = VALID_TERRITORY,
|
||||
"XENOBIOLOGY_COMPATIBLE" = XENOBIOLOGY_COMPATIBLE,
|
||||
"NO_ALERTS" = NO_ALERTS,
|
||||
) ,
|
||||
"sight" = list(
|
||||
"SEE_INFRA" = SEE_INFRA,
|
||||
"SEE_SELF" = SEE_SELF,
|
||||
@@ -32,7 +49,12 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"UNIQUE_RENAME" = UNIQUE_RENAME,
|
||||
"USES_TGUI" = USES_TGUI,
|
||||
"FROZEN" = FROZEN,
|
||||
"SHOVABLE_ONTO" = SHOVABLE_ONTO
|
||||
"SHOVABLE_ONTO" = SHOVABLE_ONTO,
|
||||
"BLOCK_Z_OUT_DOWN" = BLOCK_Z_OUT_DOWN,
|
||||
"BLOCK_Z_OUT_UP" = BLOCK_Z_OUT_UP,
|
||||
"BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN,
|
||||
"BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP,
|
||||
"EXAMINE_SKIP" = EXAMINE_SKIP
|
||||
),
|
||||
"datum_flags" = list(
|
||||
"DF_USE_TAG" = DF_USE_TAG,
|
||||
@@ -259,6 +281,13 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
),
|
||||
"shield_flags" = list(
|
||||
"SHIELD_TRANSPARENT" = SHIELD_TRANSPARENT,
|
||||
"SHIELD_ENERGY_WEAK" = SHIELD_ENERGY_WEAK,
|
||||
"SHIELD_KINETIC_WEAK" = SHIELD_KINETIC_WEAK,
|
||||
"SHIELD_KINETIC_STRONG" = SHIELD_KINETIC_STRONG,
|
||||
"SHIELD_ENERGY_STRONG" = SHIELD_ENERGY_STRONG,
|
||||
"SHIELD_DISABLER_DISRUPTED" = SHIELD_DISABLER_DISRUPTED,
|
||||
"SHIELD_NO_RANGED" = SHIELD_NO_RANGED,
|
||||
"SHIELD_NO_MELEE" = SHIELD_NO_MELEE,
|
||||
"SHIELD_CAN_BASH" = SHIELD_CAN_BASH,
|
||||
"SHIELD_BASH_WALL_KNOCKDOWN" = SHIELD_BASH_WALL_KNOCKDOWN,
|
||||
"SHIELD_BASH_ALWAYS_KNOCKDOWN" = SHIELD_BASH_ALWAYS_KNOCKDOWN,
|
||||
|
||||
@@ -48,6 +48,9 @@ GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area)
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_abstract_markers)
|
||||
|
||||
/// Global list of megafauna spawns on cave gen
|
||||
GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/megafauna/dragon = 4, /mob/living/simple_animal/hostile/megafauna/colossus = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = 6))
|
||||
|
||||
GLOBAL_LIST_EMPTY(stationroom_landmarks) //List of all spawns for stationrooms
|
||||
|
||||
///Away missions, VR, random z levels stuff.
|
||||
|
||||
@@ -123,7 +123,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_HIGH_BLOOD" = TRAIT_HIGH_BLOOD,
|
||||
"TRAIT_EMPATH" = TRAIT_EMPATH,
|
||||
"TRAIT_FRIENDLY" = TRAIT_FRIENDLY,
|
||||
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT
|
||||
"TRAIT_IWASBATONED" = TRAIT_IWASBATONED
|
||||
),
|
||||
/obj/item/bodypart = list(
|
||||
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS
|
||||
|
||||
@@ -169,5 +169,9 @@
|
||||
A.attack_robot(src)
|
||||
|
||||
/atom/proc/attack_robot(mob/user)
|
||||
if((isturf(src) || istype(src, /obj/structure/table) || istype(src, /obj/machinery/conveyor)) && get_dist(user, src) <= 1)
|
||||
user.Move_Pulled(src)
|
||||
return
|
||||
|
||||
attack_ai(user)
|
||||
return
|
||||
|
||||
@@ -361,7 +361,7 @@
|
||||
/obj/screen/mov_intent/update_icon_state()
|
||||
switch(hud?.mymob?.m_intent)
|
||||
if(MOVE_INTENT_WALK)
|
||||
icon_state = "walking"
|
||||
icon_state = CONFIG_GET(flag/sprint_enabled)? "walking" : "walking_nosprint"
|
||||
if(MOVE_INTENT_RUN)
|
||||
icon_state = CONFIG_GET(flag/sprint_enabled)? "running" : "running_nosprint"
|
||||
|
||||
|
||||
@@ -85,21 +85,16 @@
|
||||
makeItemInactive()
|
||||
|
||||
/obj/screen/storage/volumetric_box/proc/makeItemInactive()
|
||||
if(!our_item)
|
||||
return
|
||||
our_item.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
|
||||
our_item.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
|
||||
return
|
||||
|
||||
/obj/screen/storage/volumetric_box/proc/makeItemActive()
|
||||
if(!our_item)
|
||||
return
|
||||
our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others!
|
||||
our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE
|
||||
return
|
||||
|
||||
/obj/screen/storage/volumetric_box/center
|
||||
icon_state = "stored_continue"
|
||||
var/obj/screen/storage/volumetric_edge/stored_left/left
|
||||
var/obj/screen/storage/volumetric_edge/stored_right/right
|
||||
var/obj/screen/storage/item_holder/holder
|
||||
var/pixel_size
|
||||
|
||||
/obj/screen/storage/volumetric_box/center/Initialize(mapload, new_master, our_item)
|
||||
@@ -110,6 +105,9 @@
|
||||
/obj/screen/storage/volumetric_box/center/Destroy()
|
||||
QDEL_NULL(left)
|
||||
QDEL_NULL(right)
|
||||
vis_contents.Cut()
|
||||
if(holder)
|
||||
QDEL_NULL(holder)
|
||||
return ..()
|
||||
|
||||
/obj/screen/storage/volumetric_box/center/proc/on_screen_objects()
|
||||
@@ -123,13 +121,36 @@
|
||||
return
|
||||
pixel_size = pixels
|
||||
cut_overlays()
|
||||
vis_contents.Cut()
|
||||
//our icon size is 32 pixels.
|
||||
transform = matrix((pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE, 0, 0, 0, 1, 0)
|
||||
var/multiplier = (pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE
|
||||
transform = matrix(multiplier, 0, 0, 0, 1, 0)
|
||||
if(our_item)
|
||||
if(holder)
|
||||
qdel(holder)
|
||||
holder = new(null, src, our_item)
|
||||
holder.transform = matrix(1 / multiplier, 0, 0, 0, 1, 0)
|
||||
holder.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
holder.appearance_flags &= ~RESET_TRANSFORM
|
||||
makeItemInactive()
|
||||
vis_contents += holder
|
||||
left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE
|
||||
right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE
|
||||
add_overlay(left)
|
||||
add_overlay(right)
|
||||
|
||||
/obj/screen/storage/volumetric_box/center/makeItemInactive()
|
||||
if(!holder)
|
||||
return
|
||||
holder.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
|
||||
holder.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
|
||||
|
||||
/obj/screen/storage/volumetric_box/center/makeItemActive()
|
||||
if(!holder)
|
||||
return
|
||||
holder.our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others!
|
||||
holder.our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE
|
||||
|
||||
/obj/screen/storage/volumetric_edge
|
||||
layer = VOLUMETRIC_STORAGE_BOX_LAYER
|
||||
plane = VOLUMETRIC_STORAGE_BOX_PLANE
|
||||
@@ -157,3 +178,20 @@
|
||||
/obj/screen/storage/volumetric_edge/stored_right
|
||||
icon_state = "stored_end"
|
||||
appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM
|
||||
|
||||
/obj/screen/storage/item_holder
|
||||
var/obj/item/our_item
|
||||
vis_flags = NONE
|
||||
|
||||
/obj/screen/storage/item_holder/Initialize(mapload, new_master, obj/item/I)
|
||||
. = ..()
|
||||
our_item = I
|
||||
vis_contents += I
|
||||
|
||||
/obj/screen/storage/item_holder/Destroy()
|
||||
vis_contents.Cut()
|
||||
our_item = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/storage/item_holder/Click(location, control, params)
|
||||
return our_item.Click(location, control, params)
|
||||
|
||||
@@ -94,8 +94,7 @@
|
||||
else if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
|
||||
M.lastattacker = user.real_name
|
||||
M.lastattackerckey = user.ckey
|
||||
M.set_last_attacker(user)
|
||||
|
||||
if(force && M == user && user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/selfouch, user)
|
||||
|
||||
@@ -404,9 +404,9 @@ Example config:
|
||||
if(!Get(/datum/config_entry/flag/no_storyteller_threat_removal))
|
||||
var/min_chaos = (probabilities in storyteller_min_chaos) ? storyteller_min_chaos[config_tag] : initial(S.min_chaos)
|
||||
var/max_chaos = (probabilities in storyteller_max_chaos) ? storyteller_max_chaos[config_tag] : initial(S.max_chaos)
|
||||
if(SSpersistence.average_dynamic_threat < min_chaos)
|
||||
if(SSpersistence.average_threat + 50 < min_chaos)
|
||||
continue
|
||||
if(SSpersistence.average_dynamic_threat > max_chaos)
|
||||
if(SSpersistence.average_threat + 50 > max_chaos)
|
||||
continue
|
||||
if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len)
|
||||
var/name = initial(S.name)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
SUBSYSTEM_DEF(activity)
|
||||
name = "Activity tracking"
|
||||
flags = SS_BACKGROUND | SS_NO_TICK_CHECK
|
||||
priority = FIRE_PRIORITY_ACTIVITY
|
||||
wait = 1 MINUTES
|
||||
var/list/deferred_threats = list()
|
||||
var/current_threat = 0
|
||||
var/list/threat_history = list()
|
||||
var/list/threats = list()
|
||||
|
||||
/datum/controller/subsystem/activity/Initialize(timeofday)
|
||||
RegisterSignal(SSdcs,COMSIG_GLOB_EXPLOSION,.proc/on_explosion)
|
||||
RegisterSignal(SSdcs,COMSIG_GLOB_MOB_DEATH,.proc/on_death)
|
||||
|
||||
/datum/controller/subsystem/activity/fire(resumed = 0)
|
||||
calculate_threat()
|
||||
|
||||
/datum/controller/subsystem/activity/proc/calculate_threat()
|
||||
threats = deferred_threats.Copy()
|
||||
deferred_threats.Cut()
|
||||
threats["antagonists"] = 0
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
if(A?.owner?.current && A.owner.current.stat != DEAD)
|
||||
threats["antagonists"] += A.threat()
|
||||
threats["events"] = 0
|
||||
for(var/r in SSevents.running)
|
||||
var/datum/round_event/R = r
|
||||
threats["events"] += R.threat()
|
||||
threats["players"] = 0
|
||||
SEND_SIGNAL(src, COMSIG_THREAT_CALC, threats)
|
||||
for(var/m in GLOB.player_list)
|
||||
var/mob/M = m
|
||||
if (M?.mind?.assigned_role && M.stat != DEAD)
|
||||
var/datum/job/J = SSjob.GetJob(M.mind.assigned_role)
|
||||
if(J)
|
||||
if(length(M.mind.antag_datums))
|
||||
threats["players"] += J.GetThreat()
|
||||
else
|
||||
threats["players"] -= J.GetThreat()
|
||||
else if(M?.stat == DEAD && !M.voluntary_ghosted)
|
||||
threats["dead_players"] += 1
|
||||
current_threat = 0
|
||||
for(var/threat_type in threats)
|
||||
current_threat += threats[threat_type]
|
||||
threat_history += "[world.time]"
|
||||
threat_history["[world.time]"] = current_threat
|
||||
|
||||
/datum/controller/subsystem/activity/proc/get_average_threat()
|
||||
if(!length(threat_history))
|
||||
return 0
|
||||
var/total_weight = 0
|
||||
var/total_amt = 0
|
||||
for(var/i in 1 to threat_history.len-1)
|
||||
var/weight = (text2num(threat_history[i+1])-text2num(threat_history[i]))
|
||||
total_weight += weight
|
||||
total_amt += weight * (threat_history[threat_history[i]])
|
||||
return round(total_amt / total_weight,0.1)
|
||||
|
||||
/datum/controller/subsystem/activity/proc/get_max_threat()
|
||||
. = 0
|
||||
for(var/threat in threat_history)
|
||||
. = max(threat_history[threat], .)
|
||||
|
||||
/datum/controller/subsystem/activity/proc/on_explosion(datum/source, atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
|
||||
if(!("explosions" in deferred_threats))
|
||||
deferred_threats["explosions"] = 0
|
||||
var/area/A = get_area(epicenter)
|
||||
if(is_station_level(epicenter.z) && (A.area_flags & BLOBS_ALLOWED) && !istype(A, /area/asteroid))
|
||||
deferred_threats["explosions"] += devastation_range**2 + heavy_impact_range**2 / 4 + light_impact_range**2 / 8 // 75 for a maxcap
|
||||
|
||||
/datum/controller/subsystem/activity/proc/on_death(datum/source, mob/M, gibbed)
|
||||
if(!("crew_deaths" in deferred_threats))
|
||||
deferred_threats["crew_deaths"] = 0
|
||||
if(M?.mind && SSjob.GetJob(M.mind.assigned_role))
|
||||
deferred_threats["crew_deaths"] += 1
|
||||
@@ -34,6 +34,9 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/reservation_ready = list()
|
||||
var/clearing_reserved_turfs = FALSE
|
||||
|
||||
///All possible biomes in assoc list as type || instance
|
||||
var/list/biomes = list()
|
||||
|
||||
// Z-manager stuff
|
||||
var/station_start // should only be used for maploading-related tasks
|
||||
var/space_levels_so_far = 0
|
||||
@@ -79,10 +82,12 @@ SUBSYSTEM_DEF(mapping)
|
||||
config = old_config
|
||||
GLOB.year_integer += config.year_offset
|
||||
GLOB.announcertype = (config.announcertype == "standard" ? (prob(1) ? "medibot" : "classic") : config.announcertype)
|
||||
initialize_biomes()
|
||||
loadWorld()
|
||||
repopulate_sorted_areas()
|
||||
process_teleport_locs() //Sets up the wizard teleport locations
|
||||
preloadTemplates()
|
||||
|
||||
#ifndef LOWMEMORYMODE
|
||||
// Create space ruin levels
|
||||
while (space_levels_so_far < config.space_ruin_levels)
|
||||
@@ -92,15 +97,16 @@ SUBSYSTEM_DEF(mapping)
|
||||
for (var/i in 1 to config.space_empty_levels)
|
||||
++space_levels_so_far
|
||||
empty_space = add_new_zlevel("Empty Area [space_levels_so_far]", list(ZTRAIT_LINKAGE = CROSSLINKED))
|
||||
// and the transit level
|
||||
transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE))
|
||||
|
||||
// Pick a random away mission.
|
||||
if(CONFIG_GET(flag/roundstart_away))
|
||||
createRandomZlevel()
|
||||
// Pick a random VR level.
|
||||
|
||||
// Load the virtual reality hub
|
||||
if(CONFIG_GET(flag/roundstart_vr))
|
||||
to_chat(world, "<span class='boldannounce'>Loading virtual reality...</span>")
|
||||
createRandomZlevel(VIRT_REALITY_NAME, list(ZTRAIT_AWAY = TRUE, ZTRAIT_VR = TRUE), GLOB.potential_vr_levels)
|
||||
to_chat(world, "<span class='boldannounce'>Virtual reality loaded.</span>")
|
||||
|
||||
// Generate mining ruins
|
||||
loading_ruins = TRUE
|
||||
@@ -115,7 +121,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// needs to be whitelisted for underground too so place_below ruins work
|
||||
seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), ice_ruins_templates)
|
||||
for (var/ice_z in ice_ruins)
|
||||
spawn_rivers(ice_z, 4, /turf/open/transparent/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers)
|
||||
spawn_rivers(ice_z, 4, /turf/open/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers)
|
||||
|
||||
var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND)
|
||||
if (ice_ruins_underground.len)
|
||||
@@ -133,8 +139,13 @@ SUBSYSTEM_DEF(mapping)
|
||||
if (station_ruins.len)
|
||||
seedRuins(station_ruins, (SSmapping.config.station_ruin_budget < 0) ? CONFIG_GET(number/station_space_budget) : SSmapping.config.station_ruin_budget, list(/area/space/station_ruins), station_ruins_templates)
|
||||
SSmapping.seedStation()
|
||||
|
||||
loading_ruins = FALSE
|
||||
#endif
|
||||
// Run map generation after ruin generation to prevent issues
|
||||
run_map_generation()
|
||||
// Add the transit level
|
||||
transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE))
|
||||
repopulate_sorted_areas()
|
||||
// Set up Z-level transitions.
|
||||
setup_map_transitions()
|
||||
@@ -320,7 +331,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
for(var/area/A in world)
|
||||
if (is_type_in_typecache(A, station_areas_blacklist))
|
||||
continue
|
||||
if (!A.contents.len || !A.unique)
|
||||
if (!A.contents.len || !(A.area_flags & UNIQUE_AREA))
|
||||
continue
|
||||
var/turf/picked = A.contents[1]
|
||||
if (is_station_level(picked.z))
|
||||
@@ -329,6 +340,10 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
if(!GLOB.the_station_areas.len)
|
||||
log_world("ERROR: Station areas list failed to generate!")
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/run_map_generation()
|
||||
for(var/area/A in world)
|
||||
A.RunGeneration()
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/maprotate()
|
||||
var/players = GLOB.clients.len
|
||||
var/list/mapvotes = list()
|
||||
@@ -584,6 +599,12 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
used_turfs.Cut()
|
||||
reserve_turfs(clearing)
|
||||
|
||||
///Initialize all biomes, assoc as type || instance
|
||||
/datum/controller/subsystem/mapping/proc/initialize_biomes()
|
||||
for(var/biome_path in subtypesof(/datum/biome))
|
||||
var/datum/biome/biome_instance = new biome_path()
|
||||
biomes[biome_path] += biome_instance
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/reg_in_areas_in_z(list/areas)
|
||||
for(var/B in areas)
|
||||
var/area/A = B
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(min_spawns)
|
||||
name = "Minimum Spawns" /// this hot steaming pile of garbage makes sure theres a minimum of tendrils scattered around
|
||||
init_order = INIT_ORDER_DEFAULT
|
||||
flags = SS_BACKGROUND | SS_NO_FIRE
|
||||
flags = SS_NO_FIRE | SS_NO_INIT
|
||||
wait = 2
|
||||
var/where_we_droppin_boys_iterations = 0
|
||||
var/snaxi_snowflake_check = FALSE
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var/list/saved_chaos = list(5,5,5)
|
||||
var/list/saved_dynamic_rules = list(list(),list(),list())
|
||||
var/list/saved_storytellers = list("foo","bar","baz")
|
||||
var/list/average_dynamic_threat = 50
|
||||
var/average_threat = 50
|
||||
var/list/saved_maps
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveServerPersistence()
|
||||
@@ -38,9 +38,10 @@
|
||||
saved_chaos[3] = saved_chaos[2]
|
||||
saved_chaos[2] = saved_chaos[1]
|
||||
saved_chaos[1] = SSticker.mode.get_chaos()
|
||||
average_threat = (SSactivity.get_average_threat() + average_threat) / 2
|
||||
json_file = file("data/RecentChaos.json")
|
||||
file_data = list()
|
||||
file_data["data"] = saved_chaos
|
||||
file_data["data"] = saved_chaos + average_threat
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
@@ -49,10 +50,9 @@
|
||||
saved_storytellers[3] = saved_storytellers[2]
|
||||
saved_storytellers[2] = saved_storytellers[1]
|
||||
saved_storytellers[1] = mode.storyteller.name
|
||||
average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_storytellers + average_dynamic_threat
|
||||
file_data["data"] = saved_storytellers
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
if(!json)
|
||||
return
|
||||
saved_chaos = json["data"]
|
||||
if(saved_chaos.len > 3)
|
||||
average_threat = saved_chaos[4]
|
||||
saved_chaos.len = 3
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
@@ -112,9 +115,6 @@
|
||||
if(!json)
|
||||
return
|
||||
saved_storytellers = json["data"]
|
||||
if(saved_storytellers.len > 3)
|
||||
average_dynamic_threat = saved_storytellers[4]
|
||||
saved_storytellers.len = 3
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/datum/component/activity
|
||||
var/activity_level = 0
|
||||
var/not_moved_counter = 0
|
||||
var/list/historical_activity_levels = list()
|
||||
|
||||
/datum/component/activity/Initialize()
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/living/L = parent
|
||||
|
||||
RegisterSignal(L, COMSIG_LIVING_SET_AS_ATTACKER, .proc/on_set_as_attacker)
|
||||
RegisterSignal(L, COMSIG_LIVING_ATTACKER_SET, .proc/on_attacker_set)
|
||||
RegisterSignal(L, COMSIG_MOB_DEATH, .proc/on_death)
|
||||
RegisterSignal(L, COMSIG_EXIT_AREA, .proc/on_exit_area)
|
||||
RegisterSignal(L, COMSIG_LIVING_LIFE, .proc/on_life)
|
||||
RegisterSignal(L, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE, COMSIG_MOB_APPLY_DAMAGE), .proc/minor_activity)
|
||||
|
||||
/datum/component/activity/proc/log_activity()
|
||||
historical_activity_levels[world.time] = activity_level
|
||||
|
||||
/datum/component/activity/proc/minor_activity(datum/source)
|
||||
activity_level += 1
|
||||
|
||||
/datum/component/activity/proc/on_attacker_set(datum/source, mob/attacker)
|
||||
activity_level += 10
|
||||
if(attacker?.mind)
|
||||
activity_level += 10
|
||||
log_activity()
|
||||
|
||||
/datum/component/activity/proc/on_set_as_attacker(datum/source, mob/target)
|
||||
activity_level += 10
|
||||
if(target?.mind)
|
||||
activity_level += 20
|
||||
log_activity()
|
||||
|
||||
/datum/component/activity/proc/on_death(datum/source)
|
||||
activity_level += 100 // dying means you're doing SOMETHING
|
||||
log_activity()
|
||||
|
||||
/datum/component/activity/proc/on_exit_area(datum/source)
|
||||
activity_level += 1
|
||||
not_moved_counter = 0
|
||||
|
||||
/datum/component/activity/proc/on_life(datum/source, seconds, times_fired)
|
||||
var/mob/living/L = source
|
||||
if(L.stat >= UNCONSCIOUS) // can't expect the unconscious to move
|
||||
return
|
||||
not_moved_counter += seconds
|
||||
var/should_log = FALSE
|
||||
switch(not_moved_counter)
|
||||
if(60 to 120)
|
||||
activity_level -= 1
|
||||
if(120 to 600)
|
||||
activity_level -= 5
|
||||
if(600 to 1200)
|
||||
activity_level -= 10
|
||||
should_log = TRUE
|
||||
if(1200 to INFINITY)
|
||||
activity_level -= 20
|
||||
should_log = TRUE
|
||||
activity_level = max(activity_level, 0)
|
||||
if(should_log)
|
||||
log_activity()
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
|
||||
var/meat_quality = 50 + (bonus_modifier/10) //increases through quality of butchering tool, and through if it was butchered in the kitchen or not
|
||||
if(istype(get_area(butcher), /area/crew_quarters/kitchen))
|
||||
if(istype(get_area(butcher), /area/service/kitchen))
|
||||
meat_quality = meat_quality + 10
|
||||
var/turf/T = meat.drop_location()
|
||||
var/final_effectiveness = effectiveness - meat.butcher_difficulty
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
/datum/crafting_recipe/strobeshield
|
||||
name = "Strobe Shield"
|
||||
result = /obj/item/assembly/flash/shield
|
||||
result = /obj/item/shield/riot/flash
|
||||
reqs = list(/obj/item/wallframe/flasher = 1,
|
||||
/obj/item/assembly/flash/handheld = 1,
|
||||
/obj/item/shield/riot = 1)
|
||||
|
||||
@@ -56,10 +56,10 @@
|
||||
detonate()
|
||||
|
||||
/datum/component/explodable/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMGE, .proc/explodable_attack_zone, TRUE)
|
||||
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMAGE, .proc/explodable_attack_zone, TRUE)
|
||||
|
||||
/datum/component/explodable/proc/on_drop(datum/source, mob/user)
|
||||
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMGE)
|
||||
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMAGE)
|
||||
|
||||
/// Checks if we're hitting the zone this component is covering
|
||||
/datum/component/explodable/proc/is_hitting_zone(def_zone)
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
return
|
||||
strength -= strength / hl3_release_date
|
||||
if(strength <= RAD_BACKGROUND_RADIATION)
|
||||
return PROCESS_KILL
|
||||
qdel(src)
|
||||
|
||||
|
||||
/datum/component/radioactive/proc/glow_loop(atom/movable/master)
|
||||
|
||||
@@ -47,18 +47,8 @@
|
||||
|
||||
var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number.
|
||||
|
||||
/// "legacy"/default view mode's storage "boxes"
|
||||
var/obj/screen/storage/boxes/ui_boxes
|
||||
/// New volumetric storage display mode's left side
|
||||
var/obj/screen/storage/left/ui_left
|
||||
/// New volumetric storage display mode's center 'blocks'
|
||||
var/obj/screen/storage/continuous/ui_continuous
|
||||
/// The close button, used in all modes. Frames right side in volumetric mode.
|
||||
var/obj/screen/storage/close/ui_close
|
||||
/// Associative list of list(item = screen object) for volumetric storage item screen blocks
|
||||
var/list/ui_item_blocks
|
||||
|
||||
var/current_maxscreensize
|
||||
/// Ui objects by person. mob = list(objects)
|
||||
var/list/ui_by_mob = list()
|
||||
|
||||
var/allow_big_nesting = FALSE //allow storage objects of the same or greater size.
|
||||
|
||||
@@ -125,18 +115,16 @@
|
||||
|
||||
/datum/component/storage/Destroy()
|
||||
close_all()
|
||||
QDEL_NULL(ui_boxes)
|
||||
QDEL_NULL(ui_close)
|
||||
QDEL_NULL(ui_continuous)
|
||||
QDEL_NULL(ui_left)
|
||||
// DO NOT USE QDEL_LIST_ASSOC.
|
||||
if(ui_item_blocks)
|
||||
for(var/i in ui_item_blocks)
|
||||
qdel(ui_item_blocks[i]) //qdel the screen object not the item
|
||||
ui_item_blocks.Cut()
|
||||
wipe_ui_objects()
|
||||
LAZYCLEARLIST(is_using)
|
||||
return ..()
|
||||
|
||||
/datum/component/storage/proc/wipe_ui_objects()
|
||||
for(var/i in ui_by_mob)
|
||||
var/list/objects = ui_by_mob[i]
|
||||
QDEL_LIST(objects)
|
||||
ui_by_mob.Cut()
|
||||
|
||||
/datum/component/storage/PreTransfer()
|
||||
update_actions()
|
||||
|
||||
@@ -351,13 +339,6 @@
|
||||
return master._removal_reset(thing)
|
||||
|
||||
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
|
||||
if(LAZYACCESS(ui_item_blocks, thing))
|
||||
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
|
||||
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
|
||||
var/mob/M = i
|
||||
M.client?.screen -= C.on_screen_objects()
|
||||
ui_item_blocks -= thing
|
||||
qdel(C)
|
||||
_removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
|
||||
refresh_mob_views()
|
||||
|
||||
@@ -467,14 +448,14 @@
|
||||
return
|
||||
A.add_fingerprint(M)
|
||||
|
||||
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE, ghost = FALSE)
|
||||
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
|
||||
var/atom/A = parent
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
A.add_fingerprint(M)
|
||||
if(!force && (check_locked(null, M) || !M.CanReach(parent, view_only = TRUE)))
|
||||
return FALSE
|
||||
ui_show(M, !ghost)
|
||||
ui_show(M)
|
||||
|
||||
/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
|
||||
if(isitem(O))
|
||||
@@ -596,7 +577,7 @@
|
||||
return can_be_inserted(I, silent, M)
|
||||
|
||||
/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M)
|
||||
return user_show_to_mob(M, TRUE, TRUE)
|
||||
return user_show_to_mob(M, TRUE)
|
||||
|
||||
/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE)
|
||||
return user_show_to_mob(showto, force)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
if(QDELETED(I))
|
||||
continue
|
||||
if(!.[I.type])
|
||||
.[I.type] = new /datum/numbered_display(I, 1)
|
||||
.[I.type] = new /datum/numbered_display(I, 1, src)
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.type]
|
||||
ND.number++
|
||||
@@ -20,6 +20,8 @@
|
||||
. = list()
|
||||
var/list/accessible_contents = accessible_items()
|
||||
var/adjusted_contents = length(accessible_contents)
|
||||
var/obj/screen/storage/close/ui_close
|
||||
var/obj/screen/storage/boxes/ui_boxes
|
||||
|
||||
//Numbered contents display
|
||||
var/list/datum/numbered_display/numbered_contents
|
||||
@@ -60,12 +62,13 @@
|
||||
for(var/obj/O in accessible_items())
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
|
||||
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
var/obj/screen/storage/item_holder/D = new(null, src, O)
|
||||
D.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
|
||||
D.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
O.maptext = ""
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
. += O
|
||||
. += D
|
||||
cx++
|
||||
if(cx - screen_start_x >= columns)
|
||||
cx = screen_start_x
|
||||
@@ -78,6 +81,9 @@
|
||||
*/
|
||||
/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns)
|
||||
. = list()
|
||||
var/obj/screen/storage/left/ui_left
|
||||
var/obj/screen/storage/continuous/ui_continuous
|
||||
var/obj/screen/storage/close/ui_close
|
||||
|
||||
// Generate ui_item_blocks for missing ones and render+orient.
|
||||
var/list/atom/contents = accessible_items()
|
||||
@@ -128,14 +134,10 @@
|
||||
var/first = TRUE
|
||||
var/row = 1
|
||||
|
||||
LAZYINITLIST(ui_item_blocks)
|
||||
|
||||
for(var/i in percentage_by_item)
|
||||
I = i
|
||||
var/percent = percentage_by_item[I]
|
||||
if(!ui_item_blocks[I])
|
||||
ui_item_blocks[I] = new /obj/screen/storage/volumetric_box/center(null, src, I)
|
||||
var/obj/screen/storage/volumetric_box/center/B = ui_item_blocks[I]
|
||||
var/obj/screen/storage/volumetric_box/center/B = new /obj/screen/storage/volumetric_box/center(null, src, I)
|
||||
var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM)
|
||||
var/addrow = FALSE
|
||||
if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1))
|
||||
@@ -143,25 +145,17 @@
|
||||
addrow = TRUE
|
||||
|
||||
// now that we have pixels_to_use, place our thing and add it to the returned list.
|
||||
B.screen_loc = I.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]"
|
||||
B.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]"
|
||||
// add the used pixels to pixel after we place the object
|
||||
current_pixel += pixels_to_use + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING)
|
||||
first = FALSE //apply padding to everything after this
|
||||
|
||||
// set various things
|
||||
B.set_pixel_size(pixels_to_use)
|
||||
B.layer = VOLUMETRIC_STORAGE_BOX_LAYER
|
||||
B.plane = VOLUMETRIC_STORAGE_BOX_PLANE
|
||||
B.name = I.name
|
||||
|
||||
I.mouse_opacity = MOUSE_OPACITY_ICON
|
||||
I.maptext = ""
|
||||
I.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
|
||||
I.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
|
||||
|
||||
// finally add our things.
|
||||
. += B.on_screen_objects()
|
||||
. += I
|
||||
|
||||
// go up a row if needed
|
||||
if(addrow)
|
||||
@@ -185,18 +179,19 @@
|
||||
/**
|
||||
* Shows our UI to a mob.
|
||||
*/
|
||||
/datum/component/storage/proc/ui_show(mob/M, set_screen_size = TRUE)
|
||||
/datum/component/storage/proc/ui_show(mob/M)
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
if(ui_by_mob[M] || LAZYFIND(is_using, M))
|
||||
// something went horribly wrong
|
||||
// hide first
|
||||
ui_hide(M)
|
||||
var/list/cview = getviewsize(M.client.view)
|
||||
// in tiles
|
||||
var/maxallowedscreensize = cview[1]-8
|
||||
if(set_screen_size)
|
||||
current_maxscreensize = maxallowedscreensize
|
||||
else if(current_maxscreensize)
|
||||
maxallowedscreensize = current_maxscreensize
|
||||
// we got screen size, register signal
|
||||
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_logout, override = TRUE)
|
||||
RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/on_logout, override = TRUE)
|
||||
if(M.active_storage != src)
|
||||
if(M.active_storage)
|
||||
M.active_storage.ui_hide(M)
|
||||
@@ -204,10 +199,14 @@
|
||||
LAZYOR(is_using, M)
|
||||
if(!M.client?.prefs?.no_tetris_storage && volumetric_ui())
|
||||
//new volumetric ui bay-style
|
||||
M.client.screen |= orient2hud_volumetric(M, maxallowedscreensize)
|
||||
var/list/objects = orient2hud_volumetric(M, maxallowedscreensize)
|
||||
M.client.screen |= objects
|
||||
ui_by_mob[M] = objects
|
||||
else
|
||||
//old ui
|
||||
M.client.screen |= orient2hud_legacy(M, maxallowedscreensize)
|
||||
var/list/objects = orient2hud_legacy(M, maxallowedscreensize)
|
||||
M.client.screen |= objects
|
||||
ui_by_mob[M] = objects
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
@@ -236,8 +235,10 @@
|
||||
/datum/component/storage/proc/ui_hide(mob/M)
|
||||
if(!M.client)
|
||||
return TRUE
|
||||
UnregisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT)
|
||||
M.client.screen -= list(ui_boxes, ui_close, ui_left, ui_continuous) + get_ui_item_objects_hide(M)
|
||||
UnregisterSignal(M, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_CLIENT_LOGOUT))
|
||||
M.client.screen -= ui_by_mob[M]
|
||||
var/list/objects = ui_by_mob[M]
|
||||
QDEL_LIST(objects)
|
||||
if(M.active_storage == src)
|
||||
M.active_storage = null
|
||||
LAZYREMOVE(is_using, M)
|
||||
@@ -250,48 +251,26 @@
|
||||
var/atom/real_location = real_location()
|
||||
return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking
|
||||
|
||||
/**
|
||||
* Gets the ui item objects to ui_hide.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_item_objects_hide(mob/M)
|
||||
if(!volumetric_ui() || M.client?.prefs?.no_tetris_storage)
|
||||
var/atom/real_location = real_location()
|
||||
return real_location.contents
|
||||
else
|
||||
. = list()
|
||||
for(var/i in ui_item_blocks)
|
||||
// get both the box and the item
|
||||
. += ui_item_blocks[i]
|
||||
. += i
|
||||
|
||||
/**
|
||||
* Gets our ui_boxes, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_boxes()
|
||||
if(!ui_boxes)
|
||||
ui_boxes = new(null, src)
|
||||
return ui_boxes
|
||||
return new /obj/screen/storage/boxes(null, src)
|
||||
|
||||
/**
|
||||
* Gets our ui_left, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_left()
|
||||
if(!ui_left)
|
||||
ui_left = new(null, src)
|
||||
return ui_left
|
||||
return new /obj/screen/storage/left(null, src)
|
||||
|
||||
/**
|
||||
* Gets our ui_close, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_close()
|
||||
if(!ui_close)
|
||||
ui_close = new(null, src)
|
||||
return ui_close
|
||||
return new /obj/screen/storage/close(null, src)
|
||||
|
||||
/**
|
||||
* Gets our ui_continuous, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_continuous()
|
||||
if(!ui_continuous)
|
||||
ui_continuous = new(null, src)
|
||||
return ui_continuous
|
||||
return new /obj/screen/storage/continuous(null, src)
|
||||
|
||||
@@ -384,7 +384,7 @@
|
||||
var/temp_rate = 1
|
||||
threshold_desc = list(
|
||||
"Transmission 6" = "Additionally increases temperature adjustment rate and heals those who love toxins",
|
||||
"Resistance 7" = "Increases healing speed.",
|
||||
"Stage Speed 7" = "Increases healing speed.",
|
||||
)
|
||||
/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
|
||||
if(!..())
|
||||
|
||||
+3
-2
@@ -329,12 +329,13 @@
|
||||
uni_identity = generate_uni_identity()
|
||||
unique_enzymes = generate_unique_enzymes()
|
||||
|
||||
/datum/dna/proc/initialize_dna(newblood_type)
|
||||
/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE)
|
||||
if(newblood_type)
|
||||
blood_type = newblood_type
|
||||
unique_enzymes = generate_unique_enzymes()
|
||||
uni_identity = generate_uni_identity()
|
||||
generate_dna_blocks()
|
||||
if(!skip_index) //I hate this
|
||||
generate_dna_blocks()
|
||||
features = random_features(species?.id, holder?.gender)
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
/**
|
||||
* A holder for simple behaviour that can be attached to many different types
|
||||
*
|
||||
* Only one element of each type is instanced during game init.
|
||||
* Otherwise acts basically like a lightweight component.
|
||||
*/
|
||||
* A holder for simple behaviour that can be attached to many different types
|
||||
*
|
||||
* Only one element of each type is instanced during game init.
|
||||
* Otherwise acts basically like a lightweight component.
|
||||
*/
|
||||
/datum/element
|
||||
/// Option flags for element behaviour
|
||||
var/element_flags = NONE
|
||||
/**
|
||||
* The index of the first attach argument to consider for duplicate elements
|
||||
* Is only used when flags contains ELEMENT_BESPOKE
|
||||
*
|
||||
* Is only used when flags contains [ELEMENT_BESPOKE]
|
||||
*
|
||||
* This is infinity so you must explicitly set this
|
||||
*/
|
||||
var/id_arg_index = INFINITY
|
||||
|
||||
/// Activates the functionality defined by the element on the given target datum
|
||||
/datum/element/proc/Attach(datum/target)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(type == /datum/element)
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
|
||||
@@ -25,8 +27,10 @@
|
||||
|
||||
/// Deactivates the functionality defines by the element on the given datum
|
||||
/datum/element/proc/Detach(datum/source, force)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
|
||||
|
||||
/datum/element/Destroy(force)
|
||||
@@ -45,9 +49,9 @@
|
||||
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
|
||||
|
||||
/**
|
||||
* Finds the singleton for the element type given and detaches it from src
|
||||
* You only need additional arguments beyond the type if you're using ELEMENT_BESPOKE
|
||||
*/
|
||||
* Finds the singleton for the element type given and detaches it from src
|
||||
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
|
||||
*/
|
||||
/datum/proc/_RemoveElement(list/arguments)
|
||||
var/datum/element/ele = SSdcs.GetElement(arguments)
|
||||
ele.Detach(src)
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
|
||||
/obj/item/clothing/head/mob_holder/dropped(mob/user)
|
||||
. = ..()
|
||||
if(held_mob && !ismob(loc))//don't release on soft-drops
|
||||
if(held_mob && !ismob(loc) && !istype(loc,/obj/item/storage))//don't release on soft-drops
|
||||
release()
|
||||
|
||||
/obj/item/clothing/head/mob_holder/proc/release()
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/datum/element/turf_z_transparency
|
||||
var/show_bottom_level = FALSE
|
||||
|
||||
///This proc sets up the signals to handle updating viscontents when turfs above/below update. Handle plane and layer here too so that they don't cover other obs/turfs in Dream Maker
|
||||
/datum/element/turf_z_transparency/Attach(datum/target, show_bottom_level = TRUE)
|
||||
. = ..()
|
||||
if(!isturf(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
var/turf/our_turf = target
|
||||
|
||||
src.show_bottom_level = show_bottom_level
|
||||
|
||||
our_turf.plane = OPENSPACE_PLANE
|
||||
our_turf.layer = OPENSPACE_LAYER
|
||||
|
||||
RegisterSignal(target, COMSIG_TURF_MULTIZ_DEL, .proc/on_multiz_turf_del)
|
||||
RegisterSignal(target, COMSIG_TURF_MULTIZ_NEW, .proc/on_multiz_turf_new)
|
||||
|
||||
ADD_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, TURF_TRAIT)
|
||||
|
||||
|
||||
update_multiz(our_turf, TRUE, TRUE)
|
||||
|
||||
/datum/element/turf_z_transparency/Detach(datum/source, force)
|
||||
. = ..()
|
||||
var/turf/our_turf = source
|
||||
our_turf.vis_contents.len = 0
|
||||
REMOVE_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, TURF_TRAIT)
|
||||
|
||||
///Updates the viscontents or underlays below this tile.
|
||||
/datum/element/turf_z_transparency/proc/update_multiz(turf/our_turf, prune_on_fail = FALSE, init = FALSE)
|
||||
var/turf/below_turf = our_turf.below()
|
||||
if(!below_turf)
|
||||
our_turf.vis_contents.len = 0
|
||||
if(!show_bottom_level(our_turf) && prune_on_fail) //If we cant show whats below, and we prune on fail, change the turf to plating as a fallback
|
||||
our_turf.ChangeTurf(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
|
||||
return FALSE
|
||||
if(init)
|
||||
our_turf.vis_contents += below_turf
|
||||
if(isclosedturf(our_turf)) //Show girders below closed turfs
|
||||
var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = TURF_LAYER-0.01)
|
||||
girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += girder_underlay
|
||||
var/mutable_appearance/plating_underlay = mutable_appearance('icons/turf/floors.dmi', "plating", layer = TURF_LAYER-0.02)
|
||||
plating_underlay = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += plating_underlay
|
||||
return TRUE
|
||||
|
||||
/datum/element/turf_z_transparency/proc/on_multiz_turf_del(turf/our_turf, turf/T, dir)
|
||||
SIGNAL_HANDLER
|
||||
if(dir != DOWN)
|
||||
return
|
||||
update_multiz(our_turf)
|
||||
|
||||
/datum/element/turf_z_transparency/proc/on_multiz_turf_new(turf/our_turf, turf/T, dir)
|
||||
SIGNAL_HANDLER
|
||||
if(dir != DOWN)
|
||||
return
|
||||
update_multiz(our_turf)
|
||||
|
||||
///Called when there is no real turf below this turf
|
||||
/datum/element/turf_z_transparency/proc/show_bottom_level(turf/our_turf)
|
||||
if(!show_bottom_level)
|
||||
return FALSE
|
||||
var/turf/path = SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF) || /turf/open/space
|
||||
if(!ispath(path))
|
||||
path = text2path(path)
|
||||
if(!ispath(path))
|
||||
warning("Z-level [our_turf.z] has invalid baseturf '[SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF)]'")
|
||||
path = /turf/open/space
|
||||
var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), initial(path.icon_state), layer = TURF_LAYER-0.02, plane = PLANE_SPACE)
|
||||
underlay_appearance.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += underlay_appearance
|
||||
return TRUE
|
||||
@@ -34,13 +34,13 @@
|
||||
. = ..()
|
||||
UnregisterSignal(source, COMSIG_MOB_ATTACK_HAND)
|
||||
|
||||
/datum/element/wuv/proc/on_attack_hand(datum/source, mob/user)
|
||||
/datum/element/wuv/proc/on_attack_hand(datum/source, mob/user, act_intent)
|
||||
var/mob/living/L = source
|
||||
|
||||
if(L.stat == DEAD)
|
||||
return
|
||||
//we want to delay the effect to be displayed after the mob is petted, not before.
|
||||
switch(user.a_intent)
|
||||
switch(act_intent)
|
||||
if(INTENT_HARM)
|
||||
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
|
||||
if(INTENT_HELP)
|
||||
|
||||
@@ -317,6 +317,8 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
|
||||
var/took = (REALTIMEOFDAY - started_at) / 10
|
||||
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPLOSION,epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
|
||||
|
||||
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
|
||||
if(GLOB.Debug2)
|
||||
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// effectout: effect to show right after teleportation
|
||||
// asoundin: soundfile to play before teleportation
|
||||
// asoundout: soundfile to play after teleportation
|
||||
// no_effects: disable the default effectin/effectout of sparks
|
||||
// forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation)
|
||||
// no_effects: disable the default effectin/effectout of sparks
|
||||
// forced: whether or not to ignore no_teleport
|
||||
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
|
||||
// teleporting most effects just deletes them
|
||||
@@ -15,7 +15,8 @@
|
||||
)) - typecacheof(list(
|
||||
/obj/effect/dummy/chameleon,
|
||||
/obj/effect/wisp,
|
||||
/obj/effect/mob_spawn
|
||||
/obj/effect/mob_spawn,
|
||||
/obj/effect/immovablerod,
|
||||
))
|
||||
if(delete_atoms[teleatom.type])
|
||||
qdel(teleatom)
|
||||
@@ -66,7 +67,7 @@
|
||||
|
||||
var/area/A = get_area(curturf)
|
||||
var/area/B = get_area(destturf)
|
||||
if(!forced && (HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT) || A.noteleport || B.noteleport))
|
||||
if(!forced && (HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT) || (A.area_flags & NOTELEPORT) || (B.area_flags & NOTELEPORT)))
|
||||
return FALSE
|
||||
|
||||
if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
|
||||
@@ -99,13 +100,13 @@
|
||||
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
|
||||
if (location && !isobserver(teleatom))
|
||||
if (sound)
|
||||
playsound(location, sound, 60, 1)
|
||||
playsound(location, sound, 60, TRUE)
|
||||
if (effect)
|
||||
effect.attach(location)
|
||||
effect.start()
|
||||
|
||||
// Safe location finder
|
||||
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE)
|
||||
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE, dense_atoms = TRUE)
|
||||
if(!zlevels)
|
||||
if (zlevel)
|
||||
zlevels = list(zlevel)
|
||||
@@ -122,12 +123,17 @@
|
||||
if(!isfloorturf(random_location))
|
||||
continue
|
||||
var/turf/open/floor/F = random_location
|
||||
var/area/destination_area = F.loc
|
||||
|
||||
if(cycle < 300 && destination_area.area_flags & NOTELEPORT)//if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
|
||||
continue
|
||||
if(!F.air)
|
||||
continue
|
||||
|
||||
var/datum/gas_mixture/A = F.air
|
||||
var/list/A_gases = A.get_gases()
|
||||
var/trace_gases
|
||||
for(var/id in A.get_gases())
|
||||
for(var/id in A_gases)
|
||||
if(id in GLOB.hardcoded_gases)
|
||||
continue
|
||||
trace_gases = TRUE
|
||||
@@ -136,7 +142,7 @@
|
||||
// Can most things breathe?
|
||||
if(trace_gases)
|
||||
continue
|
||||
if(A.get_moles(/datum/gas/oxygen) < 16)
|
||||
if(A.get_moles(/datum/gas/oxygen) >= 16)
|
||||
continue
|
||||
if(A.get_moles(/datum/gas/plasma))
|
||||
continue
|
||||
@@ -156,6 +162,16 @@
|
||||
if(!L.is_safe())
|
||||
continue
|
||||
|
||||
// Check that we're not warping onto a table or window
|
||||
if(!dense_atoms)
|
||||
var/density_found = FALSE
|
||||
for(var/atom/movable/found_movable in F)
|
||||
if(found_movable.density)
|
||||
density_found = TRUE
|
||||
break
|
||||
if(density_found)
|
||||
continue
|
||||
|
||||
// DING! You have passed the gauntlet, and are "probably" safe.
|
||||
return F
|
||||
|
||||
@@ -167,9 +183,11 @@
|
||||
if(T.is_transition_turf())
|
||||
continue // Avoid picking these.
|
||||
var/area/A = T.loc
|
||||
if(!A.noteleport)
|
||||
if(!(A.area_flags & NOTELEPORT))
|
||||
posturfs.Add(T)
|
||||
return posturfs
|
||||
|
||||
/proc/get_teleport_turf(turf/center, precision = 0)
|
||||
return safepick(get_teleport_turfs(center, precision))
|
||||
var/list/turfs = get_teleport_turfs(center, precision)
|
||||
if (length(turfs))
|
||||
return pick(turfs)
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/datum/map_generator/cave_generator
|
||||
var/name = "Cave Generator"
|
||||
///Weighted list of the types that spawns if the turf is open
|
||||
var/open_turf_types = list(/turf/open/floor/plating/asteroid/airless = 1)
|
||||
///Weighted list of the types that spawns if the turf is closed
|
||||
var/closed_turf_types = list(/turf/closed/mineral/random = 1)
|
||||
|
||||
|
||||
///Weighted list of mobs that can spawn in the area.
|
||||
var/list/mob_spawn_list
|
||||
// Weighted list of Megafauna that can spawn in the caves
|
||||
var/list/megafauna_spawn_list
|
||||
///Weighted list of flora that can spawn in the area.
|
||||
var/list/flora_spawn_list
|
||||
///Weighted list of extra features that can spawn in the area, such as geysers.
|
||||
var/list/feature_spawn_list
|
||||
|
||||
|
||||
///Base chance of spawning a mob
|
||||
var/mob_spawn_chance = 6
|
||||
///Base chance of spawning flora
|
||||
var/flora_spawn_chance = 2
|
||||
///Base chance of spawning features
|
||||
var/feature_spawn_chance = 0.1
|
||||
///Unique ID for this spawner
|
||||
var/string_gen
|
||||
|
||||
///Chance of cells starting closed
|
||||
var/initial_closed_chance = 45
|
||||
///Amount of smoothing iterations
|
||||
var/smoothing_iterations = 20
|
||||
///How much neighbours does a dead cell need to become alive
|
||||
var/birth_limit = 4
|
||||
///How little neighbours does a alive cell need to die
|
||||
var/death_limit = 3
|
||||
|
||||
/datum/map_generator/cave_generator/New()
|
||||
. = ..()
|
||||
if(!mob_spawn_list)
|
||||
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 1, /mob/living/simple_animal/hostile/asteroid/goliath = 5, /mob/living/simple_animal/hostile/asteroid/basilisk = 4, /mob/living/simple_animal/hostile/asteroid/hivelord = 3)
|
||||
if(!megafauna_spawn_list)
|
||||
megafauna_spawn_list = GLOB.megafauna_spawn_list
|
||||
if(!flora_spawn_list)
|
||||
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
|
||||
if(!feature_spawn_list)
|
||||
feature_spawn_list = list(/obj/structure/geyser/random = 1)
|
||||
|
||||
/datum/map_generator/cave_generator/generate_terrain(list/turfs)
|
||||
. = ..()
|
||||
var/start_time = REALTIMEOFDAY
|
||||
string_gen = rustg_cnoise_generate("[initial_closed_chance]", "[smoothing_iterations]", "[birth_limit]", "[death_limit]", "[world.maxx]", "[world.maxy]") //Generate the raw CA data
|
||||
|
||||
for(var/i in turfs) //Go through all the turfs and generate them
|
||||
var/turf/gen_turf = i
|
||||
|
||||
var/area/A = gen_turf.loc
|
||||
if(!(A.area_flags & CAVES_ALLOWED))
|
||||
continue
|
||||
|
||||
var/closed = text2num(string_gen[world.maxx * (gen_turf.y - 1) + gen_turf.x])
|
||||
|
||||
var/stored_flags
|
||||
if(gen_turf.flags_1 & NO_RUINS_1)
|
||||
stored_flags |= NO_RUINS_1
|
||||
|
||||
var/turf/new_turf = pickweight(closed ? closed_turf_types : open_turf_types)
|
||||
|
||||
new_turf = gen_turf.ChangeTurf(new_turf, initial(new_turf.baseturfs), CHANGETURF_DEFER_CHANGE)
|
||||
|
||||
new_turf.flags_1 |= stored_flags
|
||||
|
||||
if(!closed)//Open turfs have some special behavior related to spawning flora and mobs.
|
||||
|
||||
var/turf/open/new_open_turf = new_turf
|
||||
|
||||
///Spawning isn't done in procs to save on overhead on the 60k turfs we're going through.
|
||||
|
||||
//FLORA SPAWNING HERE
|
||||
var/atom/spawned_flora
|
||||
if(flora_spawn_list && prob(flora_spawn_chance))
|
||||
var/can_spawn = TRUE
|
||||
|
||||
if(!(A.area_flags & FLORA_ALLOWED))
|
||||
can_spawn = FALSE
|
||||
if(can_spawn)
|
||||
spawned_flora = pickweight(flora_spawn_list)
|
||||
spawned_flora = new spawned_flora(new_open_turf)
|
||||
|
||||
//FEATURE SPAWNING HERE
|
||||
var/atom/spawned_feature
|
||||
if(feature_spawn_list && prob(feature_spawn_chance))
|
||||
var/can_spawn = TRUE
|
||||
|
||||
if(!(A.area_flags & FLORA_ALLOWED)) //checks the same flag because lol dunno
|
||||
can_spawn = FALSE
|
||||
|
||||
var/atom/picked_feature = pickweight(feature_spawn_list)
|
||||
|
||||
for(var/obj/structure/F in range(7, new_open_turf))
|
||||
if(istype(F, picked_feature))
|
||||
can_spawn = FALSE
|
||||
|
||||
if(can_spawn)
|
||||
spawned_feature = new picked_feature(new_open_turf)
|
||||
|
||||
//MOB SPAWNING HERE
|
||||
|
||||
if(mob_spawn_list && !spawned_flora && !spawned_feature && prob(mob_spawn_chance))
|
||||
var/can_spawn = TRUE
|
||||
|
||||
if(!(A.area_flags & MOB_SPAWN_ALLOWED))
|
||||
can_spawn = FALSE
|
||||
|
||||
var/atom/picked_mob = pickweight(mob_spawn_list)
|
||||
|
||||
if(picked_mob == SPAWN_MEGAFAUNA) //
|
||||
if((A.area_flags & MEGAFAUNA_SPAWN_ALLOWED) && megafauna_spawn_list?.len) //this is danger. it's boss time.
|
||||
picked_mob = pickweight(megafauna_spawn_list)
|
||||
else //this is not danger, don't spawn a boss, spawn something else
|
||||
picked_mob = pickweight(mob_spawn_list - SPAWN_MEGAFAUNA) //What if we used 100% of the brain...and did something (slightly) less shit than a while loop?
|
||||
|
||||
for(var/thing in urange(12, new_open_turf)) //prevents mob clumps
|
||||
if(!ishostile(thing) && !istype(thing, /obj/structure/spawner))
|
||||
continue
|
||||
if((ispath(picked_mob, /mob/living/simple_animal/hostile/megafauna) || ismegafauna(thing)) && get_dist(new_open_turf, thing) <= 7)
|
||||
can_spawn = FALSE //if there's a megafauna within standard view don't spawn anything at all
|
||||
break
|
||||
if(ispath(picked_mob, /mob/living/simple_animal/hostile/asteroid) || istype(thing, /mob/living/simple_animal/hostile/asteroid))
|
||||
can_spawn = FALSE //if the random is a standard mob, avoid spawning if there's another one within 12 tiles
|
||||
break
|
||||
if((ispath(picked_mob, /obj/structure/spawner/lavaland) || istype(thing, /obj/structure/spawner/lavaland)) && get_dist(new_open_turf, thing) <= 2)
|
||||
can_spawn = FALSE //prevents tendrils spawning in each other's collapse range
|
||||
break
|
||||
|
||||
if(can_spawn)
|
||||
if(ispath(picked_mob, /mob/living/simple_animal/hostile/megafauna/bubblegum)) //there can be only one bubblegum, so don't waste spawns on it
|
||||
megafauna_spawn_list.Remove(picked_mob)
|
||||
|
||||
new picked_mob(new_open_turf)
|
||||
CHECK_TICK
|
||||
|
||||
var/message = "[name] finished in [(REALTIMEOFDAY - start_time)/10]s!"
|
||||
to_chat(world, "<span class='boldannounce'>[message]</span>")
|
||||
log_world(message)
|
||||
@@ -0,0 +1,28 @@
|
||||
/datum/map_generator/cave_generator/icemoon
|
||||
open_turf_types = list(/turf/open/floor/plating/asteroid/snow/icemoon = 19, /turf/open/floor/plating/ice/icemoon = 1)
|
||||
closed_turf_types = list(/turf/closed/mineral/random/snow = 1)
|
||||
|
||||
|
||||
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/wolf = 50, /obj/structure/spawner/ice_moon = 3, \
|
||||
/mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon/polarbear = 3, \
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10, \
|
||||
/mob/living/simple_animal/hostile/asteroid/lobstrosity = 15)
|
||||
flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/rock/icy = 2, /obj/structure/flora/rock/pile/icy = 2, /obj/structure/flora/grass/both = 6, /obj/structure/flora/ash = 2)
|
||||
feature_spawn_list = list(/obj/structure/geyser/random = 1)
|
||||
|
||||
/datum/map_generator/cave_generator/icemoon/surface
|
||||
flora_spawn_chance = 4
|
||||
mob_spawn_list = null
|
||||
initial_closed_chance = 53
|
||||
birth_limit = 5
|
||||
death_limit = 4
|
||||
smoothing_iterations = 10
|
||||
|
||||
/datum/map_generator/cave_generator/icemoon/deep
|
||||
closed_turf_types = list(/turf/closed/mineral/random/snow/underground = 1)
|
||||
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/ice_demon = 50, /obj/structure/spawner/ice_moon/demonic_portal = 3, \
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_whelp = 30, /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 3, \
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 3, \
|
||||
SPAWN_MEGAFAUNA = 2)
|
||||
megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/colossus = 1)
|
||||
flora_spawn_list = list(/obj/structure/flora/rock/icy = 6, /obj/structure/flora/rock/pile/icy = 6, /obj/structure/flora/ash = 1)
|
||||
@@ -0,0 +1,16 @@
|
||||
/datum/map_generator/cave_generator/lavaland
|
||||
open_turf_types = list(/turf/open/floor/plating/asteroid/basalt/lava_land_surface = 1)
|
||||
closed_turf_types = list(/turf/closed/mineral/random/volcanic = 1)
|
||||
|
||||
|
||||
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/random = 50, /obj/structure/spawner/lavaland/goliath = 3, \
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40, /obj/structure/spawner/lavaland = 2, \
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30, /obj/structure/spawner/lavaland/legion = 3, \
|
||||
SPAWN_MEGAFAUNA = 4, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10)
|
||||
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
|
||||
feature_spawn_list = list(/obj/structure/geyser/random = 1)
|
||||
|
||||
initial_closed_chance = 45
|
||||
smoothing_iterations = 50
|
||||
birth_limit = 4
|
||||
death_limit = 3
|
||||
@@ -0,0 +1,91 @@
|
||||
//the random offset applied to square coordinates, causes intermingling at biome borders
|
||||
#define BIOME_RANDOM_SQUARE_DRIFT 2
|
||||
|
||||
/datum/map_generator/jungle_generator
|
||||
///2D list of all biomes based on heat and humidity combos.
|
||||
var/list/possible_biomes = list(
|
||||
BIOME_LOW_HEAT = list(
|
||||
BIOME_LOW_HUMIDITY = /datum/biome/plains,
|
||||
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/mudlands,
|
||||
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/mudlands,
|
||||
BIOME_HIGH_HUMIDITY = /datum/biome/water
|
||||
),
|
||||
BIOME_LOWMEDIUM_HEAT = list(
|
||||
BIOME_LOW_HUMIDITY = /datum/biome/plains,
|
||||
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/jungle,
|
||||
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
|
||||
BIOME_HIGH_HUMIDITY = /datum/biome/mudlands
|
||||
),
|
||||
BIOME_HIGHMEDIUM_HEAT = list(
|
||||
BIOME_LOW_HUMIDITY = /datum/biome/plains,
|
||||
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
|
||||
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle/deep,
|
||||
BIOME_HIGH_HUMIDITY = /datum/biome/jungle
|
||||
),
|
||||
BIOME_HIGH_HEAT = list(
|
||||
BIOME_LOW_HUMIDITY = /datum/biome/wasteland,
|
||||
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
|
||||
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
|
||||
BIOME_HIGH_HUMIDITY = /datum/biome/jungle/deep
|
||||
)
|
||||
)
|
||||
///Used to select "zoom" level into the perlin noise, higher numbers result in slower transitions
|
||||
var/perlin_zoom = 65
|
||||
|
||||
///Seeds the rust-g perlin noise with a random number.
|
||||
/datum/map_generator/jungle_generator/generate_terrain(list/turfs)
|
||||
. = ..()
|
||||
var/height_seed = rand(0, 50000)
|
||||
var/humidity_seed = rand(0, 50000)
|
||||
var/heat_seed = rand(0, 50000)
|
||||
|
||||
for(var/t in turfs) //Go through all the turfs and generate them
|
||||
var/turf/gen_turf = t
|
||||
var/drift_x = (gen_turf.x + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom
|
||||
var/drift_y = (gen_turf.y + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom
|
||||
|
||||
var/height = text2num(rustg_noise_get_at_coordinates("[height_seed]", "[drift_x]", "[drift_y]"))
|
||||
|
||||
|
||||
var/datum/biome/selected_biome
|
||||
if(height <= 0.85) //If height is less than 0.85, we generate biomes based on the heat and humidity of the area.
|
||||
var/humidity = text2num(rustg_noise_get_at_coordinates("[humidity_seed]", "[drift_x]", "[drift_y]"))
|
||||
var/heat = text2num(rustg_noise_get_at_coordinates("[heat_seed]", "[drift_x]", "[drift_y]"))
|
||||
var/heat_level //Type of heat zone we're in LOW-MEDIUM-HIGH
|
||||
var/humidity_level //Type of humidity zone we're in LOW-MEDIUM-HIGH
|
||||
|
||||
switch(heat)
|
||||
if(0 to 0.25)
|
||||
heat_level = BIOME_LOW_HEAT
|
||||
if(0.25 to 0.5)
|
||||
heat_level = BIOME_LOWMEDIUM_HEAT
|
||||
if(0.5 to 0.75)
|
||||
heat_level = BIOME_HIGHMEDIUM_HEAT
|
||||
if(0.75 to 1)
|
||||
heat_level = BIOME_HIGH_HEAT
|
||||
switch(humidity)
|
||||
if(0 to 0.25)
|
||||
humidity_level = BIOME_LOW_HUMIDITY
|
||||
if(0.25 to 0.5)
|
||||
humidity_level = BIOME_LOWMEDIUM_HUMIDITY
|
||||
if(0.5 to 0.75)
|
||||
humidity_level = BIOME_HIGHMEDIUM_HUMIDITY
|
||||
if(0.75 to 1)
|
||||
humidity_level = BIOME_HIGH_HUMIDITY
|
||||
selected_biome = possible_biomes[heat_level][humidity_level]
|
||||
else //Over 0.85; It's a mountain
|
||||
selected_biome = /datum/biome/mountain
|
||||
selected_biome = SSmapping.biomes[selected_biome] //Get the instance of this biome from SSmapping
|
||||
selected_biome.generate_turf(gen_turf)
|
||||
CHECK_TICK
|
||||
|
||||
/turf/open/genturf
|
||||
name = "ungenerated turf"
|
||||
desc = "If you see this, and you're not a ghost, yell at coders"
|
||||
icon = 'icons/turf/debug.dmi'
|
||||
icon_state = "genturf"
|
||||
|
||||
/area/mine/planetgeneration
|
||||
name = "planet generation area"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
map_generator = /datum/map_generator/jungle_generator
|
||||
@@ -0,0 +1,6 @@
|
||||
///This type is responsible for any map generation behavior that is done in areas, override this to allow for area-specific map generation. This generation is ran by areas in initialize.
|
||||
/datum/map_generator
|
||||
|
||||
///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation.
|
||||
/datum/map_generator/proc/generate_terrain(list/turfs)
|
||||
return
|
||||
@@ -0,0 +1,53 @@
|
||||
///This datum handles the transitioning from a turf to a specific biome, and handles spawning decorative structures and mobs.
|
||||
/datum/biome
|
||||
///Type of turf this biome creates
|
||||
var/turf_type
|
||||
///Chance of having a structure from the flora types list spawn
|
||||
var/flora_density = 0
|
||||
///Chance of having a mob from the fauna types list spawn
|
||||
var/fauna_density = 0
|
||||
///list of type paths of objects that can be spawned when the turf spawns flora
|
||||
var/list/flora_types = list(/obj/structure/flora/grass/jungle)
|
||||
///list of type paths of mobs that can be spawned when the turf spawns fauna
|
||||
var/list/fauna_types = list()
|
||||
|
||||
///This proc handles the creation of a turf of a specific biome type
|
||||
/datum/biome/proc/generate_turf(turf/gen_turf)
|
||||
gen_turf.ChangeTurf(turf_type, null, CHANGETURF_DEFER_CHANGE)
|
||||
if(length(fauna_types) && prob(fauna_density))
|
||||
var/mob/fauna = pick(fauna_types)
|
||||
new fauna(gen_turf)
|
||||
|
||||
if(length(flora_types) && prob(flora_density))
|
||||
var/obj/structure/flora = pick(flora_types)
|
||||
new flora(gen_turf)
|
||||
|
||||
/datum/biome/mudlands
|
||||
// turf_type = /turf/open/floor/plating/dirt/jungle/dark
|
||||
turf_type = /turf/open/floor/plating/dirt/jungle
|
||||
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/rock/jungle, /obj/structure/flora/rock/pile/largejungle)
|
||||
flora_density = 3
|
||||
|
||||
/datum/biome/plains
|
||||
// turf_type = /turf/open/floor/plating/grass/jungle
|
||||
turf_type = /turf/open/floor/grass
|
||||
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle)
|
||||
flora_density = 15
|
||||
|
||||
/datum/biome/jungle
|
||||
// turf_type = /turf/open/floor/plating/grass/jungle
|
||||
turf_type = /turf/open/floor/grass
|
||||
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle)
|
||||
flora_density = 40
|
||||
|
||||
/datum/biome/jungle/deep
|
||||
flora_density = 65
|
||||
|
||||
/datum/biome/wasteland
|
||||
// turf_type = /turf/open/floor/plating/dirt/jungle/wasteland
|
||||
turf_type = /turf/open/floor/plating/dirt/jungle
|
||||
/datum/biome/water
|
||||
turf_type = /turf/open/water/jungle
|
||||
|
||||
/datum/biome/mountain
|
||||
turf_type = /turf/closed/mineral/random //jungle
|
||||
@@ -223,9 +223,10 @@
|
||||
///Subtype of CQC. Only used for the chef.
|
||||
/datum/martial_art/cqc/under_siege
|
||||
name = "Close Quarters Cooking"
|
||||
var/list/valid_areas = list(/area/service/kitchen)
|
||||
|
||||
///Prevents use if the cook is not in the kitchen.
|
||||
/datum/martial_art/cqc/under_siege/can_use(mob/living/carbon/human/H) //this is used to make chef CQC only work in kitchen
|
||||
if(!istype(get_area(H), /area/crew_quarters/kitchen))
|
||||
/datum/martial_art/cqc/under_siege/can_use(mob/living/owner) //this is used to make chef CQC only work in kitchen
|
||||
if(!is_type_in_list(get_area(owner), valid_areas))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -52,7 +52,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
name = "diamond"
|
||||
desc = "Highly pressurized carbon"
|
||||
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
strength_modifier = 1.1
|
||||
strength_modifier = 1.2
|
||||
alpha = 132
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/diamond
|
||||
@@ -85,6 +85,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
name = "plasma"
|
||||
desc = "Isn't plasma a state of matter? Oh whatever."
|
||||
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
strength_modifier = 0.7
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/plasma
|
||||
value_per_unit = 0.1
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
/datum/mutation/human/proc/get_spans()
|
||||
return list()
|
||||
|
||||
/mob/living/carbon/proc/update_mutations_overlay()
|
||||
/mob/living/proc/update_mutations_overlay()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/update_mutations_overlay()
|
||||
@@ -142,13 +142,12 @@
|
||||
if(overlays_standing[CM.layer_used])
|
||||
mut_overlay = overlays_standing[CM.layer_used]
|
||||
var/mutable_appearance/V = CM.get_visual_indicator()
|
||||
if(!mut_overlay.Find(V)) //either we lack the visual indicator or we have the wrong one
|
||||
remove_overlay(CM.layer_used)
|
||||
for(var/mutable_appearance/MA in CM.visual_indicators[CM.type])
|
||||
mut_overlay.Remove(MA)
|
||||
mut_overlay |= V
|
||||
overlays_standing[CM.layer_used] = mut_overlay
|
||||
apply_overlay(CM.layer_used)
|
||||
remove_overlay(CM.layer_used) //trying to find its existence defeats the point because if cut_overlays is called it doesn't bother reloading it.
|
||||
for(var/mutable_appearance/MA in CM.visual_indicators[CM.type])
|
||||
mut_overlay.Remove(MA)
|
||||
mut_overlay |= V
|
||||
overlays_standing[CM.layer_used] = mut_overlay
|
||||
apply_overlay(CM.layer_used)
|
||||
|
||||
/datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone
|
||||
if(modified || !power || !owner)
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
desc = "Allows a creature to voluntary discard a random appendage."
|
||||
quality = POSITIVE
|
||||
text_gain_indication = "<span class='notice'>Your joints feel loose.</span>"
|
||||
instability = 30
|
||||
instability = 20
|
||||
power = /obj/effect/proc_holder/spell/self/self_amputation
|
||||
|
||||
energy_coeff = 1
|
||||
@@ -316,7 +316,7 @@
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/BP = pick(parts)
|
||||
BP.dismember()
|
||||
BP.dismember(harmless=TRUE)
|
||||
|
||||
//spider webs
|
||||
/datum/mutation/human/webbing
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
desc = "The user's chemical balance is more robust."
|
||||
quality = POSITIVE
|
||||
text_gain_indication = "<span class='notice'>You feel stimmed.</span>"
|
||||
difficulty = 16
|
||||
difficulty = 18
|
||||
|
||||
/datum/mutation/human/paranoia
|
||||
name = "Paranoia"
|
||||
|
||||
@@ -30,3 +30,7 @@
|
||||
/datum/generecipe/hulk
|
||||
required = "/datum/mutation/human/strong; /datum/mutation/human/radioactive"
|
||||
result = HULK
|
||||
|
||||
/datum/generecipe/thermal
|
||||
required = "/datum/mutation/human/nearsight; /datum/mutation/human/stimmed"
|
||||
result = THERMAL
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/mutation/human/radioactive
|
||||
name = "Radioactivity"
|
||||
desc = "A volatile mutation that causes the host to sent out deadly beta radiation. This affects both the hosts and their surroundings."
|
||||
desc = "A volatile mutation that causes the host to send out deadly beta radiation. This affects both the hosts and their surroundings."
|
||||
quality = NEGATIVE
|
||||
text_gain_indication = "<span class='warning'>You can feel it in your bones!</span>"
|
||||
time_coeff = 5
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
difficulty = 18
|
||||
text_gain_indication = "<span class='notice'>You can see the heat rising off of your skin...</span>"
|
||||
time_coeff = 2
|
||||
instability = 25
|
||||
instability = 40
|
||||
locked = TRUE
|
||||
var/visionflag = TRAIT_THERMAL_VISION
|
||||
|
||||
/datum/mutation/human/thermal/on_acquiring(mob/living/carbon/human/owner)
|
||||
@@ -63,7 +64,7 @@
|
||||
name = "X Ray Vision"
|
||||
desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, wich might be fun for later //hmb
|
||||
text_gain_indication = "<span class='notice'>The walls suddenly disappear!</span>"
|
||||
instability = 35
|
||||
instability = 50
|
||||
locked = TRUE
|
||||
visionflag = TRAIT_XRAY_VISION
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Cold Resistance gives your entire body an orange halo, and makes you immune to the effects of vacuum and cold.
|
||||
/datum/mutation/human/space_adaptation
|
||||
name = "Space Adaptation"
|
||||
desc = "A strange mutation that renders the host immune to the vacuum if space. Will still need an oxygen supply."
|
||||
desc = "A strange mutation that renders the host immune to the vacuum of space. Will still need an oxygen supply."
|
||||
quality = POSITIVE
|
||||
difficulty = 16
|
||||
text_gain_indication = "<span class='notice'>Your body feels warm!</span>"
|
||||
@@ -11,7 +11,7 @@
|
||||
/datum/mutation/human/space_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
|
||||
..()
|
||||
if(!(type in visual_indicators))
|
||||
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "fire", -MUTATIONS_LAYER))
|
||||
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "space_adapt", -MUTATIONS_LAYER))
|
||||
|
||||
/datum/mutation/human/space_adaptation/get_visual_indicator()
|
||||
return visual_indicators[type][1]
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
var/obj/item/sample_object
|
||||
var/number
|
||||
|
||||
/datum/numbered_display/New(obj/item/sample, _number = 1)
|
||||
/datum/numbered_display/New(obj/item/sample, _number = 1, datum/component/storage/parent)
|
||||
if(!istype(sample))
|
||||
qdel(src)
|
||||
sample_object = sample
|
||||
sample_object = new /obj/screen/storage/item_holder(null, parent, sample)
|
||||
number = _number
|
||||
|
||||
+294
-57
@@ -1,71 +1,185 @@
|
||||
/**
|
||||
* # Outfit datums
|
||||
*
|
||||
* This is a clean system of applying outfits to mobs, if you need to equip someone in a uniform
|
||||
* this is the way to do it cleanly and properly.
|
||||
*
|
||||
* You can also specify an outfit datum on a job to have it auto equipped to the mob on join
|
||||
*
|
||||
* /mob/living/carbon/human/proc/equipOutfit(outfit) is the mob level proc to equip an outfit
|
||||
* and you pass it the relevant datum outfit
|
||||
*
|
||||
* outfits can also be saved as json blobs downloadable by a client and then can be uploaded
|
||||
* by that user to recreate the outfit, this is used by admins to allow for custom event outfits
|
||||
* that can be restored at a later date
|
||||
*/
|
||||
/datum/outfit
|
||||
///Name of the outfit (shows up in the equip admin verb)
|
||||
var/name = "Naked"
|
||||
|
||||
var/uniform = null
|
||||
var/suit = null
|
||||
var/toggle_helmet = TRUE
|
||||
var/back = null
|
||||
var/belt = null
|
||||
var/gloves = null
|
||||
var/shoes = null
|
||||
var/head = null
|
||||
var/mask = null
|
||||
var/neck = null
|
||||
var/ears = null
|
||||
var/glasses = null
|
||||
/// Type path of item to go in the idcard slot
|
||||
var/id = null
|
||||
var/l_pocket = null
|
||||
var/r_pocket = null
|
||||
|
||||
/// Type path of item to go in uniform slot
|
||||
var/uniform = null
|
||||
|
||||
/// Type path of item to go in suit slot
|
||||
var/suit = null
|
||||
|
||||
/**
|
||||
* Type path of item to go in suit storage slot
|
||||
*
|
||||
* (make sure it's valid for that suit)
|
||||
*/
|
||||
var/suit_store = null
|
||||
var/r_hand = null
|
||||
|
||||
/// Type path of item to go in back slot
|
||||
var/back = null
|
||||
|
||||
/**
|
||||
* list of items that should go in the backpack of the user
|
||||
*
|
||||
* Format of this list should be: list(path=count,otherpath=count)
|
||||
*/
|
||||
var/list/backpack_contents = null
|
||||
|
||||
/// Type path of item to go in belt slot
|
||||
var/belt = null
|
||||
|
||||
/// Type path of item to go in ears slot
|
||||
var/ears = null
|
||||
|
||||
/// Type path of item to go in the glasses slot
|
||||
var/glasses = null
|
||||
|
||||
/// Type path of item to go in gloves slot
|
||||
var/gloves = null
|
||||
|
||||
/// Type path of item to go in head slot
|
||||
var/head = null
|
||||
|
||||
/// Type path of item to go in mask slot
|
||||
var/mask = null
|
||||
|
||||
/// Type path of item to go in neck slot
|
||||
var/neck = null
|
||||
|
||||
/// Type path of item to go in shoes slot
|
||||
var/shoes = null
|
||||
|
||||
/// Type path of item for left pocket slot
|
||||
var/l_pocket = null
|
||||
|
||||
/// Type path of item for right pocket slot
|
||||
var/r_pocket = null
|
||||
|
||||
///Type path of item to go in the right hand
|
||||
var/l_hand = null
|
||||
var/internals_slot = null //ID of slot containing a gas tank
|
||||
var/list/backpack_contents = null // In the list(path=count,otherpath=count) format
|
||||
var/box // Internals box. Will be inserted at the start of backpack_contents
|
||||
var/list/implants = null
|
||||
|
||||
//Type path of item to go in left hand
|
||||
var/r_hand = null
|
||||
|
||||
/// Any clothing accessory item
|
||||
var/accessory = null
|
||||
|
||||
var/can_be_admin_equipped = TRUE // Set to FALSE if your outfit requires runtime parameters
|
||||
var/list/chameleon_extras //extra types for chameleon outfit changes, mostly guns
|
||||
/// Internals box. Will be inserted at the start of backpack_contents
|
||||
var/box
|
||||
|
||||
/**
|
||||
* extra types for chameleon outfit changes, mostly guns
|
||||
*
|
||||
* Format of this list is (typepath, typepath, typepath)
|
||||
*
|
||||
* These are all added and returns in the list for get_chamelon_diguise_info proc
|
||||
*/
|
||||
var/list/chameleon_extras
|
||||
|
||||
/**
|
||||
* Any implants the mob should start implanted with
|
||||
*
|
||||
* Format of this list is (typepath, typepath, typepath)
|
||||
*/
|
||||
var/list/implants = null
|
||||
|
||||
///ID of the slot containing a gas tank
|
||||
var/internals_slot = null
|
||||
|
||||
/// Should the toggle helmet proc be called on the helmet during equip
|
||||
var/toggle_helmet = TRUE
|
||||
|
||||
/// Any undershirt. While on humans it is a string, here we use paths to stay consistent with the rest of the equips.
|
||||
var/datum/sprite_accessory/undershirt = null
|
||||
|
||||
/**
|
||||
* Called at the start of the equip proc
|
||||
*
|
||||
* Override to change the value of the slots depending on client prefs, species and
|
||||
* other such sources of change
|
||||
*
|
||||
* Extra Arguments
|
||||
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||
*
|
||||
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||
*/
|
||||
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
//to be overridden for customization depending on client prefs,species etc
|
||||
return
|
||||
|
||||
/**
|
||||
* Called after the equip proc has finished
|
||||
*
|
||||
* All items are on the mob at this point, use this proc to toggle internals
|
||||
* fiddle with id bindings and accesses etc
|
||||
*
|
||||
* Extra Arguments
|
||||
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||
*
|
||||
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||
*/
|
||||
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
//to be overridden for toggling internals, id binding, access etc
|
||||
return
|
||||
|
||||
/**
|
||||
* Equips all defined types and paths to the mob passed in
|
||||
*
|
||||
* Extra Arguments
|
||||
* * visualsOnly true if this is only for display (in the character setup screen)
|
||||
*
|
||||
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
|
||||
*/
|
||||
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
pre_equip(H, visualsOnly, preference_source)
|
||||
|
||||
//Start with uniform,suit,backpack for additional slots
|
||||
if(uniform)
|
||||
H.equip_to_slot_or_del(new uniform(H),SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new uniform(H), SLOT_W_UNIFORM, TRUE)
|
||||
if(suit)
|
||||
H.equip_to_slot_or_del(new suit(H),SLOT_WEAR_SUIT)
|
||||
H.equip_to_slot_or_del(new suit(H), SLOT_WEAR_SUIT, TRUE)
|
||||
if(back)
|
||||
H.equip_to_slot_or_del(new back(H),SLOT_BACK)
|
||||
H.equip_to_slot_or_del(new back(H), SLOT_BACK, TRUE)
|
||||
if(belt)
|
||||
H.equip_to_slot_or_del(new belt(H),SLOT_BELT)
|
||||
H.equip_to_slot_or_del(new belt(H), SLOT_BELT, TRUE)
|
||||
if(gloves)
|
||||
H.equip_to_slot_or_del(new gloves(H),SLOT_GLOVES)
|
||||
H.equip_to_slot_or_del(new gloves(H), SLOT_GLOVES, TRUE)
|
||||
if(shoes)
|
||||
H.equip_to_slot_or_del(new shoes(H),SLOT_SHOES)
|
||||
H.equip_to_slot_or_del(new shoes(H), SLOT_SHOES, TRUE)
|
||||
if(head)
|
||||
H.equip_to_slot_or_del(new head(H),SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new head(H), SLOT_HEAD, TRUE)
|
||||
if(mask)
|
||||
H.equip_to_slot_or_del(new mask(H),SLOT_WEAR_MASK)
|
||||
H.equip_to_slot_or_del(new mask(H), SLOT_WEAR_MASK, TRUE)
|
||||
if(neck)
|
||||
H.equip_to_slot_or_del(new neck(H),SLOT_NECK)
|
||||
H.equip_to_slot_or_del(new neck(H), SLOT_NECK, TRUE)
|
||||
if(ears)
|
||||
H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
|
||||
H.equip_to_slot_or_del(new ears(H), SLOT_EARS, TRUE)
|
||||
if(glasses)
|
||||
H.equip_to_slot_or_del(new glasses(H),SLOT_GLASSES)
|
||||
H.equip_to_slot_or_del(new glasses(H), SLOT_GLASSES, TRUE)
|
||||
if(id)
|
||||
H.equip_to_slot_or_del(new id(H),SLOT_WEAR_ID)
|
||||
H.equip_to_slot_or_del(new id(H), SLOT_WEAR_ID, TRUE)
|
||||
if(suit_store)
|
||||
H.equip_to_slot_or_del(new suit_store(H),SLOT_S_STORE)
|
||||
H.equip_to_slot_or_del(new suit_store(H), SLOT_S_STORE, TRUE)
|
||||
if(undershirt)
|
||||
H.undershirt = initial(undershirt.name)
|
||||
|
||||
if(accessory)
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
@@ -81,9 +195,9 @@
|
||||
|
||||
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
|
||||
if(l_pocket)
|
||||
H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE)
|
||||
H.equip_to_slot_or_del(new l_pocket(H), SLOT_L_STORE, TRUE)
|
||||
if(r_pocket)
|
||||
H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE)
|
||||
H.equip_to_slot_or_del(new r_pocket(H), SLOT_R_STORE, TRUE)
|
||||
|
||||
if(box)
|
||||
if(!backpack_contents)
|
||||
@@ -97,7 +211,7 @@
|
||||
if(!isnum(number))//Default to 1
|
||||
number = 1
|
||||
for(var/i in 1 to number)
|
||||
H.equip_to_slot_or_del(new path(H),SLOT_IN_BACKPACK)
|
||||
H.equip_to_slot_or_del(new path(H), SLOT_IN_BACKPACK, TRUE)
|
||||
|
||||
if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
|
||||
@@ -112,55 +226,178 @@
|
||||
H.update_action_buttons_icon()
|
||||
if(implants)
|
||||
for(var/implant_type in implants)
|
||||
var/obj/item/implant/I = new implant_type
|
||||
var/obj/item/implant/I = new implant_type(H)
|
||||
I.implant(H, null, TRUE)
|
||||
|
||||
H.update_body()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Apply a fingerprint from the passed in human to all items in the outfit
|
||||
*
|
||||
* Used for forensics setup when the mob is first equipped at roundstart
|
||||
* essentially calls add_fingerprint to every defined item on the human
|
||||
*
|
||||
*/
|
||||
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
|
||||
if(!istype(H))
|
||||
return
|
||||
if(H.back)
|
||||
H.back.add_fingerprint(H,1) //The 1 sets a flag to ignore gloves
|
||||
H.back.add_fingerprint(H, ignoregloves = TRUE)
|
||||
for(var/obj/item/I in H.back.contents)
|
||||
I.add_fingerprint(H,1)
|
||||
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.wear_id)
|
||||
H.wear_id.add_fingerprint(H,1)
|
||||
H.wear_id.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.w_uniform)
|
||||
H.w_uniform.add_fingerprint(H,1)
|
||||
H.w_uniform.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.wear_suit)
|
||||
H.wear_suit.add_fingerprint(H,1)
|
||||
H.wear_suit.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.wear_mask)
|
||||
H.wear_mask.add_fingerprint(H,1)
|
||||
H.wear_mask.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.wear_neck)
|
||||
H.wear_neck.add_fingerprint(H,1)
|
||||
H.wear_neck.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.head)
|
||||
H.head.add_fingerprint(H,1)
|
||||
H.head.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.shoes)
|
||||
H.shoes.add_fingerprint(H,1)
|
||||
H.shoes.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.gloves)
|
||||
H.gloves.add_fingerprint(H,1)
|
||||
H.gloves.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.ears)
|
||||
H.ears.add_fingerprint(H,1)
|
||||
H.ears.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.glasses)
|
||||
H.glasses.add_fingerprint(H,1)
|
||||
H.glasses.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.belt)
|
||||
H.belt.add_fingerprint(H,1)
|
||||
H.belt.add_fingerprint(H, ignoregloves = TRUE)
|
||||
for(var/obj/item/I in H.belt.contents)
|
||||
I.add_fingerprint(H,1)
|
||||
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.s_store)
|
||||
H.s_store.add_fingerprint(H,1)
|
||||
H.s_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.l_store)
|
||||
H.l_store.add_fingerprint(H,1)
|
||||
H.l_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||
if(H.r_store)
|
||||
H.r_store.add_fingerprint(H,1)
|
||||
H.r_store.add_fingerprint(H, ignoregloves = TRUE)
|
||||
for(var/obj/item/I in H.held_items)
|
||||
I.add_fingerprint(H,1)
|
||||
return 1
|
||||
I.add_fingerprint(H, ignoregloves = TRUE)
|
||||
return TRUE
|
||||
|
||||
/// Return a list of all the types that are required to disguise as this outfit type
|
||||
/datum/outfit/proc/get_chameleon_disguise_info()
|
||||
var/list/types = list(uniform, suit, back, belt, gloves, shoes, head, mask, neck, ears, glasses, id, l_pocket, r_pocket, suit_store, r_hand, l_hand)
|
||||
types += chameleon_extras
|
||||
listclearnulls(types)
|
||||
return types
|
||||
|
||||
/// Return a json list of this outfit
|
||||
/datum/outfit/proc/get_json_data()
|
||||
. = list()
|
||||
.["outfit_type"] = type
|
||||
.["name"] = name
|
||||
.["uniform"] = uniform
|
||||
.["suit"] = suit
|
||||
.["toggle_helmet"] = toggle_helmet
|
||||
.["back"] = back
|
||||
.["belt"] = belt
|
||||
.["gloves"] = gloves
|
||||
.["shoes"] = shoes
|
||||
.["head"] = head
|
||||
.["mask"] = mask
|
||||
.["neck"] = neck
|
||||
.["ears"] = ears
|
||||
.["glasses"] = glasses
|
||||
.["id"] = id
|
||||
.["l_pocket"] = l_pocket
|
||||
.["r_pocket"] = r_pocket
|
||||
.["suit_store"] = suit_store
|
||||
.["r_hand"] = r_hand
|
||||
.["l_hand"] = l_hand
|
||||
.["internals_slot"] = internals_slot
|
||||
.["backpack_contents"] = backpack_contents
|
||||
.["box"] = box
|
||||
.["implants"] = implants
|
||||
.["accessory"] = accessory
|
||||
|
||||
/// Copy most vars from another outfit to this one
|
||||
/datum/outfit/proc/copy_from(datum/outfit/target)
|
||||
name = target.name
|
||||
uniform = target.uniform
|
||||
suit = target.suit
|
||||
toggle_helmet = target.toggle_helmet
|
||||
back = target.back
|
||||
belt = target.belt
|
||||
gloves = target.gloves
|
||||
shoes = target.shoes
|
||||
head = target.head
|
||||
mask = target.mask
|
||||
neck = target.neck
|
||||
ears = target.ears
|
||||
glasses = target.glasses
|
||||
id = target.id
|
||||
l_pocket = target.l_pocket
|
||||
r_pocket = target.r_pocket
|
||||
suit_store = target.suit_store
|
||||
r_hand = target.r_hand
|
||||
l_hand = target.l_hand
|
||||
internals_slot = target.internals_slot
|
||||
backpack_contents = target.backpack_contents
|
||||
box = target.box
|
||||
implants = target.implants
|
||||
accessory = target.accessory
|
||||
|
||||
/// Prompt the passed in mob client to download this outfit as a json blob
|
||||
/datum/outfit/proc/save_to_file(mob/admin)
|
||||
var/stored_data = get_json_data()
|
||||
var/json = json_encode(stored_data)
|
||||
//Kinda annoying but as far as i can tell you need to make actual file.
|
||||
var/f = file("data/TempOutfitUpload")
|
||||
fdel(f)
|
||||
WRITE_FILE(f,json)
|
||||
admin << ftp(f,"[name].json")
|
||||
|
||||
/// Create an outfit datum from a list of json data
|
||||
/datum/outfit/proc/load_from(list/outfit_data)
|
||||
//This could probably use more strict validation
|
||||
name = outfit_data["name"]
|
||||
uniform = text2path(outfit_data["uniform"])
|
||||
suit = text2path(outfit_data["suit"])
|
||||
toggle_helmet = outfit_data["toggle_helmet"]
|
||||
back = text2path(outfit_data["back"])
|
||||
belt = text2path(outfit_data["belt"])
|
||||
gloves = text2path(outfit_data["gloves"])
|
||||
shoes = text2path(outfit_data["shoes"])
|
||||
head = text2path(outfit_data["head"])
|
||||
mask = text2path(outfit_data["mask"])
|
||||
neck = text2path(outfit_data["neck"])
|
||||
ears = text2path(outfit_data["ears"])
|
||||
glasses = text2path(outfit_data["glasses"])
|
||||
id = text2path(outfit_data["id"])
|
||||
l_pocket = text2path(outfit_data["l_pocket"])
|
||||
r_pocket = text2path(outfit_data["r_pocket"])
|
||||
suit_store = text2path(outfit_data["suit_store"])
|
||||
r_hand = text2path(outfit_data["r_hand"])
|
||||
l_hand = text2path(outfit_data["l_hand"])
|
||||
internals_slot = outfit_data["internals_slot"]
|
||||
var/list/backpack = outfit_data["backpack_contents"]
|
||||
backpack_contents = list()
|
||||
for(var/item in backpack)
|
||||
var/itype = text2path(item)
|
||||
if(itype)
|
||||
backpack_contents[itype] = backpack[item]
|
||||
box = text2path(outfit_data["box"])
|
||||
var/list/impl = outfit_data["implants"]
|
||||
implants = list()
|
||||
for(var/I in impl)
|
||||
var/imptype = text2path(I)
|
||||
if(imptype)
|
||||
implants += imptype
|
||||
accessory = text2path(outfit_data["accessory"])
|
||||
return TRUE
|
||||
|
||||
/datum/outfit/vv_get_dropdown()
|
||||
. = ..()
|
||||
VV_DROPDOWN_OPTION("", "---")
|
||||
VV_DROPDOWN_OPTION(VV_HK_TO_OUTFIT_EDITOR, "Outfit Editor")
|
||||
|
||||
/datum/outfit/vv_do_topic(list/href_list)
|
||||
. = ..()
|
||||
if(href_list[VV_HK_TO_OUTFIT_EDITOR])
|
||||
usr.client.open_outfit_editor(src)
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
/datum/status_effect/off_balance/on_remove()
|
||||
var/active_item = owner.get_active_held_item()
|
||||
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
|
||||
if(active_item)
|
||||
owner.visible_message("<span class='warning'>[owner.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
return ..()
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
|
||||
/obj/screen/alert/status_effect/mesmerized
|
||||
name = "Mesmerized"
|
||||
desc = "You cant tear your sight from who is in front of you... their gaze is simply too enthralling.."
|
||||
desc = "You can't tear your sight from who is in front of you... their gaze is simply too enthralling.."
|
||||
icon = 'icons/mob/actions/bloodsucker.dmi'
|
||||
icon_state = "power_mez"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
area_type = /area
|
||||
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
|
||||
/area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison, /area/ruin, /area/space/nearstation, /area/icemoon)
|
||||
/area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle, /area/security/prison/safe, /area/security/prison/toilet)
|
||||
target_trait = ZTRAIT_STATION
|
||||
|
||||
immunity_type = "rad"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,3 +30,7 @@
|
||||
var/obj/machinery/camera/cam = X
|
||||
cam.lostTargetRef(WEAKREF(O))
|
||||
return
|
||||
|
||||
/area/ai_monitored/turret_protected/ai/Initialize()
|
||||
. = ..()
|
||||
src.area_flags |= ABDUCTOR_PROOF
|
||||
|
||||
+50
-52
@@ -13,6 +13,8 @@
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
invisibility = INVISIBILITY_LIGHTING
|
||||
|
||||
var/area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA
|
||||
|
||||
var/fire = null
|
||||
///Whether there is an atmos alarm in this area
|
||||
var/atmosalm = FALSE
|
||||
@@ -60,7 +62,7 @@
|
||||
|
||||
|
||||
///This datum, if set, allows terrain generation behavior to be ran on Initialize()
|
||||
// var/datum/map_generator/map_generator
|
||||
var/datum/map_generator/map_generator
|
||||
|
||||
///Used to decide what kind of reverb the area makes sound have
|
||||
var/sound_environment = SOUND_ENVIRONMENT_NONE
|
||||
@@ -70,12 +72,8 @@
|
||||
/// Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
|
||||
var/map_name
|
||||
|
||||
/// If it's valid territory for gangs/cults to summon
|
||||
var/valid_territory = TRUE
|
||||
/// malf ais can hack this
|
||||
var/valid_malf_hack = TRUE
|
||||
/// if blobs can spawn there and if it counts towards their score.
|
||||
var/blob_allowed = TRUE
|
||||
/// whether servants can warp into this area from Reebe
|
||||
var/clockwork_warp_allowed = TRUE
|
||||
/// Message to display when the clockwork warp fails
|
||||
@@ -107,14 +105,10 @@
|
||||
var/static_light = 0
|
||||
var/static_environ
|
||||
|
||||
/// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
|
||||
var/noteleport = FALSE
|
||||
/// Hides area from player Teleport function.
|
||||
var/hidden = FALSE
|
||||
/// Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
|
||||
var/safe = FALSE
|
||||
/// If false, loading multiple maps with this area type will create multiple instances.
|
||||
var/unique = TRUE
|
||||
|
||||
var/no_air = null
|
||||
|
||||
@@ -157,7 +151,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
/proc/process_teleport_locs()
|
||||
for(var/V in GLOB.sortedAreas)
|
||||
var/area/AR = V
|
||||
if(istype(AR, /area/shuttle) || AR.noteleport)
|
||||
if(istype(AR, /area/shuttle) || (AR.area_flags & NOTELEPORT))
|
||||
continue
|
||||
if(GLOB.teleportlocs[AR.name])
|
||||
continue
|
||||
@@ -177,7 +171,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
/area/New()
|
||||
// This interacts with the map loader, so it needs to be set immediately
|
||||
// rather than waiting for atoms to initialize.
|
||||
if (unique)
|
||||
if (area_flags & UNIQUE_AREA)
|
||||
GLOB.areas_by_type[type] = src
|
||||
|
||||
if(!minimap_color) // goes in New() because otherwise it doesn't fucking work
|
||||
@@ -228,7 +222,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
reg_in_areas_in_z()
|
||||
|
||||
//so far I'm only implementing it on mapped unique areas, it's easier this way.
|
||||
if(unique && sub_areas)
|
||||
if((area_flags & UNIQUE_AREA) && sub_areas)
|
||||
if(type in sub_areas)
|
||||
WARNING("\"[src]\" typepath found inside its own sub-areas list, please make sure it doesn't share its parent type initial sub-areas value.")
|
||||
sub_areas = null
|
||||
@@ -261,21 +255,20 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
power_change() // all machines set to current power level, also updates icon
|
||||
update_beauty()
|
||||
|
||||
/// Soon ™
|
||||
/area/proc/RunGeneration()
|
||||
// if(map_generator)
|
||||
// map_generator = new map_generator()
|
||||
// var/list/turfs = list()
|
||||
// for(var/turf/T in contents)
|
||||
// turfs += T
|
||||
// map_generator.generate_terrain(turfs)
|
||||
if(map_generator)
|
||||
map_generator = new map_generator()
|
||||
var/list/turfs = list()
|
||||
for(var/turf/T in contents)
|
||||
turfs += T
|
||||
map_generator.generate_terrain(turfs)
|
||||
|
||||
/area/proc/test_gen()
|
||||
// if(map_generator)
|
||||
// var/list/turfs = list()
|
||||
// for(var/turf/T in contents)
|
||||
// turfs += T
|
||||
// map_generator.generate_terrain(turfs)
|
||||
if(map_generator)
|
||||
var/list/turfs = list()
|
||||
for(var/turf/T in contents)
|
||||
turfs += T
|
||||
map_generator.generate_terrain(turfs)
|
||||
|
||||
/**
|
||||
* Register this area as belonging to a z level
|
||||
@@ -327,6 +320,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
|
||||
*/
|
||||
/area/proc/poweralert(state, obj/source)
|
||||
if (area_flags & NO_ALERTS)
|
||||
return
|
||||
if (state != poweralm)
|
||||
poweralm = state
|
||||
if(istype(source)) //Only report power alarms on the z-level where the source is located.
|
||||
@@ -358,6 +353,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
p.triggerAlarm("Power", src, cameras, source)
|
||||
|
||||
/area/proc/atmosalert(danger_level, obj/source)
|
||||
if (area_flags & NO_ALERTS)
|
||||
return
|
||||
if(danger_level != atmosalm)
|
||||
if (danger_level==2)
|
||||
|
||||
@@ -420,19 +417,19 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
if (!fire)
|
||||
set_fire_alarm_effects(TRUE)
|
||||
ModifyFiredoors(FALSE)
|
||||
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.triggerAlarm("Fire", src, cameras, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.triggerAlarm("Fire", src, cameras, source)
|
||||
if (!(area_flags & NO_ALERTS)) //Check here instead at the start of the proc so that fire alarms can still work locally even in areas that don't send alerts
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.triggerAlarm("Fire", src, cameras, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.triggerAlarm("Fire", src, cameras, source)
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -441,18 +438,19 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
set_fire_alarm_effects(FALSE)
|
||||
ModifyFiredoors(TRUE)
|
||||
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.cancelAlarm("Fire", src, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.cancelAlarm("Fire", src, source)
|
||||
if (!(area_flags & NO_ALERTS)) //Check here instead at the start of the proc so that fire alarms can still work locally even in areas that don't send alerts
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.cancelAlarm("Fire", src, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.cancelAlarm("Fire", src, source)
|
||||
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -467,7 +465,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
DOOR.lock()
|
||||
|
||||
/area/proc/burglaralert(obj/trigger)
|
||||
if(always_unpowered) //no burglar alarms in space/asteroid
|
||||
if (area_flags & NO_ALERTS)
|
||||
return
|
||||
|
||||
//Trigger alarm effect
|
||||
@@ -675,9 +673,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
power_light = FALSE
|
||||
power_environ = FALSE
|
||||
always_unpowered = FALSE
|
||||
valid_territory = FALSE
|
||||
valid_malf_hack = FALSE
|
||||
blob_allowed = FALSE
|
||||
area_flags &= ~VALID_TERRITORY
|
||||
area_flags &= ~BLOBS_ALLOWED
|
||||
addSorted()
|
||||
|
||||
/area/proc/update_areasize()
|
||||
|
||||
@@ -8,6 +8,7 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
|
||||
name = "Strange Location"
|
||||
icon_state = "away"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
// ambience_index = AMBIENCE_AWAY
|
||||
ambientsounds = AWAY_MISSION
|
||||
sound_environment = SOUND_ENVIRONMENT_ROOM
|
||||
|
||||
@@ -27,3 +28,8 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
|
||||
/area/awaymission/vr
|
||||
name = "Virtual Reality"
|
||||
icon_state = "awaycontent1"
|
||||
requires_power = FALSE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
var/pacifist = TRUE // if when you enter this zone, you become a pacifist or not
|
||||
var/death = FALSE // if when you enter this zone, you die
|
||||
// network_root_id = "VR"
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
|
||||
// CENTCOM
|
||||
|
||||
// Side note, be sure to change the network_root_id of any areas that are not a part of centcom
|
||||
// and just using the z space as safe harbor. It shouldn't matter much as centcom z is isolated
|
||||
// from everything anyway
|
||||
|
||||
/area/centcom
|
||||
name = "CentCom"
|
||||
icon_state = "centcom"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
noteleport = TRUE
|
||||
blob_allowed = FALSE //Should go without saying, no blobs should take over centcom as a win condition.
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
|
||||
flags_1 = NONE
|
||||
|
||||
/area/centcom/control
|
||||
@@ -33,6 +36,7 @@
|
||||
name = "VIP Zone"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
// dear mappers who make winterball: THROW YOUR AREAS IN A DIFFERENT MAP, THIS IS DEFAULT GAME STUFF NOT EVENT STUFF
|
||||
/area/centcom/winterball
|
||||
name = "winterball Zone"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
@@ -56,7 +60,7 @@
|
||||
var/loading_id = ""
|
||||
|
||||
/area/centcom/supplypod/loading/Initialize()
|
||||
. = ..()
|
||||
. = ..()
|
||||
if(!loading_id)
|
||||
CRASH("[type] created without a loading_id")
|
||||
if(GLOB.supplypod_loading_bays[loading_id])
|
||||
@@ -128,17 +132,19 @@
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
noteleport = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
|
||||
flags_1 = NONE
|
||||
// network_root_id = "MAGIC_NET"
|
||||
|
||||
//Abductors
|
||||
/area/abductor_ship
|
||||
name = "Abductor Ship"
|
||||
icon_state = "yellow"
|
||||
requires_power = FALSE
|
||||
noteleport = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
// network_root_id = "ALIENS"
|
||||
|
||||
//Syndicates
|
||||
/area/syndicate_mothership
|
||||
@@ -146,26 +152,28 @@
|
||||
icon_state = "syndie-ship"
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
noteleport = TRUE
|
||||
blob_allowed = FALSE //Not... entirely sure this will ever come up... but if the bus makes blobs AND ops, it shouldn't aim for the ops to win.
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
|
||||
flags_1 = NONE
|
||||
// ambience_index = AMBIENCE_DANGER
|
||||
ambientsounds = HIGHSEC
|
||||
// network_root_id = SYNDICATE_NETWORK_ROOT
|
||||
|
||||
/area/syndicate_mothership/control
|
||||
name = "Syndicate Control Room"
|
||||
icon_state = "syndie-control"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
// network_root_id = SYNDICATE_NETWORK_ROOT
|
||||
|
||||
/area/syndicate_mothership/elite_squad
|
||||
name = "Syndicate Elite Squad"
|
||||
icon_state = "syndie-elite"
|
||||
// network_root_id = SYNDICATE_NETWORK_ROOT
|
||||
|
||||
/area/fabric_of_reality
|
||||
name = "Tear in the Fabric of Reality"
|
||||
requires_power = FALSE
|
||||
has_gravity = TRUE
|
||||
noteleport = TRUE
|
||||
blob_allowed = FALSE
|
||||
area_flags = UNIQUE_AREA | NOTELEPORT
|
||||
|
||||
//CAPTURE THE FLAG
|
||||
|
||||
@@ -174,6 +182,7 @@
|
||||
icon_state = "yellow"
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
|
||||
/area/ctf/control_room
|
||||
name = "Control Room A"
|
||||
@@ -209,11 +218,10 @@
|
||||
icon_state = "yellow"
|
||||
requires_power = FALSE
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
noteleport = TRUE
|
||||
hidden = TRUE
|
||||
area_flags = HIDDEN_AREA | NOTELEPORT | UNIQUE_AREA
|
||||
ambientsounds = REEBE
|
||||
|
||||
/area/reebe/city_of_cogs
|
||||
name = "City of Cogs"
|
||||
icon_state = "purple"
|
||||
hidden = FALSE
|
||||
area_flags = NOTELEPORT | UNIQUE_AREA
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
name = "Holodeck"
|
||||
icon_state = "Holodeck"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
flags_1 = 0
|
||||
hidden = TRUE
|
||||
flags_1 = NONE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA
|
||||
sound_environment = SOUND_ENVIRONMENT_PADDED_CELL
|
||||
|
||||
var/obj/machinery/computer/holodeck/linked
|
||||
var/restricted = 0 // if true, program goes on emag list
|
||||
var/restricted = FALSE // if true, program goes on emag list
|
||||
// network_root_id = "HOLODECK"
|
||||
|
||||
/*
|
||||
Power tracking: Use the holodeck computer's power grid
|
||||
|
||||
@@ -3,44 +3,49 @@
|
||||
/area/mine
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flora_allowed = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED
|
||||
|
||||
/area/mine/explored
|
||||
name = "Mine"
|
||||
icon_state = "explored"
|
||||
music = null
|
||||
always_unpowered = TRUE
|
||||
requires_power = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
outdoors = TRUE
|
||||
flags_1 = NONE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
flora_allowed = FALSE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NO_ALERTS
|
||||
sound_environment = SOUND_AREA_STANDARD_STATION
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/mine/unexplored
|
||||
name = "Mine"
|
||||
icon_state = "unexplored"
|
||||
music = null
|
||||
always_unpowered = TRUE
|
||||
requires_power = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
outdoors = TRUE
|
||||
flags_1 = NONE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
tunnel_allowed = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NO_ALERTS | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED
|
||||
map_generator = /datum/map_generator/cave_generator
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/mine/lobby
|
||||
name = "Mining Station"
|
||||
icon_state = "mining_lobby"
|
||||
|
||||
/area/mine/storage
|
||||
name = "Mining Station Storage"
|
||||
icon_state = "mining_storage"
|
||||
|
||||
/area/mine/production
|
||||
name = "Mining Station Starboard Wing"
|
||||
@@ -62,19 +67,27 @@
|
||||
|
||||
/area/mine/cafeteria
|
||||
name = "Mining Station Cafeteria"
|
||||
icon_state = "mining_labor_cafe"
|
||||
|
||||
/area/mine/hydroponics
|
||||
name = "Mining Station Hydroponics"
|
||||
icon_state = "mining_labor_hydro"
|
||||
|
||||
/area/mine/sleeper
|
||||
name = "Mining Station Emergency Sleeper"
|
||||
|
||||
/area/mine/mechbay
|
||||
name = "Mining Station Mech Bay"
|
||||
icon_state = "mechbay"
|
||||
|
||||
/area/mine/laborcamp
|
||||
name = "Labor Camp"
|
||||
icon_state = "mining_labor"
|
||||
|
||||
/area/mine/laborcamp/security
|
||||
name = "Labor Camp Security"
|
||||
icon_state = "security"
|
||||
// ambience_index = AMBIENCE_DANGER
|
||||
ambientsounds = HIGHSEC
|
||||
|
||||
|
||||
@@ -86,33 +99,36 @@
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
flora_allowed = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED
|
||||
sound_environment = SOUND_AREA_LAVALAND
|
||||
|
||||
/area/lavaland/surface
|
||||
name = "Lavaland"
|
||||
icon_state = "explored"
|
||||
music = null
|
||||
always_unpowered = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
requires_power = TRUE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED | NO_ALERTS
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/lavaland/underground
|
||||
name = "Lavaland Caves"
|
||||
icon_state = "unexplored"
|
||||
music = null
|
||||
always_unpowered = TRUE
|
||||
requires_power = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED | NO_ALERTS
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/lavaland/surface/outdoors
|
||||
name = "Lavaland Wastes"
|
||||
@@ -120,16 +136,16 @@
|
||||
|
||||
/area/lavaland/surface/outdoors/unexplored //monsters and ruins spawn here
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | NO_ALERTS
|
||||
map_generator = /datum/map_generator/cave_generator/lavaland
|
||||
|
||||
/area/lavaland/surface/outdoors/unexplored/danger //megafauna will also spawn here
|
||||
icon_state = "danger"
|
||||
megafauna_spawn_allowed = TRUE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED | NO_ALERTS
|
||||
|
||||
/area/lavaland/surface/outdoors/explored
|
||||
name = "Lavaland Labor Camp"
|
||||
flora_allowed = FALSE
|
||||
area_flags = VALID_TERRITORY | UNIQUE_AREA | NO_ALERTS
|
||||
|
||||
|
||||
|
||||
@@ -139,61 +155,68 @@
|
||||
icon_state = "mining"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
flags_1 = NONE
|
||||
flora_allowed = TRUE
|
||||
blob_allowed = FALSE
|
||||
area_flags = UNIQUE_AREA | FLORA_ALLOWED
|
||||
sound_environment = SOUND_AREA_ICEMOON
|
||||
|
||||
/area/icemoon/surface
|
||||
name = "Icemoon"
|
||||
icon_state = "explored"
|
||||
always_unpowered = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
requires_power = TRUE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
area_flags = UNIQUE_AREA | FLORA_ALLOWED | NO_ALERTS
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/icemoon/surface/outdoors // weather happens here
|
||||
name = "Icemoon Wastes"
|
||||
outdoors = TRUE
|
||||
|
||||
/area/icemoon/surface/outdoors/labor_camp
|
||||
name = "Icemoon Labor Camp"
|
||||
area_flags = UNIQUE_AREA | NO_ALERTS
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored //monsters and ruins spawn here
|
||||
icon_state = "unexplored"
|
||||
area_flags = UNIQUE_AREA | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | CAVES_ALLOWED | NO_ALERTS
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers // rivers spawn here
|
||||
icon_state = "danger"
|
||||
map_generator = /datum/map_generator/cave_generator/icemoon/surface
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters
|
||||
area_flags = UNIQUE_AREA | FLORA_ALLOWED | CAVES_ALLOWED | NO_ALERTS
|
||||
|
||||
/area/icemoon/underground
|
||||
name = "Icemoon Caves"
|
||||
outdoors = TRUE
|
||||
always_unpowered = TRUE
|
||||
requires_power = TRUE
|
||||
poweralm = FALSE
|
||||
power_environ = FALSE
|
||||
power_equip = FALSE
|
||||
power_light = FALSE
|
||||
// ambience_index = AMBIENCE_MINING
|
||||
ambientsounds = MINING
|
||||
area_flags = UNIQUE_AREA | FLORA_ALLOWED | NO_ALERTS
|
||||
// min_ambience_cooldown = 70 SECONDS
|
||||
// max_ambience_cooldown = 220 SECONDS
|
||||
|
||||
/area/icemoon/underground/unexplored // mobs and megafauna and ruins spawn here
|
||||
name = "Icemoon Caves"
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
megafauna_spawn_allowed = TRUE
|
||||
area_flags = CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED | NO_ALERTS
|
||||
|
||||
/area/icemoon/underground/unexplored/rivers // rivers spawn here
|
||||
icon_state = "danger"
|
||||
map_generator = /datum/map_generator/cave_generator/icemoon
|
||||
|
||||
/area/icemoon/underground/explored
|
||||
/area/icemoon/underground/unexplored/rivers/deep
|
||||
map_generator = /datum/map_generator/cave_generator/icemoon/deep
|
||||
|
||||
/area/icemoon/underground/explored // ruins can't spawn here
|
||||
name = "Icemoon Underground"
|
||||
flora_allowed = FALSE
|
||||
|
||||
/area/icemoon/surface/outdoors
|
||||
name = "Icemoon Wastes"
|
||||
outdoors = TRUE
|
||||
|
||||
/area/icemoon/surface/outdoors/labor_camp
|
||||
name = "Icemoon Labor Camp"
|
||||
flora_allowed = FALSE
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored //monsters and ruins spawn here
|
||||
icon_state = "unexplored"
|
||||
tunnel_allowed = TRUE
|
||||
mob_spawn_allowed = TRUE
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers // rivers spawn here
|
||||
icon_state = "danger"
|
||||
|
||||
/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters
|
||||
mob_spawn_allowed = FALSE
|
||||
area_flags = UNIQUE_AREA | NO_ALERTS
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
/area/ruin/space
|
||||
has_gravity = FALSE
|
||||
blob_allowed = FALSE //Nope, no winning in space as a blob. Gotta eat the station.
|
||||
outdoors = TRUE
|
||||
ambientsounds = SPACE
|
||||
area_flags = UNIQUE_AREA
|
||||
|
||||
/area/ruin/space/has_grav
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
@@ -12,7 +10,6 @@
|
||||
/area/ruin/space/has_grav/powered
|
||||
requires_power = FALSE
|
||||
|
||||
|
||||
/area/ruin/fakespace
|
||||
icon_state = "space"
|
||||
requires_power = TRUE
|
||||
@@ -22,10 +19,8 @@
|
||||
power_light = FALSE
|
||||
power_equip = FALSE
|
||||
power_environ = FALSE
|
||||
valid_territory = FALSE
|
||||
outdoors = TRUE
|
||||
ambientsounds = SPACE
|
||||
blob_allowed = FALSE
|
||||
|
||||
/////////////
|
||||
|
||||
@@ -133,22 +128,20 @@
|
||||
|
||||
/area/ruin/space/diner
|
||||
name = "Space Diner"
|
||||
area_flags = UNIQUE_AREA
|
||||
|
||||
/area/ruin/space/diner/interior
|
||||
name = "Space Diner"
|
||||
icon_state = "maintbar"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
blob_allowed = FALSE //Nope, no winning in the diner as a blob. Gotta eat the main station.
|
||||
|
||||
/area/ruin/space/diner/solars
|
||||
requires_power = FALSE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
|
||||
valid_territory = FALSE
|
||||
blob_allowed = FALSE
|
||||
flags_1 = NONE
|
||||
ambientsounds = ENGINEERING
|
||||
name = "Space Diner Solar Array"
|
||||
icon_state = "yellow"
|
||||
requires_power = FALSE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
|
||||
flags_1 = NONE
|
||||
ambientsounds = ENGINEERING
|
||||
|
||||
//Ruin of "Skelter" ship
|
||||
|
||||
@@ -257,7 +250,7 @@
|
||||
//Ruin of old teleporter
|
||||
|
||||
/area/ruin/space/oldteleporter
|
||||
name = "Old teleporter"
|
||||
name = "Old Teleporter"
|
||||
icon_state = "teleporter"
|
||||
|
||||
|
||||
@@ -301,7 +294,7 @@
|
||||
icon_state = "storage_wing"
|
||||
|
||||
/area/ruin/space/has_grav/deepstorage/dorm
|
||||
name = "Deep Storage Dormory"
|
||||
name = "Deep Storage Dormitory"
|
||||
icon_state = "crew_quarters"
|
||||
|
||||
/area/ruin/space/has_grav/deepstorage/kitchen
|
||||
@@ -339,7 +332,9 @@
|
||||
/area/ruin/space/has_grav/ancientstation/atmo
|
||||
name = "Beta Station Atmospherics"
|
||||
icon_state = "red"
|
||||
has_gravity = FALSE
|
||||
// ambience_index = AMBIENCE_ENGI
|
||||
ambientsounds = ENGINEERING
|
||||
has_gravity = TRUE
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/betanorth
|
||||
name = "Beta Station North Corridor"
|
||||
@@ -349,9 +344,15 @@
|
||||
name = "Station Solar Array"
|
||||
icon_state = "panelsAP"
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/betacorridor
|
||||
name = "Beta Station Main Corridor"
|
||||
icon_state = "bluenew"
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/engi
|
||||
name = "Charlie Station Engineering"
|
||||
icon_state = "engine"
|
||||
// ambience_index = AMBIENCE_ENGI
|
||||
ambientsounds = ENGINEERING
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/comm
|
||||
name = "Charlie Station Command"
|
||||
@@ -385,6 +386,27 @@
|
||||
name = "Hivebot Mothership"
|
||||
icon_state = "teleporter"
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/deltaai
|
||||
name = "Delta Station AI Core"
|
||||
icon_state = "ai"
|
||||
ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg')
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/mining
|
||||
name = "Beta Station Mining Equipment"
|
||||
icon_state = "mining"
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/medbay
|
||||
name = "Beta Station Medbay"
|
||||
icon_state = "medbay"
|
||||
|
||||
/area/ruin/space/has_grav/ancientstation/betastorage
|
||||
name = "Beta Station Storage"
|
||||
icon_state = "storage"
|
||||
|
||||
/area/solars/ancientstation
|
||||
name = "Charlie Station Solar Array"
|
||||
icon_state = "panelsP"
|
||||
|
||||
//DERELICT
|
||||
|
||||
/area/ruin/space/derelict
|
||||
@@ -469,11 +491,11 @@
|
||||
name = "Abandoned Ship"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/solar/derelict_starboard
|
||||
/area/solars/derelict_starboard
|
||||
name = "Derelict Starboard Solar Array"
|
||||
icon_state = "panelsS"
|
||||
|
||||
/area/solar/derelict_aft
|
||||
/area/solars/derelict_aft
|
||||
name = "Derelict Aft Solar Array"
|
||||
icon_state = "yellow"
|
||||
|
||||
@@ -496,28 +518,24 @@
|
||||
power_light = FALSE
|
||||
power_environ = FALSE
|
||||
|
||||
|
||||
//DJSTATION
|
||||
|
||||
/area/ruin/space/djstation
|
||||
name = "Ruskie DJ Station"
|
||||
icon_state = "DJ"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
blob_allowed = FALSE //Nope, no winning on the DJ station as a blob. Gotta eat the main station.
|
||||
|
||||
/area/ruin/space/djstation/solars
|
||||
name = "DJ Station Solars"
|
||||
icon_state = "DJ"
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
|
||||
|
||||
//ABANDONED TELEPORTER
|
||||
|
||||
/area/ruin/space/abandoned_tele
|
||||
name = "Abandoned Teleporter"
|
||||
icon_state = "teleporter"
|
||||
music = "signal"
|
||||
ambientsounds = list('sound/ambience/ambimalf.ogg')
|
||||
ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/signal.ogg')
|
||||
|
||||
//OLD AI SAT
|
||||
|
||||
@@ -561,3 +579,13 @@
|
||||
/area/ruin/space/has_grav/powered/advancedlab
|
||||
name = "Abductor Replication Lab"
|
||||
icon_state = "yellow"
|
||||
|
||||
//HELL'S FACTORY OPERATING FACILITY
|
||||
// /area/ruin/space/has_grav/hellfactory
|
||||
// name = "Hell Factory"
|
||||
// icon_state = "yellow"
|
||||
|
||||
// /area/ruin/space/has_grav/hellfactoryoffice
|
||||
// name = "Hell Factory Office"
|
||||
// icon_state = "red"
|
||||
// area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | NOTELEPORT
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
has_gravity = STANDARD_GRAVITY
|
||||
always_unpowered = FALSE
|
||||
valid_territory = FALSE
|
||||
icon_state = "shuttle"
|
||||
// Loading the same shuttle map at a different time will produce distinct area instances.
|
||||
unique = FALSE
|
||||
area_flags = NO_ALERTS
|
||||
icon_state = "shuttle"
|
||||
flags_1 = CAN_BE_DIRTY_1
|
||||
// area_limited_icon_smoothing = /area/shuttle
|
||||
sound_environment = SOUND_ENVIRONMENT_ROOM
|
||||
|
||||
/area/shuttle/Initialize()
|
||||
@@ -32,7 +33,8 @@
|
||||
|
||||
/area/shuttle/syndicate
|
||||
name = "Syndicate Infiltrator"
|
||||
blob_allowed = FALSE
|
||||
// ambience_index = AMBIENCE_DANGER
|
||||
// area_limited_icon_smoothing = /area/shuttle/syndicate
|
||||
ambientsounds = HIGHSEC
|
||||
canSmoothWithAreas = /area/shuttle/syndicate
|
||||
|
||||
@@ -57,7 +59,6 @@
|
||||
|
||||
/area/shuttle/pirate
|
||||
name = "Pirate Shuttle"
|
||||
blob_allowed = FALSE
|
||||
requires_power = TRUE
|
||||
canSmoothWithAreas = /area/shuttle/pirate
|
||||
|
||||
@@ -65,12 +66,22 @@
|
||||
name = "Pirate Shuttle Vault"
|
||||
requires_power = FALSE
|
||||
|
||||
/area/shuttle/pirate/flying_dutchman
|
||||
name = "Flying Dutchman"
|
||||
requires_power = FALSE
|
||||
|
||||
////////////////////////////Bounty Hunter Shuttles////////////////////////////
|
||||
|
||||
/area/shuttle/hunter
|
||||
name = "Hunter Shuttle"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
////////////////////////////White Ship////////////////////////////
|
||||
|
||||
/area/shuttle/abandoned
|
||||
name = "Abandoned Ship"
|
||||
blob_allowed = FALSE
|
||||
requires_power = TRUE
|
||||
// area_limited_icon_smoothing = /area/shuttle/abandoned
|
||||
canSmoothWithAreas = /area/shuttle/abandoned
|
||||
|
||||
/area/shuttle/abandoned/bridge
|
||||
@@ -94,13 +105,6 @@
|
||||
/area/shuttle/abandoned/pod
|
||||
name = "Abandoned Ship Pod"
|
||||
|
||||
////////////////////////////Bounty Hunter Shuttles////////////////////////////
|
||||
/area/shuttle/hunter
|
||||
name = "Hunter Shuttle"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
blob_allowed = FALSE
|
||||
canSmoothWithAreas = /area/shuttle/hunter
|
||||
|
||||
////////////////////////////Single-area shuttles////////////////////////////
|
||||
|
||||
/area/shuttle/transit
|
||||
@@ -117,44 +121,67 @@
|
||||
|
||||
/area/shuttle/arrival
|
||||
name = "Arrival Shuttle"
|
||||
unique = TRUE // SSjob refers to this area for latejoiners
|
||||
area_flags = UNIQUE_AREA// SSjob refers to this area for latejoiners
|
||||
|
||||
/area/shuttle/pod_1
|
||||
name = "Escape Pod One"
|
||||
area_flags = BLOBS_ALLOWED
|
||||
|
||||
/area/shuttle/pod_2
|
||||
name = "Escape Pod Two"
|
||||
area_flags = BLOBS_ALLOWED
|
||||
|
||||
/area/shuttle/pod_3
|
||||
name = "Escape Pod Three"
|
||||
area_flags = BLOBS_ALLOWED
|
||||
|
||||
/area/shuttle/pod_4
|
||||
name = "Escape Pod Four"
|
||||
area_flags = BLOBS_ALLOWED
|
||||
|
||||
/area/shuttle/mining
|
||||
name = "Mining Shuttle"
|
||||
blob_allowed = FALSE
|
||||
area_flags = NONE //Set this so it doesn't inherit NO_ALERTS
|
||||
|
||||
/area/shuttle/mining/large
|
||||
name = "Mining Shuttle"
|
||||
requires_power = TRUE
|
||||
|
||||
/area/shuttle/labor
|
||||
name = "Labor Camp Shuttle"
|
||||
blob_allowed = FALSE
|
||||
area_flags = NONE //Set this so it doesn't inherit NO_ALERTS
|
||||
|
||||
/area/shuttle/supply
|
||||
name = "Supply Shuttle"
|
||||
blob_allowed = FALSE
|
||||
area_flags = NOTELEPORT
|
||||
|
||||
/area/shuttle/escape
|
||||
name = "Emergency Shuttle"
|
||||
area_flags = BLOBS_ALLOWED
|
||||
// area_limited_icon_smoothing = /area/shuttle/escape
|
||||
canSmoothWithAreas = /area/shuttle/escape
|
||||
flags_1 = CAN_BE_DIRTY_1 // | CULT_PERMITTED_1
|
||||
|
||||
/area/shuttle/escape/backup
|
||||
name = "Backup Emergency Shuttle"
|
||||
|
||||
/area/shuttle/escape/brig
|
||||
name = "Escape Shuttle Brig"
|
||||
icon_state = "shuttlered"
|
||||
|
||||
/area/shuttle/escape/luxury
|
||||
name = "Luxurious Emergency Shuttle"
|
||||
// area_flags = NOTELEPORT
|
||||
|
||||
/area/shuttle/escape/simulation
|
||||
name = "Medieval Reality Simulation Dome"
|
||||
icon_state = "shuttlectf"
|
||||
area_flags = NOTELEPORT
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
/area/shuttle/escape/arena
|
||||
name = "The Arena"
|
||||
noteleport = TRUE
|
||||
area_flags = NOTELEPORT
|
||||
|
||||
/area/shuttle/escape/meteor
|
||||
name = "\proper a meteor with engines strapped to it"
|
||||
@@ -162,34 +189,26 @@
|
||||
|
||||
/area/shuttle/transport
|
||||
name = "Transport Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/assault_pod
|
||||
name = "Steel Rain"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/sbc_starfury
|
||||
name = "SBC Starfury"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/sbc_fighter1
|
||||
name = "SBC Fighter 1"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/sbc_fighter2
|
||||
name = "SBC Fighter 2"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/sbc_corvette
|
||||
name = "SBC corvette"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/syndicate_scout
|
||||
name = "Syndicate Scout"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/caravan
|
||||
blob_allowed = FALSE
|
||||
requires_power = TRUE
|
||||
|
||||
/area/shuttle/caravan/syndicate1
|
||||
|
||||
@@ -58,14 +58,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/threat_level = 0
|
||||
/// The current antag threat. Recalculated every time a ruletype starts or ends.
|
||||
var/threat = 0
|
||||
/// Threat average over the course of the round, for endgame logs.
|
||||
var/threat_average = 0
|
||||
/// Number of times threat average has been calculated, for calculating above.
|
||||
var/threat_average_weight = 0
|
||||
/// Last time a threat average sample was taken. Used for weighting the rolling average.
|
||||
var/last_threat_sample_time = 0
|
||||
/// Maximum threat recorded so far, for cross-round chaos adjustment.
|
||||
var/max_threat = 0
|
||||
/// Things that cause a rolling threat adjustment to be displayed at roundend.
|
||||
var/list/threat_tallies = list()
|
||||
/// Running information about the threat. Can store text or datum entries.
|
||||
@@ -745,17 +737,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
continue
|
||||
if(!M.voluntary_ghosted)
|
||||
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
|
||||
threat = storyteller.calculate_threat() + added_threat
|
||||
max_threat = max(max_threat,threat)
|
||||
if(threat_average_weight)
|
||||
var/cur_sample_weight = world.time - last_threat_sample_time
|
||||
threat_average = ((threat_average * threat_average_weight) + (threat * cur_sample_weight)) / (threat_average_weight + cur_sample_weight)
|
||||
threat_average_weight += cur_sample_weight
|
||||
last_threat_sample_time = world.time
|
||||
else
|
||||
threat_average = threat
|
||||
threat_average_weight++
|
||||
last_threat_sample_time = world.time
|
||||
threat = (SSactivity.current_threat * 0.6 + SSactivity.get_max_threat() * 0.2 + SSactivity.get_average_threat() * 0.2) + added_threat
|
||||
|
||||
/// Removes type from the list
|
||||
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
|
||||
|
||||
@@ -45,27 +45,6 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
mode.midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
/datum/dynamic_storyteller/proc/calculate_threat()
|
||||
var/threat = 0
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
if(A?.owner?.current && A.owner.current.stat != DEAD)
|
||||
threat += A.threat()
|
||||
for(var/r in SSevents.running)
|
||||
var/datum/round_event/R = r
|
||||
threat += R.threat()
|
||||
for(var/obj/item/phylactery/P in GLOB.poi_list)
|
||||
threat += 25 // can't be giving them too much of a break
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (M?.mind?.assigned_role && M.stat != DEAD)
|
||||
var/datum/job/J = SSjob.GetJob(M.mind.assigned_role)
|
||||
if(J)
|
||||
if(length(M.mind.antag_datums))
|
||||
threat += J.GetThreat()
|
||||
else
|
||||
threat -= J.GetThreat()
|
||||
threat += (mode.current_players[CURRENT_DEAD_PLAYERS].len)*dead_player_weight
|
||||
return round(threat,0.1)
|
||||
|
||||
/datum/dynamic_storyteller/proc/do_process()
|
||||
return
|
||||
|
||||
@@ -95,7 +74,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
if(voters)
|
||||
GLOB.dynamic_curve_centre += (mean/voters)
|
||||
if(flags & USE_PREV_ROUND_WEIGHTS)
|
||||
GLOB.dynamic_curve_centre += (50 - SSpersistence.average_dynamic_threat) / 10
|
||||
GLOB.dynamic_curve_centre += (SSpersistence.average_threat) / 10
|
||||
GLOB.dynamic_forced_threat_level = forced_threat_level
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_midround_cooldown()
|
||||
|
||||
@@ -5,28 +5,16 @@
|
||||
continue
|
||||
S.charge = 0
|
||||
S.output_level = 0
|
||||
S.output_attempt = 0
|
||||
S.output_attempt = FALSE
|
||||
S.update_icon()
|
||||
S.power_change()
|
||||
|
||||
var/list/skipped_areas = list(/area/engine/engineering, /area/engine/supermatter, /area/engine/atmospherics_engine, /area/ai_monitored/turret_protected/ai)
|
||||
|
||||
for(var/area/A in world)
|
||||
if( !A.requires_power || A.always_unpowered || A.base_area)
|
||||
for(var/area/A in GLOB.the_station_areas)
|
||||
if(!A.requires_power || A.always_unpowered )
|
||||
continue
|
||||
if(GLOB.typecache_powerfailure_safe_areas[A.type])
|
||||
continue
|
||||
|
||||
var/skip = 0
|
||||
for(var/area_type in skipped_areas)
|
||||
if(istype(A,area_type))
|
||||
skip = 1
|
||||
break
|
||||
if(A.contents)
|
||||
for(var/atom/AT in A.contents)
|
||||
if(!is_station_level(AT.z)) //Only check one, it's enough.
|
||||
skip = 1
|
||||
break
|
||||
if(skip)
|
||||
continue
|
||||
A.power_light = FALSE
|
||||
A.power_equip = FALSE
|
||||
A.power_environ = FALSE
|
||||
@@ -35,13 +23,7 @@
|
||||
for(var/obj/machinery/power/apc/C in GLOB.apcs_list)
|
||||
if(C.cell && is_station_level(C.z))
|
||||
var/area/A = C.area
|
||||
|
||||
var/skip = 0
|
||||
for(var/area_type in skipped_areas)
|
||||
if(istype(A,area_type))
|
||||
skip = 1
|
||||
break
|
||||
if(skip)
|
||||
if(GLOB.typecache_powerfailure_safe_areas[A.type])
|
||||
continue
|
||||
|
||||
C.cell.charge = 0
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
|
||||
for(var/mob/dead/new_player/player in players)
|
||||
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
|
||||
if((role in player.client.prefs.be_special) && (ROLE_SYNDICATE in player.client.prefs.be_special))
|
||||
if((role in player.client.prefs.be_special) && !(ROLE_NO_ANTAGONISM in player.client.prefs.be_special))
|
||||
if(!jobban_isbanned(player, ROLE_SYNDICATE) && !QDELETED(player) && !jobban_isbanned(player, role) && !QDELETED(player)) //Nodrak/Carn: Antag Job-bans
|
||||
if(age_check(player.client)) //Must be older than the minimum age
|
||||
candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
|
||||
|
||||
@@ -413,7 +413,7 @@
|
||||
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) //First, collect all area types on the station zlevel
|
||||
for(var/ar in SSmapping.areas_in_z["[z]"])
|
||||
var/area/A = ar
|
||||
if(!(A.type in valid_territories) && A.valid_territory)
|
||||
if(!(A.type in valid_territories) && (A.area_flags & VALID_TERRITORY))
|
||||
valid_territories |= A.type
|
||||
return valid_territories.len
|
||||
|
||||
|
||||
@@ -412,6 +412,24 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
|
||||
counter++
|
||||
return counter >= 8
|
||||
|
||||
/datum/objective/freedom
|
||||
name = "freedom"
|
||||
explanation_text = "Don't get captured by nanotrasen."
|
||||
team_explanation_text = "Have all members of your team free of nanotrasen custody."
|
||||
|
||||
/datum/objective/freedom/check_completion()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
for(var/m in owners)
|
||||
var/datum/mind/M = m
|
||||
if(!considered_alive(M))
|
||||
return FALSE
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
return FALSE
|
||||
var/turf/location = get_turf(M.current)
|
||||
if(!location || istype(location, /turf/open/floor/plasteel/shuttle/red) || istype(location, /turf/open/floor/mineral/plastitanium/red/brig)) // Fails if they are in the shuttle brig
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/escape
|
||||
name = "escape"
|
||||
explanation_text = "Escape on the shuttle or an escape pod alive and without being in custody."
|
||||
@@ -1240,7 +1258,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
|
||||
var/payout_bonus = 0
|
||||
var/area/dropoff = null
|
||||
var/static/list/blacklisted_areas = typecacheof(list(/area/ai_monitored/turret_protected,
|
||||
/area/solar/,
|
||||
/area/solars/,
|
||||
/area/ruin/, //thank you station space ruins
|
||||
/area/science/test_area/,
|
||||
/area/shuttle/))
|
||||
|
||||
@@ -33,70 +33,6 @@
|
||||
/datum/sabotage_objective/processing/check_conditions()
|
||||
return won
|
||||
|
||||
/*
|
||||
/datum/sabotage_objective/processing/power_sink
|
||||
name = "Drain at least 100 megajoules of power using a power sink."
|
||||
sabotage_type = "powersink"
|
||||
special_equipment = list(/obj/item/sbeacondrop/powersink)
|
||||
var/sink_found = FALSE
|
||||
var/count = 0
|
||||
|
||||
/datum/sabotage_objective/processing/power_sink/check_condition_processing()
|
||||
for(var/s in GLOB.power_sinks)
|
||||
var/obj/item/powersink/sink = s
|
||||
won = max(won,sink.power_drained/1e8)
|
||||
*/
|
||||
|
||||
/obj/item/paper/guides/antag/supermatter_sabotage
|
||||
info = "Ways to sabotage a supermatter:<br>\
|
||||
<ul>\
|
||||
<li>Set the air alarm's operating mode to anything that isn't 'draught' (yes, anything, though 'off' works best). Or just smash the air alarm, that works too.</li>\
|
||||
<li>Wrench a pipe (the junction to the cold loop is most effective, but some setups will robust through this no issue; best to try for multiple)</li>\
|
||||
<li>Pump in as much carbon dioxide, oxygen, plasma or tritium as you can find (this will likely also cause a singularity or tesla delamination, so watch out!)</li>\
|
||||
<li>Unset the filters on the cooling loop, or, perhaps more insidious, set them to oxygen/plasma.</li>\
|
||||
<li>Deactivate the digital valve that sends the exhaust gases to space (note: only works on box station; others you must unwrench).</li>\
|
||||
<li>There are many other ways; be creative!</li>\
|
||||
</ul>"
|
||||
|
||||
/*/datum/sabotage_objective/processing/supermatter
|
||||
name = "Sabotage the supermatter so that it goes under 50% integrity. If it is delaminated, you will fail."
|
||||
sabotage_type = "supermatter"
|
||||
special_equipment = list(/obj/item/paper/guides/antag/supermatter_sabotage)
|
||||
var/list/supermatters = list()
|
||||
excludefromjob = list("Chief Engineer", "Station Engineer", "Atmospheric Technician")
|
||||
|
||||
/datum/sabotage_objective/processing/supermatter/check_condition_processing()
|
||||
if(!supermatters.len)
|
||||
supermatters = list()
|
||||
for(var/obj/machinery/power/supermatter_crystal/S in GLOB.machines)
|
||||
// Delaminating, not within coverage, not on a tile.
|
||||
if (!isturf(S.loc) || !(is_station_level(S.z) || is_mining_level(S.z)))
|
||||
continue
|
||||
supermatters.Add(S)
|
||||
for(var/obj/machinery/power/supermatter_crystal/S in supermatters) // you can win this with a wishgranter... lol.
|
||||
won = max(1-((S.get_integrity()-50)/50),won)
|
||||
return FALSE
|
||||
|
||||
/datum/sabotage_objective/processing/supermatter/can_run()
|
||||
return (locate(/obj/machinery/power/supermatter_crystal) in GLOB.machines)
|
||||
|
||||
/datum/sabotage_objective/station_integrity
|
||||
name = "Make sure the station is at less than 80% integrity by the end. Smash walls, windows etc. to reach this goal."
|
||||
sabotage_type = "integrity"
|
||||
|
||||
/datum/sabotage_objective/station_integrity/check_conditions()
|
||||
return 5-(max(SSticker.station_integrity*4,320)/80)
|
||||
*/
|
||||
/datum/sabotage_objective/cloner
|
||||
name = "Destroy all Nanotrasen cloning machines."
|
||||
sabotage_type = "cloner"
|
||||
|
||||
/datum/sabotage_objective/cloner/check_conditions()
|
||||
for(var/obj/machinery/clonepod/cloner in GLOB.machines)
|
||||
if(is_station_level(cloner.z))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/sabotage_objective/ai_law
|
||||
name = "Upload a hacked law to the AI."
|
||||
sabotage_type = "ailaw"
|
||||
|
||||
@@ -519,6 +519,8 @@ Class Procs:
|
||||
|
||||
//called on machinery construction (i.e from frame to machinery) but not on initialization
|
||||
/obj/machinery/proc/on_construction()
|
||||
for(var/obj/I in contents)
|
||||
I.moveToNullspace()
|
||||
return
|
||||
|
||||
//called on deconstruction before the final deletion
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
icon_state = "0"
|
||||
state = 0
|
||||
|
||||
/obj/structure/frame/computer/attackby(obj/item/P, mob/user, params)
|
||||
/obj/structure/frame/computer/attackby(obj/item/P, mob/living/user, params)
|
||||
add_fingerprint(user)
|
||||
switch(state)
|
||||
if(0)
|
||||
@@ -11,7 +11,7 @@
|
||||
to_chat(user, "<span class='notice'>You start wrenching the frame into place...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50))
|
||||
to_chat(user, "<span class='notice'>You wrench the frame into place.</span>")
|
||||
setAnchored(TRUE)
|
||||
set_anchored(TRUE)
|
||||
state = 1
|
||||
return
|
||||
if(P.tool_behaviour == TOOL_WELDER)
|
||||
@@ -19,7 +19,7 @@
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You start deconstructing the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50) && state == 0)
|
||||
if(P.use_tool(src, user, 20, volume=50))
|
||||
to_chat(user, "<span class='notice'>You deconstruct the frame.</span>")
|
||||
var/obj/item/stack/sheet/metal/M = new (drop_location(), 5)
|
||||
M.add_fingerprint(user)
|
||||
@@ -28,15 +28,15 @@
|
||||
if(1)
|
||||
if(P.tool_behaviour == TOOL_WRENCH)
|
||||
to_chat(user, "<span class='notice'>You start to unfasten the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50) && state == 1)
|
||||
if(P.use_tool(src, user, 20, volume=50))
|
||||
to_chat(user, "<span class='notice'>You unfasten the frame.</span>")
|
||||
setAnchored(FALSE)
|
||||
set_anchored(FALSE)
|
||||
state = 0
|
||||
return
|
||||
if(istype(P, /obj/item/circuitboard/computer) && !circuit)
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
to_chat(user, "<span class='notice'>You place [P] inside the frame.</span>")
|
||||
icon_state = "1"
|
||||
circuit = P
|
||||
@@ -71,8 +71,10 @@
|
||||
if(istype(P, /obj/item/stack/cable_coil))
|
||||
if(!P.tool_start_check(user, amount=5))
|
||||
return
|
||||
if(state != 2)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start adding cables to the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, 5, 50, CALLBACK(src, .proc/check_state, 2)))
|
||||
if(P.use_tool(src, user, 20, volume=50, amount=5))
|
||||
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
|
||||
state = 3
|
||||
icon_state = "3"
|
||||
@@ -90,9 +92,11 @@
|
||||
if(istype(P, /obj/item/stack/sheet/glass))
|
||||
if(!P.tool_start_check(user, amount=2))
|
||||
return
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
if(state != 3)
|
||||
return
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
to_chat(user, "<span class='notice'>You start to put in the glass panel...</span>")
|
||||
if(P.use_tool(src, user, 20, 2, 0, CALLBACK(src, .proc/check_state, 3)))
|
||||
if(P.use_tool(src, user, 20, amount=2))
|
||||
to_chat(user, "<span class='notice'>You put in the glass panel.</span>")
|
||||
state = 4
|
||||
src.icon_state = "4"
|
||||
@@ -109,14 +113,51 @@
|
||||
if(P.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
P.play_tool_sound(src)
|
||||
to_chat(user, "<span class='notice'>You connect the monitor.</span>")
|
||||
var/obj/B = new circuit.build_path (loc, circuit)
|
||||
B.setDir(dir)
|
||||
transfer_fingerprints_to(B)
|
||||
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc)
|
||||
new_machine.setDir(dir)
|
||||
transfer_fingerprints_to(new_machine)
|
||||
|
||||
if(istype(new_machine, /obj/machinery/computer))
|
||||
var/obj/machinery/computer/new_computer = new_machine
|
||||
|
||||
// Machines will init with a set of default components.
|
||||
// Triggering handle_atom_del will make the machine realise it has lost a component_parts and then deconstruct.
|
||||
// Move to nullspace so we don't trigger handle_atom_del, then qdel.
|
||||
// Finally, replace new machine's parts with this frame's parts.
|
||||
if(new_computer.circuit)
|
||||
// Move to nullspace and delete.
|
||||
new_computer.circuit.moveToNullspace()
|
||||
QDEL_NULL(new_computer.circuit)
|
||||
for(var/old_part in new_computer.component_parts)
|
||||
var/atom/movable/movable_part = old_part
|
||||
// Move to nullspace and delete.
|
||||
movable_part.moveToNullspace()
|
||||
qdel(movable_part)
|
||||
|
||||
// Set anchor state and move the frame's parts over to the new machine.
|
||||
// Then refresh parts and call on_construction().
|
||||
new_computer.set_anchored(anchored)
|
||||
new_computer.component_parts = list()
|
||||
|
||||
circuit.forceMove(new_computer)
|
||||
new_computer.component_parts += circuit
|
||||
new_computer.circuit = circuit
|
||||
|
||||
for(var/new_part in src)
|
||||
var/atom/movable/movable_part = new_part
|
||||
movable_part.forceMove(new_computer)
|
||||
new_computer.component_parts += movable_part
|
||||
|
||||
new_computer.RefreshParts()
|
||||
new_computer.on_construction()
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/frame/computer/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
if(state == 4)
|
||||
@@ -127,13 +168,12 @@
|
||||
..()
|
||||
|
||||
/obj/structure/frame/computer/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
||||
..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE, TRUE, FALSE))
|
||||
return
|
||||
|
||||
if(anchored)
|
||||
to_chat(usr, "<span class='warning'>You must unwrench [src] before rotating it!</span>")
|
||||
return TRUE
|
||||
return
|
||||
|
||||
setDir(turn(dir, -90))
|
||||
return TRUE
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/temp = "Inactive"
|
||||
var/scantemp_ckey
|
||||
var/scantemp_name
|
||||
var/scantemp = "Ready to Scan"
|
||||
var/scantemp = "Inactive"
|
||||
var/menu = 1 //Which menu screen to display
|
||||
var/datum/data/record/active_record = null
|
||||
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
|
||||
@@ -132,7 +132,6 @@
|
||||
src.diskette = W
|
||||
to_chat(user, "<span class='notice'>You insert [W].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
src.updateUsrDialog()
|
||||
else if(W.tool_behaviour == TOOL_MULTITOOL)
|
||||
if(istype(W.buffer, clonepod_type))
|
||||
if(get_area(W.buffer) != get_area(src))
|
||||
@@ -151,311 +150,233 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/cloning/ui_interact(mob/user)
|
||||
/obj/machinery/computer/cloning/AltClick(mob/user)
|
||||
. = ..()
|
||||
EjectDisk(user)
|
||||
|
||||
updatemodules(TRUE)
|
||||
/obj/machinery/computer/cloning/proc/EjectDisk(mob/user)
|
||||
if(diskette)
|
||||
scantemp = "Disk Ejected"
|
||||
diskette.forceMove(drop_location())
|
||||
usr.put_in_active_hand(diskette)
|
||||
diskette = null
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
|
||||
var/dat = ""
|
||||
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
|
||||
/obj/machinery/computer/cloning/proc/Save(mob/user, target)
|
||||
var/datum/data/record/GRAB = null
|
||||
for(var/datum/data/record/record in records)
|
||||
if(record.fields["id"] == target)
|
||||
GRAB = record
|
||||
break
|
||||
else
|
||||
continue
|
||||
if(!GRAB || !GRAB.fields)
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
scantemp = "Failed saving to disk: Data Corruption"
|
||||
return FALSE
|
||||
if(!diskette || diskette.read_only)
|
||||
scantemp = !diskette ? "Failed saving to disk: No disk." : "Failed saving to disk: Disk refuses override attempt."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
diskette.fields = GRAB.fields.Copy()
|
||||
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
|
||||
scantemp = "Saved to disk successfully."
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/DeleteRecord(mob/user, target)
|
||||
var/datum/data/record/GRAB = null
|
||||
for(var/datum/data/record/record in records)
|
||||
if(record.fields["id"] == target)
|
||||
GRAB = record
|
||||
break
|
||||
else
|
||||
continue
|
||||
if(!GRAB)
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
scantemp = "Cannot delete: Data Corrupted."
|
||||
return FALSE
|
||||
var/obj/item/card/id/C = usr.get_idcard(hand_first = TRUE)
|
||||
if(istype(C) || istype(C, /obj/item/pda) || istype(C, /obj/item/modular_computer/tablet))
|
||||
if(check_access(C))
|
||||
scantemp = "[GRAB.fields["name"]] => Record deleted."
|
||||
records.Remove(GRAB)
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
var/obj/item/circuitboard/computer/cloning/board = circuit
|
||||
board.records = records
|
||||
return TRUE
|
||||
scantemp = "Cannot delete: Access Denied."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/Load(mob/user)
|
||||
if(!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
|
||||
scantemp = "Failed loading: Load error."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
for(var/datum/data/record/R in records)
|
||||
if(R.fields["key"] == diskette.fields["key"])
|
||||
scantemp = "Failed loading: Data already exists!"
|
||||
return FALSE
|
||||
var/datum/data/record/R = new(src)
|
||||
for(var/key in diskette.fields)
|
||||
R.fields[key] = diskette.fields[key]
|
||||
records += R
|
||||
scantemp = "Loaded into internal storage successfully."
|
||||
var/obj/item/circuitboard/computer/cloning/board = circuit
|
||||
board.records = records
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/Clone(mob/user, target)
|
||||
var/datum/data/record/C = find_record("id", target, records)
|
||||
//Look for that player! They better be dead!
|
||||
if(C)
|
||||
var/obj/machinery/clonepod/pod = GetAvailablePod()
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!LAZYLEN(pods))
|
||||
temp = "Error: No Clonepods detected."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!pod)
|
||||
temp = "Error: No Clonepods available."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!CONFIG_GET(flag/revival_cloning))
|
||||
temp = "Error: Unable to initiate cloning cycle."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.occupant)
|
||||
temp = "Warning: Cloning cycle already in progress."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
|
||||
temp = "Notice: [C.fields["name"]] => Cloning cycle in progress..."
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
records.Remove(C)
|
||||
else
|
||||
temp = "Error: [C.fields["name"]] => Initialisation failure."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
|
||||
else
|
||||
temp = "Failed to clone: Data corrupted."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/proc/Toggle_lock(mob/user)
|
||||
if(!scanner.is_operational())
|
||||
return
|
||||
if(!scanner.locked && !scanner.occupant) //I figured out that if you're fast enough, you can lock an open pod
|
||||
return
|
||||
scanner.locked = !scanner.locked
|
||||
playsound(src, scanner.locked ? 'sound/machines/terminal_prompt_deny.ogg' : 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/proc/Scan(mob/user)
|
||||
if(!scanner.is_operational() || !scanner.occupant)
|
||||
return
|
||||
scantemp = "[scantemp_name] => Scanning..."
|
||||
loading = TRUE
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
say("Initiating scan...")
|
||||
var/prev_locked = scanner.locked
|
||||
scanner.locked = TRUE
|
||||
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/proc/Toggle_autoprocess(mob/user)
|
||||
autoprocess = !autoprocess
|
||||
if(autoprocess)
|
||||
START_PROCESSING(SSmachines, src)
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
else
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["useRecords"] = use_records
|
||||
var/list/records_to_send = list()
|
||||
if(use_records)
|
||||
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
|
||||
if(!autoprocess)
|
||||
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
|
||||
else
|
||||
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Autoclone</span>"
|
||||
dat += "<h3>Cloning Pod Status</h3>"
|
||||
dat += "<div class='statusDisplay'>[temp] </div>"
|
||||
|
||||
switch(src.menu)
|
||||
if(1)
|
||||
// Modules
|
||||
if (isnull(src.scanner) || !LAZYLEN(pods))
|
||||
dat += "<h3>Modules</h3>"
|
||||
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
|
||||
if (isnull(src.scanner))
|
||||
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
|
||||
if (!LAZYLEN(pods))
|
||||
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
|
||||
|
||||
// Scanner
|
||||
if (!isnull(src.scanner))
|
||||
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
|
||||
|
||||
dat += "<h3>Scanner Functions</h3>"
|
||||
|
||||
dat += "<div class='statusDisplay'>"
|
||||
if(!scanner_occupant)
|
||||
dat += "Scanner Unoccupied"
|
||||
else if(loading)
|
||||
dat += "[scanner_occupant] => Scanning..."
|
||||
else
|
||||
if(use_records)
|
||||
if(scanner_occupant.ckey != scantemp_ckey || scanner_occupant.name != scantemp_name)
|
||||
scantemp = "Ready to Scan"
|
||||
scantemp_ckey = scanner_occupant.ckey
|
||||
scantemp_name = scanner_occupant.name
|
||||
else
|
||||
scantemp = "Ready to Clone"
|
||||
dat += "[scanner_occupant] => [scantemp]"
|
||||
dat += "</div>"
|
||||
|
||||
if(scanner_occupant)
|
||||
dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
|
||||
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
|
||||
else
|
||||
dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
|
||||
if(use_records)
|
||||
// Database
|
||||
dat += "<h3>Database Functions</h3>"
|
||||
if (src.records.len && src.records.len > 0)
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
|
||||
else
|
||||
dat += "<span class='linkOff'>View Records (0)</span><br>"
|
||||
if (src.diskette)
|
||||
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
|
||||
|
||||
|
||||
|
||||
if(2)
|
||||
dat += "<h3>Current records</h3>"
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=1'><< Back</a><br><br>"
|
||||
data["hasAutoprocess"] = TRUE
|
||||
if(length(records))
|
||||
for(var/datum/data/record/R in records)
|
||||
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=[REF(src)];view_rec=[R.fields["id"]]'>View Record</a>"
|
||||
if(3)
|
||||
dat += "<h3>Selected Record</h3>"
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=2'><< Back</a><br>"
|
||||
|
||||
if (!src.active_record)
|
||||
dat += "<font class='bad'>Record not found.</font>"
|
||||
else
|
||||
dat += "<h4>[src.active_record.fields["name"]]</h4>"
|
||||
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=[REF(src)];clone=[active_record.fields["id"]]'>Clone</a><br>"
|
||||
|
||||
var/obj/item/implant/health/H = locate(active_record.fields["imp"])
|
||||
|
||||
if ((H) && (istype(H)))
|
||||
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
|
||||
var/list/record_entry = list()
|
||||
record_entry["name"] = "[R.fields["name"]]"
|
||||
record_entry["id"] = "[R.fields["id"]]"
|
||||
var/obj/item/implant/health/H = locate(R.fields["imp"])
|
||||
if(H && istype(H))
|
||||
record_entry["damages"] = H.sensehealth(TRUE)
|
||||
else
|
||||
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
|
||||
record_entry["damages"] = FALSE
|
||||
record_entry["UI"] = "[R.fields["UI"]]"
|
||||
record_entry["UE"] = "[R.fields["UE"]]"
|
||||
record_entry["blood_type"] = "[R.fields["blood_type"]]"
|
||||
records_to_send += list(record_entry)
|
||||
data["records"] = records_to_send
|
||||
else
|
||||
data["records"] = list()
|
||||
if(diskette && diskette.fields)
|
||||
var/list/disk_data = list()
|
||||
disk_data["name"] = "[diskette.fields["name"]]"
|
||||
disk_data["id"] = "[diskette.fields["id"]]"
|
||||
disk_data["UI"] = "[diskette.fields["UI"]]"
|
||||
disk_data["UE"] = "[diskette.fields["UE"]]"
|
||||
disk_data["blood_type"] = "[diskette.fields["blood_type"]]"
|
||||
data["diskData"] = disk_data
|
||||
else
|
||||
data["diskData"] = list()
|
||||
else
|
||||
data["hasAutoprocess"] = FALSE
|
||||
data["autoprocess"] = autoprocess
|
||||
var/list/lack_machine = list()
|
||||
if(isnull(src.scanner))
|
||||
lack_machine += "ERROR: No Scanner Detected!"
|
||||
if(!LAZYLEN(pods))
|
||||
lack_machine += "ERROR: No Pod Detected!"
|
||||
data["lacksMachine"] = lack_machine
|
||||
data["temp"] = temp
|
||||
var/build_temp = null
|
||||
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner?.occupant)
|
||||
if(scanner_occupant?.ckey != scantemp_ckey || scanner_occupant?.name != scantemp_name)
|
||||
if(use_records)
|
||||
build_temp = "Ready to Scan"
|
||||
scantemp_ckey = scanner_occupant?.ckey
|
||||
scantemp_name = scanner_occupant?.name
|
||||
else
|
||||
build_temp = "Ready to Clone"
|
||||
scantemp = "[scanner_occupant] => [build_temp]"
|
||||
data["scanTemp"] = scantemp
|
||||
data["scannerLocked"] = scanner?.locked
|
||||
data["hasOccupant"] = scanner?.occupant
|
||||
data["recordsLength"] = "View Records ([length(records)])"
|
||||
|
||||
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
|
||||
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
|
||||
return data
|
||||
|
||||
if(diskette && diskette.fields)
|
||||
dat += "<div class='block'>"
|
||||
dat += "<h4>Inserted Disk</h4>"
|
||||
dat += "<b>Contents:</b> "
|
||||
var/list/L = list()
|
||||
if(diskette.fields["UI"])
|
||||
L += "Unique Identifier"
|
||||
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
|
||||
L += "Unique Enzymes"
|
||||
if(diskette.fields["SE"])
|
||||
L += "Structural Enzymes"
|
||||
dat += english_list(L, "Empty", " + ", " + ")
|
||||
dat += "<br /><a href='byond://?src=[REF(src)];disk=load'>Load from Disk</a>"
|
||||
|
||||
dat += "<br /><a href='byond://?src=[REF(src)];disk=save'>Save to Disk</a>"
|
||||
dat += "</div>"
|
||||
|
||||
dat += "<font size=1><a href='byond://?src=[REF(src)];del_rec=1'>Delete Record</a></font>"
|
||||
|
||||
if(4)
|
||||
if (!src.active_record)
|
||||
src.menu = 2
|
||||
dat = "[src.temp]<br>"
|
||||
dat += "<h3>Confirm Record Deletion</h3>"
|
||||
|
||||
dat += "<b><a href='byond://?src=[REF(src)];del_rec=1'>Scan card to confirm.</a></b><br>"
|
||||
dat += "<b><a href='byond://?src=[REF(src)];menu=3'>Cancel</a></b>"
|
||||
|
||||
|
||||
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/cloning/Topic(href, href_list)
|
||||
/obj/machinery/computer/cloning/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("toggle_autoprocess")
|
||||
Toggle_autoprocess(usr)
|
||||
if("scan")
|
||||
Scan(usr)
|
||||
if("toggle_lock")
|
||||
Toggle_lock(usr)
|
||||
if("clone")
|
||||
Clone(usr, params["target"])
|
||||
if("delrecord")
|
||||
DeleteRecord(usr, params["target"])
|
||||
if("save")
|
||||
Save(usr, params["target"])
|
||||
if("load")
|
||||
Load(usr)
|
||||
if("eject")
|
||||
EjectDisk(usr)
|
||||
|
||||
if(loading)
|
||||
/obj/machinery/computer/cloning/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(href_list["task"])
|
||||
switch(href_list["task"])
|
||||
if("autoprocess")
|
||||
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
|
||||
autoprocess = TRUE
|
||||
START_PROCESSING(SSmachines, src)
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
if("stopautoprocess")
|
||||
autoprocess = FALSE
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
src.updateUsrDialog()
|
||||
. = TRUE
|
||||
|
||||
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
|
||||
scantemp = ""
|
||||
|
||||
loading = TRUE
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
say("Initiating scan...")
|
||||
var/prev_locked = scanner.locked
|
||||
scanner.locked = TRUE
|
||||
src.updateUsrDialog()
|
||||
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
|
||||
. = TRUE
|
||||
|
||||
//No locking an open scanner.
|
||||
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
|
||||
if ((!scanner.locked) && (scanner.occupant))
|
||||
scanner.locked = TRUE
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else
|
||||
scanner.locked = FALSE
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
src.updateUsrDialog()
|
||||
. = TRUE
|
||||
|
||||
|
||||
else if (href_list["refresh"])
|
||||
src.updateUsrDialog()
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
|
||||
if(. || !use_records)
|
||||
return
|
||||
if(href_list["view_rec"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
src.active_record = find_record("id", href_list["view_rec"], records)
|
||||
if(active_record)
|
||||
if(!active_record.fields["ckey"])
|
||||
records -= active_record
|
||||
active_record = null
|
||||
src.temp = "<font class='bad'>Record Corrupt</font>"
|
||||
else
|
||||
src.menu = 3
|
||||
else
|
||||
src.temp = "Record missing."
|
||||
src.updateUsrDialog()
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["del_rec"])
|
||||
if ((!src.active_record) || (src.menu < 3))
|
||||
return
|
||||
if (src.menu == 3) //If we are viewing a record, confirm deletion
|
||||
src.temp = "Delete record?"
|
||||
src.menu = 4
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
|
||||
else if (src.menu == 4)
|
||||
var/obj/item/card/id/C = usr.get_active_held_item()
|
||||
if (istype(C)||istype(C, /obj/item/pda))
|
||||
if(src.check_access(C))
|
||||
src.temp = "[src.active_record.fields["name"]] => Record deleted."
|
||||
src.records.Remove(active_record)
|
||||
active_record = null
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
src.menu = 2
|
||||
var/obj/item/circuitboard/computer/cloning/board = circuit
|
||||
board.records = records
|
||||
else
|
||||
src.temp = "<font class='bad'>Access Denied.</font>"
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["disk"] && use_records) //Load or eject.
|
||||
switch(href_list["disk"])
|
||||
if("load")
|
||||
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
|
||||
src.temp = "<font class='bad'>Load error.</font>"
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if (!src.active_record)
|
||||
src.temp = "<font class='bad'>Record error.</font>"
|
||||
src.menu = 1
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
|
||||
for(var/key in diskette.fields)
|
||||
src.active_record.fields[key] = diskette.fields[key]
|
||||
src.temp = "Load successful."
|
||||
src.updateUsrDialog()
|
||||
var/obj/item/circuitboard/computer/cloning/board = circuit
|
||||
board.records = records
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
if("eject")
|
||||
if(src.diskette)
|
||||
src.diskette.forceMove(drop_location())
|
||||
src.diskette = null
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
if("save")
|
||||
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
|
||||
src.temp = "<font class='bad'>Save error.</font>"
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
|
||||
diskette.fields = active_record.fields.Copy()
|
||||
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
|
||||
src.temp = "Save successful."
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["clone"])
|
||||
var/datum/data/record/C = find_record("id", href_list["clone"], records)
|
||||
//Look for that player! They better be dead!
|
||||
if(C)
|
||||
var/obj/machinery/clonepod/pod = GetAvailablePod()
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!LAZYLEN(pods))
|
||||
temp = "<font class='bad'>No Clonepods detected.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!pod)
|
||||
temp = "<font class='bad'>No Clonepods available.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!CONFIG_GET(flag/revival_cloning))
|
||||
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.occupant)
|
||||
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
|
||||
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
records.Remove(C)
|
||||
if(active_record == C)
|
||||
active_record = null
|
||||
menu = 1
|
||||
src.updateUsrDialog()
|
||||
else
|
||||
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
|
||||
else
|
||||
temp = "<font class='bad'>Data corruption.</font>"
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["menu"] && use_records)
|
||||
menu = text2num(href_list["menu"])
|
||||
src.updateUsrDialog()
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
updatemodules(TRUE)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CloningConsole", "Cloning System Control")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
|
||||
if(!scanner || !L)
|
||||
@@ -469,7 +390,6 @@
|
||||
|
||||
loading = FALSE
|
||||
scanner.locked = prev_locked
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
|
||||
@@ -568,44 +488,44 @@
|
||||
var/obj/machinery/clonepod/pod = GetAvailablePod()
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!LAZYLEN(pods))
|
||||
temp = "<font class='bad'>No Clonepods detected.</font>"
|
||||
temp = "No Clonepods detected."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!pod)
|
||||
temp = "<font class='bad'>No Clonepods available.</font>"
|
||||
temp = "No Clonepods available."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.occupant)
|
||||
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
|
||||
temp = "Cloning cycle already in progress."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else
|
||||
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
|
||||
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
|
||||
temp = "[mob_occupant.real_name] => Cloning data sent to pod."
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
|
||||
if(!istype(dna))
|
||||
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
|
||||
scantemp = "Unable to locate valid genetic data."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(!experimental)
|
||||
if(mob_occupant.suiciding || mob_occupant.hellbound)
|
||||
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
|
||||
scantemp = "Subject's brain is not responding to scanning stimuli."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
|
||||
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
|
||||
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
|
||||
return
|
||||
if (!experimental)
|
||||
if(!mob_occupant.ckey || !mob_occupant.client)
|
||||
scantemp = "<font class='bad'>Mental interface failure.</font>"
|
||||
scantemp = "Mental interface failure."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if (find_record("ckey", mob_occupant.ckey, records))
|
||||
scantemp = "<font class='average'>Subject already in database.</font>"
|
||||
scantemp = "Subject already in database."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(SSeconomy.full_ancap && !account)
|
||||
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
|
||||
scantemp = "Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan."
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
return TRUE
|
||||
@@ -618,3 +538,4 @@
|
||||
icon_keyboard = "med_key"
|
||||
circuit = /obj/item/circuitboard/computer/cloning/prototype
|
||||
clonepod_type = /obj/machinery/clonepod/experimental
|
||||
use_records = FALSE //Wait, so you tell me it lacks records but you never set it as false?
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
return FALSE
|
||||
return ACCESS_CAPTAIN in authorize_access
|
||||
|
||||
/obj/machinery/computer/communications/proc/authenticated_as_non_silicon_command(mob/user)
|
||||
if (issilicon(user))
|
||||
return FALSE
|
||||
return ACCESS_HEADS in authorize_access //Should always be the case if authorized as it usually needs head access to log in, buut lets be sure.
|
||||
|
||||
/// Are we a silicon, OR we're logged in as the captain?
|
||||
/obj/machinery/computer/communications/proc/authenticated_as_silicon_or_captain(mob/user)
|
||||
if (issilicon(user))
|
||||
@@ -97,8 +102,14 @@
|
||||
if ("answerMessage")
|
||||
if (!authenticated(usr))
|
||||
return
|
||||
var/answer_index = text2num(params["answer"])
|
||||
var/message_index = text2num(params["message"])
|
||||
var/answer_index = params["answer"]
|
||||
var/message_index = params["message"]
|
||||
|
||||
// If either of these aren't numbers, then bad voodoo.
|
||||
if(!isnum(answer_index) || !isnum(message_index))
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when replying to a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
|
||||
CRASH("Non-numeric index provided when answering comms console message.")
|
||||
|
||||
if (!answer_index || !message_index || answer_index < 1 || message_index < 1)
|
||||
return
|
||||
var/datum/comm_message/message = messages[message_index]
|
||||
@@ -151,7 +162,11 @@
|
||||
if ("deleteMessage")
|
||||
if (!authenticated(usr))
|
||||
return
|
||||
var/message_index = text2num(params["message"])
|
||||
var/message_index = params["message"]
|
||||
|
||||
if(!isnum(message_index))
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when deleting a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
|
||||
CRASH("Non-numeric index provided when deleting comms console message.")
|
||||
if (!message_index)
|
||||
return
|
||||
LAZYREMOVE(messages, LAZYACCESS(messages, message_index))
|
||||
@@ -160,7 +175,7 @@
|
||||
return
|
||||
make_announcement(usr)
|
||||
if ("messageAssociates")
|
||||
if (!authenticated_as_non_silicon_captain(usr))
|
||||
if (!authenticated_as_non_silicon_command(usr))
|
||||
return
|
||||
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
|
||||
return
|
||||
@@ -361,9 +376,9 @@
|
||||
data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user, TRUE)
|
||||
|
||||
if (authenticated_as_non_silicon_captain(user))
|
||||
data["canMessageAssociates"] = TRUE
|
||||
data["canRequestNuke"] = TRUE
|
||||
|
||||
if (authenticated_as_non_silicon_command(user))
|
||||
data["canMessageAssociates"] = TRUE
|
||||
if (can_send_messages_to_other_sectors(user))
|
||||
data["canSendToSectors"] = TRUE
|
||||
|
||||
|
||||
@@ -200,6 +200,6 @@
|
||||
if(is_centcom_level(T.z) || is_away_level(T.z))
|
||||
return FALSE
|
||||
var/area/A = get_area(T)
|
||||
if(!A || A.noteleport)
|
||||
if(!A || (A.area_flags & NOTELEPORT))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -217,6 +217,8 @@
|
||||
new_machine.RefreshParts()
|
||||
|
||||
new_machine.on_construction()
|
||||
// TODO: make sleepers not shit out parts PROPERLY THIS TIME.
|
||||
new_machine.circuit.moveToNullspace()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
@@ -409,7 +409,10 @@
|
||||
visible_message("<span class='notice'>\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.</span>")
|
||||
|
||||
// Ghost and delete the mob.
|
||||
if(!mob_occupant.get_ghost(1))
|
||||
var/mob/dead/observer/G = mob_occupant.get_ghost(TRUE)
|
||||
if(G)
|
||||
G.voluntary_ghosted = TRUE
|
||||
else
|
||||
mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE)
|
||||
|
||||
QDEL_NULL(occupant)
|
||||
|
||||
+235
-195
@@ -1,9 +1,5 @@
|
||||
#define LIMBGROWER_MAIN_MENU 1
|
||||
#define LIMBGROWER_CATEGORY_MENU 2
|
||||
#define LIMBGROWER_CHEMICAL_MENU 3
|
||||
//use these for the menu system
|
||||
|
||||
|
||||
/// The limbgrower. Makes organd and limbs with synthflesh and chems.
|
||||
/// See [limbgrower_designs.dm] for everything we can make.
|
||||
/obj/machinery/limbgrower
|
||||
name = "limb grower"
|
||||
desc = "It grows new limbs using Synthflesh."
|
||||
@@ -15,161 +11,235 @@
|
||||
active_power_usage = 100
|
||||
circuit = /obj/item/circuitboard/machine/limbgrower
|
||||
|
||||
var/operating = FALSE
|
||||
var/disabled = FALSE
|
||||
/// The category of limbs we're browing in our UI.
|
||||
var/selected_category = "human"
|
||||
/// If we're currently printing something.
|
||||
var/busy = FALSE
|
||||
var/prod_coeff = 1
|
||||
/// How efficient our machine is. Better parts = less chemicals used and less power used. Range of 1 to 0.25.
|
||||
var/production_coefficient = 1
|
||||
/// How long it takes for us to print a limb. Affected by production_coefficient.
|
||||
var/production_speed = 3 SECONDS
|
||||
/// The design we're printing currently.
|
||||
var/datum/design/being_built
|
||||
/// Our internal techweb for limbgrower designs.
|
||||
var/datum/techweb/stored_research
|
||||
var/selected_category
|
||||
var/screen = 1
|
||||
/// All the categories of organs we can print.
|
||||
var/list/categories = list(
|
||||
"human" = /datum/species/human,
|
||||
"lizard" = /datum/species/lizard,
|
||||
"mammal" = /datum/species/mammal,
|
||||
"insect" = /datum/species/insect,
|
||||
"fly" = /datum/species/fly,
|
||||
"plasmaman" = /datum/species/plasmaman,
|
||||
"xeno" = /datum/species/xeno,
|
||||
"other" = /datum/species,
|
||||
)
|
||||
var/list/stored_species = list()
|
||||
"human",
|
||||
"lizard",
|
||||
"mammal",
|
||||
"insect",
|
||||
"fly",
|
||||
"plasmaman",
|
||||
"xeno",
|
||||
"other",
|
||||
)
|
||||
var/obj/item/disk/data/dna_disk
|
||||
|
||||
/obj/machinery/limbgrower/Initialize()
|
||||
create_reagents(100, OPENCONTAINER)
|
||||
stored_research = new /datum/techweb/specialized/autounlocking/limbgrower
|
||||
for(var/i in categories)
|
||||
var/species = categories[i]
|
||||
stored_species[i] = new species()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/plumbing/simple_demand)
|
||||
AddComponent(/datum/component/simple_rotation, ROTATION_WRENCH | ROTATION_CLOCKWISE, null, CALLBACK(src, .proc/can_be_rotated))
|
||||
|
||||
/obj/machinery/limbgrower/ui_interact(mob/user)
|
||||
/obj/machinery/limbgrower/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(!is_operational())
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Limbgrower", src)
|
||||
ui.open()
|
||||
|
||||
var/dat = main_win(user)
|
||||
/obj/machinery/limbgrower/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
switch(screen)
|
||||
if(LIMBGROWER_MAIN_MENU)
|
||||
dat = main_win(user)
|
||||
if(LIMBGROWER_CATEGORY_MENU)
|
||||
dat = category_win(user,selected_category)
|
||||
if(LIMBGROWER_CHEMICAL_MENU)
|
||||
dat = chemical_win(user)
|
||||
for(var/datum/reagent/reagent_id in reagents.reagent_list)
|
||||
var/list/reagent_data = list(
|
||||
reagent_name = reagent_id.name,
|
||||
reagent_amount = reagent_id.volume,
|
||||
reagent_type = reagent_id.type
|
||||
)
|
||||
data["reagents"] += list(reagent_data)
|
||||
|
||||
var/datum/browser/popup = new(user, "Limb Grower", name, 400, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
data["total_reagents"] = reagents.total_volume
|
||||
data["max_reagents"] = reagents.maximum_volume
|
||||
data["busy"] = busy
|
||||
var/list/disk_data = list()
|
||||
disk_data["disk"] = dna_disk //Do i, the machine, have a disk?
|
||||
disk_data["name"] = dna_disk?.fields["name"] //Name for the human saved if there is one
|
||||
data["disk"] = disk_data
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/limbgrower/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["categories"] = list()
|
||||
|
||||
var/species_categories = categories.Copy()
|
||||
for(var/species in species_categories)
|
||||
species_categories[species] = list()
|
||||
for(var/design_id in stored_research.researched_designs)
|
||||
var/datum/design/limb_design = SSresearch.techweb_design_by_id(design_id)
|
||||
for(var/found_category in species_categories)
|
||||
if(found_category in limb_design.category)
|
||||
species_categories[found_category] += limb_design
|
||||
|
||||
for(var/category in species_categories)
|
||||
var/list/category_data = list(
|
||||
name = category,
|
||||
designs = list(),
|
||||
)
|
||||
for(var/datum/design/found_design in species_categories[category])
|
||||
var/list/all_reagents = list()
|
||||
for(var/reagent_typepath in found_design.reagents_list)
|
||||
var/datum/reagent/reagent_id = find_reagent_object_from_type(reagent_typepath)
|
||||
var/list/reagent_data = list(
|
||||
name = reagent_id.name,
|
||||
amount = (found_design.reagents_list[reagent_typepath] * production_coefficient),
|
||||
)
|
||||
all_reagents += list(reagent_data)
|
||||
|
||||
category_data["designs"] += list(list(
|
||||
parent_category = category,
|
||||
name = found_design.name,
|
||||
id = found_design.id,
|
||||
needed_reagents = all_reagents,
|
||||
))
|
||||
|
||||
data["categories"] += list(category_data)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/limbgrower/on_deconstruction()
|
||||
for(var/obj/item/reagent_containers/glass/G in component_parts)
|
||||
reagents.trans_to(G, G.reagents.maximum_volume)
|
||||
for(var/obj/item/reagent_containers/glass/our_beaker in component_parts)
|
||||
reagents.trans_to(our_beaker, our_beaker.reagents.maximum_volume)
|
||||
..()
|
||||
|
||||
/obj/machinery/limbgrower/attackby(obj/item/O, mob/user, params)
|
||||
if(busy)
|
||||
/obj/machinery/limbgrower/attackby(obj/item/user_item, mob/living/user, params)
|
||||
if (busy)
|
||||
to_chat(user, "<span class=\"alert\">\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return
|
||||
|
||||
if(default_deconstruction_screwdriver(user, "limbgrower_panelopen", "limbgrower_idleoff", O))
|
||||
updateUsrDialog()
|
||||
if(default_deconstruction_screwdriver(user, "limbgrower_panelopen", "limbgrower_idleoff", user_item))
|
||||
ui_close(user)
|
||||
return
|
||||
|
||||
if(panel_open && default_deconstruction_crowbar(O))
|
||||
return
|
||||
|
||||
if(user.a_intent == INTENT_HARM) //so we can hit the machine
|
||||
if(user_item.tool_behaviour == TOOL_WRENCH && panel_open)
|
||||
return ..()
|
||||
|
||||
if(istype(O, /obj/item/disk))
|
||||
if(panel_open && default_deconstruction_crowbar(user_item))
|
||||
return
|
||||
|
||||
if(istype(user_item, /obj/item/disk))
|
||||
if(dna_disk)
|
||||
to_chat(user, "<span class='warning'>\The [src] already has a dna disk, take it out first!</span>")
|
||||
return
|
||||
else
|
||||
O.forceMove(src)
|
||||
dna_disk = O
|
||||
to_chat(user, "<span class='notice'>You insert \the [O] into \the [src].</span>")
|
||||
user_item.forceMove(src)
|
||||
dna_disk = user_item
|
||||
to_chat(user, "<span class='notice'>You insert \the [user_item] into \the [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
return
|
||||
|
||||
/obj/machinery/limbgrower/Topic(href, href_list)
|
||||
if(..())
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/limbgrower/proc/can_be_rotated()
|
||||
if(panel_open)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/limbgrower/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if (!busy)
|
||||
if(href_list["menu"])
|
||||
screen = text2num(href_list["menu"])
|
||||
|
||||
if(href_list["category"])
|
||||
selected_category = href_list["category"]
|
||||
if (busy)
|
||||
to_chat(usr, "<span class='danger'>\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return
|
||||
|
||||
if(href_list["disposeI"]) //Get rid of a reagent incase you add the wrong one by mistake
|
||||
reagents.del_reagent(text2path(href_list["disposeI"]))
|
||||
switch(action)
|
||||
|
||||
if(href_list["make"])
|
||||
if("empty_reagent")
|
||||
reagents.del_reagent(text2path(params["reagent_type"]))
|
||||
. = TRUE
|
||||
|
||||
/////////////////
|
||||
//href protection
|
||||
being_built = stored_research.isDesignResearchedID(href_list["make"]) //check if it's a valid design
|
||||
if("eject_disk")
|
||||
eject_disk(usr)
|
||||
|
||||
if("make_limb")
|
||||
being_built = stored_research.isDesignResearchedID(params["design_id"])
|
||||
if(!being_built)
|
||||
return
|
||||
CRASH("[src] was passed an invalid design id!")
|
||||
|
||||
/// All the reagents we're using to make our organ.
|
||||
var/list/consumed_reagents_list = being_built.reagents_list.Copy()
|
||||
/// The amount of power we're going to use, based on how much reagent we use.
|
||||
var/power = 0
|
||||
|
||||
var/synth_cost = being_built.reagents_list[/datum/reagent/medicine/synthflesh]*prod_coeff
|
||||
var/power = max(2000, synth_cost/5)
|
||||
for(var/reagent_id in consumed_reagents_list)
|
||||
consumed_reagents_list[reagent_id] *= production_coefficient
|
||||
if(!reagents.has_reagent(reagent_id, consumed_reagents_list[reagent_id]))
|
||||
audible_message("<span class='notice'>\The [src] buzzes.</span>")
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
|
||||
return
|
||||
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/synthflesh, being_built.reagents_list[/datum/reagent/medicine/synthflesh]*prod_coeff))
|
||||
busy = TRUE
|
||||
use_power(power)
|
||||
flick("limbgrower_fill",src)
|
||||
icon_state = "limbgrower_idleon"
|
||||
addtimer(CALLBACK(src, .proc/build_item),32*prod_coeff)
|
||||
power = max(2000, (power + consumed_reagents_list[reagent_id]))
|
||||
|
||||
if(href_list["dna_disk"])
|
||||
var/mob/living/carbon/user = usr
|
||||
if(istype(user))
|
||||
if(!dna_disk)
|
||||
var/obj/item/disk/diskette = user.get_active_held_item()
|
||||
if(istype(diskette))
|
||||
diskette.forceMove(src)
|
||||
dna_disk = diskette
|
||||
to_chat(user, "<span class='notice'>You insert \the [diskette] into \the [src].</span>")
|
||||
else
|
||||
dna_disk.forceMove(src.loc)
|
||||
user.put_in_active_hand(dna_disk)
|
||||
to_chat(user, "<span class='notice'>You remove \the [dna_disk] from \the [src].</span>")
|
||||
dna_disk = null
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You are unable to grasp \the [dna_disk] disk from \the [src].</span>")
|
||||
else
|
||||
to_chat(usr, "<span class=\"alert\">\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
busy = TRUE
|
||||
use_power(power)
|
||||
flick("limbgrower_fill",src)
|
||||
icon_state = "limbgrower_idleon"
|
||||
selected_category = params["active_tab"]
|
||||
addtimer(CALLBACK(src, .proc/build_item, consumed_reagents_list), production_speed * production_coefficient)
|
||||
. = TRUE
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/limbgrower/proc/build_item()
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/synthflesh, being_built.reagents_list[/datum/reagent/medicine/synthflesh]*prod_coeff)) //sanity check, if this happens we are in big trouble
|
||||
reagents.remove_reagent(/datum/reagent/medicine/synthflesh, being_built.reagents_list[/datum/reagent/medicine/synthflesh]*prod_coeff)
|
||||
var/buildpath = being_built.build_path
|
||||
if(ispath(buildpath, /obj/item/bodypart)) //This feels like spaghetti code, but i need to initiliaze a limb somehow
|
||||
build_limb(buildpath)
|
||||
else if(ispath(buildpath, /obj/item/organ/genital)) //genitals are uhh... customizable
|
||||
build_genital(buildpath)
|
||||
else
|
||||
//Just build whatever it is
|
||||
new buildpath(loc)
|
||||
else
|
||||
src.visible_message("<span class=\"error\"> Something went very wrong and there isnt enough synthflesh anymore!</span>")
|
||||
busy = FALSE
|
||||
flick("limbgrower_unfill",src)
|
||||
icon_state = "limbgrower_idleoff"
|
||||
updateUsrDialog()
|
||||
/*
|
||||
* The process of beginning to build a limb or organ.
|
||||
* Goes through and sanity checks that we actually have enough reagent to build our item.
|
||||
* Then, remove those reagents from our reagents datum.
|
||||
*
|
||||
* After the reagents are handled, we can proceede with making the limb or organ. (Limbs are handled in a separate proc)
|
||||
*
|
||||
* modified_consumed_reagents_list - the list of reagents we will consume on build, modified by the production coefficient.
|
||||
*/
|
||||
/obj/machinery/limbgrower/proc/build_item(list/modified_consumed_reagents_list)
|
||||
for(var/reagent_id in modified_consumed_reagents_list)
|
||||
if(!reagents.has_reagent(reagent_id, modified_consumed_reagents_list[reagent_id]))
|
||||
audible_message("<span class='notice'>\The [src] buzzes.</span>")
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
|
||||
break
|
||||
|
||||
/obj/machinery/limbgrower/proc/build_limb(buildpath)
|
||||
reagents.remove_reagent(reagent_id, modified_consumed_reagents_list[reagent_id])
|
||||
|
||||
var/built_typepath = being_built.build_path
|
||||
// If we have a bodypart, we need to initialize the limb on its own. Otherwise we can build it here.
|
||||
if(ispath(built_typepath, /obj/item/bodypart))
|
||||
build_limb(built_typepath)
|
||||
else if(ispath(built_typepath, /obj/item/organ/genital)) //genitals are uhh... customizable
|
||||
build_genital(built_typepath)
|
||||
else
|
||||
new built_typepath(loc)
|
||||
|
||||
busy = FALSE
|
||||
flick("limbgrower_unfill", src)
|
||||
icon_state = "limbgrower_idleoff"
|
||||
|
||||
/*
|
||||
* The process of putting together a limb.
|
||||
* This is called from after we remove the reagents, so this proc is just initializing the limb type.
|
||||
*
|
||||
* This proc handles skin / mutant color, greyscaling, names and descriptions, and various other limb creation steps.
|
||||
*
|
||||
* built_typepath - the path of the bodypart we're building.
|
||||
*/
|
||||
/obj/machinery/limbgrower/proc/build_limb(built_typepath)
|
||||
//i need to create a body part manually using a set icon (otherwise it doesnt appear)
|
||||
var/obj/item/bodypart/limb
|
||||
var/datum/species/selected = stored_species[selected_category]
|
||||
limb = new buildpath(loc)
|
||||
var/datum/species/selected = GLOB.species_datums[selected_category]
|
||||
limb = new built_typepath(loc)
|
||||
limb.base_bp_icon = selected.icon_limbs || DEFAULT_BODYPART_ICON_ORGANIC
|
||||
limb.species_id = selected.limbs_id
|
||||
limb.color_src = (MUTCOLORS in selected.species_traits ? MUTCOLORS : (selected.use_skintones ? SKINTONE : FALSE))
|
||||
@@ -178,6 +248,7 @@
|
||||
limb.update_icon_dropped()
|
||||
limb.name = "\improper synthetic [lowertext(selected.name)] [limb.name]"
|
||||
limb.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]."
|
||||
limb.forcereplace = TRUE
|
||||
for(var/obj/item/bodypart/BP in limb)
|
||||
BP.base_bp_icon = selected.icon_limbs || DEFAULT_BODYPART_ICON_ORGANIC
|
||||
BP.species_id = selected.limbs_id
|
||||
@@ -188,135 +259,103 @@
|
||||
BP.name = "\improper synthetic [lowertext(selected.name)] [limb.name]"
|
||||
BP.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]."
|
||||
|
||||
/obj/machinery/limbgrower/proc/build_genital(buildpath)
|
||||
/*
|
||||
* Builds genitals, modifies to be the same
|
||||
* as the person's cloning data on the data disk
|
||||
*/
|
||||
/obj/machinery/limbgrower/proc/build_genital(built_typepath)
|
||||
//i needed to create a way to customize gene tools using dna
|
||||
var/list/features = dna_disk?.fields["features"]
|
||||
if(length(features))
|
||||
switch(buildpath)
|
||||
switch(built_typepath)
|
||||
if(/obj/item/organ/genital/penis)
|
||||
var/obj/item/organ/genital/penis/penis = new(loc)
|
||||
if(features["has_cock"])
|
||||
penis.shape = features["cock_shape"]
|
||||
penis.length = features["cock_shape"]
|
||||
penis.diameter_ratio = features["cock_diameter_ratio"]
|
||||
penis.color = sanitize_hexcolor(features["cock_color"], 6)
|
||||
penis.update_icon()
|
||||
penis.color = sanitize_hexcolor(features["cock_color"], 6, TRUE)
|
||||
penis.update()
|
||||
if(/obj/item/organ/genital/testicles)
|
||||
var/obj/item/organ/genital/testicles/balls = new(loc)
|
||||
if(features["has_balls"])
|
||||
balls.color = sanitize_hexcolor(features["balls_color"], 6)
|
||||
balls.color = sanitize_hexcolor(features["balls_color"], 6, TRUE)
|
||||
balls.shape = features["balls_shape"]
|
||||
balls.size = features["balls_size"]
|
||||
balls.fluid_rate = features["balls_cum_rate"]
|
||||
balls.fluid_mult = features["balls_cum_mult"]
|
||||
balls.fluid_efficiency = features["balls_efficiency"]
|
||||
balls.update()
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/vegana = new(loc)
|
||||
if(features["has_vagina"])
|
||||
vegana.color = sanitize_hexcolor(features["vag_color"], 6)
|
||||
if(features["has_vag"])
|
||||
vegana.color = sanitize_hexcolor(features["vag_color"], 6, TRUE)
|
||||
vegana.shape = features["vag_shape"]
|
||||
vegana.update()
|
||||
if(/obj/item/organ/genital/breasts)
|
||||
var/obj/item/organ/genital/breasts/boobs = new(loc)
|
||||
if(features["has_breasts"])
|
||||
boobs.color = sanitize_hexcolor(features["breasts_color"], 6)
|
||||
boobs.color = sanitize_hexcolor(features["breasts_color"], 6, TRUE)
|
||||
boobs.size = features["breasts_size"]
|
||||
boobs.shape = features["breasts_shape"]
|
||||
if(!features["breasts_producing"])
|
||||
boobs.genital_flags &= ~(GENITAL_FUID_PRODUCTION|CAN_CLIMAX_WITH|CAN_MASTURBATE_WITH)
|
||||
boobs.update()
|
||||
else
|
||||
new buildpath(loc)
|
||||
new built_typepath(loc)
|
||||
else
|
||||
new buildpath(loc)
|
||||
new built_typepath(loc)
|
||||
|
||||
/obj/machinery/limbgrower/RefreshParts()
|
||||
reagents.maximum_volume = 0
|
||||
for(var/obj/item/reagent_containers/glass/G in component_parts)
|
||||
reagents.maximum_volume += G.volume
|
||||
G.reagents.trans_to(src, G.reagents.total_volume)
|
||||
var/T=1.2
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
T -= M.rating*0.2
|
||||
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
|
||||
for(var/obj/item/reagent_containers/glass/our_beaker in component_parts)
|
||||
reagents.maximum_volume += our_beaker.volume
|
||||
our_beaker.reagents.trans_to(src, our_beaker.reagents.total_volume)
|
||||
production_coefficient = 1.2
|
||||
for(var/obj/item/stock_parts/manipulator/our_manipulator in component_parts)
|
||||
production_coefficient -= our_manipulator.rating * 0.2
|
||||
production_coefficient = clamp(production_coefficient, 0, 1) // coefficient goes from 1 -> 0.8 -> 0.6 -> 0.4
|
||||
|
||||
/obj/machinery/limbgrower/examine(mob/user)
|
||||
. = ..()
|
||||
if(!panel_open)
|
||||
. += "<span class='notice'>It looks like as if the panel were open you could rotate it with a <b>wrench</b>.</span>"
|
||||
else
|
||||
. += "<span class='notice'>The panel is open.</span>"
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += "<span class='notice'>The status display reads: Storing up to <b>[reagents.maximum_volume]u</b> of synthflesh.<br>Synthflesh consumption at <b>[prod_coeff*100]%</b>.<span>"
|
||||
. += "<span class='notice'>The status display reads: Storing up to <b>[reagents.maximum_volume]u</b> of reagents.<br>Reagent consumption rate at <b>[production_coefficient * 100]%</b>.</span>"
|
||||
|
||||
/obj/machinery/limbgrower/proc/main_win(mob/user)
|
||||
var/dat = "<div class='statusDisplay'><h3>[src] Menu:</h3><br>"
|
||||
dat += "<A href='?src=[REF(src)];dna_disk=1'>[dna_disk ? "Remove" : "Insert"] cloning data disk</A>"
|
||||
dat += "<hr>"
|
||||
dat += "<A href='?src=[REF(src)];menu=[LIMBGROWER_CHEMICAL_MENU]'>Chemical Storage</A>"
|
||||
dat += materials_printout()
|
||||
dat += "<table style='width:100%' align='center'><tr>"
|
||||
|
||||
for(var/C in categories)
|
||||
dat += "<td><A href='?src=[REF(src)];category=[C];menu=[LIMBGROWER_CATEGORY_MENU]'>[C]</A></td>"
|
||||
dat += "</tr><tr>"
|
||||
//one category per line
|
||||
|
||||
dat += "</tr></table></div>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/limbgrower/proc/category_win(mob/user,selected_category)
|
||||
var/dat = "<A href='?src=[REF(src)];menu=[LIMBGROWER_MAIN_MENU]'>Return to main menu</A>"
|
||||
dat += "<div class='statusDisplay'><h3>Browsing [selected_category]:</h3><br>"
|
||||
dat += materials_printout()
|
||||
|
||||
for(var/v in stored_research.researched_designs)
|
||||
var/datum/design/D = SSresearch.techweb_design_by_id(v)
|
||||
if(!(selected_category in D.category))
|
||||
continue
|
||||
if(disabled || !can_build(D))
|
||||
dat += "<span class='linkOff'>[D.name]</span>"
|
||||
else
|
||||
dat += "<a href='?src=[REF(src)];make=[D.id];multiplier=1'>[D.name]</a>"
|
||||
dat += "[get_design_cost(D)]<br>"
|
||||
|
||||
dat += "</div>"
|
||||
return dat
|
||||
|
||||
|
||||
/obj/machinery/limbgrower/proc/chemical_win(mob/user)
|
||||
var/dat = "<A href='?src=[REF(src)];menu=[LIMBGROWER_MAIN_MENU]'>Return to main menu</A>"
|
||||
dat += "<div class='statusDisplay'><h3>Browsing Chemical Storage:</h3><br>"
|
||||
dat += materials_printout()
|
||||
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
dat += "[R.name]: [R.volume]"
|
||||
dat += "<A href='?src=[REF(src)];disposeI=[R]'>Purge</A><BR>"
|
||||
|
||||
dat += "</div>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/limbgrower/proc/materials_printout()
|
||||
var/dat = "<b>Total amount:></b> [reagents.total_volume] / [reagents.maximum_volume] cm<sup>3</sup><br>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/limbgrower/proc/can_build(datum/design/D)
|
||||
return (reagents.has_reagent(/datum/reagent/medicine/synthflesh, D.reagents_list[/datum/reagent/medicine/synthflesh]*prod_coeff)) //Return whether the machine has enough synthflesh to produce the design
|
||||
|
||||
/obj/machinery/limbgrower/proc/get_design_cost(datum/design/D)
|
||||
var/dat
|
||||
if(D.reagents_list[/datum/reagent/medicine/synthflesh])
|
||||
dat += "[D.reagents_list[/datum/reagent/medicine/synthflesh] * prod_coeff] Synthetic flesh "
|
||||
return dat
|
||||
/*
|
||||
* Checks our reagent list to see if a design can be built.
|
||||
*
|
||||
* limb_design - the design we're checking for buildability.
|
||||
*
|
||||
* returns TRUE if we have enough reagent to build it. Returns FALSE if we do not.
|
||||
*/
|
||||
/obj/machinery/limbgrower/proc/can_build(datum/design/limb_design)
|
||||
for(var/datum/reagent/reagent_id in limb_design.reagents_list)
|
||||
if(!reagents.has_reagent(reagent_id, limb_design.reagents_list[reagent_id] * production_coefficient))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Emagging a limbgrower allows you to build synthetic armblades.
|
||||
/obj/machinery/limbgrower/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
for(var/id in SSresearch.techweb_designs)
|
||||
var/datum/design/D = SSresearch.techweb_design_by_id(id)
|
||||
if((D.build_type & LIMBGROWER) && ("emagged" in D.category))
|
||||
stored_research.add_design(D)
|
||||
for(var/design_id in SSresearch.techweb_designs)
|
||||
var/datum/design/found_design = SSresearch.techweb_design_by_id(design_id)
|
||||
if((found_design.build_type & LIMBGROWER) && ("emagged" in found_design.category))
|
||||
stored_research.add_design(found_design)
|
||||
to_chat(user, "<span class='warning'>A warning flashes onto the screen, stating that safety overrides have been deactivated!</span>")
|
||||
obj_flags |= EMAGGED
|
||||
return TRUE
|
||||
update_static_data(user)
|
||||
|
||||
/obj/machinery/limbgrower/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
eject_disk(user)
|
||||
|
||||
/obj/machinery/limbgrower/proc/eject_disk(mob/user)
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
if(busy)
|
||||
to_chat(user, "<span class=\"alert\">\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
@@ -325,6 +364,7 @@
|
||||
dna_disk.forceMove(src.loc)
|
||||
user.put_in_active_hand(dna_disk)
|
||||
to_chat(user, "<span class='notice'>You remove \the [dna_disk] from \the [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
dna_disk = null
|
||||
else
|
||||
to_chat(user, "<span class='warning'>\The [src] has doesn't have a disk on it!")
|
||||
|
||||
@@ -21,6 +21,7 @@ Buildable meters
|
||||
level = 2
|
||||
var/piping_layer = PIPING_LAYER_DEFAULT
|
||||
var/RPD_type
|
||||
var/disposable = TRUE
|
||||
|
||||
/obj/item/pipe/directional
|
||||
RPD_type = PIPE_UNARY
|
||||
@@ -236,3 +237,22 @@ Buildable meters
|
||||
/obj/item/pipe_meter/proc/setAttachLayer(new_layer = PIPING_LAYER_DEFAULT)
|
||||
piping_layer = new_layer
|
||||
PIPING_LAYER_DOUBLE_SHIFT(src, piping_layer)
|
||||
|
||||
/obj/item/pipe/bluespace
|
||||
pipe_type = /obj/machinery/atmospherics/pipe/bluespace
|
||||
var/bluespace_network_name = "default"
|
||||
icon_state = "bluespace"
|
||||
disposable = FALSE
|
||||
|
||||
/obj/item/pipe/bluespace/attack_self(mob/user)
|
||||
var/new_name = input(user, "Enter identifier for bluespace pipe network", "bluespace pipe", bluespace_network_name) as text|null
|
||||
if(!isnull(new_name))
|
||||
bluespace_network_name = new_name
|
||||
|
||||
/obj/item/pipe/bluespace/make_from_existing(obj/machinery/atmospherics/pipe/bluespace/make_from)
|
||||
bluespace_network_name = make_from.bluespace_network_name
|
||||
return ..()
|
||||
|
||||
/obj/item/pipe/bluespace/build_pipe(obj/machinery/atmospherics/pipe/bluespace/A)
|
||||
A.bluespace_network_name = bluespace_network_name
|
||||
return ..()
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
if (. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(get_charge())
|
||||
use_power(cell.charge*severity/100)
|
||||
use_power((cell.charge/3)*(severity*0.005))
|
||||
take_damage(severity/3, BURN, "energy", 1)
|
||||
mecha_log_message("EMP detected", color="red")
|
||||
|
||||
|
||||
@@ -375,12 +375,14 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
|
||||
. = TRUE
|
||||
|
||||
if((mode & DESTROY_MODE) && istype(A, /obj/item/pipe) || istype(A, /obj/structure/disposalconstruct) || istype(A, /obj/structure/c_transit_tube) || istype(A, /obj/structure/c_transit_tube_pod) || istype(A, /obj/item/pipe_meter))
|
||||
to_chat(user, "<span class='notice'>You start destroying a pipe...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, destroy_speed, target = A))
|
||||
activate()
|
||||
qdel(A)
|
||||
return
|
||||
var/obj/item/pipe/P = A
|
||||
if(!istype(P) || P.disposable)
|
||||
to_chat(user, "<span class='notice'>You start destroying a pipe...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, destroy_speed, target = A))
|
||||
activate()
|
||||
qdel(A)
|
||||
return
|
||||
|
||||
if((mode & PAINT_MODE))
|
||||
if(istype(A, /obj/machinery/atmospherics/pipe) && !istype(A, /obj/machinery/atmospherics/pipe/layer_manifold))
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
to_chat(user, "<span class='notice'>You need to get closer!</span>")
|
||||
return
|
||||
if(use_paint(user) && isturf(F))
|
||||
F.AddElement(/datum/element/decal, 'icons/turf/decals.dmi', stored_decal_total, turn(stored_dir, -dir2angle(F.dir)), CLEAN_STRONG, color, null, null, alpha)
|
||||
F.AddElement(/datum/element/decal, 'icons/turf/decals.dmi', stored_decal_total, stored_dir, CLEAN_STRONG, color, null, null, alpha)
|
||||
|
||||
/obj/item/airlock_painter/decal/attack_self(mob/user)
|
||||
if((ink) && (ink.charges >= 1))
|
||||
@@ -180,6 +180,11 @@
|
||||
stored_decal_total = "[stored_decal][yellow_fix][stored_color]"
|
||||
return
|
||||
|
||||
/obj/item/airlock_painter/decal/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/decals)
|
||||
)
|
||||
|
||||
/obj/item/airlock_painter/decal/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -189,6 +194,7 @@
|
||||
/obj/item/airlock_painter/decal/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["decal_direction"] = stored_dir
|
||||
data["decal_dir_text"] = dir2text(stored_dir)
|
||||
data["decal_color"] = stored_color
|
||||
data["decal_style"] = stored_decal
|
||||
data["decal_list"] = list()
|
||||
|
||||
@@ -75,18 +75,3 @@
|
||||
desc = "A chromosome that reduces action based mutation cooldowns by by 50%."
|
||||
icon_state = "energy"
|
||||
energy_coeff = 0.5
|
||||
|
||||
/obj/item/chromosome/reinforcer
|
||||
name = "reinforcement chromosome"
|
||||
desc = "A chromosome that renders mutations immune to mutadone."
|
||||
icon_state = "reinforcer"
|
||||
weight = 3
|
||||
|
||||
/obj/item/chromosome/reinforcer/can_apply(datum/mutation/human/HM)
|
||||
if(!HM || !(HM.can_chromosome == CHROMOSOME_NONE))
|
||||
return FALSE
|
||||
return !HM.mutadone_proof
|
||||
|
||||
/obj/item/chromosome/reinforcer/apply(datum/mutation/human/HM)
|
||||
HM.mutadone_proof = TRUE
|
||||
..()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user