diff --git a/.travis.yml b/.travis.yml index f26102a3b3..bfb37118dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,44 @@ #pretending we're C because otherwise ruby will initialize, even with "language: dm". language: c +sudo: false env: - BYOND_MAJOR="508" - BYOND_MINOR="1287" + BYOND_MAJOR="510" + BYOND_MINOR="1346" + MACRO_COUNT=987 -before_install: - - sudo apt-get update -qq - - sudo apt-get install libc6:i386 libgcc1:i386 libstdc++6:i386 -qq - - sudo apt-get install python -qq - - sudo apt-get install python-pip -qq - - sudo pip install PyYaml -q - - sudo pip install beautifulsoup4 -q +cache: + directories: + - $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR} + +addons: + apt: + packages: + - libc6-i386 + - libgcc1:i386 + - libstdc++6:i386 + +before_script: + - chmod +x ./install-byond.sh + - ./install-byond.sh install: - - curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip - - unzip byond.zip - - cd byond - - sudo make install - - cd .. + - pip install --user PyYaml -q + - pip install --user beautifulsoup4 -q script: - shopt -s globstar - (! grep 'step_[xy]' maps/**/*.dmm) - (! find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano) - - (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; [ $num -le 1355 ]) + - (! grep -En "<\s*span\s+class\s*=\s*('[^'>]+|[^'>]+')\s*>" **/*.dm) + - awk -f tools/indentation.awk **/*.dm + - md5sum -c - <<< "88490b460c26947f5ec1ab1bb9fa9f17 *html/changelogs/example.yml" + - (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ]) + - source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup + - python tools/TagMatcher/tag-matcher.py ../.. + - echo "#define UNIT_TEST 1" > code/_unit_tests.dm + - cp config/example/* config/ - DreamMaker polaris.dme + - DreamDaemon polaris.dmb -invisible -trusted -core 2>&1 | tee log.txt + - grep "All Unit Tests Passed" log.txt + diff --git a/btime.dll b/btime.dll new file mode 100644 index 0000000000..af6c82a998 Binary files /dev/null and b/btime.dll differ diff --git a/btime.so b/btime.so new file mode 100644 index 0000000000..edb3cc3113 Binary files /dev/null and b/btime.so differ diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm index 9fcdad8613..11777e51d2 100644 --- a/code/ATMOSPHERICS/components/unary/cold_sink.dm +++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm @@ -10,6 +10,7 @@ anchored = 1 use_power = 0 idle_power_usage = 5 // 5 Watts for thermostat related circuitry + circuit = /obj/item/weapon/circuitboard/unary_atmos/cooler var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something. var/internal_volume = 600 // L @@ -23,8 +24,8 @@ /obj/machinery/atmospherics/unary/freezer/New() ..() initialize_directions = dir + circuit = new circuit(src) component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/unary_atmos/cooler(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm index e139f6faf3..8ee9600606 100644 --- a/code/ATMOSPHERICS/components/unary/heat_source.dm +++ b/code/ATMOSPHERICS/components/unary/heat_source.dm @@ -10,6 +10,7 @@ anchored = 1 use_power = 0 idle_power_usage = 5 //5 Watts for thermostat related circuitry + circuit = /obj/item/weapon/circuitboard/unary_atmos/heater var/max_temperature = T20C + 680 var/internal_volume = 600 //L @@ -23,9 +24,8 @@ /obj/machinery/atmospherics/unary/heater/New() ..() initialize_directions = dir - + circuit = new circuit(src) component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/unary_atmos/heater(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) diff --git a/code/ATMOSPHERICS/mainspipe.dm b/code/ATMOSPHERICS/mainspipe.dm index 520d7a55b2..a2976974bf 100644 --- a/code/ATMOSPHERICS/mainspipe.dm +++ b/code/ATMOSPHERICS/mainspipe.dm @@ -36,8 +36,6 @@ obj/machinery/atmospherics/mains_pipe icon = 'icons/obj/atmospherics/mainspipe.dmi' layer = 2.4 //under wires with their 2.5 - force = 20 - var/volume = 0 var/alert_pressure = 80*ONE_ATMOSPHERE diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 6f70f822ad..c445988c53 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -3,7 +3,6 @@ var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke var/datum/pipeline/parent var/volume = 0 - force = 20 layer = 2.4 //under wires with their 2.44 use_power = 0 diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 8831f8aa40..01a84fdf5d 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -43,7 +43,7 @@ mob/check_airflow_movable(n) return 0 return 1 -mob/dead/observer/check_airflow_movable() +mob/observer/check_airflow_movable() return 0 mob/living/silicon/check_airflow_movable() @@ -247,6 +247,6 @@ zone/proc/movables() . = list() for(var/turf/T in contents) for(var/atom/movable/A in T) - if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/eye)) + if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/observer)) continue . += A diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 7222470f71..bb4ec95a84 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -406,7 +406,7 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs) //Get heat transfer coefficients for clothing. for(var/obj/item/clothing/C in src) - if(l_hand == C || r_hand == C) + if(item_is_in_hands(C)) continue if( C.max_heat_protection_temperature >= last_temperature ) diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index 7e91a26b3f..2bfbed9681 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -348,7 +348,7 @@ var/global/vs_control/vsc = new else if(istext(vars["[V]_RANDOM"])) var/txt = vars["[V]_RANDOM"] if(findtextEx(txt,"PROB")) - txt = text2list(txt,"/") + txt = splittext(txt,"/") txt[1] = replacetext(txt[1],"PROB","") var/p = text2num(txt[1]) var/r = txt[2] @@ -358,7 +358,7 @@ var/global/vs_control/vsc = new newvalue = vars[V] else if(findtextEx(txt,"PICK")) txt = replacetext(txt,"PICK","") - txt = text2list(txt,",") + txt = splittext(txt,",") newvalue = pick(txt) else newvalue = roll(txt) diff --git a/code/__defines/appearance.dm b/code/__defines/appearance.dm new file mode 100644 index 0000000000..faa97e8f06 --- /dev/null +++ b/code/__defines/appearance.dm @@ -0,0 +1,3 @@ +// Consider these images/atoms as part of the UI/HUD +#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA +#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR diff --git a/code/__defines/btime.dm b/code/__defines/btime.dm new file mode 100644 index 0000000000..d4cefc3524 --- /dev/null +++ b/code/__defines/btime.dm @@ -0,0 +1,18 @@ +// Comment this out if the external btime library is unavailable +#define PRECISE_TIMER_AVAILABLE + +#ifdef PRECISE_TIMER_AVAILABLE +var/global/__btime__libName = "btime.[world.system_type==MS_WINDOWS?"dll":"so"]" +#define TimeOfHour (__extern__timeofhour) +#define __extern__timeofhour text2num(call(__btime__libName, "gettime")()) +/hook/startup/proc/checkbtime() + try + // This will always return 1 unless the btime library cannot be accessed + if(TimeOfHour || 1) return 1 + catch(var/exception/e) + log_to_dd("PRECISE_TIMER_AVAILABLE is defined in btime.dm, but calling the btime library failed: [e]") + log_to_dd("This is a fatal error. The world will now shut down.") + del(world) +#else +#define TimeOfHour (world.timeofday % 36000) +#endif \ No newline at end of file diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm index 4fbdebf6f1..31f0233b23 100644 --- a/code/__defines/chemistry.dm +++ b/code/__defines/chemistry.dm @@ -24,6 +24,7 @@ #define IS_TAJARA 5 #define IS_XENOS 6 #define IS_TESHARI 7 +#define IS_SLIME 8 #define CE_STABLE "stable" // Inaprovaline #define CE_ANTIBIOTIC "antibiotic" // Spaceacilin diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index 09931cb622..124be53452 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -9,6 +9,7 @@ #define CUT "cut" #define BRUISE "bruise" +#define PIERCE "pierce" #define STUN "stun" #define WEAKEN "weaken" @@ -34,18 +35,20 @@ #define ORGAN_BLEEDING (1<<1) #define ORGAN_BROKEN (1<<2) #define ORGAN_DESTROYED (1<<3) -#define ORGAN_ROBOT (1<<4) -#define ORGAN_SPLINTED (1<<5) -#define ORGAN_DEAD (1<<6) -#define ORGAN_MUTATED (1<<7) -#define ORGAN_ASSISTED (1<<8) +#define ORGAN_SPLINTED (1<<4) +#define ORGAN_DEAD (1<<5) +#define ORGAN_MUTATED (1<<6) #define DROPLIMB_EDGE 0 #define DROPLIMB_BLUNT 1 #define DROPLIMB_BURN 2 // Damage above this value must be repaired with surgery. -#define ROBOLIMB_SELF_REPAIR_CAP 30 +#define ROBOLIMB_REPAIR_CAP 30 + +#define ORGAN_ASSISTED 1 // Like pacemakers, not robotic +#define ORGAN_ROBOT 2 // Fully robotic, no organic parts +#define ORGAN_LIFELIKE 3 // Robotic, made to appear organic //Germs and infections. #define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still. diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm index 4808926bb2..22b0b7ab62 100644 --- a/code/__defines/gamemode.dm +++ b/code/__defines/gamemode.dm @@ -18,7 +18,7 @@ #define BE_ALIEN 0x40 #define BE_AI 0x80 #define BE_CULTIST 0x100 -#define BE_MONKEY 0x200 +#define BE_RENEGADE 0x200 #define BE_NINJA 0x400 #define BE_RAIDER 0x800 #define BE_PLANT 0x1000 @@ -37,7 +37,7 @@ var/list/be_special_flags = list( "Xenomorph" = BE_ALIEN, "Positronic Brain" = BE_AI, "Cultist" = BE_CULTIST, - "Monkey" = BE_MONKEY, + "Renegade" = BE_RENEGADE, "Ninja" = BE_NINJA, "Raider" = BE_RAIDER, "Diona" = BE_PLANT, @@ -82,6 +82,7 @@ var/list/be_special_flags = list( #define MODE_LOYALIST "loyalist" #define MODE_MALFUNCTION "malf" #define MODE_TRAITOR "traitor" +#define MODE_AUTOTRAITOR "autotraitor" #define DEFAULT_TELECRYSTAL_AMOUNT 12 diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm index eaa0b7d2a9..cc77b8c3c5 100644 --- a/code/__defines/machinery.dm +++ b/code/__defines/machinery.dm @@ -27,21 +27,21 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define AI_CAMERA_LUMINOSITY 6 // Camera networks -#define NETWORK_CRESCENT "Crescent" -#define NETWORK_CAFE_DOCK "Cafe Dock" +#define NETWORK_CRESCENT "Spaceport" +// #define NETWORK_CAFE_DOCK "Cafe Dock" #define NETWORK_CARGO "Cargo" #define NETWORK_CIVILIAN "Civilian" -#define NETWORK_CIVILIAN_EAST "Civilian East" -#define NETWORK_CIVILIAN_WEST "Civilian West" +// #define NETWORK_CIVILIAN_EAST "Civilian East" +// #define NETWORK_CIVILIAN_WEST "Civilian West" #define NETWORK_COMMAND "Command" #define NETWORK_ENGINE "Engine" #define NETWORK_ENGINEERING "Engineering" #define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost" #define NETWORK_ERT "ZeEmergencyResponseTeam" -#define NETWORK_EXODUS "Northern Star" +#define NETWORK_EXODUS station_short #define NETWORK_MEDICAL "Medical" #define NETWORK_MERCENARY "MercurialNet" -#define NETWORK_MINE "MINE" +#define NETWORK_MINE "Mining Outpost" #define NETWORK_NORTHERN_STAR "Northern Star" #define NETWORK_RESEARCH "Research" #define NETWORK_RESEARCH_OUTPOST "Research Outpost" @@ -50,6 +50,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define NETWORK_SECURITY "Security" #define NETWORK_TELECOM "Tcomsat" #define NETWORK_THUNDER "Thunderdome" +#define NETWORK_COMMUNICATORS "Communicators" // Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them. var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret") diff --git a/code/__defines/math_physics.dm b/code/__defines/math_physics.dm index 987cb1ba9d..198f87eccc 100644 --- a/code/__defines/math_physics.dm +++ b/code/__defines/math_physics.dm @@ -15,9 +15,10 @@ #define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio. #define HUMAN_EXPOSED_SURFACE_AREA 5.2 //m^2, surface area of 1.7m (H) x 0.46m (D) cylinder -#define T0C 273.15 // 0.0 degrees celcius -#define T20C 293.15 // 20.0 degrees celcius -#define TCMB 2.7 // -270.3 degrees celcius +#define T0C 273.15 // 0.0 degrees celcius +#define T20C 293.15 // 20.0 degrees celcius +#define TCMB 2.7 // -270.3 degrees celcius +#define TN60C 213.15 // -60 degrees celcius #define CLAMP01(x) max(0, min(1, x)) #define QUANTIZE(variable) (round(variable,0.0001)) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 9741282f93..0a06743993 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -23,27 +23,7 @@ // Some arbitrary defines to be used by self-pruning global lists. (see master_controller) #define PROCESS_KILL 26 // Used to trigger removal from a processing list. -#define MAX_GEAR_COST 10 // Used in chargen for accessory loadout limit. - -// Preference toggles. -#define SOUND_ADMINHELP 0x1 -#define SOUND_MIDI 0x2 -#define SOUND_AMBIENCE 0x4 -#define SOUND_LOBBY 0x8 -#define CHAT_OOC 0x10 -#define CHAT_DEAD 0x20 -#define CHAT_GHOSTEARS 0x40 -#define CHAT_GHOSTSIGHT 0x80 -#define CHAT_PRAYER 0x100 -#define CHAT_RADIO 0x200 -#define CHAT_ATTACKLOGS 0x400 -#define CHAT_DEBUGLOGS 0x800 -#define CHAT_LOOC 0x1000 -#define CHAT_GHOSTRADIO 0x2000 -#define SHOW_TYPING 0x4000 -#define CHAT_NOICONS 0x8000 - -#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC) +#define MAX_GEAR_COST 15 // Used in chargen for accessory loadout limit. // For secHUDs and medHUDs and variants. The number is the location of the image on the list hud_list of humans. #define HEALTH_HUD 1 // A simple line rounding the mob's number health. @@ -58,24 +38,37 @@ #define LIFE_HUD 10 // STATUS_HUD that only reports dead or alive //some colors -#define COLOR_WHITE "#FFFFFF" -#define COLOR_SILVER "#C0C0C0" -#define COLOR_GRAY "#808080" -#define COLOR_BLACK "#000000" -#define COLOR_RED "#FF0000" -#define COLOR_MAROON "#800000" -#define COLOR_YELLOW "#FFFF00" -#define COLOR_OLIVE "#808000" -#define COLOR_LIME "#00FF00" -#define COLOR_GREEN "#008000" -#define COLOR_CYAN "#00FFFF" -#define COLOR_TEAL "#008080" -#define COLOR_BLUE "#0000FF" -#define COLOR_NAVY "#000080" -#define COLOR_PINK "#FF00FF" -#define COLOR_PURPLE "#800080" -#define COLOR_ORANGE "#FF9900" -#define COLOR_LUMINOL "#66FFFF" +#define COLOR_WHITE "#FFFFFF" +#define COLOR_SILVER "#C0C0C0" +#define COLOR_GRAY "#808080" +#define COLOR_BLACK "#000000" +#define COLOR_RED "#FF0000" +#define COLOR_MAROON "#800000" +#define COLOR_YELLOW "#FFFF00" +#define COLOR_OLIVE "#808000" +#define COLOR_LIME "#00FF00" +#define COLOR_GREEN "#008000" +#define COLOR_CYAN "#00FFFF" +#define COLOR_TEAL "#008080" +#define COLOR_BLUE "#0000FF" +#define COLOR_NAVY "#000080" +#define COLOR_PINK "#FF00FF" +#define COLOR_PURPLE "#800080" +#define COLOR_ORANGE "#FF9900" +#define COLOR_LUMINOL "#66FFFF" +#define COLOR_BEIGE "#CEB689" +#define COLOR_BLUE_GRAY "#6A97B0" +#define COLOR_BROWN "#B19664" +#define COLOR_DARK_BROWN "#917448" +#define COLOR_DARK_ORANGE "#B95A00" +#define COLOR_GREEN_GRAY "#8DAF6A" +#define COLOR_RED_GRAY "#AA5F61" +#define COLOR_PALE_BLUE_GRAY "#8BBBD5" +#define COLOR_PALE_GREEN_GRAY "#AED18B" +#define COLOR_PALE_RED_GRAY "#CC9090" +#define COLOR_PALE_PURPLE_GRAY "#BDA2BA" +#define COLOR_PURPLE_GRAY "#A2819E" + // Shuttles. // These define the time taken for the shuttle to get to the space station, and the time before it leaves again. @@ -98,10 +91,10 @@ // Setting this much higher than 1024 could allow spammers to DOS the server easily. #define MAX_MESSAGE_LEN 1024 -#define MAX_PAPER_MESSAGE_LEN 3072 -#define MAX_BOOK_MESSAGE_LEN 9216 +#define MAX_PAPER_MESSAGE_LEN 6144 +#define MAX_BOOK_MESSAGE_LEN 12288 #define MAX_LNAME_LEN 64 -#define MAX_NAME_LEN 26 +#define MAX_NAME_LEN 52 // Event defines. #define EVENT_LEVEL_MUNDANE 1 @@ -163,19 +156,6 @@ #define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act() #define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs. -// Custom colors -#define COLOR_BEIGE "#CEB689" -#define COLOR_BLUE_GRAY "#6A97B0" -#define COLOR_BROWN "#B19664" -#define COLOR_DARK_BROWN "#917448" -#define COLOR_DARK_ORANGE "#B95A00" -#define COLOR_GREEN_GRAY "#8DAF6A" -#define COLOR_RED_GRAY "#AA5F61" -#define COLOR_PALE_BLUE_GRAY "#8BBBD5" -#define COLOR_PALE_GREEN_GRAY "#AED18B" -#define COLOR_PALE_RED_GRAY "#CC9090" -#define COLOR_PALE_PURPLE_GRAY "#BDA2BA" -#define COLOR_PURPLE_GRAY "#A2819E" // Vending stuff #define CAT_NORMAL 1 diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 98ad3b28ca..68b313d9a1 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -13,7 +13,6 @@ #define GODMODE 0x1000 #define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath. #define DISFIGURED 0x4000 // Set but never checked. Remove this sometime and replace occurences with the appropriate organ code -#define XENO_HOST 0x8000 // Tracks whether we're gonna be a baby alien's mummy. // Grab levels. #define GRAB_PASSIVE 1 @@ -27,11 +26,11 @@ #define BORGXRAY 0x4 #define BORGMATERIAL 8 -#define HOSTILE_STANCE_IDLE 1 -#define HOSTILE_STANCE_ALERT 2 -#define HOSTILE_STANCE_ATTACK 3 -#define HOSTILE_STANCE_ATTACKING 4 -#define HOSTILE_STANCE_TIRED 5 +#define STANCE_IDLE 1 +#define STANCE_ALERT 2 +#define STANCE_ATTACK 3 +#define STANCE_ATTACKING 4 +#define STANCE_TIRED 5 #define LEFT 1 #define RIGHT 2 @@ -136,9 +135,15 @@ #define INCAPACITATION_RESTRAINED 1 #define INCAPACITATION_BUCKLED_PARTIALLY 2 #define INCAPACITATION_BUCKLED_FULLY 4 +#define INCAPACITATION_STUNNED 8 +#define INCAPACITATION_FORCELYING 16 //needs a better name - represents being knocked down BUT still conscious. +#define INCAPACITATION_KNOCKOUT 32 + #define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY) -#define INCAPACITATION_ALL (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY) +#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING) +#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED) +#define INCAPACITATION_ALL (~INCAPACITATION_NONE) // Bodyparts and organs. #define O_MOUTH "mouth" @@ -180,4 +185,9 @@ #define MOB_PULL_NONE 0 #define MOB_PULL_SMALLER 1 #define MOB_PULL_SAME 2 -#define MOB_PULL_LARGER 3 \ No newline at end of file +#define MOB_PULL_LARGER 3 + +//XENOBIO2 FLAGS +#define NOMUT 0 +#define COLORMUT 1 +#define SPECIESMUT 2 diff --git a/code/controllers/ProcessScheduler/core/_define.dm b/code/__defines/process_scheduler.dm similarity index 66% rename from code/controllers/ProcessScheduler/core/_define.dm rename to code/__defines/process_scheduler.dm index f0165c9870..76449b9a4b 100644 --- a/code/controllers/ProcessScheduler/core/_define.dm +++ b/code/__defines/process_scheduler.dm @@ -11,7 +11,10 @@ #define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds #define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds #define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks -#define PROCESS_DEFAULT_SLEEP_INTERVAL 2 // 2 ticks +#define PROCESS_DEFAULT_SLEEP_INTERVAL 8 // 2 ticks #define PROCESS_DEFAULT_CPU_THRESHOLD 90 // 90% -//#define UPDATE_QUEUE_DEBUG \ No newline at end of file +// SCHECK macros +// This references src directly to work around a weird bug with try/catch +#define SCHECK_EVERY(this_many_calls) if(++src.calls_since_last_scheck >= this_many_calls) sleepCheck() +#define SCHECK SCHECK_EVERY(50) \ No newline at end of file diff --git a/code/__defines/research.dm b/code/__defines/research.dm index d40722d0cf..9c3bec3066 100644 --- a/code/__defines/research.dm +++ b/code/__defines/research.dm @@ -12,7 +12,8 @@ #define TECH_ILLEGAL "syndicate" #define TECH_ARCANE "arcane" -#define IMPRINTER 0x1 //For circuits. Uses glass/chemicals. -#define PROTOLATHE 0x2 //New stuff. Uses glass/metal/chemicals -#define MECHFAB 0x4 //Mechfab -#define CHASSIS 0x8 //For protolathe, but differently +#define IMPRINTER 0x0001 //For circuits. Uses glass/chemicals. +#define PROTOLATHE 0x0002 //New stuff. Uses glass/metal/chemicals +#define MECHFAB 0x0004 //Mechfab +#define CHASSIS 0x0008 //For protolathe, but differently +#define PROSFAB 0x0010 //For prosthetics fab \ No newline at end of file diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index 2dec4406a4..143c7aa251 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -8,9 +8,9 @@ // unused: 0x8000 - higher than this will overflow // Species spawn flags -#define IS_WHITELISTED 0x1 // Must be whitelisted to play. -#define CAN_JOIN 0x2 // Species is selectable in chargen. -#define IS_RESTRICTED 0x4 // Is not a core/normally playable species. (castes, mutantraces) +#define SPECIES_IS_WHITELISTED 0x1 // Must be whitelisted to play. +#define SPECIES_IS_RESTRICTED 0x2 // Is not a core/normally playable species. (castes, mutantraces) +#define SPECIES_CAN_JOIN 0x4 // Species is selectable in chargen. // Species appearance flags #define HAS_SKIN_TONE 0x1 // Skin tone selectable in chargen. (0-255) @@ -19,6 +19,7 @@ #define HAS_UNDERWEAR 0x8 // Underwear is drawn onto the mob icon. #define HAS_EYE_COLOR 0x10 // Eye colour selectable in chargen. (RGB) #define HAS_HAIR_COLOR 0x20 // Hair colour selectable in chargen. (RGB) +#define RADIATION_GLOWS 0x40 // Radiation causes this character to glow. // Languages. #define LANGUAGE_SOL_COMMON "Sol Common" @@ -29,6 +30,8 @@ #define LANGUAGE_ROOTSPEAK "Rootspeak" #define LANGUAGE_TRADEBAND "Tradeband" #define LANGUAGE_GUTTER "Gutter" +#define LANGUAGE_SCHECHI "Schechi" +#define LANGUAGE_CULT "Cult" // Language flags. #define WHITELISTED 1 // Language is available if the speaker is whitelisted. diff --git a/code/__defines/unit_tests.dm b/code/__defines/unit_tests.dm new file mode 100644 index 0000000000..478c75fdb2 --- /dev/null +++ b/code/__defines/unit_tests.dm @@ -0,0 +1,4 @@ +#define ASCII_ESC ascii2text(27) +#define ASCII_RED "[ASCII_ESC]\[31m" +#define ASCII_GREEN "[ASCII_ESC]\[32m" +#define ASCII_RESET "[ASCII_ESC]\[0m" \ No newline at end of file diff --git a/code/modules/nano/JSON Reader.dm b/code/_compatibility/509/JSON Reader.dm similarity index 98% rename from code/modules/nano/JSON Reader.dm rename to code/_compatibility/509/JSON Reader.dm index 12edf1dd5c..544d197ccd 100644 --- a/code/modules/nano/JSON Reader.dm +++ b/code/_compatibility/509/JSON Reader.dm @@ -1,3 +1,5 @@ +#if DM_VERSION < 510 + json_token var value @@ -202,4 +204,6 @@ json_reader die(json_token/T) if(!T) T = get_token() - CRASH("Unexpected token: [T.value].") \ No newline at end of file + CRASH("Unexpected token: [T.value].") + +#endif \ No newline at end of file diff --git a/code/modules/nano/JSON Writer.dm b/code/_compatibility/509/JSON Writer.dm similarity index 97% rename from code/modules/nano/JSON Writer.dm rename to code/_compatibility/509/JSON Writer.dm index 97acc0b2cc..de3bb54a3e 100644 --- a/code/modules/nano/JSON Writer.dm +++ b/code/_compatibility/509/JSON Writer.dm @@ -1,3 +1,5 @@ +#if DM_VERSION < 510 + json_writer var use_cache = 0 @@ -48,7 +50,7 @@ json_writer var/lrep = length(json_escape[targ]) txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ)) start = i + lrep - + return {""[txt]""} is_associative(list/L) @@ -56,3 +58,5 @@ json_writer // if the key is a list that means it's actually an array of lists (stupid Byond...) if(!isnum(key) && !isnull(L[key]) && !istype(key, /list)) return TRUE + +#endif \ No newline at end of file diff --git a/code/modules/nano/_JSON.dm b/code/_compatibility/509/_JSON.dm similarity index 54% rename from code/modules/nano/_JSON.dm rename to code/_compatibility/509/_JSON.dm index 9579189981..46f488ac56 100644 --- a/code/modules/nano/_JSON.dm +++ b/code/_compatibility/509/_JSON.dm @@ -1,17 +1,14 @@ +#if DM_VERSION < 510 /* n_Json v11.3.21 */ proc - json2list(json) + json_decode(json) var/static/json_reader/_jsonr = new() return _jsonr.ReadObject(_jsonr.ScanJson(json)) - list2json(list/L) + json_encode(list/L) var/static/json_writer/_jsonw = new() return _jsonw.write(L) - - list2json_usecache(list/L) - var/static/json_writer/_jsonw = new() - _jsonw.use_cache = 1 - return _jsonw.write(L) +#endif \ No newline at end of file diff --git a/code/_compatibility/509/text.dm b/code/_compatibility/509/text.dm new file mode 100644 index 0000000000..c22790ccb8 --- /dev/null +++ b/code/_compatibility/509/text.dm @@ -0,0 +1,6 @@ +#if DM_VERSION < 510 + +/proc/replacetext(text, find, replacement) + return jointext(splittext(text, find), replacement) + +#endif \ No newline at end of file diff --git a/code/_compatibility/509/type2type.dm b/code/_compatibility/509/type2type.dm new file mode 100644 index 0000000000..62d7a5e5c7 --- /dev/null +++ b/code/_compatibility/509/type2type.dm @@ -0,0 +1,102 @@ +#if DM_VERSION < 510 +// Concatenates a list of strings into a single string. A seperator may optionally be provided. +/proc/jointext(list/ls, sep) + if (ls.len <= 1) // Early-out code for empty or singleton lists. + return ls.len ? ls[1] : "" + + var/l = ls.len // Made local for sanic speed. + var/i = 0 // Incremented every time a list index is accessed. + + if (sep <> null) + // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc... + #define S1 sep, ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + // Having the small concatenations come before the large ones boosted speed by an average of at least 5%. + if (l-1 & 0x01) // 'i' will always be 1 here. + . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2. + if (l-i & 0x02) + . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if (l-i & 0x04) + . = text("[][][][][][][][][]", ., S4) // And so on.... + if (l-i & 0x08) + . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4) + if (l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16) + if (l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if (l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while (l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 + else + // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc... + #define S1 ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + if (l-1 & 0x01) // 'i' will always be 1 here. + . += S1 // Append 1 element if the remaining elements are not a multiple of 2. + if (l-i & 0x02) + . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if (l-i & 0x04) + . = text("[][][][][]", ., S4) // And so on... + if (l-i & 0x08) + . = text("[][][][][][][][][]", ., S4, S4) + if (l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][]", ., S16) + if (l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if (l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while (l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 + +// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator) +/proc/splittext(text, delimiter="\n") + var/delim_len = length(delimiter) + if (delim_len < 1) + return list(text) + + . = list() + var/last_found = 1 + var/found + + do + found = findtext(text, delimiter, last_found, 0) + . += copytext(text, last_found, found) + last_found = found + delim_len + while (found) +#endif \ No newline at end of file diff --git a/code/_helpers/_global_objects.dm b/code/_helpers/_global_objects.dm new file mode 100644 index 0000000000..4cbbcf3314 --- /dev/null +++ b/code/_helpers/_global_objects.dm @@ -0,0 +1 @@ +var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() \ No newline at end of file diff --git a/code/_helpers/datum_pool.dm b/code/_helpers/datum_pool.dm index 5c13c0d8ba..b5bcea123f 100644 --- a/code/_helpers/datum_pool.dm +++ b/code/_helpers/datum_pool.dm @@ -74,7 +74,6 @@ var/global/list/GlobalPool = list() D.Destroy() D.ResetVars() - D.disposed = 1 //Set to stop processing while pooled /proc/IsPooled(var/datum/D) if(isnull(GlobalPool[D.type])) @@ -86,7 +85,6 @@ var/global/list/GlobalPool = list() New(arglist(args)) else New(args) - disposed = null /atom/movable/Prepare(args) var/list/args_list = args diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 258060396d..c3ce40e657 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -244,10 +244,50 @@ var/turf/ear = get_turf(M) if(ear) // Ghostship is magic: Ghosts can hear radio chatter from anywhere - if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO))) + if(speaker_coverage[ear] || (istype(M, /mob/observer/dead) && M.is_preference_enabled(/datum/client_preference/ghost_radio))) . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . +//Uses dview to quickly return mobs and objects in view, +// then adds additional mobs or objects if they are in range 'smartly', +// based on their presence in lists of players or registered objects +// Type: 1-audio, 2-visual, 0-neither +/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/type = 1) + var/list/mobs = list() + var/list/objs = list() + + var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM) + var/list/hearturfs = list() + + for(var/atom/movable/AM in hear) + if(ismob(AM)) + mobs += AM + hearturfs += AM.locs[1] + else if(isobj(AM)) + objs += AM + hearturfs += AM.locs[1] + + //A list of every mob with a client + for(var/mob/M in player_list) + if(M.loc && M.locs[1] in hearturfs) + mobs |= M + + else if(M.stat == DEAD) + switch(type) + if(1) //Audio messages use ghost_ears + if(M.is_preference_enabled(/datum/client_preference/ghost_ears)) + mobs |= M + if(2) //Visual messages use ghost_sight + if(M.is_preference_enabled(/datum/client_preference/ghost_sight)) + mobs |= M + + //For objects below the top level who still want to hear + for(var/obj/O in listening_objects) + if(O.loc && O.locs[1] in hearturfs) + objs |= O + + return list("mobs" = mobs, "objs" = objs) + #define SIGN(X) ((X<0)?-1:1) proc @@ -323,7 +363,7 @@ proc/isInSight(var/atom/A, var/atom/B) var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn var/i = 0 while(candidates.len <= 0 && i < 5) - for(var/mob/dead/observer/G in player_list) + for(var/mob/observer/dead/G in player_list) if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) candidates += G.key @@ -337,7 +377,7 @@ proc/isInSight(var/atom/A, var/atom/B) var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn var/i = 0 while(candidates.len <= 0 && i < 5) - for(var/mob/dead/observer/G in player_list) + for(var/mob/observer/dead/G in player_list) if(G.client.prefs.be_special & BE_ALIEN) if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) // the most active players are more likely to become an alien if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 57527aab42..9a90a3676b 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -11,6 +11,7 @@ var/global/list/human_mob_list = list() //List of all human mobs and sub-type var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player +var/global/list/listening_objects = list() //List of all objects which care about receiving messages (communicators, radios, etc) var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions @@ -23,6 +24,9 @@ var/global/list/joblist = list() //list of all jobstypes, minus borg and AI var/global/list/turfs = list() //list of all turfs +#define all_genders_define_list list(MALE,FEMALE,PLURAL,NEUTER) +#define all_genders_text_list list("Male","Female","Plural","Neuter") + //Languages/species/whitelist. var/global/list/all_species[0] var/global/list/all_languages[0] @@ -30,6 +34,8 @@ var/global/list/language_keys[0] // Table of say codes for all languages var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check. var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise. +var/list/mannequins_ + // Posters var/global/list/poster_designs = list() @@ -46,39 +52,7 @@ var/global/list/facial_hair_styles_male_list = list() var/global/list/facial_hair_styles_female_list = list() var/global/list/skin_styles_female_list = list() //unused //Underwear -var/global/list/underwear_top_t = list( - "Bra, Red" = "t1", "Bra, White" = "t2", "Bra, Yellow" = "t3", "Bra, Blue" = "t4", "Bra, Black" = "t5", "Lacy Bra" = "t6", "Sports Bra, Black" = "t7", "Sports Bra, White" = "t8", - "Sports Bra Alt, Black" = "t9", "Sporta Bra Alt, White" = "t10", "Bra, Baby-Blue" = "t11", "Bra, Green" = "t12", "Bra, Pink" = "t13", "Bra, Violet" = "t14", - "Lacy Bra Alt" = "t15", "Lacy Bra Alt, Violet" = "t16", "Halterneck Bra, Black" = "t17", "Halterneck Bra, Blue" = "t18", "Halterneck Bra, Green" = "t19", "Halterneck Bra, Purple" = "t20", - "Halterneck Bra, Red" = "t21", "Halterneck Bra, Teal" = "t22", "Halterneck Bra, Violet" = "t23", "Halterneck Bra, White" = "t24", "None") -var/global/list/underwear_bottom_t = list( - "Briefs, White" = "b1", "Briefs, Grey" = "b2", "Briefs, Green" = "b3", "Briefs, Blue" = "b4", "Briefs, Black" = "b5", "Boxers, Loveheart" = "b7", "Boxers, Black" = "b8", - "Boxers, Grey" = "b9", "Boxers, Green & Blue Striped" = "b10", "Panties, Red" = "b11", "Panties, White" = "b12", "Panties, Yellow" = "b13", "Panties, Blue" = "b14", - "Panties, Light-Black" = "b15", "Thong" = "b16", "Panties, Black" = "b17", "Panties Alt, White" = "b18", "Compression Shorts, Black" = "b19", "Compression Shorts, White" = "b20", - "Compression Shorts, Baby-Blue" = "b21", "Panties, Green" = "b22", "Compression Shorts, Pink" = "b23", "Thong, Violet" = "b24", "Thong Alt" = "b25", "Thong Alt, Violet" = "b26", - "Alt Thong, Black" = "b27", "Alt Thong, Blue" = "b28", "Alt Thong, Green" = "b29", "Alt Thong, Purple" = "b30", "Alt Thong, Red" = "b31", "Alt Thong, Teal" = "b32", - "Alt Thong, Violet" = "b33", "Alt Thong, White" = "b34", "None") - //undershirt -var/global/list/undershirt_t = list( - "White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3", - "White shirt" = "u4", "White shirt 2" = "shirt_white_s", "White tank top 2" = "tank_white_s", - "Black shirt 2" = "shirt_black_s", "Grey shirt" = "shirt_grey_s", "Heart shirt" = "lover_s", - "I love NT shirt" = "ilovent_s", "White shortsleeve shirt" = "whiteshortsleeve_s", "Purple shortsleeve shirt" = "purpleshortsleeve_s", - "Blue shortsleeve shirt" = "blueshortsleeve_s", "Green shortsleeve shirt" = "greenshortsleeve_s", "Black shortsleeve shirt" = "blackshortsleeve_s", - "Blue shirt" = "blueshirt_s", "Red shirt" = "redshirt_s", "Yellow shirt" = "yellowshirt_s", "Green shirt" = "greenshirt_s", - "Blue polo shirt" = "bluepolo_s", "Red polo shirt" = "redpolo_s", "White polo shirt" = "whitepolo_s", - "Grey-yellow polo shirt" = "grayyellowpolo_s", "Fire tank top" = "tank_fire_s", "NT shirt" = "shirt_nano_s", - "Blue shirt 2" = "shirt_blue_s", "Red shirt 2" = "shirt_red_s", "Red tank top" = "tank_red_s", "Green shirt 2" = "shirt_green_s", - "Tiedye shirt" = "shirt_tiedye_s", "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s", - "Blue striped shirt" = "shirt_stripes_s", "Blue sport shirt" = "blueshirtsport_s", "None") - //Socks -var/global/list/socks_t = list( - "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee", - "White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short", - "Black knee" = "black_knee", "Black thigh" = "black_thigh", "Thin knee" = "thin_knee", - "Thin thigh" = "thin_thigh", "Pantyhose" = "pantyhose", "Striped thigh" = "striped_thigh", - "Striped knee" = "striped_knee", "Rainbow knee" = "rainbow_knee", "Rainbow thigh" = "rainbow_thigh", - "Fishnets" = "fishnet", "Thin white thigh" = "thinwhite_thigh", "Thin white knee" = "thinwhite_knee", "None") +var/datum/category_collection/underwear/global_underwear = new() //Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt") @@ -128,6 +102,14 @@ var/global/list/string_slot_flags = list( "holster" = SLOT_HOLSTER ) +/proc/get_mannequin(var/ckey) + if(!mannequins_) + mannequins_ = new() + . = mannequins_[ckey] + if(!.) + . = new/mob/living/carbon/human/dummy/mannequin() + mannequins_[ckey] = . + ////////////////////////// /////Initial Building///// ////////////////////////// @@ -185,16 +167,22 @@ var/global/list/string_slot_flags = list( language_keys[lowertext(L.key)] = L var/rkey = 0 - paths = typesof(/datum/species)-/datum/species + paths = typesof(/datum/species) for(var/T in paths) + rkey++ - var/datum/species/S = new T + + var/datum/species/S = T + if(!initial(S.name)) + continue + + S = new T S.race_key = rkey //Used in mob icon caching. all_species[S.name] = S - if(!(S.spawn_flags & IS_RESTRICTED)) + if(!(S.spawn_flags & SPECIES_IS_RESTRICTED)) playable_species += S.name - if(S.spawn_flags & IS_WHITELISTED) + if(S.spawn_flags & SPECIES_IS_WHITELISTED) whitelisted_species += S.name //Posters @@ -216,3 +204,5 @@ var/global/list/string_slot_flags = list( . += " has: [t]\n" world << . */ +//Hexidecimal numbers +var/global/list/hexNums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index f8a4b12b96..d4e6710b35 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -30,13 +30,6 @@ return "[output][and_text][input[index]]" - -/proc/ConvertReqString2List(var/list/source_list) - var/list/temp_list = params2list(source_list) - for(var/O in temp_list) - temp_list[O] = text2num(temp_list[O]) - return temp_list - //Returns list element or null. Should prevent "index out of bounds" error. proc/listgetindex(var/list/list,index) if(istype(list) && list.len) @@ -48,9 +41,7 @@ proc/listgetindex(var/list/list,index) return proc/islist(list/list) - if(istype(list)) - return 1 - return 0 + return(istype(list)) //Return either pick(list) or null if list is not of type /list or is empty proc/safepick(list/list) @@ -611,13 +602,13 @@ proc/dd_sortedTextList(list/incoming) /datum/alarm/dd_SortValue() return "[sanitize_old(last_name)]" -/proc/subtypes(prototype) +/proc/subtypesof(prototype) return (typesof(prototype) - prototype) //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. /proc/init_subtypes(prototype, list/L) if(!istype(L)) L = list() - for(var/path in subtypes(prototype)) + for(var/path in subtypesof(prototype)) L += new path() return L diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index 23119c69ad..35618c9b66 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -25,16 +25,14 @@ if (config.log_admin) diary << "\[[time_stamp()]]ADMIN: [text][log_end]" - /proc/log_debug(text) if (config.log_debug) diary << "\[[time_stamp()]]DEBUG: [text][log_end]" for(var/client/C in admins) - if(C.prefs.toggles & CHAT_DEBUGLOGS) + if(C.is_preference_enabled(/datum/client_preference/debug/show_debug_logs)) C << "DEBUG: [text]" - /proc/log_game(text) if (config.log_game) diary << "\[[time_stamp()]]GAME: [text][log_end]" @@ -79,9 +77,17 @@ if (config.log_pda) diary << "\[[time_stamp()]]PDA: [text][log_end]" +/proc/log_to_dd(text) + world.log << text //this comes before the config check because it can't possibly runtime + if(config.log_world_output) + diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]" + /proc/log_misc(text) diary << "\[[time_stamp()]]MISC: [text][log_end]" +/proc/log_unit_test(text) + world.log << "## UNIT_TEST: [text]" + //pretty print a direction bitflag, can be useful for debugging. /proc/print_dir(var/dir) var/list/comps = list() @@ -91,7 +97,7 @@ if(dir & WEST) comps += "WEST" if(dir & UP) comps += "UP" if(dir & DOWN) comps += "DOWN" - + return english_list(comps, nothing_text="0", and_text="|", comma_text="|") //more or less a logging utility diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 9213765bbc..9f4ece96f8 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -30,13 +30,10 @@ proc/random_hair_style(gender, species = "Human") var/list/valid_hairstyles = list() for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - - if(gender != NEUTER && gender != PLURAL) - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue if( !(species in S.species_allowed)) continue valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] @@ -52,13 +49,10 @@ proc/random_facial_hair_style(gender, species = "Human") var/list/valid_facialhairstyles = list() for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - - if(gender != NEUTER && gender != PLURAL) - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue if( !(species in S.species_allowed)) continue @@ -171,3 +165,88 @@ Proc for attack log creation, because really why not return 0 var/mob/living/silicon/robot/R = thing.loc return (thing in R.module.modules) + +/proc/get_exposed_defense_zone(var/atom/movable/target) + var/obj/item/weapon/grab/G = locate() in target + if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people. + return pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg") + else + return pick("chest", "groin") + +/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1) + if(!user || !target) + return 0 + var/user_loc = user.loc + var/target_loc = target.loc + + var/holding = user.get_active_hand() + var/datum/progressbar/progbar + if (progress) + progbar = new(user, time, target) + + var/endtime = world.time+time + var/starttime = world.time + . = 1 + while (world.time < endtime) + sleep(1) + if (progress) + progbar.update(world.time - starttime) + if(!user || !target) + . = 0 + break + if(uninterruptible) + continue + + if(!user || user.incapacitated() || user.loc != user_loc) + . = 0 + break + + if(target.loc != target_loc) + . = 0 + break + + if(user.get_active_hand() != holding) + . = 0 + break + + if (progbar) + qdel(progbar) + +/proc/do_after(mob/user, delay, atom/target = null, needhand = 1, progress = 1, var/incapacitation_flags = INCAPACITATION_DEFAULT) + if(!user) + return 0 + var/atom/target_loc = null + if(target) + target_loc = target.loc + + var/atom/original_loc = user.loc + + var/holding = user.get_active_hand() + + var/datum/progressbar/progbar + if (progress) + progbar = new(user, delay, target) + + var/endtime = world.time + delay + var/starttime = world.time + . = 1 + while (world.time < endtime) + sleep(1) + if (progress) + progbar.update(world.time - starttime) + + if(!user || user.incapacitated(incapacitation_flags) || user.loc != original_loc) + . = 0 + break + + if(target_loc && (!target || target_loc != target.loc)) + . = 0 + break + + if(needhand) + if(user.get_active_hand() != holding) + . = 0 + break + + if (progbar) + qdel(progbar) diff --git a/code/_helpers/names.dm b/code/_helpers/names.dm index 437661b7fc..dbd19610e6 100644 --- a/code/_helpers/names.dm +++ b/code/_helpers/names.dm @@ -44,7 +44,7 @@ var/religion_name = null return capitalize(name) /proc/system_name() - return "Vir" + return starsys_name /proc/station_name() if (station_name) @@ -161,7 +161,7 @@ var/syndicate_code_response//Code response for traitors. Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay. Can probably be done through "{ }" but I don't really see the practical benefit. One example of an earlier system is commented below. - /N + -N */ /proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 549060b0af..68cb5276fa 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -175,13 +175,6 @@ /* * Text modification */ - -/proc/replacetext(text, find, replacement) - return list2text(text2list(text, find), replacement) - -/proc/replacetextEx(text, find, replacement) - return list2text(text2listEx(text, find), replacement) - /proc/replace_characters(var/t,var/list/repl_chars) for(var/char in repl_chars) t = replacetext(t, char, repl_chars[char]) @@ -311,7 +304,7 @@ proc/TextPreview(var/string,var/len=40) // to always create it and then throw it out. /var/icon/text_tag_icons = new('./icons/chattags.dmi') /proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) - if(C && (C.prefs.toggles & CHAT_NOICONS)) + if(!(C && C.is_preference_enabled(/datum/client_preference/chat_tags))) return tagdesc return "[tagdesc]" @@ -330,3 +323,12 @@ proc/TextPreview(var/string,var/len=40) if(48 to 57) //Numbers return 1 return 0 + +/** + * Strip out the special beyond characters for \proper and \improper + * from text that will be sent to the browser. + */ +/proc/strip_improper(var/text) + return replacetext(replacetext(text, "\proper", ""), "\improper", "") + +#define gender2text(gender) capitalize(gender) \ No newline at end of file diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index 336d72fc13..19e2206cd0 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -30,11 +30,21 @@ proc/isDay(var/month, var/day) var/next_duration_update = 0 var/last_round_duration = 0 -proc/round_duration() +var/round_start_time = 0 + +/hook/roundstart/proc/start_timer() + round_start_time = world.time + return 1 + +#define round_duration_in_ticks (round_start_time ? world.time - round_start_time : 0) + +/proc/round_duration_as_text() + if(!round_start_time) + return "00:00" if(last_round_duration && world.time < next_duration_update) return last_round_duration - var/mills = world.time // 1/10 of a second, not real milliseconds but whatever + var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever //var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something var/mins = round((mills % 36000) / 600) var/hours = round(mills / 36000) diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index 4a6958aaad..0bcf546123 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -50,141 +50,15 @@ while (left-- > 0) . = "0[.]" -// Concatenates a list of strings into a single string. A seperator may optionally be provided. -/proc/list2text(list/ls, sep) - if (ls.len <= 1) // Early-out code for empty or singleton lists. - return ls.len ? ls[1] : "" - - var/l = ls.len // Made local for sanic speed. - var/i = 0 // Incremented every time a list index is accessed. - - if (sep <> null) - // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc... - #define S1 sep, ls[++i] - #define S4 S1, S1, S1, S1 - #define S16 S4, S4, S4, S4 - #define S64 S16, S16, S16, S16 - - . = "[ls[++i]]" // Make sure the initial element is converted to text. - - // Having the small concatenations come before the large ones boosted speed by an average of at least 5%. - if (l-1 & 0x01) // 'i' will always be 1 here. - . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2. - if (l-i & 0x02) - . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. - if (l-i & 0x04) - . = text("[][][][][][][][][]", ., S4) // And so on.... - if (l-i & 0x08) - . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4) - if (l-i & 0x10) - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16) - if (l-i & 0x20) - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) - if (l-i & 0x40) - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) - while (l > i) // Chomp through the rest of the list, 128 elements at a time. - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) - - #undef S64 - #undef S16 - #undef S4 - #undef S1 - else - // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc... - #define S1 ls[++i] - #define S4 S1, S1, S1, S1 - #define S16 S4, S4, S4, S4 - #define S64 S16, S16, S16, S16 - - . = "[ls[++i]]" // Make sure the initial element is converted to text. - - if (l-1 & 0x01) // 'i' will always be 1 here. - . += S1 // Append 1 element if the remaining elements are not a multiple of 2. - if (l-i & 0x02) - . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. - if (l-i & 0x04) - . = text("[][][][][]", ., S4) // And so on... - if (l-i & 0x08) - . = text("[][][][][][][][][]", ., S4, S4) - if (l-i & 0x10) - . = text("[][][][][][][][][][][][][][][][][]", ., S16) - if (l-i & 0x20) - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) - if (l-i & 0x40) - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) - while (l > i) // Chomp through the rest of the list, 128 elements at a time. - . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ - [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) - - #undef S64 - #undef S16 - #undef S4 - #undef S1 - -// Slower then list2text, but correctly processes associative lists. -proc/tg_list2text(list/list, glue=",") - if (!istype(list) || !list.len) - return - var/output - for(var/i=1 to list.len) - output += (i!=1? glue : null)+(!isnull(list["[list[i]]"])?"[list["[list[i]]"]]":"[list[i]]") - return output - -// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator) -/proc/text2list(text, delimiter="\n") - var/delim_len = length(delimiter) - if (delim_len < 1) - return list(text) - - . = list() - var/last_found = 1 - var/found - - do - found = findtext(text, delimiter, last_found, 0) - . += copytext(text, last_found, found) - last_found = found + delim_len - while (found) - -// Case sensitive version of /proc/text2list(). -/proc/text2listEx(text, delimiter="\n") - var/delim_len = length(delimiter) - if (delim_len < 1) - return list(text) - - . = list() - var/last_found = 1 - var/found - - do - found = findtextEx(text, delimiter, last_found, 0) - . += copytext(text, last_found, found) - last_found = found + delim_len - while (found) - /proc/text2numlist(text, delimiter="\n") var/list/num_list = list() - for(var/x in text2list(text, delimiter)) + for(var/x in splittext(text, delimiter)) num_list += text2num(x) return num_list // Splits the text of a file at seperator and returns them in a list. /proc/file2list(filename, seperator="\n") - return text2list(return_file_text(filename),seperator) + return splittext(return_file_text(filename),seperator) // Turns a direction into text /proc/num2dir(direction) @@ -275,6 +149,26 @@ proc/tg_list2text(list/list, glue=",") if (rights & R_MENTOR) . += "[seperator]+MENTOR" return . +// Converts a hexadecimal color (e.g. #FF0050) to a list of numbers for red, green, and blue (e.g. list(255,0,80) ). +/proc/hex2rgb(hex) + // Strips the starting #, in case this is ever supplied without one, so everything doesn't break. + if(findtext(hex,"#",1,2)) + hex = copytext(hex, 2) + return list(hex2rgb_r(hex), hex2rgb_g(hex), hex2rgb_b(hex)) + +// The three procs below require that the '#' part of the hex be stripped, which hex2rgb() does automatically. +/proc/hex2rgb_r(hex) + var/hex_to_work_on = copytext(hex,1,3) + return hex2num(hex_to_work_on) + +/proc/hex2rgb_g(hex) + var/hex_to_work_on = copytext(hex,3,5) + return hex2num(hex_to_work_on) + +/proc/hex2rgb_b(hex) + var/hex_to_work_on = copytext(hex,5,7) + return hex2num(hex_to_work_on) + // heat2color functions. Adapted from: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ /proc/heat2color(temp) return rgb(heat2color_r(temp), heat2color_g(temp), heat2color_b(temp)) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index bd6f014e0b..1e14d39183 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -137,7 +137,7 @@ Turf and target are seperate in case you want to teleport some distance from a t //Now to find a box from center location and make that our destination. for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) )) - if(density&&T.density) continue//If density was specified. + if(density&&(T.density||T.contains_dense_objects())) continue//If density was specified. if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map. if(T.y>world.maxy || T.y<1) continue destination_list += T @@ -146,7 +146,7 @@ Turf and target are seperate in case you want to teleport some distance from a t else return else//Same deal here. - if(density&&destination.density) return + if(density&&(destination.density||destination.contains_dense_objects())) return if(destination.x>world.maxx || destination.x<1) return if(destination.y>world.maxy || destination.y<1) return else return @@ -462,7 +462,7 @@ Turf and target are seperate in case you want to teleport some distance from a t if (M.real_name && M.real_name != M.name) name += " \[[M.real_name]\]" if (M.stat == 2) - if(istype(M, /mob/dead/observer/)) + if(istype(M, /mob/observer/dead/)) name += " \[ghost\]" else name += " \[dead\]" @@ -474,7 +474,7 @@ Turf and target are seperate in case you want to teleport some distance from a t /proc/sortmobs() var/list/moblist = list() var/list/sortmob = sortAtom(mob_list) - for(var/mob/eye/M in sortmob) + for(var/mob/observer/eye/M in sortmob) moblist.Add(M) for(var/mob/living/silicon/ai/M in sortmob) moblist.Add(M) @@ -488,7 +488,7 @@ Turf and target are seperate in case you want to teleport some distance from a t moblist.Add(M) for(var/mob/living/carbon/alien/M in sortmob) moblist.Add(M) - for(var/mob/dead/observer/M in sortmob) + for(var/mob/observer/dead/M in sortmob) moblist.Add(M) for(var/mob/new_player/M in sortmob) moblist.Add(M) @@ -646,47 +646,6 @@ proc/GaussRandRound(var/sigma,var/roundto) else return get_step(ref, base_dir) -/proc/do_mob(var/mob/user, var/mob/target, var/delay = 30, var/numticks = 5, var/needhand = 1) //This is quite an ugly solution but i refuse to use the old request system. - if(!user || !target) return 0 - if(numticks == 0) return 0 - - var/delayfraction = round(delay/numticks) - var/original_user_loc = user.loc - var/original_target_loc = target.loc - var/holding = user.get_active_hand() - - for(var/i = 0, i[content]" -/proc/get_random_colour(var/simple, var/lower, var/upper) +/proc/get_random_colour(var/simple, var/lower=0, var/upper=255) var/colour if(simple) colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF")) @@ -1351,3 +1309,15 @@ var/mob/dview/dview_mob = new // call to generate a stack trace and print to runtime logs /proc/crash_with(msg) CRASH(msg) + +/proc/screen_loc2turf(scr_loc, turf/origin) + var/tX = splittext(scr_loc, ",") + var/tY = splittext(tX[2], ":") + var/tZ = origin.z + tY = tY[1] + tX = splittext(tX[1], ":") + tX = tX[1] + tX = max(1, min(world.maxx, origin.x + (text2num(tX) - (world.view + 1)))) + tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1)))) + return locate(tX, tY, tZ) + diff --git a/code/_macros.dm b/code/_macros.dm index b6ddf4f12c..801498d915 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -7,13 +7,15 @@ #define isanimal(A) istype(A, /mob/living/simple_animal) +#define isairlock(A) istype(A, /obj/machinery/door/airlock) + #define isbrain(A) istype(A, /mob/living/carbon/brain) #define iscarbon(A) istype(A, /mob/living/carbon) #define iscorgi(A) istype(A, /mob/living/simple_animal/corgi) -#define isEye(A) istype(A, /mob/eye) +#define isEye(A) istype(A, /mob/observer/eye) #define ishuman(A) istype(A, /mob/living/carbon/human) @@ -23,7 +25,7 @@ #define isnewplayer(A) istype(A, /mob/new_player) -#define isobserver(A) istype(A, /mob/dead/observer) +#define isobserver(A) istype(A, /mob/observer/dead) #define isorgan(A) istype(A, /obj/item/organ/external) @@ -34,3 +36,7 @@ #define issilicon(A) istype(A, /mob/living/silicon) #define isslime(A) istype(A, /mob/living/carbon/slime) + +#define isxeno(A) istype(A, /mob/living/simple_animal/xeno) + +#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") diff --git a/code/_onclick/_defines.dm b/code/_onclick/_defines.dm new file mode 100644 index 0000000000..3c76c35e80 --- /dev/null +++ b/code/_onclick/_defines.dm @@ -0,0 +1 @@ +#define CLICKCATCHER_PLANE -99 \ No newline at end of file diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index dfb6de5e91..c5c48dbbf2 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -121,9 +121,9 @@ /obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors! if(density) - Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!) + Topic(src, list("command"="open", "activate" = "1")) else - Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "0"), 1) + Topic(src, list("command"="open", "activate" = "0")) return 1 /atom/proc/AICtrlClick() @@ -131,17 +131,17 @@ /obj/machinery/door/airlock/AICtrlClick() // Bolts doors if(locked) - Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!) + Topic(src, list("command"="bolts", "activate" = "0")) else - Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "1"), 1) + Topic(src, list("command"="bolts", "activate" = "1")) return 1 /obj/machinery/power/apc/AICtrlClick() // turns off/on APCs. - Topic(src, list("src"= "\ref[src]", "breaker"="1"), 1) // 1 meaning no window (consistency!) + Topic(src, list("breaker"="1")) return 1 /obj/machinery/turretid/AICtrlClick() //turns off/on Turrets - Topic(src, list("src"= "\ref[src]", "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!) + Topic(src, list("command"="enable", "value"="[!enabled]")) return 1 /atom/proc/AIAltClick(var/atom/A) @@ -150,14 +150,14 @@ /obj/machinery/door/airlock/AIAltClick() // Electrifies doors. if(!electrified_until) // permanent shock - Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!) + Topic(src, list("command"="electrify_permanently", "activate" = "1")) else // disable/6 is not in Topic; disable/5 disables both temporary and permanent shock - Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "0"), 1) + Topic(src, list("command"="electrify_permanently", "activate" = "0")) return 1 /obj/machinery/turretid/AIAltClick() //toggles lethal on turrets - Topic(src, list("src"= "\ref[src]", "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!) + Topic(src, list("command"="lethal", "value"="[!lethal]")) return 1 /atom/proc/AIMiddleClick(var/mob/living/silicon/user) @@ -169,9 +169,9 @@ return if(!src.lights) - Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!) + Topic(src, list("command"="lights", "activate" = "1")) else - Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "0"), 1) + Topic(src, list("command"="lights", "activate" = "0")) return 1 // diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 9fa5fa3654..52c56ccb17 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -87,6 +87,7 @@ if(in_throw_mode) if(isturf(A) || isturf(A.loc)) throw_item(A) + trigger_aiming(TARGET_CAN_CLICK) return 1 throw_mode_off() @@ -94,20 +95,14 @@ if(W == A) // Handle attack_self W.attack_self(src) - if(hand) - update_inv_l_hand(0) - else - update_inv_r_hand(0) + trigger_aiming(TARGET_CAN_CLICK) + update_inv_active_hand(0) return 1 //Atoms on your person // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth. var/sdepth = A.storage_depth(src) if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1)) - // faster access to objects already on you - if(A.loc != src) - setMoveCooldown(10) //getting something out of a backpack - if(W) var/resolved = W.resolve_attackby(A, src) if(!resolved && A && W) @@ -116,6 +111,8 @@ if(ismob(A)) // No instant mob attacking setClickCooldown(DEFAULT_ATTACK_COOLDOWN) UnarmedAttack(A, 1) + + trigger_aiming(TARGET_CAN_CLICK) return 1 if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that @@ -126,8 +123,6 @@ sdepth = A.storage_depth_turf() if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) if(A.Adjacent(src)) // see adjacent.dm - setMoveCooldown(5) - if(W) // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) var/resolved = W.resolve_attackby(A,src) @@ -137,12 +132,15 @@ if(ismob(A)) // No instant mob attacking setClickCooldown(DEFAULT_ATTACK_COOLDOWN) UnarmedAttack(A, 1) + trigger_aiming(TARGET_CAN_CLICK) return else // non-adjacent click if(W) W.afterattack(A, src, 0, params) // 0: not Adjacent else RangedAttack(A, params) + + trigger_aiming(TARGET_CAN_CLICK) return 1 /mob/proc/setClickCooldown(var/timeout) @@ -194,15 +192,8 @@ if((LASER in mutations) && a_intent == I_HURT) LaserEyes(A) // moved into a proc below else if(TK in mutations) - switch(get_dist(src,A)) - if(1 to 5) // not adjacent may mean blocked by window - setMoveCooldown(2) - if(5 to 7) - setMoveCooldown(5) - if(8 to tk_maxrange) - setMoveCooldown(10) - else - return + if(get_dist(src, A) > tk_maxrange) + return A.attack_tk(src) /* Restrained ClickOn @@ -328,3 +319,28 @@ else direction = WEST if(direction != dir) facedir(direction) + +/obj/screen/click_catcher + icon = 'icons/mob/screen_gen.dmi' + icon_state = "click_catcher" + plane = CLICKCATCHER_PLANE + mouse_opacity = 2 + screen_loc = "CENTER-7,CENTER-7" + +/obj/screen/click_catcher/proc/MakeGreed() + . = list() + for(var/i = 0, i<15, i++) + for(var/j = 0, j<15, j++) + var/obj/screen/click_catcher/CC = new() + CC.screen_loc = "NORTH-[i],EAST-[j]" + . += CC + +/obj/screen/click_catcher/Click(location, control, params) + var/list/modifiers = params2list(params) + if(modifiers["middle"] && istype(usr, /mob/living/carbon)) + var/mob/living/carbon/C = usr + C.swap_hand() + else + var/turf/T = screen_loc2turf("screen-loc", get_turf(usr)) + T.Click(location, control, params) + . = 1 diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm index 589947df32..687b03ce99 100644 --- a/code/_onclick/hud/ability_screen_objects.dm +++ b/code/_onclick/hud/ability_screen_objects.dm @@ -68,15 +68,15 @@ update_icon() /obj/screen/movable/ability_master/proc/open_ability_master() - var/list/screen_loc_xy = text2list(screen_loc,",") + var/list/screen_loc_xy = splittext(screen_loc,",") //Create list of X offsets - var/list/screen_loc_X = text2list(screen_loc_xy[1],":") + var/list/screen_loc_X = splittext(screen_loc_xy[1],":") var/x_position = decode_screen_X(screen_loc_X[1]) var/x_pix = screen_loc_X[2] //Create list of Y offsets - var/list/screen_loc_Y = text2list(screen_loc_xy[2],":") + var/list/screen_loc_Y = splittext(screen_loc_xy[2],":") var/y_position = decode_screen_Y(screen_loc_Y[1]) var/y_pix = screen_loc_Y[2] diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index ab959eae53..37d9616ea5 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -40,9 +40,9 @@ using.layer = SCREEN_LAYER adding += using -//Crew Monitorting +//Crew Monitoring using = new /obj/screen() - using.name = "Crew Monitorting" + using.name = "Crew Monitoring" using.icon = 'icons/mob/screen_ai.dmi' using.icon_state = "crew_monitor" using.screen_loc = ui_ai_crew_monitor @@ -130,6 +130,8 @@ using.layer = SCREEN_LAYER adding += using + mymob.client.screen = list() mymob.client.screen += adding + other + mymob.client.screen += mymob.client.void return \ No newline at end of file diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index 59004934d7..1f0df80141 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -21,26 +21,13 @@ mymob.healths.name = "health" mymob.healths.screen_loc = ui_alien_health - mymob.blind = new /obj/screen() - mymob.blind.icon = 'icons/mob/screen1_full.dmi' - mymob.blind.icon_state = "blackimageoverlay" - mymob.blind.name = " " - mymob.blind.screen_loc = "1,1" - mymob.blind.layer = 0 - - mymob.flash = new /obj/screen() - mymob.flash.icon = 'icons/mob/screen1_alien.dmi' - mymob.flash.icon_state = "blank" - mymob.flash.name = "flash" - mymob.flash.screen_loc = ui_entire_screen - mymob.flash.layer = 17 - mymob.fire = new /obj/screen() mymob.fire.icon = 'icons/mob/screen1_alien.dmi' mymob.fire.icon_state = "fire0" mymob.fire.name = "fire" mymob.fire.screen_loc = ui_fire - mymob.client.screen = null - mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach ) - mymob.client.screen += src.adding + src.other \ No newline at end of file + mymob.client.screen = list() + mymob.client.screen += list( mymob.healths, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach ) + mymob.client.screen += src.adding + src.other + mymob.client.screen += mymob.client.void \ No newline at end of file diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm new file mode 100644 index 0000000000..fd226eb70c --- /dev/null +++ b/code/_onclick/hud/fullscreen.dm @@ -0,0 +1,118 @@ +#define FULLSCREEN_LAYER 18 +#define DAMAGE_LAYER FULLSCREEN_LAYER + 0.1 +#define BLIND_LAYER DAMAGE_LAYER + 0.1 +#define CRIT_LAYER BLIND_LAYER + 0.1 + +/mob + var/list/screens = list() + +/mob/proc/set_fullscreen(condition, screen_name, screen_type, arg) + condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name) + +/mob/proc/overlay_fullscreen(category, type, severity) + var/obj/screen/fullscreen/screen = screens[category] + + if(screen) + if(screen.type != type) + clear_fullscreen(category, FALSE) + screen = null + else if(!severity || severity == screen.severity) + return null + + if(!screen) + screen = PoolOrNew(type) + + screen.icon_state = "[initial(screen.icon_state)][severity]" + screen.severity = severity + + screens[category] = screen + if(client && stat != DEAD) + client.screen += screen + return screen + +/mob/proc/clear_fullscreen(category, animated = 10) + var/obj/screen/fullscreen/screen = screens[category] + if(!screen) + return + + screens -= category + + if(animated) + spawn(0) + animate(screen, alpha = 0, time = animated) + sleep(animated) + if(client) + client.screen -= screen + qdel(screen) + else + if(client) + client.screen -= screen + qdel(screen) + +/mob/proc/clear_fullscreens() + for(var/category in screens) + clear_fullscreen(category) + +/mob/proc/hide_fullscreens() + if(client) + for(var/category in screens) + client.screen -= screens[category] + +/mob/proc/reload_fullscreen() + if(client && stat != DEAD) //dead mob do not see any of the fullscreen overlays that he has. + for(var/category in screens) + client.screen |= screens[category] + +/obj/screen/fullscreen + icon = 'icons/mob/screen_full.dmi' + icon_state = "default" + screen_loc = "CENTER-7,CENTER-7" + layer = FULLSCREEN_LAYER + mouse_opacity = 0 + var/severity = 0 + +/obj/screen/fullscreen/Destroy() + severity = 0 + return ..() + +/obj/screen/fullscreen/brute + icon_state = "brutedamageoverlay" + layer = DAMAGE_LAYER + +/obj/screen/fullscreen/oxy + icon_state = "oxydamageoverlay" + layer = DAMAGE_LAYER + +/obj/screen/fullscreen/crit + icon_state = "passage" + layer = CRIT_LAYER + +/obj/screen/fullscreen/blind + icon_state = "blackimageoverlay" + layer = BLIND_LAYER + +/obj/screen/fullscreen/impaired + icon_state = "impairedoverlay" + +/obj/screen/fullscreen/blurry + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "blurry" + +/obj/screen/fullscreen/flash + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "flash" + +/obj/screen/fullscreen/flash/noise + icon_state = "noise" + +/obj/screen/fullscreen/high + icon = 'icons/mob/screen1.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "druggy" + +#undef FULLSCREEN_LAYER +#undef BLIND_LAYER +#undef DAMAGE_LAYER +#undef CRIT_LAYER \ No newline at end of file diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 1968864792..45c6f7e277 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -6,12 +6,14 @@ var/datum/global_hud/global_hud = new() var/list/global_huds = list( global_hud.druggy, global_hud.blurry, + global_hud.whitense, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, - global_hud.science) + global_hud.science + ) /datum/hud/var/obj/screen/grab_intent /datum/hud/var/obj/screen/hurt_intent @@ -21,6 +23,7 @@ var/list/global_huds = list( /datum/global_hud var/obj/screen/druggy var/obj/screen/blurry + var/obj/screen/whitense var/list/vimpaired var/list/darkMask var/obj/screen/nvg @@ -53,6 +56,14 @@ var/list/global_huds = list( blurry.layer = 17 blurry.mouse_opacity = 0 + //static overlay effect for cameras and the like + whitense = new /obj/screen() + whitense.screen_loc = ui_entire_screen + whitense.icon = 'icons/effects/static.dmi' + whitense.icon_state = "1 light" + whitense.layer = 17 + whitense.mouse_opacity = 0 + nvg = setup_overlay("nvg_hud") thermal = setup_overlay("thermal_hud") meson = setup_overlay("meson_hud") @@ -260,9 +271,9 @@ datum/hud/New(mob/owner) if(ishuman(mymob)) human_hud(ui_style, ui_color, ui_alpha, mymob) // Pass the player the UI style chosen in preferences else if(isrobot(mymob)) - robot_hud() + robot_hud(ui_style, ui_color, ui_alpha, mymob) else if(isbrain(mymob)) - brain_hud(ui_style) + mymob.instantiate_hud(src) else if(isalien(mymob)) larva_hud() else if(isslime(mymob)) @@ -375,3 +386,9 @@ datum/hud/New(mob/owner) hud_used.hidden_inventory_update() hud_used.persistant_inventory_update() update_action_buttons() + +/mob/proc/add_click_catcher() + client.screen += client.void + +/mob/new_player/add_click_catcher() + return \ No newline at end of file diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index bf894f859c..db161755ae 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -162,7 +162,7 @@ inv_box.name = "r_hand" inv_box.icon = ui_style inv_box.icon_state = "r_hand_inactive" - if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use + if(!target.hand) //This being 0 or null means the right hand is in use inv_box.icon_state = "r_hand_active" inv_box.screen_loc = ui_rhand inv_box.slot_id = slot_r_hand @@ -177,7 +177,7 @@ inv_box.name = "l_hand" inv_box.icon = ui_style inv_box.icon_state = "l_hand_inactive" - if(mymob && mymob.hand) //This being 1 means the left hand is in use + if(target.hand) //This being 1 means the left hand is in use inv_box.icon_state = "l_hand_active" inv_box.screen_loc = ui_lhand inv_box.slot_id = slot_l_hand @@ -313,31 +313,6 @@ mymob.wiz_energy_display.icon_state = "wiz_energy" hud_elements |= mymob.wiz_energy_display - mymob.blind = new /obj/screen() - mymob.blind.icon = 'icons/mob/screen1_full.dmi' - mymob.blind.icon_state = "blackimageoverlay" - mymob.blind.name = " " - mymob.blind.screen_loc = "1,1" - mymob.blind.mouse_opacity = 0 - mymob.blind.layer = 0 - hud_elements |= mymob.blind - - mymob.damageoverlay = new /obj/screen() - mymob.damageoverlay.icon = 'icons/mob/screen1_full.dmi' - mymob.damageoverlay.icon_state = "oxydamageoverlay0" - mymob.damageoverlay.name = "dmg" - mymob.damageoverlay.screen_loc = "1,1" - mymob.damageoverlay.mouse_opacity = 0 - mymob.damageoverlay.layer = 18.1 //The black screen overlay sets layer to 18 to display it, this one has to be just on top. - hud_elements |= mymob.damageoverlay - - mymob.flash = new /obj/screen() - mymob.flash.icon = ui_style - mymob.flash.icon_state = "blank" - mymob.flash.name = "flash" - mymob.flash.screen_loc = ui_entire_screen - mymob.flash.layer = 17 - hud_elements |= mymob.flash mymob.pain = new /obj/screen( null ) @@ -371,11 +346,12 @@ mymob.radio_use_icon.color = ui_color mymob.radio_use_icon.alpha = ui_alpha - mymob.client.screen = null + mymob.client.screen = list() mymob.client.screen += hud_elements mymob.client.screen += src.adding + src.hotkeybuttons - inventory_shown = 0; + mymob.client.screen += mymob.client.void + inventory_shown = 0 return @@ -397,10 +373,7 @@ f_style = "Shaved" if(dna.species == "Human") //no more xenos losing ears/tentacles h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") - undershirt = null - underwear_top = null - underwear_bottom = null - socks = null + all_underwear.Cut() regenerate_icons() /obj/screen/ling @@ -416,7 +389,6 @@ /obj/screen/wizard/instability name = "instability" icon_state = "instability-1" - invisibility = 0 /obj/screen/wizard/energy name = "energy" diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm index d543b8b12a..71eff4a392 100644 --- a/code/_onclick/hud/movable_screen_objects.dm +++ b/code/_onclick/hud/movable_screen_objects.dm @@ -27,13 +27,13 @@ return //Split screen-loc up into X+Pixel_X and Y+Pixel_Y - var/list/screen_loc_params = text2list(PM["screen-loc"], ",") + var/list/screen_loc_params = splittext(PM["screen-loc"], ",") //Split X+Pixel_X up into list(X, Pixel_X) - var/list/screen_loc_X = text2list(screen_loc_params[1],":") + var/list/screen_loc_X = splittext(screen_loc_params[1],":") screen_loc_X[1] = encode_screen_X(text2num(screen_loc_X[1])) //Split Y+Pixel_Y up into list(Y, Pixel_Y) - var/list/screen_loc_Y = text2list(screen_loc_params[2],":") + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") screen_loc_Y[1] = encode_screen_Y(text2num(screen_loc_Y[1])) if(snap2grid) //Discard Pixel Values diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm index 69896b163a..cab3e3bfca 100644 --- a/code/_onclick/hud/other_mobs.dm +++ b/code/_onclick/hud/other_mobs.dm @@ -5,14 +5,6 @@ /datum/hud/proc/ghost_hud() return -/datum/hud/proc/brain_hud(ui_style = 'icons/mob/screen1_Midnight.dmi') - mymob.blind = new /obj/screen() - mymob.blind.icon = 'icons/mob/screen1_full.dmi' - mymob.blind.icon_state = "blackimageoverlay" - mymob.blind.name = " " - mymob.blind.screen_loc = "1,1" - mymob.blind.layer = 0 - /datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi') blobpwrdisplay = new /obj/screen() @@ -27,9 +19,10 @@ blobhealthdisplay.screen_loc = ui_internal blobhealthdisplay.layer = 20 - mymob.client.screen = null + mymob.client.screen = list() mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay) + mymob.client.screen += mymob.client.void /datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi') @@ -94,8 +87,9 @@ src.adding += using hurt_intent = using - mymob.client.screen = null + mymob.client.screen = list() mymob.client.screen += src.adding + mymob.client.screen += mymob.client.void return @@ -114,13 +108,6 @@ else if(istype(mymob,/mob/living/simple_animal/construct/harvester)) constructtype = "harvester" - mymob.flash = new /obj/screen() - mymob.flash.icon = 'icons/mob/screen1.dmi' - mymob.flash.icon_state = "blank" - mymob.flash.name = "flash" - mymob.flash.screen_loc = ui_entire_screen - mymob.flash.layer = 17 - if(constructtype) mymob.fire = new /obj/screen() mymob.fire.icon = 'icons/mob/screen1_construct.dmi' @@ -151,6 +138,7 @@ mymob.purged.name = "purged" mymob.purged.screen_loc = ui_construct_purge - mymob.client.screen = null + mymob.client.screen = list() - mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged, mymob.flash) + mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged) + mymob.client.screen += mymob.client.void diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 95f8f3c9d3..ff0d8cdd5b 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -1,7 +1,20 @@ var/obj/screen/robot_inventory +/* +/mob/living/silicon/robot/instantiate_hud(var/datum/hud/HUD, var/ui_style, var/ui_color, var/ui_alpha) + HUD.robot_hud(ui_style, ui_color, ui_alpha, src)*/ +/datum/hud/proc/robot_hud(ui_style='icons/mob/screen1_robot.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255, var/mob/living/silicon/robot/target) +/* var/datum/hud_data/hud_data + if(!istype(target)) + hud_data = new() -/datum/hud/proc/robot_hud() + if(hud_data.icon) + ui_style = hud_data.icon*/ + + if(ui_style == 'icons/mob/screen/minimalist.dmi') + ui_style = 'icons/mob/screen1_robot_minimalist.dmi' + else + ui_style = 'icons/mob/screen1_robot.dmi' src.adding = list() src.other = list() @@ -12,7 +25,9 @@ var/obj/screen/robot_inventory using = new /obj/screen() using.name = "radio" using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style + using.color = ui_color + using.alpha = ui_alpha using.icon_state = "radio" using.screen_loc = ui_movi using.layer = 20 @@ -23,7 +38,9 @@ var/obj/screen/robot_inventory using = new /obj/screen() using.name = "module1" using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style + using.color = ui_color + using.alpha = ui_alpha using.icon_state = "inv1" using.screen_loc = ui_inv1 using.layer = 20 @@ -33,7 +50,9 @@ var/obj/screen/robot_inventory using = new /obj/screen() using.name = "module2" using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style + using.color = ui_color + using.alpha = ui_alpha using.icon_state = "inv2" using.screen_loc = ui_inv2 using.layer = 20 @@ -43,7 +62,9 @@ var/obj/screen/robot_inventory using = new /obj/screen() using.name = "module3" using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style + using.color = ui_color + using.alpha = ui_alpha using.icon_state = "inv3" using.screen_loc = ui_inv3 using.layer = 20 @@ -56,7 +77,8 @@ var/obj/screen/robot_inventory using = new /obj/screen() using.name = "act_intent" using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style + using.alpha = ui_alpha using.icon_state = mymob.a_intent using.screen_loc = ui_acti using.layer = 20 @@ -65,47 +87,60 @@ var/obj/screen/robot_inventory //Cell mymob:cells = new /obj/screen() - mymob:cells.icon = 'icons/mob/screen1_robot.dmi' + mymob:cells.icon = ui_style mymob:cells.icon_state = "charge-empty" + mymob:cells.alpha = ui_alpha mymob:cells.name = "cell" mymob:cells.screen_loc = ui_toxin + src.other += mymob:cells //Health mymob.healths = new /obj/screen() - mymob.healths.icon = 'icons/mob/screen1_robot.dmi' + mymob.healths.icon = ui_style mymob.healths.icon_state = "health0" + mymob.healths.alpha = ui_alpha mymob.healths.name = "health" mymob.healths.screen_loc = ui_borg_health + src.other += mymob.healths //Installed Module mymob.hands = new /obj/screen() - mymob.hands.icon = 'icons/mob/screen1_robot.dmi' + mymob.hands.icon = ui_style mymob.hands.icon_state = "nomod" + mymob.hands.alpha = ui_alpha mymob.hands.name = "module" mymob.hands.screen_loc = ui_borg_module + src.other += mymob.hands //Module Panel using = new /obj/screen() using.name = "panel" - using.icon = 'icons/mob/screen1_robot.dmi' + using.icon = ui_style using.icon_state = "panel" + using.alpha = ui_alpha using.screen_loc = ui_borg_panel using.layer = 19 src.adding += using //Store mymob.throw_icon = new /obj/screen() - mymob.throw_icon.icon = 'icons/mob/screen1_robot.dmi' + mymob.throw_icon.icon = ui_style mymob.throw_icon.icon_state = "store" + mymob.throw_icon.alpha = ui_alpha + mymob.throw_icon.color = ui_color mymob.throw_icon.name = "store" mymob.throw_icon.screen_loc = ui_borg_store + src.other += mymob.throw_icon //Inventory robot_inventory = new /obj/screen() robot_inventory.name = "inventory" - robot_inventory.icon = 'icons/mob/screen1_robot.dmi' + robot_inventory.icon = ui_style robot_inventory.icon_state = "inventory" + robot_inventory.alpha = ui_alpha + robot_inventory.color = ui_color robot_inventory.screen_loc = ui_borg_inventory + src.other += robot_inventory //Temp mymob.bodytemp = new /obj/screen() @@ -113,54 +148,56 @@ var/obj/screen/robot_inventory mymob.bodytemp.name = "body temperature" mymob.bodytemp.screen_loc = ui_temp - mymob.oxygen = new /obj/screen() - mymob.oxygen.icon = 'icons/mob/screen1_robot.dmi' + mymob.oxygen.icon = ui_style mymob.oxygen.icon_state = "oxy0" + mymob.oxygen.alpha = ui_alpha mymob.oxygen.name = "oxygen" mymob.oxygen.screen_loc = ui_oxygen + src.other += mymob.oxygen mymob.fire = new /obj/screen() - mymob.fire.icon = 'icons/mob/screen1_robot.dmi' + mymob.fire.icon = ui_style mymob.fire.icon_state = "fire0" + mymob.fire.alpha = ui_alpha mymob.fire.name = "fire" mymob.fire.screen_loc = ui_fire + src.other += mymob.fire mymob.pullin = new /obj/screen() - mymob.pullin.icon = 'icons/mob/screen1_robot.dmi' + mymob.pullin.icon = ui_style mymob.pullin.icon_state = "pull0" + mymob.pullin.alpha = ui_alpha + mymob.pullin.color = ui_color mymob.pullin.name = "pull" mymob.pullin.screen_loc = ui_borg_pull - - mymob.blind = new /obj/screen() - mymob.blind.icon = 'icons/mob/screen1_full.dmi' - mymob.blind.icon_state = "blackimageoverlay" - mymob.blind.name = " " - mymob.blind.screen_loc = "1,1" - mymob.blind.layer = 0 - - mymob.flash = new /obj/screen() - mymob.flash.icon = 'icons/mob/screen1_robot.dmi' - mymob.flash.icon_state = "blank" - mymob.flash.name = "flash" - mymob.flash.screen_loc = ui_entire_screen - mymob.flash.layer = 17 + src.other += mymob.pullin mymob.zone_sel = new /obj/screen/zone_sel() - mymob.zone_sel.icon = 'icons/mob/screen1_robot.dmi' + mymob.zone_sel.icon = ui_style + mymob.zone_sel.alpha = ui_alpha mymob.zone_sel.overlays.Cut() mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") //Handle the gun settings buttons mymob.gun_setting_icon = new /obj/screen/gun/mode(null) + mymob.gun_setting_icon.icon = ui_style + mymob.gun_setting_icon.alpha = ui_alpha mymob.item_use_icon = new /obj/screen/gun/item(null) + mymob.item_use_icon.icon = ui_style + mymob.item_use_icon.alpha = ui_alpha mymob.gun_move_icon = new /obj/screen/gun/move(null) + mymob.gun_move_icon.icon = ui_style + mymob.gun_move_icon.alpha = ui_alpha mymob.radio_use_icon = new /obj/screen/gun/radio(null) + mymob.radio_use_icon.icon = ui_style + mymob.radio_use_icon.alpha = ui_alpha - mymob.client.screen = null + mymob.client.screen = list() - mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, robot_inventory, mymob.gun_setting_icon) + mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, robot_inventory, mymob.gun_setting_icon) mymob.client.screen += src.adding + src.other + mymob.client.screen += mymob.client.void return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index cbb49166c0..522db6e1c4 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -420,7 +420,7 @@ var/mob/living/silicon/ai/AI = usr AI.toggle_camera_light() - if("Crew Monitorting") + if("Crew Monitoring") if(isAI(usr)) var/mob/living/silicon/ai/AI = usr AI.subsystem_crew_monitor() diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm index a59474749a..3365a4384d 100644 --- a/code/_onclick/hud/spell_screen_objects.dm +++ b/code/_onclick/hud/spell_screen_objects.dm @@ -57,15 +57,15 @@ overlays.Add(open_state) /obj/screen/movable/spell_master/proc/open_spellmaster() - var/list/screen_loc_xy = text2list(screen_loc,",") + var/list/screen_loc_xy = splittext(screen_loc,",") //Create list of X offsets - var/list/screen_loc_X = text2list(screen_loc_xy[1],":") + var/list/screen_loc_X = splittext(screen_loc_xy[1],":") var/x_position = decode_screen_X(screen_loc_X[1]) var/x_pix = screen_loc_X[2] //Create list of Y offsets - var/list/screen_loc_Y = text2list(screen_loc_xy[2],":") + var/list/screen_loc_Y = splittext(screen_loc_xy[2],":") var/y_position = decode_screen_Y(screen_loc_Y[1]) var/y_pix = screen_loc_Y[2] diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 093975051b..8c55b0d850 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -1,40 +1,59 @@ +/* +=== Item Click Call Sequences === +These are the default click code call sequences used when clicking on stuff with an item. + +Atoms: + +mob/ClickOn() calls the item's resolve_attackby() proc. +item/resolve_attackby() calls the target atom's attackby() proc. + +Mobs: + +mob/living/attackby() after checking for surgery, calls the item's attack() proc. +item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself. +mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit. + +Item Hit Effects: + +item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to +avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent). +*/ // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) return +//I would prefer to rename this to attack(), but that would involve touching hundreds of files. +/obj/item/proc/resolve_attackby(atom/A, mob/user) + add_fingerprint(user) + return A.attackby(src, user) + // No comment /atom/proc/attackby(obj/item/W, mob/user) return /atom/movable/attackby(obj/item/W, mob/user) - if(!(W.flags&NOBLUDGEON)) + if(!(W.flags & NOBLUDGEON)) visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(istype(I) && ismob(user)) - I.attack(src, user) - + if(!ismob(user)) + return 0 + if(can_operate(src) && I.do_surgery(src,user)) //Surgery + return 1 + return I.attack(src, user, user.zone_sel.selecting) // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters) return -//TODO: refactor mob attack code. -/* -Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here. -leave attackby() as handling the general case of "using an item on a mob" -attackby() will decide to call attacked_by() or not. -attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm" -attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing. -attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now). -*/ - -/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - - if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 +//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files. +/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone) + if(!force || (flags & NOBLUDGEON)) + return 0 + if(M == user && user.a_intent != I_HURT) + return 0 ///////////////////////// user.lastattacked = M @@ -46,50 +65,22 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) ///////////////////////// - // Attacking someone with a weapon while they are neck-grabbed - if(user.a_intent == I_HURT) - for(var/obj/item/weapon/grab/G in M.grabbed_by) - if(G.assailant == user && G.state >= GRAB_NECK) - M.attack_throat(src, G, user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + var/hit_zone = M.resolve_item_attack(src, user, target_zone) + if(hit_zone) + apply_hit_effect(M, user, hit_zone) + + return 1 + +//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result +/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if(hitsound) + playsound(loc, hitsound, 50, 1, -1) + var/power = force if(HULK in user.mutations) power *= 2 + return target.hit_with_weapon(src, user, power, hit_zone) - // TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z - user.do_attack_animation(M) - user.break_cloak() - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - - // Handle striking to cripple. - var/dislocation_str - if(user.a_intent == I_DISARM) - dislocation_str = H.attack_joint(src, user, def_zone) - if(H.attacked_by(src, user, def_zone) && hitsound) - playsound(loc, hitsound, 50, 1, -1) - spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves. - if(dislocation_str) user.visible_message("[dislocation_str]") - return 1 - return 0 - else - if(attack_verb.len) - user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") - else - user.visible_message("[M] has been attacked with [src] by [user]!") - - if (hitsound) - playsound(loc, hitsound, 50, 1, -1) - switch(damtype) - if("brute") - M.take_organ_damage(power) - if(prob(33)) // Added blood for whacking non-humans too - var/turf/simulated/location = get_turf(M) - if(istype(location)) location.add_blood_floor(M) - if("fire") - if (!(COLD_RESISTANCE in M.mutations)) - M.take_organ_damage(0, power) - M << "Aargh it burns!" - M.updatehealth() - add_fingerprint(user) - return 1 diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index d1c0b7b505..f34a68a742 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -1,5 +1,5 @@ /client/var/inquisitive_ghost = 1 -/mob/dead/observer/verb/toggle_inquisition() // warning: unexpected inquisition +/mob/observer/dead/verb/toggle_inquisition() // warning: unexpected inquisition set name = "Toggle Inquisitiveness" set desc = "Sets whether your ghost examines everything on click by default" set category = "Ghost" @@ -10,25 +10,24 @@ else src << "You will no longer examine things you click on." -/mob/dead/observer/DblClickOn(var/atom/A, var/params) +/mob/observer/dead/DblClickOn(var/atom/A, var/params) if(client.buildmode) build_click(src, client.buildmode, params, A) return if(can_reenter_corpse && mind && mind.current) if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it reenter_corpse() // (cloning scanner, body bag, closet, mech, etc) - return // seems legit. + return // Things you might plausibly want to follow - if((ismob(A) && A != src) || istype(A,/obj/singularity)) + if(istype(A,/atom/movable)) ManualFollow(A) - // Otherwise jump else following = null forceMove(get_turf(A)) -/mob/dead/observer/ClickOn(var/atom/A, var/params) +/mob/observer/dead/ClickOn(var/atom/A, var/params) if(client.buildmode) build_click(src, client.buildmode, params, A) return @@ -39,7 +38,7 @@ A.attack_ghost(src) // Oh by the way this didn't work with old click code which is why clicking shit didn't spam you -/atom/proc/attack_ghost(mob/dead/observer/user as mob) +/atom/proc/attack_ghost(mob/observer/dead/user as mob) if(user.client && user.client.inquisitive_ghost) user.examinate(src) return diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 95c77d6708..ac07b8d075 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -55,6 +55,7 @@ if(!..()) return 0 + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) A.attack_generic(src,rand(5,6),"bitten") /* @@ -76,6 +77,9 @@ Feedstop() return + //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/mob/living/M = A if (istype(M)) @@ -88,7 +92,7 @@ if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime)) if(ishuman(M)) var/mob/living/carbon/human/H = M - stunprob *= H.species.siemens_coefficient + stunprob *= max(H.species.siemens_coefficient,0) switch(power * 10) @@ -144,6 +148,7 @@ custom_emote(1,"[friendly] [A]!") return + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/damage = rand(melee_damage_lower, melee_damage_upper) if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound) playsound(loc, attack_sound, 50, 1, 1) diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index 354e377121..d416475a27 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -107,20 +107,11 @@ var/const/tk_maxrange = 15 return var/d = get_dist(user, target) - if(focus) d = max(d,get_dist(user,focus)) // whichever is further - switch(d) - if(0) - ; - if(1 to 5) // not adjacent may mean blocked by window - if(!proximity) - user.setMoveCooldown(2) - if(5 to 7) - user.setMoveCooldown(5) - if(8 to tk_maxrange) - user.setMoveCooldown(10) - else - user << "Your mind won't reach that far." - return + if(focus) + d = max(d, get_dist(user, focus)) // whichever is further + if(d > tk_maxrange) + user << "Your mind won't reach that far." + return if(!focus) focus_object(target, user) diff --git a/code/_unit_tests.dm b/code/_unit_tests.dm new file mode 100644 index 0000000000..88eebd5aec --- /dev/null +++ b/code/_unit_tests.dm @@ -0,0 +1,10 @@ +/* + * + * This file is used by Travis to indicate that Unit Tests are to be ran. + * Do not add anything but the UNIT_TEST definition here as it will be overwritten by Travis when running tests. + * + * + * Should you wish to edit set UNIT_TEST to 1 like so: + * #define UNIT_TEST 1 + */ +#define UNIT_TEST 0 diff --git a/code/controllers/ProcessScheduler/ProcessScheduler.dme b/code/controllers/ProcessScheduler/ProcessScheduler.dme deleted file mode 100644 index bf17734cc2..0000000000 --- a/code/controllers/ProcessScheduler/ProcessScheduler.dme +++ /dev/null @@ -1,32 +0,0 @@ -// DM Environment file for ProcessScheduler.dme. -// All manual changes should be made outside the BEGIN_ and END_ blocks. -// New source code should be placed in .dm files: choose File/New --> Code File. - -// BEGIN_INTERNALS -// END_INTERNALS - -// BEGIN_FILE_DIR -#define FILE_DIR . -// END_FILE_DIR - -// BEGIN_PREFERENCES -// END_PREFERENCES - -// BEGIN_INCLUDE -#include "core\_define.dm" -#include "core\_stubs.dm" -#include "core\process.dm" -#include "core\processScheduler.dm" -#include "core\updateQueue.dm" -#include "core\updateQueueWorker.dm" -#include "test\processSchedulerView.dm" -#include "test\testDyingUpdateQueueProcess.dm" -#include "test\testHarness.dm" -#include "test\testHungProcess.dm" -#include "test\testNiceProcess.dm" -#include "test\testSlowProcess.dm" -#include "test\testUpdateQueue.dm" -#include "test\testUpdateQueueProcess.dm" -#include "test\testZombieProcess.dm" -// END_INCLUDE - diff --git a/code/controllers/ProcessScheduler/core/_stubs.dm b/code/controllers/ProcessScheduler/core/_stubs.dm index 326fd29ac2..1aa2c8efb8 100644 --- a/code/controllers/ProcessScheduler/core/_stubs.dm +++ b/code/controllers/ProcessScheduler/core/_stubs.dm @@ -4,15 +4,7 @@ * This file contains constructs that the process scheduler expects to exist * in a standard ss13 fork. */ -/* -/** - * message_admins - * - * sends a message to admins - */ -/proc/message_admins(msg) - world << msg -*/ + /** * logTheThing * @@ -22,17 +14,6 @@ */ /proc/logTheThing(type, source, target, text, diaryType) if(diaryType) - world << "Diary: \[[diaryType]:[type]] [text]" + log_debug("Diary: \[[diaryType]:[type]] [text]") else - world << "Log: \[[type]] [text]" - -/** - * var/disposed - * - * In goonstation, disposed is set to 1 after an object enters the delete queue - * or the object is placed in an object pool (effectively out-of-play so to speak) - */ -/datum/var/disposed -// Garbage collection (controller). -/datum/var/gcDestroyed -/datum/var/timeDestroyed \ No newline at end of file + log_debug("Log: \[[type]] [text]") diff --git a/code/controllers/ProcessScheduler/core/process.dm b/code/controllers/ProcessScheduler/core/process.dm index 1f27f4c1de..b7767c367f 100644 --- a/code/controllers/ProcessScheduler/core/process.dm +++ b/code/controllers/ProcessScheduler/core/process.dm @@ -48,7 +48,7 @@ // This controls how often the process will yield (call sleep(0)) while it is running. // Every concurrent process should sleep periodically while running in order to allow other // processes to execute concurrently. - var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL + var/tmp/sleep_interval // hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME @@ -59,20 +59,20 @@ // hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process. var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME - // cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag) - var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD - // How many times in the current run has the process deferred work till the next tick? var/tmp/cpu_defer_count = 0 + // How many SCHECKs have been skipped (to limit btime calls) + var/tmp/calls_since_last_scheck = 0 + /** * recordkeeping vars */ - // Records the time (server ticks) at which the process last finished sleeping + // Records the time (1/10s timeofday) at which the process last finished sleeping var/tmp/last_slept = 0 - // Records the time (s-ticks) at which the process last began running + // Records the time (1/10s timeofday) at which the process last began running var/tmp/run_start = 0 // Records the number of times this process has been killed and restarted @@ -85,26 +85,33 @@ var/tmp/last_object -datum/controller/process/New(var/datum/controller/processScheduler/scheduler) + // Counts the number of times an exception has occurred; gets reset after 10 + var/tmp/list/exceptions = list() + + // Number of deciseconds to delay before starting the process + var/start_delay = 0 + +/datum/controller/process/New(var/datum/controller/processScheduler/scheduler) ..() main = scheduler previousStatus = "idle" idle() name = "process" schedule_interval = 50 - sleep_interval = 2 + sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL last_slept = 0 run_start = 0 ticks = 0 last_task = 0 last_object = null -datum/controller/process/proc/started() +/datum/controller/process/proc/started() + var/timeofhour = TimeOfHour // Initialize last_slept so we can know when to sleep - last_slept = world.timeofday + last_slept = timeofhour // Initialize run_start so we can detect hung processes. - run_start = world.timeofday + run_start = timeofhour // Initialize defer count cpu_defer_count = 0 @@ -114,65 +121,65 @@ datum/controller/process/proc/started() onStart() -datum/controller/process/proc/finished() +/datum/controller/process/proc/finished() ticks++ idle() main.processFinished(src) onFinish() -datum/controller/process/proc/doWork() +/datum/controller/process/proc/doWork() -datum/controller/process/proc/setup() +/datum/controller/process/proc/setup() -datum/controller/process/proc/process() +/datum/controller/process/proc/process() started() doWork() finished() -datum/controller/process/proc/running() +/datum/controller/process/proc/running() idle = 0 queued = 0 running = 1 hung = 0 setStatus(PROCESS_STATUS_RUNNING) -datum/controller/process/proc/idle() +/datum/controller/process/proc/idle() queued = 0 running = 0 idle = 1 hung = 0 setStatus(PROCESS_STATUS_IDLE) -datum/controller/process/proc/queued() +/datum/controller/process/proc/queued() idle = 0 running = 0 queued = 1 hung = 0 setStatus(PROCESS_STATUS_QUEUED) -datum/controller/process/proc/hung() +/datum/controller/process/proc/hung() hung = 1 setStatus(PROCESS_STATUS_HUNG) -datum/controller/process/proc/handleHung() +/datum/controller/process/proc/handleHung() + var/timeofhour = TimeOfHour var/datum/lastObj = last_object var/lastObjType = "null" if(istype(lastObj)) lastObjType = lastObj.type - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < run_start) - run_start -= 864000 - - var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(world.timeofday - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < run_start) + run_start -= 36000 + var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(timeofhour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" logTheThing("debug", null, null, msg) logTheThing("diary", null, null, msg, "debug") message_admins(msg) main.restartProcess(src.name) -datum/controller/process/proc/kill() +/datum/controller/process/proc/kill() if (!killed) var/msg = "[name] process was killed at tick #[ticks]." logTheThing("debug", null, null, msg) @@ -182,59 +189,68 @@ datum/controller/process/proc/kill() // Allow inheritors to clean up if needed onKill() - killed = TRUE + // This should del + del(src) - del(src) // This should del - -datum/controller/process/proc/scheck(var/tickId = 0) +// Do not call this directly - use SHECK or SCHECK_EVERY +/datum/controller/process/proc/sleepCheck(var/tickId = 0) + calls_since_last_scheck = 0 if (killed) // The kill proc is the only place where killed is set. // The kill proc should have deleted this datum, and all sleeping procs that are // owned by it. CRASH("A killed process is still running somehow...") + if (hung) + // This will only really help if the doWork proc ends up in an infinite loop. + handleHung() + CRASH("Process [name] hung and was restarted.") - // For each tick the process defers, it increments the cpu_defer_count so we don't - // defer indefinitely - if (world.cpu >= cpu_threshold + cpu_defer_count * 10) - sleep(1) + if (main.getCurrentTickElapsedTime() > main.timeAllowance) + sleep(world.tick_lag) cpu_defer_count++ - last_slept = world.timeofday + last_slept = TimeOfHour else - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < last_slept) - last_slept -= 864000 + var/timeofhour = TimeOfHour + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < last_slept) + last_slept -= 36000 - if (world.timeofday > last_slept + sleep_interval) - // If we haven't slept in sleep_interval ticks, sleep to allow other work to proceed. + if (timeofhour > last_slept + sleep_interval) + // If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed. sleep(0) - last_slept = world.timeofday + last_slept = TimeOfHour -datum/controller/process/proc/update() +/datum/controller/process/proc/update() // Clear delta if(previousStatus != status) setStatus(status) var/elapsedTime = getElapsedTime() - if (elapsedTime > hang_restart_time) + if (hung) + handleHung() + return + else if (elapsedTime > hang_restart_time) hung() else if (elapsedTime > hang_alert_time) setStatus(PROCESS_STATUS_PROBABLY_HUNG) else if (elapsedTime > hang_warning_time) setStatus(PROCESS_STATUS_MAYBE_HUNG) -datum/controller/process/proc/getElapsedTime() - if (world.timeofday < run_start) - return world.timeofday - (run_start - 864000) - return world.timeofday - run_start -datum/controller/process/proc/tickDetail() +/datum/controller/process/proc/getElapsedTime() + var/timeofhour = TimeOfHour + if (timeofhour < run_start) + return timeofhour - (run_start - 36000) + return timeofhour - run_start + +/datum/controller/process/proc/tickDetail() return -datum/controller/process/proc/getContext() +/datum/controller/process/proc/getContext() return "[name][main.averageRunTime(src)][main.last_run_time[src]][main.highest_run_time[src]][ticks]\n" -datum/controller/process/proc/getContextData() +/datum/controller/process/proc/getContextData() return list( "name" = name, "averageRunTime" = main.averageRunTime(src), @@ -246,10 +262,10 @@ datum/controller/process/proc/getContextData() "disabled" = disabled ) -datum/controller/process/proc/getStatus() +/datum/controller/process/proc/getStatus() return status -datum/controller/process/proc/getStatusText(var/s = 0) +/datum/controller/process/proc/getStatusText(var/s = 0) if(!s) s = status switch(s) @@ -268,21 +284,21 @@ datum/controller/process/proc/getStatusText(var/s = 0) else return "UNKNOWN" -datum/controller/process/proc/getPreviousStatus() +/datum/controller/process/proc/getPreviousStatus() return previousStatus -datum/controller/process/proc/getPreviousStatusText() +/datum/controller/process/proc/getPreviousStatusText() return getStatusText(previousStatus) -datum/controller/process/proc/setStatus(var/newStatus) +/datum/controller/process/proc/setStatus(var/newStatus) previousStatus = status status = newStatus -datum/controller/process/proc/setLastTask(var/task, var/object) +/datum/controller/process/proc/setLastTask(var/task, var/object) last_task = task last_object = object -datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) main = target.main name = target.name schedule_interval = target.schedule_interval @@ -295,28 +311,62 @@ datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target last_object = target.last_object copyStateFrom(target) -datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) -datum/controller/process/proc/onKill() +/datum/controller/process/proc/onKill() -datum/controller/process/proc/onStart() +/datum/controller/process/proc/onStart() -datum/controller/process/proc/onFinish() +/datum/controller/process/proc/onFinish() -datum/controller/process/proc/disable() +/datum/controller/process/proc/disable() disabled = 1 -datum/controller/process/proc/enable() +/datum/controller/process/proc/enable() disabled = 0 +/datum/controller/process/proc/getAverageRunTime() + return main.averageRunTime(src) /datum/controller/process/proc/getLastRunTime() return main.getProcessLastRunTime(src) +/datum/controller/process/proc/getHighestRunTime() + return main.getProcessHighestRunTime(src) + /datum/controller/process/proc/getTicks() return ticks -/datum/controller/process/proc/getStatName() - return name +/datum/controller/process/proc/statProcess() + var/averageRunTime = round(getAverageRunTime(), 0.1)/10 + var/lastRunTime = round(getLastRunTime(), 0.1)/10 + var/highestRunTime = round(getHighestRunTime(), 0.1)/10 + stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [cpu_defer_count]") -/datum/controller/process/proc/getTickTime() - return "#[getTicks()]\t- [getLastRunTime()]" +/datum/controller/process/proc/catchException(var/exception/e, var/thrower) + var/etext = "[e]" + var/eid = "[e]" // Exception ID, for tracking repeated exceptions + var/ptext = "" // "processing..." text, for what was being processed (if known) + if(istype(e)) + etext += " in [e.file], line [e.line]" + eid = "[e.file]:[e.line]" + if(eid in exceptions) + if(exceptions[eid]++ >= 10) + return + else + exceptions[eid] = 1 + if(istype(thrower, /datum)) + var/datum/D = thrower + ptext = " processing [D.type]" + if(istype(thrower, /atom)) + var/atom/A = thrower + ptext += " ([A]) ([A.x],[A.y],[A.z])" + log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]") + if(exceptions[eid] >= 10) + log_to_dd("This exception will now be ignored for ten minutes.") + spawn(6000) + exceptions[eid] = 0 + +/datum/controller/process/proc/catchBadType(var/datum/caught) + if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed)) + return // Only bother with types we can identify and that don't belong + catchException("Type [caught.type] does not belong in process' queue") \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/processScheduler.dm b/code/controllers/ProcessScheduler/core/processScheduler.dm index 1be2404593..bde79fba07 100644 --- a/code/controllers/ProcessScheduler/core/processScheduler.dm +++ b/code/controllers/ProcessScheduler/core/processScheduler.dm @@ -17,7 +17,10 @@ var/global/datum/controller/processScheduler/processScheduler // Process name -> process object map var/tmp/datum/controller/process/list/nameToProcessMap = new - // Process last start times + // Process last queued times (world time) + var/tmp/datum/controller/process/list/last_queued = new + + // Process last start times (real time) var/tmp/datum/controller/process/list/last_start = new // Process last run durations @@ -29,8 +32,8 @@ var/global/datum/controller/processScheduler/processScheduler // Process highest run time var/tmp/datum/controller/process/list/highest_run_time = new - // Sleep 1 tick -- This may be too aggressive. - var/tmp/scheduler_sleep_interval = 1 + // How long to sleep between runs (set to tick_lag in New) + var/tmp/scheduler_sleep_interval // Controls whether the scheduler is running or not var/tmp/isRunning = 0 @@ -38,6 +41,25 @@ var/global/datum/controller/processScheduler/processScheduler // Setup for these processes will be deferred until all the other processes are set up. var/tmp/list/deferredSetupList = new + var/tmp/currentTick = 0 + + var/tmp/currentTickStart = 0 + + var/tmp/timeAllowance = 0 + + var/tmp/cpuAverage = 0 + + var/tmp/timeAllowanceMax = 0 + +/datum/controller/processScheduler/New() + ..() + // When the process scheduler is first new'd, tick_lag may be wrong, so these + // get re-initialized when the process scheduler is started. + // (These are kept here for any processes that decide to process before round start) + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + /** * deferSetupFor * @param path processPath @@ -57,7 +79,7 @@ var/global/datum/controller/processScheduler/processScheduler var/process // Add all the processes we can find, except for the ticker - for (process in typesof(/datum/controller/process) - /datum/controller/process) + for (process in subtypesof(/datum/controller/process)) if (!(process in deferredSetupList)) addProcess(new process(src)) @@ -66,11 +88,22 @@ var/global/datum/controller/processScheduler/processScheduler /datum/controller/processScheduler/proc/start() isRunning = 1 + // tick_lag will have been set by now, so re-initialize these + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + updateStartDelays() spawn(0) process() /datum/controller/processScheduler/proc/process() + updateCurrentTickData() + + for(var/i=world.tick_lag,i last_start[p] + p.schedule_interval) + if (world.time >= last_queued[p] + p.schedule_interval) setQueuedProcessState(p) /datum/controller/processScheduler/proc/runQueuedProcesses() @@ -176,6 +201,10 @@ var/global/datum/controller/processScheduler/processScheduler nameToProcessMap[newProcess.name] = newProcess +/datum/controller/processScheduler/proc/updateStartDelays() + for(var/datum/controller/process/p in processes) + if(p.start_delay) + last_queued[p] = world.time - p.start_delay /datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process) spawn(0) @@ -197,8 +226,6 @@ var/global/datum/controller/processScheduler/processScheduler if (!(process in idle)) idle += process - process.idle() - /datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process) if (process in running) running -= process @@ -218,21 +245,22 @@ var/global/datum/controller/processScheduler/processScheduler if (!(process in running)) running += process - process.running() - /datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null) if (isnull(time)) - time = world.timeofday - - last_start[process] = time + time = TimeOfHour + last_queued[process] = world.time + last_start[process] = time + else + last_queued[process] = (time == 0 ? 0 : world.time) + last_start[process] = time /datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null) if (isnull(time)) - time = world.timeofday + time = TimeOfHour // If world.timeofday has rolled over, then we need to adjust. if (time < last_start[process]) - last_start[process] -= 864000 + last_start[process] -= 36000 var/lastRunTime = time - last_start[process] @@ -273,6 +301,12 @@ var/global/datum/controller/processScheduler/processScheduler return t / c return c +/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) + return last_run_time[process] + +/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process) + return highest_run_time[process] + /datum/controller/processScheduler/proc/getStatusData() var/list/data = new @@ -310,11 +344,39 @@ var/global/datum/controller/processScheduler/processScheduler var/datum/controller/process/process = nameToProcessMap[processName] process.disable() -/datum/controller/processScheduler/proc/getProcess(var/name) - return nameToProcessMap[name] +/datum/controller/processScheduler/proc/getCurrentTickElapsedTime() + if (world.time > currentTick) + updateCurrentTickData() + return 0 + else + return TimeOfHour - currentTickStart -/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) - return last_run_time[process] +/datum/controller/processScheduler/proc/updateCurrentTickData() + if (world.time > currentTick) + // New tick! + currentTick = world.time + currentTickStart = TimeOfHour + updateTimeAllowance() + cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3 -/datum/controller/processScheduler/proc/getIsRunning() - return isRunning +/datum/controller/processScheduler/proc/updateTimeAllowance() + // Time allowance goes down linearly with world.cpu. + var/tmp/error = cpuAverage - 100 + var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error)) + + //timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1)) + timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta)) + +/datum/controller/processScheduler/proc/sign(var/x) + if (x == 0) + return 1 + return x / abs(x) + +/datum/controller/processScheduler/proc/statProcesses() + if(!isRunning) + stat("Processes", "Scheduler not running") + return + stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])") + stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA") + for(var/datum/controller/process/p in processes) + p.statProcess() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/updateQueue.dm b/code/controllers/ProcessScheduler/core/updateQueue.dm deleted file mode 100644 index 118b6692b5..0000000000 --- a/code/controllers/ProcessScheduler/core/updateQueue.dm +++ /dev/null @@ -1,127 +0,0 @@ -/** - * updateQueue.dm - */ - -#ifdef UPDATE_QUEUE_DEBUG -#define uq_dbg(text) world << text -#else -#define uq_dbg(text) -#endif -/datum/updateQueue - var/tmp/list/objects - var/tmp/previousStart - var/tmp/procName - var/tmp/list/arguments - var/tmp/datum/updateQueueWorker/currentWorker - var/tmp/workerTimeout - var/tmp/adjustedWorkerTimeout - var/tmp/currentKillCount - var/tmp/totalKillCount - -/datum/updateQueue/New(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - ..() - - uq_dbg("Update queue created.") - - // Init proc allows for recycling the worker. - init(objects = objects, procName = procName, arguments = arguments, workerTimeout = workerTimeout, inplace = inplace) - -/** - * init - * @param list objects objects to update - * @param text procName the proc to call on each item in the object list - * @param list arguments optional arguments to pass to the update proc - * @param number workerTimeout number of ticks to wait for an update to - finish before forking a new update worker - * @param bool inplace whether the updateQueue should make a copy of objects. - the internal list will be modified, so it is usually - a good idea to leave this alone. Default behavior is to - copy. - */ -/datum/updateQueue/proc/init(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - uq_dbg("Update queue initialization started.") - - if (!inplace) - // Make an internal copy of the list so we're not modifying the original. - initList(objects) - else - src.objects = objects - - // Init vars - src.procName = procName - src.arguments = arguments - src.workerTimeout = workerTimeout - - adjustedWorkerTimeout = workerTimeout - currentKillCount = 0 - totalKillCount = 0 - - uq_dbg("Update queue initialization finished. procName = '[procName]'") - -/datum/updateQueue/proc/initList(list/toCopy) - /** - * We will copy the list in reverse order, as our doWork proc - * will access them by popping an element off the end of the list. - * This ends up being quite a lot faster than taking elements off - * the head of the list. - */ - objects = new - - uq_dbg("Copying [toCopy.len] items for processing.") - - for(var/i=toCopy.len,i>0,) - objects.len++ - objects[objects.len] = toCopy[i--] - -/datum/updateQueue/proc/Run() - uq_dbg("Starting run...") - - startWorker() - while (istype(currentWorker) && !currentWorker.finished) - sleep(2) - checkWorker() - - uq_dbg("UpdateQueue completed run.") - -/datum/updateQueue/proc/checkWorker() - if(istype(currentWorker)) - // If world.timeofday has rolled over, then we need to adjust. - if(world.timeofday < currentWorker.lastStart) - currentWorker.lastStart -= 864000 - - if(world.timeofday - currentWorker.lastStart > adjustedWorkerTimeout) - // This worker is a bit slow, let's spawn a new one and kill the old one. - uq_dbg("Current worker is lagging... starting a new one.") - killWorker() - startWorker() - else // No worker! - uq_dbg("update queue ended up without a worker... starting a new one...") - startWorker() - -/datum/updateQueue/proc/startWorker() - // only run the worker if we have objects to work on - if(objects.len) - uq_dbg("Starting worker process.") - - // No need to create a fresh worker if we already have one... - if (istype(currentWorker)) - currentWorker.init(objects, procName, arguments) - else - currentWorker = new(objects, procName, arguments) - currentWorker.start() - else - uq_dbg("Queue is empty. No worker was started.") - currentWorker = null - -/datum/updateQueue/proc/killWorker() - // Kill the worker - currentWorker.kill() - currentWorker = null - // After we kill a worker, yield so that if the worker's been tying up the cpu, other stuff can immediately resume - sleep(-1) - currentKillCount++ - totalKillCount++ - if (currentKillCount >= 3) - uq_dbg("[currentKillCount] workers have been killed with a timeout of [adjustedWorkerTimeout]. Increasing worker timeout to compensate.") - adjustedWorkerTimeout++ - currentKillCount = 0 \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm b/code/controllers/ProcessScheduler/core/updateQueueWorker.dm deleted file mode 100644 index 66f66bbcc0..0000000000 --- a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm +++ /dev/null @@ -1,83 +0,0 @@ -datum/updateQueueWorker - var/tmp/list/objects - var/tmp/killed - var/tmp/finished - var/tmp/procName - var/tmp/list/arguments - var/tmp/lastStart - var/tmp/cpuThreshold - -datum/updateQueueWorker/New(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - ..() - uq_dbg("updateQueueWorker created.") - - init(objects, procName, arguments, cpuThreshold) - -datum/updateQueueWorker/proc/init(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - src.objects = objects - src.procName = procName - src.arguments = arguments - src.cpuThreshold = cpuThreshold - - killed = 0 - finished = 0 - -datum/updateQueueWorker/proc/doWork() - // If there's nothing left to execute or we were killed, mark finished and return. - if (!objects || !objects.len) return finished() - - lastStart = world.timeofday // Absolute number of ticks since the world started up - - var/datum/object = objects[objects.len] // Pull out the object - objects.len-- // Remove the object from the list - - if (istype(object) && !isturf(object) && !object.disposed && isnull(object.gcDestroyed)) // We only work with real objects - call(object, procName)(arglist(arguments)) - - // If there's nothing left to execute - // or we were killed while running the above code, mark finished and return. - if (!objects || !objects.len) return finished() - - if (world.cpu > cpuThreshold) - // We don't want to force a tick into overtime! - // If the tick is about to go overtime, spawn the next update to go - // in the next tick. - uq_dbg("tick went into overtime with world.cpu = [world.cpu], deferred next update to next tick [1+(world.time / world.tick_lag)]") - - spawn(1) - doWork() - else - spawn(0) // Execute anonymous function immediately as if we were in a while loop... - doWork() - -datum/updateQueueWorker/proc/finished() - uq_dbg("updateQueueWorker finished.") - /** - * If the worker was killed while it was working on something, it - * should delete itself when it finally finishes working on it. - * Meanwhile, the updateQueue will have proceeded on with the rest of - * the queue. This will also terminate the spawned function that was - * created in the kill() proc. - */ - if(killed) - del(src) - - finished = 1 - -datum/updateQueueWorker/proc/kill() - uq_dbg("updateQueueWorker killed.") - killed = 1 - objects = null - - /** - * If the worker is not done in 30 seconds after it's killed, - * we'll forcibly delete it, causing the anonymous function it was - * running to be terminated. Hasta la vista, baby. - */ - spawn(300) - del(src) - -datum/updateQueueWorker/proc/start() - uq_dbg("updateQueueWorker started.") - spawn(0) - doWork() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/processSchedulerView.dm b/code/controllers/ProcessScheduler/test/processSchedulerView.dm deleted file mode 100644 index ae78b3f015..0000000000 --- a/code/controllers/ProcessScheduler/test/processSchedulerView.dm +++ /dev/null @@ -1,94 +0,0 @@ -/datum/processSchedulerView - -/datum/processSchedulerView/Topic(href, href_list) - if (!href_list["action"]) - return - - switch (href_list["action"]) - if ("kill") - var/toKill = href_list["name"] - processScheduler.killProcess(toKill) - refreshProcessTable() - if ("enable") - var/toEnable = href_list["name"] - processScheduler.enableProcess(toEnable) - refreshProcessTable() - if ("disable") - var/toDisable = href_list["name"] - processScheduler.disableProcess(toDisable) - refreshProcessTable() - if ("refresh") - refreshProcessTable() - -/datum/processSchedulerView/proc/refreshProcessTable() - windowCall("handleRefresh", getProcessTable()) - -/datum/processSchedulerView/proc/windowCall(var/function, var/data = null) - usr << output(data, "processSchedulerContext.browser:[function]") - -/datum/processSchedulerView/proc/getProcessTable() - var/text = "" - // and the context of each - for (var/list/data in processScheduler.getStatusData()) - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - - text += "
NameAvg(s)Last(s)Highest(s)TickcountTickrateStateAction
[data["name"]][num2text(data["averageRunTime"]/10,3)][num2text(data["lastRunTime"]/10,3)][num2text(data["highestRunTime"]/10,3)][num2text(data["ticks"],4)][data["schedule"]][data["status"]]" - if (data["disabled"]) - text += "" - else - text += "" - text += "
" - return text - -/** - * getContext - * Outputs an interface showing stats for all processes. - */ -/datum/processSchedulerView/proc/getContext() - bootstrap_browse() - usr << browse('processScheduler.js', "file=processScheduler.js;display=0") - - var/text = {" - Process Scheduler Detail - - [bootstrap_includes()] - - - -

Process Scheduler

-
- -
- -

The process scheduler controls [processScheduler.getProcessCount()] loops.

"} - - text += "
" - text += getProcessTable() - text += "
" - - usr << browse(text, "window=processSchedulerContext;size=800x600") - -/datum/processSchedulerView/proc/bootstrap_browse() - usr << browse('bower_components/jquery/dist/jquery.min.js', "file=jquery.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/js/bootstrap.min.js', "file=bootstrap.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/css/bootstrap.min.css', "file=bootstrap.min.css;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings-white.png', "file=glyphicons-halflings-white.png;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings.png', "file=glyphicons-halflings.png;display=0") - usr << browse('bower_components/json2/json2.js', "file=json2.js;display=0") - -/datum/processSchedulerView/proc/bootstrap_includes() - return {" - - - - - "} diff --git a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm b/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm deleted file mode 100644 index d08ec46c7d..0000000000 --- a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm +++ /dev/null @@ -1,27 +0,0 @@ -/** - * testDyingUpdateQueueProcess - * This process is an example of a process using an updateQueue. - * The datums updated by this process behave badly and block the update loop - * by sleeping. If you #define UPDATE_QUEUE_DEBUG, you will see the updateQueue - * killing off its worker processes and spawning new ones to work around slow - * updates. This means that if you have a code path that sleeps for a long time - * in mob.Life once in a blue moon, the mob update loop will not hang. - */ -/datum/slowTestDatum/proc/wackyUpdateProcessName() - sleep(rand(0,20)) // Randomly REALLY slow :| - -/datum/controller/process/testDyingUpdateQueueProcess - var/tmp/datum/updateQueue/updateQueueInstance - var/tmp/list/testDatums = list() - -/datum/controller/process/testDyingUpdateQueueProcess/setup() - name = "Dying UpdateQueue Process" - schedule_interval = 30 // every 3 seconds - updateQueueInstance = new - for(var/i = 1, i < 30, i++) - testDatums.Add(new /datum/slowTestDatum) - -/datum/controller/process/testDyingUpdateQueueProcess/doWork() - updateQueueInstance.init(testDatums, "wackyUpdateProcessName") - updateQueueInstance.Run() - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHarness.dm b/code/controllers/ProcessScheduler/test/testHarness.dm deleted file mode 100644 index 2b5f1dff81..0000000000 --- a/code/controllers/ProcessScheduler/test/testHarness.dm +++ /dev/null @@ -1,35 +0,0 @@ -/* - These are simple defaults for your project. - */ -#define DEBUG - -var/global/datum/processSchedulerView/processSchedulerView - -world - loop_checks = 0 - New() - ..() - processScheduler = new - processSchedulerView = new - -mob - step_size = 8 - - New() - ..() - - - verb - startProcessScheduler() - set name = "Start Process Scheduler" - processScheduler.setup() - processScheduler.start() - - getProcessSchedulerContext() - set name = "Get Process Scheduler Status Panel" - processSchedulerView.getContext() - - runUpdateQueueTests() - set name = "Run Update Queue Testsuite" - var/datum/updateQueueTests/t = new - t.runTests() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHungProcess.dm b/code/controllers/ProcessScheduler/test/testHungProcess.dm deleted file mode 100644 index ced05dd4d7..0000000000 --- a/code/controllers/ProcessScheduler/test/testHungProcess.dm +++ /dev/null @@ -1,15 +0,0 @@ -/** - * testHungProcess - * This process is an example of a simple update loop process that hangs. - */ - -/datum/controller/process/testHungProcess/setup() - name = "Hung Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testHungProcess/doWork() - sleep(1000) // FUCK - // scheck is also responsible for handling hung processes. If a process - // hangs, and later resumes, but has already been killed by the scheduler, - // scheck will force the process to bail out. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testNiceProcess.dm b/code/controllers/ProcessScheduler/test/testNiceProcess.dm deleted file mode 100644 index aa921bc62f..0000000000 --- a/code/controllers/ProcessScheduler/test/testNiceProcess.dm +++ /dev/null @@ -1,13 +0,0 @@ -/** - * testNiceProcess - * This process is an example of a simple update loop process that is - * relatively fast. - */ - -/datum/controller/process/testNiceProcess/setup() - name = "Nice Process" - schedule_interval = 10 // every second - -/datum/controller/process/testNiceProcess/doWork() - sleep(rand(1,5)) // Just to pretend we're doing something - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testSlowProcess.dm b/code/controllers/ProcessScheduler/test/testSlowProcess.dm deleted file mode 100644 index b7c9e6e21e..0000000000 --- a/code/controllers/ProcessScheduler/test/testSlowProcess.dm +++ /dev/null @@ -1,28 +0,0 @@ -/** - * testSlowProcess - * This process is an example of a simple update loop process that is slow. - * The update loop here sleeps inside to provide an example, but if you had - * a computationally intensive loop process that is simply slow, you can use - * scheck() inside the loop to force it to yield periodically according to - * the sleep_interval var. By default, scheck will cause a loop to sleep every - * 2 ticks. - */ - -/datum/controller/process/testSlowProcess/setup() - name = "Slow Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testSlowProcess/doWork() - // set background = 1 will cause loop constructs to sleep periodically, - // whenever the BYOND scheduler deems it productive to do so. - // This behavior is not always sufficient, nor is it always consistent. - // Rather than leaving it up to the BYOND scheduler, we can control it - // ourselves and leave nothing to the black box. - set background = 1 - - for(var/i=1,i<30,i++) - // Just to pretend we're doing something here - sleep(rand(3, 5)) - - // Forces this loop to yield(sleep) periodically. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm b/code/controllers/ProcessScheduler/test/testUpdateQueue.dm deleted file mode 100644 index 07b64e927f..0000000000 --- a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm +++ /dev/null @@ -1,209 +0,0 @@ -var/global/list/updateQueueTestCount = list() - -/datum/updateQueueTests - var/start - proc - runTests() - world << "Running 9 tests..." - testUpdateQueuePerformance() - sleep(1) - testInplace() - sleep(1) - testInplaceUpdateQueuePerformance() - sleep(1) - testUpdateQueueReinit() - sleep(1) - testCrashingQueue() - sleep(1) - testEmptyQueue() - sleep(1) - testManySlowItemsInQueue() - sleep(1) - testVariableWorkerTimeout() - sleep(1) - testReallySlowItemInQueue() - sleep(1) - world << "Finished!" - - beginTiming() - start = world.time - - endTiming(text) - var/time = (world.time - start) / world.tick_lag - world << {"Performance - [text] - [time] ticks"} - - getCount() - return updateQueueTestCount[updateQueueTestCount.len] - - incrementTestCount() - updateQueueTestCount.len++ - updateQueueTestCount[updateQueueTestCount.len] = 0 - - assertCountEquals(count, text) - assertThat(getCount() == count, text) - - assertCountLessThan(count, text) - assertThat(getCount() < count, text) - - assertCountGreaterThan(count, text) - assertThat(getCount() > count, text) - - assertThat(condition, text) - if (condition) - world << {"PASS: [text]"} - else - world << {"FAIL: [text]"} - - testUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects") - - assertCountEquals(100000, "test that update queue updates all objects expected") - del(objs) - del(uq) - - testUpdateQueueReinit() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - objs = new - - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - uq.init(objs) - uq.Run() - assertCountEquals(200, "test that update queue reinitializes properly and updates all objects as expected.") - del(objs) - del(uq) - - testInplace() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objects = objs, inplace = 1) - uq.Run() - assertThat(objs.len == 0, "test that update queue inplace option really works inplace") - assertCountEquals(100, "test that inplace update queue updates the right number of objects") - del(objs) - del(uq) - - testInplaceUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects in place") - del(objs) - del(uq) - - testCrashingQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/crasher(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue handles crashed update procs OK") - del(objs) - del(uq) - - testEmptyQueue() - incrementTestCount() - var/list/objs = new - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(0, "test that update queue doesn't barf on empty lists") - del(objs) - del(uq) - - testManySlowItemsInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=30,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(30, "test that update queue slows down execution if too many objects are slow to update") - del(objs) - del(uq) - - testVariableWorkerTimeout() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=20,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs, workerTimeout=6) - uq.Run() - assertCountEquals(20, "test that variable worker timeout works properly") - del(objs) - del(uq) - - testReallySlowItemInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/reallySlow(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue skips objects that are too slow to update") - del(objs) - del(uq) - - - -datum/uqTestDatum - var/testNum - New(testNum) - ..() - src.testNum = testNum - proc/update() - updateQueueTestCount[testNum]++ - proc/lag(cycles) - set background = 1 - for(var/i=0,i time_to_kill) - break - var/atom/A = locate(refID) - if(A && A.gcDestroyed == GCd_at_time) - searching += A - if(searching.len >= checkRemain) - break - - for(var/atom/A in searching) - testing("GC: Searching references for [A] | [A.type]") - if(A.loc != null) - testing("GC: [A] | [A.type] is located in [A.loc] instead of null") - if(A.contents.len) - testing("GC: [A] | [A.type] has contents: [list2text(A.contents)]") - if(searching.len) - for(var/atom/D in world) - LookForRefs(D, searching) - for(var/datum/D) - LookForRefs(D, searching) - #endif while(destroyed.len && --checkRemain >= 0) - if(dels >= maxDels) + if(remaining_force_dels <= 0) #ifdef GC_DEBUG testing("GC: Reached max force dels per tick [dels] vs [maxDels]") #endif @@ -88,13 +70,22 @@ world/loop_checks = 0 testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --") logging["[A.type]"]++ del(A) - ++dels - ++hard_dels - #ifdef GC_DEBUG + + hard_dels++ + remaining_force_dels-- else + #ifdef GC_DEBUG testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]") - #endif + #endif + soft_dels++ + tick_dels++ + total_dels++ destroyed.Cut(1, 2) + SCHECK + +#undef GC_FORCE_DEL_PER_TICK +#undef GC_COLLECTION_TIMEOUT +#undef GC_COLLECTIONS_PER_TICK #ifdef GC_FINDREF /datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ) @@ -132,8 +123,11 @@ world/loop_checks = 0 destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list. destroyed["\ref[A]"] = world.time -/datum/controller/process/garbage_collector/getStatName() - return ..()+"([garbage_collector.destroyed.len]/[garbage_collector.dels]/[garbage_collector.hard_dels])" +/datum/controller/process/garbage_collector/statProcess() + ..() + stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued") + stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run") + // Tests if an atom has been deleted. /proc/deleted(atom/A) @@ -149,7 +143,7 @@ world/loop_checks = 0 crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.") del(A) if(garbage_collector) - garbage_collector.dels++ + garbage_collector.total_dels++ garbage_collector.hard_dels++ else if(isnull(A.gcDestroyed)) // Let our friend know they're about to get collected @@ -263,4 +257,4 @@ world/loop_checks = 0 #ifdef GC_FINDREF #undef GC_FINDREF -#endif +#endif \ No newline at end of file diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm index cd01e24829..26cc136ccc 100644 --- a/code/controllers/Processes/inactivity.dm +++ b/code/controllers/Processes/inactivity.dm @@ -4,10 +4,11 @@ /datum/controller/process/inactivity/doWork() if(config.kick_inactive) - for(var/client/C in clients) + for(last_object in clients) + var/client/C = last_object if(!C.holder && C.is_afk(config.kick_inactive MINUTES)) - if(!istype(C.mob, /mob/dead)) + if(!istype(C.mob, /mob/observer/dead)) log_access("AFK: [key_name(C)]") C << "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected." del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients. - scheck() + SCHECK diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm index 7959ee4fa7..405615dc1f 100644 --- a/code/controllers/Processes/machinery.dm +++ b/code/controllers/Processes/machinery.dm @@ -3,6 +3,7 @@ /datum/controller/process/machinery/setup() name = "machinery" schedule_interval = 20 // every 2 seconds + start_delay = 12 /datum/controller/process/machinery/doWork() internal_sort() @@ -17,12 +18,9 @@ machines = dd_sortedObjectList(machines) /datum/controller/process/machinery/proc/internal_process_machinery() - for(var/obj/machinery/M in machines) + for(last_object in machines) + var/obj/machinery/M = last_object if(M && !M.gcDestroyed) - #ifdef PROFILE_MACHINES - var/time_start = world.timeofday - #endif - if(M.process() == PROCESS_KILL) //M.inMachineList = 0 We don't use this debugging function machines.Remove(M) @@ -31,41 +29,39 @@ if(M && M.use_power) M.auto_use_power() - #ifdef PROFILE_MACHINES - var/time_end = world.timeofday - - if(!(M.type in machine_profiling)) - machine_profiling[M.type] = 0 - - machine_profiling[M.type] += (time_end - time_start) - #endif - - scheck() + SCHECK /datum/controller/process/machinery/proc/internal_process_power() - for(var/datum/powernet/powerNetwork in powernets) - if(istype(powerNetwork) && !powerNetwork.disposed) + for(last_object in powernets) + var/datum/powernet/powerNetwork = last_object + if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed)) powerNetwork.reset() - scheck() + SCHECK continue powernets.Remove(powerNetwork) /datum/controller/process/machinery/proc/internal_process_power_drain() // Currently only used by powersinks. These items get priority processed before machinery - for(var/obj/item/I in processing_power_items) + for(last_object in processing_power_items) + var/obj/item/I = last_object if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list. processing_power_items.Remove(I) - scheck() + SCHECK /datum/controller/process/machinery/proc/internal_process_pipenets() - for(var/datum/pipe_network/pipeNetwork in pipe_networks) - if(istype(pipeNetwork) && !pipeNetwork.disposed) + for(last_object in pipe_networks) + var/datum/pipe_network/pipeNetwork = last_object + if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed)) pipeNetwork.process() - scheck() + SCHECK continue pipe_networks.Remove(pipeNetwork) -/datum/controller/process/machinery/getStatName() - return ..()+"(MCH:[machines.len] PWR:[powernets.len] PIP:[pipe_networks.len])" +/datum/controller/process/machinery/statProcess() + ..() + stat(null, "[machines.len] machines") + stat(null, "[powernets.len] powernets") + stat(null, "[pipe_networks.len] pipenets") + stat(null, "[processing_power_items.len] power item\s") \ No newline at end of file diff --git a/code/controllers/Processes/mob.dm b/code/controllers/Processes/mob.dm index 39d4844a02..b44842036d 100644 --- a/code/controllers/Processes/mob.dm +++ b/code/controllers/Processes/mob.dm @@ -4,20 +4,26 @@ /datum/controller/process/mob/setup() name = "mob" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 16 /datum/controller/process/mob/started() ..() - if(!updateQueueInstance) - if(!mob_list) - mob_list = list() - else if(mob_list.len) - updateQueueInstance = new + if(!mob_list) + mob_list = list() /datum/controller/process/mob/doWork() - if(updateQueueInstance) - updateQueueInstance.init(mob_list, "Life") - updateQueueInstance.Run() + for(last_object in mob_list) + var/mob/M = last_object + if(isnull(M.gcDestroyed)) + try + M.Life() + catch(var/exception/e) + catchException(e, M) + SCHECK + else + catchBadType(M) + mob_list -= M -/datum/controller/process/mob/getStatName() - return ..()+"([mob_list.len])" +/datum/controller/process/mob/statProcess() + ..() + stat(null, "[mob_list.len] mobs") \ No newline at end of file diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm index 654b1621be..49b9048c07 100644 --- a/code/controllers/Processes/nanoui.dm +++ b/code/controllers/Processes/nanoui.dm @@ -1,14 +1,19 @@ -/datum/controller/process/nanoui - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/nanoui/setup() name = "nanoui" - schedule_interval = 10 // every 1 second - updateQueueInstance = new + schedule_interval = 20 // every 2 seconds + +/datum/controller/process/nanoui/statProcess() + ..() + stat(null, "[nanomanager.processing_uis.len] UIs") /datum/controller/process/nanoui/doWork() - updateQueueInstance.init(nanomanager.processing_uis, "process") - updateQueueInstance.Run() - -/datum/controller/process/nanoui/getStatName() - return ..()+"([nanomanager.processing_uis.len])" + for(last_object in nanomanager.processing_uis) + var/datum/nanoui/NUI = last_object + if(istype(NUI) && isnull(NUI.gcDestroyed)) + try + NUI.process() + catch(var/exception/e) + catchException(e, NUI) + else + catchBadType(NUI) + nanomanager.processing_uis -= NUI \ No newline at end of file diff --git a/code/controllers/Processes/obj.dm b/code/controllers/Processes/obj.dm index 37766cf92d..bd50edd111 100644 --- a/code/controllers/Processes/obj.dm +++ b/code/controllers/Processes/obj.dm @@ -1,24 +1,26 @@ -var/global/list/object_profiling = list() -/datum/controller/process/obj - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/obj/setup() name = "obj" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 8 /datum/controller/process/obj/started() ..() - if(!updateQueueInstance) - if(!processing_objects) - processing_objects = list() - else if(processing_objects.len) - updateQueueInstance = new + if(!processing_objects) + processing_objects = list() /datum/controller/process/obj/doWork() - if(updateQueueInstance) - updateQueueInstance.init(processing_objects, "process") - updateQueueInstance.Run() + for(last_object in processing_objects) + var/datum/O = last_object + if(isnull(O.gcDestroyed)) + try + O:process() + catch(var/exception/e) + catchException(e, O) + SCHECK + else + catchBadType(O) + processing_objects -= O -/datum/controller/process/obj/getStatName() - return ..()+"([processing_objects.len])" +/datum/controller/process/obj/statProcess() + ..() + stat(null, "[processing_objects.len] objects") \ No newline at end of file diff --git a/code/controllers/Processes/scheduler.dm b/code/controllers/Processes/scheduler.dm new file mode 100644 index 0000000000..fdbe55faed --- /dev/null +++ b/code/controllers/Processes/scheduler.dm @@ -0,0 +1,133 @@ +/var/datum/controller/process/scheduler/scheduler + +/************ +* Scheduler * +************/ +/datum/controller/process/scheduler + var/list/scheduled_tasks + +/datum/controller/process/scheduler/setup() + name = "scheduler" + schedule_interval = 3 SECONDS + scheduled_tasks = list() + scheduler = src + +/datum/controller/process/scheduler/doWork() + for(last_object in scheduled_tasks) + var/datum/scheduled_task/scheduled_task = last_object + try + if(world.time > scheduled_task.trigger_time) + unschedule(scheduled_task) + scheduled_task.pre_process() + scheduled_task.process() + scheduled_task.post_process() + catch(var/exception/e) + catchException(e, last_object) + SCHECK + +/datum/controller/process/scheduler/statProcess() + ..() + stat(null, "[scheduled_tasks.len] task\s") + +/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st) + scheduled_tasks += st + destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule) + +/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st) + if(st in scheduled_tasks) + scheduled_tasks -= st + destroyed_event.unregister(st, src) + +/********** +* Helpers * +**********/ +/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list()) + return schedule_task(world.time + in_time, procedure, arguments) + +/proc/schedule_task_with_source_in(var/in_time, var/source, var/procedure, var/list/arguments = list()) + return schedule_task_with_source(world.time + in_time, source, procedure, arguments) + +/proc/schedule_task(var/trigger_time, var/procedure, var/list/arguments) + var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/destroy_scheduled_task, list()) + scheduler.schedule(st) + return st + +/proc/schedule_task_with_source(var/trigger_time, var/source, var/procedure, var/list/arguments) + var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/destroy_scheduled_task, list()) + scheduler.schedule(st) + return st + +/proc/schedule_repeating_task(var/trigger_time, var/repeat_interval, var/procedure, var/list/arguments) + var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval)) + scheduler.schedule(st) + return st + +/proc/schedule_repeating_task_with_source(var/trigger_time, var/repeat_interval, var/source, var/procedure, var/list/arguments) + var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval)) + scheduler.schedule(st) + return st + +/************* +* Task Datum * +*************/ +/datum/scheduled_task + var/trigger_time + var/procedure + var/list/arguments + var/task_after_process + var/list/task_after_process_args + +/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) + ..() + src.trigger_time = trigger_time + src.procedure = procedure + src.arguments = arguments ? arguments : list() + src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task + src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list() + task_after_process_args += src + +/datum/scheduled_task/Destroy() + procedure = null + arguments.Cut() + task_after_process = null + task_after_process_args.Cut() + return ..() + +/datum/scheduled_task/proc/pre_process() + task_triggered_event.raise_event(list(src)) + +/datum/scheduled_task/proc/process() + if(procedure) + call(procedure)(arglist(arguments)) + +/datum/scheduled_task/proc/post_process() + call(task_after_process)(arglist(task_after_process_args)) + +// Resets the trigger time, has no effect if the task has already triggered +/datum/scheduled_task/proc/trigger_task_in(var/trigger_in) + src.trigger_time = world.time + trigger_in + +/datum/scheduled_task/source + var/datum/source + +/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) + src.source = source + destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed) + ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args) + +/datum/scheduled_task/source/Destroy() + source = null + return ..() + +/datum/scheduled_task/source/process() + call(source, procedure)(arglist(arguments)) + +/datum/scheduled_task/source/proc/source_destroyed() + qdel(src) + +/proc/destroy_scheduled_task(var/datum/scheduled_task/st) + qdel(st) + +/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st) + st.trigger_time = world.time + trigger_delay + scheduler.schedule(st) \ No newline at end of file diff --git a/code/controllers/Processes/turf.dm b/code/controllers/Processes/turf.dm index 2ac33f48ba..bfced8f93b 100644 --- a/code/controllers/Processes/turf.dm +++ b/code/controllers/Processes/turf.dm @@ -5,10 +5,12 @@ var/global/list/turf/processing_turfs = list() schedule_interval = 20 // every 2 seconds /datum/controller/process/turf/doWork() - for(var/turf/T in processing_turfs) + for(last_object in processing_turfs) + var/turf/T = last_object if(T.process() == PROCESS_KILL) processing_turfs.Remove(T) - scheck() + SCHECK -/datum/controller/process/turf/getStatName() - return ..()+"([processing_turfs.len])" +/datum/controller/process/turf/statProcess() + ..() + stat(null, "[processing_turfs.len] turf\s") \ No newline at end of file diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm index 597b7f607c..afd1435ffa 100644 --- a/code/controllers/autotransfer.dm +++ b/code/controllers/autotransfer.dm @@ -12,6 +12,6 @@ datum/controller/transfer_controller/Destroy() datum/controller/transfer_controller/proc/process() currenttick = currenttick + 1 - if (world.time >= timerbuffer - 600) + if (round_duration_in_ticks >= timerbuffer - 1 MINUTE) vote.autotransfer() - timerbuffer = timerbuffer + config.vote_autotransfer_interval \ No newline at end of file + timerbuffer = timerbuffer + config.vote_autotransfer_interval diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 28dadc5adb..b249db9a47 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -21,7 +21,8 @@ var/list/gamemode_cache = list() var/log_pda = 0 // log pda messages var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits var/log_runtime = 0 // logs world.log to a file - var/sql_enabled = 1 // for sql switching + var/log_world_output = 0 // log world.log << messages + var/sql_enabled = 0 // for sql switching var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour var/allow_vote_restart = 0 // allow votes to restart var/ert_admin_call_only = 0 @@ -265,7 +266,7 @@ var/list/gamemode_cache = list() if(type == "config") switch (name) if ("resource_urls") - config.resource_urls = text2list(value, " ") + config.resource_urls = splittext(value, " ") if ("admin_legacy_system") config.admin_legacy_system = 1 @@ -289,7 +290,7 @@ var/list/gamemode_cache = list() config.log_access = 1 if ("sql_enabled") - config.sql_enabled = text2num(value) + config.sql_enabled = 1 if ("log_say") config.log_say = 1 @@ -327,6 +328,9 @@ var/list/gamemode_cache = list() if ("log_pda") config.log_pda = 1 + if ("log_world_output") + config.log_world_output = 1 + if ("log_hrefs") config.log_hrefs = 1 @@ -337,7 +341,7 @@ var/list/gamemode_cache = list() config.generate_asteroid = 1 if ("asteroid_z_levels") - config.asteroid_z_levels = text2list(value, ";") + config.asteroid_z_levels = splittext(value, ";") //Numbers get stored as strings, so we'll fix that right now. for(var/z_level in config.asteroid_z_levels) z_level = text2num(z_level) @@ -696,7 +700,7 @@ var/list/gamemode_cache = list() config.starlight = value >= 0 ? value : 0 if("ert_species") - config.ert_species = text2list(value, ";") + config.ert_species = splittext(value, ";") if(!config.ert_species.len) config.ert_species += "Human" @@ -707,7 +711,7 @@ var/list/gamemode_cache = list() config.aggressive_changelog = 1 if("default_language_prefixes") - var/list/values = text2list(value, " ") + var/list/values = splittext(value, " ") if(values.len > 0) language_prefixes = values diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm index 001372b4e3..e330024475 100644 --- a/code/controllers/hooks-defs.dm +++ b/code/controllers/hooks-defs.dm @@ -1,87 +1,87 @@ -/** - * Startup hook. - * Called in world.dm when the server starts. - */ -/hook/startup - -/** - * Roundstart hook. - * Called in gameticker.dm when a round starts. - */ -/hook/roundstart - -/** - * Roundend hook. - * Called in gameticker.dm when a round ends. - */ -/hook/roundend - -/** - * Death hook. - * Called in death.dm when someone dies. - * Parameters: var/mob/living/carbon/human, var/gibbed - */ -/hook/death - -/** - * Cloning hook. - * Called in cloning.dm when someone is brought back by the wonders of modern science. - * Parameters: var/mob/living/carbon/human - */ -/hook/clone - -/** - * Debrained hook. - * Called in brain_item.dm when someone gets debrained. - * Parameters: var/obj/item/organ/brain - */ -/hook/debrain - -/** - * Borged hook. - * Called in robot_parts.dm when someone gets turned into a cyborg. - * Parameters: var/mob/living/silicon/robot - */ -/hook/borgify - -/** - * Podman hook. - * Called in podmen.dm when someone is brought back as a Diona. - * Parameters: var/mob/living/carbon/alien/diona - */ -/hook/harvest_podman - -/** - * Payroll revoked hook. - * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal. - * Parameters: var/datum/money_account - */ -/hook/revoke_payroll - -/** - * Account suspension hook. - * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal. - * Parameters: var/datum/money_account - */ -/hook/change_account_status - -/** - * Employee reassignment hook. - * Called in card.dm when someone's card is reassigned at the HoP's desk. - * Parameters: var/obj/item/weapon/card/id - */ -/hook/reassign_employee - -/** - * Employee terminated hook. - * Called in card.dm when someone's card is terminated at the HoP's desk. - * Parameters: var/obj/item/weapon/card/id - */ -/hook/terminate_employee - -/** - * Crate sold hook. - * Called in supplyshuttle.dm when a crate is sold on the shuttle. - * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle - */ -/hook/sell_crate +/** + * Startup hook. + * Called in world.dm when the server starts. + */ +/hook/startup + +/** + * Roundstart hook. + * Called in gameticker.dm when a round starts. + */ +/hook/roundstart + +/** + * Roundend hook. + * Called in gameticker.dm when a round ends. + */ +/hook/roundend + +/** + * Death hook. + * Called in death.dm when someone dies. + * Parameters: var/mob/living/carbon/human, var/gibbed + */ +/hook/death + +/** + * Cloning hook. + * Called in cloning.dm when someone is brought back by the wonders of modern science. + * Parameters: var/mob/living/carbon/human + */ +/hook/clone + +/** + * Debrained hook. + * Called in brain_item.dm when someone gets debrained. + * Parameters: var/obj/item/organ/brain + */ +/hook/debrain + +/** + * Borged hook. + * Called in robot_parts.dm when someone gets turned into a cyborg. + * Parameters: var/mob/living/silicon/robot + */ +/hook/borgify + +/** + * Podman hook. + * Called in podmen.dm when someone is brought back as a Diona. + * Parameters: var/mob/living/carbon/alien/diona + */ +/hook/harvest_podman + +/** + * Payroll revoked hook. + * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/revoke_payroll + +/** + * Account suspension hook. + * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/change_account_status + +/** + * Employee reassignment hook. + * Called in card.dm when someone's card is reassigned at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/reassign_employee + +/** + * Employee terminated hook. + * Called in card.dm when someone's card is terminated at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/terminate_employee + +/** + * Crate sold hook. + * Called in supplyshuttle.dm when a crate is sold on the shuttle. + * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle + */ +/hook/sell_crate diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm index 48f1199ef7..e7888304e5 100644 --- a/code/controllers/hooks.dm +++ b/code/controllers/hooks.dm @@ -9,11 +9,11 @@ * * To add some code to be called by the hook, define a proc under the type, as so: * @code - /hook/foo/proc/bar() - if(1) - return 1 //Sucessful - else - return 0 //Error, or runtime. +/hook/foo/proc/bar() + if(1) + return 1 //Sucessful + else + return 0 //Error, or runtime. * @endcode * All hooks must return nonzero on success, as runtimes will force return null. */ diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 5263e1af79..682b0fb3d0 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -47,7 +47,8 @@ datum/controller/game_controller/proc/setup_objects() admin_notice("Initializing objects", R_DEBUG) sleep(-1) for(var/atom/movable/object in world) - object.initialize() + if(isnull(object.gcDestroyed)) + object.initialize() admin_notice("Initializing areas", R_DEBUG) sleep(-1) diff --git a/code/controllers/observer_listener/atom/observer.dm b/code/controllers/observer_listener/atom/observer.dm new file mode 100644 index 0000000000..da38580414 --- /dev/null +++ b/code/controllers/observer_listener/atom/observer.dm @@ -0,0 +1,31 @@ +#define OBSERVER_EVENT_DESTROY "OnDestroy" + +/atom + var/list/observer_events + +/atom/Destroy() + var/list/destroy_listeners = get_listener_list_from_event(OBSERVER_EVENT_DESTROY) + if(destroy_listeners) + for(var/destroy_listener in destroy_listeners) + call(destroy_listener, destroy_listeners[destroy_listener])(src) + + for(var/list/listeners in observer_events) + listeners.Cut() + + return ..() + +/atom/proc/register(var/event, var/procOwner, var/proc_call) + var/list/listeners = get_listener_list_from_event(event) + listeners[procOwner] = proc_call + +/atom/proc/unregister(var/event, var/procOwner) + var/list/listeners = get_listener_list_from_event(event) + listeners -= procOwner + +/atom/proc/get_listener_list_from_event(var/observer_event) + if(!observer_events) observer_events = list() + var/list/listeners = observer_events[observer_event] + if(!listeners) + listeners = list() + observer_events[observer_event] = listeners + return listeners diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index be9688b09b..bd3d82247c 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -264,7 +264,7 @@ var/global/datum/shuttle_controller/shuttle_controller var/datum/shuttle/ferry/multidock/specops/ERT = new() ERT.location = 0 ERT.warmup_time = 10 - ERT.area_offsite = locate(/area/shuttle/specops/station) //centcom is the home station, the Northern Star is offsite + ERT.area_offsite = locate(/area/shuttle/specops/station) //centcom is the home station, the player station is offsite ERT.area_station = locate(/area/shuttle/specops/centcom) ERT.docking_controller_tag = "specops_shuttle_port" ERT.docking_controller_tag_station = "specops_shuttle_port" @@ -317,9 +317,9 @@ var/global/datum/shuttle_controller/shuttle_controller "Arrivals dock" = "nuke_shuttle_dock_airlock", ) - MS.announcer = "NDV Icarus" - MS.arrival_message = "Attention, [station_short], you have a large signature approaching the station - looks unarmed to surface scans. We're too far out to intercept - brace for visitors." - MS.departure_message = "Your visitors are on their way out of the system, [station_short], burning delta-v like it's nothing. Good riddance." + MS.announcer = "Automated Traffic Control" + MS.arrival_message = "Attention. A vessel is approaching the colony." + MS.departure_message = "Attention. A vessel is now leaving from the colony." MS.interim = locate(/area/syndicate_station/transit) MS.warmup_time = 0 diff --git a/code/controllers/subsystem/alarms.dm b/code/controllers/subsystem/alarms.dm deleted file mode 100644 index b05be7ccbf..0000000000 --- a/code/controllers/subsystem/alarms.dm +++ /dev/null @@ -1,30 +0,0 @@ -// We manually initialize the alarm handlers instead of looping over all existing types -// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. -/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() -/var/global/datum/alarm_handler/camera/camera_alarm = new() -/var/global/datum/alarm_handler/fire/fire_alarm = new() -/var/global/datum/alarm_handler/motion/motion_alarm = new() -/var/global/datum/alarm_handler/power/power_alarm = new() - -/datum/subsystem/alarm - name = "Alarm" - var/list/datum/alarm/all_handlers - -/datum/subsystem/alarm/New() - all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) - -/datum/subsystem/alarm/fire() - for(var/datum/alarm_handler/AH in all_handlers) - AH.process() - -/datum/subsystem/alarm/proc/active_alarms() - var/list/all_alarms = new - for(var/datum/alarm_handler/AH in all_handlers) - var/list/alarms = AH.alarms - all_alarms += alarms - - return all_alarms - -/datum/subsystem/alarm/proc/number_of_active_alarms() - var/list/alarms = active_alarms() - return alarms.len diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index c394318c28..ee361c9888 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -25,7 +25,7 @@ usr.client.debug_variables(antag) message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") -/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry")) +/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -92,5 +92,11 @@ if("Chemistry") debug_variables(chemistryProcess) feedback_add_details("admin_verb", "DChem") + if("Vote") + debug_variables(vote) + feedback_add_details("admin_verb", "DVote") + if("Xenobio") + debug_variables(xenobio_controller) + feedback_add_details("admin_verb", "DXenobio") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index efab120483..e6f88731b6 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -1,9 +1,15 @@ var/datum/controller/vote/vote = new() -var/global/list/round_voters = list() //Keeps track of the individuals voting for a given round, for use in forcedrafting. +var/global/list/round_voters = list() // Keeps track of the individuals voting for a given round, for use in forcedrafting. -datum/controller/vote - var/initiator = null +#define VOTE_RESTART "restart" +#define VOTE_GAMEMODE "gamemode" +#define VOTE_CREW_TRANSFER "crew_transfer" +#define VOTE_ADD_ANTAGONIST "add_antagonist" +#define VOTE_CUSTOM "custom" + +/datum/controller/vote + var/initiator = null // Key of the one who started the vote or "the server" var/started_time = null var/time_remaining = 0 var/mode = null @@ -11,385 +17,366 @@ datum/controller/vote var/list/choices = list() var/list/gamemode_names = list() var/list/voted = list() - var/list/voting = list() var/list/current_votes = list() var/list/additional_text = list() - var/auto_muted = 0 - New() - if(vote != src) - if(istype(vote)) - del(vote) - vote = src +/datum/controller/vote/New() + if(vote != src) + if(istype(vote)) + del(vote) + vote = src - proc/process() //called by master_controller - if(mode) - // No more change mode votes after the game has started. - // 3 is GAME_STATE_PLAYING, but that #define is undefined for some reason - if(mode == "gamemode" && ticker.current_state >= 2) - world << "Voting aborted due to game start." - src.reset() - return +/datum/controller/vote/proc/process() //called by master_controller + if(mode) + // No more change mode votes after the game has started. + if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP) + world << "Voting aborted due to game start." + src.reset() + return - // Calculate how much time is remaining by comparing current time, to time of vote start, - // plus vote duration - time_remaining = round((started_time + config.vote_period - world.time)/10) - - if(time_remaining < 0) - result() - for(var/client/C in voting) - if(C) - C << browse(null,"window=vote") - reset() - else - for(var/client/C in voting) - if(C) - C << browse(vote.interface(C),"window=vote") - - voting.Cut() - - proc/autotransfer() - initiate_vote("crew_transfer","the server", 1) - log_debug("The server has called a crew transfer vote") - - proc/autogamemode() - initiate_vote("gamemode","the server", 1) - log_debug("The server has called a gamemode vote") - - proc/reset() - initiator = null - time_remaining = 0 - mode = null - question = null - choices.Cut() - voted.Cut() - voting.Cut() - current_votes.Cut() - additional_text.Cut() - - proc/get_result() - //get the highest number of votes - var/greatest_votes = 0 - var/total_votes = 0 - for(var/option in choices) - var/votes = choices[option] - total_votes += votes - if(votes > greatest_votes) - greatest_votes = votes - //default-vote for everyone who didn't vote - if(!config.vote_no_default && choices.len) - var/non_voters = (clients.len - total_votes) - if(non_voters > 0) - if(mode == "restart") - choices["Continue Playing"] += non_voters - if(choices["Continue Playing"] >= greatest_votes) - greatest_votes = choices["Continue Playing"] - else if(mode == "gamemode") - if(master_mode in choices) - choices[master_mode] += non_voters - if(choices[master_mode] >= greatest_votes) - greatest_votes = choices[master_mode] - else if(mode == "crew_transfer") - var/factor = 0.5 - switch(world.time / (10 * 60)) // minutes - if(0 to 60) - factor = 0.5 - if(61 to 120) - factor = 0.8 - if(121 to 240) - factor = 1 - if(241 to 300) - factor = 1.2 - else - factor = 1.4 - choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor) - world << "Crew Transfer Factor: [factor]" - greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"]) - - - //get all options with that many votes and return them in a list - . = list() - if(greatest_votes) - for(var/option in choices) - if(choices[option] == greatest_votes) - . += option - return . - - proc/announce_result() - var/list/winners = get_result() - var/text - if(winners.len > 0) - if(winners.len > 1) - if(mode != "gamemode" || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes - text = "Vote Tied Between:\n" - for(var/option in winners) - text += "\t[option]\n" - . = pick(winners) - - for(var/key in current_votes) - if(choices[current_votes[key]] == .) - round_voters += key // Keep track of who voted for the winning round. - if((mode == "gamemode" && . == "Extended") || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes - text += "Vote Result: [.]" - else - if(mode != "gamemode") - text += "Vote Result: [.]" - else - text += "The vote has ended." // What will be shown if it is a gamemode vote that isn't extended - - else - text += "Vote Result: Inconclusive - No Votes!" - if(mode == "add_antagonist") - antag_add_failed = 1 - log_vote(text) - world << "[text]" - return . - - proc/result() - . = announce_result() - var/restart = 0 - if(.) - switch(mode) - if("restart") - if(. == "Restart Round") - restart = 1 - if("gamemode") - if(master_mode != .) - world.save_mode(.) - if(ticker && ticker.mode) - restart = 1 - else - master_mode = . - if("crew_transfer") - if(. == "Initiate Crew Transfer") - init_shift_change(null, 1) - if("add_antagonist") - if(isnull(.) || . == "None") - antag_add_failed = 1 - else - additional_antag_types |= antag_names_to_ids[.] - - if(mode == "gamemode") //fire this even if the vote fails. - if(!round_progressing) - round_progressing = 1 - world << "The round will start soon." - - if(restart) - world << "World restarting due to vote..." - feedback_set_details("end_error","restart vote") - if(blackbox) blackbox.save_all_data_to_sql() - sleep(50) - log_game("Rebooting due to restart vote") - world.Reboot() - - return . - - proc/submit_vote(var/ckey, var/vote) - if(mode) - if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder) - return 0 - if(vote && vote >= 1 && vote <= choices.len) - if(current_votes[ckey]) - choices[choices[current_votes[ckey]]]-- - voted += usr.ckey - choices[choices[vote]]++ //check this - current_votes[ckey] = vote - return vote - return 0 - - proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0) - if(!mode) - if(started_time != null && !(check_rights(R_ADMIN) || automatic)) - var/next_allowed_time = (started_time + config.vote_delay) - if(next_allowed_time > world.time) - return 0 + // Calculate how much time is remaining by comparing current time, to time of vote start, + // plus vote duration + time_remaining = round((started_time + config.vote_period - world.time)/10) + if(time_remaining < 0) + result() reset() - switch(vote_type) - if("restart") - choices.Add("Restart Round","Continue Playing") - if("gamemode") - if(ticker.current_state >= 2) - return 0 - choices.Add(config.votable_modes) - for (var/F in choices) - var/datum/game_mode/M = gamemode_cache[F] - if(!M) - continue - gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works - additional_text.Add("[M.required_players]") - gamemode_names["secret"] = "Secret" - if("crew_transfer") - if(check_rights(R_ADMIN|R_MOD, 0)) - question = "End the shift?" - choices.Add("Initiate Crew Transfer", "Continue The Round") + +/datum/controller/vote/proc/autotransfer() + initiate_vote(VOTE_CREW_TRANSFER, "the server", 1) + log_debug("The server has called a crew transfer vote") + +/datum/controller/vote/proc/autogamemode() + initiate_vote(VOTE_GAMEMODE, "the server", 1) + log_debug("The server has called a gamemode vote") + +/datum/controller/vote/proc/reset() + initiator = null + time_remaining = 0 + mode = null + question = null + choices.Cut() + voted.Cut() + current_votes.Cut() + additional_text.Cut() + +/datum/controller/vote/proc/get_result() // Get the highest number of votes + var/greatest_votes = 0 + var/total_votes = 0 + + for(var/option in choices) + var/votes = choices[option] + total_votes += votes + if(votes > greatest_votes) + greatest_votes = votes + + if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote + var/non_voters = (clients.len - total_votes) + if(non_voters > 0) + if(mode == VOTE_RESTART) + choices["Continue Playing"] += non_voters + if(choices["Continue Playing"] >= greatest_votes) + greatest_votes = choices["Continue Playing"] + else if(mode == VOTE_GAMEMODE) + if(master_mode in choices) + choices[master_mode] += non_voters + if(choices[master_mode] >= greatest_votes) + greatest_votes = choices[master_mode] + else if(mode == VOTE_CREW_TRANSFER) + var/factor = 0.5 + switch(world.time / (10 * 60)) // minutes + if(0 to 60) + factor = 0.5 + if(61 to 120) + factor = 0.8 + if(121 to 240) + factor = 1 + if(241 to 300) + factor = 1.2 else - if (get_security_level() == "red" || get_security_level() == "delta") - initiator_key << "The current alert status is too high to call for a crew transfer!" - return 0 - if(ticker.current_state <= 2) - return 0 - initiator_key << "The crew transfer button has been disabled!" - question = "End the shift?" - choices.Add("Initiate Crew Transfer", "Continue The Round") - if("add_antagonist") - if(!config.allow_extra_antags || ticker.current_state >= 2) - return 0 - for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] - if(!(antag.id in additional_antag_types) && antag.is_votable()) - choices.Add(antag.role_text) - choices.Add("None") - if("custom") - question = sanitizeSafe(input(usr,"What is the vote for?") as text|null) - if(!question) return 0 - for(var/i=1,i<=10,i++) - var/option = capitalize(sanitize(input(usr,"Please enter an option or hit cancel to finish") as text|null)) - if(!option || mode || !usr.client) break - choices.Add(option) - else - return 0 - mode = vote_type - initiator = initiator_key - started_time = world.time - var/text = "[capitalize(mode)] vote started by [initiator]." - if(mode == "custom") - text += "\n[question]" + factor = 1.4 + choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor) + world << "Crew Transfer Factor: [factor]" + greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"]) - log_vote(text) - world << "[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote." - switch(vote_type) - if("crew_transfer") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) - if("gamemode") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) - if("custom") - world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) - if(mode == "gamemode" && round_progressing) - round_progressing = 0 - world << "Round start has been delayed." + . = list() // Get all options with that many votes and return them in a list + if(greatest_votes) + for(var/option in choices) + if(choices[option] == greatest_votes) + . += option - time_remaining = round(config.vote_period/10) - return 1 - return 0 +/datum/controller/vote/proc/announce_result() + var/list/winners = get_result() + var/text + if(winners.len > 0) + if(winners.len > 1) + if(mode != VOTE_GAMEMODE || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes + text = "Vote Tied Between:\n" + for(var/option in winners) + text += "\t[option]\n" + . = pick(winners) - proc/interface(var/client/C) - if(!C) return - var/admin = 0 - var/trialmin = 0 - if(C.holder) - if(C.holder.rights & R_ADMIN) - admin = 1 - trialmin = 1 // don't know why we use both of these it's really weird, but I'm 2 lasy to refactor this all to use just admin. - voting |= C - - . = "Voting Panel" - if(mode) - if(question) . += "

Vote: '[question]'

" - else . += "

Vote: [capitalize(mode)]

" - . += "Time Left: [time_remaining] s
" - . += "" - if(capitalize(mode) == "Gamemode") .+= "" - - for(var/i = 1, i <= choices.len, i++) - var/votes = choices[choices[i]] - if(!votes) votes = 0 - . += "" - if(mode == "gamemode") - if(current_votes[C.ckey] == i) - . += "" - else - . += "" - else - if(current_votes[C.ckey] == i) - . += "" - else - . += "" - if (additional_text.len >= i) - . += additional_text[i] - . += "" - - . += "
ChoicesVotesMinimum Players
[gamemode_names[choices[i]]][votes][gamemode_names[choices[i]]][votes][choices[i]][votes][choices[i]][votes]

" - if(admin) - . += "(Cancel Vote) " + for(var/key in current_votes) + if(choices[current_votes[key]] == .) + round_voters += key // Keep track of who voted for the winning round. + if(mode != VOTE_GAMEMODE || . == "Extended" || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes + text += "Vote Result: [.]" else - . += "

Start a vote:



" - . += "Close" - return . + text += "The vote has ended." + else + text += "Vote Result: Inconclusive - No Votes!" + if(mode == VOTE_ADD_ANTAGONIST) + antag_add_failed = 1 + log_vote(text) + world << "[text]" - Topic(href,href_list[],hsrc) - if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid - switch(href_list["vote"]) - if("close") - voting -= usr.client - usr << browse(null, "window=vote") - return - if("cancel") - if(usr.client.holder) - reset() - if("toggle_restart") - if(usr.client.holder) - config.allow_vote_restart = !config.allow_vote_restart - if("toggle_gamemode") - if(usr.client.holder) - config.allow_vote_mode = !config.allow_vote_mode - if("restart") - if(config.allow_vote_restart || usr.client.holder) - initiate_vote("restart",usr.key) - if("gamemode") - if(config.allow_vote_mode || usr.client.holder) - initiate_vote("gamemode",usr.key) - if("crew_transfer") - if(config.allow_vote_restart || usr.client.holder) - initiate_vote("crew_transfer",usr.key) - if("add_antagonist") - if(config.allow_extra_antags) - initiate_vote("add_antagonist",usr.key) - if("custom") - if(usr.client.holder) - initiate_vote("custom",usr.key) +/datum/controller/vote/proc/result() + . = announce_result() + var/restart = 0 + if(.) + switch(mode) + if(VOTE_RESTART) + if(. == "Restart Round") + restart = 1 + if(VOTE_GAMEMODE) + if(master_mode != .) + world.save_mode(.) + if(ticker && ticker.mode) + restart = 1 + else + master_mode = . + if(VOTE_CREW_TRANSFER) + if(. == "Initiate Crew Transfer") + init_shift_change(null, 1) + if(VOTE_ADD_ANTAGONIST) + if(isnull(.) || . == "None") + antag_add_failed = 1 + else + additional_antag_types |= antag_names_to_ids[.] + + if(mode == VOTE_GAMEMODE) //fire this even if the vote fails. + if(!round_progressing) + round_progressing = 1 + world << "The round will start soon." + + if(restart) + world << "World restarting due to vote..." + feedback_set_details("end_error", "restart vote") + if(blackbox) + blackbox.save_all_data_to_sql() + sleep(50) + log_game("Rebooting due to restart vote") + world.Reboot() + +/datum/controller/vote/proc/submit_vote(var/ckey, var/newVote) + if(mode) + if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder) + return + if(current_votes[ckey]) + choices[choices[current_votes[ckey]]]-- + if(newVote && newVote >= 1 && newVote <= choices.len) + choices[choices[newVote]]++ + current_votes[ckey] = newVote + else + current_votes[ckey] = null + +/datum/controller/vote/proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0) + if(!mode) + if(started_time != null && !(check_rights(R_ADMIN) || automatic)) + var/next_allowed_time = (started_time + config.vote_delay) + if(next_allowed_time > world.time) + return 0 + + reset() + + switch(vote_type) + if(VOTE_RESTART) + choices.Add("Restart Round", "Continue Playing") + if(VOTE_GAMEMODE) + if(ticker.current_state >= GAME_STATE_SETTING_UP) + return 0 + choices.Add(config.votable_modes) + for(var/F in choices) + var/datum/game_mode/M = gamemode_cache[F] + if(!M) + continue + gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works + additional_text.Add("[M.required_players]") + gamemode_names["secret"] = "Secret" + if(VOTE_CREW_TRANSFER) + if(!check_rights(R_ADMIN|R_MOD, 0)) // The gods care not for the affairs of the mortals + if(get_security_level() == "red" || get_security_level() == "delta") + initiator_key << "The current alert status is too high to call for a crew transfer!" + return 0 + if(ticker.current_state <= GAME_STATE_SETTING_UP) + initiator_key << "The crew transfer button has been disabled!" + return 0 + question = "End the shift?" + choices.Add("Initiate Crew Transfer", "Continue The Round") + if(VOTE_ADD_ANTAGONIST) + if(!config.allow_extra_antags || ticker.current_state >= GAME_STATE_SETTING_UP) + return 0 + for(var/antag_type in all_antag_types) + var/datum/antagonist/antag = all_antag_types[antag_type] + if(!(antag.id in additional_antag_types) && antag.is_votable()) + choices.Add(antag.role_text) + choices.Add("None") + if(VOTE_CUSTOM) + question = sanitizeSafe(input(usr, "What is the vote for?") as text|null) + if(!question) + return 0 + for(var/i = 1 to 10) + var/option = capitalize(sanitize(input(usr, "Please enter an option or hit cancel to finish") as text|null)) + if(!option || mode || !usr.client) + break + choices.Add(option) else - var/t = round(text2num(href_list["vote"])) - if(t) // It starts from 1, so there's no problem - submit_vote(usr.ckey, t) - usr.vote() + return 0 + mode = vote_type + initiator = initiator_key + started_time = world.time + var/text = "[capitalize(mode)] vote started by [initiator]." + if(mode == VOTE_CUSTOM) + text += "\n[question]" -/mob/verb/vote() + log_vote(text) + + world << "[text]\nType vote or click here to place your votes.\nYou have [config.vote_period / 10] seconds to vote." + if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM) + world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) + + if(mode == VOTE_GAMEMODE && round_progressing) + round_progressing = 0 + world << "Round start has been delayed." + + time_remaining = round(config.vote_period / 10) + return 1 + return 0 + +/datum/controller/vote/proc/interface(var/client/C) + if(!istype(C)) + return + var/admin = 0 + if(C.holder) + if(C.holder.rights & R_ADMIN) + admin = 1 + + . = "Voting Panel" + if(mode) + if(question) + . += "

Vote: '[question]'

" + else + . += "

Vote: [capitalize(mode)]

" + . += "Time Left: [time_remaining] s
" + . += "" + if(mode == VOTE_GAMEMODE) + .+= "" + + for(var/i = 1 to choices.len) + var/votes = choices[choices[i]] + if(!votes) + votes = 0 + . += "" + var/thisVote = (current_votes[C.ckey] == i) + if(mode == VOTE_GAMEMODE) + . += "" + else + . += "" + if (additional_text.len >= i) + . += additional_text[i] + . += "" + + . += "" + + . += "
ChoicesVotesMinimum Players
[thisVote ? "" : ""][gamemode_names[choices[i]]][thisVote ? "" : ""][votes][thisVote ? "" : ""][choices[i]][thisVote ? "" : ""][votes]
Unvote

" + if(admin) + . += "(Cancel Vote) " + else + . += "

Start a vote:



" + + . += "Close" + +/datum/controller/vote/Topic(href, href_list[]) + if(!usr || !usr.client) + return + switch(href_list["vote"]) + if("close") + usr << browse(null, "window=vote") + return + + if("cancel") + if(usr.client.holder) + reset() + if("toggle_restart") + if(usr.client.holder) + config.allow_vote_restart = !config.allow_vote_restart + if("toggle_gamemode") + if(usr.client.holder) + config.allow_vote_mode = !config.allow_vote_mode + + if(VOTE_RESTART) + if(config.allow_vote_restart || usr.client.holder) + initiate_vote(VOTE_RESTART, usr.key) + if(VOTE_GAMEMODE) + if(config.allow_vote_mode || usr.client.holder) + initiate_vote(VOTE_GAMEMODE, usr.key) + if(VOTE_CREW_TRANSFER) + if(config.allow_vote_restart || usr.client.holder) + initiate_vote(VOTE_CREW_TRANSFER, usr.key) + if(VOTE_ADD_ANTAGONIST) + if(config.allow_extra_antags || usr.client.holder) + initiate_vote(VOTE_ADD_ANTAGONIST, usr.key) + if(VOTE_CUSTOM) + if(usr.client.holder) + initiate_vote(VOTE_CUSTOM, usr.key) + + if("unvote") + submit_vote(usr.ckey, null) + + else + var/t = round(text2num(href_list["vote"])) + if(t) // It starts from 1, so there's no problem + submit_vote(usr.ckey, t) + usr.client.vote() + +/client/verb/vote() set category = "OOC" set name = "Vote" if(vote) - src << browse(vote.interface(client),"window=vote") + src << browse(vote.interface(src), "window=vote;size=500x[300 + vote.choices.len * 25]") diff --git a/code/datums/EPv2.dm b/code/datums/EPv2.dm index f0e912fa55..d5b85475db 100644 --- a/code/datums/EPv2.dm +++ b/code/datums/EPv2.dm @@ -103,25 +103,26 @@ var/global/list/all_exonet_connections = list() return null // Proc: send_message() -// Parameters: 2 (target_address - the desired address to send the message to, message - the message to send) +// Parameters: 3 (target_address - the desired address to send the message to, message - the message to send, text - the message text if message is of type "text") // Description: Sends the message to target_address, by calling receive_message() on the desired datum. -/datum/exonet_protocol/proc/send_message(var/target_address, var/message) +/datum/exonet_protocol/proc/send_message(var/target_address, var/message, var/text) if(!address) return 0 for(var/datum/exonet_protocol/exonet in all_exonet_connections) if(exonet.address == target_address) - exonet.receive_message(holder, address, message) + exonet.receive_message(holder, address, message, text) break // Proc: receive_message() -// Parameters: 3 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent) +// Parameters: 4 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent, +// text - the message text if message is of type "text") // Description: Called when send_message() successfully reaches the intended datum. By default, calls receive_exonet_message() on the holder atom. -/datum/exonet_protocol/proc/receive_message(var/atom/origin_atom, var/origin_address, var/message) - holder.receive_exonet_message(origin_atom, origin_address, message) +/datum/exonet_protocol/proc/receive_message(var/atom/origin_atom, var/origin_address, var/message, var/text) + holder.receive_exonet_message(origin_atom, origin_address, message, text) return // Proc: receive_exonet_message() // Parameters: 3 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent) // Description: Override this to make your atom do something when a message is received. -/atom/proc/receive_exonet_message(var/atom/origin_atom, var/origin_address, var/message) +/atom/proc/receive_exonet_message(var/atom/origin_atom, var/origin_address, var/message, var/text) return diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 09281bf1f7..577698532e 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -28,6 +28,9 @@ height = nheight if (nref) ref = nref + // If a client exists, but they have disabled fancy windowing, disable it! + if(user && user.client && !user.client.is_preference_enabled(/datum/client_preference/browser_style)) + return add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs /datum/browser/proc/set_title(ntitle) @@ -74,10 +77,11 @@ if (title_image) title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'" - return {" + return {" - + + [head_content] @@ -177,4 +181,4 @@ if(src && src.mob) //world << "[src] was [src.mob.machine], setting to null" src.mob.unset_machine() - return \ No newline at end of file + return diff --git a/code/datums/category.dm b/code/datums/category.dm index 01cbc21386..3bc9640b79 100644 --- a/code/datums/category.dm +++ b/code/datums/category.dm @@ -2,17 +2,20 @@ * Category Collection * **********************/ /datum/category_collection - var/category_group_type // The type of categories to initialize - var/list/datum/category_group/categories // The list of initialized categories + var/category_group_type // Type of categories to initialize + var/list/datum/category_group/categories // List of initialized categories + var/list/datum/category_group/categories_by_name // Associative list of initialized categories, keyed by name /datum/category_collection/New() ..() categories = new() + categories_by_name = new() for(var/category_type in typesof(category_group_type)) var/datum/category_group/category = category_type if(initial(category.name)) category = new category(src) categories += category + categories_by_name[category.name] = category categories = dd_sortedObjectList(categories) /datum/category_collection/Destroy() @@ -26,20 +29,23 @@ ******************/ /datum/category_group var/name = "" - var/category_item_type // The type of items to initialize - var/list/datum/category_item/items // The list of initialized items - var/datum/category_collection/collection // The collection this group belongs to + var/category_item_type // Type of items to initialize + var/list/datum/category_item/items // List of initialized items + var/list/datum/category_item/items_by_name // Associative list of initialized items, by name + var/datum/category_collection/collection // The collection this group belongs to /datum/category_group/New(var/datum/category_collection/cc) ..() collection = cc items = new() + items_by_name = new() for(var/item_type in typesof(category_item_type)) var/datum/category_item/item = item_type if(initial(item.name)) item = new item(src) items += item + items_by_name[item.name] = item // For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order // If you change this, confirm that character setup doesn't become completely unordered. diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index f9b05a3afe..cc603aa2df 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -1,3 +1,4 @@ + /hook/startup/proc/createDatacore() data_core = new /datum/datacore() return 1 @@ -25,11 +26,11 @@ var/dat = {" @@ -74,11 +75,21 @@ if(real_rank in civilian_positions) civ[name] = rank department = 1 - if(real_rank in nonhuman_positions) - bot[name] = rank - department = 1 if(!department && !(name in heads)) misc[name] = rank + + // Synthetics don't have actual records, so we will pull them from here. + for(var/mob/living/silicon/ai/ai in mob_list) + bot[ai.name] = "Artificial Intelligence" + + for(var/mob/living/silicon/robot/robot in mob_list) + // No combat/syndicate cyborgs, no drones. + if(robot.module && robot.module.hide_on_manifest) + continue + + bot[robot.name] = "[robot.modtype] [robot.braintype]" + + if(heads.len > 0) dat += "" for(name in heads) @@ -176,7 +187,7 @@ G.fields["fingerprint"] = md5(H.dna.uni_identity) G.fields["p_stat"] = "Active" G.fields["m_stat"] = "Stable" - G.fields["sex"] = H.gender + G.fields["sex"] = gender2text(H.gender) G.fields["species"] = H.get_species() G.fields["home_system"] = H.home_system G.fields["citizenship"] = H.citizenship @@ -189,6 +200,7 @@ var/datum/data/record/M = CreateMedicalRecord(H.real_name, id) M.fields["b_type"] = H.b_type M.fields["b_dna"] = H.dna.unique_enzymes + M.fields["id_gender"] = gender2text(H.identifying_gender) if(H.med_record && !jobban_isbanned(H, "Records")) M.fields["notes"] = H.med_record @@ -204,7 +216,8 @@ L.fields["rank"] = H.mind.assigned_role L.fields["age"] = H.age L.fields["fingerprint"] = md5(H.dna.uni_identity) - L.fields["sex"] = H.gender + L.fields["sex"] = gender2text(H.gender) + L.fields["id_gender"] = gender2text(H.identifying_gender) L.fields["b_type"] = H.b_type L.fields["b_dna"] = H.dna.unique_enzymes L.fields["enzymes"] = H.dna.SE // Used in respawning @@ -245,8 +258,9 @@ preview_icon.Blend(E.get_icon(), ICON_OVERLAY) //Tail - if(H.species.tail) - temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.species.tail]_s") + var/use_species_tail = H.species.get_tail(H) + if(use_species_tail) + temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[use_species_tail]_s") preview_icon.Blend(temp, ICON_OVERLAY) // Skin tone @@ -408,7 +422,7 @@ G.fields["id"] = id G.fields["rank"] = "Unassigned" G.fields["real_rank"] = "Unassigned" - G.fields["sex"] = "Male" + G.fields["sex"] = "Unknown" G.fields["age"] = "Unknown" G.fields["fingerprint"] = "Unknown" G.fields["p_stat"] = "Active" @@ -450,6 +464,7 @@ M.fields["name"] = name M.fields["b_type"] = "AB+" M.fields["b_dna"] = md5(name) + M.fields["id_gender"] = "Unknown" M.fields["mi_dis"] = "None" M.fields["mi_dis_d"] = "No minor disabilities have been declared." M.fields["ma_dis"] = "None" diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 5d6400886e..aef0fd0ac2 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -14,7 +14,7 @@ var/global/datum/getrev/revdata = new() var/list/head_log = file2list(".git/logs/HEAD", "\n") for(var/line=head_log.len, line>=1, line--) if(head_log[line]) - var/list/last_entry = text2list(head_log[line], " ") + var/list/last_entry = splittext(head_log[line], " ") if(last_entry.len < 2) continue revision = last_entry[2] // Get date/time @@ -28,7 +28,6 @@ var/global/datum/getrev/revdata = new() world.log << branch world.log << date world.log << revision - return client/verb/showrevinfo() set category = "OOC" @@ -43,4 +42,3 @@ client/verb/showrevinfo() src << revdata.revision else src << "Revision unknown" - return diff --git a/code/datums/mind.dm b/code/datums/mind.dm index c058e2ff5d..11d622b255 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -61,13 +61,17 @@ //put this here for easier tracking ingame var/datum/money_account/initial_account - + //used for antag tcrystal trading, more info in code\game\objects\items\telecrystals.dm var/accept_tcrystals = 0 + //used for optional self-objectives that antagonists can give themselves, which are displayed at the end of the round. + var/ambitions + /datum/mind/New(var/key) src.key = key + ..() /datum/mind/proc/transfer_to(mob/living/new_character) if(!istype(new_character)) @@ -106,6 +110,8 @@ output += "Objective #[obj_count]: [objective.explanation_text]" obj_count++ + if(ambitions) + output += "
Ambitions: [ambitions]
" recipient << browse(output,"window=memory") /datum/mind/proc/edit_memory() @@ -139,7 +145,8 @@ else out += "None." - out += "
\[add\]" + out += "
\[add\]

" + out += "Ambitions: [ambitions ? ambitions : "None"] \[edit\]
" usr << browse(out, "window=edit_memory[src]") /datum/mind/Topic(href, href_list) @@ -147,7 +154,7 @@ if(href_list["add_antagonist"]) var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]] - if(antag) + if(antag) if(antag.add_antagonist(src, 1, 1, 0, 1, 1)) // Ignore equipment and role type for this. log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.role_text].") else @@ -179,6 +186,18 @@ if (isnull(new_memo)) return memory = new_memo + else if (href_list["amb_edit"]) + var/datum/mind/mind = locate(href_list["amb_edit"]) + if(!mind) + return + var/new_ambition = input("Enter a new ambition", "Memory", mind.ambitions) as null|message + if(isnull(new_ambition)) + return + if(mind) + mind.ambitions = sanitize(new_ambition) + mind.current << "Your ambitions have been changed by higher powers, they are now: [mind.ambitions]" + log_and_message_admins("made [key_name(mind.current)]'s ambitions be '[mind.ambitions]'.") + else if (href_list["obj_edit"] || href_list["obj_add"]) var/datum/objective/objective var/objective_pos @@ -326,7 +345,7 @@ log_admin("[key_name_admin(usr)] has de-loyalty implanted [current].") if("add") H << "You somehow have become the recepient of a loyalty transplant, and it just activated!" - H.implant_loyalty(H, override = TRUE) + H.implant_loyalty(override = TRUE) log_admin("[key_name_admin(usr)] has loyalty implanted [current].") else else if (href_list["silicon"]) diff --git a/code/datums/observation/_debug.dm b/code/datums/observation/_debug.dm new file mode 100644 index 0000000000..2f882929cf --- /dev/null +++ b/code/datums/observation/_debug.dm @@ -0,0 +1,11 @@ +/**************** +* Debug Support * +****************/ +var/datum/all_observable_events/all_observable_events = new() + +/datum/all_observable_events + var/list/events + +/datum/all_observable_events/New() + events = list() + ..() diff --git a/code/datums/observation/_defines.dm b/code/datums/observation/_defines.dm new file mode 100644 index 0000000000..902d655870 --- /dev/null +++ b/code/datums/observation/_defines.dm @@ -0,0 +1 @@ +#define CANCEL_MOVE_EVENT -55 diff --git a/code/datums/observation/destroyed.dm b/code/datums/observation/destroyed.dm new file mode 100644 index 0000000000..6a65300a25 --- /dev/null +++ b/code/datums/observation/destroyed.dm @@ -0,0 +1,15 @@ +// Observer Pattern Implementation: Destroyed +// Registration type: /datum +// +// Raised when: A /datum instance is destroyed. +// +// Arguments that the called proc should expect: +// /datum/destroyed_instance: The instance that was destroyed. +var/decl/observ/destroyed/destroyed_event = new() + +/decl/observ/destroyed + name = "Destroyed" + +/datum/Destroy() + destroyed_event.raise_event(src) + . = ..() diff --git a/code/datums/observation/dir_set.dm b/code/datums/observation/dir_set.dm new file mode 100644 index 0000000000..1f4c8e251e --- /dev/null +++ b/code/datums/observation/dir_set.dm @@ -0,0 +1,35 @@ +// Observer Pattern Implementation: Direction Set +// Registration type: /atom +// +// Raised when: An /atom changes dir using the set_dir() proc. +// +// Arguments that the called proc should expect: +// /atom/dir_changer: The instance that changed direction +// /old_dir: The dir before the change. +// /new_dir: The dir after the change. + +var/decl/observ/dir_set/dir_set_event = new() + +/decl/observ/dir_set + name = "Direction Set" + expected_type = /atom + +/decl/observ/dir_set/register(var/atom/dir_changer, var/datum/listener, var/proc_call) + . = ..() + + // Listen to the parent if possible. + if(. && istype(dir_changer.loc, /atom/movable)) // We don't care about registering to turfs. + register(dir_changer.loc, dir_changer, /atom/proc/recursive_dir_set) + +/********************* +* Direction Handling * +*********************/ + +/atom/movable/Entered(var/atom/movable/am, atom/old_loc) + . = ..() + if(. != CANCEL_MOVE_EVENT && dir_set_event.has_listeners(am)) + dir_set_event.register(src, am, /atom/proc/recursive_dir_set) + +/atom/movable/Exited(var/atom/movable/am, atom/old_loc) + . = ..() + dir_set_event.unregister(src, am, /atom/proc/recursive_dir_set) diff --git a/code/datums/observation/equipped.dm b/code/datums/observation/equipped.dm new file mode 100644 index 0000000000..de07a74355 --- /dev/null +++ b/code/datums/observation/equipped.dm @@ -0,0 +1,38 @@ +// Observer Pattern Implementation: Equipped +// Registration type: /mob +// +// Raised when: A mob equips an item. +// +// Arguments that the called proc should expect: +// /mob/equipper: The mob that equipped the item. +// /obj/item/item: The equipped item. +// slot: The slot equipped to. +var/decl/observ/mob_equipped/mob_equipped_event = new() + +/decl/observ/mob_equipped + name = "Mob Equipped" + expected_type = /mob + +// Observer Pattern Implementation: Equipped +// Registration type: /obj/item +// +// Raised when: A mob equips an item. +// +// Arguments that the called proc should expect: +// /obj/item/item: The equipped item. +// /mob/equipper: The mob that equipped the item. +// slot: The slot equipped to. +var/decl/observ/item_equipped/item_equipped_event = new() + +/decl/observ/item_equipped + name = "Item Equipped" + expected_type = /obj/item + +/******************** +* Equipped Handling * +********************/ + +/obj/item/equipped(var/mob/user, var/slot) + . = ..() + mob_equipped_event.raise_event(user, src, slot) + item_equipped_event.raise_event(src, user, slot) diff --git a/code/datums/observation/helpers.dm b/code/datums/observation/helpers.dm new file mode 100644 index 0000000000..79ee8eb08d --- /dev/null +++ b/code/datums/observation/helpers.dm @@ -0,0 +1,18 @@ +/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc) + moved_event.raise_event(src, old_loc, new_loc) + +/atom/movable/proc/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc) + var/turf/T = get_turf(new_loc) + if(T && T != loc) + forceMove(T) + +/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir) + set_dir(new_dir) + +/proc/register_all_movement(var/event_source, var/listener) + moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) + dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set) + +/proc/unregister_all_movement(var/event_source, var/listener) + moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move) + dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set) diff --git a/code/datums/observation/logged_in.dm b/code/datums/observation/logged_in.dm new file mode 100644 index 0000000000..311ff8acb6 --- /dev/null +++ b/code/datums/observation/logged_in.dm @@ -0,0 +1,21 @@ +// Observer Pattern Implementation: Logged in +// Registration type: /mob +// +// Raised when: A mob logs in (not client) +// +// Arguments that the called proc should expect: +// /mob/joiner: The mob that has logged in + +var/decl/observ/logged_in/logged_in_event = new() + +/decl/observ/logged_in + name = "Logged In" + expected_type = /mob + +/***************** +* Login Handling * +*****************/ + +/mob/Login() + ..() + logged_in_event.raise_event(src) diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm new file mode 100644 index 0000000000..86a6b793ac --- /dev/null +++ b/code/datums/observation/moved.dm @@ -0,0 +1,52 @@ +// Observer Pattern Implementation: Moved +// Registration type: /atom/movable +// +// Raised when: An /atom/movable instance has moved using Move() or forceMove(). +// +// Arguments that the called proc should expect: +// /atom/movable/moving_instance: The instance that moved +// /atom/old_loc: The loc before the move. +// /atom/new_loc: The loc after the move. + +var/decl/observ/moved/moved_event = new() + +/decl/observ/moved + name = "Moved" + expected_type = /atom/movable + +/decl/observ/moved/register(var/atom/movable/mover, var/datum/listener, var/proc_call) + . = ..() + + // Listen to the parent if possible. + if(. && istype(mover.loc, expected_type)) + register(mover.loc, mover, /atom/movable/proc/recursive_move) + +/******************** +* Movement Handling * +********************/ + +/atom/Entered(var/atom/movable/am, var/atom/old_loc) + . = ..() + moved_event.raise_event(am, old_loc, am.loc) + +/atom/movable/Entered(var/atom/movable/am, atom/old_loc) + . = ..() + if(moved_event.has_listeners(am)) + moved_event.register(src, am, /atom/movable/proc/recursive_move) + +/atom/movable/Exited(var/atom/movable/am, atom/old_loc) + . = ..() + moved_event.unregister(src, am, /atom/movable/proc/recursive_move) + +// Entered() typically lifts the moved event, but in the case of null-space we'll have to handle it. +/atom/movable/Move() + var/old_loc = loc + . = ..() + if(. && !loc) + moved_event.raise_event(src, old_loc, null) + +/atom/movable/forceMove(atom/destination) + var/old_loc = loc + . = ..() + if(. && !loc) + moved_event.raise_event(src, old_loc, null) diff --git a/code/datums/observation/observation.dm b/code/datums/observation/observation.dm new file mode 100644 index 0000000000..32a96871e6 --- /dev/null +++ b/code/datums/observation/observation.dm @@ -0,0 +1,238 @@ +// +// Observer Pattern Implementation +// +// Implements a basic observer pattern with the following main procs: +// +// /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance which is generating events. +// listener: The instance which may be listening to events by event_source +// proc_call: Optional. The specific proc to call when the event is raised. +// +// Returns true if listener is listening for events by event_source, and proc_call supplied is either null or one of the proc that will be called when an event is raised. +// +// /decl/observ/proc/has_listeners(var/event_source) +// event_source: The instance which is generating events. +// +// Returns true if the given event_source has any listeners at all, globally or to specific event sources. +// +// /decl/observ/proc/register(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance you wish to receive events from. +// listener: The instance/owner of the proc to call when an event is raised by the event_source. +// proc_call: The proc to call when an event is raised. +// +// It is possible to register the same listener to the same event_source multiple times as long as it is using different proc_calls. +// Registering again using the same event_source, listener, and proc_call that has been registered previously will have no additional effect. +// I.e.: The proc_call will still only be called once per raised event. That particular proc_call will only have to be unregistered once. +// +// When proc_call is called the first argument is always the source of the event (event_source). +// Additional arguments may or may not be supplied, see individual event definition files (destroyed.dm, moved.dm, etc.) for details. +// +// The instance making the register() call is also responsible for calling unregister(), see below for additonal details, including when event_source is destroyed. +// This can be handled by listening to the event_source's destroyed event, unregistering in the listener's Destroy() proc, etc. +// +// /decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call) +// event_source: The instance you wish to stop receiving events from. +// listener: The instance which will no longer receive the events. +// proc_call: Optional: The proc_call to unregister. +// +// Unregisters the listener from the event_source. +// If a proc_call has been supplied only that particular proc_call will be unregistered. If the proc_call isn't currently registered there will be no effect. +// If no proc_call has been supplied, the listener will have all registrations made to the given event_source undone. +// +// /decl/observ/proc/register_global(var/datum/listener, var/proc_call) +// listener: The instance/owner of the proc to call when an event is raised by any and all sources. +// proc_call: The proc to call when an event is raised. +// +// Works very much the same as register(), only the listener/proc_call will receive all relevant events from all event sources. +// Global registrations can overlap with registrations made to specific event sources and these will not affect each other. +// +// /decl/observ/proc/unregister_global(var/datum/listener, var/proc_call) +// listener: The instance/owner of the proc which will no longer receive the events. +// proc_call: Optional: The proc_call to unregister. +// +// Works very much the same as unregister(), only it undoes global registrations instead. +// +// /decl/observ/proc/raise_event(src, ...) +// Should never be called unless implementing a new event type. +// The first argument shall always be the event_source belonging to the event. Beyond that there are no restrictions. + +/decl/observ + var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry. + var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type. + var/list/event_sources = list() // Associative list of event sources, each with their own associative list. This associative list contains an instance/list of procs to call when the event is raised. + var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. + +/decl/observ/New() + all_observable_events.events += src + . = ..() + +/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) + // Return whether there are global listeners unless the event source is given. + if (!event_source) + return !!global_listeners.len + + // Return whether anything is listening to a source, if no listener is given. + if (!listener) + return global_listeners.len || (event_source in event_sources) + + // Return false if nothing is associated with that source. + if (!(event_source in event_sources)) + return FALSE + + // Get and check the listeners for the reuqested event. + var/listeners = event_sources[event_source] + if (!(listener in listeners)) + return FALSE + + // Return true unless a specific callback needs checked. + if (!proc_call) + return TRUE + + // Check if the specific callback exists. + var/list/callback = listeners[listener] + if (!callback) + return FALSE + + return (proc_call in callback) + +/decl/observ/proc/has_listeners(var/event_source) + return is_listening(event_source) + +/decl/observ/proc/register(var/datum/event_source, var/datum/listener, var/proc_call) + // Sanity checking. + if (!(event_source && listener && proc_call)) + return FALSE + if (istype(event_source, /decl/observ)) + return FALSE + + // Crash if the event source is the wrong type. + if (!istype(event_source, expected_type)) + CRASH("Unexpected type. Expected [expected_type], was [event_source.type]") + + // Setup the listeners for this source if needed. + var/list/listeners = event_sources[event_source] + if (!listeners) + listeners = list() + event_sources[event_source] = listeners + + // Make sure the callbacks are a list. + var/list/callbacks = listeners[listener] + if (!callbacks) + callbacks = list() + listeners[listener] = callbacks + + // If the proc_call is already registered skip + if(proc_call in callbacks) + return FALSE + + // Add the callback, and return true. + callbacks += proc_call + return TRUE + +/decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call) + // Sanity. + if (!(event_source && listener && (event_source in event_sources))) + return FALSE + + // Return false if nothing is listening for this event. + var/list/listeners = event_sources[event_source] + if (!listeners) + return FALSE + + // Remove all callbacks if no specific one is given. + if (!proc_call) + if(listeners.Remove(listener)) + // Perform some cleanup and return true. + if (!listeners.len) + event_sources -= event_source + return TRUE + return FALSE + + // See if the listener is registered. + var/list/callbacks = listeners[listener] + if (!callbacks) + return FALSE + + // See if the callback exists. + if(!callbacks.Remove(proc_call)) + return FALSE + + if (!callbacks.len) + listeners -= listener + if (!listeners.len) + event_sources -= event_source + return TRUE + +/decl/observ/proc/register_global(var/datum/listener, var/proc_call) + // Sanity. + if (!(listener && proc_call)) + return FALSE + + // Make sure the callbacks are setup. + var/list/callbacks = global_listeners[listener] + if (!callbacks) + callbacks = list() + global_listeners[listener] = callbacks + + // Add the callback and return true. + callbacks |= proc_call + return TRUE + +/decl/observ/proc/unregister_global(var/datum/listener, var/proc_call) + // Return false unless the listener is set as a global listener. + if (!(listener && (listener in global_listeners))) + return FALSE + + // Remove all callbacks if no specific one is given. + if (!proc_call) + global_listeners -= listener + return TRUE + + // See if the listener is registered. + var/list/callbacks = global_listeners[listener] + if (!callbacks) + return FALSE + + // See if the callback exists. + if(!callbacks.Remove(proc_call)) + return FALSE + + if (!callbacks.len) + global_listeners -= listener + return TRUE + +/decl/observ/proc/raise_event() + // Sanity + if (!args.len) + return FALSE + + // Call the global listeners. + for (var/datum/listener in global_listeners) + var/list/callbacks = global_listeners[listener] + for (var/proc_call in callbacks) + + // If the callback crashes, record the error and remove it. + try + call(listener, proc_call)(arglist(args)) + catch (var/exception/e) + error("[e.name] - [e.file] - [e.line]") + error(e.desc) + unregister_global(listener, proc_call) + + // Call the listeners for this specific event source, if they exist. + var/source = args[1] + if (source in event_sources) + var/list/listeners = event_sources[source] + for (var/datum/listener in listeners) + var/list/callbacks = listeners[listener] + for (var/proc_call in callbacks) + + // If the callback crashes, record the error and remove it. + try + call(listener, proc_call)(arglist(args)) + catch (var/exception/e) + error("[e.name] - [e.file] - [e.line]") + error(e.desc) + unregister(source, listener, proc_call) + + return TRUE diff --git a/code/datums/observation/task_triggered.dm b/code/datums/observation/task_triggered.dm new file mode 100644 index 0000000000..0c04ef2ead --- /dev/null +++ b/code/datums/observation/task_triggered.dm @@ -0,0 +1,13 @@ +// +// Observer Pattern Implementation: Scheduled task triggered +// Registration type: /datum/scheduled_task +// +// Raised when: When a scheduled task reaches its trigger time. +// +// Arguments that the called proc should expect: +// /datum/scheduled_task/task: The task that reached its trigger time. +var/decl/observ/task_triggered/task_triggered_event = new() + +/decl/observ/task_triggered + name = "Task Triggered" + expected_type = /datum/scheduled_task diff --git a/code/datums/observation/unequipped.dm b/code/datums/observation/unequipped.dm new file mode 100644 index 0000000000..3287c0a3b5 --- /dev/null +++ b/code/datums/observation/unequipped.dm @@ -0,0 +1,38 @@ +// Observer Pattern Implementation: Unequipped (dropped) +// Registration type: /mob +// +// Raised when: A mob unequips/drops an item. +// +// Arguments that the called proc should expect: +// /mob/equipped: The mob that unequipped/dropped the item. +// /obj/item/item: The unequipped item. + +var/decl/observ/mob_unequipped/mob_unequipped_event = new() + +/decl/observ/mob_unequipped + name = "Mob Unequipped" + expected_type = /mob + +// Observer Pattern Implementation: Unequipped (dropped) +// Registration type: /obj/item +// +// Raised when: A mob unequips/drops an item. +// +// Arguments that the called proc should expect: +// /obj/item/item: The unequipped item. +// /mob/equipped: The mob that unequipped/dropped the item. + +var/decl/observ/item_unequipped/item_unequipped_event = new() + +/decl/observ/item_unequipped + name = "Item Unequipped" + expected_type = /obj/item + +/********************** +* Unequipped Handling * +**********************/ + +/obj/item/dropped(var/mob/user) + ..() + mob_unequipped_event.raise_event(user, src) + item_unequipped_event.raise_event(src, user) diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm new file mode 100644 index 0000000000..eb6ccceef8 --- /dev/null +++ b/code/datums/observation/~cleanup.dm @@ -0,0 +1,70 @@ +var/list/global_listen_count = list() +var/list/event_sources_count = list() +var/list/event_listen_count = list() + +/decl/observ/destroyed/raise_event() + . = ..() + if(!.) + return + var/source = args[1] + + if(global_listen_count[source]) + cleanup_global_listener(source, global_listen_count[source]) + if(event_sources_count[source]) + cleanup_source_listeners(source, event_sources_count[source]) + if(event_listen_count[source]) + cleanup_event_listener(source, event_listen_count[source]) + + +/decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call) + . = ..() + if(.) + event_sources_count[event_source] += 1 + event_listen_count[listener] += 1 + +/decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call) + . = ..() + if(.) + event_sources_count[event_source] -= 1 + event_listen_count[listener] -= 1 + +/decl/observ/register_global(var/datum/listener, var/proc_call) + . = ..() + if(.) + global_listen_count[listener] += 1 + +/decl/observ/unregister_global(var/datum/listener, var/proc_call) + . = ..() + if(.) + global_listen_count[listener] -= 1 + +/decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count) + global_listen_count -= listener + for(var/entry in all_observable_events.events) + var/decl/observ/event = entry + if(event.unregister_global(listener)) + log_debug("[event] - [listener] was deleted while still registered to global events.") + if(!(--listen_count)) + return + +/decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count) + event_sources_count -= event_source + for(var/entry in all_observable_events.events) + var/decl/observ/event = entry + var/proc_owners = event.event_sources[event_source] + if(proc_owners) + for(var/proc_owner in proc_owners) + if(event.unregister(event_source, proc_owner)) + log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].") + if(!(--source_listener_count)) + return + +/decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count) + event_listen_count -= listener + for(var/entry in all_observable_events.events) + var/decl/observ/event = entry + for(var/event_source in event.event_sources) + if(event.unregister(event_source, listener)) + log_debug("[event] - [listener] was deleted while still listening to [event_source].") + if(!(--listener_count)) + return diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm new file mode 100644 index 0000000000..bed0f33275 --- /dev/null +++ b/code/datums/progressbar.dm @@ -0,0 +1,43 @@ +/datum/progressbar + var/goal = 1 + var/image/bar + var/shown = 0 + var/mob/user + var/client/client + +/datum/progressbar/New(mob/user, goal_number, atom/target) + . = ..() + if(!target) target = user + if (!istype(target)) + EXCEPTION("Invalid target given") + if (goal_number) + goal = goal_number + bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0") + bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + bar.pixel_y = 32 + src.user = user + if(user) + client = user.client + +/datum/progressbar/Destroy() + if (client) + client.images -= bar + qdel(bar) + . = ..() + +/datum/progressbar/proc/update(progress) + //world << "Update [progress] - [goal] - [(progress / goal)] - [((progress / goal) * 100)] - [round(((progress / goal) * 100), 5)]" + if (!user || !user.client) + shown = 0 + return + if (user.client != client) + if (client) + client.images -= bar + shown = 0 + client = user.client + + progress = Clamp(progress, 0, goal) + bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]" + if (!shown && user.is_preference_enabled(/datum/client_preference/show_progress_bar)) + user.client.images += bar + shown = 1 diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm index 6098315c11..23af6093ef 100644 --- a/code/datums/recipe.dm +++ b/code/datums/recipe.dm @@ -74,18 +74,33 @@ if (items && items.len) var/list/checklist = list() checklist = items.Copy() // You should really trust Copy - for(var/obj/O in container) - if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown)) - continue // Fruit is handled in check_fruit(). - var/found = 0 - for(var/i = 1; i < checklist.len+1; i++) - var/item_type = checklist[i] - if (istype(O,item_type)) - checklist.Cut(i, i+1) - found = 1 - break - if (!found) - . = 0 + if(istype(container, /obj/machinery)) + var/obj/machinery/machine = container + for(var/obj/O in ((machine.contents - machine.component_parts) - machine.circuit)) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown)) + continue // Fruit is handled in check_fruit(). + var/found = 0 + for(var/i = 1; i < checklist.len+1; i++) + var/item_type = checklist[i] + if (istype(O,item_type)) + checklist.Cut(i, i+1) + found = 1 + break + if (!found) + . = 0 + else + for(var/obj/O in container.contents) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown)) + continue // Fruit is handled in check_fruit(). + var/found = 0 + for(var/i = 1; i < checklist.len+1; i++) + var/item_type = checklist[i] + if (istype(O,item_type)) + checklist.Cut(i, i+1) + found = 1 + break + if (!found) + . = 0 if (checklist.len) . = -1 return . @@ -93,9 +108,15 @@ //general version /datum/recipe/proc/make(var/obj/container as obj) var/obj/result_obj = new result(container) - for (var/obj/O in (container.contents-result_obj)) - O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) - qdel(O) + if(istype(container, /obj/machinery)) + var/obj/machinery/machine = container + for (var/obj/O in ((machine.contents-result_obj - machine.component_parts) - machine.circuit)) + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + qdel(O) + else + for (var/obj/O in (container.contents-result_obj)) + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + qdel(O) container.reagents.clear_reagents() return result_obj @@ -105,12 +126,21 @@ world << "Recipe [type] is defined without a result, please bug this." return var/obj/result_obj = new result(container) - for (var/obj/O in (container.contents-result_obj)) - if (O.reagents) - O.reagents.del_reagent("nutriment") - O.reagents.update_total() - O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) - qdel(O) + if(istype(container, /obj/machinery)) + var/obj/machinery/machine = container + for (var/obj/O in ((machine.contents-result_obj - machine.component_parts) - machine.circuit)) + if (O.reagents) + O.reagents.del_reagent("nutriment") + O.reagents.update_total() + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + qdel(O) + else + for (var/obj/O in (container.contents-result_obj)) + if (O.reagents) + O.reagents.del_reagent("nutriment") + O.reagents.update_total() + O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) + qdel(O) container.reagents.clear_reagents() return result_obj diff --git a/code/datums/repositories/cameras.dm b/code/datums/repositories/cameras.dm new file mode 100644 index 0000000000..7bac2a4634 --- /dev/null +++ b/code/datums/repositories/cameras.dm @@ -0,0 +1,34 @@ +var/global/datum/repository/cameras/camera_repository = new() + +/proc/invalidateCameraCache() + camera_repository.networks.Cut() + camera_repository.invalidated = 1 + camera_repository.camera_cache_id = (++camera_repository.camera_cache_id % 999999) + +/datum/repository/cameras + var/list/networks + var/invalidated = 1 + var/camera_cache_id = 1 + +/datum/repository/cameras/New() + networks = list() + ..() + +/datum/repository/cameras/proc/cameras_in_network(var/network) + setup_cache() + var/list/network_list = networks[network] + return network_list + +/datum/repository/cameras/proc/setup_cache() + if(!invalidated) + return + invalidated = 0 + + cameranet.process_sort() + for(var/obj/machinery/camera/C in cameranet.cameras) + var/cam = C.nano_structure() + for(var/network in C.network) + if(!networks[network]) + networks[network] = list() + var/list/netlist = networks[network] + netlist[++netlist.len] = cam diff --git a/code/datums/crew.dm b/code/datums/repositories/crew.dm similarity index 95% rename from code/datums/crew.dm rename to code/datums/repositories/crew.dm index d46a83846f..6fbe1863da 100644 --- a/code/datums/crew.dm +++ b/code/datums/repositories/crew.dm @@ -1,9 +1,5 @@ var/global/datum/repository/crew/crew_repository = new() -/datum/cache_entry - var/timestamp - var/data - /datum/repository/crew var/list/cache_data diff --git a/code/datums/repositories/repository.dm b/code/datums/repositories/repository.dm new file mode 100644 index 0000000000..6267099c93 --- /dev/null +++ b/code/datums/repositories/repository.dm @@ -0,0 +1,4 @@ +/datum/cache_entry + var/timestamp + var/data + diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm deleted file mode 100644 index 1bf774c850..0000000000 --- a/code/datums/supplypacks.dm +++ /dev/null @@ -1,2295 +0,0 @@ -//SUPPLY PACKS -//NOTE: only secure crate types use the access var (and are lockable) -//NOTE: hidden packs only show up when the computer has been hacked. -//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards. -//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle. -//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points. - -var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Atmospherics","Medical","Reagents","Reagent Cartridges","Science","Hydroponics", "Supply", "Miscellaneous") - -/datum/supply_packs - var/name = null - var/list/contains = list() - var/manifest = "" - var/amount = null - var/cost = null - var/containertype = null - var/containername = null - var/access = null - var/hidden = 0 - var/contraband = 0 - var/group = "Operations" - -/datum/supply_packs/New() - manifest += "
    " - for(var/path in contains) - if(!path || !ispath(path, /atom)) - continue - var/atom/O = path - manifest += "
  • [initial(O.name)]
  • " - manifest += "
" - -/datum/supply_packs/specialops - name = "Special Ops supplies" - contains = list(/obj/item/weapon/storage/box/emps, - /obj/item/weapon/grenade/smokebomb, - /obj/item/weapon/grenade/smokebomb, - /obj/item/weapon/grenade/smokebomb, - /obj/item/weapon/pen/reagent/paralysis, - /obj/item/weapon/grenade/chem_grenade/incendiary) - cost = 20 - containertype = /obj/structure/closet/crate - containername = "Special Ops crate" - group = "Security" - hidden = 1 - -/datum/supply_packs/forensics - name = "Auxiliary forensic tools" - contains = list(/obj/item/weapon/forensics/sample_kit, - /obj/item/weapon/forensics/sample_kit/powder, - /obj/item/weapon/storage/box/swabs, - /obj/item/weapon/storage/box/swabs, - /obj/item/weapon/storage/box/swabs, - /obj/item/device/uv_light, - /obj/item/weapon/reagent_containers/spray/luminol) - cost = 30 - containertype = /obj/structure/closet/crate - containername = "Auxiliary forensic tools" - group = "Security" - -/datum/supply_packs/food - name = "Kitchen supply crate" - contains = list(/obj/item/weapon/reagent_containers/food/condiment/flour, - /obj/item/weapon/reagent_containers/food/condiment/flour, - /obj/item/weapon/reagent_containers/food/condiment/flour, - /obj/item/weapon/reagent_containers/food/condiment/flour, - /obj/item/weapon/reagent_containers/food/drinks/milk, - /obj/item/weapon/reagent_containers/food/drinks/milk, - /obj/item/weapon/storage/fancy/egg_box, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/tofu, - /obj/item/weapon/reagent_containers/food/snacks/meat, - /obj/item/weapon/reagent_containers/food/snacks/meat - ) - cost = 10 - containertype = /obj/structure/closet/crate/freezer - containername = "Food crate" - group = "Supply" - -/datum/supply_packs/monkey - name = "Monkey crate" - contains = list (/obj/item/weapon/storage/box/monkeycubes) - cost = 20 - containertype = /obj/structure/closet/crate/freezer - containername = "Monkey crate" - group = "Hydroponics" - -/datum/supply_packs/farwa - name = "Farwa crate" - contains = list (/obj/item/weapon/storage/box/monkeycubes/farwacubes) - cost = 30 - containertype = /obj/structure/closet/crate/freezer - containername = "Farwa crate" - group = "Hydroponics" - -/datum/supply_packs/skrell - name = "Neaera crate" - contains = list (/obj/item/weapon/storage/box/monkeycubes/neaeracubes) - cost = 30 - containertype = /obj/structure/closet/crate/freezer - containername = "Neaera crate" - group = "Hydroponics" - -/datum/supply_packs/stok - name = "Stok crate" - contains = list (/obj/item/weapon/storage/box/monkeycubes/stokcubes) - cost = 30 - containertype = /obj/structure/closet/crate/freezer - containername = "Stok crate" - group = "Hydroponics" - -/datum/supply_packs/beanbagammo - name = "Beanbag shells" - contains = list(/obj/item/weapon/storage/box/beanbags, - /obj/item/weapon/storage/box/beanbags, - /obj/item/weapon/storage/box/beanbags) - cost = 30 - containertype = /obj/structure/closet/crate - containername = "Beanbag shells" - group = "Security" - -/datum/supply_packs/toner - name = "Toner cartridges" - contains = list(/obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner, - /obj/item/device/toner) - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Toner cartridges" - group = "Supply" - -/datum/supply_packs/party - name = "Party equipment" - contains = list(/obj/item/weapon/storage/box/drinkingglasses, - /obj/item/weapon/reagent_containers/food/drinks/shaker, - /obj/item/weapon/reagent_containers/food/drinks/flask/barflask, - /obj/item/weapon/reagent_containers/food/drinks/bottle/patron, - /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager, - /obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey, - /obj/item/weapon/storage/fancy/cigarettes/dromedaryco, - /obj/item/weapon/lipstick/random, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, - /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer) - cost = 20 - containertype = /obj/structure/closet/crate - containername = "Party equipment" - group = "Hospitality" - -/datum/supply_packs/lasertag - name = "Lasertag equipment" - contains = list(/obj/item/weapon/gun/energy/lasertag/red, - /obj/item/clothing/suit/redtag, - /obj/item/weapon/gun/energy/lasertag/blue, - /obj/item/clothing/suit/bluetag) - containertype = /obj/structure/closet - containername = "Lasertag Closet" - group = "Hospitality" - cost = 20 - -/datum/supply_packs/internals - name = "Internals crate" - contains = list(/obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/weapon/tank/air, - /obj/item/weapon/tank/air, - /obj/item/weapon/tank/air) - cost = 10 - containertype = /obj/structure/closet/crate/internals - containername = "Internals crate" - group = "Atmospherics" - -/datum/supply_packs/evacuation - name = "Emergency equipment" - contains = list(/obj/item/weapon/storage/toolbox/emergency, - /obj/item/weapon/storage/toolbox/emergency, - /obj/item/clothing/suit/storage/hazardvest, - /obj/item/clothing/suit/storage/hazardvest, - /obj/item/clothing/suit/storage/vest, - /obj/item/clothing/suit/storage/vest, - /obj/item/weapon/tank/emergency_oxygen/engi, - /obj/item/weapon/tank/emergency_oxygen/engi, - /obj/item/weapon/tank/emergency_oxygen/engi, - /obj/item/weapon/tank/emergency_oxygen/engi, - /obj/item/clothing/suit/space/emergency, - /obj/item/clothing/suit/space/emergency, - /obj/item/clothing/suit/space/emergency, - /obj/item/clothing/suit/space/emergency, - /obj/item/clothing/head/helmet/space/emergency, - /obj/item/clothing/head/helmet/space/emergency, - /obj/item/clothing/head/helmet/space/emergency, - /obj/item/clothing/head/helmet/space/emergency, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas) - cost = 45 - containertype = /obj/structure/closet/crate/internals - containername = "Emergency crate" - group = "Atmospherics" - - -/datum/supply_packs/inflatable - name = "Inflatable barriers" - contains = list(/obj/item/weapon/storage/briefcase/inflatable, - /obj/item/weapon/storage/briefcase/inflatable, - /obj/item/weapon/storage/briefcase/inflatable) - cost = 20 - containertype = /obj/structure/closet/crate - containername = "Inflatable Barrier Crate" - group = "Atmospherics" - -/datum/supply_packs/janitor - name = "Janitorial supplies" - contains = list(/obj/item/weapon/reagent_containers/glass/bucket, - /obj/item/weapon/mop, - /obj/item/weapon/caution, - /obj/item/weapon/caution, - /obj/item/weapon/caution, - /obj/item/weapon/caution, - /obj/item/weapon/storage/bag/trash, - /obj/item/device/lightreplacer, - /obj/item/weapon/reagent_containers/spray/cleaner, - /obj/item/weapon/reagent_containers/glass/rag, - /obj/item/weapon/grenade/chem_grenade/cleaner, - /obj/item/weapon/grenade/chem_grenade/cleaner, - /obj/item/weapon/grenade/chem_grenade/cleaner, - /obj/structure/mopbucket) - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Janitorial supplies" - group = "Supply" - -/datum/supply_packs/lightbulbs - name = "Replacement lights" - contains = list(/obj/item/weapon/storage/box/lights/mixed, - /obj/item/weapon/storage/box/lights/mixed, - /obj/item/weapon/storage/box/lights/mixed) - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Replacement lights" - group = "Engineering" - -/datum/supply_packs/wizard - name = "Wizard costume" - contains = list(/obj/item/weapon/staff, - /obj/item/clothing/suit/wizrobe/fake, - /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/fake) - cost = 20 - containertype = /obj/structure/closet/crate - containername = "Wizard costume crate" - group = "Miscellaneous" - -/datum/supply_packs/foam_weapons - name = "Foam Weapon Crate" - contains = list( - /obj/item/weapon/material/sword/foam, - /obj/item/weapon/material/sword/foam, - /obj/item/weapon/material/twohanded/baseballbat/foam, - /obj/item/weapon/material/twohanded/baseballbat/foam, - /obj/item/weapon/material/twohanded/spear/foam, - /obj/item/weapon/material/twohanded/spear/foam, - /obj/item/weapon/material/twohanded/fireaxe/foam, - /obj/item/weapon/material/twohanded/fireaxe/foam - ) - cost = 80 - containertype = /obj/structure/closet/crate - containername = "foam weapon crate" - group = "Miscellaneous" - -/datum/supply_packs/mule - name = "Mulebot Crate" - contains = list() - cost = 20 - containertype = /obj/structure/largecrate/animal/mulebot - containername = "Mulebot Crate" - group = "Operations" - -/datum/supply_packs/cargotrain - name = "Cargo Train Tug" - contains = list(/obj/vehicle/train/cargo/engine) - cost = 45 - containertype = /obj/structure/largecrate - containername = "Cargo Train Tug Crate" - group = "Operations" - -/datum/supply_packs/cargotrailer - name = "Cargo Train Trolley" - contains = list(/obj/vehicle/train/cargo/trolley) - cost = 15 - containertype = /obj/structure/largecrate - containername = "Cargo Train Trolley Crate" - group = "Operations" - -/datum/supply_packs/lisa - name = "Corgi Crate" - contains = list() - cost = 50 - containertype = /obj/structure/largecrate/animal/corgi - containername = "Corgi Crate" - group = "Hydroponics" - -/datum/supply_packs/hydroponics // -- Skie - name = "Hydroponics Supply Crate" - contains = list(/obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/glass/bottle/ammonia, - /obj/item/weapon/reagent_containers/glass/bottle/ammonia, - /obj/item/weapon/material/hatchet, - /obj/item/weapon/material/minihoe, - /obj/item/device/analyzer/plant_analyzer, - /obj/item/clothing/gloves/botanic_leather, - /obj/item/clothing/suit/apron, - /obj/item/weapon/material/minihoe, - /obj/item/weapon/storage/box/botanydisk - ) // Updated with new things - cost = 15 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Hydroponics crate" - access = access_hydroponics - group = "Hydroponics" - -//farm animals - useless and annoying, but potentially a good source of food -/datum/supply_packs/cow - name = "Cow crate" - cost = 30 - containertype = /obj/structure/largecrate/animal/cow - containername = "Cow crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/goat - name = "Goat crate" - cost = 25 - containertype = /obj/structure/largecrate/animal/goat - containername = "Goat crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/chicken - name = "Chicken crate" - cost = 20 - containertype = /obj/structure/largecrate/animal/chick - containername = "Chicken crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/seeds - name = "Seeds crate" - contains = list(/obj/item/seeds/chiliseed, - /obj/item/seeds/berryseed, - /obj/item/seeds/cornseed, - /obj/item/seeds/eggplantseed, - /obj/item/seeds/tomatoseed, - /obj/item/seeds/appleseed, - /obj/item/seeds/soyaseed, - /obj/item/seeds/wheatseed, - /obj/item/seeds/carrotseed, - /obj/item/seeds/harebell, - /obj/item/seeds/lemonseed, - /obj/item/seeds/orangeseed, - /obj/item/seeds/grassseed, - /obj/item/seeds/sunflowerseed, - /obj/item/seeds/chantermycelium, - /obj/item/seeds/potatoseed, - /obj/item/seeds/sugarcaneseed) - cost = 10 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Seeds crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/weedcontrol - name = "Weed control crate" - contains = list(/obj/item/weapon/material/hatchet, - /obj/item/weapon/material/hatchet, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/weapon/reagent_containers/spray/plantbgone, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/weapon/grenade/chem_grenade/antiweed, - /obj/item/weapon/grenade/chem_grenade/antiweed) - cost = 25 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Weed control crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/exoticseeds - name = "Exotic seeds crate" - contains = list(/obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/libertymycelium, - /obj/item/seeds/reishimycelium, - /obj/item/seeds/random, - /obj/item/seeds/random, - /obj/item/seeds/random, - /obj/item/seeds/random, - /obj/item/seeds/random, - /obj/item/seeds/random, - /obj/item/seeds/kudzuseed) - cost = 15 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Exotic Seeds crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/medical - name = "Medical crate" - contains = list(/obj/item/weapon/storage/firstaid/regular, - /obj/item/weapon/storage/firstaid/fire, - /obj/item/weapon/storage/firstaid/toxin, - /obj/item/weapon/storage/firstaid/o2, - /obj/item/weapon/storage/firstaid/adv, - /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, - /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, - /obj/item/weapon/reagent_containers/glass/bottle/stoxin, - /obj/item/weapon/storage/box/syringes, - /obj/item/weapon/storage/box/autoinjectors) - cost = 10 - containertype = /obj/structure/closet/crate/medical - containername = "Medical crate" - group = "Medical" - -/datum/supply_packs/bloodpack - name = "BloodPack crate" - contains = list(/obj/item/weapon/storage/box/bloodpacks, - /obj/item/weapon/storage/box/bloodpacks, - /obj/item/weapon/storage/box/bloodpacks) - cost = 10 - containertype = /obj/structure/closet/crate/medical - containername = "BloodPack crate" - group = "Medical" - -/datum/supply_packs/bodybag - name = "Body bag crate" - contains = list(/obj/item/weapon/storage/box/bodybags, - /obj/item/weapon/storage/box/bodybags, - /obj/item/weapon/storage/box/bodybags) - cost = 10 - containertype = /obj/structure/closet/crate/medical - containername = "Body bag crate" - group = "Medical" - -/datum/supply_packs/cryobag - name = "Stasis bag crate" - contains = list(/obj/item/bodybag/cryobag, - /obj/item/bodybag/cryobag, - /obj/item/bodybag/cryobag) - cost = 50 - containertype = /obj/structure/closet/crate/medical - containername = "Stasis bag crate" - group = "Medical" - -/datum/supply_packs/virus - name = "Virus sample crate" -/* contains = list(/obj/item/weapon/reagent_containers/glass/bottle/flu_virion, - /obj/item/weapon/reagent_containers/glass/bottle/cold, - /obj/item/weapon/reagent_containers/glass/bottle/epiglottis_virion, - /obj/item/weapon/reagent_containers/glass/bottle/liver_enhance_virion, - /obj/item/weapon/reagent_containers/glass/bottle/fake_gbs, - /obj/item/weapon/reagent_containers/glass/bottle/magnitis, - /obj/item/weapon/reagent_containers/glass/bottle/pierrot_throat, - /obj/item/weapon/reagent_containers/glass/bottle/brainrot, - /obj/item/weapon/reagent_containers/glass/bottle/hullucigen_virion, - /obj/item/weapon/storage/box/syringes, - /obj/item/weapon/storage/box/beakers, - /obj/item/weapon/reagent_containers/glass/bottle/mutagen)*/ - contains = list(/obj/item/weapon/virusdish/random, - /obj/item/weapon/virusdish/random, - /obj/item/weapon/virusdish/random, - /obj/item/weapon/virusdish/random) - cost = 25 - containertype = "/obj/structure/closet/crate/secure" - containername = "Virus sample crate" - access = access_cmo - group = "Science" - -/datum/supply_packs/metal50 - name = "50 metal sheets" - contains = list(/obj/item/stack/material/steel) - amount = 50 - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Metal sheets crate" - group = "Engineering" - -/datum/supply_packs/glass50 - name = "50 glass sheets" - contains = list(/obj/item/stack/material/glass) - amount = 50 - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Glass sheets crate" - group = "Engineering" - -/datum/supply_packs/wood50 - name = "50 wooden planks" - contains = list(/obj/item/stack/material/wood) - amount = 50 - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Wooden planks crate" - group = "Engineering" - -/datum/supply_packs/plastic50 - name = "50 plastic sheets" - contains = list(/obj/item/stack/material/plastic) - amount = 50 - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Plastic sheets crate" - group = "Engineering" - -/datum/supply_packs/smescoil - name = "Superconducting Magnetic Coil" - contains = list(/obj/item/weapon/smes_coil) - cost = 75 - containertype = /obj/structure/closet/crate - containername = "Superconducting Magnetic Coil crate" - group = "Engineering" - -/datum/supply_packs/electrical - name = "Electrical maintenance crate" - contains = list(/obj/item/weapon/storage/toolbox/electrical, - /obj/item/weapon/storage/toolbox/electrical, - /obj/item/clothing/gloves/yellow, - /obj/item/clothing/gloves/yellow, - /obj/item/weapon/cell, - /obj/item/weapon/cell, - /obj/item/weapon/cell/high, - /obj/item/weapon/cell/high) - cost = 15 - containertype = /obj/structure/closet/crate - containername = "Electrical maintenance crate" - group = "Engineering" - -/datum/supply_packs/mechanical - name = "Mechanical maintenance crate" - contains = list(/obj/item/weapon/storage/belt/utility/full, - /obj/item/weapon/storage/belt/utility/full, - /obj/item/weapon/storage/belt/utility/full, - /obj/item/clothing/suit/storage/hazardvest, - /obj/item/clothing/suit/storage/hazardvest, - /obj/item/clothing/suit/storage/hazardvest, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/welding, - /obj/item/clothing/head/hardhat) - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Mechanical maintenance crate" - group = "Engineering" - -/datum/supply_packs/watertank - name = "Water tank crate" - contains = list(/obj/structure/reagent_dispensers/watertank) - cost = 8 - containertype = /obj/structure/largecrate - containername = "water tank crate" - group = "Hydroponics" - -/datum/supply_packs/fueltank - name = "Fuel tank crate" - contains = list(/obj/structure/reagent_dispensers/fueltank) - cost = 8 - containertype = /obj/structure/largecrate - containername = "fuel tank crate" - group = "Engineering" - -/datum/supply_packs/coolanttank - name = "Coolant tank crate" - contains = list(/obj/structure/reagent_dispensers/coolanttank) - cost = 16 - containertype = /obj/structure/largecrate - containername = "coolant tank crate" - group = "Science" - -/datum/supply_packs/solar - name = "Solar Pack crate" - contains = list(/obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, - /obj/item/solar_assembly, // 21 Solar Assemblies. 1 Extra for the controller - /obj/item/weapon/circuitboard/solar_control, - /obj/item/weapon/tracker_electronics, - /obj/item/weapon/paper/solar) - cost = 20 - containertype = /obj/structure/closet/crate - containername = "Solar pack crate" - group = "Engineering" - -/datum/supply_packs/engine - name = "Emitter crate" - contains = list(/obj/machinery/power/emitter, - /obj/machinery/power/emitter) - cost = 10 - containertype = /obj/structure/closet/crate/secure - containername = "Emitter crate" - access = access_ce - group = "Engineering" - -/datum/supply_packs/engine/field_gen - name = "Field Generator crate" - contains = list(/obj/machinery/field_generator, - /obj/machinery/field_generator) - containertype = /obj/structure/closet/crate/secure - containername = "Field Generator crate" - access = access_ce - group = "Engineering" - -/datum/supply_packs/engine/sing_gen - name = "Singularity Generator crate" - contains = list(/obj/machinery/the_singularitygen) - containertype = /obj/structure/closet/crate/secure - containername = "Singularity Generator crate" - access = access_ce - group = "Engineering" - -/datum/supply_packs/engine/collector - name = "Collector crate" - contains = list(/obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector, - /obj/machinery/power/rad_collector) - containername = "Collector crate" - group = "Engineering" - -/datum/supply_packs/engine/PA - name = "Particle Accelerator crate" - cost = 40 - contains = list(/obj/structure/particle_accelerator/fuel_chamber, - /obj/machinery/particle_accelerator/control_box, - /obj/structure/particle_accelerator/particle_emitter/center, - /obj/structure/particle_accelerator/particle_emitter/left, - /obj/structure/particle_accelerator/particle_emitter/right, - /obj/structure/particle_accelerator/power_box, - /obj/structure/particle_accelerator/end_cap) - containertype = /obj/structure/closet/crate/secure - containername = "Particle Accelerator crate" - access = access_ce - group = "Engineering" - -/datum/supply_packs/mecha_ripley - name = "Circuit Crate (\"Ripley\" APLU)" - contains = list(/obj/item/weapon/book/manual/ripley_build_and_repair, - /obj/item/weapon/circuitboard/mecha/ripley/main, //TEMPORARY due to lack of circuitboard printer - /obj/item/weapon/circuitboard/mecha/ripley/peripherals) //TEMPORARY due to lack of circuitboard printer - cost = 30 - containertype = /obj/structure/closet/crate/secure - containername = "APLU \"Ripley\" Circuit Crate" - access = access_robotics - group = "Science" - -/datum/supply_packs/mecha_odysseus - name = "Circuit Crate (\"Odysseus\")" - contains = list(/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, //TEMPORARY due to lack of circuitboard printer - /obj/item/weapon/circuitboard/mecha/odysseus/main) //TEMPORARY due to lack of circuitboard printer - cost = 25 - containertype = /obj/structure/closet/crate/secure - containername = "\"Odysseus\" Circuit Crate" - access = access_robotics - group = "Science" - -/datum/supply_packs/hoverpod - name = "Hoverpod Shipment" - contains = list() - cost = 80 - containertype = /obj/structure/largecrate/hoverpod - containername = "Hoverpod Crate" - group = "Operations" - -/datum/supply_packs/robotics - name = "Robotics assembly crate" - contains = list(/obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/weapon/storage/toolbox/electrical, - /obj/item/device/flash, - /obj/item/device/flash, - /obj/item/device/flash, - /obj/item/device/flash, - /obj/item/weapon/cell/high, - /obj/item/weapon/cell/high) - cost = 10 - containertype = /obj/structure/closet/crate/secure/gear - containername = "Robotics assembly" - access = access_robotics - group = "Engineering" - -/datum/supply_packs/phoron - name = "Phoron assembly crate" - contains = list(/obj/item/weapon/tank/phoron, - /obj/item/weapon/tank/phoron, - /obj/item/weapon/tank/phoron, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/igniter, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/prox_sensor, - /obj/item/device/assembly/timer, - /obj/item/device/assembly/timer, - /obj/item/device/assembly/timer) - cost = 10 - containertype = /obj/structure/closet/crate/secure/phoron - containername = "Phoron assembly crate" - access = access_tox_storage - group = "Science" - -/datum/supply_packs/weapons - name = "Weapons crate" - contains = list(/obj/item/weapon/melee/baton, - /obj/item/weapon/melee/baton, - /obj/item/weapon/gun/energy/gun, - /obj/item/weapon/gun/energy/gun, - /obj/item/weapon/gun/energy/taser, - /obj/item/weapon/gun/energy/taser, - /obj/item/weapon/gun/projectile/colt/detective, - /obj/item/weapon/gun/projectile/colt/detective, - /obj/item/weapon/storage/box/flashbangs, - /obj/item/weapon/storage/box/flashbangs) - cost = 40 - containertype = /obj/structure/closet/crate/secure/weapon - containername = "Weapons crate" - access = access_security - group = "Security" - -/datum/supply_packs/flareguns - name = "Flare guns crate" - contains = list(/obj/item/weapon/gun/projectile/sec/flash, - /obj/item/ammo_magazine/c45m/flash, - /obj/item/weapon/gun/projectile/shotgun/doublebarrel/flare, - /obj/item/weapon/storage/box/flashshells) - cost = 25 - containertype = /obj/structure/closet/crate/secure/weapon - containername = "Flare gun crate" - access = access_security - group = "Security" - -/datum/supply_packs/eweapons - name = "Experimental weapons crate" - contains = list(/obj/item/weapon/gun/energy/xray, - /obj/item/weapon/gun/energy/xray, - /obj/item/weapon/shield/energy, - /obj/item/weapon/shield/energy) - cost = 125 - containertype = /obj/structure/closet/crate/secure/weapon - containername = "Experimental weapons crate" - access = access_armory - group = "Security" - -/datum/supply_packs/randomised/armor - num_contained = 5 - contains = list(/obj/item/clothing/suit/storage/vest, - /obj/item/clothing/suit/storage/vest/officer, - /obj/item/clothing/suit/storage/vest/warden, - /obj/item/clothing/suit/storage/vest/hos, - /obj/item/clothing/suit/storage/vest/pcrc, - /obj/item/clothing/suit/storage/vest/detective, - /obj/item/clothing/suit/storage/vest/heavy, - /obj/item/clothing/suit/storage/vest/heavy/officer, - /obj/item/clothing/suit/storage/vest/heavy/warden, - /obj/item/clothing/suit/storage/vest/heavy/hos, - /obj/item/clothing/suit/storage/vest/heavy/pcrc) - - name = "Armor crate" - cost = 40 - containertype = /obj/structure/closet/crate/secure - containername = "Armor crate" - access = access_security - group = "Security" - -/datum/supply_packs/riot_gear - name = "Riot gear crate" - contains = list(/obj/item/weapon/melee/baton, - /obj/item/weapon/melee/baton, - /obj/item/weapon/melee/baton, - /obj/item/weapon/shield/riot, - /obj/item/weapon/shield/riot, - /obj/item/weapon/shield/riot, - /obj/item/weapon/handcuffs, - /obj/item/weapon/handcuffs, - /obj/item/weapon/handcuffs, - /obj/item/weapon/storage/box/flashbangs, - /obj/item/weapon/storage/box/beanbags, - /obj/item/weapon/storage/box/handcuffs) - cost = 40 - containertype = /obj/structure/closet/crate/secure - containername = "riot gear crate" - access = access_armory - group = "Security" - -/datum/supply_packs/riot_armor - name = "Riot armor set crate" - contains = list(/obj/item/clothing/head/helmet/riot, - /obj/item/clothing/suit/armor/riot, - /obj/item/clothing/gloves/arm_guard/riot, - /obj/item/clothing/shoes/leg_guard/riot) - cost = 30 - containertype = /obj/structure/closet/crate/secure - containername = "riot armor set crate" - access = access_armory - group = "Security" - -/datum/supply_packs/ablative_armor - name = "Ablative armor set crate" - contains = list(/obj/item/clothing/head/helmet/laserproof, - /obj/item/clothing/suit/armor/laserproof, - /obj/item/clothing/gloves/arm_guard/laserproof, - /obj/item/clothing/shoes/leg_guard/laserproof) - cost = 40 - containertype = /obj/structure/closet/crate/secure - containername = "ablative armor set crate" - access = access_armory - group = "Security" - -/datum/supply_packs/bullet_resistant_armor - name = "Bullet resistant armor set crate" - contains = list(/obj/item/clothing/head/helmet/bulletproof, - /obj/item/clothing/suit/armor/bulletproof, - /obj/item/clothing/gloves/arm_guard/bulletproof, - /obj/item/clothing/shoes/leg_guard/bulletproof) - cost = 35 - containertype = /obj/structure/closet/crate/secure - containername = "bullet resistant armor set crate" - access = access_armory - group = "Security" - -/datum/supply_packs/combat_armor - name = "Combat armor set crate" - contains = list(/obj/item/clothing/head/helmet/combat, - /obj/item/clothing/suit/armor/combat, - /obj/item/clothing/gloves/arm_guard/combat, - /obj/item/clothing/shoes/leg_guard/combat) - cost = 40 - containertype = /obj/structure/closet/crate/secure - containername = "combat armor set crate" - access = access_armory - group = "Security" - -/datum/supply_packs/tactical - name = "Tactical suits" - containertype = /obj/structure/closet/crate/secure - containername = "Tactical Suit Locker" - cost = 60 - group = "Security" - access = access_armory - contains = list(/obj/item/clothing/under/tactical, - /obj/item/clothing/suit/armor/tactical, - /obj/item/clothing/head/helmet/tactical, - /obj/item/clothing/mask/balaclava/tactical, - /obj/item/clothing/glasses/sunglasses/sechud/tactical, - /obj/item/weapon/storage/belt/security/tactical, - /obj/item/clothing/shoes/jackboots, - /obj/item/clothing/gloves/black, - /obj/item/clothing/under/tactical, - /obj/item/clothing/suit/armor/tactical, - /obj/item/clothing/head/helmet/tactical, - /obj/item/clothing/mask/balaclava/tactical, - /obj/item/clothing/glasses/sunglasses/sechud/tactical, - /obj/item/weapon/storage/belt/security/tactical, - /obj/item/clothing/shoes/jackboots, - /obj/item/clothing/gloves/black) - -/datum/supply_packs/energyweapons - name = "Energy weapons crate" - contains = list(/obj/item/weapon/gun/energy/laser, - /obj/item/weapon/gun/energy/laser, - /obj/item/weapon/gun/energy/laser) - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "energy weapons crate" - access = access_armory - group = "Security" - -/datum/supply_packs/shotgun - name = "Shotgun crate" - contains = list(/obj/item/weapon/storage/box/shotgunammo, - /obj/item/weapon/storage/box/shotgunshells, - /obj/item/weapon/gun/projectile/shotgun/pump/combat, - /obj/item/weapon/gun/projectile/shotgun/pump/combat) - cost = 65 - containertype = /obj/structure/closet/crate/secure - containername = "Shotgun crate" - access = access_armory - group = "Security" - -/datum/supply_packs/erifle - name = "Energy marksman crate" - contains = list(/obj/item/weapon/gun/energy/sniperrifle, - /obj/item/weapon/gun/energy/sniperrifle) - cost = 90 - containertype = /obj/structure/closet/crate/secure - containername = "Energy marksman crate" - access = access_armory - group = "Security" - -/datum/supply_packs/shotgunammo - name = "Ballistic ammunition crate" - contains = list(/obj/item/weapon/storage/box/shotgunammo, - /obj/item/weapon/storage/box/shotgunammo, - /obj/item/weapon/storage/box/shotgunshells, - /obj/item/weapon/storage/box/shotgunshells) - cost = 60 - containertype = /obj/structure/closet/crate/secure - containername = "ballistic ammunition crate" - access = access_armory - group = "Security" - -/datum/supply_packs/ionweapons - name = "Electromagnetic weapons crate" - contains = list(/obj/item/weapon/gun/energy/ionrifle, - /obj/item/weapon/gun/energy/ionrifle, - /obj/item/weapon/storage/box/emps) - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "electromagnetic weapons crate" - access = access_armory - group = "Security" - -/datum/supply_packs/randomised/automatic - name = "Automatic weapon crate" - num_contained = 2 - contains = list(/obj/item/weapon/gun/projectile/automatic/wt550, - /obj/item/weapon/gun/projectile/automatic/z8) - cost = 90 - containertype = /obj/structure/closet/crate/secure - containername = "Automatic weapon crate" - access = access_armory - group = "Security" - -/datum/supply_packs/randomised/autoammo - name = "Automatic weapon ammunition crate" - num_contained = 6 - contains = list(/obj/item/ammo_magazine/mc9mmt, - /obj/item/ammo_magazine/mc9mmt/rubber, - /obj/item/ammo_magazine/a556) - cost = 20 - containertype = /obj/structure/closet/crate/secure - containername = "Automatic weapon ammunition crate" - access = access_armory - group = "Security" - -/* -/datum/supply_packs/loyalty - name = "Loyalty implant crate" - contains = list (/obj/item/weapon/storage/lockbox/loyalty) - cost = 60 - containertype = /obj/structure/closet/crate/secure - containername = "Loyalty implant crate" - access = access_armory - group = "Security" -*/ - -/datum/supply_packs/energy_guns - name = "energy guns crate" - contains = list(/obj/item/weapon/gun/energy/gun, - /obj/item/weapon/gun/energy/gun) - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "energy guns crate" - access = access_armory - group = "Security" - -/datum/supply_packs/securitybarriers - name = "Security barrier crate" - contains = list(/obj/machinery/deployable/barrier, - /obj/machinery/deployable/barrier, - /obj/machinery/deployable/barrier, - /obj/machinery/deployable/barrier) - cost = 20 - containertype = /obj/structure/closet/crate/secure/gear - containername = "Security barrier crate" - group = "Security" - -/datum/supply_packs/securitybarriers - name = "Wall shield Generators" - contains = list(/obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen, - /obj/machinery/shieldwallgen) - cost = 20 - containertype = /obj/structure/closet/crate/secure - containername = "wall shield generators crate" - access = access_teleporter - group = "Security" - -/datum/supply_packs/randomised - var/num_contained = 4 //number of items picked to be contained in a randomised crate - contains = list(/obj/item/clothing/head/collectable/chef, - /obj/item/clothing/head/collectable/paper, - /obj/item/clothing/head/collectable/tophat, - /obj/item/clothing/head/collectable/captain, - /obj/item/clothing/head/collectable/beret, - /obj/item/clothing/head/collectable/welding, - /obj/item/clothing/head/collectable/flatcap, - /obj/item/clothing/head/collectable/pirate, - /obj/item/clothing/head/collectable/kitty, - /obj/item/clothing/head/collectable/rabbitears, - /obj/item/clothing/head/collectable/wizard, - /obj/item/clothing/head/collectable/hardhat, - /obj/item/clothing/head/collectable/HoS, - /obj/item/clothing/head/collectable/thunderdome, - /obj/item/clothing/head/collectable/swat, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/police, - /obj/item/clothing/head/collectable/slime, - /obj/item/clothing/head/collectable/xenom, - /obj/item/clothing/head/collectable/petehat) - name = "Collectable hat crate!" - cost = 200 - containertype = /obj/structure/closet/crate - containername = "Collectable hats crate! Brought to you by Bass.inc!" - group = "Miscellaneous" - -/datum/supply_packs/randomised/New() - manifest += "Contains any [num_contained] of:" - ..() - -/datum/supply_packs/artscrafts - name = "Arts and Crafts supplies" - contains = list(/obj/item/weapon/storage/fancy/crayons, - /obj/item/device/camera, - /obj/item/device/camera_film, - /obj/item/device/camera_film, - /obj/item/weapon/storage/photo_album, - /obj/item/weapon/packageWrap, - /obj/item/weapon/reagent_containers/glass/paint/red, - /obj/item/weapon/reagent_containers/glass/paint/green, - /obj/item/weapon/reagent_containers/glass/paint/blue, - /obj/item/weapon/reagent_containers/glass/paint/yellow, - /obj/item/weapon/reagent_containers/glass/paint/purple, - /obj/item/weapon/reagent_containers/glass/paint/black, - /obj/item/weapon/reagent_containers/glass/paint/white, - /obj/item/weapon/contraband/poster, - /obj/item/weapon/wrapping_paper, - /obj/item/weapon/wrapping_paper, - /obj/item/weapon/wrapping_paper) - cost = 10 - containertype = "/obj/structure/closet/crate" - containername = "Arts and Crafts crate" - group = "Operations" - - -/datum/supply_packs/randomised/contraband - num_contained = 5 - contains = list(/obj/item/seeds/bloodtomatoseed, - /obj/item/weapon/storage/pill_bottle/zoom, - /obj/item/weapon/storage/pill_bottle/happy, - /obj/item/weapon/reagent_containers/food/drinks/bottle/pwine) - - name = "Contraband crate" - cost = 30 - containertype = /obj/structure/closet/crate - containername = "Unlabeled crate" - contraband = 1 - group = "Operations" - -/datum/supply_packs/boxes - name = "Empty boxes" - contains = list(/obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box, - /obj/item/weapon/storage/box) - cost = 10 - containertype = "/obj/structure/closet/crate" - containername = "Empty box crate" - group = "Supply" - -/datum/supply_packs/surgery - name = "Surgery crate" - contains = list(/obj/item/weapon/cautery, - /obj/item/weapon/surgicaldrill, - /obj/item/clothing/mask/breath/medical, - /obj/item/weapon/tank/anesthetic, - /obj/item/weapon/FixOVein, - /obj/item/weapon/hemostat, - /obj/item/weapon/scalpel, - /obj/item/weapon/bonegel, - /obj/item/weapon/retractor, - /obj/item/weapon/bonesetter, - /obj/item/weapon/circular_saw) - cost = 25 - containertype = "/obj/structure/closet/crate/secure" - containername = "Surgery crate" - access = access_medical - group = "Medical" - -/datum/supply_packs/sterile - name = "Sterile equipment crate" - contains = list(/obj/item/clothing/under/rank/medical/green, - /obj/item/clothing/under/rank/medical/green, - /obj/item/clothing/head/surgery/green, - /obj/item/clothing/head/surgery/green, - /obj/item/weapon/storage/box/masks, - /obj/item/weapon/storage/box/gloves, - /obj/item/weapon/storage/belt/medical, - /obj/item/weapon/storage/belt/medical, - /obj/item/weapon/storage/belt/medical) - cost = 15 - containertype = "/obj/structure/closet/crate" - containername = "Sterile equipment crate" - group = "Medical" - -/datum/supply_packs/randomised/pizza - num_contained = 5 - contains = list(/obj/item/pizzabox/margherita, - /obj/item/pizzabox/mushroom, - /obj/item/pizzabox/meat, - /obj/item/pizzabox/vegetable) - name = "Surprise pack of five pizzas" - cost = 15 - containertype = /obj/structure/closet/crate/freezer - containername = "Pizza crate" - group = "Hospitality" - -/datum/supply_packs/randomised/costume - num_contained = 3 - contains = list(/obj/item/clothing/suit/pirate, - /obj/item/clothing/suit/judgerobe, - /obj/item/clothing/suit/wcoat, - /obj/item/clothing/suit/hastur, - /obj/item/clothing/suit/holidaypriest, - /obj/item/clothing/suit/nun, - /obj/item/clothing/suit/imperium_monk, - /obj/item/clothing/suit/ianshirt, - /obj/item/clothing/under/gimmick/rank/captain/suit, - /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/under/rank/mailman, - /obj/item/clothing/under/dress/dress_saloon, - /obj/item/clothing/suit/suspenders, - /obj/item/clothing/suit/storage/toggle/labcoat/mad, - /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, - /obj/item/clothing/under/schoolgirl, - /obj/item/clothing/under/owl, - /obj/item/clothing/under/waiter, - /obj/item/clothing/under/gladiator, - /obj/item/clothing/under/soviet, - /obj/item/clothing/under/scratch, - /obj/item/clothing/under/wedding/bride_white, - /obj/item/clothing/suit/chef, - /obj/item/clothing/suit/apron/overalls, - /obj/item/clothing/under/redcoat, - /obj/item/clothing/under/kilt) - name = "Costumes crate" - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Actor Costumes" - group = "Miscellaneous" - -/datum/supply_packs/formal_wear - contains = list(/obj/item/clothing/head/bowler, - /obj/item/clothing/head/that, - /obj/item/clothing/suit/storage/toggle/internalaffairs, - /obj/item/clothing/suit/storage/toggle/lawyer/bluejacket, - /obj/item/clothing/suit/storage/toggle/lawyer/purpjacket, - /obj/item/clothing/under/suit_jacket, - /obj/item/clothing/under/suit_jacket/female, - /obj/item/clothing/under/suit_jacket/really_black, - /obj/item/clothing/under/suit_jacket/red, - /obj/item/clothing/under/lawyer/bluesuit, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/shoes/black, - /obj/item/clothing/shoes/black, - /obj/item/clothing/shoes/leather, - /obj/item/clothing/suit/wcoat) - name = "Formalwear closet" - cost = 30 - containertype = /obj/structure/closet - containername = "Formalwear for the best occasions." - group = "Miscellaneous" - -/datum/supply_packs/randomised/card_packs - num_contained = 5 - contains = list(/obj/item/weapon/pack/cardemon, - /obj/item/weapon/pack/spaceball, - /obj/item/weapon/deck/holder) - name = "Trading Card Crate" - cost = 10 - containertype = /obj/structure/closet/crate - containername = "cards crate" - group = "Miscellaneous" - -/datum/supply_packs/shield_gen - contains = list(/obj/item/weapon/circuitboard/shield_gen) - name = "Bubble shield generator circuitry" - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "bubble shield generator circuitry crate" - group = "Engineering" - access = access_ce - -/datum/supply_packs/shield_gen_ex - contains = list(/obj/item/weapon/circuitboard/shield_gen_ex) - name = "Hull shield generator circuitry" - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "hull shield generator circuitry crate" - group = "Engineering" - access = access_ce - -/datum/supply_packs/shield_cap - contains = list(/obj/item/weapon/circuitboard/shield_cap) - name = "Bubble shield capacitor circuitry" - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "shield capacitor circuitry crate" - group = "Engineering" - access = access_ce - -/datum/supply_packs/smbig - name = "Supermatter Core" - contains = list(/obj/machinery/power/supermatter) - cost = 150 - containertype = /obj/structure/closet/crate/secure/phoron - containername = "Supermatter crate (CAUTION)" - group = "Engineering" - access = access_ce - - -/* /datum/supply_packs/smsmall // Currently nonfunctional, waiting on virgil - name = "Supermatter Shard" - contains = list(/obj/machinery/power/supermatter/shard) - cost = 25 - containertype = /obj/structure/closet/crate/secure/phoron - containername = "Supermatter shard crate (CAUTION)" - access = access_ce - group = "Engineering" */ - -/datum/supply_packs/eftpos - contains = list(/obj/item/device/eftpos) - name = "EFTPOS scanner" - cost = 10 - containertype = /obj/structure/closet/crate - containername = "EFTPOS crate" - group = "Miscellaneous" - -/datum/supply_packs/teg - contains = list(/obj/machinery/power/generator) - name = "Mark I Thermoelectric Generator" - cost = 75 - containertype = /obj/structure/closet/crate/secure/large - containername = "Mk1 TEG crate" - group = "Engineering" - access = access_engine - -/datum/supply_packs/circulator - contains = list(/obj/machinery/atmospherics/binary/circulator) - name = "Binary atmospheric circulator" - cost = 60 - containertype = /obj/structure/closet/crate/secure/large - containername = "Atmospheric circulator crate" - group = "Engineering" - access = access_engine - -/datum/supply_packs/air_dispenser - contains = list(/obj/machinery/pipedispenser/orderable) - name = "Pipe Dispenser" - cost = 35 - containertype = /obj/structure/closet/crate/secure/large - containername = "Pipe Dispenser Crate" - group = "Engineering" - access = access_atmospherics - -/datum/supply_packs/disposals_dispenser - contains = list(/obj/machinery/pipedispenser/disposal/orderable) - name = "Disposals Pipe Dispenser" - cost = 35 - containertype = /obj/structure/closet/crate/secure/large - containername = "Disposal Dispenser Crate" - group = "Engineering" - access = access_atmospherics - -/datum/supply_packs/bee_keeper - name = "Beekeeping crate" - contains = list(/obj/item/beehive_assembly, - /obj/item/bee_smoker, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/honey_frame, - /obj/item/bee_pack) - cost = 40 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Beekeeping crate" - access = access_hydroponics - group = "Hydroponics" - -/datum/supply_packs/cardboard_sheets - contains = list(/obj/item/stack/material/cardboard) - name = "50 cardboard sheets" - amount = 50 - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Cardboard sheets crate" - group = "Miscellaneous" - -/datum/supply_packs/bureaucracy - contains = list(/obj/item/weapon/clipboard, - /obj/item/weapon/clipboard, - /obj/item/weapon/pen/red, - /obj/item/weapon/pen/blue, - /obj/item/weapon/pen/blue, - /obj/item/device/camera_film, - /obj/item/weapon/folder/blue, - /obj/item/weapon/folder/red, - /obj/item/weapon/folder/yellow, - /obj/item/weapon/hand_labeler, - /obj/item/weapon/tape_roll, - /obj/structure/filingcabinet/chestdrawer{anchored = 0}, - /obj/item/weapon/paper_bin) - name = "Office supplies" - cost = 15 - containertype = /obj/structure/closet/crate - containername = "Office supplies crate" - group = "Supply" - -/datum/supply_packs/radsuit - contains = list(/obj/item/clothing/suit/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/head/radiation) - name = "Radiation suits package" - cost = 20 - containertype = /obj/structure/closet/radiation - containername = "Radiation suit locker" - group = "Engineering" - -/datum/supply_packs/carpet - name = "Imported carpet" - containertype = /obj/structure/closet - containername = "Imported carpet crate" - cost = 15 - group = "Miscellaneous" - contains = list(/obj/item/stack/tile/carpet) - amount = 50 - -/datum/supply_packs/linoleum - name = "Linoleum" - containertype = /obj/structure/closet - containername = "Linoleum crate" - cost = 15 - group = "Miscellaneous" - contains = list(/obj/item/stack/tile/linoleum) - amount = 50 - -/datum/supply_packs/hydrotray - name = "Empty hydroponics tray" - cost = 30 - containertype = /obj/structure/closet/crate/hydroponics - containername = "Hydroponics tray crate" - group = "Hydroponics" - contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0}) - access = access_hydroponics - -/datum/supply_packs/canister_empty - name = "Empty gas canister" - cost = 7 - containername = "Empty gas canister crate" - containertype = /obj/structure/largecrate - contains = list(/obj/machinery/portable_atmospherics/canister) - group = "Atmospherics" - -/datum/supply_packs/canister_air - name = "Air canister" - cost = 10 - containername = "Air canister crate" - containertype = /obj/structure/largecrate - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/air) - -/datum/supply_packs/canister_oxygen - name = "Oxygen canister" - cost = 15 - containername = "Oxygen canister crate" - containertype = /obj/structure/largecrate - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) - -/datum/supply_packs/canister_nitrogen - name = "Nitrogen canister" - cost = 10 - containername = "Nitrogen canister crate" - containertype = /obj/structure/largecrate - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) - -/datum/supply_packs/canister_phoron - name = "Phoron gas canister" - cost = 60 - containername = "Phoron gas canister crate" - containertype = /obj/structure/closet/crate/secure/large - access = access_atmospherics - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/phoron) - -/datum/supply_packs/canister_sleeping_agent - name = "N2O gas canister" - cost = 40 - containername = "N2O gas canister crate" - containertype = /obj/structure/closet/crate/secure/large - access = access_atmospherics - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent) - -/datum/supply_packs/canister_carbon_dioxide - name = "Carbon dioxide gas canister" - cost = 40 - containername = "CO2 canister crate" - containertype = /obj/structure/closet/crate/secure/large - access = access_atmospherics - group = "Atmospherics" - contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) - -/datum/supply_packs/pacman_parts - name = "P.A.C.M.A.N. portable generator parts" - cost = 45 - containername = "P.A.C.M.A.N. Portable Generator Construction Kit" - containertype = /obj/structure/closet/crate/secure - group = "Engineering" - access = access_tech_storage - contains = list(/obj/item/weapon/stock_parts/micro_laser, - /obj/item/weapon/stock_parts/capacitor, - /obj/item/weapon/stock_parts/matter_bin, - /obj/item/weapon/circuitboard/pacman) - -/datum/supply_packs/super_pacman_parts - name = "Super P.A.C.M.A.N. portable generator parts" - cost = 55 - containername = "Super P.A.C.M.A.N. portable generator construction kit" - containertype = /obj/structure/closet/crate/secure - group = "Engineering" - access = access_tech_storage - contains = list(/obj/item/weapon/stock_parts/micro_laser, - /obj/item/weapon/stock_parts/capacitor, - /obj/item/weapon/stock_parts/matter_bin, - /obj/item/weapon/circuitboard/pacman/super) - -/datum/supply_packs/witch - name = "Witch costume" - containername = "Witch costume" - containertype = /obj/structure/closet - cost = 20 - contains = list(/obj/item/clothing/suit/wizrobe/marisa/fake, - /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/marisa/fake, - /obj/item/weapon/staff/broom) - group = "Miscellaneous" - -/datum/supply_packs/randomised/costume_hats - name = "Costume hats" - containername = "Actor hats crate" - containertype = /obj/structure/closet - cost = 10 - num_contained = 3 - contains = list(/obj/item/clothing/head/redcoat, - /obj/item/clothing/head/mailman, - /obj/item/clothing/head/plaguedoctorhat, - /obj/item/clothing/head/pirate, - /obj/item/clothing/head/hasturhood, - /obj/item/clothing/head/powdered_wig, - /obj/item/clothing/head/hairflower, - /obj/item/clothing/head/hairflower/yellow, - /obj/item/clothing/head/hairflower/blue, - /obj/item/clothing/head/hairflower/pink, - /obj/item/clothing/mask/gas/owl_mask, - /obj/item/clothing/mask/gas/monkeymask, - /obj/item/clothing/head/helmet/gladiator, - /obj/item/clothing/head/ushanka) - group = "Miscellaneous" - -/datum/supply_packs/spare_pda - name = "Spare PDAs" - cost = 10 - containertype = /obj/structure/closet/crate - containername = "Spare PDA crate" - group = "Supply" - contains = list(/obj/item/device/pda, - /obj/item/device/pda, - /obj/item/device/pda) - -/datum/supply_packs/randomised/dresses - name = "Womens formal dress locker" - containername = "Pretty dress locker" - containertype = /obj/structure/closet - cost = 15 - num_contained = 3 - contains = list(/obj/item/clothing/under/wedding/bride_orange, - /obj/item/clothing/under/wedding/bride_purple, - /obj/item/clothing/under/wedding/bride_blue, - /obj/item/clothing/under/wedding/bride_red, - /obj/item/clothing/under/wedding/bride_white, - /obj/item/clothing/under/sundress, - /obj/item/clothing/under/dress/dress_green, - /obj/item/clothing/under/dress/dress_pink, - /obj/item/clothing/under/dress/dress_orange, - /obj/item/clothing/under/dress/dress_yellow, - /obj/item/clothing/under/dress/dress_saloon) - group = "Miscellaneous" - -/datum/supply_packs/painters - name = "Station Painting Supplies" - cost = 10 - containername = "station painting supplies crate" - containertype = /obj/structure/closet/crate - group = "Engineering" - contains = list(/obj/item/device/pipe_painter, - /obj/item/device/pipe_painter, - /obj/item/device/floor_painter, - /obj/item/device/floor_painter) - - -/datum/supply_packs/randomised/exosuit_mod - num_contained = 1 - contains = list( - /obj/item/device/kit/paint/ripley, - /obj/item/device/kit/paint/ripley/death, - /obj/item/device/kit/paint/ripley/flames_red, - /obj/item/device/kit/paint/ripley/flames_blue - ) - name = "Random APLU modkit" - cost = 200 - containertype = /obj/structure/closet/crate - containername = "heavy crate" - group = "Miscellaneous" - -/datum/supply_packs/randomised/exosuit_mod/durand - contains = list( - /obj/item/device/kit/paint/durand, - /obj/item/device/kit/paint/durand/seraph, - /obj/item/device/kit/paint/durand/phazon - ) - name = "Random Durand exosuit modkit" - -/datum/supply_packs/randomised/exosuit_mod/gygax - contains = list( - /obj/item/device/kit/paint/gygax, - /obj/item/device/kit/paint/gygax/darkgygax, - /obj/item/device/kit/paint/gygax/recitence - ) - name = "Random Gygax exosuit modkit" - -/datum/supply_packs/engineeringvoidsuits - name = "Engineering voidsuits" - contains = list(/obj/item/clothing/suit/space/void/engineering, - /obj/item/clothing/suit/space/void/engineering, - /obj/item/clothing/head/helmet/space/void/engineering, - /obj/item/clothing/head/helmet/space/void/engineering, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/shoes/magboots, - /obj/item/clothing/shoes/magboots, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen) - cost = 40 - containertype = "/obj/structure/closet/crate/secure" - containername = "Engineering voidsuit crate" - access = access_engine_equip - group = "Engineering" - -/datum/supply_packs/atmosvoidsuits - name = "Atmospheric voidsuits" - contains = list(/obj/item/clothing/suit/space/void/atmos, - /obj/item/clothing/suit/space/void/atmos, - /obj/item/clothing/head/helmet/space/void/atmos, - /obj/item/clothing/head/helmet/space/void/atmos, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/shoes/magboots, - /obj/item/clothing/shoes/magboots, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen) - cost = 45 - containertype = "/obj/structure/closet/crate/secure" - containername = "Atmospheric voidsuit crate" - access = access_atmospherics - group = "Atmospherics" - -/datum/supply_packs/miningvoidsuits - name = "Mining voidsuits" - contains = list(/obj/item/clothing/suit/space/void/mining, - /obj/item/clothing/suit/space/void/mining, - /obj/item/clothing/head/helmet/space/void/mining, - /obj/item/clothing/head/helmet/space/void/mining, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen) - cost = 35 - containertype = "/obj/structure/closet/crate/secure" - containername = "Mining voidsuit crate" - access = access_mining - group = "Supply" - -/datum/supply_packs/randomised/webbing - name = "Webbing crate" - num_contained = 4 - contains = list(/obj/item/clothing/accessory/storage/black_vest, - /obj/item/clothing/accessory/storage/brown_vest, - /obj/item/clothing/accessory/storage/webbing) - cost = 15 - containertype = "/obj/structure/closet/crate" - containername = "Webbing crate" - group = "Operations" - -/datum/supply_packs/securityvoidsuits - name = "Security voidsuits" - contains = list(/obj/item/clothing/suit/space/void/security, - /obj/item/clothing/suit/space/void/security, - /obj/item/clothing/head/helmet/space/void/security, - /obj/item/clothing/head/helmet/space/void/security, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/shoes/magboots, - /obj/item/clothing/shoes/magboots, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen) - cost = 55 - containertype = "/obj/structure/closet/crate/secure" - containername = "Security voidsuit crate" - access = access_security - group = "Security" - -/datum/supply_packs/randomised/holster - name = "Holster crate" - num_contained = 4 - contains = list(/obj/item/clothing/accessory/holster, - /obj/item/clothing/accessory/holster/armpit, - /obj/item/clothing/accessory/holster/waist, - /obj/item/clothing/accessory/holster/hip) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Holster crate" - access = access_security - group = "Security" - -/datum/supply_packs/medicalvoidsuits - name = "Medical voidsuits" - contains = list(/obj/item/clothing/suit/space/void/medical, - /obj/item/clothing/suit/space/void/medical, - /obj/item/clothing/head/helmet/space/void/medical, - /obj/item/clothing/head/helmet/space/void/medical, - /obj/item/clothing/mask/breath, - /obj/item/clothing/mask/breath, - /obj/item/clothing/shoes/magboots, - /obj/item/clothing/shoes/magboots, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen) - cost = 40 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical voidsuit crate" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/securityextragear - name = "Security surplus equipment" - contains = list(/obj/item/weapon/storage/belt/security, - /obj/item/weapon/storage/belt/security, - /obj/item/weapon/storage/belt/security, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/device/radio/headset/headset_sec/alt, - /obj/item/device/radio/headset/headset_sec/alt, - /obj/item/device/radio/headset/headset_sec/alt, - /obj/item/clothing/suit/storage/hooded/wintercoat/security, - /obj/item/clothing/suit/storage/hooded/wintercoat/security, - /obj/item/clothing/suit/storage/hooded/wintercoat/security) - cost = 25 - containertype = "/obj/structure/closet/crate/secure" - containername = "Security surplus equipment" - access = access_security - group = "Security" - -/datum/supply_packs/detectivegear - name = "Forensic investigation equipment" - contains = list(/obj/item/weapon/storage/box/evidence, - /obj/item/weapon/storage/box/evidence, - /obj/item/clothing/suit/storage/vest/detective, - /obj/item/weapon/cartridge/detective, - /obj/item/device/radio/headset/headset_sec, - /obj/item/taperoll/police, - /obj/item/clothing/glasses/sunglasses, - /obj/item/device/camera, - /obj/item/weapon/folder/red, - /obj/item/weapon/folder/blue, - /obj/item/weapon/storage/belt/detective, - /obj/item/clothing/gloves/black, - /obj/item/device/taperecorder, - /obj/item/device/mass_spectrometer, - /obj/item/device/camera_film, - /obj/item/device/camera_film, - /obj/item/weapon/storage/photo_album, - /obj/item/device/reagent_scanner) - cost = 35 - containertype = "/obj/structure/closet/crate/secure" - containername = "Forensic equipment" - access = access_forensics_lockers - group = "Security" - -/datum/supply_packs/detectiveclothes - name = "Investigation apparel" - contains = list(/obj/item/clothing/under/det/black, - /obj/item/clothing/under/det/black, - /obj/item/clothing/under/det/grey, - /obj/item/clothing/under/det/grey, - /obj/item/clothing/head/det/grey, - /obj/item/clothing/head/det/grey, - /obj/item/clothing/under/det, - /obj/item/clothing/under/det, - /obj/item/clothing/head/det, - /obj/item/clothing/head/det, - /obj/item/clothing/suit/storage/det_trench, - /obj/item/clothing/suit/storage/det_trench/grey, - /obj/item/clothing/suit/storage/forensics/red, - /obj/item/clothing/suit/storage/forensics/blue, - /obj/item/clothing/under/det/corporate, - /obj/item/clothing/under/det/corporate, - /obj/item/clothing/accessory/badge/holo/detective, - /obj/item/clothing/accessory/badge/holo/detective, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Investigation clothing" - access = access_forensics_lockers - group = "Security" - -/datum/supply_packs/officergear - name = "Officer equipment" - contains = list(/obj/item/clothing/suit/storage/vest/officer, - /obj/item/clothing/head/helmet, - /obj/item/weapon/cartridge/security, - /obj/item/clothing/accessory/badge/holo, - /obj/item/clothing/accessory/badge/holo/cord, - /obj/item/device/radio/headset/headset_sec, - /obj/item/weapon/storage/belt/security, - /obj/item/device/flash, - /obj/item/weapon/reagent_containers/spray/pepper, - /obj/item/weapon/grenade/flashbang, - /obj/item/weapon/melee/baton/loaded, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/taperoll/police, - /obj/item/clothing/gloves/black, - /obj/item/device/hailer, - /obj/item/device/flashlight/flare, - /obj/item/clothing/accessory/storage/black_vest, - /obj/item/clothing/head/soft/sec/corp, - /obj/item/clothing/under/rank/security/corp, - /obj/item/weapon/gun/energy/taser) - cost = 30 - containertype = "/obj/structure/closet/crate/secure" - containername = "Officer equipment" - access = access_brig - group = "Security" - -/datum/supply_packs/wardengear - name = "Warden equipment" - contains = list(/obj/item/clothing/suit/storage/vest/warden, - /obj/item/clothing/under/rank/warden, - /obj/item/clothing/under/rank/warden/corp, - /obj/item/clothing/suit/armor/vest/warden, - /obj/item/clothing/suit/armor/vest/warden/alt, - /obj/item/clothing/head/helmet/warden, - /obj/item/weapon/cartridge/security, - /obj/item/device/radio/headset/headset_sec, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/taperoll/police, - /obj/item/device/hailer, - /obj/item/clothing/accessory/badge/holo/warden, - /obj/item/weapon/storage/box/flashbangs, - /obj/item/weapon/storage/belt/security, - /obj/item/weapon/reagent_containers/spray/pepper, - /obj/item/weapon/melee/baton/loaded, - /obj/item/weapon/storage/box/holobadge, - /obj/item/clothing/head/beret/sec/corporate/warden) - cost = 45 - containertype = "/obj/structure/closet/crate/secure" - containername = "Warden equipment" - access = access_armory - group = "Security" - -/datum/supply_packs/headofsecgear - name = "Head of security equipment" - contains = list(/obj/item/clothing/head/helmet/HoS, - /obj/item/clothing/suit/storage/vest/hos, - /obj/item/clothing/under/rank/head_of_security/corp, - /obj/item/clothing/suit/armor/hos, - /obj/item/clothing/head/helmet/HoS/dermal, - /obj/item/weapon/cartridge/hos, - /obj/item/device/radio/headset/heads/hos, - /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/weapon/storage/belt/security, - /obj/item/device/flash, - /obj/item/device/hailer, - /obj/item/clothing/accessory/badge/holo/hos, - /obj/item/clothing/accessory/holster/waist, - /obj/item/weapon/melee/telebaton, - /obj/item/weapon/shield/riot/tele, - /obj/item/clothing/head/beret/sec/corporate/hos) - cost = 65 - containertype = "/obj/structure/closet/crate/secure" - containername = "Head of security equipment" - access = access_hos - group = "Security" - -/datum/supply_packs/securityclothing - name = "Security uniform crate" - contains = list(/obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/security, - /obj/item/weapon/storage/backpack/security, - /obj/item/clothing/accessory/armband, - /obj/item/clothing/accessory/armband, - /obj/item/clothing/accessory/armband, - /obj/item/clothing/accessory/armband, - /obj/item/clothing/under/rank/security, - /obj/item/clothing/under/rank/security, - /obj/item/clothing/under/rank/security, - /obj/item/clothing/under/rank/security, - /obj/item/clothing/under/rank/security2, - /obj/item/clothing/under/rank/security2, - /obj/item/clothing/under/rank/security2, - /obj/item/clothing/under/rank/security2, - /obj/item/clothing/under/rank/warden, - /obj/item/clothing/under/rank/head_of_security, - /obj/item/clothing/suit/armor/hos/jensen, - /obj/item/clothing/head/soft/sec, - /obj/item/clothing/head/soft/sec, - /obj/item/clothing/head/soft/sec, - /obj/item/clothing/head/soft/sec, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/weapon/storage/box/holobadge) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Security uniform crate" - access = access_security - group = "Security" - -/datum/supply_packs/navybluesecurityclothing - name = "Navy blue security uniform crate" - contains = list(/obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/security, - /obj/item/weapon/storage/backpack/security, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/under/rank/security/navyblue, - /obj/item/clothing/suit/security/navyofficer, - /obj/item/clothing/suit/security/navyofficer, - /obj/item/clothing/suit/security/navyofficer, - /obj/item/clothing/suit/security/navyofficer, - /obj/item/clothing/under/rank/warden/navyblue, - /obj/item/clothing/suit/security/navywarden, - /obj/item/clothing/under/rank/head_of_security/navyblue, - /obj/item/clothing/suit/security/navyhos, - /obj/item/clothing/head/beret/sec/navy/officer, - /obj/item/clothing/head/beret/sec/navy/officer, - /obj/item/clothing/head/beret/sec/navy/officer, - /obj/item/clothing/head/beret/sec/navy/officer, - /obj/item/clothing/head/beret/sec/navy/warden, - /obj/item/clothing/head/beret/sec/navy/hos, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/weapon/storage/box/holobadge) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Navy blue security uniform crate" - access = access_security - group = "Security" - -/datum/supply_packs/corporatesecurityclothing - name = "Corporate security uniform crate" - contains = list(/obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/satchel_sec, - /obj/item/weapon/storage/backpack/security, - /obj/item/weapon/storage/backpack/security, - /obj/item/clothing/under/rank/security/corp, - /obj/item/clothing/under/rank/security/corp, - /obj/item/clothing/under/rank/security/corp, - /obj/item/clothing/under/rank/security/corp, - /obj/item/clothing/head/soft/sec/corp, - /obj/item/clothing/head/soft/sec/corp, - /obj/item/clothing/head/soft/sec/corp, - /obj/item/clothing/head/soft/sec/corp, - /obj/item/clothing/under/rank/warden/corp, - /obj/item/clothing/under/rank/head_of_security/corp, - /obj/item/clothing/head/beret/sec, - /obj/item/clothing/head/beret/sec, - /obj/item/clothing/head/beret/sec, - /obj/item/clothing/head/beret/sec, - /obj/item/clothing/head/beret/sec/corporate/warden, - /obj/item/clothing/head/beret/sec/corporate/hos, - /obj/item/clothing/under/det/corporate, - /obj/item/clothing/under/det/corporate, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/clothing/gloves/black, - /obj/item/weapon/storage/box/holobadge) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Corporate security uniform crate" - access = access_security - group = "Security" - -/datum/supply_packs/securitybiosuit - name = "Security biohazard gear" - contains = list(/obj/item/clothing/head/bio_hood/security, - /obj/item/clothing/under/rank/security, - /obj/item/clothing/suit/bio_suit/security, - /obj/item/clothing/shoes/white, - /obj/item/clothing/mask/gas, - /obj/item/weapon/tank/oxygen, - /obj/item/clothing/gloves/latex) - cost = 35 - containertype = "/obj/structure/closet/crate/secure" - containername = "Security biohazard gear" - access = access_security - group = "Security" - -/datum/supply_packs/medicalextragear - name = "Medical surplus equipment" - contains = list(/obj/item/weapon/storage/belt/medical, - /obj/item/weapon/storage/belt/medical, - /obj/item/weapon/storage/belt/medical, - /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/glasses/hud/health, - /obj/item/device/radio/headset/headset_med/alt, - /obj/item/device/radio/headset/headset_med/alt, - /obj/item/device/radio/headset/headset_med/alt, - /obj/item/clothing/suit/storage/hooded/wintercoat/medical, - /obj/item/clothing/suit/storage/hooded/wintercoat/medical, - /obj/item/clothing/suit/storage/hooded/wintercoat/medical) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical surplus equipment" - access = access_medical - group = "Medical" - -/datum/supply_packs/cmogear - name = "Chief medical officer equipment" - contains = list(/obj/item/weapon/storage/belt/medical, - /obj/item/device/radio/headset/heads/cmo, - /obj/item/clothing/under/rank/chief_medical_officer, - /obj/item/weapon/reagent_containers/hypospray, - /obj/item/clothing/accessory/stethoscope, - /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat/cmo, - /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, - /obj/item/clothing/mask/surgical, - /obj/item/clothing/shoes/white, - /obj/item/weapon/cartridge/cmo, - /obj/item/clothing/gloves/latex, - /obj/item/device/healthanalyzer, - /obj/item/device/flashlight/pen, - /obj/item/weapon/reagent_containers/syringe) - cost = 60 - containertype = "/obj/structure/closet/crate/secure" - containername = "Chief medical officer equipment" - access = access_cmo - group = "Medical" - -/datum/supply_packs/doctorgear - name = "Medical Doctor equipment" - contains = list(/obj/item/weapon/storage/belt/medical, - /obj/item/device/radio/headset/headset_med, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/accessory/stethoscope, - /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/mask/surgical, - /obj/item/weapon/storage/firstaid/adv, - /obj/item/clothing/shoes/white, - /obj/item/weapon/cartridge/medical, - /obj/item/clothing/gloves/latex, - /obj/item/device/healthanalyzer, - /obj/item/device/flashlight/pen, - /obj/item/weapon/reagent_containers/syringe) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical Doctor equipment" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/chemistgear - name = "Chemist equipment" - contains = list(/obj/item/weapon/storage/box/beakers, - /obj/item/device/radio/headset/headset_med, - /obj/item/weapon/storage/box/autoinjectors, - /obj/item/clothing/under/rank/chemist, - /obj/item/clothing/glasses/science, - /obj/item/clothing/suit/storage/toggle/labcoat/chemist, - /obj/item/clothing/mask/surgical, - /obj/item/clothing/shoes/white, - /obj/item/weapon/cartridge/chemistry, - /obj/item/clothing/gloves/latex, - /obj/item/weapon/reagent_containers/dropper, - /obj/item/device/healthanalyzer, - /obj/item/weapon/storage/box/pillbottles, - /obj/item/weapon/reagent_containers/syringe) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Chemist equipment" - access = access_chemistry - group = "Medical" - -/datum/supply_packs/paramedicgear - name = "Paramedic equipment" - contains = list(/obj/item/weapon/storage/belt/medical/emt, - /obj/item/device/radio/headset/headset_med, - /obj/item/clothing/under/rank/medical/black, - /obj/item/clothing/accessory/armband/medgreen, - /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat/emt, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/suit/storage/toggle/fr_jacket, - /obj/item/clothing/mask/gas, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/accessory/stethoscope, - /obj/item/weapon/storage/firstaid/adv, - /obj/item/clothing/shoes/jackboots, - /obj/item/clothing/gloves/latex, - /obj/item/device/healthanalyzer, - /obj/item/weapon/cartridge/medical, - /obj/item/device/flashlight/pen, - /obj/item/weapon/reagent_containers/syringe) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Paramedic equipment" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/psychiatristgear - name = "Psychiatrist equipment" - contains = list(/obj/item/clothing/under/rank/psych, - /obj/item/device/radio/headset/headset_med, - /obj/item/clothing/under/rank/psych/turtleneck, - /obj/item/clothing/shoes/laceup, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/shoes/white, - /obj/item/weapon/clipboard, - /obj/item/weapon/folder/white, - /obj/item/weapon/pen, - /obj/item/weapon/cartridge/medical) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Psychiatrist equipment" - access = access_psychiatrist - group = "Medical" - -/* -/datum/supply_packs/geneticistgear - name = "Geneticist equipment" - contains = list(/obj/item/weapon/storage/belt/medical, - /obj/item/device/radio/headset/headset_medsci, - /obj/item/clothing/under/rank/geneticist, - /obj/item/clothing/accessory/stethoscope, - /obj/item/clothing/suit/storage/toggle/labcoat/genetics, - /obj/item/clothing/mask/surgical, - /obj/item/clothing/shoes/white, - /obj/item/clothing/gloves/latex, - /obj/item/weapon/cartridge/medical, - /obj/item/device/healthanalyzer, - /obj/item/device/flashlight/pen, - /obj/item/weapon/reagent_containers/syringe) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Geneticist equipment" - access = access_genetics - group = "Medical" -*/ - -/datum/supply_packs/medicalscrubs - name = "Medical scrubs" - contains = list(/obj/item/clothing/shoes/white, - /obj/item/clothing/shoes/white, - /obj/item/clothing/shoes/white, - /obj/item/clothing/under/rank/medical/blue, - /obj/item/clothing/under/rank/medical/blue, - /obj/item/clothing/under/rank/medical/blue, - /obj/item/clothing/under/rank/medical/green, - /obj/item/clothing/under/rank/medical/green, - /obj/item/clothing/under/rank/medical/green, - /obj/item/clothing/under/rank/medical/purple, - /obj/item/clothing/under/rank/medical/purple, - /obj/item/clothing/under/rank/medical/purple, - /obj/item/clothing/under/rank/medical/black, - /obj/item/clothing/under/rank/medical/black, - /obj/item/clothing/under/rank/medical/black, - /obj/item/clothing/head/surgery, - /obj/item/clothing/head/surgery, - /obj/item/clothing/head/surgery, - /obj/item/clothing/head/surgery/purple, - /obj/item/clothing/head/surgery/purple, - /obj/item/clothing/head/surgery/purple, - /obj/item/clothing/head/surgery/blue, - /obj/item/clothing/head/surgery/blue, - /obj/item/clothing/head/surgery/blue, - /obj/item/clothing/head/surgery/green, - /obj/item/clothing/head/surgery/green, - /obj/item/clothing/head/surgery/green, - /obj/item/clothing/head/surgery/black, - /obj/item/clothing/head/surgery/black, - /obj/item/clothing/head/surgery/black, - /obj/item/weapon/storage/box/masks, - /obj/item/weapon/storage/box/gloves) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical scrubs crate" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/autopsy - name = "Autopsy equipment" - contains = list(/obj/item/weapon/folder/white, - /obj/item/device/camera, - /obj/item/device/camera_film, - /obj/item/device/camera_film, - /obj/item/weapon/autopsy_scanner, - /obj/item/weapon/scalpel, - /obj/item/weapon/storage/box/masks, - /obj/item/weapon/storage/box/gloves, - /obj/item/weapon/pen) - cost = 20 - containertype = "/obj/structure/closet/crate/secure" - containername = "Autopsy equipment crate" - access = access_morgue - group = "Medical" - -/datum/supply_packs/medicaluniforms - name = "Medical uniforms" - contains = list(/obj/item/clothing/shoes/white, - /obj/item/clothing/shoes/white, - /obj/item/clothing/shoes/white, - /obj/item/clothing/under/rank/chief_medical_officer, - /obj/item/clothing/under/rank/geneticist, - /obj/item/clothing/under/rank/virologist, - /obj/item/clothing/under/rank/nursesuit, - /obj/item/clothing/under/rank/nurse, - /obj/item/clothing/under/rank/orderly, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/suit/storage/toggle/labcoat/cmo, - /obj/item/clothing/suit/storage/toggle/labcoat/emt, - /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, - /obj/item/clothing/suit/storage/toggle/labcoat/genetics, - /obj/item/clothing/suit/storage/toggle/labcoat/virologist, - /obj/item/clothing/suit/storage/toggle/labcoat/chemist, - /obj/item/weapon/storage/box/masks, - /obj/item/weapon/storage/box/gloves) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical uniform crate" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/medicalbiosuits - name = "Medical biohazard gear" - contains = list(/obj/item/clothing/head/bio_hood, - /obj/item/clothing/head/bio_hood, - /obj/item/clothing/head/bio_hood, - /obj/item/clothing/suit/bio_suit, - /obj/item/clothing/suit/bio_suit, - /obj/item/clothing/suit/bio_suit, - /obj/item/clothing/head/bio_hood/virology, - /obj/item/clothing/suit/bio_suit/virology, - /obj/item/clothing/suit/bio_suit/cmo, - /obj/item/clothing/head/bio_hood/cmo, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/clothing/mask/gas, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/tank/oxygen, - /obj/item/weapon/storage/box/masks, - /obj/item/weapon/storage/box/gloves) - cost = 50 - containertype = "/obj/structure/closet/crate/secure" - containername = "Medical biohazard equipment" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/portablefreezers - name = "Portable freezers crate" - contains = list(/obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer, - /obj/item/weapon/storage/box/freezer) - cost = 25 - containertype = "/obj/structure/closet/crate/secure" - containername = "Portable freezers" - access = access_medical_equip - group = "Medical" - -/datum/supply_packs/minergear - name = "Shaft miner equipment" - contains = list(/obj/item/weapon/storage/backpack/industrial, - /obj/item/weapon/storage/backpack/satchel_eng, - /obj/item/clothing/suit/storage/hooded/wintercoat/miner, - /obj/item/device/radio/headset/headset_cargo, - /obj/item/clothing/under/rank/miner, - /obj/item/clothing/gloves/black, - /obj/item/clothing/shoes/black, - /obj/item/device/analyzer, - /obj/item/weapon/storage/bag/ore, - /obj/item/device/flashlight/lantern, - /obj/item/weapon/shovel, - /obj/item/weapon/pickaxe, - /obj/item/weapon/mining_scanner, - /obj/item/clothing/glasses/material, - /obj/item/clothing/glasses/meson) - cost = 15 - containertype = "/obj/structure/closet/crate/secure" - containername = "Shaft miner equipment" - access = access_mining - group = "Supply" - -/datum/supply_packs/chaplaingear - name = "Chaplain equipment" - contains = list(/obj/item/clothing/under/rank/chaplain, - /obj/item/clothing/shoes/black, - /obj/item/clothing/suit/nun, - /obj/item/clothing/head/nun_hood, - /obj/item/clothing/suit/chaplain_hoodie, - /obj/item/clothing/head/chaplain_hood, - /obj/item/clothing/suit/holidaypriest, - /obj/item/clothing/under/wedding/bride_white, - /obj/item/weapon/storage/backpack/cultpack, - /obj/item/weapon/storage/fancy/candle_box, - /obj/item/weapon/storage/fancy/candle_box, - /obj/item/weapon/storage/fancy/candle_box) - cost = 10 - containertype = "/obj/structure/closet/crate" - containername = "Chaplain equipment crate" - group = "Miscellaneous" \ No newline at end of file diff --git a/code/datums/supplypacks/atmospherics.dm b/code/datums/supplypacks/atmospherics.dm new file mode 100644 index 0000000000..91c85f8ac2 --- /dev/null +++ b/code/datums/supplypacks/atmospherics.dm @@ -0,0 +1,83 @@ +/* +* Here is where any supply packs related +* to being atmospherics tasks live. +*/ + + +/datum/supply_packs/atmos + group = "Atmospherics" + +/datum/supply_packs/atmos/inflatable + name = "Inflatable barriers" + contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Inflatable Barrier Crate" + +/datum/supply_packs/atmos/canister_empty + name = "Empty gas canister" + cost = 7 + containername = "Empty gas canister crate" + containertype = /obj/structure/largecrate + contains = list(/obj/machinery/portable_atmospherics/canister) + +/datum/supply_packs/atmos/canister_air + name = "Air canister" + cost = 10 + containername = "Air canister crate" + containertype = /obj/structure/largecrate + contains = list(/obj/machinery/portable_atmospherics/canister/air) + +/datum/supply_packs/atmos/canister_oxygen + name = "Oxygen canister" + cost = 15 + containername = "Oxygen canister crate" + containertype = /obj/structure/largecrate + contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) + +/datum/supply_packs/atmos/canister_nitrogen + name = "Nitrogen canister" + cost = 10 + containername = "Nitrogen canister crate" + containertype = /obj/structure/largecrate + contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) + +/datum/supply_packs/atmos/canister_phoron + name = "Phoron gas canister" + cost = 60 + containername = "Phoron gas canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + contains = list(/obj/machinery/portable_atmospherics/canister/phoron) + +/datum/supply_packs/atmos/canister_sleeping_agent + name = "N2O gas canister" + cost = 40 + containername = "N2O gas canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent) + +/datum/supply_packs/atmos/canister_carbon_dioxide + name = "Carbon dioxide gas canister" + cost = 40 + containername = "CO2 canister crate" + containertype = /obj/structure/closet/crate/secure/large + access = access_atmospherics + contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) + +/datum/supply_packs/atmos/air_dispenser + contains = list(/obj/machinery/pipedispenser/orderable) + name = "Pipe Dispenser" + cost = 35 + containertype = /obj/structure/closet/crate/secure/large + containername = "Pipe Dispenser Crate" + access = access_atmospherics + +/datum/supply_packs/atmos/disposals_dispenser + contains = list(/obj/machinery/pipedispenser/disposal/orderable) + name = "Disposals Pipe Dispenser" + cost = 35 + containertype = /obj/structure/closet/crate/secure/large + containername = "Disposal Dispenser Crate" + access = access_atmospherics \ No newline at end of file diff --git a/code/datums/supplypacks/contraband.dm b/code/datums/supplypacks/contraband.dm new file mode 100644 index 0000000000..fa8c237fe8 --- /dev/null +++ b/code/datums/supplypacks/contraband.dm @@ -0,0 +1,45 @@ +/* +* Here is where any supply packs that may or may not be legal +* and require modification of the supply controller live. +*/ + + +/datum/supply_packs/randomised/contraband + num_contained = 5 + contains = list( + /obj/item/seeds/bloodtomatoseed, + /obj/item/weapon/storage/pill_bottle/zoom, + /obj/item/weapon/storage/pill_bottle/happy, + /obj/item/weapon/reagent_containers/food/drinks/bottle/pwine + ) + + name = "Contraband crate" + cost = 30 + containertype = /obj/structure/closet/crate + containername = "Unlabeled crate" + contraband = 1 + group = "Supplies" + +/datum/supply_packs/security/specialops + name = "Special Ops supplies" + contains = list( + /obj/item/weapon/storage/box/emps, + /obj/item/weapon/grenade/smokebomb = 3, + /obj/item/weapon/pen/reagent/paralysis, + /obj/item/weapon/grenade/chem_grenade/incendiary + ) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Special Ops crate" + hidden = 1 + +/datum/supply_packs/security/bolt_rifles_mosin + name = "Surplus militia rifles" + contains = list( + /obj/item/weapon/gun/projectile/shotgun/pump/rifle/mosin = 3, + /obj/item/ammo_magazine/clip/a762 = 6 + ) + cost = 50 + hidden = 1 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "Weapons crate" \ No newline at end of file diff --git a/code/datums/supplypacks/costumes.dm b/code/datums/supplypacks/costumes.dm new file mode 100644 index 0000000000..b5a494321a --- /dev/null +++ b/code/datums/supplypacks/costumes.dm @@ -0,0 +1,165 @@ +/* +* Here is where any supply packs +* related to weapons live. +*/ + + +/datum/supply_packs/costumes + group = "Costumes" + +/datum/supply_packs/randomised/costumes + group = "Costumes" + +/datum/supply_packs/costumes/wizard + name = "Wizard costume" + contains = list( + /obj/item/weapon/staff, + /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/fake + ) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Wizard costume crate" + +/datum/supply_packs/randomised/costumes/hats + num_contained = 4 + contains = list( + /obj/item/clothing/head/collectable/chef, + /obj/item/clothing/head/collectable/paper, + /obj/item/clothing/head/collectable/tophat, + /obj/item/clothing/head/collectable/captain, + /obj/item/clothing/head/collectable/beret, + /obj/item/clothing/head/collectable/welding, + /obj/item/clothing/head/collectable/flatcap, + /obj/item/clothing/head/collectable/pirate, + /obj/item/clothing/head/collectable/kitty, + /obj/item/clothing/head/collectable/rabbitears, + /obj/item/clothing/head/collectable/wizard, + /obj/item/clothing/head/collectable/hardhat, + /obj/item/clothing/head/collectable/HoS, + /obj/item/clothing/head/collectable/thunderdome, + /obj/item/clothing/head/collectable/swat, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/police, + /obj/item/clothing/head/collectable/slime, + /obj/item/clothing/head/collectable/xenom, + /obj/item/clothing/head/collectable/petehat + ) + name = "Collectable hat crate!" + cost = 200 + containertype = /obj/structure/closet/crate + containername = "Collectable hats crate! Brought to you by Bass.inc!" + +/datum/supply_packs/randomised/costumes/costume + num_contained = 3 + contains = list( + /obj/item/clothing/suit/pirate, + /obj/item/clothing/suit/judgerobe, + /obj/item/clothing/suit/wcoat, + /obj/item/clothing/suit/hastur, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/suit/nun, + /obj/item/clothing/suit/imperium_monk, + /obj/item/clothing/suit/ianshirt, + /obj/item/clothing/under/gimmick/rank/captain/suit, + /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/under/rank/mailman, + /obj/item/clothing/under/dress/dress_saloon, + /obj/item/clothing/suit/suspenders, + /obj/item/clothing/suit/storage/toggle/labcoat/mad, + /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, + /obj/item/clothing/under/schoolgirl, + /obj/item/clothing/under/owl, + /obj/item/clothing/under/waiter, + /obj/item/clothing/under/gladiator, + /obj/item/clothing/under/soviet, + /obj/item/clothing/under/scratch, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/suit/chef, + /obj/item/clothing/suit/apron/overalls, + /obj/item/clothing/under/redcoat, + /obj/item/clothing/under/kilt + ) + name = "Costumes crate" + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Actor Costumes" + +/datum/supply_packs/costumes/formal_wear + contains = list( + /obj/item/clothing/head/bowler, + /obj/item/clothing/head/that, + /obj/item/clothing/suit/storage/toggle/internalaffairs, + /obj/item/clothing/suit/storage/toggle/lawyer/bluejacket, + /obj/item/clothing/suit/storage/toggle/lawyer/purpjacket, + /obj/item/clothing/under/suit_jacket, + /obj/item/clothing/under/suit_jacket/female, + /obj/item/clothing/under/suit_jacket/really_black, + /obj/item/clothing/under/suit_jacket/red, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/shoes/black = 2, + /obj/item/clothing/shoes/leather, + /obj/item/clothing/suit/wcoat + ) + name = "Formalwear closet" + cost = 30 + containertype = /obj/structure/closet + containername = "Formalwear for the best occasions." + +datum/supply_packs/costumes/witch + name = "Witch costume" + containername = "Witch costume" + containertype = /obj/structure/closet + cost = 20 + contains = list( + /obj/item/clothing/suit/wizrobe/marisa/fake, + /obj/item/clothing/shoes/sandal, + /obj/item/clothing/head/wizard/marisa/fake, + /obj/item/weapon/staff/broom + ) + +/datum/supply_packs/randomised/costumes/costume_hats + name = "Costume hats" + containername = "Actor hats crate" + containertype = /obj/structure/closet + cost = 10 + num_contained = 3 + contains = list( + /obj/item/clothing/head/redcoat, + /obj/item/clothing/head/mailman, + /obj/item/clothing/head/plaguedoctorhat, + /obj/item/clothing/head/pirate, + /obj/item/clothing/head/hasturhood, + /obj/item/clothing/head/powdered_wig, + /obj/item/clothing/head/hairflower, + /obj/item/clothing/head/hairflower/yellow, + /obj/item/clothing/head/hairflower/blue, + /obj/item/clothing/head/hairflower/pink, + /obj/item/clothing/mask/gas/owl_mask, + /obj/item/clothing/mask/gas/monkeymask, + /obj/item/clothing/head/helmet/gladiator, + /obj/item/clothing/head/ushanka + ) + +/datum/supply_packs/randomised/costumes/dresses + name = "Womens formal dress locker" + containername = "Pretty dress locker" + containertype = /obj/structure/closet + cost = 15 + num_contained = 3 + contains = list( + /obj/item/clothing/under/wedding/bride_orange, + /obj/item/clothing/under/wedding/bride_purple, + /obj/item/clothing/under/wedding/bride_blue, + /obj/item/clothing/under/wedding/bride_red, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/under/sundress, + /obj/item/clothing/under/dress/dress_green, + /obj/item/clothing/under/dress/dress_pink, + /obj/item/clothing/under/dress/dress_orange, + /obj/item/clothing/under/dress/dress_yellow, + /obj/item/clothing/under/dress/dress_saloon + ) \ No newline at end of file diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm new file mode 100644 index 0000000000..900419d0d3 --- /dev/null +++ b/code/datums/supplypacks/engineering.dm @@ -0,0 +1,192 @@ +/* +* Here is where any supply packs +* related to engineering tasks live. +*/ + + +/datum/supply_packs/eng + group = "Engineering" + +/datum/supply_packs/eng/lightbulbs + name = "Replacement lights" + contains = list(/obj/item/weapon/storage/box/lights/mixed = 3) + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Replacement lights" + +/datum/supply_packs/eng/smescoil + name = "Superconducting Magnetic Coil" + contains = list(/obj/item/weapon/smes_coil) + cost = 75 + containertype = /obj/structure/closet/crate + containername = "Superconducting Magnetic Coil crate" + +/datum/supply_packs/eng/electrical + name = "Electrical maintenance crate" + contains = list( + /obj/item/weapon/storage/toolbox/electrical = 2, + /obj/item/clothing/gloves/yellow = 2, + /obj/item/weapon/cell = 2, + /obj/item/weapon/cell/high = 2 + ) + cost = 15 + containertype = /obj/structure/closet/crate + containername = "Electrical maintenance crate" + +/datum/supply_packs/eng/mechanical + name = "Mechanical maintenance crate" + contains = list( + /obj/item/weapon/storage/belt/utility/full = 3, + /obj/item/clothing/suit/storage/hazardvest = 3, + /obj/item/clothing/head/welding = 2, + /obj/item/clothing/head/hardhat + ) + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Mechanical maintenance crate" + +/datum/supply_packs/eng/fueltank + name = "Fuel tank crate" + contains = list(/obj/structure/reagent_dispensers/fueltank) + cost = 8 + containertype = /obj/structure/largecrate + containername = "fuel tank crate" + +/datum/supply_packs/eng/solar + name = "Solar Pack crate" + contains = list( + /obj/item/solar_assembly = 21, + /obj/item/weapon/circuitboard/solar_control, + /obj/item/weapon/tracker_electronics, + /obj/item/weapon/paper/solar + ) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Solar pack crate" + +/datum/supply_packs/eng/engine + name = "Emitter crate" + contains = list(/obj/machinery/power/emitter = 2) + cost = 10 + containertype = /obj/structure/closet/crate/secure + containername = "Emitter crate" + access = access_ce + +/datum/supply_packs/engine/eng/field_gen + name = "Field Generator crate" + contains = list(/obj/machinery/field_generator = 2) + containertype = /obj/structure/closet/crate/secure + containername = "Field Generator crate" + access = access_ce + +/datum/supply_packs/eng/engine/sing_gen + name = "Singularity Generator crate" + contains = list(/obj/machinery/the_singularitygen) + containertype = /obj/structure/closet/crate/secure + containername = "Singularity Generator crate" + access = access_ce + +/datum/supply_packs/eng/engine/collector + name = "Collector crate" + contains = list(/obj/machinery/power/rad_collector = 3) + containername = "Collector crate" + +/datum/supply_packs/eng/engine/PA + name = "Particle Accelerator crate" + cost = 40 + contains = list( + /obj/structure/particle_accelerator/fuel_chamber, + /obj/machinery/particle_accelerator/control_box, + /obj/structure/particle_accelerator/particle_emitter/center, + /obj/structure/particle_accelerator/particle_emitter/left, + /obj/structure/particle_accelerator/particle_emitter/right, + /obj/structure/particle_accelerator/power_box, + /obj/structure/particle_accelerator/end_cap + ) + containertype = /obj/structure/closet/crate/secure + containername = "Particle Accelerator crate" + access = access_ce + +/datum/supply_packs/eng/shield_gen + contains = list(/obj/item/weapon/circuitboard/shield_gen) + name = "Bubble shield generator circuitry" + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "bubble shield generator circuitry crate" + access = access_ce + +/datum/supply_packs/eng/shield_gen_ex + contains = list(/obj/item/weapon/circuitboard/shield_gen_ex) + name = "Hull shield generator circuitry" + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "hull shield generator circuitry crate" + access = access_ce + +/datum/supply_packs/eng/shield_cap + contains = list(/obj/item/weapon/circuitboard/shield_cap) + name = "Bubble shield capacitor circuitry" + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "shield capacitor circuitry crate" + access = access_ce + +/datum/supply_packs/eng/smbig + name = "Supermatter Core" + contains = list(/obj/machinery/power/supermatter) + cost = 150 + containertype = /obj/structure/closet/crate/secure/phoron + containername = "Supermatter crate (CAUTION)" + access = access_ce + +/datum/supply_packs/eng/teg + contains = list(/obj/machinery/power/generator) + name = "Mark I Thermoelectric Generator" + cost = 75 + containertype = /obj/structure/closet/crate/secure/large + containername = "Mk1 TEG crate" + access = access_engine + +/datum/supply_packs/eng/circulator + contains = list(/obj/machinery/atmospherics/binary/circulator) + name = "Binary atmospheric circulator" + cost = 60 + containertype = /obj/structure/closet/crate/secure/large + containername = "Atmospheric circulator crate" + access = access_engine + +/datum/supply_packs/eng/radsuit + contains = list( + /obj/item/clothing/suit/radiation = 3, + /obj/item/clothing/head/radiation = 3 + ) + name = "Radiation suits package" + cost = 20 + containertype = /obj/structure/closet/radiation + containername = "Radiation suit locker" + +/datum/supply_packs/eng/pacman_parts + name = "P.A.C.M.A.N. portable generator parts" + cost = 45 + containername = "P.A.C.M.A.N. Portable Generator Construction Kit" + containertype = /obj/structure/closet/crate/secure + access = access_tech_storage + contains = list( + /obj/item/weapon/stock_parts/micro_laser, + /obj/item/weapon/stock_parts/capacitor, + /obj/item/weapon/stock_parts/matter_bin, + /obj/item/weapon/circuitboard/pacman + ) + +/datum/supply_packs/eng/super_pacman_parts + name = "Super P.A.C.M.A.N. portable generator parts" + cost = 55 + containername = "Super P.A.C.M.A.N. portable generator construction kit" + containertype = /obj/structure/closet/crate/secure + access = access_tech_storage + contains = list( + /obj/item/weapon/stock_parts/micro_laser, + /obj/item/weapon/stock_parts/capacitor, + /obj/item/weapon/stock_parts/matter_bin, + /obj/item/weapon/circuitboard/pacman/super + ) diff --git a/code/datums/supplypacks/hospitality.dm b/code/datums/supplypacks/hospitality.dm new file mode 100644 index 0000000000..6dd421b243 --- /dev/null +++ b/code/datums/supplypacks/hospitality.dm @@ -0,0 +1,62 @@ +/* +* Here is where any supply packs related +* to being hospitable tasks live +*/ + + +/datum/supply_packs/hospitality + group = "Hospitality" + +/datum/supply_packs/hospitality/party + name = "Party equipment" + contains = list( + /obj/item/weapon/storage/box/mixedglasses = 2, + /obj/item/weapon/storage/box/glasses/square, + /obj/item/weapon/reagent_containers/food/drinks/shaker, + /obj/item/weapon/reagent_containers/food/drinks/flask/barflask, + /obj/item/weapon/reagent_containers/food/drinks/bottle/patron, + /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager, + /obj/item/weapon/reagent_containers/food/drinks/bottle/specialwhiskey, + /obj/item/weapon/storage/fancy/cigarettes/dromedaryco, + /obj/item/weapon/lipstick/random, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale = 2, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 4, + ) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Party equipment" + +/datum/supply_packs/hospitality/barsupplies + name = "Bar supplies" + contains = list( + /obj/item/weapon/storage/box/glasses/cocktail, + /obj/item/weapon/storage/box/glasses/rocks, + /obj/item/weapon/storage/box/glasses/square, + /obj/item/weapon/storage/box/glasses/pint, + /obj/item/weapon/storage/box/glasses/wine, + /obj/item/weapon/storage/box/glasses/shake, + /obj/item/weapon/storage/box/glasses/shot, + /obj/item/weapon/storage/box/glasses/mug, + /obj/item/weapon/reagent_containers/food/drinks/shaker, + /obj/item/weapon/storage/box/glass_extras/straws, + /obj/item/weapon/storage/box/glass_extras/sticks + ) + cost = 10 + containertype = /obj/structure/closet/crate + containername = "crate of bar supplies" + +/datum/supply_packs/randomised/hospitality/ + group = "Hospitality" + +/datum/supply_packs/randomised/hospitality/pizza + num_contained = 5 + contains = list( + /obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable + ) + name = "Surprise pack of five pizzas" + cost = 15 + containertype = /obj/structure/closet/crate/freezer + containername = "Pizza crate" diff --git a/code/datums/supplypacks/hydroponics.dm b/code/datums/supplypacks/hydroponics.dm new file mode 100644 index 0000000000..a9a26fd561 --- /dev/null +++ b/code/datums/supplypacks/hydroponics.dm @@ -0,0 +1,149 @@ +/* +* Here is where any supply packs +* related to hydroponics tasks live. +*/ + + +/datum/supply_packs/hydro + group = "Hydroponics" + +/datum/supply_packs/hydro/monkey + name = "Monkey crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes) + cost = 20 + containertype = /obj/structure/closet/crate/freezer + containername = "Monkey crate" + +/datum/supply_packs/hydro/farwa + name = "Farwa crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/farwacubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "Farwa crate" + +/datum/supply_packs/hydro/neara + name = "Neaera crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/neaeracubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "Neaera crate" + +/datum/supply_packs/hydro/stok + name = "Stok crate" + contains = list (/obj/item/weapon/storage/box/monkeycubes/stokcubes) + cost = 30 + containertype = /obj/structure/closet/crate/freezer + containername = "Stok crate" + +/datum/supply_packs/hydro/lisa + name = "Corgi Crate" + contains = list() + cost = 50 + containertype = /obj/structure/largecrate/animal/corgi + containername = "Corgi Crate" + +/datum/supply_packs/hydro/hydroponics + name = "Hydroponics Supply Crate" + contains = list( + /obj/item/weapon/reagent_containers/spray/plantbgone = 4, + /obj/item/weapon/reagent_containers/glass/bottle/ammonia = 2, + /obj/item/weapon/material/hatchet, + /obj/item/weapon/material/minihoe, + /obj/item/device/analyzer/plant_analyzer, + /obj/item/clothing/gloves/botanic_leather, + /obj/item/clothing/suit/apron, + /obj/item/weapon/material/minihoe, + /obj/item/weapon/storage/box/botanydisk + ) + cost = 15 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Hydroponics crate" + access = access_hydroponics + +/datum/supply_packs/hydro/cow + name = "Cow crate" + cost = 30 + containertype = /obj/structure/largecrate/animal/cow + containername = "Cow crate" + access = access_hydroponics + +/datum/supply_packs/hydro/goat + name = "Goat crate" + cost = 25 + containertype = /obj/structure/largecrate/animal/goat + containername = "Goat crate" + access = access_hydroponics + +/datum/supply_packs/hydro/chicken + name = "Chicken crate" + cost = 20 + containertype = /obj/structure/largecrate/animal/chick + containername = "Chicken crate" + access = access_hydroponics + +/datum/supply_packs/hydro/seeds + name = "Seeds crate" + contains = list( + /obj/item/seeds/chiliseed, + /obj/item/seeds/berryseed, + /obj/item/seeds/cornseed, + /obj/item/seeds/eggplantseed, + /obj/item/seeds/tomatoseed, + /obj/item/seeds/appleseed, + /obj/item/seeds/soyaseed, + /obj/item/seeds/wheatseed, + /obj/item/seeds/carrotseed, + /obj/item/seeds/harebell, + /obj/item/seeds/lemonseed, + /obj/item/seeds/orangeseed, + /obj/item/seeds/grassseed, + /obj/item/seeds/sunflowerseed, + /obj/item/seeds/chantermycelium, + /obj/item/seeds/potatoseed, + /obj/item/seeds/sugarcaneseed + ) + cost = 10 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Seeds crate" + access = access_hydroponics + +/datum/supply_packs/hydro/weedcontrol + name = "Weed control crate" + contains = list( + /obj/item/weapon/material/hatchet = 2, + /obj/item/weapon/reagent_containers/spray/plantbgone = 4, + /obj/item/clothing/mask/gas = 2, + /obj/item/weapon/grenade/chem_grenade/antiweed = 2 + ) + cost = 25 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Weed control crate" + access = access_hydroponics + +/datum/supply_packs/hydro/watertank + name = "Water tank crate" + contains = list(/obj/structure/reagent_dispensers/watertank) + cost = 8 + containertype = /obj/structure/largecrate + containername = "water tank crate" + +/datum/supply_packs/hydro/bee_keeper + name = "Beekeeping crate" + contains = list( + /obj/item/beehive_assembly, + /obj/item/bee_smoker, + /obj/item/honey_frame = 5, + /obj/item/bee_pack + ) + cost = 40 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Beekeeping crate" + access = access_hydroponics + +/datum/supply_packs/hydro/tray + name = "Empty hydroponics tray" + cost = 30 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Hydroponics tray crate" + contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0}) + access = access_hydroponics \ No newline at end of file diff --git a/code/datums/supplypacks/materials.dm b/code/datums/supplypacks/materials.dm new file mode 100644 index 0000000000..b25565ae0f --- /dev/null +++ b/code/datums/supplypacks/materials.dm @@ -0,0 +1,68 @@ +/* +* Here is where any supply packs +* related to materials live. +*/ + + +/datum/supply_packs/materials + group = "Materials" + +/datum/supply_packs/materials/metal50 + name = "50 metal sheets" + contains = list(/obj/item/stack/material/steel) + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Metal sheets crate" + +/datum/supply_packs/materials/glass50 + name = "50 glass sheets" + contains = list(/obj/item/stack/material/glass) + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Glass sheets crate" + +/datum/supply_packs/materials/wood50 + name = "50 wooden planks" + contains = list(/obj/item/stack/material/wood) + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Wooden planks crate" + +/datum/supply_packs/materials/plastic50 + name = "50 plastic sheets" + contains = list(/obj/item/stack/material/plastic) + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Plastic sheets crate" + +/datum/supply_packs/materials/cardboard_sheets + contains = list(/obj/item/stack/material/cardboard) + name = "50 cardboard sheets" + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Cardboard sheets crate" + +/datum/supply_packs/materials/carpet + name = "Imported carpet" + containertype = /obj/structure/closet/crate + containername = "Imported carpet crate" + cost = 15 + contains = list( + /obj/item/stack/tile/carpet, + /obj/item/stack/tile/carpet/blue + ) + amount = 50 + + +/datum/supply_packs/misc/linoleum + name = "Linoleum" + containertype = /obj/structure/closet/crate + containername = "Linoleum crate" + cost = 15 + contains = list(/obj/item/stack/tile/linoleum) + amount = 50 \ No newline at end of file diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm new file mode 100644 index 0000000000..c7cc7dc575 --- /dev/null +++ b/code/datums/supplypacks/medical.dm @@ -0,0 +1,309 @@ +/* +* Here is where any supply packs +* related to medical tasks live. +*/ + + +/datum/supply_packs/med + group = "Medical" + +/datum/supply_packs/med/medical + name = "Medical crate" + contains = list( + /obj/item/weapon/storage/firstaid/regular, + /obj/item/weapon/storage/firstaid/fire, + /obj/item/weapon/storage/firstaid/toxin, + /obj/item/weapon/storage/firstaid/o2, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, + /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, + /obj/item/weapon/reagent_containers/glass/bottle/stoxin, + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/storage/box/autoinjectors + ) + cost = 10 + containertype = /obj/structure/closet/crate/medical + containername = "Medical crate" + +/datum/supply_packs/med/bloodpack + name = "BloodPack crate" + contains = list(/obj/item/weapon/storage/box/bloodpacks = 3) + cost = 10 + containertype = /obj/structure/closet/crate/medical + containername = "BloodPack crate" + +/datum/supply_packs/med/bodybag + name = "Body bag crate" + contains = list(/obj/item/weapon/storage/box/bodybags = 3) + cost = 10 + containertype = /obj/structure/closet/crate/medical + containername = "Body bag crate" + +/datum/supply_packs/med/cryobag + name = "Stasis bag crate" + contains = list(/obj/item/bodybag/cryobag = 3) + cost = 50 + containertype = /obj/structure/closet/crate/medical + containername = "Stasis bag crate" + +/datum/supply_packs/med/surgery + name = "Surgery crate" + contains = list( + /obj/item/weapon/cautery, + /obj/item/weapon/surgicaldrill, + /obj/item/clothing/mask/breath/medical, + /obj/item/weapon/tank/anesthetic, + /obj/item/weapon/FixOVein, + /obj/item/weapon/hemostat, + /obj/item/weapon/scalpel, + /obj/item/weapon/bonegel, + /obj/item/weapon/retractor, + /obj/item/weapon/bonesetter, + /obj/item/weapon/circular_saw + ) + cost = 25 + containertype = "/obj/structure/closet/crate/secure" + containername = "Surgery crate" + access = access_medical + +/datum/supply_packs/med/sterile + name = "Sterile equipment crate" + contains = list( + /obj/item/clothing/under/rank/medical/green = 2, + /obj/item/clothing/head/surgery/green = 2, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves, + /obj/item/weapon/storage/belt/medical = 3 + ) + cost = 15 + containertype = "/obj/structure/closet/crate" + containername = "Sterile equipment crate" + +/datum/supply_packs/med/extragear + name = "Medical surplus equipment" + contains = list( + /obj/item/weapon/storage/belt/medical = 3, + /obj/item/clothing/glasses/hud/health = 3, + /obj/item/device/radio/headset/headset_med/alt = 3, + /obj/item/clothing/suit/storage/hooded/wintercoat/medical = 3 + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical surplus equipment" + access = access_medical + +/datum/supply_packs/med/cmogear + name = "Chief medical officer equipment" + contains = list( + /obj/item/weapon/storage/belt/medical, + /obj/item/device/radio/headset/heads/cmo, + /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/weapon/reagent_containers/hypospray, + /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat/cmo, + /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/cmo, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe + ) + cost = 60 + containertype = "/obj/structure/closet/crate/secure" + containername = "Chief medical officer equipment" + access = access_cmo + +/datum/supply_packs/med/doctorgear + name = "Medical Doctor equipment" + contains = list( + /obj/item/weapon/storage/belt/medical, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/medical, + /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/mask/surgical, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/medical, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical Doctor equipment" + access = access_medical_equip + +/datum/supply_packs/med/chemistgear + name = "Chemist equipment" + contains = list( + /obj/item/weapon/storage/box/beakers, + /obj/item/device/radio/headset/headset_med, + /obj/item/weapon/storage/box/autoinjectors, + /obj/item/clothing/under/rank/chemist, + /obj/item/clothing/glasses/science, + /obj/item/clothing/suit/storage/toggle/labcoat/chemist, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/shoes/white, + /obj/item/weapon/cartridge/chemistry, + /obj/item/clothing/gloves/latex, + /obj/item/weapon/reagent_containers/dropper, + /obj/item/device/healthanalyzer, + /obj/item/weapon/storage/box/pillbottles, + /obj/item/weapon/reagent_containers/syringe + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Chemist equipment" + access = access_chemistry + +/datum/supply_packs/med/paramedicgear + name = "Paramedic equipment" + contains = list( + /obj/item/weapon/storage/belt/medical/emt, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/medical/black, + /obj/item/clothing/accessory/armband/medgreen, + /obj/item/clothing/glasses/hud/health, + /obj/item/clothing/suit/storage/toggle/labcoat/emt, + /obj/item/clothing/under/rank/medical/paramedic, + /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/mask/gas, + /obj/item/clothing/under/rank/medical/paramedic, + /obj/item/clothing/accessory/stethoscope, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/gloves/latex, + /obj/item/device/healthanalyzer, + /obj/item/weapon/cartridge/medical, + /obj/item/device/flashlight/pen, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/clothing/accessory/storage/white_vest + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Paramedic equipment" + access = access_medical_equip + +/datum/supply_packs/med/psychiatristgear + name = "Psychiatrist equipment" + contains = list( + /obj/item/clothing/under/rank/psych, + /obj/item/device/radio/headset/headset_med, + /obj/item/clothing/under/rank/psych/turtleneck, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/shoes/white, + /obj/item/weapon/clipboard, + /obj/item/weapon/folder/white, + /obj/item/weapon/pen, + /obj/item/weapon/cartridge/medical + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Psychiatrist equipment" + access = access_psychiatrist + +/datum/supply_packs/med/medicalscrubs + name = "Medical scrubs" + contains = list( + /obj/item/clothing/shoes/white = 3,, + /obj/item/clothing/under/rank/medical/blue = 3, + /obj/item/clothing/under/rank/medical/green = 3, + /obj/item/clothing/under/rank/medical/purple = 3, + /obj/item/clothing/under/rank/medical/black = 3, + /obj/item/clothing/head/surgery = 3, + /obj/item/clothing/head/surgery/purple = 3, + /obj/item/clothing/head/surgery/blue = 3, + /obj/item/clothing/head/surgery/green = 3, + /obj/item/clothing/head/surgery/black = 3, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical scrubs crate" + access = access_medical_equip + +/datum/supply_packs/med/autopsy + name = "Autopsy equipment" + contains = list( + /obj/item/weapon/folder/white, + /obj/item/device/camera, + /obj/item/device/camera_film = 2, + /obj/item/weapon/autopsy_scanner, + /obj/item/weapon/scalpel, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves, + /obj/item/weapon/pen + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Autopsy equipment crate" + access = access_morgue + +/datum/supply_packs/med/medicaluniforms + name = "Medical uniforms" + contains = list( + /obj/item/clothing/shoes/white = 3, + /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/clothing/under/rank/geneticist, + /obj/item/clothing/under/rank/virologist, + /obj/item/clothing/under/rank/nursesuit, + /obj/item/clothing/under/rank/nurse, + /obj/item/clothing/under/rank/orderly, + /obj/item/clothing/under/rank/medical = 3, + /obj/item/clothing/under/rank/medical/paramedic = 3, + /obj/item/clothing/suit/storage/toggle/labcoat = 3, + /obj/item/clothing/suit/storage/toggle/labcoat/cmo, + /obj/item/clothing/suit/storage/toggle/labcoat/emt, + /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/suit/storage/toggle/labcoat/genetics, + /obj/item/clothing/suit/storage/toggle/labcoat/virologist, + /obj/item/clothing/suit/storage/toggle/labcoat/chemist, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical uniform crate" + access = access_medical_equip + +/datum/supply_packs/med/medicalbiosuits + name = "Medical biohazard gear" + contains = list( + /obj/item/clothing/head/bio_hood = 3, + /obj/item/clothing/suit/bio_suit = 3, + /obj/item/clothing/head/bio_hood/virology = 2, + /obj/item/clothing/suit/bio_suit/cmo, + /obj/item/clothing/head/bio_hood/cmo, + /obj/item/clothing/mask/gas = 5, + /obj/item/weapon/tank/oxygen = 5, + /obj/item/weapon/storage/box/masks, + /obj/item/weapon/storage/box/gloves + ) + cost = 50 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical biohazard equipment" + access = access_medical_equip + +/datum/supply_packs/med/portablefreezers + name = "Portable freezers crate" + contains = list(/obj/item/weapon/storage/box/freezer = 7) + cost = 25 + containertype = "/obj/structure/closet/crate/secure" + containername = "Portable freezers" + access = access_medical_equip + +/datum/supply_packs/med/virus + name = "Virus sample crate" + contains = list(/obj/item/weapon/virusdish/random = 4) + cost = 25 + containertype = "/obj/structure/closet/crate/secure" + containername = "Virus sample crate" + access = access_cmo \ No newline at end of file diff --git a/code/datums/supplypacks/misc.dm b/code/datums/supplypacks/misc.dm new file mode 100644 index 0000000000..80c25b48a3 --- /dev/null +++ b/code/datums/supplypacks/misc.dm @@ -0,0 +1,97 @@ +/* +* Here is where any supply packs +* that don't belong elsewhere live. +*/ + + +/datum/supply_packs/misc + group = "Miscellaneous" + +/datum/supply_packs/randomised/misc + group = "Miscellaneous" + + +/datum/supply_packs/randomised/misc/card_packs + num_contained = 5 + contains = list( + /obj/item/weapon/pack/cardemon, + /obj/item/weapon/pack/spaceball, + /obj/item/weapon/deck/holder + ) + name = "Trading Card Crate" + cost = 10 + containertype = /obj/structure/closet/crate + containername = "cards crate" + +/datum/supply_packs/misc/eftpos + contains = list(/obj/item/device/eftpos) + name = "EFTPOS scanner" + cost = 10 + containertype = /obj/structure/closet/crate + containername = "EFTPOS crate" + +/datum/supply_packs/misc/chaplaingear + name = "Chaplain equipment" + contains = list( + /obj/item/clothing/under/rank/chaplain, + /obj/item/clothing/shoes/black, + /obj/item/clothing/suit/nun, + /obj/item/clothing/head/nun_hood, + /obj/item/clothing/suit/chaplain_hoodie, + /obj/item/clothing/head/chaplain_hood, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/weapon/storage/backpack/cultpack, + /obj/item/weapon/storage/fancy/candle_box = 3 + ) + cost = 10 + containertype = "/obj/structure/closet/crate" + containername = "Chaplain equipment crate" + +/datum/supply_packs/misc/hoverpod + name = "Hoverpod Shipment" + contains = list() + cost = 80 + containertype = /obj/structure/largecrate/hoverpod + containername = "Hoverpod Crate" + +/datum/supply_packs/randomised/misc/webbing + name = "Webbing crate" + num_contained = 4 + contains = list( + /obj/item/clothing/accessory/storage/black_vest, + /obj/item/clothing/accessory/storage/brown_vest, + /obj/item/clothing/accessory/storage/white_vest, + /obj/item/clothing/accessory/storage/black_drop_pouches, + /obj/item/clothing/accessory/storage/brown_drop_pouches, + /obj/item/clothing/accessory/storage/white_drop_pouches, + /obj/item/clothing/accessory/storage/webbing + ) + cost = 15 + containertype = "/obj/structure/closet/crate" + containername = "Webbing crate" + +/datum/supply_packs/atmos/internals + name = "Internals crate" + contains = list( + /obj/item/clothing/mask/gas = 3, + /obj/item/weapon/tank/air = 3 + ) + cost = 10 + containertype = /obj/structure/closet/crate/internals + containername = "Internals crate" + +/datum/supply_packs/atmos/evacuation + name = "Emergency equipment" + contains = list( + /obj/item/weapon/storage/toolbox/emergency = 2, + /obj/item/clothing/suit/storage/hazardvest = 2, + /obj/item/clothing/suit/storage/vest = 2, + /obj/item/weapon/tank/emergency_oxygen/engi = 4, + /obj/item/clothing/suit/space/emergency = 4, + /obj/item/clothing/head/helmet/space/emergency = 4, + /obj/item/clothing/mask/gas = 4 + ) + cost = 45 + containertype = /obj/structure/closet/crate/internals + containername = "Emergency crate" \ No newline at end of file diff --git a/code/datums/supplypacks/munitions.dm b/code/datums/supplypacks/munitions.dm new file mode 100644 index 0000000000..a33c9accac --- /dev/null +++ b/code/datums/supplypacks/munitions.dm @@ -0,0 +1,151 @@ +/* +* Here is where any supply packs +* related to weapons live. +*/ + +/datum/supply_packs/munitions + group = "Munitions" + +/datum/supply_packs/randomised/munitions + group = "Munitions" + access = access_security + +/datum/supply_packs/munitions/weapons + name = "Weapons crate" + contains = list( + /obj/item/weapon/melee/baton = 2, + /obj/item/weapon/gun/energy/gun = 2, + /obj/item/weapon/gun/energy/taser = 2, + /obj/item/weapon/gun/projectile/colt/detective = 2, + /obj/item/weapon/storage/box/flashbangs = 2 + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "Weapons crate" + +/datum/supply_packs/munitions/flareguns + name = "Flare guns crate" + contains = list( + /obj/item/weapon/gun/projectile/sec/flash, + /obj/item/ammo_magazine/c45m/flash, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel/flare, + /obj/item/weapon/storage/box/flashshells + ) + cost = 25 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "Flare gun crate" + +/datum/supply_packs/munitions/eweapons + name = "Experimental weapons crate" + contains = list( + /obj/item/weapon/gun/energy/xray = 2, + /obj/item/weapon/shield/energy = 2) + cost = 125 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "Experimental weapons crate" + access = access_armory + +/datum/supply_packs/munitions/energyweapons + name = "Energy weapons crate" + contains = list(/obj/item/weapon/gun/energy/laser = 3) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "energy weapons crate" + access = access_armory + +/datum/supply_packs/munitions/shotgun + name = "Shotgun crate" + contains = list( + /obj/item/weapon/storage/box/shotgunammo, + /obj/item/weapon/storage/box/shotgunshells, + /obj/item/weapon/gun/projectile/shotgun/pump/combat = 2 + ) + cost = 65 + containertype = /obj/structure/closet/crate/secure + containername = "Shotgun crate" + access = access_armory + +/datum/supply_packs/munitions/erifle + name = "Energy marksman crate" + contains = list(/obj/item/weapon/gun/energy/sniperrifle = 2) + cost = 90 + containertype = /obj/structure/closet/crate/secure + containername = "Energy marksman crate" + access = access_armory + +/datum/supply_packs/munitions/ionweapons + name = "Electromagnetic weapons crate" + contains = list( + /obj/item/weapon/gun/energy/ionrifle = 2, + /obj/item/weapon/storage/box/emps + ) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "electromagnetic weapons crate" + access = access_armory + +/datum/supply_packs/randomised/munitions/automatic + name = "Automatic weapon crate" + num_contained = 2 + contains = list( + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/automatic/z8 + ) + cost = 90 + containertype = /obj/structure/closet/crate/secure + containername = "Automatic weapon crate" + access = access_armory + +/datum/supply_packs/munitions/energy_guns + name = "energy guns crate" + contains = list(/obj/item/weapon/gun/energy/gun = 2) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "energy guns crate" + access = access_armory + +/datum/supply_packs/munitions/bolt_rifles_competitive + name = "Competitive shooting crate" + contains = list( + /obj/item/device/assembly/timer, + /obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice = 2, + /obj/item/ammo_magazine/clip/a762/practice = 4, + /obj/item/target = 2, + /obj/item/target/alien = 2, + /obj/item/target/syndicate = 2 + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/weapon + containername = "Weapons crate" + +/datum/supply_packs/munitions/shotgunammo + name = "Ballistic ammunition crate" + contains = list( + /obj/item/weapon/storage/box/shotgunammo = 2, + /obj/item/weapon/storage/box/shotgunshells = 2 + ) + cost = 60 + containertype = /obj/structure/closet/crate/secure + containername = "ballistic ammunition crate" + access = access_armory + +/datum/supply_packs/randomised/munitions/autoammo + name = "Automatic weapon ammunition crate" + num_contained = 6 + contains = list( + /obj/item/ammo_magazine/mc9mmt, + /obj/item/ammo_magazine/mc9mmt/rubber, + /obj/item/ammo_magazine/a556 + ) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "Automatic weapon ammunition crate" + access = access_armory + +/datum/supply_packs/munitions/beanbagammo + name = "Beanbag shells" + contains = list(/obj/item/weapon/storage/box/beanbags = 3) + cost = 30 + containertype = /obj/structure/closet/crate + containername = "Beanbag shells" + access = null diff --git a/code/datums/supplypacks/recreation.dm b/code/datums/supplypacks/recreation.dm new file mode 100644 index 0000000000..18895b48f4 --- /dev/null +++ b/code/datums/supplypacks/recreation.dm @@ -0,0 +1,69 @@ +/* +* Here is where any supply packs +* related to recreation live. +*/ + + +/datum/supply_packs/recreation + group = "Recreation" + +/datum/supply_packs/randomised/recreation + group = "Recreation" + access = access_security + +/datum/supply_packs/recreation/foam_weapons + name = "Foam Weapon Crate" + contains = list( + /obj/item/weapon/material/sword/foam = 2, + /obj/item/weapon/material/twohanded/baseballbat/foam = 2, + /obj/item/weapon/material/twohanded/spear/foam = 2, + /obj/item/weapon/material/twohanded/fireaxe/foam = 2 + ) + cost = 80 + containertype = /obj/structure/closet/crate + containername = "foam weapon crate" + +/datum/supply_packs/recreation/lasertag + name = "Lasertag equipment" + contains = list( + /obj/item/weapon/gun/energy/lasertag/red, + /obj/item/clothing/suit/redtag, + /obj/item/weapon/gun/energy/lasertag/blue, + /obj/item/clothing/suit/bluetag + ) + containertype = /obj/structure/closet + containername = "Lasertag Closet" + cost = 20 + +/datum/supply_packs/recreation/artscrafts + name = "Arts and Crafts supplies" + contains = list( + /obj/item/weapon/storage/fancy/crayons, + /obj/item/device/camera, + /obj/item/device/camera_film = 2, + /obj/item/weapon/storage/photo_album, + /obj/item/weapon/packageWrap, + /obj/item/weapon/reagent_containers/glass/paint/red, + /obj/item/weapon/reagent_containers/glass/paint/green, + /obj/item/weapon/reagent_containers/glass/paint/blue, + /obj/item/weapon/reagent_containers/glass/paint/yellow, + /obj/item/weapon/reagent_containers/glass/paint/purple, + /obj/item/weapon/reagent_containers/glass/paint/black, + /obj/item/weapon/reagent_containers/glass/paint/white, + /obj/item/weapon/contraband/poster, + /obj/item/weapon/wrapping_paper = 3 + ) + cost = 10 + containertype = "/obj/structure/closet/crate" + containername = "Arts and Crafts crate" + +/datum/supply_packs/recreation/painters + name = "Station Painting Supplies" + cost = 10 + containername = "station painting supplies crate" + containertype = /obj/structure/closet/crate + contains = list( + /obj/item/device/pipe_painter = 2, + /obj/item/device/floor_painter = 2, + /obj/item/device/closet_painter = 2 + ) \ No newline at end of file diff --git a/code/datums/supplypacks/robotics.dm b/code/datums/supplypacks/robotics.dm new file mode 100644 index 0000000000..090f3d2078 --- /dev/null +++ b/code/datums/supplypacks/robotics.dm @@ -0,0 +1,104 @@ +/* +* Here is where any supply packs +* related to robotics tasks live. +*/ + + +/datum/supply_packs/robotics + group = "Robotics" + +/datum/supply_packs/randomised/robotics + group = "Robotics" + access = access_robotics + +/datum/supply_packs/eng/robotics + name = "Robotics assembly crate" + contains = list( + /obj/item/device/assembly/prox_sensor = 3, + /obj/item/weapon/storage/toolbox/electrical, + /obj/item/device/flash = 4, + /obj/item/weapon/cell/high = 2 + ) + cost = 10 + containertype = /obj/structure/closet/crate/secure/gear + containername = "Robotics assembly" + access = access_robotics + +/datum/supply_packs/robotics/robolimbs_basic + name = "Basic robolimb blueprints" + contains = list( + /obj/item/weapon/disk/limb/morpheus, + /obj/item/weapon/disk/limb/xion + ) + cost = 15 + containertype = /obj/structure/closet/crate/secure/gear + containername = "Robolimb blueprints (basic)" + access = access_robotics + +/datum/supply_packs/robotics/robolimbs_adv + name = "All robolimb blueprints" + contains = list( + /obj/item/weapon/disk/limb/bishop, + /obj/item/weapon/disk/limb/hesphiastos, + /obj/item/weapon/disk/limb/morpheus, + /obj/item/weapon/disk/limb/veymed, + /obj/item/weapon/disk/limb/wardtakahashi, + /obj/item/weapon/disk/limb/xion, + /obj/item/weapon/disk/limb/zenghu, + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/gear + containername = "Robolimb blueprints (adv)" + access = access_robotics + +/datum/supply_packs/robotics/mecha_ripley + name = "Circuit Crate (\"Ripley\" APLU)" + contains = list( + /obj/item/weapon/book/manual/ripley_build_and_repair, + /obj/item/weapon/circuitboard/mecha/ripley/main, + /obj/item/weapon/circuitboard/mecha/ripley/peripherals + ) + cost = 30 + containertype = /obj/structure/closet/crate/secure + containername = "APLU \"Ripley\" Circuit Crate" + access = access_robotics + +/datum/supply_packs/robotics/mecha_odysseus + name = "Circuit Crate (\"Odysseus\")" + contains = list( + /obj/item/weapon/circuitboard/mecha/odysseus/peripherals, + /obj/item/weapon/circuitboard/mecha/odysseus/main + ) + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "\"Odysseus\" Circuit Crate" + access = access_robotics + +/datum/supply_packs/randomised/robotics/exosuit_mod + num_contained = 1 + contains = list( + /obj/item/device/kit/paint/ripley, + /obj/item/device/kit/paint/ripley/death, + /obj/item/device/kit/paint/ripley/flames_red, + /obj/item/device/kit/paint/ripley/flames_blue + ) + name = "Random APLU modkit" + cost = 200 + containertype = /obj/structure/closet/crate + containername = "heavy crate" + +/datum/supply_packs/randomised/robotics/exosuit_mod/durand + contains = list( + /obj/item/device/kit/paint/durand, + /obj/item/device/kit/paint/durand/seraph, + /obj/item/device/kit/paint/durand/phazon + ) + name = "Random Durand exosuit modkit" + +/datum/supply_packs/randomised/robotics/exosuit_mod/gygax + contains = list( + /obj/item/device/kit/paint/gygax, + /obj/item/device/kit/paint/gygax/darkgygax, + /obj/item/device/kit/paint/gygax/recitence + ) + name = "Random Gygax exosuit modkit" \ No newline at end of file diff --git a/code/datums/supplypacks/science.dm b/code/datums/supplypacks/science.dm new file mode 100644 index 0000000000..e95cb2d9cf --- /dev/null +++ b/code/datums/supplypacks/science.dm @@ -0,0 +1,41 @@ +/* +* Here is where any supply packs +* related to security tasks live +*/ +/datum/supply_packs/sci + group = "Science" + +/datum/supply_packs/sci/coolanttank + name = "Coolant tank crate" + contains = list(/obj/structure/reagent_dispensers/coolanttank) + cost = 16 + containertype = /obj/structure/largecrate + containername = "coolant tank crate" + +/datum/supply_packs/sci/phoron + name = "Phoron assembly crate" + contains = list( + /obj/item/weapon/tank/phoron = 3, + /obj/item/device/assembly/igniter = 3, + /obj/item/device/assembly/prox_sensor = 3, + /obj/item/device/assembly/timer = 3 + ) + cost = 10 + containertype = /obj/structure/closet/crate/secure/phoron + containername = "Phoron assembly crate" + access = access_tox_storage + +/datum/supply_packs/sci/exoticseeds + name = "Exotic seeds crate" + contains = list( + /obj/item/seeds/replicapod = 2, + /obj/item/seeds/libertymycelium, + /obj/item/seeds/reishimycelium, + /obj/item/seeds/random = 6, + /obj/item/seeds/kudzuseed + ) + cost = 15 + containertype = /obj/structure/closet/crate/hydroponics + containername = "Exotic Seeds crate" + access = access_hydroponics + diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm new file mode 100644 index 0000000000..483d8e0c12 --- /dev/null +++ b/code/datums/supplypacks/security.dm @@ -0,0 +1,375 @@ +/* +* Here is where any supply packs +* related to security tasks live +*/ + + +/datum/supply_packs/security + group = "Security" + access = access_security + +/datum/supply_packs/randomised/security + group = "Security" + access = access_security + +/datum/supply_packs/randomised/security/armor + num_contained = 5 + contains = list( + /obj/item/clothing/suit/storage/vest, + /obj/item/clothing/suit/storage/vest/officer, + /obj/item/clothing/suit/storage/vest/warden, + /obj/item/clothing/suit/storage/vest/hos, + /obj/item/clothing/suit/storage/vest/pcrc, + /obj/item/clothing/suit/storage/vest/detective, + /obj/item/clothing/suit/storage/vest/heavy, + /obj/item/clothing/suit/storage/vest/heavy/officer, + /obj/item/clothing/suit/storage/vest/heavy/warden, + /obj/item/clothing/suit/storage/vest/heavy/hos, + /obj/item/clothing/suit/storage/vest/heavy/pcrc + ) + + name = "Armor crate" + cost = 40 + containertype = /obj/structure/closet/crate/secure + containername = "Armor crate" + +/datum/supply_packs/security/riot_gear + name = "Riot gear crate" + contains = list( + /obj/item/weapon/melee/baton = 3, + /obj/item/weapon/shield/riot = 3, + /obj/item/weapon/handcuffs = 3, + /obj/item/weapon/storage/box/flashbangs, + /obj/item/weapon/storage/box/beanbags, + /obj/item/weapon/storage/box/handcuffs + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure + containername = "riot gear crate" + access = access_armory + +/datum/supply_packs/security/riot_armor + name = "Riot armor set crate" + contains = list( + /obj/item/clothing/head/helmet/riot, + /obj/item/clothing/suit/armor/riot, + /obj/item/clothing/gloves/arm_guard/riot, + /obj/item/clothing/shoes/leg_guard/riot + ) + cost = 30 + containertype = /obj/structure/closet/crate/secure + containername = "riot armor set crate" + access = access_armory + +/datum/supply_packs/security/ablative_armor + name = "Ablative armor set crate" + contains = list( + /obj/item/clothing/head/helmet/laserproof, + /obj/item/clothing/suit/armor/laserproof, + /obj/item/clothing/gloves/arm_guard/laserproof, + /obj/item/clothing/shoes/leg_guard/laserproof + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure + containername = "ablative armor set crate" + access = access_armory + +/datum/supply_packs/security/bullet_resistant_armor + name = "Bullet resistant armor set crate" + contains = list( + /obj/item/clothing/head/helmet/bulletproof, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/gloves/arm_guard/bulletproof, + /obj/item/clothing/shoes/leg_guard/bulletproof + ) + cost = 35 + containertype = /obj/structure/closet/crate/secure + containername = "bullet resistant armor set crate" + access = access_armory + +/datum/supply_packs/security/combat_armor + name = "Combat armor set crate" + contains = list( + /obj/item/clothing/head/helmet/combat, + /obj/item/clothing/suit/armor/combat, + /obj/item/clothing/gloves/arm_guard/combat, + /obj/item/clothing/shoes/leg_guard/combat + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure + containername = "combat armor set crate" + access = access_armory + +/datum/supply_packs/security/tactical + name = "Tactical suits" + containertype = /obj/structure/closet/crate/secure + containername = "Tactical Suit Locker" + cost = 60 + access = access_armory + contains = list( + /obj/item/clothing/under/tactical, + /obj/item/clothing/suit/armor/tactical, + /obj/item/clothing/head/helmet/tactical, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/glasses/sunglasses/sechud/tactical, + /obj/item/weapon/storage/belt/security/tactical, + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/gloves/black, + /obj/item/clothing/under/tactical, + /obj/item/clothing/suit/armor/tactical, + /obj/item/clothing/head/helmet/tactical, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/glasses/sunglasses/sechud/tactical, + /obj/item/weapon/storage/belt/security/tactical, + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/gloves/black + ) + +/datum/supply_packs/security/securitybarriers + name = "Security barrier crate" + contains = list(/obj/machinery/deployable/barrier = 4) + cost = 20 + containertype = /obj/structure/closet/crate/secure/gear + containername = "Security barrier crate" + access = null + +/datum/supply_packs/security/securityshieldgen + name = "Wall shield Generators" + contains = list(/obj/machinery/shieldwallgen = 4) + cost = 20 + containertype = /obj/structure/closet/crate/secure + containername = "wall shield generators crate" + access = access_teleporter + +/datum/supply_packs/randomised/security/holster + name = "Holster crate" + num_contained = 4 + contains = list( + /obj/item/clothing/accessory/holster, + /obj/item/clothing/accessory/holster/armpit, + /obj/item/clothing/accessory/holster/waist, + /obj/item/clothing/accessory/holster/hip + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Holster crate" + +/datum/supply_packs/security/extragear + name = "Security surplus equipment" + contains = list( + /obj/item/weapon/storage/belt/security = 3, + /obj/item/clothing/glasses/sunglasses/sechud = 3, + /obj/item/device/radio/headset/headset_sec/alt = 3, + /obj/item/clothing/suit/storage/hooded/wintercoat/security = 3 + ) + cost = 25 + containertype = "/obj/structure/closet/crate/secure" + containername = "Security surplus equipment" + access = null + +/datum/supply_packs/security/detectivegear + name = "Forensic investigation equipment" + contains = list( + /obj/item/weapon/storage/box/evidence = 2, + /obj/item/clothing/suit/storage/vest/detective, + /obj/item/weapon/cartridge/detective, + /obj/item/device/radio/headset/headset_sec, + /obj/item/taperoll/police, + /obj/item/clothing/glasses/sunglasses, + /obj/item/device/camera, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/blue, + /obj/item/weapon/storage/belt/detective, + /obj/item/clothing/gloves/black, + /obj/item/device/taperecorder, + /obj/item/device/mass_spectrometer, + /obj/item/device/camera_film = 2, + /obj/item/weapon/storage/photo_album, + /obj/item/device/reagent_scanner, + /obj/item/device/flashlight/maglight, + /obj/item/weapon/storage/briefcase/crimekit + ) + cost = 40 + containertype = "/obj/structure/closet/crate/secure" + containername = "Forensic equipment" + access = access_forensics_lockers + +/datum/supply_packs/security/detectiveclothes + name = "Investigation apparel" + contains = list( + /obj/item/clothing/under/det/black = 2, + /obj/item/clothing/under/det/grey = 2, + /obj/item/clothing/head/det/grey = 2, + /obj/item/clothing/under/det = 2, + /obj/item/clothing/head/det = 2, + /obj/item/clothing/suit/storage/det_trench, + /obj/item/clothing/suit/storage/det_trench/grey, + /obj/item/clothing/suit/storage/forensics/red, + /obj/item/clothing/suit/storage/forensics/blue, + /obj/item/clothing/under/det/corporate = 2, + /obj/item/clothing/accessory/badge/holo/detective = 2, + /obj/item/clothing/gloves/black = 2 + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Investigation clothing" + access = access_forensics_lockers + +/datum/supply_packs/security/officergear + name = "Officer equipment" + contains = list( + /obj/item/clothing/suit/storage/vest/officer, + /obj/item/clothing/head/helmet, + /obj/item/weapon/cartridge/security, + /obj/item/clothing/accessory/badge/holo, + /obj/item/clothing/accessory/badge/holo/cord, + /obj/item/device/radio/headset/headset_sec, + /obj/item/weapon/storage/belt/security, + /obj/item/device/flash, + /obj/item/weapon/reagent_containers/spray/pepper, + /obj/item/weapon/grenade/flashbang, + /obj/item/weapon/melee/baton/loaded, + /obj/item/clothing/glasses/sunglasses/sechud, + /obj/item/taperoll/police, + /obj/item/clothing/gloves/black, + /obj/item/device/hailer, + /obj/item/device/flashlight/flare, + /obj/item/clothing/accessory/storage/black_vest, + /obj/item/clothing/head/soft/sec/corp, + /obj/item/clothing/under/rank/security/corp, + /obj/item/weapon/gun/energy/taser, + /obj/item/device/flashlight/maglight + ) + cost = 30 + containertype = "/obj/structure/closet/crate/secure" + containername = "Officer equipment" + access = access_brig + +/datum/supply_packs/security/wardengear + name = "Warden equipment" + contains = list( + /obj/item/clothing/suit/storage/vest/warden, + /obj/item/clothing/under/rank/warden, + /obj/item/clothing/under/rank/warden/corp, + /obj/item/clothing/suit/armor/vest/warden, + /obj/item/clothing/suit/armor/vest/warden/alt, + /obj/item/clothing/head/helmet/warden, + /obj/item/weapon/cartridge/security, + /obj/item/device/radio/headset/headset_sec, + /obj/item/clothing/glasses/sunglasses/sechud, + /obj/item/taperoll/police, + /obj/item/device/hailer, + /obj/item/clothing/accessory/badge/holo/warden, + /obj/item/weapon/storage/box/flashbangs, + /obj/item/weapon/storage/belt/security, + /obj/item/weapon/reagent_containers/spray/pepper, + /obj/item/weapon/melee/baton/loaded, + /obj/item/weapon/storage/box/holobadge, + /obj/item/clothing/head/beret/sec/corporate/warden, + /obj/item/device/flashlight/maglight + ) + cost = 45 + containertype = "/obj/structure/closet/crate/secure" + containername = "Warden equipment" + access = access_armory + +/datum/supply_packs/security/headofsecgear + name = "Head of security equipment" + contains = list( + /obj/item/clothing/head/helmet/HoS, + /obj/item/clothing/suit/storage/vest/hos, + /obj/item/clothing/under/rank/head_of_security/corp, + /obj/item/clothing/suit/armor/hos, + /obj/item/clothing/head/helmet/HoS/dermal, + /obj/item/weapon/cartridge/hos, + /obj/item/device/radio/headset/heads/hos, + /obj/item/clothing/glasses/sunglasses/sechud, + /obj/item/weapon/storage/belt/security, + /obj/item/device/flash, + /obj/item/device/hailer, + /obj/item/clothing/accessory/badge/holo/hos, + /obj/item/clothing/accessory/holster/waist, + /obj/item/weapon/melee/telebaton, + /obj/item/weapon/shield/riot/tele, + /obj/item/clothing/head/beret/sec/corporate/hos, + /obj/item/device/flashlight/maglight + ) + cost = 65 + containertype = "/obj/structure/closet/crate/secure" + containername = "Head of security equipment" + access = access_hos + +/datum/supply_packs/security/securityclothing + name = "Security uniform crate" + contains = list( + /obj/item/weapon/storage/backpack/satchel/sec = 2, + /obj/item/weapon/storage/backpack/security = 2, + /obj/item/clothing/accessory/armband = 4, + /obj/item/clothing/under/rank/security = 4, + /obj/item/clothing/under/rank/security2 = 4, + /obj/item/clothing/under/rank/warden, + /obj/item/clothing/under/rank/head_of_security, + /obj/item/clothing/suit/armor/hos/jensen, + /obj/item/clothing/head/soft/sec = 4, + /obj/item/clothing/gloves/black = 4, + /obj/item/weapon/storage/box/holobadge + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Security uniform crate" + +/datum/supply_packs/security/navybluesecurityclothing + name = "Navy blue security uniform crate" + contains = list( + /obj/item/weapon/storage/backpack/satchel/sec = 2, + /obj/item/weapon/storage/backpack/security = 2, + /obj/item/clothing/under/rank/security/navyblue = 4, + /obj/item/clothing/suit/security/navyofficer = 4, + /obj/item/clothing/under/rank/warden/navyblue, + /obj/item/clothing/suit/security/navywarden, + /obj/item/clothing/under/rank/head_of_security/navyblue, + /obj/item/clothing/suit/security/navyhos, + /obj/item/clothing/head/beret/sec/navy/officer = 4, + /obj/item/clothing/head/beret/sec/navy/warden, + /obj/item/clothing/head/beret/sec/navy/hos, + /obj/item/clothing/gloves/black = 4, + /obj/item/weapon/storage/box/holobadge + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Navy blue security uniform crate" + +/datum/supply_packs/security/corporatesecurityclothing + name = "Corporate security uniform crate" + contains = list( + /obj/item/weapon/storage/backpack/satchel/sec = 2, + /obj/item/weapon/storage/backpack/security = 2, + /obj/item/clothing/under/rank/security/corp = 4, + /obj/item/clothing/head/soft/sec/corp = 4, + /obj/item/clothing/under/rank/warden/corp, + /obj/item/clothing/under/rank/head_of_security/corp, + /obj/item/clothing/head/beret/sec = 4, + /obj/item/clothing/head/beret/sec/corporate/warden, + /obj/item/clothing/head/beret/sec/corporate/hos, + /obj/item/clothing/under/det/corporate = 2, + /obj/item/clothing/gloves/black = 4, + /obj/item/weapon/storage/box/holobadge + ) + cost = 20 + containertype = "/obj/structure/closet/crate/secure" + containername = "Corporate security uniform crate" + +/datum/supply_packs/security/biosuit + name = "Security biohazard gear" + contains = list( + /obj/item/clothing/head/bio_hood/security, + /obj/item/clothing/under/rank/security, + /obj/item/clothing/suit/bio_suit/security, + /obj/item/clothing/shoes/white, + /obj/item/clothing/mask/gas, + /obj/item/weapon/tank/oxygen, + /obj/item/clothing/gloves/latex + ) + cost = 35 + containertype = "/obj/structure/closet/crate/secure" + containername = "Security biohazard gear" diff --git a/code/datums/supplypacks/supply.dm b/code/datums/supplypacks/supply.dm new file mode 100644 index 0000000000..e9832b3657 --- /dev/null +++ b/code/datums/supplypacks/supply.dm @@ -0,0 +1,130 @@ +/* +* Here is where any supply packs +* related to civilian tasks live +*/ + +/datum/supply_packs/supply + group = "Supplies" + +/datum/supply_packs/supply/food + name = "Kitchen supply crate" + contains = list( + /obj/item/weapon/reagent_containers/food/condiment/flour = 6, + /obj/item/weapon/reagent_containers/food/drinks/milk = 3, + /obj/item/weapon/reagent_containers/food/drinks/soymilk = 2, + /obj/item/weapon/storage/fancy/egg_box = 2, + /obj/item/weapon/reagent_containers/food/snacks/tofu = 4, + /obj/item/weapon/reagent_containers/food/snacks/meat = 4 + ) + cost = 10 + containertype = /obj/structure/closet/crate/freezer + containername = "Food crate" + +/datum/supply_packs/supply/toner + name = "Toner cartridges" + contains = list(/obj/item/device/toner = 6) + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Toner cartridges" + +/datum/supply_packs/supply/janitor + name = "Janitorial supplies" + contains = list( + /obj/item/weapon/reagent_containers/glass/bucket, + /obj/item/weapon/mop, + /obj/item/clothing/under/rank/janitor, + /obj/item/weapon/cartridge/janitor, + /obj/item/clothing/gloves/black, + /obj/item/clothing/head/soft/purple, + /obj/item/weapon/storage/belt/janitor, + /obj/item/clothing/shoes/galoshes, + /obj/item/weapon/caution = 4, + /obj/item/weapon/storage/bag/trash, + /obj/item/device/lightreplacer, + /obj/item/weapon/reagent_containers/spray/cleaner, + /obj/item/weapon/reagent_containers/glass/rag, + /obj/item/weapon/grenade/chem_grenade/cleaner = 3, + /obj/structure/mopbucket + ) + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Janitorial supplies" + +/datum/supply_packs/supply/boxes + name = "Empty boxes" + contains = list(/obj/item/weapon/storage/box = 10) + cost = 10 + containertype = "/obj/structure/closet/crate" + containername = "Empty box crate" + +/datum/supply_packs/supply/bureaucracy + contains = list( + /obj/item/weapon/clipboard = 2, + /obj/item/weapon/pen/red, + /obj/item/weapon/pen/blue, + /obj/item/weapon/pen/blue, + /obj/item/device/camera_film, + /obj/item/weapon/folder/blue, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/yellow, + /obj/item/weapon/hand_labeler, + /obj/item/weapon/tape_roll, + /obj/structure/filingcabinet/chestdrawer{anchored = 0}, + /obj/item/weapon/paper_bin + ) + name = "Office supplies" + cost = 15 + containertype = /obj/structure/closet/crate + containername = "Office supplies crate" + +/datum/supply_packs/supply/spare_pda + name = "Spare PDAs" + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Spare PDA crate" + contains = list(/obj/item/device/pda = 3) + +/datum/supply_packs/supply/minergear + name = "Shaft miner equipment" + contains = list( + /obj/item/weapon/storage/backpack/industrial, + /obj/item/weapon/storage/backpack/satchel/eng, + /obj/item/clothing/suit/storage/hooded/wintercoat/miner, + /obj/item/device/radio/headset/headset_cargo, + /obj/item/clothing/under/rank/miner, + /obj/item/clothing/gloves/black, + /obj/item/clothing/shoes/black, + /obj/item/device/analyzer, + /obj/item/weapon/storage/bag/ore, + /obj/item/device/flashlight/lantern, + /obj/item/weapon/shovel, + /obj/item/weapon/pickaxe, + /obj/item/weapon/mining_scanner, + /obj/item/clothing/glasses/material, + /obj/item/clothing/glasses/meson + ) + cost = 15 + containertype = "/obj/structure/closet/crate/secure" + containername = "Shaft miner equipment" + access = access_mining + +/datum/supply_packs/supply/mule + name = "Mulebot Crate" + contains = list() + cost = 20 + containertype = /obj/structure/largecrate/animal/mulebot + containername = "Mulebot Crate" + +/datum/supply_packs/supply/cargotrain + name = "Cargo Train Tug" + contains = list(/obj/vehicle/train/cargo/engine) + cost = 45 + containertype = /obj/structure/largecrate + containername = "Cargo Train Tug Crate" + +/datum/supply_packs/supply/cargotrailer + name = "Cargo Train Trolley" + contains = list(/obj/vehicle/train/cargo/trolley) + cost = 15 + containertype = /obj/structure/largecrate + containername = "Cargo Train Trolley Crate" \ No newline at end of file diff --git a/code/datums/supplypacks/supplypacks.dm b/code/datums/supplypacks/supplypacks.dm new file mode 100644 index 0000000000..c62231285c --- /dev/null +++ b/code/datums/supplypacks/supplypacks.dm @@ -0,0 +1,54 @@ +//SUPPLY PACKS +//NOTE: only secure crate types use the access var (and are lockable) +//NOTE: hidden packs only show up when the computer has been hacked. +//ANOTER NOTE: Contraband is obtainable through modified supplycomp circuitboards. +//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle. +//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points. + +//var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Atmospherics","Medical","Reagents","Reagent Cartridges","Science","Hydroponics", "Supply", "Miscellaneous") +var/list/all_supply_groups = list("Atmospherics", + "Costumes", + "Engineering", + "Hospitality", + "Hydroponics", + "Materials", + "Medical", + "Miscellaneous", + "Munitions", + "Reagents", + "Reagent Cartridges", + "Recreation", + "Robotics", + "Science", + "Security", + "Supplies", + "Voidsuits") + +/datum/supply_packs + var/name = null + var/list/contains = list() + var/manifest = "" + var/amount = null + var/cost = null + var/containertype = null + var/containername = null + var/access = null + var/hidden = 0 + var/contraband = 0 + var/group = "Operations" + +/datum/supply_packs/New() + manifest += "
    " + for(var/path in contains) + if(!path || !ispath(path, /atom)) + continue + var/atom/O = path + manifest += "
  • [initial(O.name)]
  • " + manifest += "
" + +/datum/supply_packs/randomised + var/num_contained //number of items picked to be contained in a randomised crate + +/datum/supply_packs/randomised/New() + manifest += "Contains any [num_contained] of:" + ..() \ No newline at end of file diff --git a/code/datums/supplypacks/voidsuits.dm b/code/datums/supplypacks/voidsuits.dm new file mode 100644 index 0000000000..3d37bd171a --- /dev/null +++ b/code/datums/supplypacks/voidsuits.dm @@ -0,0 +1,76 @@ +/* +* Here is where any supply packs +* related to voidsuits live. +*/ + + +/datum/supply_packs/voidsuits + group = "Voidsuits" + +/datum/supply_packs/voidsuits/atmos + name = "Atmospheric voidsuits" + contains = list( + /obj/item/clothing/suit/space/void/atmos = 2, + /obj/item/clothing/head/helmet/space/void/atmos = 2, + /obj/item/clothing/mask/breath = 2, + /obj/item/clothing/shoes/magboots = 2, + /obj/item/weapon/tank/oxygen = 2, + ) + cost = 45 + containertype = "/obj/structure/closet/crate/secure" + containername = "Atmospheric voidsuit crate" + access = access_atmospherics + +/datum/supply_packs/voidsuits/engineering + name = "Engineering voidsuits" + contains = list( + /obj/item/clothing/suit/space/void/engineering = 2, + /obj/item/clothing/head/helmet/space/void/engineering = 2, + /obj/item/clothing/mask/breath = 2, + /obj/item/clothing/shoes/magboots = 2, + /obj/item/weapon/tank/oxygen = 2 + ) + cost = 40 + containertype = "/obj/structure/closet/crate/secure" + containername = "Engineering voidsuit crate" + access = access_engine_equip + +/datum/supply_packs/voidsuits/medical + name = "Medical voidsuits" + contains = list( + /obj/item/clothing/suit/space/void/medical = 2, + /obj/item/clothing/head/helmet/space/void/medical = 2, + /obj/item/clothing/mask/breath = 2, + /obj/item/clothing/shoes/magboots = 2, + /obj/item/weapon/tank/oxygen = 2 + ) + cost = 40 + containertype = "/obj/structure/closet/crate/secure" + containername = "Medical voidsuit crate" + access = access_medical_equip + +/datum/supply_packs/voidsuits/security + name = "Security voidsuits" + contains = list( + /obj/item/clothing/suit/space/void/security = 2, + /obj/item/clothing/head/helmet/space/void/security = 2, + /obj/item/clothing/mask/breath = 2, + /obj/item/clothing/shoes/magboots = 2, + /obj/item/weapon/tank/oxygen = 2 + ) + cost = 55 + containertype = "/obj/structure/closet/crate/secure" + containername = "Security voidsuit crate" + +/datum/supply_packs/voidsuits/supply + name = "Mining voidsuits" + contains = list( + /obj/item/clothing/suit/space/void/mining = 2, + /obj/item/clothing/head/helmet/space/void/mining = 2, + /obj/item/clothing/mask/breath = 2, + /obj/item/weapon/tank/oxygen = 2 + ) + cost = 35 + containertype = "/obj/structure/closet/crate/secure" + containername = "Mining voidsuit crate" + access = access_mining \ No newline at end of file diff --git a/code/datums/underwear/bottom.dm b/code/datums/underwear/bottom.dm new file mode 100644 index 0000000000..64d90f62b4 --- /dev/null +++ b/code/datums/underwear/bottom.dm @@ -0,0 +1,60 @@ +/datum/category_item/underwear/bottom/none + name = "None" + always_last = TRUE + +/datum/category_item/underwear/bottom/briefs + name = "Briefs" + icon_state = "briefs" + has_color = TRUE + +/datum/category_item/underwear/bottom/briefs/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/bottom/boxers_loveheart + name = "Boxers, Loveheart" + icon_state = "boxers_loveheart" + +/datum/category_item/underwear/bottom/boxers + name = "Boxers" + icon_state = "boxers" + has_color = TRUE + +/datum/category_item/underwear/bottom/boxers_green_and_blue + name = "Boxers, green & blue striped" + icon_state = "boxers_green_and_blue" + +/datum/category_item/underwear/bottom/panties + name = "Panties" + icon_state = "panties" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/bottom/lacy_thong + name = "Lacy thong" + icon_state = "lacy_thong" + +/datum/category_item/underwear/bottom/lacy_thong_alt + name = "Lacy thong, alt" + icon_state = "lacy_thong_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties_alt + name = "Panties, alt" + icon_state = "panties_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/compression_shorts + name = "Compression shorts" + icon_state = "compression_shorts" + has_color = TRUE + +/datum/category_item/underwear/bottom/thong + name = "Thong" + icon_state = "thong" + has_color = TRUE + +/datum/category_item/underwear/bottom/fishnet_lower + name = "Fishnets" + icon_state = "fishnet_lower" \ No newline at end of file diff --git a/code/datums/underwear/socks.dm b/code/datums/underwear/socks.dm new file mode 100644 index 0000000000..fc1c96ce53 --- /dev/null +++ b/code/datums/underwear/socks.dm @@ -0,0 +1,59 @@ +/datum/category_item/underwear/socks/none + always_last = TRUE + name = "None" + +/datum/category_item/underwear/socks/normal + name = "Normal" + icon_state = "socks_norm" + has_color = TRUE + +/datum/category_item/underwear/socks/short + name = "Short" + icon_state = "socks_short" + has_color = TRUE + +/datum/category_item/underwear/socks/thigh + name = "Thigh" + icon_state = "socks_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/knee + name = "Knee" + icon_state = "socks_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_knee + name = "Knee, striped" + icon_state = "striped_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_thigh + name = "Thigh, striped" + icon_state = "striped_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/pantyhose + name = "Pantyhose" + icon_state = "pantyhose" + +/datum/category_item/underwear/socks/thin_thigh + name = "Thigh, thin" + icon_state = "thin_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_knee + name = "Knee, thin" + icon_state = "thin_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/rainbow_thigh + name = "Thigh, rainbow" + icon_state = "rainbow_thigh" + +/datum/category_item/underwear/socks/rainbow_knee + name = "Knee, rainbow" + icon_state = "rainbow_knee" + +/datum/category_item/underwear/socks/fishnet + name = "Fishnet" + icon_state = "fishnet" \ No newline at end of file diff --git a/code/datums/underwear/top.dm b/code/datums/underwear/top.dm new file mode 100644 index 0000000000..044f10e7cb --- /dev/null +++ b/code/datums/underwear/top.dm @@ -0,0 +1,55 @@ +/datum/category_item/underwear/top/none + name = "None" + always_last = TRUE + +/datum/category_item/underwear/top/none/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/top/bra + is_default = TRUE + name = "Bra" + icon_state = "bra" + has_color = TRUE + +/datum/category_item/underwear/top/bra/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/top/sports_bra + name = "Sports bra" + icon_state = "sports_bra" + has_color = TRUE + +/datum/category_item/underwear/top/sports_bra_alt + name = "Sports bra, alt" + icon_state = "sports_bra_alt" + has_color = TRUE + +/datum/category_item/underwear/top/lacy_bra + name = "Lacy bra" + icon_state = "lacy_bra" + +/datum/category_item/underwear/top/lacy_bra_alt + name = "Lacy bra, alt" + icon_state = "lacy_bra_alt" + has_color = TRUE + +/datum/category_item/underwear/top/lacy_bra_alt_stripe + name = "Lacy bra, alt, stripe" + icon_state = "lacy_bra_alt_stripe" + +/datum/category_item/underwear/top/halterneck_bra + name = "Halterneck bra" + icon_state = "halterneck_bra" + has_color = TRUE + +/datum/category_item/underwear/top/fishnet_base + name = "Fishnet top" + icon_state = "fishnet_body" + +/datum/category_item/underwear/top/fishnet_sleeves + name = "Fishnet with sleeves" + icon_state = "fishnet_sleeves" + +/datum/category_item/underwear/top/fishnet_gloves + name = "Fishnet with gloves" + icon_state = "fishnet_gloves" \ No newline at end of file diff --git a/code/datums/underwear/undershirts.dm b/code/datums/underwear/undershirts.dm new file mode 100644 index 0000000000..33886f997d --- /dev/null +++ b/code/datums/underwear/undershirts.dm @@ -0,0 +1,65 @@ +/datum/category_item/underwear/undershirt/none + is_default = TRUE + name = "None" + always_last = TRUE + +/datum/category_item/underwear/undershirt/shirt + name = "Shirt" + icon_state = "undershirt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top + name = "Tank top" + icon_state = "tanktop" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt + name = "Tank top, alt" + icon_state = "tanktop_alt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_fire + name = "Tank top, fire" + icon_state = "tank_fire_s" + +/datum/category_item/underwear/undershirt/shirt_heart + name = "Shirt, heart" + icon_state = "lover_s" + +/datum/category_item/underwear/undershirt/shirt_nt + name = "Shirt, NT" + icon_state = "shirt_nano_s" + +/datum/category_item/underwear/undershirt/shirt_love_nt + name = "Shirt, I<3NT" + icon_state = "lover_s" + +/datum/category_item/underwear/undershirt/shortsleeve_shirt + name = "Shortsleeve shirt" + icon_state = "shortsleeve" + has_color = TRUE + +/datum/category_item/underwear/undershirt/polo_shirt + name = "Polo shirt" + icon_state = "polo" + has_color = TRUE + +/datum/category_item/underwear/undershirt/sport_shirt_green + name = "Sport shirt, green" + icon_state = "greenshirtsport_s" + +/datum/category_item/underwear/undershirt/sport_shirt_red + name = "Sport shirt, red" + icon_state = "redshirtsport_s" + +/datum/category_item/underwear/undershirt/sport_shirt_blue + name = "Sport shirt, blue" + icon_state = "blueshirtsport_s" + +/datum/category_item/underwear/undershirt/shirt_tiedye + name = "Shirt, tiedye" + icon_state = "shirt_tiedye_s" + +/datum/category_item/underwear/undershirt/shirt_blue_striped + name = "Shirt, blue stripes" + icon_state = "shirt_stripes_s" \ No newline at end of file diff --git a/code/datums/underwear/underwear.dm b/code/datums/underwear/underwear.dm new file mode 100644 index 0000000000..d14ddea133 --- /dev/null +++ b/code/datums/underwear/underwear.dm @@ -0,0 +1,66 @@ +/**************************** +* Category Collection Setup * +****************************/ +/datum/category_collection/underwear + category_group_type = /datum/category_group/underwear + +/************* +* Categories * +*************/ +/datum/category_group/underwear + var/sort_order // Lower sort order is applied as icons first + +datum/category_group/underwear/dd_SortValue() + return sort_order + +/datum/category_group/underwear/top + name = "Underwear, top" + sort_order = 1 + category_item_type = /datum/category_item/underwear/top + +/datum/category_group/underwear/bottom + name = "Underwear, bottom" + sort_order = 2 + category_item_type = /datum/category_item/underwear/bottom + +/datum/category_group/underwear/socks + name = "Socks" + sort_order = 3 + category_item_type = /datum/category_item/underwear/socks + +/datum/category_group/underwear/undershirt + name = "Undershirt" + sort_order = 4 // Undershirts currently have the highest sort order because they may cover both underwear and socks. + category_item_type = /datum/category_item/underwear/undershirt + +/******************* +* Category entries * +*******************/ +/datum/category_item/underwear + var/always_last = FALSE // Should this entry be sorte last? + var/is_default = FALSE // Should this entry be considered the default for its type? + var/icon = 'icons/mob/human.dmi' // Which icon to get the underwear from + var/icon_state // And the particular item state + var/list/tweaks = list() // Underwear customizations. + var/has_color = FALSE + +/datum/category_item/underwear/New() + if(has_color) + tweaks += gear_tweak_free_color_choice + +/datum/category_item/underwear/dd_SortValue() + if(always_last) + return "~"+name + return name + +/datum/category_item/underwear/proc/is_default(var/gender) + return is_default + +/datum/category_item/underwear/proc/generate_image(var/list/metadata) + if(!icon_state) + return + + var/image/I = image(icon = 'icons/mob/human.dmi', icon_state = icon_state) + for(var/datum/gear_tweak/gt in tweaks) + gt.tweak_item(I, metadata && metadata["[gt]"] ? metadata["[gt]"] : gt.get_default()) + return I \ No newline at end of file diff --git a/code/datums/uplink/ammunition.dm b/code/datums/uplink/ammunition.dm new file mode 100644 index 0000000000..8308cfc319 --- /dev/null +++ b/code/datums/uplink/ammunition.dm @@ -0,0 +1,103 @@ +/************* +* Ammunition * +*************/ +/datum/uplink_item/item/ammo + item_cost = 2 + category = /datum/uplink_category/ammunition + +/datum/uplink_item/item/ammo/a357 + name = ".357 Speedloader" + path = /obj/item/ammo_magazine/a357 + +/datum/uplink_item/item/ammo/mc9mm + name = "Pistol Magazine (9mm)" + path = /obj/item/ammo_magazine/mc9mm + +/datum/uplink_item/item/ammo/c45m + name = "Pistol Magazine (.45)" + path = /obj/item/ammo_magazine/c45m + +/datum/uplink_item/item/ammo/tommymag + name = "Tommygun Magazine (.45)" + path = /obj/item/ammo_magazine/tommymag + +/datum/uplink_item/item/ammo/tommydrum + name = "Tommygun Drum Magazine (.45)" + path = /obj/item/ammo_magazine/tommydrum + item_cost = 4 // Buy 40 bullets, get 10 free! + +/datum/uplink_item/item/ammo/darts + name = "Darts" + path = /obj/item/ammo_magazine/chemdart + +/datum/uplink_item/item/ammo/sniperammo + name = "Anti-Materiel Rifle ammo box (14.5mm)" + path = /obj/item/weapon/storage/box/sniperammo + +/datum/uplink_item/item/ammo/a556 + name = "10rnd Rifle Magazine (5.56mm)" + path = /obj/item/ammo_magazine/a556 + +/datum/uplink_item/item/ammo/a556/ap + name = "10rnd Rifle Magazine (5.56mm AP)" + path = /obj/item/ammo_magazine/a556/ap + +/datum/uplink_item/item/ammo/a556m + name = "20rnd Rifle Magazine (5.56mm)" + path = /obj/item/ammo_magazine/a556m + item_cost = 4 + +/datum/uplink_item/item/ammo/a556m/ap + name = "20rnd Rifle Magazine (5.56mm AP)" + path = /obj/item/ammo_magazine/a556m/ap + item_cost = 4 + +/datum/uplink_item/item/ammo/c762 + name = "20rnd Rifle Magazine (7.62mm)" + path = /obj/item/ammo_magazine/c762 + +/datum/uplink_item/item/ammo/c762/ap + name = "20rnd Rifle Magazine (7.62mm AP)" + path = /obj/item/ammo_magazine/c762/ap + +/datum/uplink_item/item/ammo/s762 + name = "10rnd Rifle Magazine (7.62mm)" + path = /obj/item/ammo_magazine/s762 + item_cost = 1 // Half the capacity. + +/datum/uplink_item/item/ammo/s762/ap + name = "10rnd Rifle Magazine (7.62mm AP)" + path = /obj/item/ammo_magazine/s762/ap + +/datum/uplink_item/item/ammo/a10mm + name = "SMG Magazine (10mm)" + path = /obj/item/ammo_magazine/a10mm + +/datum/uplink_item/item/ammo/a762 + name = "Machinegun Magazine (7.62mm)" + path = /obj/item/ammo_magazine/a762 + +/datum/uplink_item/item/ammo/a762/ap + name = "Machinegun Magazine (7.62mm AP)" + path = /obj/item/ammo_magazine/a762/ap + +/datum/uplink_item/item/ammo/g12 + name = "12g Auto-Shotgun Magazine (Slug)" + path = /obj/item/ammo_magazine/g12 + +/datum/uplink_item/item/ammo/g12/beanbag + name = "12g Auto-Shotgun Magazine (Beanbag)" + path = /obj/item/ammo_magazine/g12/beanbag + item_cost = 1 // Discount due to it being LTL. + +/datum/uplink_item/item/ammo/g12/pellet + name = "12g Auto-Shotgun Magazine (Pellet)" + path = /obj/item/ammo_magazine/g12/pellet + +/datum/uplink_item/item/ammo/g12/stun + name = "12g Auto-Shotgun Magazine (Stun)" + path = /obj/item/weapon/storage/box/stunshells + +/datum/uplink_item/item/ammo/g12/flash + name = "12g Auto-Shotgun Magazine (Flash)" + path = /obj/item/weapon/storage/box/flashshells \ No newline at end of file diff --git a/code/datums/uplink/announcements.dm b/code/datums/uplink/announcements.dm new file mode 100644 index 0000000000..1b3cf75462 --- /dev/null +++ b/code/datums/uplink/announcements.dm @@ -0,0 +1,109 @@ +/**************** +* Announcements * +*****************/ +/datum/uplink_item/abstract/announcements + category = /datum/uplink_category/services + +/datum/uplink_item/abstract/announcements/buy(var/obj/item/device/uplink/U, var/mob/user) + . = ..() + if(.) + log_and_message_admins("has triggered a falsified [src]", user) + +/datum/uplink_item/abstract/announcements/fake_centcom + item_cost = DEFAULT_TELECRYSTAL_AMOUNT / 2 + +/datum/uplink_item/abstract/announcements/fake_centcom/New() + ..() + name = "[command_name()] Update Announcement" + desc = "Causes a falsified [command_name()] Update. Triggers immediately after supplying additional data." + +/datum/uplink_item/abstract/announcements/fake_centcom/extra_args(var/mob/user) + var/title = sanitize(input("Enter your announcement title.", "Announcement Title") as null|text) + if(!title) + return + var/message = sanitize(input("Enter your announcement message.", "Announcement Title") as null|text) + if(!message) + return + return list("title" = title, "message" = message) + +/datum/uplink_item/abstract/announcements/fake_centcom/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user, var/list/args) + command_announcement.Announce(args["message"], args["title"]) + return 1 + +/datum/uplink_item/abstract/announcements/fake_crew_arrival + name = "Crew Arrival Announcement/Records" + desc = "Creates a fake crew arrival announcement as well as fake crew records, using your current appearance (including held items!) and worn id card. Trigger with care!" + item_cost = 4 + +/datum/uplink_item/abstract/announcements/fake_crew_arrival/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user, var/list/args) + if(!user) + return 0 + + var/obj/item/weapon/card/id/I = user.GetIdCard() + var/datum/data/record/random_general_record + var/datum/data/record/random_medical_record + if(data_core.general.len) + random_general_record = pick(data_core.general) + random_medical_record = find_medical_record("id", random_general_record.fields["id"]) + + var/datum/data/record/general = data_core.CreateGeneralRecord(user) + if(I) + general.fields["age"] = I.age + general.fields["rank"] = I.assignment + general.fields["real_rank"] = I.assignment + general.fields["name"] = I.registered_name + general.fields["sex"] = I.sex + else + var/mob/living/carbon/human/H + if(istype(user,/mob/living/carbon/human)) + H = user + general.fields["age"] = H.age + else + general.fields["age"] = initial(H.age) + var/assignment = GetAssignment(user) + general.fields["rank"] = assignment + general.fields["real_rank"] = assignment + general.fields["name"] = user.real_name + general.fields["sex"] = capitalize(user.gender) + + general.fields["species"] = user.get_species() + var/datum/data/record/medical = data_core.CreateMedicalRecord(general.fields["name"], general.fields["id"]) + data_core.CreateSecurityRecord(general.fields["name"], general.fields["id"]) + + if(!random_general_record) + general.fields["citizenship"] = random_general_record.fields["citizenship"] + general.fields["faction"] = random_general_record.fields["faction"] + general.fields["fingerprint"] = random_general_record.fields["fingerprint"] + general.fields["home_system"] = random_general_record.fields["home_system"] + general.fields["religion"] = random_general_record.fields["religion"] + if(random_medical_record) + medical.fields["b_type"] = random_medical_record.fields["b_type"] + medical.fields["b_dna"] = random_medical_record.fields["b_type"] + + if(I) + general.fields["fingerprint"] = I.fingerprint_hash + medical.fields["b_type"] = I.blood_type + medical.fields["b_dna"] = I.dna_hash + + AnnounceArrivalSimple(general.fields["name"], general.fields["rank"]) + return 1 + +/datum/uplink_item/abstract/announcements/fake_ion_storm + name = "Ion Storm Announcement" + desc = "Interferes with the station's ion sensors. Triggers immediately upon investment." + item_cost = 1 + +/datum/uplink_item/abstract/announcements/fake_ion_storm/get_goods(var/obj/item/device/uplink/U, var/loc) + ion_storm_announcement() + return 1 + +/datum/uplink_item/abstract/announcements/fake_radiation + name = "Radiation Storm Announcement" + desc = "Interferes with the station's radiation sensors. Triggers immediately upon investment." + item_cost = 3 + +/datum/uplink_item/abstract/announcements/fake_radiation/get_goods(var/obj/item/device/uplink/U, var/loc) + var/datum/event_meta/EM = new(EVENT_LEVEL_MUNDANE, "Fake Radiation Storm", add_to_queue = 0) + new/datum/event/radiation_storm/syndicate(EM) + return 1 + diff --git a/code/datums/uplink/armor.dm b/code/datums/uplink/armor.dm new file mode 100644 index 0000000000..30a41d8edb --- /dev/null +++ b/code/datums/uplink/armor.dm @@ -0,0 +1,15 @@ +/******** +* Armor * +********/ +/datum/uplink_item/item/armor + category = /datum/uplink_category/armor + +/datum/uplink_item/item/armor/combat + name = "Combat Armor Set" + item_cost = 5 + path = /obj/item/weapon/storage/box/syndie_kit/combat_armor + +/datum/uplink_item/item/armor/heavy_vest + name = "Heavy Armor Vest" + item_cost = 4 + path = /obj/item/clothing/suit/storage/vest/heavy/merc diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm new file mode 100644 index 0000000000..b837625c8a --- /dev/null +++ b/code/datums/uplink/badassery.dm @@ -0,0 +1,78 @@ +/************ +* Badassery * +************/ +/datum/uplink_item/item/badassery + category = /datum/uplink_category/badassery + +/datum/uplink_item/item/badassery/balloon + name = "For showing that You Are The BOSS (Useless Balloon)" + item_cost = DEFAULT_TELECRYSTAL_AMOUNT + path = /obj/item/toy/syndicateballoon + +/datum/uplink_item/item/badassery/balloon/NT + name = "For showing that you love NT SOO much (Useless Balloon)" + path = /obj/item/toy/nanotrasenballoon + +/************** +* Random Item * +**************/ +/datum/uplink_item/item/badassery/random_one + name = "Random Item" + desc = "Buys you one random item." + +/datum/uplink_item/item/badassery/random_one/buy(var/obj/item/device/uplink/U, var/mob/user) + var/datum/uplink_item/item = default_uplink_selection.get_random_item(U.uses) + return item.buy(U, user) + +/datum/uplink_item/item/badassery/random_one/can_buy(obj/item/device/uplink/U) + return default_uplink_selection.get_random_item(U.uses, U) != null + +/datum/uplink_item/item/badassery/random_many + name = "Random Items" + desc = "Buys you as many random items you can afford. Convenient packaging NOT included." + +/datum/uplink_item/item/badassery/random_many/cost(var/telecrystals) + return max(1, telecrystals) + +/datum/uplink_item/item/badassery/random_many/get_goods(var/obj/item/device/uplink/U, var/loc) + var/list/bought_items = list() + for(var/datum/uplink_item/UI in get_random_uplink_items(U, U.uses, loc)) + UI.purchase_log(U) + var/obj/item/I = UI.get_goods(U, loc) + if(istype(I)) + bought_items += I + + return bought_items + +/datum/uplink_item/item/badassery/random_many/purchase_log(obj/item/device/uplink/U) + feedback_add_details("traitor_uplink_items_bought", "[src]") + log_and_message_admins("used \the [U.loc] to buy \a [src]") + +/**************** +* Surplus Crate * +****************/ +/datum/uplink_item/item/badassery/surplus + name = "Surplus Crate" + item_cost = 40 + var/item_worth = 60 + var/icon + +/datum/uplink_item/item/badassery/surplus/New() + ..() + desc = "A crate containing [item_worth] telecrystal\s worth of surplus leftovers." + +/datum/uplink_item/item/badassery/surplus/get_goods(var/obj/item/device/uplink/U, var/loc) + var/obj/structure/largecrate/C = new(loc) + var/random_items = get_random_uplink_items(null, item_worth, C) + for(var/datum/uplink_item/I in random_items) + I.purchase_log(U) + I.get_goods(U, C) + + return C + +/datum/uplink_item/item/badassery/surplus/log_icon() + if(!icon) + var/obj/structure/largecrate/C = /obj/structure/largecrate + icon = image(initial(C.icon), initial(C.icon_state)) + + return "\icon[icon]" \ No newline at end of file diff --git a/code/datums/uplink/grenades.dm b/code/datums/uplink/grenades.dm new file mode 100644 index 0000000000..f7c6d1a072 --- /dev/null +++ b/code/datums/uplink/grenades.dm @@ -0,0 +1,35 @@ +/*********** +* Grenades * +************/ +/datum/uplink_item/item/grenades + category = /datum/uplink_category/grenades + +/datum/uplink_item/item/grenades/anti_photon + name = "5xPhoton Disruption Grenades" + item_cost = 2 + path = /obj/item/weapon/storage/box/anti_photons + +/datum/uplink_item/item/grenades/emp + name = "5xEMP Grenades" + item_cost = 3 + path = /obj/item/weapon/storage/box/emps + +/datum/uplink_item/item/grenades/smoke + name = "7xSmoke Grenades" + item_cost = 2 + path = /obj/item/weapon/storage/box/smokes + +/datum/uplink_item/item/grenades/frags + name = "5xFrag Grenades" + item_cost = 6 + path = /obj/item/weapon/storage/box/frags + +/datum/uplink_item/item/grenades/flashbnags + name = "7xFlashbangs" + item_cost = 4 + path = /obj/item/weapon/storage/box/flashbangs + +/datum/uplink_item/item/grenades/metalfoam + name = "7xMetal Foam Grenades" + item_cost = 3 + path = /obj/item/weapon/storage/box/metalfoam \ No newline at end of file diff --git a/code/datums/uplink/hardsuit_modules.dm b/code/datums/uplink/hardsuit_modules.dm new file mode 100644 index 0000000000..66ecfb6bf9 --- /dev/null +++ b/code/datums/uplink/hardsuit_modules.dm @@ -0,0 +1,40 @@ +/******************* +* Hardsuit Modules * +*******************/ +/datum/uplink_item/item/hardsuit_modules + category = /datum/uplink_category/hardsuit_modules + +/datum/uplink_item/item/hardsuit_modules/thermal + name = "Thermal Scanner" + item_cost = 2 + path = /obj/item/rig_module/vision/thermal + +/datum/uplink_item/item/hardsuit_modules/energy_net + name = "Net Projector" + item_cost = 3 + path = /obj/item/rig_module/fabricator/energy_net + +/datum/uplink_item/item/ewar_voice + name = "Electrowarfare Suite and Voice Synthesiser" + item_cost = 4 + path = /obj/item/weapon/storage/box/syndie_kit/ewar_voice + +/datum/uplink_item/item/hardsuit_modules/maneuvering_jets + name = "Maneuvering Jets" + item_cost = 4 + path = /obj/item/rig_module/maneuvering_jets + +/datum/uplink_item/item/hardsuit_modules/egun + name = "Mounted Energy Gun" + item_cost = 6 + path = /obj/item/rig_module/mounted/egun + +/datum/uplink_item/item/hardsuit_modules/power_sink + name = "Power Sink" + item_cost = 6 + path = /obj/item/rig_module/power_sink + +/datum/uplink_item/item/hardsuit_modules/laser_canon + name = "Mounted Laser Cannon" + item_cost = 8 + path = /obj/item/rig_module/mounted diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm new file mode 100644 index 0000000000..c4302464b6 --- /dev/null +++ b/code/datums/uplink/implants.dm @@ -0,0 +1,25 @@ +/*********** +* Implants * +***********/ +/datum/uplink_item/item/implants + category = /datum/uplink_category/implants + +/datum/uplink_item/item/implants/imp_freedom + name = "Freedom Implant" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/imp_freedom + +/datum/uplink_item/item/implants/imp_compress + name = "Compressed Matter Implant" + item_cost = 4 + path = /obj/item/weapon/storage/box/syndie_kit/imp_compress + +/datum/uplink_item/item/implants/imp_explosive + name = "Explosive Implant (DANGER!)" + item_cost = 6 + path = /obj/item/weapon/storage/box/syndie_kit/imp_explosive + +/datum/uplink_item/item/implants/imp_uplink + name = "Uplink Implant" //Original name: "Uplink Implant (Contains 5 Telecrystals)" + item_cost = 5 //Original cost: 10 + path = /obj/item/weapon/storage/box/syndie_kit/imp_uplink diff --git a/code/datums/uplink/medical.dm b/code/datums/uplink/medical.dm new file mode 100644 index 0000000000..d14ca10a07 --- /dev/null +++ b/code/datums/uplink/medical.dm @@ -0,0 +1,36 @@ +/********** +* Medical * +**********/ +/datum/uplink_item/item/medical + category = /datum/uplink_category/medical + +/datum/uplink_item/item/medical/sinpockets + name = "Box of Sin-Pockets" + item_cost = 1 + path = /obj/item/weapon/storage/box/sinpockets + +/datum/uplink_item/item/medical/surgery + name = "Surgery kit" + item_cost = 6 + path = /obj/item/weapon/storage/firstaid/surgery + +/datum/uplink_item/item/medical/combat + name = "Combat medical kit" + item_cost = 6 + path = /obj/item/weapon/storage/firstaid/combat + +/datum/uplink_item/item/medical/freezer + name = "Portable Freezer" + item_cost = 2 + path = /obj/item/weapon/storage/box/freezer + +/datum/uplink_item/item/medical/ambrosiaseeds + name = "Box of 7x ambrosia seed packets" + item_cost = 1 + path = /obj/item/weapon/storage/box/ambrosia + +/datum/uplink_item/item/medical/ambrosiadeusseeds + name = "Box of 7x ambrosia deus seed packets" + item_cost = 2 + path = /obj/item/weapon/storage/box/ambrosiadeus + diff --git a/code/datums/uplink/stealth_items.dm b/code/datums/uplink/stealth_items.dm new file mode 100644 index 0000000000..31364a0953 --- /dev/null +++ b/code/datums/uplink/stealth_items.dm @@ -0,0 +1,45 @@ +/******************************* +* Stealth and Camouflage Items * +*******************************/ +/datum/uplink_item/item/stealth_items + category = /datum/uplink_category/stealth_items + +/datum/uplink_item/item/stealth_items/id + name = "Agent ID card" + item_cost = 2 + path = /obj/item/weapon/card/id/syndicate + +/datum/uplink_item/item/stealth_items/syndigaloshes + name = "No-Slip Shoes" + item_cost = 2 + path = /obj/item/clothing/shoes/syndigaloshes + +/datum/uplink_item/item/stealth_items/spy + name = "Bug Kit" + item_cost = 2 + path = /obj/item/weapon/storage/box/syndie_kit/spy + +/datum/uplink_item/item/stealth_items/chameleon_kit + name = "Chameleon Kit" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/chameleon + +/datum/uplink_item/item/stealth_items/chameleon_projector + name = "Chameleon-Projector" + item_cost = 4 + path = /obj/item/device/chameleon + +/datum/uplink_item/item/stealth_items/chameleon_projector + name = "Chameleon-Projector" + item_cost = 4 + path = /obj/item/device/chameleon + +/datum/uplink_item/item/stealth_items/voice + name = "Voice Changer" + item_cost = 4 + path = /obj/item/clothing/mask/gas/voice + +/datum/uplink_item/item/stealth_items/camera_floppy + name = "Camera Network Access - Floppy" + item_cost = 6 + path = /obj/item/weapon/disk/file/cameras/syndicate diff --git a/code/datums/uplink/stealthy_weapons.dm b/code/datums/uplink/stealthy_weapons.dm new file mode 100644 index 0000000000..ead34c5646 --- /dev/null +++ b/code/datums/uplink/stealthy_weapons.dm @@ -0,0 +1,35 @@ +/************************************* +* Stealthy and Inconspicuous Weapons * +*************************************/ +/datum/uplink_item/item/stealthy_weapons + category = /datum/uplink_category/stealthy_weapons + +/datum/uplink_item/item/stealthy_weapons/soap + name = "Subversive Soap" + item_cost = 1 + path = /obj/item/weapon/soap/syndie + +/datum/uplink_item/item/stealthy_weapons/concealed_cane + name = "Concealed Cane Sword" + item_cost = 1 + path = /obj/item/weapon/cane/concealed + +/datum/uplink_item/item/stealthy_weapons/detomatix + name = "Detomatix PDA Cartridge" + item_cost = 3 + path = /obj/item/weapon/cartridge/syndicate + +/datum/uplink_item/item/stealthy_weapons/parapen + name = "Paralysis Pen" + item_cost = 3 + path = /obj/item/weapon/pen/reagent/paralysis + +/datum/uplink_item/item/stealthy_weapons/cigarette_kit + name = "Cigarette Kit" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/cigarette + +/datum/uplink_item/item/stealthy_weapons/random_toxin + name = "Random Toxin - Beaker" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/toxin diff --git a/code/datums/uplink/tools.dm b/code/datums/uplink/tools.dm new file mode 100644 index 0000000000..fb1b52c068 --- /dev/null +++ b/code/datums/uplink/tools.dm @@ -0,0 +1,85 @@ +/******************** +* Devices and Tools * +********************/ +/datum/uplink_item/item/tools + category = /datum/uplink_category/tools + +/datum/uplink_item/item/tools/toolbox + name = "Fully Loaded Toolbox" + item_cost = 1 + path = /obj/item/weapon/storage/toolbox/syndicate + +/datum/uplink_item/item/tools/plastique + name = "C-4 (Destroys walls)" + item_cost = 2 + path = /obj/item/weapon/plastique + +/datum/uplink_item/item/tools/encryptionkey_radio + name = "Encrypted Radio Channel Key" + item_cost = 2 + path = /obj/item/device/encryptionkey/syndicate + +/datum/uplink_item/item/tools/encryptionkey_binary + name = "Binary Translator Key" + item_cost = 3 + path = /obj/item/device/encryptionkey/binary + +/datum/uplink_item/item/tools/emag + name = "Cryptographic Sequencer" + item_cost = 3 + path = /obj/item/weapon/card/emag + +/datum/uplink_item/item/tools/clerical + name = "Morphic Clerical Kit" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/clerical + +/datum/uplink_item/item/tools/space_suit + name = "Space Suit" + item_cost = 3 + path = /obj/item/weapon/storage/box/syndie_kit/space + +/datum/uplink_item/item/tools/thermal + name = "Thermal Imaging Glasses" + item_cost = 3 + path = /obj/item/clothing/glasses/thermal/syndi + +/datum/uplink_item/item/tools/powersink + name = "Powersink (DANGER!)" + item_cost = 5 + path = /obj/item/device/powersink + +/datum/uplink_item/item/tools/ai_module + name = "Hacked AI Upload Module" + item_cost = 7 + path = /obj/item/weapon/aiModule/syndicate + +/datum/uplink_item/item/tools/supply_beacon + name = "Hacked Supply Beacon (DANGER!)" + item_cost = 7 + path = /obj/item/supply_beacon + +/datum/uplink_item/item/tools/teleporter + name = "Teleporter Circuit Board" + item_cost = 20 + path = /obj/item/weapon/circuitboard/teleporter + +/datum/uplink_item/item/tools/money + name = "Operations Funding" + item_cost = 3 + path = /obj/item/weapon/storage/secure/briefcase/money + desc = "A briefcase with 10,000 untraceable thalers for funding your sneaky activities." + +/datum/uplink_item/item/tools/crystal + name = "Tradable Crystal" + item_cost = 1 + path = /obj/item/device/telecrystal + desc = "A telecrystal that can be transferred from one user to another. Be sure not to give it to just anyone." + +/datum/uplink_item/item/tools/hacking_tool + name = "Door Hacking Tool" + item_cost = 2 + path = /obj/item/device/multitool/hacktool + desc = "Appears and functions as a standard multitool until the mode is toggled by applying a screwdriver appropriately. \ + When in hacking mode this device will grant full access to any standard airlock within 20 to 40 seconds. \ + This device will also be able to immediately access the last 6 to 8 hacked airlocks." \ No newline at end of file diff --git a/code/game/objects/items/devices/uplink_categories.dm b/code/datums/uplink/uplink_categories.dm similarity index 87% rename from code/game/objects/items/devices/uplink_categories.dm rename to code/datums/uplink/uplink_categories.dm index 68ed72a6fb..6e222b764b 100644 --- a/code/game/objects/items/devices/uplink_categories.dm +++ b/code/datums/uplink/uplink_categories.dm @@ -1,49 +1,49 @@ -/datum/uplink_category - var/name = "" - var/list/datum/uplink_item/items - -/datum/uplink_category/New() - ..() - items = list() - -/datum/uplink_category/proc/can_view(obj/item/device/uplink/U) - for(var/datum/uplink_item/item in items) - if(item.can_view(U)) - return 1 - return 0 - -/datum/uplink_category/ammunition - name = "Ammunition" - -/datum/uplink_category/grenades - name = "Grenades and Thrown Objects" - -/datum/uplink_category/visible_weapons - name = "Highly Visible and Dangerous Weapons" - -/datum/uplink_category/stealthy_weapons - name = "Stealthy and Inconspicuous Weapons" - -/datum/uplink_category/stealth_items - name = "Stealth and Camouflage Items" - -/datum/uplink_category/armor - name = "Armor" - -/datum/uplink_category/tools - name = "Devices and Tools" - -/datum/uplink_category/implants - name = "Implants" - -/datum/uplink_category/medical - name = "Medical" - -/datum/uplink_category/hardsuit_modules - name = "Hardsuit Modules" - -/datum/uplink_category/services - name = "Services" - -/datum/uplink_category/badassery - name = "Badassery" +/datum/uplink_category + var/name = "" + var/list/datum/uplink_item/items + +/datum/uplink_category/New() + ..() + items = list() + +/datum/uplink_category/proc/can_view(obj/item/device/uplink/U) + for(var/datum/uplink_item/item in items) + if(item.can_view(U)) + return 1 + return 0 + +datum/uplink_category/ammunition + name = "Ammunition" + +/datum/uplink_category/services + name = "Services" + +/datum/uplink_category/armor + name = "Armor" + +/datum/uplink_category/badassery + name = "Badassery" + +/datum/uplink_category/grenades + name = "Grenades and Thrown Objects" + +/datum/uplink_category/hardsuit_modules + name = "Hardsuit Modules" + +/datum/uplink_category/implants + name = "Implants" + +/datum/uplink_category/medical + name = "Medical" + +/datum/uplink_category/stealth_items + name = "Stealth and Camouflage Items" + +/datum/uplink_category/stealthy_weapons + name = "Stealthy and Inconspicuous Weapons" + +/datum/uplink_category/tools + name = "Devices and Tools" + +/datum/uplink_category/visible_weapons + name = "Highly Visible and Dangerous Weapons" \ No newline at end of file diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm new file mode 100644 index 0000000000..32a7d0cffb --- /dev/null +++ b/code/datums/uplink/uplink_items.dm @@ -0,0 +1,174 @@ +var/datum/uplink/uplink = new() + +/datum/uplink + var/list/items_assoc + var/list/datum/uplink_item/items + var/list/datum/uplink_category/categories + +/datum/uplink/New() + items_assoc = list() + items = init_subtypes(/datum/uplink_item) + categories = init_subtypes(/datum/uplink_category) + categories = dd_sortedObjectList(categories) + + for(var/datum/uplink_item/item in items) + if(!item.name) + items -= item + continue + + items_assoc[item.type] = item + + for(var/datum/uplink_category/category in categories) + if(item.category == category.type) + category.items += item + + for(var/datum/uplink_category/category in categories) + category.items = dd_sortedObjectList(category.items) + +/datum/uplink_item + var/name + var/desc + var/item_cost = 0 + var/datum/uplink_category/category // Item category + var/list/datum/antagonist/antag_roles // Antag roles this item is displayed to. If empty, display to all. + +/datum/uplink_item/item + var/path = null + +/datum/uplink_item/New() + ..() + antag_roles = list() + + + +/datum/uplink_item/proc/buy(var/obj/item/device/uplink/U, var/mob/user) + var/extra_args = extra_args(user) + if(!extra_args) + return + + if(!can_buy(U)) + return + + if(U.CanUseTopic(user, inventory_state) != STATUS_INTERACTIVE) + return + + var/cost = cost(U.uses, U) + + var/goods = get_goods(U, get_turf(user), user, extra_args) + if(!goods) + return + + purchase_log(U) + user.mind.tcrystals -= cost + U.used_TC += cost + return goods + +// Any additional arguments you wish to send to the get_goods +/datum/uplink_item/proc/extra_args(var/mob/user) + return 1 + +/datum/uplink_item/proc/can_buy(obj/item/device/uplink/U) + if(cost(U.uses, U) > U.uses) + return 0 + + return can_view(U) + +/datum/uplink_item/proc/can_view(obj/item/device/uplink/U) + // Making the assumption that if no uplink was supplied, then we don't care about antag roles + if(!U || !antag_roles.len) + return 1 + + // With no owner, there's no need to check antag status. + if(!U.uplink_owner) + return 0 + + for(var/antag_role in antag_roles) + var/datum/antagonist/antag = all_antag_types[antag_role] + if(antag.is_antagonist(U.uplink_owner)) + return 1 + return 0 + +/datum/uplink_item/proc/cost(var/telecrystals, obj/item/device/uplink/U) + . = item_cost + if(U) + . = U.get_item_cost(src, .) + +/datum/uplink_item/proc/description() + return desc + +// get_goods does not necessarily return physical objects, it is simply a way to acquire the uplink item without paying +/datum/uplink_item/proc/get_goods(var/obj/item/device/uplink/U, var/loc) + return 0 + +/datum/uplink_item/proc/log_icon() + return + +/datum/uplink_item/proc/purchase_log(obj/item/device/uplink/U) + feedback_add_details("traitor_uplink_items_bought", "[src]") + log_and_message_admins("used \the [U.loc] to buy \a [src]") + U.purchase_log[src] = U.purchase_log[src] + 1 + +datum/uplink_item/dd_SortValue() + return cost(INFINITY) + +/******************************** +* * +* Physical Uplink Entries * +* * +********************************/ +/datum/uplink_item/item/buy(var/obj/item/device/uplink/U, var/mob/user) + var/obj/item/I = ..() + if(!I) + return + + if(istype(I, /list)) + var/list/L = I + if(L.len) I = L[1] + + if(istype(I) && ishuman(user)) + var/mob/living/carbon/human/A = user + A.put_in_any_hand_if_possible(I) + return I + +/datum/uplink_item/item/get_goods(var/obj/item/device/uplink/U, var/loc) + var/obj/item/I = new path(loc) + return I + +/datum/uplink_item/item/description() + if(!desc) + // Fallback description + var/obj/temp = src.path + desc = initial(temp.desc) + return ..() + +/datum/uplink_item/item/log_icon() + var/obj/I = path + return "\icon[I]" + +/******************************** +* * +* Abstract Uplink Entries * +* * +********************************/ +/datum/uplink_item/abstract + var/static/image/default_abstract_uplink_icon + +/datum/uplink_item/abstract/log_icon() + if(!default_abstract_uplink_icon) + default_abstract_uplink_icon = image('icons/obj/pda.dmi', "pda-syn") + + return "\icon[default_abstract_uplink_icon]" + +/**************** +* Support procs * +****************/ +/proc/get_random_uplink_items(var/obj/item/device/uplink/U, var/remaining_TC, var/loc) + var/list/bought_items = list() + while(remaining_TC) + var/datum/uplink_item/I = default_uplink_selection.get_random_item(remaining_TC, U, bought_items) + if(!I) + break + bought_items += I + remaining_TC -= I.cost(remaining_TC, U) + + return bought_items diff --git a/code/datums/uplink/visible_weapons.dm b/code/datums/uplink/visible_weapons.dm new file mode 100644 index 0000000000..c0e8d3aaca --- /dev/null +++ b/code/datums/uplink/visible_weapons.dm @@ -0,0 +1,106 @@ +/*************************************** +* Highly Visible and Dangerous Weapons * +***************************************/ +/datum/uplink_item/item/visible_weapons + category = /datum/uplink_category/visible_weapons + +/datum/uplink_item/item/visible_weapons/energy_sword + name = "Energy Sword" + item_cost = 4 + path = /obj/item/weapon/melee/energy/sword + +/datum/uplink_item/item/visible_weapons/dartgun + name = "Dart Gun" + item_cost = 5 + path = /obj/item/weapon/gun/projectile/dartgun + +/datum/uplink_item/item/visible_weapons/crossbow + name = "Energy Crossbow" + item_cost = 5 + path = /obj/item/weapon/gun/energy/crossbow + +/datum/uplink_item/item/visible_weapons/silenced_45 + name = "Silenced .45" + item_cost = 5 + path = /obj/item/weapon/gun/projectile/silenced + +/datum/uplink_item/item/visible_weapons/riggedlaser + name = "Exosuit Rigged Laser" + item_cost = 6 + path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser + +/datum/uplink_item/item/visible_weapons/revolver + name = "Revolver" + item_cost = 6 + path = /obj/item/weapon/gun/projectile/revolver + +/datum/uplink_item/item/visible_weapons/Derringer + name = ".357 Derringer Pistol" + item_cost = 5 + path = /obj/item/weapon/gun/projectile/derringer + +/datum/uplink_item/item/visible_weapons/heavysniper + name = "Anti-Materiel Rifle (14.5mm)" + item_cost = DEFAULT_TELECRYSTAL_AMOUNT + path = /obj/item/weapon/gun/projectile/heavysniper + +/datum/uplink_item/item/visible_weapons/tommygun + name = "Tommygun (.45)" // We're keeping this because it's CLASSY. -Spades + item_cost = 7 + path = /obj/item/weapon/gun/projectile/automatic/tommygun + +//These are for traitors (or other antags, perhaps) to have the option of purchasing some merc gear. +/datum/uplink_item/item/visible_weapons/submachinegun + name = "Submachine Gun (10mm)" + item_cost = 6 + path = /obj/item/weapon/gun/projectile/automatic/c20r + +/datum/uplink_item/item/visible_weapons/assaultrifle + name = "Assault Rifle (7.62mm)" + item_cost = 7 + path = /obj/item/weapon/gun/projectile/automatic/sts35 + +/datum/uplink_item/item/visible_weapons/bullpuprifle + name = "Assault Rifle (5.56mm)" + item_cost = 7 + path = /obj/item/weapon/gun/projectile/automatic/carbine + +/datum/uplink_item/item/visible_weapons/combatshotgun + name = "Combat Shotgun" + item_cost = 7 + path = /obj/item/weapon/gun/projectile/shotgun/pump/combat + +/datum/uplink_item/item/visible_weapons/egun + name = "Energy Gun" + item_cost = 5 + path = /obj/item/weapon/gun/energy/gun + +/datum/uplink_item/item/visible_weapons/lasercannon + name = "Laser Cannon" + item_cost = 6 + path = /obj/item/weapon/gun/energy/lasercannon + +/datum/uplink_item/item/visible_weapons/lasercarbine + name = "Laser Carbine" + item_cost = 7 + path = /obj/item/weapon/gun/energy/laser + +/datum/uplink_item/item/visible_weapons/ionrifle + name = "Ion Rifle" + item_cost = 5 + path = /obj/item/weapon/gun/energy/ionrifle + +/datum/uplink_item/item/visible_weapons/xray + name = "Xray Gun" + item_cost = 7 + path = /obj/item/weapon/gun/energy/xray + +/datum/uplink_item/item/visible_weapons/tactknife + name = "Tactical Knife" + item_cost = 1 + path = /obj/item/weapon/material/hatchet/tacknife + +/datum/uplink_item/item/visible_weapons/combatknife + name = "Combat Knife" + item_cost = 3 + path = /obj/item/weapon/material/hatchet/tacknife/combatknife \ No newline at end of file diff --git a/code/datums/vending/stored_item.dm b/code/datums/vending/stored_item.dm new file mode 100644 index 0000000000..4fed107d77 --- /dev/null +++ b/code/datums/vending/stored_item.dm @@ -0,0 +1,58 @@ +/* +* Datum that holds the instances and information about the items stored. Currently used in SmartFridges and Vending Machines. +*/ +/datum/stored_item + var/item_name = "name" //Name of the item(s) displayed + var/item_path = null + var/amount = 0 + var/list/instances //What items are actually stored + var/stored //The thing holding it is + +/datum/stored_item/New(var/stored, var/path, var/name = null, var/amount = 0) + src.item_path = path + + if(!name) + var/atom/tmp = path + src.item_name = initial(tmp.name) + else + src.item_name = name + + src.amount = amount + src.stored = stored + + ..() + +/datum/stored_item/Destroy() + stored = null + if(instances) + for(var/product in instances) + qdel(product) + instances.Cut() + . = ..() + +/datum/stored_item/proc/get_amount() + return instances ? instances.len : amount + +/datum/stored_item/proc/get_product(var/product_location) + if(!get_amount() || !product_location) + return + init_products() + + var/atom/movable/product = instances[instances.len] // Remove the last added product + instances -= product + product.forceMove(product_location) + +/datum/stored_item/proc/add_product(var/atom/movable/product) + if(product.type != item_path) + return 0 + init_products() + product.forceMove(stored) + instances += product + +/datum/stored_item/proc/init_products() + if(instances) + return + instances = list() + for(var/i = 1 to amount) + var/new_product = new item_path(stored) + instances += new_product \ No newline at end of file diff --git a/code/datums/vending/vending.dm b/code/datums/vending/vending.dm new file mode 100644 index 0000000000..329c8c1959 --- /dev/null +++ b/code/datums/vending/vending.dm @@ -0,0 +1,13 @@ +/** + * Datum used to hold further information about a product in a vending machine + */ +/datum/stored_item/vending_product + var/price = 0 // Price to buy one + var/display_color = null // Display color for vending machine listing + var/category = CAT_NORMAL // CAT_HIDDEN for contraband, CAT_COIN for premium + +/datum/stored_item/vending_product/New(var/stored, var/path, var/name = null, var/amount = 1, var/price = 0, var/color = null, var/category = CAT_NORMAL) + ..(stored, path, name, amount) + src.price = price + src.display_color = color + src.category = category \ No newline at end of file diff --git a/code/datums/wires/alarm.dm b/code/datums/wires/alarm.dm index c34b0291fb..ace1ba9ec3 100644 --- a/code/datums/wires/alarm.dm +++ b/code/datums/wires/alarm.dm @@ -11,7 +11,7 @@ var/const/AALARM_WIRE_AALARM = 16 /datum/wires/alarm/CanUse(var/mob/living/L) var/obj/machinery/alarm/A = holder - if(A.wiresexposed && A.buildstage == 2) + if(A.wiresexposed) return 1 return 0 diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 602008ccd7..3300da0ceb 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -62,9 +62,8 @@ using /datum/datacore/proc/manifest_inject( ), or manifest_insert( ) */ var/global/list/PDA_Manifest = list() -var/global/ManifestJSON -/datum/datacore/proc/get_manifest_json() +/datum/datacore/proc/get_manifest_list() if(PDA_Manifest.len) return var/heads[0] @@ -114,7 +113,7 @@ var/global/ManifestJSON department = 1 if(depthead && sci.len != 1) sci.Swap(1,sci.len) - + if(real_rank in cargo_positions) car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive) department = 1 @@ -146,7 +145,6 @@ var/global/ManifestJSON "bot" = bot,\ "misc" = misc\ ) - ManifestJSON = list2json(PDA_Manifest) return diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 83033257e3..77779bafcf 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -44,6 +44,7 @@ /obj/item/weapon/soap/deluxe/New() desc = "A deluxe Waffle Co. brand bar of soap. Smells of [pick("lavender", "vanilla", "strawberry", "chocolate" ,"space")]." + ..() /obj/item/weapon/soap/syndie desc = "An untrustworthy bar of soap. Smells of fear." @@ -129,6 +130,13 @@ icon_state = "nullrod" item_state = "foldcane" +/obj/item/weapon/cane/whitecane + name = "white cane" + desc = "A cane used by the blind." + icon = 'icons/obj/weapons.dmi' + icon_state = "whitecane" + item_state = "whitecane" + /obj/item/weapon/disk name = "disk" icon = 'icons/obj/items.dmi' @@ -269,21 +277,6 @@ throw_range = 5 w_class = 2.0 -/obj/item/weapon/wire - desc = "This is just a simple piece of regular insulated wire." - name = "wire" - icon = 'icons/obj/power.dmi' - icon_state = "item_wire" - var/amount = 1.0 - var/laying = 0.0 - var/old_lay = null - matter = list(DEFAULT_WALL_MATERIAL = 40) - attack_verb = list("whipped", "lashed", "disciplined", "tickled") - - suicide_act(mob/user) - viewers(user) << "[user] is strangling \himself with \the [src]! It looks like \he's trying to commit suicide." - return (OXYLOSS) - /obj/item/weapon/module icon = 'icons/obj/module.dmi' icon_state = "std_module" @@ -406,9 +399,11 @@ icon = 'icons/obj/stock_parts.dmi' w_class = 2.0 var/rating = 1 - New() - src.pixel_x = rand(-5.0, 5) - src.pixel_y = rand(-5.0, 5) + +/obj/item/weapon/stock_parts/New() + src.pixel_x = rand(-5.0, 5) + src.pixel_y = rand(-5.0, 5) + ..() //Rank 1 @@ -599,3 +594,29 @@ icon = 'icons/obj/stock_parts.dmi' icon_state = "smes_coil" origin_tech = list(TECH_MATERIAL = 19, TECH_ENGINEERING = 19, TECH_PHORON = 19, TECH_POWER = 19, TECH_BLUESPACE = 19, TECH_BIO = 19, TECH_COMBAT = 19, TECH_MAGNET = 19, TECH_DATA = 19, TECH_ILLEGAL = 19, TECH_ARCANE = 19) + +// Additional construction stock parts + +/obj/item/weapon/stock_parts/gear + name = "gear" + desc = "A gear used for construction." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "gear" + origin_tech = list(TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 50) + +/obj/item/weapon/stock_parts/motor + name = "motor" + desc = "A motor used for construction." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "motor" + origin_tech = list(TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 60, "glass" = 10) + +/obj/item/weapon/stock_parts/spring + name = "spring" + desc = "A spring used for construction." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "spring" + origin_tech = list(TECH_ENGINEERING = 1) + matter = list(DEFAULT_WALL_MATERIAL = 40) \ No newline at end of file diff --git a/code/defines/procs/hud.dm b/code/defines/procs/hud.dm index e5560e5ce0..78fdb6dc7b 100644 --- a/code/defines/procs/hud.dm +++ b/code/defines/procs/hud.dm @@ -72,7 +72,7 @@ mob/proc/handle_regular_hud_updates() //Used in the life.dm of mobs that can use mob/proc/in_view(var/turf/T) return view(T) -/mob/eye/in_view(var/turf/T) +/mob/observer/eye/in_view(var/turf/T) var/list/viewed = new for(var/mob/living/carbon/human/H in mob_list) if(get_dist(H, T) <= 7) diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm index 783055381c..7483fb508b 100644 --- a/code/game/antagonist/alien/borer.dm +++ b/code/game/antagonist/alien/borer.dm @@ -46,7 +46,7 @@ var/datum/antagonist/borer/borers for(var/mob/living/carbon/human/H in mob_list) if(H.stat != DEAD && !H.has_brain_worms()) var/obj/item/organ/external/head = H.get_organ(BP_HEAD) - if(head && !(head.status & ORGAN_ROBOT)) + if(head && !(head.robotic >= ORGAN_ROBOT)) host = H break if(istype(host)) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index 6d3e7d0b28..d91242ea8b 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -64,10 +64,18 @@ var/list/candidates = list() // Potential candidates. var/list/faction_members = list() // Semi-antags (in-round revs, borer thralls) + var/allow_latejoin = 0 //Determines whether or not the game mode will allow for the template to spawn try_latespawn + // ID card stuff. var/default_access = list() var/id_type = /obj/item/weapon/card/id + var/antag_text = "You are an antagonist! Within the rules, \ + try to act as an opposing force to the crew. Further RP and try to make sure \ + other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to antagonists." /datum/antagonist/New() ..() @@ -92,7 +100,7 @@ // Prune restricted status. Broke it up for readability. // Note that this is done before jobs are handed out. for(var/datum/mind/player in ticker.mode.get_players_for_role(role_type, id)) - if(ghosts_only && !istype(player.current, /mob/dead)) + if(ghosts_only && !istype(player.current, /mob/observer/dead)) log_debug("[key_name(player)] is not eligible to become a [role_text]: Only ghosts may join as this role!") else if(player.special_role) log_debug("[key_name(player)] is not eligible to become a [role_text]: They already have a special role ([player.special_role])!") @@ -124,7 +132,7 @@ return 0 player.current << "You have been selected this round as an antagonist!" message_admins("[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].") - if(istype(player.current, /mob/dead)) + if(istype(player.current, /mob/observer/dead)) create_default(player.current) else add_antagonist(player,0,0,0,1,1) diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm index 1598aacfe8..e42888737f 100644 --- a/code/game/antagonist/antagonist_add.dm +++ b/code/game/antagonist/antagonist_add.dm @@ -8,7 +8,7 @@ player.assigned_role = role_text player.special_role = role_text - if(istype(player.current, /mob/dead)) + if(istype(player.current, /mob/observer/dead)) create_default(player.current) else create_antagonist(player, move_to_spawn, do_not_announce, preserve_appearance) @@ -30,6 +30,12 @@ if(faction_verb && player.current) player.current.verbs |= faction_verb + spawn(1 SECOND) //Added a delay so that this should pop up at the bottom and not the top of the text flood the new antag gets. + player.current << "Once you decide on a goal to pursue, you can optionally display it to \ + everyone at the end of the shift with the Set Ambition verb, located in the IC tab. You can change this at any time, \ + and it otherwise has no bearing on your round." + player.current.verbs |= /mob/living/proc/write_ambition + // Handle only adding a mind and not bothering with gear etc. if(nonstandard_role_type) faction_members |= player @@ -50,5 +56,8 @@ player.special_role = null update_icons_removed(player) BITSET(player.current.hud_updateflag, SPECIALROLE_HUD) + if(!is_special_character(player)) + player.current.verbs -= /mob/living/proc/write_ambition + player.ambitions = "" return 1 return 0 \ No newline at end of file diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 072dd88bee..733ec3eda0 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -76,7 +76,7 @@ P.info = "The nuclear authorization code is: [code]" P.name = "nuclear bomb code" if(leader && leader.current) - if(get_turf(P) == get_turf(leader.current) && !(leader.current.l_hand && leader.current.r_hand)) + if(get_turf(P) == get_turf(leader.current)) leader.current.put_in_hands(P) if(!code_owner && leader) @@ -99,17 +99,14 @@ player.current << "[leader_welcome_text]" else player.current << "[welcome_text]" + if (config.objectives_disabled) + player.current << "[antag_text]" if((flags & ANTAG_HAS_NUKE) && !spawned_nuke) create_nuke() - show_objectives(player) - - // Clown clumsiness check, I guess downstream might use it. - if (player.current.mind) - if (player.current.mind.assigned_role == "Clown") - player.current << "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself." - player.current.mutations.Remove(CLUMSY) + if (!config.objectives_disabled) + show_objectives(player) return 1 /datum/antagonist/proc/set_antag_name(var/mob/living/player) diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index 056fbd1865..0cc28d5ad2 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -33,6 +33,8 @@ return (flags & ANTAG_VOTABLE) /datum/antagonist/proc/can_late_spawn() + if(!(allow_latejoin)) + return 0 update_current_antag_max() if(get_antag_count() >= cur_max) return 0 diff --git a/code/game/antagonist/antagonist_objectives.dm b/code/game/antagonist/antagonist_objectives.dm index f9b3f8116b..5dc6c5f327 100644 --- a/code/game/antagonist/antagonist_objectives.dm +++ b/code/game/antagonist/antagonist_objectives.dm @@ -30,3 +30,26 @@ world << "[loss_text]" if(loss_feedback_tag) feedback_set_details("round_end_result","[loss_feedback_tag]") +/mob/living/proc/write_ambition() + set name = "Set Ambition" + set category = "IC" + set src = usr + + if(!mind) + return + if(!is_special_character(mind)) + src << "While you may perhaps have goals, this verb's meant to only be visible \ + to antagonists. Please make a bug report!" + return + var/new_ambitions = input(src, "Write a short sentence of what your character hopes to accomplish \ + today as an antagonist. Remember that this is purely optional. It will be shown at the end of the \ + round for everybody else.", "Ambitions", mind.ambitions) as null|message + if(isnull(new_ambitions)) + return + new_ambitions = sanitize(new_ambitions) + mind.ambitions = new_ambitions + if(new_ambitions) + src << "You've set your goal to be '[new_ambitions]'." + else + src << "You leave your ambitions behind." + log_and_message_admins("has set their ambitions to now be: [new_ambitions].") diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm index ea107824d5..d862239a9f 100644 --- a/code/game/antagonist/antagonist_print.dm +++ b/code/game/antagonist/antagonist_print.dm @@ -7,6 +7,9 @@ for(var/datum/mind/P in current_antagonists) text += print_player_full(P) text += get_special_objective_text(P) + if(P.ambitions) + text += "
Their goals for today were..." + text += "
[P.ambitions]" if(!global_objectives.len && P.objectives && P.objectives.len) var/failed var/num = 1 diff --git a/code/game/antagonist/outsider/commando.dm b/code/game/antagonist/outsider/commando.dm index 135a586b2e..d7acf05273 100644 --- a/code/game/antagonist/outsider/commando.dm +++ b/code/game/antagonist/outsider/commando.dm @@ -27,7 +27,7 @@ var/datum/antagonist/deathsquad/mercenary/commandos player.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(player), slot_glasses) player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/syndicate(player), slot_wear_mask) player.equip_to_slot_or_del(new /obj/item/weapon/storage/box(player), slot_in_backpack) - player.equip_to_slot_or_del(new /obj/item/ammo_magazine/c45(player), slot_in_backpack) + player.equip_to_slot_or_del(new /obj/item/ammo_magazine/clip/c45(player), slot_in_backpack) player.equip_to_slot_or_del(new /obj/item/weapon/rig/merc(player), slot_back) player.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(player), slot_r_hand) diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm index 4cc8afff6c..1234bdb1f6 100644 --- a/code/game/antagonist/outsider/deathsquad.dm +++ b/code/game/antagonist/outsider/deathsquad.dm @@ -49,7 +49,7 @@ var/datum/antagonist/deathsquad/deathsquad player.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(player), slot_r_hand) player.equip_to_slot_or_del(new /obj/item/weapon/rig/ert/assetprotection(player), slot_back) player.equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(player), slot_s_store) - player.implant_loyalty(player) + player.implant_loyalty() var/obj/item/weapon/card/id/id = create_id("Asset Protection", player) if(id) @@ -70,7 +70,7 @@ var/datum/antagonist/deathsquad/deathsquad var/syndicate_commando_name = pick(last_names) var/datum/preferences/A = new() //Randomize appearance for the commando. - A.randomize_appearance_for(player.current) + A.randomize_appearance_and_body_for(player.current) player.name = "[syndicate_commando_rank] [syndicate_commando_name]" player.current.name = player.name diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm index 98a44442dc..29ea3d27c1 100644 --- a/code/game/antagonist/outsider/ert.dm +++ b/code/game/antagonist/outsider/ert.dm @@ -7,6 +7,12 @@ var/datum/antagonist/ert/ert role_text = "Emergency Responder" role_text_plural = "Emergency Responders" welcome_text = "As member of the Emergency Response Team, you answer only to your leader and company officials." + antag_text = "You are an anti antagonist! Within the rules, \ + try to save the station and its inhabitants from the ongoing crisis. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to the ERT." leader_welcome_text = "As leader of the Emergency Response Team, you answer only to the Company, and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." landmark_id = "Response Team" id_type = /obj/item/weapon/card/id/centcom/ERT @@ -41,6 +47,6 @@ var/datum/antagonist/ert/ert player.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes) player.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(src), slot_gloves) player.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses) - + create_id(role_text, player) return 1 diff --git a/code/game/antagonist/outsider/mercenary.dm b/code/game/antagonist/outsider/mercenary.dm index 4c071130ad..c27d510d8b 100644 --- a/code/game/antagonist/outsider/mercenary.dm +++ b/code/game/antagonist/outsider/mercenary.dm @@ -39,16 +39,15 @@ var/datum/antagonist/mercenary/mercs player.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(player), slot_shoes) player.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(player), slot_gloves) if(player.backbag == 2) player.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(player), slot_back) - if(player.backbag == 3) player.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(player), slot_back) + if(player.backbag == 3) player.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(player), slot_back) if(player.backbag == 4) player.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(player), slot_back) player.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(player.back), slot_in_backpack) player.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(player), slot_in_backpack) player.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT player.mind.accept_tcrystals = 1 - if (player.mind == leader) - var/obj/item/device/radio/uplink/U = new(player.loc, player.mind, DEFAULT_TELECRYSTAL_AMOUNT) - player.put_in_hands(U) + var/obj/item/device/radio/uplink/U = new(player.loc, player.mind, DEFAULT_TELECRYSTAL_AMOUNT) + player.put_in_hands(U) player.update_icons() diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm index bcc89a0295..b420b3d59e 100644 --- a/code/game/antagonist/outsider/raider.dm +++ b/code/game/antagonist/outsider/raider.dm @@ -27,7 +27,7 @@ var/datum/antagonist/raider/raiders /obj/item/clothing/under/serviceoveralls, /obj/item/clothing/under/captain_fly, /obj/item/clothing/under/det, - /obj/item/clothing/under/brown, + /obj/item/clothing/under/color/brown, ) var/list/raider_shoes = list( @@ -80,16 +80,22 @@ var/datum/antagonist/raider/raiders /obj/item/weapon/gun/projectile/automatic/c20r, /obj/item/weapon/gun/projectile/automatic/wt550, /obj/item/weapon/gun/projectile/automatic/sts35, + /obj/item/weapon/gun/projectile/automatic/carbine, + /obj/item/weapon/gun/projectile/automatic/tommygun, /obj/item/weapon/gun/projectile/silenced, /obj/item/weapon/gun/projectile/shotgun/pump, /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/projectile/shotgun/pump/rifle/mosin, /obj/item/weapon/gun/projectile/shotgun/doublebarrel, /obj/item/weapon/gun/projectile/shotgun/doublebarrel/pellet, /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn, /obj/item/weapon/gun/projectile/colt/detective, /obj/item/weapon/gun/projectile/pistol, /obj/item/weapon/gun/projectile/revolver, - /obj/item/weapon/gun/projectile/pirate + /obj/item/weapon/gun/projectile/pirate, + /obj/item/weapon/gun/projectile/revolver/judge, + list(/obj/item/weapon/gun/projectile/luger,/obj/item/weapon/gun/projectile/luger/brown), + list(/obj/item/weapon/gun/projectile/deagle, /obj/item/weapon/gun/projectile/deagle/gold, /obj/item/weapon/gun/projectile/deagle/camo) ) var/list/raider_holster = list( @@ -207,7 +213,7 @@ var/datum/antagonist/raider/raiders player.equip_to_slot_or_del(new new_shoes(player),slot_shoes) if(!player.shoes) //If equipping shoes failed, fall back to equipping sandals - var/fallback_type = pick(/obj/item/clothing/shoes/sandal, /obj/item/clothing/shoes/jackboots/unathi) + var/fallback_type = pick(/obj/item/clothing/shoes/sandal, /obj/item/clothing/shoes/jackboots/toeless) player.equip_to_slot_or_del(new fallback_type(player), slot_shoes) player.equip_to_slot_or_del(new new_uniform(player),slot_w_uniform) diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm index f6741cafa0..14e5f90063 100644 --- a/code/game/antagonist/outsider/wizard.dm +++ b/code/game/antagonist/outsider/wizard.dm @@ -76,12 +76,12 @@ var/datum/antagonist/wizard/wizards return 0 wizard_mob.equip_to_slot_or_del(new /obj/item/device/radio/headset(wizard_mob), slot_l_ear) - wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/under/lightpurple(wizard_mob), slot_w_uniform) + wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(wizard_mob), slot_w_uniform) wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(wizard_mob), slot_shoes) wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(wizard_mob), slot_wear_suit) wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(wizard_mob), slot_head) if(wizard_mob.backbag == 2) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(wizard_mob), slot_back) - if(wizard_mob.backbag == 3) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(wizard_mob), slot_back) + if(wizard_mob.backbag == 3) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(wizard_mob), slot_back) if(wizard_mob.backbag == 4) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(wizard_mob), slot_back) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box(wizard_mob), slot_in_backpack) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/teleportation_scroll(wizard_mob), slot_r_store) @@ -98,7 +98,7 @@ var/datum/antagonist/wizard/wizards break if(!survivor) feedback_set_details("round_end_result","loss - wizard killed") - world << "The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!" + world << "The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew!" //To batch-remove wizard spells. Linked to mind.dm. /mob/proc/spellremove() diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm index dad7ed81a2..044e968f49 100644 --- a/code/game/antagonist/station/changeling.dm +++ b/code/game/antagonist/station/changeling.dm @@ -73,4 +73,14 @@ if(player.current.client.prefs.organ_data["torso"] == "cyborg") // Full synthetic. return 0 return 1 - return 0 \ No newline at end of file + return 0 + +/datum/antagonist/changeling/print_player_full(var/datum/mind/ply) + var/text = print_player_lite(ply) + + if(ply.changeling) + var/datum/changeling/ling_datum = ply.changeling + text += " (had [ling_datum.max_geneticpoints] genomes)" + text += "
Bought [english_list(ling_datum.purchased_powers_history)]." + + return text diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm index aba2115d15..6bb049dcb0 100644 --- a/code/game/antagonist/station/cultist.dm +++ b/code/game/antagonist/station/cultist.dm @@ -110,6 +110,13 @@ var/datum/antagonist/cultist/cult . = ..() if(.) player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." + if(player.current && !istype(player.current, /mob/living/simple_animal/construct)) + player.current.add_language(LANGUAGE_CULT) + +/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + . = ..() + if(. && player.current && !istype(player.current, /mob/living/simple_animal/construct)) + player.current.remove_language(LANGUAGE_CULT) /datum/antagonist/cultist/can_become_antag(var/datum/mind/player) if(!..()) diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm index cd9dd9b83b..1e6913a374 100644 --- a/code/game/antagonist/station/renegade.dm +++ b/code/game/antagonist/station/renegade.dm @@ -1,33 +1,61 @@ var/datum/antagonist/renegade/renegades /datum/antagonist/renegade + id = MODE_RENEGADE + role_type = BE_RENEGADE role_text = "Renegade" role_text_plural = "Renegades" - welcome_text = "Your own safety matters above all else, trust no one and kill anyone who gets in your way. However, armed as you are, now would be the perfect time to settle that score or grab that pair of yellow gloves you've been eyeing..." - id = MODE_RENEGADE + bantype = "renegade" + restricted_jobs = list("AI", "Cyborg") + welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive." + antag_text = "You are a minor antagonist! Within the rules, \ + try to protect yourself and what's important to you. You aren't here to cause trouble, \ + you're just more willing (and equipped) to go to extremes to stop it than others are. \ + Your job is to somewhat oppose the other antagonists, should they threaten you, in ways that aren't quite legal themselves. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to antagonists." flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE - hard_cap = 5 - hard_cap_round = 7 hard_cap = 8 hard_cap_round = 12 - initial_spawn_req = 3 - initial_spawn_target = 6 + initial_spawn_req = 2 + initial_spawn_target = 4 var/list/spawn_guns = list( - /obj/item/weapon/gun/energy/gun, /obj/item/weapon/gun/energy/laser, - /obj/item/weapon/gun/projectile, - /obj/item/weapon/gun/projectile/revolver/detective, - /obj/item/weapon/gun/projectile/automatic/c20r, - /obj/item/weapon/gun/projectile/deagle/camo, - /obj/item/weapon/gun/projectile/pistol, - /obj/item/weapon/silencer, - /obj/item/weapon/gun/projectile/shotgun/pump, - /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/energy/captain, + /obj/item/weapon/gun/energy/lasercannon, + /obj/item/weapon/gun/energy/xray, + /obj/item/weapon/gun/energy/gun, + /obj/item/weapon/gun/energy/gun/burst, + /obj/item/weapon/gun/energy/gun/nuclear, + /obj/item/weapon/gun/energy/crossbow, + /obj/item/weapon/gun/energy/crossbow/largecrossbow, /obj/item/weapon/gun/projectile/automatic, /obj/item/weapon/gun/projectile/automatic/mini_uzi, - /obj/item/weapon/gun/energy/crossbow + /obj/item/weapon/gun/projectile/automatic/c20r, + /obj/item/weapon/gun/projectile/automatic/sts35, + /obj/item/weapon/gun/projectile/automatic/carbine, + /obj/item/weapon/gun/projectile/automatic/wt550, + /obj/item/weapon/gun/projectile/automatic/z8, + /obj/item/weapon/gun/projectile/automatic/tommygun, + /obj/item/weapon/gun/projectile/colt/detective, + /obj/item/weapon/gun/projectile/sec/wood, + /obj/item/weapon/gun/projectile/silenced, + /obj/item/weapon/gun/projectile/pistol, + /obj/item/weapon/gun/projectile/revolver, + /obj/item/weapon/gun/projectile/derringer, + /obj/item/weapon/gun/projectile/shotgun/pump, + /obj/item/weapon/gun/projectile/shotgun/pump/rifle/mosin, + /obj/item/weapon/gun/projectile/shotgun/pump/combat, + /obj/item/weapon/gun/projectile/shotgun/doublebarrel, + /obj/item/weapon/gun/projectile/revolver/judge, + list(/obj/item/weapon/gun/projectile/shotgun/doublebarrel/pellet, /obj/item/weapon/gun/projectile/shotgun/doublebarrel/sawn), + list(/obj/item/weapon/gun/projectile/deagle, /obj/item/weapon/gun/projectile/deagle/gold, /obj/item/weapon/gun/projectile/deagle/camo), + list(/obj/item/weapon/gun/projectile/revolver/detective, /obj/item/weapon/gun/projectile/revolver/deckard), + list(/obj/item/weapon/gun/projectile/luger,/obj/item/weapon/gun/projectile/luger/brown) ) /datum/antagonist/renegade/New() @@ -49,9 +77,20 @@ var/datum/antagonist/renegade/renegades return var/gun_type = pick(spawn_guns) + if(islist(gun_type)) + gun_type = pick(gun_type) var/obj/item/gun = new gun_type(get_turf(player)) - if(!(player.l_hand && player.r_hand)) - player.put_in_hands(gun) + + // Attempt to put into a container. + if(player.equip_to_storage(gun)) + return + + // If that failed, attempt to put into any valid non-handslot + if(player.equip_to_appropriate_slot(gun)) + return + + // If that failed, then finally attempt to at least let the player carry the weapon + player.put_in_hands(gun) /proc/rightandwrong() diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm index dcc7fa9df9..acc0bd3d8d 100644 --- a/code/game/antagonist/station/traitor.dm +++ b/code/game/antagonist/station/traitor.dm @@ -5,6 +5,10 @@ var/datum/antagonist/traitor/traitors id = MODE_TRAITOR protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Captain") flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + +/datum/antagonist/traitor/auto + id = MODE_AUTOTRAITOR + allow_latejoin = 1 /datum/antagonist/traitor/New() ..() diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 8ab1944f5e..bba83cd42a 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -77,7 +77,7 @@ var/list/ghostteleportlocs = list() /hook/startup/proc/setupGhostTeleportLocs() for(var/area/AR in world) if(ghostteleportlocs.Find(AR.name)) continue - if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom)) + if(istype(AR, /area/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom)) ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR var/turf/picked = pick(get_area_turfs(AR.type)) @@ -122,8 +122,6 @@ area/space/atmosalert() /area/space/partyalert() return -/area/turret_protected/ - /area/arrival requires_power = 0 @@ -840,6 +838,10 @@ area/space/atmosalert() /area/maintenance/engineering name = "Engineering Maintenance" icon_state = "maint_engineering" + +/area/maintenance/engineering/pumpstation + name = "Engineering Pump Station" + icon_state = "maint_pumpstation" /area/maintenance/evahallway name = "\improper EVA Maintenance" @@ -2422,65 +2424,65 @@ area/space/atmosalert() name = "Emergency Storage" icon_state = "storage" -/area/turret_protected/ai_upload +/area/ai_upload name = "\improper AI Upload Chamber" icon_state = "ai_upload" ambience = list('sound/ambience/ambimalf.ogg') -/area/turret_protected/ai_upload_foyer +/area/ai_upload_foyer name = "AI Upload Access" icon_state = "ai_foyer" ambience = list('sound/ambience/ambimalf.ogg') sound_env = SMALL_ENCLOSED -/area/turret_protected/ai_server_room +/area/ai_server_room name = "Messaging Server Room" icon_state = "ai_server" sound_env = SMALL_ENCLOSED -/area/turret_protected/ai +/area/ai name = "\improper AI Chamber" icon_state = "ai_chamber" ambience = list('sound/ambience/ambimalf.ogg') -/area/turret_protected/ai_cyborg_station +/area/ai_cyborg_station name = "\improper Cyborg Station" icon_state = "ai_cyborg" sound_env = SMALL_ENCLOSED -/area/turret_protected/aisat +/area/aisat name = "\improper AI Satellite" icon_state = "ai" -/area/turret_protected/aisat_interior +/area/aisat_interior name = "\improper AI Satellite" icon_state = "ai" -/area/turret_protected/AIsatextFP +/area/AIsatextFP name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 lighting_use_dynamic = 0 -/area/turret_protected/AIsatextFS +/area/AIsatextFS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 lighting_use_dynamic = 0 -/area/turret_protected/AIsatextAS +/area/AIsatextAS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 lighting_use_dynamic = 0 -/area/turret_protected/AIsatextAP +/area/AIsatextAP name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 lighting_use_dynamic = 0 -/area/turret_protected/NewAIMain +/area/NewAIMain name = "\improper AI Main New" icon_state = "storage" @@ -2524,22 +2526,22 @@ area/space/atmosalert() name = "\improper Telecoms Central Compartment" icon_state = "tcomsatcham" -/area/turret_protected/tcomsat +/area/tcomsat name = "\improper Telecoms Satellite" icon_state = "tcomsatlob" ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg') -/area/turret_protected/tcomfoyer +/area/tcomfoyer name = "\improper Telecoms Foyer" icon_state = "tcomsatentrance" ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg') -/area/turret_protected/tcomwest +/area/tcomwest name = "\improper Telecommunications Satellite West Wing" icon_state = "tcomsatwest" ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg') -/area/turret_protected/tcomeast +/area/tcomeast name = "\improper Telecommunications Satellite East Wing" icon_state = "tcomsateast" ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg') @@ -2759,12 +2761,12 @@ var/list/the_station_areas = list ( /area/rnd, /area/storage, /area/construction, - /area/ai_monitored/storage/eva, //do not try to simplify to "/area/ai_monitored" --rastaf0 + /area/ai_monitored/storage/eva, /area/ai_monitored/storage/secure, - /area/ai_monitored/storage/emergency, - /area/turret_protected/ai_upload, //do not try to simplify to "/area/turret_protected" --rastaf0 - /area/turret_protected/ai_upload_foyer, - /area/turret_protected/ai, + /area/ai_monitored/storage/emergency, + /area/ai_upload, + /area/ai_upload_foyer, + /area/ai ) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 07b3dcacc5..e118e6fa4d 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -243,7 +243,7 @@ var/list/mob/living/forced_ambiance_list = new /area/proc/play_ambience(var/mob/living/L) // Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch - if(!(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return + if(!(L && L.is_preference_enabled(/datum/client_preference/play_ambiance))) return // If we previously were in an area with force-played ambiance, stop it. if(L in forced_ambiance_list) @@ -284,20 +284,22 @@ var/list/mob/living/forced_ambiance_list = new return if(H.m_intent == "run") - H.AdjustStunned(2) - H.AdjustWeakened(2) + H.AdjustStunned(6) + H.AdjustWeakened(6) else - H.AdjustStunned(1) - H.AdjustWeakened(1) + H.AdjustStunned(3) + H.AdjustWeakened(3) mob << "The sudden appearance of gravity makes you fall to the floor!" /area/proc/prison_break() - for(var/obj/machinery/power/apc/temp_apc in src) - temp_apc.overload_lighting(70) - for(var/obj/machinery/door/airlock/temp_airlock in src) - temp_airlock.prison_open() - for(var/obj/machinery/door/window/temp_windoor in src) - temp_windoor.open() + var/obj/machinery/power/apc/theAPC = get_apc() + if(theAPC.operating) + for(var/obj/machinery/power/apc/temp_apc in src) + temp_apc.overload_lighting(70) + for(var/obj/machinery/door/airlock/temp_airlock in src) + temp_airlock.prison_open() + for(var/obj/machinery/door/window/temp_windoor in src) + temp_windoor.open() /area/proc/has_gravity() return has_gravity diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7639084918..e45be4bb6a 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -46,7 +46,8 @@ pulledby = null /atom/movable/proc/initialize() - return + if(!isnull(gcDestroyed)) + crash_with("GC: -- [type] had initialize() called after qdel() --") /atom/movable/Bump(var/atom/A, yes) if(src.throwing) @@ -211,7 +212,7 @@ /atom/movable/overlay/New() for(var/x in src.verbs) src.verbs -= x - return + ..() /atom/movable/overlay/attackby(a, b) if (src.master) diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 29d519355e..3138c65439 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -47,6 +47,7 @@ idle_power_usage = 50 active_power_usage = 300 interact_offline = 1 + circuit = /obj/item/weapon/circuitboard/clonescanner var/locked = 0 var/mob/living/carbon/occupant = null var/obj/item/weapon/reagent_containers/glass/beaker = null @@ -55,7 +56,6 @@ /obj/machinery/dna_scannernew/New() ..() component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/clonescanner(src) component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) component_parts += new /obj/item/weapon/stock_parts/manipulator(src) component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) @@ -159,7 +159,7 @@ || locate(/obj/machinery/computer/cloning, get_step(src, WEST))) if(!M.client && M.mind) - for(var/mob/dead/observer/ghost in player_list) + for(var/mob/observer/dead/ghost in player_list) if(ghost.mind == M.mind) ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)" break diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/game/gamemodes/changeling/absorbed_dna.dm new file mode 100644 index 0000000000..3c23f0270c --- /dev/null +++ b/code/game/gamemodes/changeling/absorbed_dna.dm @@ -0,0 +1,16 @@ +/datum/absorbed_dna + var/name + var/datum/dna/dna + var/speciesName + var/list/languages + var/identifying_gender + var/list/flavour_texts + +/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages, var/newIdentifying_Gender, var/list/newFlavour) + ..() + name = newName + dna = newDNA + speciesName = newSpecies + languages = newLanguages + identifying_gender = newIdentifying_Gender + flavour_texts = newFlavour ? newFlavour.Copy() : null \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 0ac3d8d35d..23bd46243e 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -1,5 +1,5 @@ /datum/game_mode/changeling - name = "changeling" + name = "Changeling" round_description = "There are alien changelings on the station. Do not let the changelings succeed!" extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. \ Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet \ diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index b6de864cf3..a60faeb830 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -1,9 +1,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega") /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) - var/list/absorbed_dna = list() - var/list/absorbed_species = list() - var/list/absorbed_languages = list() + var/list/datum/absorbed_dna/absorbed_dna = list() + var/list/absorbed_languages = list() // Necessary because of set_species stuff var/absorbedcount = 0 var/chem_charges = 20 var/chem_recharge_rate = 0.5 @@ -14,33 +13,45 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E var/isabsorbing = 0 var/geneticpoints = 5 var/max_geneticpoints = 5 - var/purchasedpowers = list() + var/list/purchased_powers = list() var/mimicing = "" var/cloaked = 0 var/armor_deployed = 0 //This is only used for changeling_generic_equip_all_slots() at the moment. var/recursive_enhancement = 0 //Used to power up other abilities from the ling power with the same name. + var/list/purchased_powers_history = list() //Used for round-end report, includes respec uses too. /datum/changeling/New(var/gender=FEMALE) ..() - var/honorific = (gender == FEMALE) ? "Ms." : "Mr." if(possible_changeling_IDs.len) changelingID = pick(possible_changeling_IDs) possible_changeling_IDs -= changelingID - changelingID = "[honorific] [changelingID]" + changelingID = "[changelingID]" else - changelingID = "[honorific] [rand(1,999)]" + changelingID = "[rand(1,999)]" /datum/changeling/proc/regenerate() chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage) geneticdamage = max(0, geneticdamage-1) /datum/changeling/proc/GetDNA(var/dna_owner) - var/datum/dna/chosen_dna - for(var/datum/dna/DNA in absorbed_dna) - if(dna_owner == DNA.real_name) - chosen_dna = DNA - break - return chosen_dna + for(var/datum/absorbed_dna/DNA in absorbed_dna) + if(dna_owner == DNA.name) + return DNA + +/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA) + var/datum/changeling/changeling = null + if(src.mind && src.mind.changeling) + changeling = src.mind.changeling + if(!changeling) + return + + for(var/language in newDNA.languages) + changeling.absorbed_languages |= language + + changeling_update_languages(changeling.absorbed_languages) + + if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite + changeling.absorbed_dna += newDNA //Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human /mob/proc/make_changeling() @@ -60,10 +71,10 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E // Code to auto-purchase free powers. for(var/datum/power/changeling/P in powerinstances) if(!P.genomecost) // Is it free? - if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already? + if(!(P in mind.changeling.purchased_powers)) // Do we not have it already? mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this. - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) + for(var/datum/power/changeling/P in mind.changeling.purchased_powers) if(P.isVerb) if(lesser_form && !P.allowduringlesserform) continue if(!(P in src.verbs)) @@ -79,21 +90,20 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E arguments = list() ) - mind.changeling.absorbed_dna |= dna + for(var/language in languages) + mind.changeling.absorbed_languages |= language var/mob/living/carbon/human/H = src if(istype(H)) - mind.changeling.absorbed_species += H.species.name - - for(var/language in languages) - mind.changeling.absorbed_languages |= language + var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages, H.identifying_gender, H.flavor_texts) + absorbDNA(newDNA) return 1 //removes our changeling verbs /mob/proc/remove_changeling_powers() if(!mind || !mind.changeling) return - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) + for(var/datum/power/changeling/P in mind.changeling.purchased_powers) if(P.isVerb) verbs -= P.verbpath var/obj/screen/ability/verb_based/changeling/C = ability_master.get_ability_by_proc_ref(P.verbpath) @@ -130,10 +140,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E return changeling - //Used to dump the languages from the changeling datum into the actual mob. /mob/proc/changeling_update_languages(var/updated_languages) - languages = list() for(var/language in updated_languages) languages += language @@ -141,8 +149,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E //This isn't strictly necessary but just to be safe... add_language("Changeling") - return - ////////// //STINGS// //They get a pretty header because there's just so fucking many of them ;_; ////////// @@ -183,9 +189,3 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting T << "You feel a tiny prick." return - - - - - - diff --git a/code/game/gamemodes/changeling/generic_equip_procs.dm b/code/game/gamemodes/changeling/generic_equip_procs.dm index 5569db8512..930e50c9c8 100644 --- a/code/game/gamemodes/changeling/generic_equip_procs.dm +++ b/code/game/gamemodes/changeling/generic_equip_procs.dm @@ -244,7 +244,7 @@ var/mob/living/carbon/human/M = src - if(M.l_hand && M.r_hand) //Make sure our hands aren't full. + if(M.hands_are_full()) //Make sure our hands aren't full. src << "Our hands are full. Drop something first." return 0 diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm index 55aad065fb..41f66fb4ec 100644 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -251,7 +251,7 @@ var/list/datum/power/changeling/powerinstances = list() for(var/datum/power/changeling/P in powerinstances) var/ownsthis = 0 - if(P in purchasedpowers) + if(P in purchased_powers) ownsthis = 1 @@ -326,7 +326,7 @@ var/list/datum/power/changeling/powerinstances = list() M.current << "This is awkward. Changeling power purchase failed, please report this bug to a coder!" return - if(Thepower in purchasedpowers) + if(Thepower in purchased_powers) M.current << "We have already evolved this ability!" return @@ -337,7 +337,10 @@ var/list/datum/power/changeling/powerinstances = list() geneticpoints -= Thepower.genomecost - purchasedpowers += Thepower + purchased_powers += Thepower + + if(Thepower.genomecost > 0) + purchased_powers_history.Add("[Pname] ([Thepower.genomecost] points)") if(Thepower.make_hud_button && Thepower.isVerb) if(!M.current.ability_master) diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 6adead4b89..e75020fc59 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -1,10 +1,10 @@ /datum/power/changeling/absorb_dna name = "Absorb DNA" - desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger." + desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger if they were of our kind." genomecost = 0 verbpath = /mob/proc/changeling_absorb_dna -//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. +//Absorbs the victim's DNA. Requires a strong grip on the victim. //Doesn't cost anything as it's the most basic ability. /mob/proc/changeling_absorb_dna() set category = "Changeling" @@ -27,9 +27,10 @@ src << "We do not know how to parse this creature's DNA!" return - if(HUSK in T.mutations) - src << "This creature's DNA is ruined beyond useability!" - return + if(HUSK in T.mutations) //Lings can always absorb other lings, unless someone beat them to it first. + if(!T.mind.changeling || T.mind.changeling && T.mind.changeling.geneticpoints < 0) + src << "This creature's DNA is ruined beyond useability!" + return if(G.state != GRAB_KILL) src << "We must have a tighter grip to absorb this creature." @@ -64,33 +65,21 @@ src << "We have absorbed [T]!" src.visible_message("[src] sucks the fluids from [T]!") T << "You have been absorbed by the changeling!" - - T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. - changeling.absorbed_dna |= T.dna if(src.nutrition < 400) src.nutrition = min((src.nutrition + T.nutrition), 400) changeling.chem_charges += 10 -// changeling.geneticpoints += 2 src.verbs += /mob/proc/changeling_respec src << "We can now re-adapt, reverting our evolution so that we may start anew, if needed." - //Steal all of their languages! - for(var/language in T.languages) - if(!(language in changeling.absorbed_languages)) - changeling.absorbed_languages += language - - changeling_update_languages(changeling.absorbed_languages) - - //Steal their species! - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts) + absorbDNA(newDNA) if(T.mind && T.mind.changeling) if(T.mind.changeling.absorbed_dna) - for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot + for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot if(dna_data in changeling.absorbed_dna) continue - changeling.absorbed_dna += dna_data + absorbDNA(dna_data) changeling.absorbedcount++ T.mind.changeling.absorbed_dna.len = 1 diff --git a/code/game/gamemodes/changeling/powers/armblade.dm b/code/game/gamemodes/changeling/powers/armblade.dm index e1d6609851..7ab1cdda3b 100644 --- a/code/game/gamemodes/changeling/powers/armblade.dm +++ b/code/game/gamemodes/changeling/powers/armblade.dm @@ -2,6 +2,7 @@ name = "Arm Blade" desc = "We reform one of our arms into a deadly blade." helptext = "We may retract our armblade by dropping it. It can deflect projectiles." + enhancedtext = "The blade will have armor peneratration." genomecost = 2 verbpath = /mob/proc/changeling_arm_blade @@ -10,9 +11,16 @@ set category = "Changeling" set name = "Arm Blade (20)" - if(changeling_generic_weapon(/obj/item/weapon/melee/arm_blade)) - return 1 - return 0 + if(src.mind.changeling.recursive_enhancement) + if(changeling_generic_weapon(/obj/item/weapon/melee/arm_blade/greater)) + src << "We prepare an extra sharp blade." + src.mind.changeling.recursive_enhancement = 0 + return 1 + + else + if(changeling_generic_weapon(/obj/item/weapon/melee/arm_blade)) + return 1 + return 0 /obj/item/weapon/melee/arm_blade name = "arm blade" @@ -31,6 +39,11 @@ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") var/mob/living/creator //This is just like ninja swords, needed to make sure dumb shit that removes the sword doesn't make it stay around. +/obj/item/weapon/melee/arm_blade/greater + name = "arm greatblade" + desc = "A grotesque blade made out of bone and flesh that cleaves through people and armor as a hot knife through butter." + armor_penetration = 30 + /obj/item/weapon/melee/arm_blade/New(location) ..() processing_objects |= src @@ -43,7 +56,7 @@ /obj/item/weapon/melee/arm_blade/dropped(mob/user) visible_message("With a sickening crunch, [creator] reforms their arm blade into an arm!", "We assimilate the weapon back into our body.", - "You hear organic matter ripping and tearing!") playsound(src, 'sound/effects/blobattack.ogg', 30, 1) spawn(1) if(src) @@ -55,7 +68,7 @@ ..() /obj/item/weapon/melee/arm_blade/process() //Stolen from ninja swords. - if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src)) + if(!creator || loc != creator || !creator.item_is_in_hands(src)) // Tidy up a bit. if(istype(loc,/mob/living)) var/mob/living/carbon/human/host = loc diff --git a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm index 694e22e8dd..6dd22efab9 100644 --- a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm +++ b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm @@ -4,11 +4,12 @@ On demand, we can attempt to recharge anything in our active hand, or we can touch someone with an electrified hand, shocking them." helptext = "We can shock someone by grabbing them and using this ability, or using the ability with an empty hand and touching them. \ Shocking someone costs ten chemicals per use." + enhancedtext = "Shocking biologicals without grabbing only requires five chemicals, and has more disabling power." genomecost = 2 - verbpath = /mob/proc/changeling_bioelectrogenesis + verbpath = /mob/living/carbon/human/proc/changeling_bioelectrogenesis //Recharge whatever's in our hand, or shock people. -/mob/proc/changeling_bioelectrogenesis() +/mob/living/carbon/human/proc/changeling_bioelectrogenesis() set category = "Changeling" set name = "Bioelectrogenesis (20 + 10/shock)" set desc = "Recharges anything in your hand, or shocks people." @@ -21,25 +22,39 @@ return 0 if(held_item == null) - if(changeling_generic_weapon(/obj/item/weapon/electric_hand,0)) //Chemical cost is handled in the equip proc. - return 1 + if(src.mind.changeling.recursive_enhancement) + if(changeling_generic_weapon(/obj/item/weapon/electric_hand/efficent)) + src << "We will shock others more efficently." + src.mind.changeling.recursive_enhancement = 0 + return 1 + else + if(changeling_generic_weapon(/obj/item/weapon/electric_hand,0)) //Chemical cost is handled in the equip proc. + return 1 return 0 else + // Handle glove conductivity. + var/obj/item/clothing/gloves/gloves = src.gloves + var/siemens = 1 + if(gloves) + siemens = gloves.siemens_coefficient + //If we're grabbing someone, electrocute them. if(istype(held_item,/obj/item/weapon/grab)) var/obj/item/weapon/grab/G = held_item if(G.affecting) - G.affecting.electrocute_act(5,src,1.0,BP_TORSO) - var/agony = 60 //The same as a stunbaton. - var/stun = 0 - G.affecting.stun_effect_act(stun, agony, BP_TORSO, src) + G.affecting.electrocute_act(10 * siemens,src,1.0,BP_TORSO) + var/agony = 80 * siemens //Does more than if hit with an electric hand, since grabbing is slower. + G.affecting.stun_effect_act(0, agony, BP_TORSO, src) - msg_admin_attack("[key_name(src)] stunned [key_name(G.affecting)] with the [src].") + msg_admin_attack("[key_name(src)] shocked [key_name(G.affecting)] with the [src].") - visible_message("Arcs of electricity strike [G.affecting]!", - "Our hand channels raw electricity into [G.affecting].", - "You hear sparks!") + if(siemens) + visible_message("Arcs of electricity strike [G.affecting]!", + "Our hand channels raw electricity into [G.affecting].", + "You hear sparks!") + else + src << "Our gloves block us from shocking \the [G.affecting]." src.mind.changeling.chem_charges -= 10 return 1 @@ -63,17 +78,19 @@ "Our hand channels raw electricity into \the [held_item].", "You hear sparks!") var/i = 10 - while(i) - cell.charge += 100 //This should be a nice compromise between recharging guns and other batteries. - if(cell.charge > cell.maxcharge) - cell.charge = cell.maxcharge - break - var/T = get_turf(src) - new /obj/effect/effect/sparks(T) - held_item.update_icon() - i-- - sleep(10) - success = 1 + if(siemens) + while(i) + cell.charge += 100 * siemens //This should be a nice compromise between recharging guns and other batteries. + if(cell.charge > cell.maxcharge) + cell.charge = cell.maxcharge + break + if(siemens) + var/T = get_turf(src) + new /obj/effect/effect/sparks(T) + held_item.update_icon() + i-- + sleep(1 SECOND) + success = 1 if(success == 0) //If we couldn't do anything with the ability, don't deduct the chemicals. src << "We are unable to affect \the [held_item]." else @@ -85,6 +102,14 @@ desc = "You could probably shock someone badly if you touched them, or recharge something." icon = 'icons/obj/weapons.dmi' icon_state = "electric_hand" + var/shock_cost = 10 + var/agony_amount = 60 + var/electrocute_amount = 10 + +/obj/item/weapon/electric_hand/efficent + shock_cost = 5 + agony_amount = 80 + electrocute_amount = 20 /obj/item/weapon/electric_hand/New() if(ismob(loc)) @@ -99,31 +124,39 @@ if(src) qdel(src) -/obj/item/weapon/electric_hand/afterattack(var/atom/target, var/mob/living/user, proximity) +/obj/item/weapon/electric_hand/afterattack(var/atom/target, var/mob/living/carbon/human/user, proximity) if(!target) return if(!proximity) return + + // Handle glove conductivity. + var/obj/item/clothing/gloves/gloves = user.gloves + var/siemens = 1 + if(gloves) + siemens = gloves.siemens_coefficient + //Excuse the copypasta. if(istype(target,/mob/living/carbon)) var/mob/living/carbon/C = target - if(user.mind.changeling.chem_charges < 10) + if(user.mind.changeling.chem_charges < shock_cost) src << "We require more chemicals to electrocute [C]!" return 0 - C.electrocute_act(5,src,1.0,BP_TORSO) - var/agony = 60 //The same as a stunbaton. - var/stun = 0 - C.stun_effect_act(stun, agony, BP_TORSO, src) + C.electrocute_act(electrocute_amount * siemens,src,1.0,BP_TORSO) + C.stun_effect_act(0, agony_amount * siemens, BP_TORSO, src) - msg_admin_attack("[key_name(user)] stunned [key_name(C)] with the [src].") + msg_admin_attack("[key_name(user)] shocked [key_name(C)] with the [src].") - visible_message("Arcs of electricity strike [C]!", - "Our hand channels raw electricity into [C]", - "You hear sparks!") + if(siemens) + visible_message("Arcs of electricity strike [C]!", + "Our hand channels raw electricity into [C]", + "You hear sparks!") + else + src << "Our gloves block us from shocking \the [C]." //qdel(src) //Since we're no longer a one hit stun, we need to stick around. - user.mind.changeling.chem_charges -= 10 + user.mind.changeling.chem_charges -= shock_cost return 1 else if(istype(target,/mob/living/silicon)) @@ -133,11 +166,12 @@ src << "We require more chemicals to electrocute [S]!" return 0 - S.electrocute_act(60,src,1.0) //If only they had surge protectors. - visible_message("Arcs of electricity strike [S]!", - "Our hand channels raw electricity into [S]", - "You hear sparks!") - S << "Warning: Electrical surge detected!" + S.electrocute_act(60 * siemens,src,1.0) //If only they had surge protectors. + if(siemens) + visible_message("Arcs of electricity strike [S]!", + "Our hand channels raw electricity into [S]", + "You hear sparks!") + S << "Warning: Electrical surge detected!" //qdel(src) user.mind.changeling.chem_charges -= 10 return 1 @@ -152,20 +186,22 @@ "Our hand channels raw electricity into \the [target].", "You hear sparks!") var/i = 10 - while(i) - cell.charge += 100 //This should be a nice compromise between recharging guns and other batteries. - if(cell.charge > cell.maxcharge) - cell.charge = cell.maxcharge - break //No point making sparks if the cell's full. -// if(!Adjacent(T)) -// break - var/Turf = get_turf(src) - new /obj/effect/effect/sparks(Turf) - T.update_icon() - i-- - sleep(10) - success = 1 - break + if(siemens) + while(i) + cell.charge += 100 * siemens //This should be a nice compromise between recharging guns and other batteries. + if(cell.charge > cell.maxcharge) + cell.charge = cell.maxcharge + break //No point making sparks if the cell's full. + // if(!Adjacent(T)) + // break + if(siemens) + var/Turf = get_turf(src) + new /obj/effect/effect/sparks(Turf) + T.update_icon() + i-- + sleep(1 SECOND) + success = 1 + break if(success == 0) src << "We are unable to affect \the [target]." else diff --git a/code/game/gamemodes/changeling/powers/cryo_sting.dm b/code/game/gamemodes/changeling/powers/cryo_sting.dm index d6a4f6302b..7fae4c1601 100644 --- a/code/game/gamemodes/changeling/powers/cryo_sting.dm +++ b/code/game/gamemodes/changeling/powers/cryo_sting.dm @@ -1,7 +1,8 @@ /datum/power/changeling/cryo_sting name = "Cryogenic Sting" desc = "We silently sting a biological with a cocktail of chemicals that freeze them." - helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing." + helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. Has \ + a three minute cooldown between uses." enhancedtext = "Increases the amount of chemicals injected." genomecost = 1 verbpath = /mob/proc/changeling_cryo_sting diff --git a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm b/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm index 0b0b95589c..8f7998f67a 100644 --- a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm +++ b/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm @@ -1,7 +1,8 @@ /datum/power/changeling/delayed_toxic_sting name = "Delayed Toxic Sting" - desc = "We silently sting a biological, causing a significant amount of toxins after a few minutes, allowing us to not implicate ourselves." - helptext = "The toxin takes effect in about two minutes." + desc = "We silently sting a biological, causing a significant amount of toxins after a few minutes, allowing us to not \ + implicate ourselves." + helptext = "The toxin takes effect in about two minutes. The sting has a three minute cooldown between uses." enhancedtext = "The toxic damage is doubled." genomecost = 1 verbpath = /mob/proc/changeling_delayed_toxic_sting @@ -25,7 +26,7 @@ while(i) T.adjustToxLoss(1) i-- - sleep(20) + sleep(2 SECONDS) src.verbs -= /mob/proc/changeling_delayed_toxic_sting spawn(3 MINUTES) src << "We are ready to use our delayed toxic string once more." diff --git a/code/game/gamemodes/changeling/powers/electric_lockpick.dm b/code/game/gamemodes/changeling/powers/electric_lockpick.dm index c8c87e6a9d..40c4b372a0 100644 --- a/code/game/gamemodes/changeling/powers/electric_lockpick.dm +++ b/code/game/gamemodes/changeling/powers/electric_lockpick.dm @@ -78,6 +78,7 @@ else //Probably broken or no power. user << "The door does not respond to the pulse." door.add_fingerprint(user) + log_and_message_admins("finger-lockpicked \an [door].") ling_datum.chem_charges -= 10 return 1 @@ -86,7 +87,7 @@ user << "We send an electrical pulse up our finger, and into \the [O]." O.add_fingerprint(user) O.emag_act(1,user,src) - log_and_message_admins("emagged \an [O].") + log_and_message_admins("finger-lockpicked \an [O].") ling_datum.chem_charges -= 10 return 1 diff --git a/code/game/gamemodes/changeling/powers/endoarmor.dm b/code/game/gamemodes/changeling/powers/endoarmor.dm index c548e549f1..4052568a50 100644 --- a/code/game/gamemodes/changeling/powers/endoarmor.dm +++ b/code/game/gamemodes/changeling/powers/endoarmor.dm @@ -1,7 +1,7 @@ /datum/power/changeling/endoarmor name = "Endoarmor" desc = "We grow hard plating underneath our skin, making us more resilient to harm by increasing our maximum health potential by 50 points." - helptext = "Our maximum health is increased to 150 health." + helptext = "Our maximum health is increased by 50 points." genomecost = 1 isVerb = 0 verbpath = /mob/proc/changeling_endoarmor diff --git a/code/game/gamemodes/changeling/powers/enfeebling_string.dm b/code/game/gamemodes/changeling/powers/enfeebling_string.dm index 35d4ef7570..94699995ff 100644 --- a/code/game/gamemodes/changeling/powers/enfeebling_string.dm +++ b/code/game/gamemodes/changeling/powers/enfeebling_string.dm @@ -1,7 +1,8 @@ /datum/power/changeling/enfeebling_string name = "Enfeebling String" desc = "We sting a biological with a potent toxin that will greatly weaken them for a short period of time." - helptext = "Lowers the maximum health of the victim for a few minutes. This sting will also warn them of this." + helptext = "Lowers the maximum health of the victim for a few minutes. This sting will also warn them of this. Has a \ + five minute coodown between uses." enhancedtext = "Maximum health is lowered further." genomecost = 1 verbpath = /mob/proc/changeling_enfeebling_string @@ -17,17 +18,21 @@ if(ishuman(T)) var/mob/living/carbon/human/H = T - var/effect = 30 + var/effect = 30 //percent if(src.mind.changeling.recursive_enhancement) effect = effect + 20 src << "We make them extremely weak." src.mind.changeling.recursive_enhancement = 0 + var/health_to_take_away = H.maxHealth * (effect / 100) - H.maxHealth -= effect - H << "You feel a small prick and you feel weak." - spawn(300) //Five minutes + H.maxHealth -= health_to_take_away + H << "You feel a small prick and you feel extremly weak!" + src.verbs -= /mob/proc/changeling_enfeebling_string + spawn(5 MINUTES) + src.verbs |= /mob/proc/changeling_enfeebling_string + src << "Our enfeebling string is ready to be used once more." if(H) //Just incase we stop existing in five minutes for whatever reason. - H.maxHealth += 30 + H.maxHealth += health_to_take_away if(!H.stat) //It'd be weird to no longer feel weak when you're dead. H << "You no longer feel extremly weak." feedback_add_details("changeling_powers","ES") diff --git a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm index 9b0d1e149a..a761a5335c 100644 --- a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm +++ b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm @@ -19,6 +19,9 @@ var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting) + if(!T) + return + if(!istype(T) || T.isSynthetic()) src << "\The [T] is not compatible with our biology." return 0 @@ -31,10 +34,8 @@ src << "This creature's DNA is ruined beyond useability!" return 0 - T.dna.real_name = T.real_name - changeling.absorbed_dna |= T.dna - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) + absorbDNA(newDNA) feedback_add_details("changeling_powers","ED") return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/fake_death.dm b/code/game/gamemodes/changeling/powers/fake_death.dm index 0018eabad6..ac7080301b 100644 --- a/code/game/gamemodes/changeling/powers/fake_death.dm +++ b/code/game/gamemodes/changeling/powers/fake_death.dm @@ -18,14 +18,13 @@ var/mob/living/carbon/C = src if(changeling.max_geneticpoints < 0) //Absorbed by another ling - src << "You have no genomes, not even your own, and cannot regenerate." + src << "We have no genomes, not even our own, and cannot regenerate." return 0 - if(!C.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death + if(!C.stat && alert("Are we sure we wish to regenerate? We will appear to be dead while doing so.","Revival","Yes","No") == "No") return C << "We will attempt to regenerate our form." - C.status_flags |= FAKEDEATH //play dead C.update_canmove() C.remove_changeling_powers() @@ -33,13 +32,12 @@ C.suiciding = 0 if(C.stat != DEAD) - C.emote("deathgasp") - C.tod = worldtime2text() + C.adjustOxyLoss(C.maxHealth * 2) spawn(rand(800,2000)) //The ling will now be able to choose when to revive src.verbs += /mob/proc/changeling_revive - src << "We are ready to rise. Use the Revive verb when you are ready." + src << "We are ready to rise. Use the Revive verb when you are ready." feedback_add_details("changeling_powers","FD") return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm index 0046e1517c..5a157cdbb7 100644 --- a/code/game/gamemodes/changeling/powers/fleshmend.dm +++ b/code/game/gamemodes/changeling/powers/fleshmend.dm @@ -31,10 +31,10 @@ C.adjustBruteLoss(-heal_amount) C.adjustOxyLoss(-heal_amount) C.adjustFireLoss(-heal_amount) - sleep(10) + sleep(1 SECOND) src.verbs -= /mob/proc/changeling_fleshmend - spawn(500) + spawn(50 SECONDS) src << "Our regeneration has slowed to normal levels." src.verbs += /mob/proc/changeling_fleshmend feedback_add_details("changeling_powers","FM") diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/game/gamemodes/changeling/powers/hivemind.dm index 7b9cdad0b9..c8e5f11604 100644 --- a/code/game/gamemodes/changeling/powers/hivemind.dm +++ b/code/game/gamemodes/changeling/powers/hivemind.dm @@ -29,9 +29,9 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) if(!(DNA in hivemind_bank)) - names += DNA.real_name + names += DNA.name if(names.len <= 0) src << "The airwaves already have all of our DNA." @@ -40,7 +40,7 @@ var/list/datum/dna/hivemind_bank = list() var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = changeling.GetDNA(S) + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) if(!chosen_dna) return @@ -59,9 +59,9 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in hivemind_bank) + for(var/datum/absorbed_dna/DNA in hivemind_bank) if(!(DNA in changeling.absorbed_dna)) - names[DNA.real_name] = DNA + names[DNA.name] = DNA if(names.len <= 0) src << "There's no new DNA to absorb from the air." @@ -69,12 +69,12 @@ var/list/datum/dna/hivemind_bank = list() var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = names[S] + var/datum/absorbed_dna/chosen_dna = names[S] if(!chosen_dna) return changeling.chem_charges -= 20 - changeling.absorbed_dna += chosen_dna + absorbDNA(chosen_dna) src << "We absorb the DNA of [S] from the air." feedback_add_details("changeling_powers","HD") return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/rapid_regen.dm b/code/game/gamemodes/changeling/powers/rapid_regen.dm index a320c33b96..6f2d43e5da 100644 --- a/code/game/gamemodes/changeling/powers/rapid_regen.dm +++ b/code/game/gamemodes/changeling/powers/rapid_regen.dm @@ -48,7 +48,7 @@ new /obj/effect/gibspawner/human(T) visible_message("With a sickening squish, [src] reforms their whole body, casting their old parts on the floor!", "We reform our body. We are whole once more.", - "You hear organic matter ripping and tearing!") feedback_add_details("changeling_powers","RR") return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/respec.dm b/code/game/gamemodes/changeling/powers/respec.dm index f2bfe8f19c..661a761d8c 100644 --- a/code/game/gamemodes/changeling/powers/respec.dm +++ b/code/game/gamemodes/changeling/powers/respec.dm @@ -9,7 +9,7 @@ src.remove_changeling_powers() //First, remove the verbs. var/datum/changeling/ling_datum = src.mind.changeling - ling_datum.purchasedpowers = list() //Then wipe all the powers we bought. + ling_datum.purchased_powers = list() //Then wipe all the powers we bought. ling_datum.geneticpoints = ling_datum.max_geneticpoints //Now refund our points to the maximum. ling_datum.chem_recharge_rate = 0.5 //If glands were bought, revert that upgrade. ling_datum.chem_storage = 50 @@ -21,5 +21,7 @@ src << "We have removed our evolutions from this form, and are now ready to readapt." + ling_datum.purchased_powers_history.Add("Re-adapt (Reset to [ling_datum.max_geneticpoints])") + //Now to lose the verb, so no unlimited resets. src.verbs -= /mob/proc/changeling_respec \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm index 7dc2310f78..79fd2dcf74 100644 --- a/code/game/gamemodes/changeling/powers/revive.dm +++ b/code/game/gamemodes/changeling/powers/revive.dm @@ -25,18 +25,24 @@ C.SetStunned(0) C.SetWeakened(0) C.radiation = 0 - C.halloss = 0 - C.shock_stage = 0 //Pain C.heal_overall_damage(C.getBruteLoss(), C.getFireLoss()) C.reagents.clear_reagents() C.restore_all_organs(ignore_prosthetic_prefs=1) //Covers things like fractures and other things not covered by the above. if(ishuman(C)) var/mob/living/carbon/human/H = src H.restore_blood() + H.mutations.Remove(HUSK) + H.status_flags -= DISFIGURED + H.update_body(1) + for(var/limb in H.organs_by_name) + var/obj/item/organ/external/current_limb = H.organs_by_name[limb] + current_limb.undislocate() + + C.halloss = 0 + C.shock_stage = 0 //Pain C << "We have regenerated." - C.status_flags &= ~(FAKEDEATH) C.update_canmove() - C.mind.changeling.purchasedpowers -= C + C.mind.changeling.purchased_powers -= C feedback_add_details("changeling_powers","CR") C.stat = CONSCIOUS src.verbs -= /mob/proc/changeling_revive diff --git a/code/game/gamemodes/changeling/powers/self_respiration.dm b/code/game/gamemodes/changeling/powers/self_respiration.dm index a00ec7958c..96b8f3d277 100644 --- a/code/game/gamemodes/changeling/powers/self_respiration.dm +++ b/code/game/gamemodes/changeling/powers/self_respiration.dm @@ -1,8 +1,8 @@ /datum/power/changeling/self_respiration name = "Self Respiration" - desc = "We evolve our body to no longer require drawing oxygen from the atmosphere.." + desc = "We evolve our body to no longer require drawing oxygen from the atmosphere." helptext = "We will no longer require internals, and we cannot inhale any gas, including harmful ones." - genomecost = 1 + genomecost = 0 isVerb = 0 verbpath = /mob/proc/changeling_self_respiration diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index 2969e11624..57a55e2e21 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -2,16 +2,8 @@ name = "Transform" desc = "We take on the apperance and voice of one we have absorbed." genomecost = 0 - make_hud_button = 0 verbpath = /mob/proc/changeling_transform -/datum/power/changeling/change_species - name = "Change Species" - desc = "We take on the apperance of a species that we have absorbed." - genomecost = 0 - make_hud_button = 0 - verbpath = /mob/proc/changeling_change_species - //Change our DNA to that of somebody we've absorbed. /mob/proc/changeling_transform() set category = "Changeling" @@ -21,71 +13,41 @@ if(!changeling) return var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" + for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) + names += "[DNA.name]" var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names if(!S) return - var/datum/dna/chosen_dna = changeling.GetDNA(S) + var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) if(!chosen_dna) return changeling.chem_charges -= 5 src.visible_message("[src] transforms!") changeling.geneticdamage = 5 - src.dna = chosen_dna.Clone() + + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/newSpecies = chosen_dna.speciesName + H.set_species(newSpecies,1) + + src.dna = chosen_dna.dna.Clone() src.dna.b_type = "AB+" //This is needed to avoid blood rejection bugs. The fact that the blood type might not match up w/ records could be a *FEATURE* too. if(ishuman(src)) var/mob/living/carbon/human/H = src H.b_type = "AB+" //For some reason we have two blood types on the mob. - src.real_name = chosen_dna.real_name - src.flavor_text = "" + H.identifying_gender = chosen_dna.identifying_gender + H.flavor_texts = chosen_dna.flavour_texts ? chosen_dna.flavour_texts.Copy() : null + src.real_name = chosen_dna.name src.UpdateAppearance() domutcheck(src, null) + changeling_update_languages(changeling.absorbed_languages) src.verbs -= /mob/proc/changeling_transform - spawn(10) src.verbs += /mob/proc/changeling_transform + spawn(10) + src.verbs += /mob/proc/changeling_transform + src.regenerate_icons() feedback_add_details("changeling_powers","TR") return 1 - -//Used to switch species based on the changeling datum. -/mob/proc/changeling_change_species() - - set category = "Changeling" - set name = "Change Species (5)" - - var/mob/living/carbon/human/H = src - if(!istype(H)) - src << "We may only use this power while in humanoid form." - return - - var/datum/changeling/changeling = changeling_power(5,1,0) - if(!changeling) return - - if(changeling.absorbed_species.len < 2) - src << "We do not know of any other species genomes to use." - return - - var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species - if(!S) return - - domutcheck(src, null) - - changeling.chem_charges -= 5 - changeling.geneticdamage = 5 - - src.visible_message("[src] transforms!") - - src.verbs -= /mob/proc/changeling_change_species - H.set_species(S,1) //Until someone moves body colour into DNA, they're going to have to use the default. - - spawn(10) - src.verbs += /mob/proc/changeling_change_species - src.regenerate_icons() - - changeling_update_languages(changeling.absorbed_languages) - feedback_add_details("changeling_powers","TR") - - return 1 \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 70e2219440..3cd2a496cb 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -1,28 +1,42 @@ /obj/item/weapon/melee/cultblade name = "cult blade" - desc = "An arcane weapon wielded by the followers of Nar-Sie" + desc = "An arcane weapon wielded by the followers of Nar-Sie." icon_state = "cultblade" item_state = "cultblade" w_class = 4 force = 30 throwforce = 10 + hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + edge = 1 + sharp = 1 /obj/item/weapon/melee/cultblade/cultify() return -/obj/item/weapon/melee/cultblade/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) +/obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone) if(iscultist(user)) - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) return ..() + + var/zone = (user.hand ? "l_arm":"r_arm") + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/affecting = H.get_organ(zone) + user << "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!" else - user.Paralyse(5) - user << "An unexplicable force powerfully repels the sword from [target]!" - var/organ = ((user.hand ? "l_":"r_") + "arm") - var/obj/item/organ/external/affecting = user.get_organ(organ) - if(affecting.take_damage(rand(force/2, force))) //random amount of damage between half of the blade's force and the full force of the blade. - user.UpdateDamageIcon() - return + user << "An unexplicable force rips through you, tearing the sword from your grasp!" + + //random amount of damage between half of the blade's force and the full force of the blade. + user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1) + user.Weaken(5) + + user.drop_from_inventory(src, src.loc) + throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed) + + var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') + playsound(loc, spooky, 50, 1) + + return 1 /obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) if(!iscultist(user)) @@ -36,7 +50,7 @@ desc = "A hood worn by the followers of Nar-Sie." flags_inv = HIDEFACE body_parts_covered = HEAD - armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0) + armor = list(melee = 50, bullet = 30, laser = 50, energy = 20, bomb = 25, bio = 10, rad = 0) cold_protection = HEAD min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE siemens_coefficient = 0 @@ -56,12 +70,12 @@ /obj/item/clothing/suit/cultrobes name = "cult robes" - desc = "A set of armored robes worn by the followers of Nar-Sie" + desc = "A set of armored robes worn by the followers of Nar-Sie." icon_state = "cultrobes" item_state = "cultrobes" body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade) - armor = list(melee = 50, bullet = 30, laser = 50,energy = 20, bomb = 25, bio = 10, rad = 0) + armor = list(melee = 50, bullet = 30, laser = 50, energy = 20, bomb = 25, bio = 10, rad = 0) flags_inv = HIDEJUMPSUIT siemens_coefficient = 0 @@ -74,7 +88,7 @@ /obj/item/clothing/suit/cultrobes/magusred name = "magus robes" - desc = "A set of armored robes worn by the followers of Nar-Sie" + desc = "A set of armored robes worn by the followers of Nar-Sie." icon_state = "magusred" item_state = "magusred" body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS @@ -82,9 +96,9 @@ /obj/item/clothing/head/helmet/space/cult name = "cult helmet" - desc = "A space worthy helmet used by the followers of Nar-Sie" + desc = "A space worthy helmet used by the followers of Nar-Sie." icon_state = "cult_helmet" - armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) + armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 30, bio = 30, rad = 30) siemens_coefficient = 0 /obj/item/clothing/head/helmet/space/cult/cultify() @@ -94,11 +108,11 @@ name = "cult armour" icon_state = "cult_armour" item_state = "cult_armour" - desc = "A bulky suit of armour, bristling with spikes. It looks space proof." + desc = "A bulky suit of armour, bristling with spikes. It looks space-worthy." w_class = 3 allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit) slowdown = 1 - armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) + armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 30, bio = 30, rad = 30) siemens_coefficient = 0 body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 226df14bfb..0f2c4d83b6 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -8,18 +8,18 @@ /obj/structure/cult/talisman name = "Altar" - desc = "A bloodstained altar dedicated to Nar-Sie" + desc = "A bloodstained altar dedicated to Nar-Sie." icon_state = "talismanaltar" /obj/structure/cult/forge name = "Daemon forge" - desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie" + desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie." icon_state = "forge" /obj/structure/cult/pylon name = "Pylon" - desc = "A floating crystal that hums with an unearthly energy" + desc = "A floating crystal that hums with an unearthly energy." icon_state = "pylon" var/isbroken = 0 light_range = 5 @@ -71,7 +71,7 @@ /obj/structure/cult/tome name = "Desk" - desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl" + desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." icon_state = "tomealtar" //sprites for this no longer exist -Pete @@ -86,7 +86,7 @@ /obj/effect/gateway name = "gateway" - desc = "You're pretty sure that abyss is staring back" + desc = "You're pretty sure that abyss is staring back." icon = 'icons/obj/cult.dmi' icon_state = "hole" density = 1 diff --git a/code/game/gamemodes/cult/cultify/mob.dm b/code/game/gamemodes/cult/cultify/mob.dm index 154078de3d..14bb380a19 100644 --- a/code/game/gamemodes/cult/cultify/mob.dm +++ b/code/game/gamemodes/cult/cultify/mob.dm @@ -6,7 +6,7 @@ /mob/proc/cultify() return -/mob/dead/cultify() +/mob/observer/dead/cultify() if(icon_state != "ghost-narsie") icon = 'icons/mob/mob.dmi' icon_state = "ghost-narsie" @@ -21,7 +21,7 @@ C << "The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.
Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.
You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.
" dust() else if(client) - var/mob/dead/G = (ghostize()) + var/mob/observer/dead/G = (ghostize()) G.icon = 'icons/mob/mob.dmi' G.icon_state = "ghost-narsie" G.overlays = 0 diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm index a3248a07e5..ea866ad856 100644 --- a/code/game/gamemodes/cult/narsie.dm +++ b/code/game/gamemodes/cult/narsie.dm @@ -143,7 +143,7 @@ var/global/list/narsie_list = list() /obj/singularity/narsie/proc/narsiefloor(var/turf/T)//leaving "footprints" if(!(istype(T, /turf/simulated/wall/cult)||istype(T, /turf/space))) if(T.icon_state != "cult-narsie") - T.desc = "something that goes beyond your understanding went this way" + T.desc = "something that goes beyond your understanding went this way." T.icon = 'icons/turf/flooring/cult.dmi' T.icon_state = "cult-narsie" T.set_light(1) @@ -298,7 +298,7 @@ var/global/list/narsie_list = list() acquire(pick(cultists)) return //no living cultists, pick a living human instead. - for(var/mob/dead/observer/ghost in player_list) + for(var/mob/observer/dead/ghost in player_list) if(!ghost.client) continue var/turf/pos = get_turf(ghost) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index d8c41eea42..853d3f02dc 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -185,7 +185,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," throw_range = 5 w_class = 2.0 unique = 1 - var/notedat = "" var/tomedat = "" var/list/words = list("ire" = "ire", "ego" = "ego", "nahlizet" = "nahlizet", "certum" = "certum", "veri" = "veri", "jatkaa" = "jatkaa", "balaq" = "balaq", "mgar" = "mgar", "karazet" = "karazet", "geeri" = "geeri") @@ -285,57 +284,12 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," "} - - Topic(href,href_list[]) - if (src.loc == usr) - var/number = text2num(href_list["number"]) - if (usr.stat|| usr.restrained()) - return - switch(href_list["action"]) - if("clear") - words[words[number]] = words[number] - if("change") - words[words[number]] = input("Enter the translation for [words[number]]", "Word notes") in engwords - for (var/w in words) - if ((words[w] == words[words[number]]) && (w != words[number])) - words[w] = w - notedat = {" -
Word translation notes
- [words[1]] is [words[words[1]]]Clear
- [words[2]] is [words[words[2]]]Clear
- [words[3]] is [words[words[3]]]Clear
- [words[4]] is [words[words[4]]]Clear
- [words[5]] is [words[words[5]]]Clear
- [words[6]] is [words[words[6]]]Clear
- [words[7]] is [words[words[7]]]Clear
- [words[8]] is [words[words[8]]]Clear
- [words[9]] is [words[words[9]]]Clear
- [words[10]] is [words[words[10]]]Clear
- "} - usr << browse("[notedat]", "window=notes") -// call(/obj/item/weapon/book/tome/proc/edit_notes)() - else - usr << browse(null, "window=notes") - return - - -// proc/edit_notes() FUCK IT. Cant get it to work properly. - K0000 -// world << "its been called! [usr]" -// notedat = {" -//
Word translation notes
-// [words[1]] is [words[words[1]]]Clear
-// [words[2]] is [words[words[2]]]Clear
-// [words[3]] is [words[words[3]]]Clear
-// [words[4]] is [words[words[4]]]Clear
-// [words[5]] is [words[words[5]]]Clear
-// [words[6]] is [words[words[6]]]Clear
-// [words[7]] is [words[words[7]]]Clear
-// [words[8]] is [words[words[8]]]Clear
-// [words[9]] is [words[words[9]]]Clear
-// [words[10]] is [words[words[10]]]Clear
-// "} -// usr << "whatev" -// usr << browse(null, "window=tank") + New() + ..() + if(!cultwords["travel"]) + runerandom() + for(var/V in cultwords) + words[cultwords[V]] = V attack(mob/living/M as mob, mob/living/user as mob) @@ -343,8 +297,8 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," user.attack_log += text("\[[time_stamp()]\] Used [name] on [M.name] ([M.ckey])") msg_admin_attack("[user.name] ([user.ckey]) used [name] on [M.name] ([M.ckey]) (JMP)") - if(istype(M,/mob/dead)) - var/mob/dead/D = M + if(istype(M,/mob/observer/dead)) + var/mob/observer/dead/D = M D.manifest(user) return if(!istype(M)) @@ -378,7 +332,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," alert("The cloth of reality can't take that much of a strain. Remove some runes first!") return else - switch(alert("You open the tome",,"Read it","Scribe a rune", "Notes")) //Fuck the "Cancel" option. Rewrite the whole tome interface yourself if you want it to work better. And input() is just ugly. - K0000 + switch(alert("You open the tome",,"Read it","Scribe a rune", "Cancel")) if("Cancel") return if("Read it") @@ -386,25 +340,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," return user << browse("[tomedat]", "window=Arcane Tome") return - if("Notes") - if(usr.get_active_hand() != src) - return - notedat = {" -
Word translation notes
- [words[1]] is [words[words[1]]]Clear
- [words[2]] is [words[words[2]]]Clear
- [words[3]] is [words[words[3]]]Clear
- [words[4]] is [words[words[4]]]Clear
- [words[5]] is [words[words[5]]]Clear
- [words[6]] is [words[words[6]]]Clear
- [words[7]] is [words[words[7]]]Clear
- [words[8]] is [words[words[8]]]Clear
- [words[9]] is [words[words[9]]]Clear
- [words[10]] is [words[words[10]]]Clear
- "} -// call(/obj/item/weapon/book/tome/proc/edit_notes)() - user << browse("[notedat]", "window=notes") - return if(usr.get_active_hand() != src) return @@ -489,21 +424,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," user << "The book seems full of illegible scribbles. Is this a joke?" return - attackby(obj/item/weapon/book/tome/T as obj, mob/living/user as mob) - if(istype(T, /obj/item/weapon/book/tome)) // sanity check to prevent a runtime error - switch(alert("Copy the runes from your tome?",,"Copy", "Cancel")) - if("cancel") - return - // var/list/nearby = viewers(1,src) //- Fuck this as well. No clue why this doesnt work. -K0000 - // if (T.loc != user) - // return - // for(var/mob/M in nearby) - // if(M == user) - for(var/entry in words) - words[entry] = T.words[entry] - user << "You copy the translation notes from your tome." - - examine(mob/user) if(!iscultist(user)) user << "An old, dusty tome with frayed edges and a sinister looking cover." diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 7824debd8b..91d802c8bf 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -342,10 +342,11 @@ var/list/sacrificed = list() usr << "The sacrifical corpse is not dead. You must free it from this world of illusions before it may be used." return fizzle() - var/mob/dead/observer/ghost - for(var/mob/dead/observer/O in loc) + var/mob/observer/dead/ghost + for(var/mob/observer/dead/O in loc) if(!O.client) continue if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + if(!(O.client.prefs.be_special & BE_CULTIST)) continue ghost = O break @@ -423,7 +424,7 @@ var/list/sacrificed = list() L.ajourn=0 return else - L.take_organ_damage(10, 0) + L.take_organ_damage(3, 0) sleep(100) return fizzle() @@ -437,11 +438,12 @@ var/list/sacrificed = list() src = null if(usr.loc!=this_rune.loc) return this_rune.fizzle() - var/mob/dead/observer/ghost - for(var/mob/dead/observer/O in this_rune.loc) + var/mob/observer/dead/ghost + for(var/mob/observer/dead/O in this_rune.loc) if(!O.client) continue if(!O.MayRespawn()) continue if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue + if(!(O.client.prefs.be_special & BE_CULTIST)) continue ghost = O break if(!ghost) @@ -463,13 +465,11 @@ var/list/sacrificed = list() break D.universal_speak = 1 D.status_flags &= ~GODMODE - D.s_tone = 35 D.b_eyes = 200 D.r_eyes = 200 D.g_eyes = 200 D.update_eyes() - D.underwear_top = 0 - D.underwear_bottom = 0 + D.all_underwear.Cut() D.key = ghost.key cult.add_antagonist(D.mind) @@ -1051,7 +1051,7 @@ var/list/sacrificed = list() for(var/mob/living/L in viewers(src)) if(iscarbon(L)) var/mob/living/carbon/C = L - flick("e_flash", C.flash) + C.flash_eyes() if(C.stuttering < 1 && (!(HULK in C.mutations))) C.stuttering = 1 C.Weaken(1) @@ -1080,7 +1080,7 @@ var/list/sacrificed = list() admin_attack_log(usr, T, "Used a stun rune.", "Was victim of a stun rune.", "used a stun rune on") else if(iscarbon(T)) var/mob/living/carbon/C = T - flick("e_flash", C.flash) + C.flash_eyes() if (!(HULK in C.mutations)) C.silent += 15 C.Weaken(25) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/blob.dm b/code/game/gamemodes/endgame/supermatter_cascade/blob.dm index 2f12370f58..c25e3c5567 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/blob.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/blob.dm @@ -112,7 +112,7 @@ /turf/unsimulated/wall/supermatter/proc/Consume(var/mob/living/user) - if(istype(user,/mob/dead/observer)) + if(istype(user,/mob/observer)) return qdel(user) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index 3374f8f9be..d42d684d56 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -43,7 +43,7 @@ var/global/universe_has_ended = 0 world << sound('sound/effects/cascade.ogg') for(var/mob/M in player_list) - flick("e_flash", M.flash) + M.flash_eyes() if(emergency_shuttle.can_recall()) priority_announcement.Announce("The emergency shuttle has returned due to bluespace distortion.") @@ -122,6 +122,6 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked continue if(M.current.stat!=2) M.current.Weaken(10) - flick("e_flash", M.current.flash) + M.current.flash_eyes() clear_antag_roles(M) diff --git a/code/game/gamemodes/epidemic/epidemic.dm b/code/game/gamemodes/epidemic/epidemic.dm index 4f98bbcc2b..07b8d7f434 100644 --- a/code/game/gamemodes/epidemic/epidemic.dm +++ b/code/game/gamemodes/epidemic/epidemic.dm @@ -1,5 +1,5 @@ /datum/game_mode/epidemic - name = "epidemic" + name = "Epidemic" config_tag = "epidemic" required_players = 1 required_players_secret = 15 diff --git a/code/game/gamemodes/events/dust.dm b/code/game/gamemodes/events/dust.dm index 492b932e46..bb8e34364c 100644 --- a/code/game/gamemodes/events/dust.dm +++ b/code/game/gamemodes/events/dust.dm @@ -53,6 +53,7 @@ The "dust" will damage the hull of the station causin minor hull breaches. New() + ..() var/startx = 0 var/starty = 0 var/endy = 0 diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm index 0f7d6149d3..04404573e8 100644 --- a/code/game/gamemodes/events/power_failure.dm +++ b/code/game/gamemodes/events/power_failure.dm @@ -3,7 +3,7 @@ if(announce) command_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", new_sound = 'sound/AI/poweroff.ogg') - var/list/skipped_areas = list(/area/turret_protected/ai) + var/list/skipped_areas = list(/area/ai) for(var/obj/machinery/power/smes/S in world) var/area/current_area = get_area(S) @@ -24,7 +24,7 @@ C.cell.charge = 0 /proc/power_restore(var/announce = 1) - var/list/skipped_areas = list(/area/turret_protected/ai) + var/list/skipped_areas = list(/area/ai) if(announce) command_announcement.Announce("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = 'sound/AI/poweron.ogg') diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 073383ac20..2aa1d2b024 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -39,10 +39,6 @@ var/global/list/additional_antag_types = list() /datum/game_mode/New() ..() - // Enforce some formatting. - // This will probably break something. - name = capitalize(lowertext(name)) - config_tag = lowertext(config_tag) /datum/game_mode/Topic(href, href_list[]) if(..()) @@ -205,7 +201,6 @@ var/global/list/additional_antag_types = list() display_roundstart_logout_report() spawn (rand(waittime_l, waittime_h)) - send_intercept() spawn(rand(100,150)) announce_ert_disabled() @@ -377,56 +372,6 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere. return 0 -/datum/game_mode/proc/send_intercept() - - var/intercepttext = "Cent. Com. Update Requested status information:
" - intercepttext += " In case you have misplaced your copy, attached is a list of personnel whom reliable sources™ suspect may be affiliated with subversive elements:
" - - var/list/disregard_roles = list() - for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] - if(antag.flags & ANTAG_SUSPICIOUS) - disregard_roles |= antag.role_text - - var/list/suspects = list() - for(var/mob/living/carbon/human/man in player_list) if(man.client && man.mind) - - // NT relation option - var/special_role = man.mind.special_role - var/datum/antagonist/special_role_data = get_antag_data(special_role) - - if (special_role in disregard_roles) - continue - else if(man.client.prefs.nanotrasen_relation == COMPANY_OPPOSED && prob(50) || \ - man.client.prefs.nanotrasen_relation == COMPANY_SKEPTICAL && prob(20)) - suspects += man - // Antags - else if(special_role_data && prob(special_role_data.suspicion_chance)) - suspects += man - - // Some poor people who were just in the wrong place at the wrong time.. - else if(prob(10)) - suspects += man - - for(var/mob/M in suspects) - if(player_is_antag(M.mind, only_offstation_roles = 1)) - continue - switch(rand(1, 100)) - if(1 to 50) - intercepttext += "Someone with the job of [M.mind.assigned_role]
" - else - intercepttext += "[M.name], the [M.mind.assigned_role]
" - - for (var/obj/machinery/computer/communications/comm in machines) - if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) - var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) - intercept.name = "Cent. Com. Status Summary" - intercept.info = intercepttext - - comm.messagetitle.Add("Cent. Com. Status Summary") - comm.messagetext.Add(intercepttext) - world << sound('sound/AI/commandreport.ogg') - /datum/game_mode/proc/get_players_for_role(var/role, var/antag_id) var/list/players = list() var/list/candidates = list() @@ -537,7 +482,7 @@ proc/display_roundstart_logout_report() continue //Dead continue //Happy connected client - for(var/mob/dead/observer/D in mob_list) + for(var/mob/observer/dead/D in mob_list) if(D.mind && (D.mind.original == L || D.mind.current == L)) if(L.stat == DEAD) if(L.suiciding) //Suicider @@ -571,25 +516,10 @@ proc/get_nt_opposed() if(dudes.len == 0) return null return pick(dudes) -//Announces objectives/generic antag text. -/proc/show_generic_antag_text(var/datum/mind/player) - if(player.current) - player.current << \ - "You are an antagonist! Within the rules, \ - try to act as an opposing force to the crew. Further RP and try to make sure \ - other players have fun! If you are confused or at a loss, always adminhelp, \ - and before taking extreme actions, please try to also contact the administration! \ - Think through your actions and make the roleplay immersive! Please remember all \ - rules aside from those without explicit exceptions apply to antagonists." - /proc/show_objectives(var/datum/mind/player) if(!player || !player.current) return - if(config.objectives_disabled) - show_generic_antag_text(player) - return - var/obj_count = 1 player.current << "Your current objectives:" for(var/datum/objective/objective in player.objectives) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index b112fae4a0..4c390e7c69 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -112,7 +112,7 @@ var/global/datum/controller/gameticker/ticker tmpmodes+=M.name tmpmodes = sortList(tmpmodes) if(tmpmodes.len) - world << "Possibilities: [english_list(tmpmodes)]" + world << "Possibilities: [english_list(tmpmodes, and_text= "; ", comma_text = "; ")]" else src.mode.announce() @@ -387,8 +387,8 @@ var/global/datum/controller/gameticker/ticker else Player << "You missed the crew transfer after the events on [station_name()] as [Player.real_name]." else - if(istype(Player,/mob/dead/observer)) - var/mob/dead/observer/O = Player + if(istype(Player,/mob/observer/dead)) + var/mob/observer/dead/O = Player if(!O.started_as_observer) Player << "You did not survive the events on [station_name()]..." else diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 39b73a8dac..f91191fac5 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -5,13 +5,13 @@ VOX HEIST ROUNDTYPE var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective. Clumsy, rewrite sometime. /datum/game_mode/heist - name = "heist" + name = "Heist" config_tag = "heist" required_players = 15 required_players_secret = 15 required_enemies = 4 round_description = "An unidentified bluespace signature is approaching the station!" - extended_round_description = "The Company's majority control of phoron in Vir has marked the \ + extended_round_description = "The Company's majority control of phoron in "+starsys_name+" has marked the \ station to be a highly valuable target for many competing organizations and individuals. Being a \ colony of sizable population and considerable wealth causes it to often be the target of various \ attempts of robbery, fraud and other malicious actions." diff --git a/code/game/gamemodes/malfunction/malf_hardware.dm b/code/game/gamemodes/malfunction/malf_hardware.dm index b33a5e49d8..864ba0722d 100644 --- a/code/game/gamemodes/malfunction/malf_hardware.dm +++ b/code/game/gamemodes/malfunction/malf_hardware.dm @@ -60,11 +60,6 @@ /datum/malf_hardware/strong_turrets/install() ..() - for(var/obj/machinery/turret/T in machines) - T.maxhealth = round(initial(T.maxhealth) * 1.4) - T.shot_delay = round(initial(T.shot_delay) / 2) - T.auto_repair = 1 - T.active_power_usage = round(initial(T.active_power_usage) * 5) for(var/obj/machinery/porta_turret/T in machines) T.maxhealth = round(initial(T.maxhealth) * 1.4) T.shot_delay = round(initial(T.shot_delay) / 2) diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index 558dbe12b6..de868328b3 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -1,5 +1,5 @@ /datum/game_mode/malfunction - name = "AI malfunction" + name = "AI Malfunction" round_description = "The AI is behaving abnormally and must be stopped." extended_round_description = "The AI will attempt to hack the APCs around the station in order to gain as much control as possible." config_tag = "malfunction" diff --git a/code/game/gamemodes/mixed/conflux.dm b/code/game/gamemodes/mixed/conflux.dm index 2d8753ce1a..0e9513bbab 100644 --- a/code/game/gamemodes/mixed/conflux.dm +++ b/code/game/gamemodes/mixed/conflux.dm @@ -1,5 +1,5 @@ /datum/game_mode/conflux - name = "conflux" + name = "Wizard & Cult" round_description = "A space wizard and a cult have invaded the station!" extended_round_description = "Cultists and wizards spawn during this round." config_tag = "conflux" diff --git a/code/game/gamemodes/mixed/infestation.dm b/code/game/gamemodes/mixed/infestation.dm index 346f51967c..34bd062b80 100644 --- a/code/game/gamemodes/mixed/infestation.dm +++ b/code/game/gamemodes/mixed/infestation.dm @@ -1,5 +1,5 @@ /datum/game_mode/infestation - name = "infestation" + name = "Borers & Changelings" round_description = "There's something in the walls!" extended_round_description = "Two alien antagonists (Cortical Borers or Changelings) spawn during this round." config_tag = "infestation" diff --git a/code/game/gamemodes/mixed/intrigue.dm b/code/game/gamemodes/mixed/intrigue.dm new file mode 100644 index 0000000000..5c432c30db --- /dev/null +++ b/code/game/gamemodes/mixed/intrigue.dm @@ -0,0 +1,12 @@ +/datum/game_mode/intrigue + name = "Traitors & Ninja" + round_description = "Crewmembers are contacted by external elements while another infiltrates the colony." + extended_round_description = "Traitors and a ninja spawn during this round." + config_tag = "intrigue" + required_players = 6 + required_players_secret = 8 + required_enemies = 3 + end_on_antag_death = 0 + antag_tags = list(MODE_NINJA, MODE_AUTOTRAITOR) + round_autoantag = 1 + require_all_templates = 1 \ No newline at end of file diff --git a/code/game/gamemodes/mixed/lizard.dm b/code/game/gamemodes/mixed/lizard.dm new file mode 100644 index 0000000000..3323db503b --- /dev/null +++ b/code/game/gamemodes/mixed/lizard.dm @@ -0,0 +1,11 @@ +/datum/game_mode/lizard + name = "Wizard & Changelings" + round_description = "A space wizard and changelings have invaded the station!" + extended_round_description = "Changelings and a wizard spawn during this round." + config_tag = "lizard" + required_players = 2 + required_players_secret = 8 + required_enemies = 3 + end_on_antag_death = 0 + antag_tags = list(MODE_WIZARD, MODE_CHANGELING) + require_all_templates = 1 \ No newline at end of file diff --git a/code/game/gamemodes/mixed/mercrenegade.dm b/code/game/gamemodes/mixed/mercrenegade.dm new file mode 100644 index 0000000000..37ef6b76d9 --- /dev/null +++ b/code/game/gamemodes/mixed/mercrenegade.dm @@ -0,0 +1,11 @@ +/datum/game_mode/mercren + name = "Mercenaries & Renegades" + round_description = "A mercenary team has invaded the station, as well as other having brought their own form protection." + extended_round_description = "Mercenaries and traitors spawn during this round." + config_tag = "mercren" + required_players = 16 //What could possibly go wrong? + required_players_secret = 15 + required_enemies = 8 + end_on_antag_death = 0 + antag_tags = list(MODE_MERCENARY, MODE_RENEGADE) + require_all_templates = 1 \ No newline at end of file diff --git a/code/game/gamemodes/mixed/mercwiz.dm b/code/game/gamemodes/mixed/mercwiz.dm new file mode 100644 index 0000000000..af3629bfef --- /dev/null +++ b/code/game/gamemodes/mixed/mercwiz.dm @@ -0,0 +1,11 @@ +/datum/game_mode/mercwiz + name = "Mercenaries & Wizard" + round_description = "A mercenary team and a wizard have invaded the station!" + extended_round_description = "Mercenaries and wizard spawn during this round." + config_tag = "mercwiz" + required_players = 15 //I don't think we can have it lower and not need an ERT every round. + required_players_secret = 15 //I don't think we can have it lower and not need an ERT every round. + required_enemies = 7 + end_on_antag_death = 0 + antag_tags = list(MODE_MERCENARY, MODE_WIZARD) + require_all_templates = 1 \ No newline at end of file diff --git a/code/game/gamemodes/mixed/paranoia.dm b/code/game/gamemodes/mixed/paranoia.dm index 7c3e903b14..cda62701a0 100644 --- a/code/game/gamemodes/mixed/paranoia.dm +++ b/code/game/gamemodes/mixed/paranoia.dm @@ -1,5 +1,5 @@ /datum/game_mode/paranoia - name = "paranoia" + name = "Malf AI, Renegades & Changelings" round_description = "The AI has malfunctioned, and subversive elements infest the crew..." extended_round_description = "Rampant AIs, renegades and changelings spawn in this mode." config_tag = "paranoia" diff --git a/code/game/gamemodes/mixed/traitorling.dm b/code/game/gamemodes/mixed/traitorling.dm index 4eb4b6c77a..1ae93d7d38 100644 --- a/code/game/gamemodes/mixed/traitorling.dm +++ b/code/game/gamemodes/mixed/traitorling.dm @@ -1,5 +1,5 @@ /datum/game_mode/traitorling - name = "traitorling" + name = "Traitors & Changelings" round_description = "There are traitors and alien changelings on the station. Do not let the changelings succeed!" extended_round_description = "Traitors and changelings both spawn during this mode." config_tag = "traitorling" diff --git a/code/game/gamemodes/mixed/traitorrenegade.dm b/code/game/gamemodes/mixed/traitorrenegade.dm new file mode 100644 index 0000000000..c69f67c02a --- /dev/null +++ b/code/game/gamemodes/mixed/traitorrenegade.dm @@ -0,0 +1,11 @@ +/datum/game_mode/traitorren + name = "Traitors & Renegades" + round_description = "Subversive elements have invaded the station, and certain individuals are feeling uncertain about their safety." + extended_round_description = "Traitors and renegades spawn during this round." + config_tag = "traitorren" + required_players = 11 //I don't think we can have it lower and not need an ERT every round. + required_players_secret = 11 //I don't think we can have it lower and not need an ERT every round. + required_enemies = 4 + end_on_antag_death = 0 + antag_tags = list(MODE_AUTOTRAITOR, MODE_RENEGADE) + require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/uprising.dm b/code/game/gamemodes/mixed/uprising.dm index 005d9dce91..d557cfc075 100644 --- a/code/game/gamemodes/mixed/uprising.dm +++ b/code/game/gamemodes/mixed/uprising.dm @@ -1,5 +1,5 @@ /datum/game_mode/uprising - name = "uprising" + name = "Revolution & Cult" config_tag = "uprising" round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!" extended_round_description = "Cultists and revolutionaries spawn in this round." diff --git a/code/game/gamemodes/mixed/visitors.dm b/code/game/gamemodes/mixed/visitors.dm new file mode 100644 index 0000000000..853e5039d4 --- /dev/null +++ b/code/game/gamemodes/mixed/visitors.dm @@ -0,0 +1,11 @@ +/datum/game_mode/visitors + name = "Wizard & Ninja" + round_description = "A space wizard and a ninja have invaded the station!" + extended_round_description = "A ninja and wizard spawn during this round." + config_tag = "visitors" + required_players = 8 + required_players_secret = 8 + required_enemies = 2 + end_on_antag_death = 0 + antag_tags = list(MODE_WIZARD, MODE_NINJA) + require_all_templates = 1 \ No newline at end of file diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 40f59026bf..480c69d27f 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -1,5 +1,5 @@ /datum/game_mode/ninja - name = "ninja" + name = "Ninja" round_description = "An agent of the Spider Clan is onboard the station!" extended_round_description = "What was that?! Was that a person or did your eyes just play tricks on you? \ You have no idea. That slim-suited, cryptic individual is an enigma to you and all of your knowledge. \ @@ -10,7 +10,7 @@ only hope this unknown assassin isn't here for you." config_tag = "ninja" required_players = 1 - required_players_secret = 8 + required_players_secret = 6 required_enemies = 1 end_on_antag_death = 0 antag_tags = list(MODE_NINJA) \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 3393373d7b..5f268bba16 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -7,7 +7,7 @@ var/list/nuke_disks = list() /datum/game_mode/nuclear name = "Mercenary" round_description = "A mercenary strike force is approaching the station!" - extended_round_description = "The Company's majority control of phoron in Vir has marked the \ + extended_round_description = "The Company's majority control of phoron in "+starsys_name+" has marked the \ station to be a highly valuable target for many competing organizations and individuals. Being a \ colony of sizable population and considerable wealth causes it to often be the target of various \ attempts of robbery, fraud and other malicious actions." diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 6b373953b1..f5dd1efe5f 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -12,6 +12,7 @@ datum/objective all_objectives |= src if(text) explanation_text = text + ..() Destroy() all_objectives -= src diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 45f88d3b05..98fc360160 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -3,10 +3,10 @@ config_tag = "revolution" round_description = "Some crewmembers are attempting to start a revolution!" extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." - required_players = 15 - required_players_secret = 15 + required_players = 12 //should be enough for a decent manifest, hopefully + required_players_secret = 12 //pretty sure rev doesn't even appear in secret required_enemies = 3 - auto_recall_shuttle = 0 //NO THANKS + auto_recall_shuttle = 0 //un-wanted on polaris end_on_antag_death = 0 shuttle_delay = 3 antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST) diff --git a/code/game/gamemodes/sandbox/sandbox.dm b/code/game/gamemodes/sandbox/sandbox.dm index a96c7c7639..a9641dabd2 100644 --- a/code/game/gamemodes/sandbox/sandbox.dm +++ b/code/game/gamemodes/sandbox/sandbox.dm @@ -1,5 +1,5 @@ /datum/game_mode/sandbox - name = "sandbox" + name = "Sandbox" config_tag = "sandbox" required_players = 0 votable = 0 diff --git a/code/game/gamemodes/technomancer/core_obj.dm b/code/game/gamemodes/technomancer/core_obj.dm index e3ae8d19c9..5942eb9a8b 100644 --- a/code/game/gamemodes/technomancer/core_obj.dm +++ b/code/game/gamemodes/technomancer/core_obj.dm @@ -189,9 +189,6 @@ return 1 return 0 -/mob - var/obj/screen/wizard/energy/wiz_energy_display = null //Unfortunately, this needs to be a mob var due to HUD code. - /mob/living/carbon/human/proc/wiz_energy_update_hud() if(client && hud_used) if(istype(back, /obj/item/weapon/technomancer_core)) //I reckon there's a better way of doing this. diff --git a/code/game/gamemodes/technomancer/instability.dm b/code/game/gamemodes/technomancer/instability.dm index ea0efd77a6..587ec16147 100644 --- a/code/game/gamemodes/technomancer/instability.dm +++ b/code/game/gamemodes/technomancer/instability.dm @@ -1,6 +1,3 @@ -/mob - var/obj/screen/wizard/instability/wiz_instability_display = null //Unfortunately, this needs to be a mob var due to HUD code. - /mob/living var/instability = 0 var/last_instability_event = null // most recent world.time that something bad happened due to instability. diff --git a/code/game/gamemodes/technomancer/spells/control.dm b/code/game/gamemodes/technomancer/spells/control.dm index 638f4359d2..0014d26af7 100644 --- a/code/game/gamemodes/technomancer/spells/control.dm +++ b/code/game/gamemodes/technomancer/spells/control.dm @@ -54,10 +54,8 @@ if(istype(L, /mob/living/simple_animal)) var/mob/living/simple_animal/SA = L SA.ai_inactive = 1 - if(istype(SA, /mob/living/simple_animal/hostile)) - var/mob/living/simple_animal/hostile/SAH = SA - SAH.friends |= src.owner - SAH.stance = HOSTILE_STANCE_IDLE + SA.friends |= src.owner + SA.stance = STANCE_IDLE L.overlays |= control_overlay controlled_mobs |= L @@ -81,12 +79,10 @@ if(living.stat) deselect(living) continue - if(istype(living, /mob/living/simple_animal/hostile)) - var/mob/living/simple_animal/hostile/SAH = living - SAH.target_mob = null - SAH.stance = HOSTILE_STANCE_IDLE if(istype(living, /mob/living/simple_animal)) var/mob/living/simple_animal/SA = living + SA.target_mob = null + SA.stance = STANCE_IDLE walk_towards(SA,T,SA.speed) else walk_towards(living,T,5) diff --git a/code/game/gamemodes/technomancer/spells/resurrect.dm b/code/game/gamemodes/technomancer/spells/resurrect.dm index 9aacbcf5be..573dba8515 100644 --- a/code/game/gamemodes/technomancer/spells/resurrect.dm +++ b/code/game/gamemodes/technomancer/spells/resurrect.dm @@ -41,7 +41,7 @@ var/mob/living/carbon/human/H = L if(!H.client && H.mind) //Don't force the dead person to come back if they don't want to. - for(var/mob/dead/observer/ghost in player_list) + for(var/mob/observer/dead/ghost in player_list) if(ghost.mind == H.mind) ghost << "The Technomancer [user.real_name] is trying to \ revive you. Return to your body if you want to be resurrected! \ diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index ee56b9070a..c4b5d787a4 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -1,7 +1,7 @@ /datum/game_mode/traitor name = "traitor" round_description = "There is a foreign agent or traitor on the station. Do not let the traitor succeed!" - extended_round_description = "The Company's majority control of phoron in Vir has marked the \ + extended_round_description = "The Company's majority control of phoron in "+starsys_name+" has marked the \ station to be a highly valuable target for many competing organizations and individuals. The varied pasts \ and experiences of your coworkers have left them susceptible to the vices and temptations of humanity. \ Is the station the safe self-contained workplace you once thought it was, or has it become a playground \ @@ -21,6 +21,7 @@ /datum/game_mode/traitor/auto name = "autotraitor" config_tag = "autotraitor" + antag_tags = list(MODE_AUTOTRAITOR) round_autoantag = 1 required_players_secret = 3 antag_scaling_coeff = 5 diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 0cc48203c5..9da98075f3 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -4,7 +4,7 @@ extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station." config_tag = "wizard" required_players = 1 - required_players_secret = 8 + required_players_secret = 6 required_enemies = 1 end_on_antag_death = 0 antag_tags = list(MODE_WIZARD) diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm index 19a578b355..5e2b40d952 100644 --- a/code/game/jobs/job/assistant.dm +++ b/code/game/jobs/job/assistant.dm @@ -7,27 +7,22 @@ total_positions = -1 spawn_positions = -1 supervisors = "absolutely everyone" - selection_color = "#dddddd" + selection_color = "#515151" economic_modifier = 1 access = list() //See /datum/job/assistant/get_access() minimal_access = list() //See /datum/job/assistant/get_access() alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor", "Resident") -/datum/job/assistant/equip(var/mob/living/carbon/human/H) +/datum/job/assistant/equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Visitor") //I doubt someone visiting the station would want to wear an ugly grey uniform - H.equip_to_slot_or_del(new /obj/item/clothing/under/assistantformal(H), slot_w_uniform) - - if("Resident") - H.equip_to_slot_or_del(new /obj/item/clothing/under/color/white(H), slot_w_uniform) - else - H.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(H), slot_w_uniform) + if(has_alt_title(H, alt_title,"Visitor")) //I doubt someone visiting the station would want to wear an ugly grey uniform + H.equip_to_slot_or_del(new /obj/item/clothing/under/assistantformal(H), slot_w_uniform) + else if(has_alt_title(H, alt_title,"Resident")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/color/white(H), slot_w_uniform) else H.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 5ac35742b2..0551df6c3c 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -10,7 +10,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) total_positions = 1 spawn_positions = 1 supervisors = "company officials and Corporate Regulations" - selection_color = "#ccccff" + selection_color = "#1D1D4F" alt_titles = list("Station Administrator") idtype = /obj/item/weapon/card/id/gold req_admin_notify = 1 @@ -19,6 +19,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) minimal_player_age = 14 economic_modifier = 20 + minimum_character_age = 25 ideal_character_age = 70 // Old geezer captains ftw @@ -27,12 +28,19 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/captain(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_cap(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/cap(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - var/obj/item/clothing/under/U = new /obj/item/clothing/under/rank/captain(H) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/captain(H), slot_w_uniform) if(H.age>49) - U.accessories += new /obj/item/clothing/accessory/medal/gold/captain(U) - H.equip_to_slot_or_del(U, slot_w_uniform) + // Since we can have something other than the default uniform at this + // point, check if we can actually attach the medal + var/obj/item/clothing/uniform = H.w_uniform + var/obj/item/clothing/accessory/medal/gold/captain/medal = new() + + if(uniform && uniform.can_attach_accessory(medal)) + uniform.attach_accessory(null, medal) + else + qdel(medal) H.equip_to_slot_or_del(new /obj/item/device/pda/captain(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/clothing/head/caphat(H), slot_head) @@ -43,7 +51,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H.back), slot_in_backpack) - H.implant_loyalty(src) + H.implant_loyalty() return 1 @@ -62,11 +70,13 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ddddff" + selection_color = "#2F2F7F" idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 10 economic_modifier = 10 + + minimum_character_age = 25 ideal_character_age = 50 access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers, @@ -88,7 +98,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/hop(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/head_of_personnel(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes) @@ -97,4 +107,5 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H), slot_l_hand) else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H.back), slot_in_backpack) - return 1 + H.implant_loyalty() + return 1 \ No newline at end of file diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index 98661a9c4f..c02048450b 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -8,7 +8,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_hydroponics, access_bar, access_kitchen) minimal_access = list(access_bar) alt_titles = list("Barista") @@ -18,7 +19,7 @@ if(!H) return 0 switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_service(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) @@ -37,7 +38,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_hydroponics, access_bar, access_kitchen) minimal_access = list(access_kitchen) alt_titles = list("Cook") @@ -64,7 +66,8 @@ total_positions = 2 spawn_positions = 1 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_hydroponics, access_bar, access_kitchen) minimal_access = list(access_hydroponics) alt_titles = list("Hydroponicist") @@ -81,7 +84,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/botanist(H), slot_belt) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/hydroponics(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_hyd(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/hyd(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) return 1 @@ -97,7 +100,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/cargo/head economic_modifier = 5 access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) @@ -127,7 +131,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "the quartermaster and the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/cargo access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting) @@ -152,7 +157,8 @@ total_positions = 3 spawn_positions = 3 supervisors = "the quartermaster and the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/cargo economic_modifier = 5 access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) minimal_access = list(access_mining, access_mining_station, access_mailsorting) @@ -163,7 +169,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_cargo (H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/industrial(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_eng(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/eng(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/miner(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/device/pda/shaftminer(H), slot_belt) @@ -188,12 +194,14 @@ department = "Civilian" department_flag = CIVILIAN faction = "Station" - total_positions = 1 - spawn_positions = 1 + total_positions = 2 + spawn_positions = 2 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_janitor, access_maint_tunnels) minimal_access = list(access_janitor, access_maint_tunnels) + alt_titles = list("Custodian") equip(var/mob/living/carbon/human/H) @@ -216,7 +224,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_library, access_maint_tunnels) minimal_access = list(access_library) alt_titles = list("Journalist") @@ -242,7 +251,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "company officials and Corporate Regulations" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian economic_modifier = 7 access = list(access_lawyer, access_sec_doors, access_maint_tunnels, access_heads) minimal_access = list(access_lawyer, access_sec_doors, access_heads) @@ -253,7 +263,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/ia(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/internalaffairs(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/internalaffairs(H), slot_wear_suit) @@ -262,7 +272,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/lawyer(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase(H), slot_l_hand) - H.implant_loyalty(H) + H.implant_loyalty() return 1 diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm index a9f441dd22..9ce0e2b811 100644 --- a/code/game/jobs/job/civilian_chaplain.dm +++ b/code/game/jobs/job/civilian_chaplain.dm @@ -8,13 +8,14 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" - selection_color = "#dddddd" + selection_color = "#515151" + idtype = /obj/item/weapon/card/id/civilian access = list(access_morgue, access_chapel_office, access_crematorium, access_maint_tunnels) minimal_access = list(access_morgue, access_chapel_office, access_crematorium) alt_titles = list("Counselor") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title, var/ask_questions = TRUE) if(!H) return 0 var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(H) //BS12 EDIT @@ -22,6 +23,10 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chaplain(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/device/pda/chaplain(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) + if(!ask_questions) + return 1 + + spawn(0) var/religion_name = "Christianity" var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Christianity, in SPACE.", "Name change", religion_name), MAX_NAME_LEN) @@ -150,3 +155,6 @@ feedback_set_details("religion_deity","[new_deity]") feedback_set_details("religion_book","[new_book_style]") return 1 + +/datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title) + return equip(H, alt_title, FALSE) diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index 20a5c1e5d1..6940cd57c9 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -8,11 +8,12 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffeeaa" - idtype = /obj/item/weapon/card/id/silver + selection_color = "#7F6E2C" + idtype = /obj/item/weapon/card/id/engineering/head req_admin_notify = 1 economic_modifier = 10 + minimum_character_age = 25 ideal_character_age = 50 @@ -32,7 +33,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/ce(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/industrial(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_eng(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/eng(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chief_engineer(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/device/pda/heads/ce(H), slot_l_store) @@ -57,7 +58,8 @@ total_positions = 5 spawn_positions = 5 supervisors = "the chief engineer" - selection_color = "#fff5cc" + selection_color = "#5B4D20" + idtype = /obj/item/weapon/card/id/engineering economic_modifier = 5 access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics) minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction) @@ -69,7 +71,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/industrial(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_eng(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/eng(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/engineer(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/workboots(H), slot_shoes) @@ -94,7 +96,8 @@ total_positions = 3 spawn_positions = 2 supervisors = "the chief engineer" - selection_color = "#fff5cc" + selection_color = "#5B4D20" + idtype = /obj/item/weapon/card/id/engineering economic_modifier = 5 access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_external_airlocks) minimal_access = list(access_eva, access_engine, access_atmospherics, access_maint_tunnels, access_emergency_storage, access_construction, access_external_airlocks) @@ -105,7 +108,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/atmospheric_technician(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/workboots(H), slot_shoes) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 3df9569247..6bdf3c1c4a 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -31,7 +31,7 @@ /datum/job/proc/equip_backpack(var/mob/living/carbon/human/H) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) /datum/job/proc/equip_survival(var/mob/living/carbon/human/H) @@ -71,8 +71,8 @@ H << "Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]" // overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/del() -/datum/job/proc/equip_preview(mob/living/carbon/human/H) - return equip(H) +/datum/job/proc/equip_preview(mob/living/carbon/human/H, var/alt_title) + . = equip(H, alt_title) /datum/job/proc/get_access() if(!config || config.jobs_have_minimal_access) @@ -104,3 +104,6 @@ /datum/job/proc/is_position_available() return (current_positions < total_positions) || (total_positions == -1) + +/datum/job/proc/has_alt_title(var/mob/H, var/supplied_title, var/desired_title) + return (supplied_title == desired_title) || (H.mind && H.mind.role_alt_title == desired_title) \ No newline at end of file diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index cced0b79b3..32fd340755 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -8,8 +8,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffddf0" - idtype = /obj/item/weapon/card/id/silver + selection_color = "#026865" + idtype = /obj/item/weapon/card/id/medical/head req_admin_notify = 1 economic_modifier = 10 access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads, @@ -19,15 +19,16 @@ access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels) + minimum_character_age = 25 minimal_player_age = 10 ideal_character_age = 50 - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/cmo(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_med(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/med(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chief_medical_officer(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes) @@ -46,50 +47,49 @@ total_positions = 5 spawn_positions = 3 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#013D3B" + idtype = /obj/item/weapon/card/id/medical economic_modifier = 7 access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_eva) minimal_access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_virology, access_eva) alt_titles = list("Surgeon","Emergency Physician","Nurse","Virologist") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/adv(H), slot_l_hand) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_med(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/med(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Emergency Physician") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) - if("Surgeon") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/blue(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/head/surgery/blue(H), slot_head) - if("Virologist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/virologist(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(H), slot_wear_mask) - switch(H.backbag) - if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/virology(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_vir(H), slot_back) - if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if("Medical Doctor") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) - if("Nurse") - if(H.gender == FEMALE) - if(prob(50)) - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nursesuit(H), slot_w_uniform) - else - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nurse(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/head/nursehat(H), slot_head) - else - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/purple(H), slot_w_uniform) + if(has_alt_title(H, alt_title,"Emergency Physician")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Surgeon")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/blue(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/surgery/blue(H), slot_head) + else if(has_alt_title(H, alt_title,"Virologist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/virologist(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(H), slot_wear_mask) + switch(H.backbag) + if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/virology(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/vir(H), slot_back) + if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) + else if(has_alt_title(H, alt_title,"Medical Doctor")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Nurse")) + if(H.gender == FEMALE) + if(prob(50)) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nursesuit(H), slot_w_uniform) + else + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/nurse(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/head/nursehat(H), slot_head) + else + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/purple(H), slot_w_uniform) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) @@ -109,7 +109,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#013D3B" + idtype = /obj/item/weapon/card/id/medical economic_modifier = 5 access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) minimal_access = list(access_medical, access_medical_equip, access_chemistry) @@ -124,7 +125,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/chemist(H), slot_belt) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/chemistry(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_chem(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/chem(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/chemist(H), slot_wear_suit) return 1 @@ -140,7 +141,7 @@ total_positions = 0 spawn_positions = 0 supervisors = "the chief medical officer and research director" - selection_color = "#ffeef0" + selection_color = "#013D3B" economic_modifier = 7 access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_research) minimal_access = list(access_medical, access_morgue, access_genetics, access_research) @@ -153,7 +154,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/geneticist(H), slot_belt) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/genetics(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_gen(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/gen(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/genetics(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/device/flashlight/pen(H), slot_s_store) @@ -170,24 +171,23 @@ spawn_positions = 1 economic_modifier = 5 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#013D3B" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_medical_equip, access_morgue, access_psychiatrist) minimal_access = list(access_medical, access_medical_equip, access_psychiatrist) alt_titles = list("Psychologist") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Psychiatrist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych(H), slot_w_uniform) - if("Psychologist") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych/turtleneck(H), slot_w_uniform) + if(has_alt_title(H, alt_title,"Psychiatrist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych(H), slot_w_uniform) + else if(has_alt_title(H, alt_title,"Psychologist")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/psych/turtleneck(H), slot_w_uniform) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes) @@ -204,29 +204,28 @@ total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#013D3B" + idtype = /obj/item/weapon/card/id/medical economic_modifier = 4 access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_eva, access_maint_tunnels, access_external_airlocks, access_psychiatrist) minimal_access = list(access_medical, access_medical_equip, access_morgue, access_eva, access_maint_tunnels, access_external_airlocks) alt_titles = list("Emergency Medical Technician") - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_med(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/adv(H), slot_l_hand) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_med(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/med(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) - if (H.mind.role_alt_title) - switch(H.mind.role_alt_title) - if("Emergency Medical Technician") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/paramedic(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) - if("Paramedic") - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/black(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + if(has_alt_title(H, alt_title,"Emergency Medical Technician")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/paramedic(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) + else if(has_alt_title(H, alt_title,"Paramedic")) + H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/black(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/fr_jacket(H), slot_wear_suit) else H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/medical/emt(H), slot_belt) diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index f5b1f4ed29..7055aa7cb3 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -8,8 +8,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffddff" - idtype = /obj/item/weapon/card/id/silver + selection_color = "#AD6BAD" + idtype = /obj/item/weapon/card/id/science/head req_admin_notify = 1 economic_modifier = 15 access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue, @@ -21,6 +21,7 @@ access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage, access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch) + minimum_character_age = 25 minimal_player_age = 14 ideal_character_age = 50 @@ -33,7 +34,7 @@ H.equip_to_slot_or_del(new /obj/item/weapon/clipboard(H), slot_l_hand) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/toxins(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_tox(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/tox(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) return 1 @@ -49,7 +50,8 @@ total_positions = 5 spawn_positions = 3 supervisors = "the research director" - selection_color = "#ffeeff" + selection_color = "#633D63" + idtype = /obj/item/weapon/card/id/science economic_modifier = 7 access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch) minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch) @@ -65,7 +67,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/science(H), slot_belt) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/toxins(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_tox(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/tox(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/science(H), slot_wear_suit) return 1 @@ -79,7 +81,8 @@ total_positions = 3 spawn_positions = 2 supervisors = "the research director" - selection_color = "#ffeeff" + selection_color = "#633D63" + idtype = /obj/item/weapon/card/id/science economic_modifier = 7 access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_hydroponics) minimal_access = list(access_research, access_xenobiology, access_hydroponics, access_tox_storage) @@ -95,7 +98,7 @@ H.equip_to_slot_or_del(new /obj/item/device/pda/science(H), slot_belt) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/toxins(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_tox(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/tox(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat/science(H), slot_wear_suit) return 1 @@ -109,7 +112,8 @@ total_positions = 2 spawn_positions = 2 supervisors = "research director" - selection_color = "#ffeeff" + selection_color = "#633D63" + idtype = /obj/item/weapon/card/id/science economic_modifier = 5 access = list(access_robotics, access_tox, access_tox_storage, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access. minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access. @@ -121,10 +125,10 @@ if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sci(H), slot_l_ear) if(H.backbag == 2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(H.backbag == 3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(H.backbag == 3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/roboticist(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/device/pda/roboticist(H), slot_belt) - H.equip_to_slot_or_del(new /obj/item/weapon/storage/toolbox/mechanical(H), slot_l_hand) + H.equip_to_slot_or_del(new /obj/item/device/pda/roboticist(H), slot_r_store) + H.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/toggle/labcoat(H), slot_wear_suit) - return 1 \ No newline at end of file + return 1 diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index cc09386234..04adecc322 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -8,8 +8,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffdddd" - idtype = /obj/item/weapon/card/id/silver + selection_color = "#8E2929" + idtype = /obj/item/weapon/card/id/security/head req_admin_notify = 1 economic_modifier = 10 access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, @@ -20,13 +20,14 @@ access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers, access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks) + minimum_character_age = 25 minimal_player_age = 14 equip(var/mob/living/carbon/human/H) if(!H) return 0 switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_sec(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/sec(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/hos(H), slot_l_ear) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/head_of_security(H), slot_w_uniform) @@ -40,7 +41,7 @@ H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_l_store) else H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_in_backpack) - H.implant_loyalty(H) + H.implant_loyalty() return 1 @@ -54,7 +55,8 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of security" - selection_color = "#ffeeee" + selection_color = "#601C1C" + idtype = /obj/item/weapon/card/id/security economic_modifier = 5 access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_morgue, access_external_airlocks) minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_external_airlocks) @@ -65,7 +67,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_sec(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/sec(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/warden(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) @@ -91,18 +93,19 @@ total_positions = 2 spawn_positions = 2 supervisors = "the head of security" - selection_color = "#ffeeee" - alt_titles = list("Forensic Technician") + selection_color = "#601C1C" + idtype = /obj/item/weapon/card/id/security + alt_titles = list("Forensic Technician","Investigator") access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks) minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks) economic_modifier = 5 minimal_player_age = 3 - equip(var/mob/living/carbon/human/H) + equip(var/mob/living/carbon/human/H, var/alt_title) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/det(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes) @@ -113,12 +116,13 @@ H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_l_hand) else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_in_backpack) - if(H.mind.role_alt_title && H.mind.role_alt_title == "Forensic Technician") + if(has_alt_title(H, alt_title,"Forensic Technician")) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/forensics/blue(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit, slot_r_hand) else H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/det_trench(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/det(H), slot_head) + H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit(H), slot_r_hand) return 1 @@ -132,7 +136,8 @@ total_positions = 4 spawn_positions = 4 supervisors = "the head of security" - selection_color = "#ffeeee" + selection_color = "#601C1C" + idtype = /obj/item/weapon/card/id/security alt_titles = list("Junior Officer") economic_modifier = 4 access = list(access_security, access_eva, access_sec_doors, access_brig, access_maint_tunnels, access_morgue, access_external_airlocks) @@ -143,7 +148,7 @@ H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(H), slot_back) - if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_sec(H), slot_back) + if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/sec(H), slot_back) if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back) H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/security(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index b64508499c..d9aa96f710 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -5,7 +5,7 @@ faction = "Station" total_positions = 0 // Not used for AI, see is_position_available below and modules/mob/living/silicon/ai/latejoin.dm spawn_positions = 1 - selection_color = "#ccffcc" + selection_color = "#3F823F" supervisors = "your laws" req_admin_notify = 1 minimal_player_age = 7 @@ -29,6 +29,7 @@ /datum/job/ai/equip_preview(mob/living/carbon/human/H) H.equip_to_slot_or_del(new /obj/item/clothing/suit/straight_jacket(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) + return 1 /datum/job/cyborg title = "Cyborg" @@ -38,7 +39,7 @@ total_positions = 2 spawn_positions = 2 supervisors = "your laws and the AI" //Nodrak - selection_color = "#ddffdd" + selection_color = "#254C25" minimal_player_age = 1 alt_titles = list("Robot", "Drone") account_allowed = 0 @@ -60,3 +61,4 @@ /datum/job/cyborg/equip_preview(mob/living/carbon/human/H) H.equip_to_slot_or_del(new /obj/item/clothing/suit/cardborg(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) + return 1 diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 7bf949e217..adf5e2ab45 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -111,7 +111,7 @@ var/global/datum/controller/occupations/job_master if(istype(job, GetJob("Assistant"))) // We don't want to give him assistant, that's boring! continue - if(job in command_positions) //If you want a command position, select it! + if(job.title in command_positions) //If you want a command position, select it! continue if(jobban_isbanned(player, job.title)) @@ -331,7 +331,6 @@ var/global/datum/controller/occupations/job_master var/list/custom_equip_slots = list() //If more than one item takes the same slot, all after the first one spawn in storage. var/list/custom_equip_leftovers = list() if(H.client.prefs.gear && H.client.prefs.gear.len && job.title != "Cyborg" && job.title != "AI") - for(var/thing in H.client.prefs.gear) var/datum/gear/G = gear_datums[thing] if(G) @@ -353,10 +352,11 @@ var/global/datum/controller/occupations/job_master if(G.slot && !(G.slot in custom_equip_slots)) // This is a miserable way to fix the loadout overwrite bug, but the alternative requires // adding an arg to a bunch of different procs. Will look into it after this merge. ~ Z + var/metadata = H.client.prefs.gear[G.display_name] if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head) custom_equip_leftovers += thing - else if(H.equip_to_slot_or_del(new G.path(H), G.slot)) - H << "Equipping you with [thing]!" + else if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) + H << "Equipping you with \the [thing]!" custom_equip_slots.Add(G.slot) else custom_equip_leftovers.Add(thing) @@ -375,8 +375,9 @@ var/global/datum/controller/occupations/job_master if(G.slot in custom_equip_slots) spawn_in_storage += thing else - if(H.equip_to_slot_or_del(new G.path(H), G.slot)) - H << "Equipping you with [thing]!" + var/metadata = H.client.prefs.gear[G.display_name] + if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) + H << "Equipping you with \the [thing]!" custom_equip_slots.Add(G.slot) else spawn_in_storage += thing @@ -439,9 +440,10 @@ var/global/datum/controller/occupations/job_master if(!isnull(B)) for(var/thing in spawn_in_storage) - H << "Placing [thing] in your [B]!" + H << "Placing \the [thing] in your [B.name]!" var/datum/gear/G = gear_datums[thing] - new G.path(B) + var/metadata = H.client.prefs.gear[G.display_name] + G.spawn_item(B, metadata) else H << "Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug." diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index f1dc546aea..440cf2e22e 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -28,7 +28,7 @@ var/list/whitelist = list() if (!text) log_misc("Failed to load config/alienwhitelist.txt") else - alien_whitelist = text2list(text, "\n") + alien_whitelist = splittext(text, "\n") //todo: admin aliens /proc/is_alien_whitelisted(mob/M, var/species) diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 4b6ac3fd11..c0ef428f99 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -9,6 +9,7 @@ use_power = 1 idle_power_usage = 40 interact_offline = 1 + circuit = /obj/item/weapon/circuitboard/sleeper_console //obj/machinery/sleep_console/New() //..() @@ -32,8 +33,39 @@ /obj/machinery/sleep_console/attack_hand(var/mob/user) if(..()) return 1 + if(connected) + connected.ui_interact(user) - connected.ui_interact(user) +/obj/machinery/sleep_console/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/screwdriver) && circuit) + user << "You start disconnecting the monitor." + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + var/obj/structure/frame/A = new /obj/structure/frame( src.loc ) + var/obj/item/weapon/circuitboard/M = new circuit( A ) + A.circuit = M + A.anchored = 1 + A.density = 1 + A.frame_type = M.board_type + for (var/obj/C in src) + C.forceMove(loc) + if (src.stat & BROKEN) + user << "The broken glass falls out." + new /obj/item/weapon/material/shard( src.loc ) + A.state = 3 + A.icon_state = "[A.frame_type]_3" + else + user << "You disconnect the monitor." + A.state = 4 + A.icon_state = "[A.frame_type]_4" + A.pixel_x = pixel_x + A.pixel_y = pixel_y + A.dir = dir + M.deconstruct(src) + qdel(src) + else + src.attack_hand(user) + return /obj/machinery/sleep_console/power_change() ..() @@ -49,6 +81,7 @@ icon_state = "sleeper_0" density = 1 anchored = 1 + circuit = /obj/item/weapon/circuitboard/sleeper var/mob/living/carbon/human/occupant = null var/list/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "paracetamol" = "Paracetamol", "anti_toxin" = "Dylovene", "dexalin" = "Dexalin") var/obj/item/weapon/reagent_containers/glass/beaker = null @@ -61,6 +94,25 @@ /obj/machinery/sleeper/New() ..() beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(src) + component_parts += new /obj/item/weapon/reagent_containers/syringe(src) + component_parts += new /obj/item/weapon/reagent_containers/syringe(src) + component_parts += new /obj/item/weapon/reagent_containers/syringe(src) + component_parts += new /obj/item/stack/material/glass/reinforced(src, 2) + + spawn(5) + //src.machine = locate(/obj/machinery/mineral/processing_unit, get_step(src, machinedir)) + var/obj/machinery/sleep_console/C = locate(/obj/machinery/sleep_console) in range(2,src) + if(C) + C.connected = src + return + + RefreshParts() /obj/machinery/sleeper/initialize() update_icon() @@ -156,6 +208,10 @@ return 1 /obj/machinery/sleeper/attackby(var/obj/item/I, var/mob/user) + if(default_deconstruction_screwdriver(user, I)) + return + if(default_deconstruction_crowbar(user, I)) + return add_fingerprint(user) if(istype(I, /obj/item/weapon/reagent_containers/glass)) if(!beaker) @@ -230,7 +286,9 @@ occupant.loc = loc occupant = null for(var/atom/movable/A in src) // In case an object was dropped inside or something - if(A == beaker) + if(A == beaker || A == circuit) + continue + if(A in component_parts) continue A.loc = loc update_use_power(1) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 5aa321ca41..43ca9d2fc3 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -10,94 +10,132 @@ density = 1 anchored = 1 + circuit = /obj/item/weapon/circuitboard/body_scanner + use_power = 1 idle_power_usage = 60 active_power_usage = 10000 //10 kW. It's a big all-body scanner. -/obj/machinery/bodyscanner/relaymove(mob/user as mob) - if (user.stat) + light_color = "#00FF00" + +/obj/machinery/bodyscanner/New() + ..() + spawn( 5 ) + var/obj/machinery/body_scanconsole/C = locate(/obj/machinery/body_scanconsole) in range(2,src) + if(C) + C.connected = src + +/obj/machinery/bodyscanner/map/New() + ..() + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/stack/material/glass/reinforced(src, 2) + RefreshParts() + +/obj/machinery/bodyscanner/power_change() + ..() + if(!(stat & (BROKEN|NOPOWER))) + set_light(2) + else + set_light(0) + +/obj/machinery/bodyscanner/attackby(var/obj/item/G, user as mob) + if(default_deconstruction_screwdriver(user, G)) return - src.go_out() - return + if(default_deconstruction_crowbar(user, G)) + return + + if(istype(G, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/H = G + if(panel_open) + user << "Close the maintenance panel first." + return + if(!ismob(H.affecting)) + return + if(occupant) + user << "The scanner is already occupied!" + return + for(var/mob/living/carbon/slime/M in range(1, H.affecting)) + if(M.Victim == H.affecting) + user << "[H.affecting.name] has a fucking slime attached to them, deal with that first." + return + var/mob/M = H.affecting + if(M.abiotic()) + user << "Subject cannot have abiotic items on." + return + M.forceMove(src) + occupant = M + icon_state = "body_scanner_1" + add_fingerprint(user) + qdel(G) + +/obj/machinery/bodyscanner/MouseDrop_T(mob/living/carbon/O, mob/user as mob) + if(!istype(O)) + return 0 //not a mob + if(user.incapacitated()) + return 0 //user shouldn't be doing things + if(O.anchored) + return 0 //mob is anchored??? + if(get_dist(user, src) > 1 || get_dist(user, O) > 1) + return 0 //doesn't use adjacent() to allow for non-cardinal (fuck my life) + if(!ishuman(user) && !isrobot(user)) + return 0 //not a borg or human + if(panel_open) + user << "Close the maintenance panel first." + return 0 //panel open + if(occupant) + user << "\The [src] is already occupied." + return 0 //occupied + + if(O.buckled) + return 0 + if(O.abiotic()) + user << "Subject cannot have abiotic items on." + return 0 + for(var/mob/living/carbon/slime/M in range(1, O)) + if(M.Victim == O) + user << "[O] has a fucking slime attached to them, deal with that first." + return 0 + + if(O == user) + visible_message("[user] climbs into \the [src].") + else + visible_message("[user] puts [O] into the body scanner.") + + O.forceMove(src) + occupant = O + icon_state = "body_scanner_1" + add_fingerprint(user) + +/obj/machinery/bodyscanner/relaymove(mob/user as mob) + if(user.incapacitated()) + return 0 //maybe they should be able to get out with cuffs, but whatever + go_out() /obj/machinery/bodyscanner/verb/eject() set src in oview(1) set category = "Object" set name = "Eject Body Scanner" - if (usr.stat != 0) + if(usr.incapacitated()) return - src.go_out() + go_out() add_fingerprint(usr) - return - -/obj/machinery/bodyscanner/verb/move_inside() - set src in oview(1) - set category = "Object" - set name = "Enter Body Scanner" - - if (usr.stat != 0) - return - if (src.occupant) - usr << "The scanner is already occupied!" - return - if (usr.abiotic()) - usr << "The subject cannot have abiotic items on." - return - usr.pulling = null - usr.client.perspective = EYE_PERSPECTIVE - usr.client.eye = src - usr.loc = src - src.occupant = usr - update_use_power(2) - src.icon_state = "body_scanner_1" - for(var/obj/O in src) - //O = null - qdel(O) - //Foreach goto(124) - src.add_fingerprint(usr) - return /obj/machinery/bodyscanner/proc/go_out() if ((!( src.occupant ) || src.locked)) return - for(var/obj/O in src) - O.loc = src.loc - //Foreach goto(30) if (src.occupant.client) src.occupant.client.eye = src.occupant.client.mob src.occupant.client.perspective = MOB_PERSPECTIVE src.occupant.loc = src.loc src.occupant = null - update_use_power(1) src.icon_state = "body_scanner_0" return -/obj/machinery/bodyscanner/attackby(obj/item/weapon/grab/G as obj, user as mob) - if ((!( istype(G, /obj/item/weapon/grab) ) || !( ismob(G.affecting) ))) - return - if (src.occupant) - user << "The scanner is already occupied!" - return - if (G.affecting.abiotic()) - user << "Subject cannot have abiotic items on." - return - var/mob/M = G.affecting - if (M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - M.loc = src - src.occupant = M - update_use_power(2) - src.icon_state = "body_scanner_1" - for(var/obj/O in src) - O.loc = src.loc - //Foreach goto(154) - src.add_fingerprint(user) - //G = null - qdel(G) - return - /obj/machinery/bodyscanner/ex_act(severity) switch(severity) if(1.0) @@ -129,8 +167,69 @@ else return -/obj/machinery/body_scanconsole/ex_act(severity) +//Body Scan Console +/obj/machinery/body_scanconsole + var/obj/machinery/bodyscanner/connected + var/known_implants = list(/obj/item/weapon/implant/chem, /obj/item/weapon/implant/death_alarm, /obj/item/weapon/implant/loyalty, /obj/item/weapon/implant/tracking) + var/delete + var/temphtml + name = "Body Scanner Console" + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "body_scannerconsole" + dir = 8 + density = 0 + anchored = 1 + circuit = /obj/item/weapon/circuitboard/scanner_console + var/printing = null + var/printing_text = null +/obj/machinery/body_scanconsole/New() + ..() + findscanner() + +/obj/machinery/body_scanconsole/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/weapon/screwdriver) && circuit) + user << "You start disconnecting the monitor." + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + var/obj/structure/frame/A = new /obj/structure/frame( src.loc ) + var/obj/item/weapon/circuitboard/M = new circuit( A ) + A.circuit = M + A.anchored = 1 + A.density = 1 + A.frame_type = M.board_type + for (var/obj/C in src) + C.forceMove(loc) + if (src.stat & BROKEN) + user << "The broken glass falls out." + new /obj/item/weapon/material/shard( src.loc ) + A.state = 3 + A.icon_state = "[A.frame_type]_3" + else + user << "You disconnect the monitor." + A.state = 4 + A.icon_state = "[A.frame_type]_4" + A.pixel_x = pixel_x + A.pixel_y = pixel_y + A.dir = dir + M.deconstruct(src) + qdel(src) + else + src.attack_hand(user) + return + +/obj/machinery/body_scanconsole/power_change() + if(stat & BROKEN) + icon_state = "body_scannerconsole-p" + else if(powered() && !panel_open) + icon_state = initial(icon_state) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "body_scannerconsole-p" + stat |= NOPOWER + +/obj/machinery/body_scanconsole/ex_act(severity) switch(severity) if(1.0) //SN src = null @@ -144,290 +243,340 @@ else return -/obj/machinery/body_scanconsole/power_change() - ..() - if(stat & BROKEN) - icon_state = "body_scannerconsole-p" - else - if (stat & NOPOWER) - spawn(rand(0, 15)) - src.icon_state = "body_scannerconsole-p" - else - icon_state = initial(icon_state) - -/obj/machinery/body_scanconsole - var/obj/machinery/bodyscanner/connected - var/known_implants = list(/obj/item/weapon/implant/chem, /obj/item/weapon/implant/death_alarm, /obj/item/weapon/implant/loyalty, /obj/item/weapon/implant/tracking) - var/delete - var/temphtml - name = "Body Scanner Console" - icon = 'icons/obj/Cryogenic2.dmi' - icon_state = "body_scannerconsole" - dir = 8 - density = 0 - anchored = 1 - -/obj/machinery/body_scanconsole/New() - ..() +/obj/machinery/body_scanconsole/proc/findscanner() spawn( 5 ) - src.connected = locate(/obj/machinery/bodyscanner, get_step(src, WEST)) //We assume dir = 8 so scanner is WEST. Other sprites do exist. + var/obj/machinery/bodyscanner/bodyscannernew = null + // Loop through every direction + for(dir in list(NORTH,EAST,SOUTH,WEST)) + // Try to find a scanner in that direction + bodyscannernew = locate(/obj/machinery/bodyscanner, get_step(src, dir)) + src.connected = bodyscannernew return - return - -/* - -/obj/machinery/body_scanconsole/process() //not really used right now - if(stat & (NOPOWER|BROKEN)) - return - //use_power(250) // power stuff - -// var/mob/M //occupant -// if (!( src.status )) //remove this -// return -// if ((src.connected && src.connected.occupant)) //connected & occupant ok -// M = src.connected.occupant -// else -// if (istype(M, /mob)) -// //do stuff -// else -/// src.temphtml = "Process terminated due to lack of occupant in scanning chamber." -// src.status = null -// src.updateDialog() -// return - -*/ /obj/machinery/body_scanconsole/attack_ai(user as mob) - return src.attack_hand(user) + return attack_hand(user) + +/obj/machinery/body_scanconsole/attack_ghost(user as mob) + return attack_hand(user) /obj/machinery/body_scanconsole/attack_hand(user as mob) - if(..()) - return if(stat & (NOPOWER|BROKEN)) return - if(!connected || (connected.stat & (NOPOWER|BROKEN))) - user << "This console is not connected to a functioning body scanner." - return - if(!ishuman(connected.occupant)) - user << "This device can only scan compatible lifeforms." + + if (panel_open) + user << "Close the maintenance panel first." return - var/dat - if (src.delete && src.temphtml) //Window in buffer but its just simple message, so nothing - src.delete = src.delete - else if (!src.delete && src.temphtml) //Window in buffer - its a menu, dont add clear message - dat = text("[]

Main Menu", src.temphtml, src) - else - if (src.connected) //Is something connected? - dat = format_occupant_data(src.connected.get_occupant_data()) - dat += "
Print
" - else - dat = "Error: No Body Scanner connected." + if(!src.connected) + findscanner() - dat += text("
Close", user) - user << browse(dat, "window=scanconsole;size=430x600") - return + ui_interact(user) + +/obj/machinery/body_scanconsole/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["connected"] = connected ? 1 : 0 + + if(connected) + data["occupied"] = connected.occupant ? 1 : 0 + + var/occupantData[0] + if(connected.occupant && ishuman(connected.occupant)) + var/mob/living/carbon/human/H = connected.occupant + occupantData["name"] = H.name + occupantData["stat"] = H.stat + occupantData["health"] = H.health + + occupantData["hasVirus"] = H.virus2.len + + occupantData["bruteLoss"] = H.getBruteLoss() + occupantData["oxyLoss"] = H.getOxyLoss() + occupantData["toxLoss"] = H.getToxLoss() + occupantData["fireLoss"] = H.getFireLoss() + + occupantData["radLoss"] = H.radiation + occupantData["cloneLoss"] = H.getCloneLoss() + occupantData["brainLoss"] = H.getBrainLoss() + occupantData["paralysis"] = H.paralysis + occupantData["paralysisSeconds"] = round(H.paralysis / 4) + occupantData["bodyTempC"] = H.bodytemperature-T0C + occupantData["bodyTempF"] = (((H.bodytemperature-T0C) * 1.8) + 32) + + occupantData["hasBorer"] = H.has_brain_worms() + + var/bloodData[0] + if(H.vessel) + var/blood_volume = round(H.vessel.get_reagent_amount("blood")) + bloodData["volume"] = blood_volume + bloodData["percent"] = round(((blood_volume / 560)*100)) + + occupantData["blood"] = bloodData + + var/reagentData[0] + if(H.reagents.reagent_list.len >= 1) + for(var/datum/reagent/R in H.reagents.reagent_list) + reagentData[++reagentData.len] = list("name" = R.name, "amount" = R.volume) + else + reagentData = null + + occupantData["reagents"] = reagentData + + var/extOrganData[0] + for(var/obj/item/organ/external/E in H.organs) + var/organData[0] + organData["name"] = E.name + organData["open"] = E.open + organData["germ_level"] = E.germ_level + organData["bruteLoss"] = E.brute_dam + organData["fireLoss"] = E.burn_dam + + var/implantData[0] + for(var/obj/I in E.implants) + var/implantSubData[0] + implantSubData["name"] = I.name + if(is_type_in_list(I, known_implants)) + implantSubData["known"] = 1 + + implantData.Add(list(implantSubData)) + + organData["implants"] = implantData + organData["implants_len"] = implantData.len + + var/organStatus[0] + if(E.status & ORGAN_DESTROYED) + organStatus["destroyed"] = 1 + if(E.status & ORGAN_BROKEN) + organStatus["broken"] = E.broken_description + if(E.status & ORGAN_ROBOT) + organStatus["robotic"] = 1 + if(E.status & ORGAN_SPLINTED) + organStatus["splinted"] = 1 + if(E.status & ORGAN_BLEEDING) + organStatus["bleeding"] = 1 + + organData["status"] = organStatus + + if(istype(E, /obj/item/organ/external/chest) && H.is_lung_ruptured()) + organData["lungRuptured"] = 1 + + for(var/datum/wound/W in E.wounds) + if(W.internal) + organData["internalBleeding"] = 1 + break + + extOrganData.Add(list(organData)) + + occupantData["extOrgan"] = extOrganData + + var/intOrganData[0] + for(var/obj/item/organ/I in H.internal_organs) + var/organData[0] + organData["name"] = I.name + if(I.status & ORGAN_ASSISTED) + organData["desc"] = "Assisted" + else if(I.robotic >= ORGAN_ROBOT) + organData["desc"] = "Mechanical" + else + organData["desc"] = null + organData["germ_level"] = I.germ_level + organData["damage"] = I.damage + + intOrganData.Add(list(organData)) + + occupantData["intOrgan"] = intOrganData + + occupantData["blind"] = (H.sdisabilities & BLIND) + occupantData["nearsighted"] = (H.disabilities & NEARSIGHTED) + + data["occupant"] = occupantData + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 800) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /obj/machinery/body_scanconsole/Topic(href, href_list) - if (..()) - return + if(..()) + return 1 - if (href_list["print"]) - if (!src.connected) - usr << "\icon[src]Error: No body scanner connected." - return - var/mob/living/carbon/human/occupant = src.connected.occupant - if (!src.connected.occupant) - usr << "\icon[src]The body scanner is empty." - return - if (!istype(occupant,/mob/living/carbon/human)) - usr << "\icon[src]The body scanner cannot scan that lifeform." - return - var/obj/item/weapon/paper/R = new(src.loc) - R.name = "Body scan report" - R.info = format_occupant_data(src.connected.get_occupant_data()) + if (href_list["print_p"]) + generate_printing_text() + if (!(printing) && printing_text) + printing = 1 + visible_message("\The [src] rattles and prints out a sheet of paper.") + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + P.info = "
Body Scan - [href_list["name"]]

" + P.info += "Time of scan: [worldtime2text(world.time)]

" + P.info += "[printing_text]" + P.info += "

Notes:
" + P.name = "Body Scan - [href_list["name"]]" + printing = null + printing_text = null -/obj/machinery/bodyscanner/proc/get_occupant_data() - if (!occupant || !istype(occupant, /mob/living/carbon/human)) - return - var/mob/living/carbon/human/H = occupant - var/list/occupant_data = list( - "stationtime" = worldtime2text(), - "stat" = H.stat, - "health" = round(H.health/H.maxHealth)*100, - "virus_present" = H.virus2.len, - "bruteloss" = H.getBruteLoss(), - "fireloss" = H.getFireLoss(), - "oxyloss" = H.getOxyLoss(), - "toxloss" = H.getToxLoss(), - "rads" = H.radiation, - "cloneloss" = H.getCloneLoss(), - "brainloss" = H.getBrainLoss(), - "paralysis" = H.paralysis, - "bodytemp" = H.bodytemperature, - "borer_present" = H.has_brain_worms(), - "inaprovaline_amount" = H.reagents.get_reagent_amount("inaprovaline"), - "dexalin_amount" = H.reagents.get_reagent_amount("dexalin"), - "stoxin_amount" = H.reagents.get_reagent_amount("stoxin"), - "bicaridine_amount" = H.reagents.get_reagent_amount("bicaridine"), - "dermaline_amount" = H.reagents.get_reagent_amount("dermaline"), - "blood_amount" = round((H.vessel.get_reagent_amount("blood") / H.species.blood_volume)*100), - "disabilities" = H.sdisabilities, - "lung_ruptured" = H.is_lung_ruptured(), - "external_organs" = H.organs.Copy(), - "internal_organs" = H.internal_organs.Copy(), - "species_organs" = H.species.has_organ //Just pass a reference for this, it shouldn't ever be modified outside of the datum. - ) - return occupant_data +/obj/machinery/body_scanconsole/proc/generate_printing_text() + var/dat = "" - -/obj/machinery/body_scanconsole/proc/format_occupant_data(var/list/occ) - var/dat = "Scan performed at [occ["stationtime"]]
" - dat += "Occupant Statistics:
" - var/aux - switch (occ["stat"]) - if(0) - aux = "Conscious" - if(1) - aux = "Unconscious" - else - aux = "Dead" - dat += text("[]\tHealth %: [] ([])

", ("Viral pathogen detected in blood stream.
" - dat += text("[]\t-Brute Damage %: []

", (""), occ["bruteloss"]) - dat += text("[]\t-Respiratory Damage %: []
", (""), occ["oxyloss"]) - dat += text("[]\t-Toxin Content %: []
", (""), occ["toxloss"]) - dat += text("[]\t-Burn Severity %: []

", (""), occ["fireloss"]) - - dat += text("[]\tRadiation Level %: []
", (""), occ["rads"]) - dat += text("[]\tGenetic Tissue Damage %: []
", (""), occ["cloneloss"]) - dat += text("[]\tApprox. Brain Damage %: []
", (""), occ["brainloss"]) - dat += text("Paralysis Summary %: [] ([] seconds left!)
", occ["paralysis"], round(occ["paralysis"] / 4)) - dat += text("Body Temperature: [occ["bodytemp"]-T0C]°C ([occ["bodytemp"]*1.8-459.67]°F)

") - - if(occ["borer_present"]) - dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
" - - dat += text("[]\tBlood Level %: [] ([] units)

", (""), occ["blood_amount"], occ["blood_amount"]) - - dat += text("Inaprovaline: [] units
", occ["inaprovaline_amount"]) - dat += text("Soporific: [] units
", occ["stoxin_amount"]) - dat += text("[]\tDermaline: [] units

", (""), occ["dermaline_amount"]) - dat += text("[]\tBicaridine: [] units
", (""), occ["bicaridine_amount"]) - dat += text("[]\tDexalin: [] units
", (""), occ["dexalin_amount"]) - - dat += "
NameRankActivity
Heads
" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - - for(var/obj/item/organ/external/e in occ["external_organs"]) - var/AN = "" - var/open = "" - var/infected = "" - var/imp = "" - var/bled = "" - var/robot = "" - var/splint = "" - var/internal_bleeding = "" - var/lung_ruptured = "" - - dat += "" - - for(var/datum/wound/W in e.wounds) if(W.internal) - internal_bleeding = "
Internal bleeding" - break - if(istype(e, /obj/item/organ/external/chest) && occ["lung_ruptured"]) - lung_ruptured = "Lung ruptured:" - if(e.status & ORGAN_SPLINTED) - splint = "Splinted:" - if(e.status & ORGAN_BLEEDING) - bled = "Bleeding:" - if(e.status & ORGAN_BROKEN) - AN = "[e.broken_description]:" - if(e.status & ORGAN_ROBOT) - robot = "Prosthetic:" - if(e.open) - open = "Open:" - - switch (e.germ_level) - if (INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200) - infected = "Mild Infection:" - if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) - infected = "Mild Infection+:" - if (INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) - infected = "Mild Infection++:" - if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) - infected = "Acute Infection:" - if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) - infected = "Acute Infection+:" - if (INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400) - infected = "Acute Infection++:" - if (INFECTION_LEVEL_THREE to INFINITY) - infected = "Septic:" - if(e.rejecting) - infected += "(being rejected)" - if (e.implants.len) - var/unknown_body = 0 - for(var/I in e.implants) - if(is_type_in_list(I,known_implants)) - imp += "[I] implanted:" + if(connected) + var/mob/living/carbon/human/occupant = connected.occupant + dat = "Occupant Statistics:
" //Blah obvious + if(istype(occupant)) //is there REALLY someone in there? + var/t1 + switch(occupant.stat) // obvious, see what their status is + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" else - unknown_body++ - if(unknown_body) - imp += "Unknown body present:" + t1 = "*dead*" + dat += " 50 ? "blue" : "red"]>\tHealth %: [occupant.health], ([t1])
" - if(!AN && !open && !infected & !imp) - AN = "None:" - if(!e.is_stump()) - dat += "
" + if(occupant.virus2.len) + dat += "Viral pathogen detected in blood stream.
" + + var/extra_font = null + extra_font = "" + dat += "[extra_font]\t-Brute Damage %: [occupant.getBruteLoss()]
" + + extra_font = "" + dat += "[extra_font]\t-Respiratory Damage %: [occupant.getOxyLoss()]
" + + extra_font = "" + dat += "[extra_font]\t-Toxin Content %: [occupant.getToxLoss()]
" + + extra_font = "" + dat += "[extra_font]\t-Burn Severity %: [occupant.getFireLoss()]
" + + extra_font = "" + dat += "[extra_font]\tRadiation Level %: [occupant.radiation]
" + + extra_font = "" + dat += "[extra_font]\tGenetic Tissue Damage %: [occupant.getCloneLoss()]
" + + extra_font = "" + dat += "[extra_font]\tApprox. Brain Damage %: [occupant.getBrainLoss()]
" + + dat += "Paralysis Summary %: [occupant.paralysis] ([round(occupant.paralysis / 4)] seconds left!)
" + dat += "Body Temperature: [occupant.bodytemperature-T0C]°C ([occupant.bodytemperature*1.8-459.67]°F)
" + + dat += "
" + + if(occupant.has_brain_worms()) + dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
" + + if(occupant.vessel) + var/blood_volume = round(occupant.vessel.get_reagent_amount("blood")) + var/blood_percent = blood_volume / 560 + blood_percent *= 100 + + extra_font = " 448 ? "blue" : "red"]>" + dat += "[extra_font]\tBlood Level %: [blood_percent] ([blood_volume] units)
" + + if(occupant.reagents) + for(var/datum/reagent/R in occupant.reagents) + dat += "Reagent: [R.name], Amount: [R.volume]
" + + dat += "
OrganBurn DamageBrute DamageOther Wounds
[e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]
" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + for(var/obj/item/organ/external/e in occupant.organs) + dat += "" + var/AN = "" + var/open = "" + var/infected = "" + var/robot = "" + var/imp = "" + var/bled = "" + var/splint = "" + var/internal_bleeding = "" + var/lung_ruptured = "" + for(var/datum/wound/W in e.wounds) if(W.internal) + internal_bleeding = "
Internal bleeding" + break + if(istype(e, /obj/item/organ/external/chest) && occupant.is_lung_ruptured()) + lung_ruptured = "Lung ruptured:" + if(e.status & ORGAN_SPLINTED) + splint = "Splinted:" + if(e.status & ORGAN_BLEEDING) + bled = "Bleeding:" + if(e.status & ORGAN_BROKEN) + AN = "[e.broken_description]:" + if(e.status & ORGAN_ROBOT) + robot = "Prosthetic:" + if(e.open) + open = "Open:" + switch (e.germ_level) + if (INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200) + infected = "Mild Infection:" + if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) + infected = "Mild Infection+:" + if (INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) + infected = "Mild Infection++:" + if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) + infected = "Acute Infection:" + if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) + infected = "Acute Infection+:" + if (INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400) + infected = "Acute Infection++:" + if (INFECTION_LEVEL_THREE to INFINITY) + infected = "Septic:" + + var/unknown_body = 0 + for(var/I in e.implants) + if(is_type_in_list(I,known_implants)) + imp += "[I] implanted:" + else + unknown_body++ + + if(unknown_body) + imp += "Unknown body present:" + if(!AN && !open && !infected & !imp) + AN = "None:" + if(!(e.status & ORGAN_DESTROYED)) + dat += "
" + else + dat += "" + dat += "" + for(var/obj/item/organ/i in occupant.internal_organs) + var/mech = "" + if(i.status & ORGAN_ASSISTED) + mech = "Assisted:" + if(i.robotic >= ORGAN_ROBOT) + mech = "Mechanical:" + var/infection = "None" + switch (i.germ_level) + if (1 to INFECTION_LEVEL_ONE + 200) + infection = "Mild Infection:" + if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) + infection = "Mild Infection+:" + if (INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) + infection = "Mild Infection++:" + if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) + infection = "Acute Infection:" + if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) + infection = "Acute Infection+:" + if (INFECTION_LEVEL_TWO + 300 to INFINITY) + infection = "Acute Infection++:" + + dat += "" + dat += "" + dat += "" + dat += "
OrganBurn DamageBrute DamageOther Wounds
[e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured][e.name]--Not Found
[i.name]N/A[i.damage][infection]:[mech]
" + if(occupant.sdisabilities & BLIND) + dat += "Cataracts detected.
" + if(occupant.disabilities & NEARSIGHTED) + dat += "Retinal misalignment detected.
" else - dat += "[e.name]--Not [e.is_stump() ? "Found" : "Attached Completely"]" - dat += "" + dat += "\The [src] is empty." + else + dat = " Error: No Body Scanner connected." - for(var/obj/item/organ/i in occ["internal_organs"]) - - var/mech = "" - if(i.status & ORGAN_ASSISTED) - mech = "Assisted:" - if(i.status & ORGAN_ROBOT) - mech = "Mechanical:" - - var/infection = "None" - switch (i.germ_level) - if (1 to INFECTION_LEVEL_ONE + 200) - infection = "Mild Infection:" - if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) - infection = "Mild Infection+:" - if (INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) - infection = "Mild Infection++:" - if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) - infection = "Acute Infection:" - if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) - infection = "Acute Infection+:" - if (INFECTION_LEVEL_TWO + 300 to INFINITY) - infection = "Acute Infection++:" - if(i.rejecting) - infection += "(being rejected)" - - dat += "" - dat += "[i.name]N/A[i.damage][infection]:[mech]" - dat += "" - dat += "" - - var/list/species_organs = occ["species_organs"] - for(var/organ_name in species_organs) - if(!locate(species_organs[organ_name]) in occ["internal_organs"]) - dat += text("No [organ_name] detected.
") - - if(occ["sdisabilities"] & BLIND) - dat += text("Cataracts detected.
") - if(occ["sdisabilities"] & NEARSIGHTED) - dat += text("Retinal misalignment detected.
") - return dat + printing_text = dat \ No newline at end of file diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index d3603fe96e..699898fde0 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -54,6 +54,7 @@ var/wiresexposed = 0 // If it's been screwdrivered open. var/aidisabled = 0 var/shorted = 0 + circuit = /obj/item/weapon/circuitboard/airalarm var/datum/wires/alarm/wires @@ -61,7 +62,6 @@ var/screen = AALARM_SCREEN_MAIN var/area_uid var/area/alarm_area - var/buildstage = 2 //2 is built, 1 is building, 0 is frame. var/target_temperature = T0C+20 var/regulating_temperature = 0 @@ -105,23 +105,8 @@ wires = null return ..() -/obj/machinery/alarm/New(var/loc, var/dir, var/building = 0) +/obj/machinery/alarm/New() ..() - - if(building) - if(loc) - src.loc = loc - - if(dir) - src.set_dir(dir) - - buildstage = 0 - wiresexposed = 1 - pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) - pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0 - update_icon() - return - first_run() /obj/machinery/alarm/proc/first_run() @@ -148,7 +133,7 @@ elect_master() /obj/machinery/alarm/process() - if((stat & (NOPOWER|BROKEN)) || shorted || buildstage != 2) + if((stat & (NOPOWER|BROKEN)) || shorted) return var/turf/simulated/location = loc @@ -605,9 +590,6 @@ data["thresholds"] = thresholds /obj/machinery/alarm/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list = list()) - if(buildstage != 2) - return STATUS_CLOSE - if(aidisabled && isAI(user)) user << "AI control for \the [src] interface has been disabled." return STATUS_CLOSE @@ -763,73 +745,43 @@ /obj/machinery/alarm/attackby(obj/item/W as obj, mob/user as mob) src.add_fingerprint(user) + if(istype(W, /obj/item/weapon/screwdriver)) // Opening that Air Alarm up. + //user << "You pop the Air Alarm's maintence panel open." + wiresexposed = !wiresexposed + user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]" + update_icon() + return - switch(buildstage) - if(2) - if(istype(W, /obj/item/weapon/screwdriver)) // Opening that Air Alarm up. - //user << "You pop the Air Alarm's maintence panel open." - wiresexposed = !wiresexposed - user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]" - update_icon() - return + if (wiresexposed && istype(W, /obj/item/weapon/wirecutters)) + user.visible_message("[user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + new/obj/item/stack/cable_coil(get_turf(src), 5) + var/obj/structure/frame/A = new /obj/structure/frame( src.loc ) + var/obj/item/weapon/circuitboard/M = new circuit( A ) + A.frame_type = "airalarm" + A.pixel_x = pixel_x + A.pixel_y = pixel_y + A.set_dir(dir) + A.circuit = M + A.anchored = 1 + for (var/obj/C in src) + C.forceMove(loc) + A.state = 2 + A.icon_state = "airalarm_2" + M.deconstruct(src) + qdel(src) + return - if (wiresexposed && istype(W, /obj/item/weapon/wirecutters)) - user.visible_message("[user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") - playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) - new/obj/item/stack/cable_coil(get_turf(src), 5) - buildstage = 1 - update_icon() - return - - if (istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))// trying to unlock the interface with an ID card - if(stat & (NOPOWER|BROKEN)) - user << "It does nothing" - return - else - if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN)) - locked = !locked - user << "You [ locked ? "lock" : "unlock"] the Air Alarm interface." - else - user << "Access denied." + if (istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))// trying to unlock the interface with an ID card + if(stat & (NOPOWER|BROKEN)) + user << "It does nothing" return - - if(1) - if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W - if (C.use(5)) - user << "You wire \the [src]." - buildstage = 2 - update_icon() - first_run() - return - else - user << "You need 5 pieces of cable to do wire \the [src]." - return - - else if(istype(W, /obj/item/weapon/crowbar)) - user << "You start prying out the circuit." - playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) - if(do_after(user,20)) - user << "You pry out the circuit!" - var/obj/item/weapon/airalarm_electronics/circuit = new /obj/item/weapon/airalarm_electronics() - circuit.loc = user.loc - buildstage = 0 - update_icon() - return - if(0) - if(istype(W, /obj/item/weapon/airalarm_electronics)) - user << "You insert the circuit!" - qdel(W) - buildstage = 1 - update_icon() - return - - else if(istype(W, /obj/item/weapon/wrench)) - user << "You remove the fire alarm assembly from the wall!" - new /obj/item/frame/air_alarm(get_turf(user)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - qdel(src) - + else + if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN)) + locked = !locked + user << "You [ locked ? "lock" : "unlock"] the Air Alarm interface." + else + user << "Access denied." return ..() /obj/machinery/alarm/power_change() @@ -839,14 +791,10 @@ /obj/machinery/alarm/examine(mob/user) ..(user) - if (buildstage < 2) - user << "It is not wired." - if (buildstage < 1) - user << "The circuit is missing." /* AIR ALARM CIRCUIT Just a object used in constructing air alarms -*/ + /obj/item/weapon/airalarm_electronics name = "air alarm electronics" icon = 'icons/obj/doors/door_assembly.dmi' @@ -854,7 +802,7 @@ Just a object used in constructing air alarms desc = "Looks like a circuit. Probably is." w_class = 2.0 matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) - +*/ /* FIRE ALARM */ @@ -875,20 +823,13 @@ FIRE ALARM power_channel = ENVIRON var/last_process = 0 var/wiresexposed = 0 - var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone var/seclevel + circuit = /obj/item/weapon/circuitboard/firealarm /obj/machinery/firealarm/update_icon() overlays.Cut() if(wiresexposed) - switch(buildstage) - if(2) - icon_state="fire_b2" - if(1) - icon_state="fire_b1" - if(0) - icon_state="fire_b0" set_light(0) return @@ -932,56 +873,36 @@ FIRE ALARM /obj/machinery/firealarm/attackby(obj/item/W as obj, mob/user as mob) src.add_fingerprint(user) - if (istype(W, /obj/item/weapon/screwdriver) && buildstage == 2) + if (istype(W, /obj/item/weapon/screwdriver)) wiresexposed = !wiresexposed update_icon() return if(wiresexposed) - switch(buildstage) - if(2) - if (istype(W, /obj/item/device/multitool)) - src.detecting = !( src.detecting ) - if (src.detecting) - user.visible_message("\The [user] has reconnected [src]'s detecting unit!", "You have reconnected [src]'s detecting unit.") - else - user.visible_message("\The [user] has disconnected [src]'s detecting unit!", "You have disconnected [src]'s detecting unit.") - else if (istype(W, /obj/item/weapon/wirecutters)) - user.visible_message("\The [user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") - new/obj/item/stack/cable_coil(get_turf(src), 5) - playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) - buildstage = 1 - update_icon() - if(1) - if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W - if (C.use(5)) - user << "You wire \the [src]." - buildstage = 2 - return - else - user << "You need 5 pieces of cable to wire \the [src]." - return - else if(istype(W, /obj/item/weapon/crowbar)) - user << "You pry out the circuit!" - playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) - spawn(20) - var/obj/item/weapon/firealarm_electronics/circuit = new /obj/item/weapon/firealarm_electronics() - circuit.loc = user.loc - buildstage = 0 - update_icon() - if(0) - if(istype(W, /obj/item/weapon/firealarm_electronics)) - user << "You insert the circuit!" - qdel(W) - buildstage = 1 - update_icon() - - else if(istype(W, /obj/item/weapon/wrench)) - user << "You remove the fire alarm assembly from the wall!" - new /obj/item/frame/fire_alarm(get_turf(user)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - qdel(src) + if (istype(W, /obj/item/device/multitool)) + src.detecting = !( src.detecting ) + if (src.detecting) + user.visible_message("\The [user] has reconnected [src]'s detecting unit!", "You have reconnected [src]'s detecting unit.") + else + user.visible_message("\The [user] has disconnected [src]'s detecting unit!", "You have disconnected [src]'s detecting unit.") + else if (istype(W, /obj/item/weapon/wirecutters)) + user.visible_message("\The [user] has cut the wires inside \the [src]!", "You have cut the wires inside \the [src].") + new/obj/item/stack/cable_coil(get_turf(src), 5) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) + var/obj/structure/frame/A = new /obj/structure/frame( src.loc ) + var/obj/item/weapon/circuitboard/M = new circuit( A ) + A.frame_type = "firealarm" + A.pixel_x = pixel_x + A.pixel_y = pixel_y + A.set_dir(dir) + A.circuit = M + A.anchored = 1 + for (var/obj/C in src) + C.forceMove(loc) + A.state = 2 + A.icon_state = "firealarm_2" + M.deconstruct(src) + qdel(src) return src.alarm() @@ -1016,9 +937,6 @@ FIRE ALARM if(user.stat || stat & (NOPOWER|BROKEN)) return - if (buildstage != 2) - return - user.set_machine(src) var/area/A = src.loc var/d1 @@ -1061,9 +979,6 @@ FIRE ALARM if (usr.stat || stat & (BROKEN|NOPOWER)) return - if (buildstage != 2) - return - if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) usr.set_machine(src) if (href_list["reset"]) @@ -1106,23 +1021,6 @@ FIRE ALARM //playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0) return - - -/obj/machinery/firealarm/New(loc, dir, building) - ..() - - if(loc) - src.loc = loc - - if(dir) - src.set_dir(dir) - - if(building) - buildstage = 0 - wiresexposed = 1 - pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) - pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0 - /obj/machinery/firealarm/proc/set_security_level(var/newlevel) if(seclevel != newlevel) seclevel = newlevel @@ -1135,7 +1033,7 @@ FIRE ALARM /* FIRE ALARM CIRCUIT Just a object used in constructing fire alarms -*/ + /obj/item/weapon/firealarm_electronics name = "fire alarm electronics" icon = 'icons/obj/doors/door_assembly.dmi' @@ -1143,7 +1041,7 @@ Just a object used in constructing fire alarms desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\"" w_class = 2.0 matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) - +*/ /obj/machinery/partyalarm name = "\improper PARTY BUTTON" desc = "Cuban Pete is in the house!" diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index c7b5f3c73a..19d1ee1253 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -94,13 +94,8 @@ obj/machinery/computer/general_air_control/Destroy() /obj/machinery/computer/general_air_control/attack_hand(mob/user) if(..(user)) return - user << browse(return_text(),"window=computer") - user.set_machine(src) - onclose(user, "computer") -/obj/machinery/computer/general_air_control/process() - ..() - src.updateUsrDialog() + ui_interact(user) /obj/machinery/computer/general_air_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -110,43 +105,27 @@ obj/machinery/computer/general_air_control/Destroy() sensor_information[id_tag] = signal.data -/obj/machinery/computer/general_air_control/proc/return_text() - var/sensor_data +/obj/machinery/computer/general_air_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/list/data = list() + var/sensors_ui[0] if(sensors.len) for(var/id_tag in sensors) var/long_name = sensors[id_tag] - var/list/data = sensor_information[id_tag] - var/sensor_part = "[long_name]:
" - - if(data) - if(data["pressure"]) - sensor_part += " Pressure: [data["pressure"]] kPa
" - if(data["temperature"]) - sensor_part += " Temperature: [data["temperature"]] K
" - if(data["oxygen"]||data["phoron"]||data["nitrogen"]||data["carbon_dioxide"]) - sensor_part += " Gas Composition :" - if(data["oxygen"]) - sensor_part += "[data["oxygen"]]% O2; " - if(data["nitrogen"]) - sensor_part += "[data["nitrogen"]]% N; " - if(data["carbon_dioxide"]) - sensor_part += "[data["carbon_dioxide"]]% CO2; " - if(data["phoron"]) - sensor_part += "[data["phoron"]]% TX; " - sensor_part += "
" - - else - sensor_part = "[long_name] can not be found!
" - - sensor_data += sensor_part - + var/list/sensor_data = sensor_information[id_tag] + sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) else - sensor_data = "No sensors connected." + sensors_ui = null - var/output = {"[name]
-Sensor Data:

[sensor_data]"} + data["sensors"] = sensors_ui - return output + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "atmo_control.tmpl", src.name, 525, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(5) /obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) @@ -156,7 +135,6 @@ obj/machinery/computer/general_air_control/Destroy() /obj/machinery/computer/general_air_control/initialize() set_frequency(frequency) - /obj/machinery/computer/general_air_control/large_tank_control icon = 'icons/obj/computer.dmi' @@ -171,39 +149,41 @@ obj/machinery/computer/general_air_control/Destroy() var/pressure_setting = ONE_ATMOSPHERE * 45 circuit = /obj/item/weapon/circuitboard/air_management/tank_control +/obj/machinery/computer/general_air_control/large_tank_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) -/obj/machinery/computer/general_air_control/large_tank_control/return_text() - var/output = ..() - //if(signal.data) - // input_info = signal.data // Attempting to fix intake control -- TLE - - output += "Tank Control System

" - if(input_info) - var/power = (input_info["power"]) - var/volume_rate = round(input_info["volume_rate"], 0.1) - output += "Input: [power?("Injecting"):("On Hold")] Refresh
Flow Rate Limit: [volume_rate] L/s
" - output += "Command: Toggle Power Set Flow Rate
" - + var/list/data = list() + var/sensors_ui[0] + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/sensor_data = sensor_information[id_tag] + sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) else - output += "ERROR: Can not find input port Search
" + sensors_ui = null - output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
" + data["sensors"] = sensors_ui + data["tanks"] = 1 - output += "
" + if(input_info) + data["input_info"] = list("power" = input_info["power"], "volume_rate" = round(input_info["volume_rate"], 0.1)) + else + data["input_info"] = null if(output_info) - var/power = (output_info["power"]) - var/output_pressure = output_info["internal"] - output += {"Output: [power?("Open"):("On Hold")] Refresh
-Max Output Pressure: [output_pressure] kPa
"} - output += "Command: Toggle Power Set Pressure
" - + data["output_info"] = list("power" = output_info["power"], "output_pressure" = output_info["internal"]) else - output += "ERROR: Can not find output port Search
" + data["output_info"] = null - output += "Max Output Pressure Set: - - - - [pressure_setting] kPa + + + +
" + data["input_flow_setting"] = round(input_flow_setting, 0.1) + data["pressure_setting"] = pressure_setting - return output + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "atmo_control.tmpl", src.name, 660, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(5) /obj/machinery/computer/general_air_control/large_tank_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -224,15 +204,11 @@ Max Output Pressure: [output_pressure] kPa
"} if(href_list["adj_pressure"]) var/change = text2num(href_list["adj_pressure"]) pressure_setting = between(0, pressure_setting + change, 50*ONE_ATMOSPHERE) - spawn(1) - src.updateUsrDialog() return 1 if(href_list["adj_input_flow_rate"]) var/change = text2num(href_list["adj_input_flow_rate"]) input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - spawn(1) - src.updateUsrDialog() return 1 if(!radio_connection) @@ -273,9 +249,6 @@ Max Output Pressure: [output_pressure] kPa
"} signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - spawn(5) - src.updateUsrDialog() - /obj/machinery/computer/general_air_control/supermatter_core icon = 'icons/obj/computer.dmi' @@ -290,39 +263,40 @@ Max Output Pressure: [output_pressure] kPa
"} var/pressure_setting = 100 circuit = /obj/item/weapon/circuitboard/air_management/supermatter_core +/obj/machinery/computer/general_air_control/supermatter_core/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) -/obj/machinery/computer/general_air_control/supermatter_core/return_text() - var/output = ..() - //if(signal.data) - // input_info = signal.data // Attempting to fix intake control -- TLE + var/list/data = list() + var/sensors_ui[0] + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/sensor_data = sensor_information[id_tag] + sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) + else + sensors_ui = null + + data["sensors"] = sensors_ui + data["core"] = 1 - output += "Core Cooling Control System

" if(input_info) - var/power = (input_info["power"]) - var/volume_rate = round(input_info["volume_rate"], 0.1) - output += "Coolant Input: [power?("Injecting"):("On Hold")] Refresh
Flow Rate Limit: [volume_rate] L/s
" - output += "Command: Toggle Power Set Flow Rate
" - + data["input_info"] = list("power" = input_info["power"], "volume_rate" = round(input_info["volume_rate"], 0.1)) else - output += "ERROR: Can not find input port Search
" - - output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
" - - output += "
" - + data["input_info"] = null if(output_info) - var/power = (output_info["power"]) - var/pressure_limit = output_info["external"] - output += {"Core Outpump: [power?("Open"):("On Hold")] Refresh
-Min Core Pressure: [pressure_limit] kPa
"} - output += "Command: Toggle Power Set Pressure
" - + data["output_info"] = list("power" = output_info["power"], "pressure_limit" = output_info["external"]) else - output += "ERROR: Can not find output port Search
" + data["output_info"] = null - output += "Min Core Pressure Set: - - - - [pressure_setting] kPa + + + +
" + data["input_flow_setting"] = round(input_flow_setting, 0.1) + data["pressure_setting"] = pressure_setting - return output + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "atmo_control.tmpl", src.name, 650, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(5) /obj/machinery/computer/general_air_control/supermatter_core/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -343,15 +317,11 @@ Min Core Pressure: [pressure_limit] kPa
"} if(href_list["adj_pressure"]) var/change = text2num(href_list["adj_pressure"]) pressure_setting = between(0, pressure_setting + change, 10*ONE_ATMOSPHERE) - spawn(1) - src.updateUsrDialog() return 1 if(href_list["adj_input_flow_rate"]) var/change = text2num(href_list["adj_input_flow_rate"]) input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - spawn(1) - src.updateUsrDialog() return 1 if(!radio_connection) @@ -392,9 +362,6 @@ Min Core Pressure: [pressure_limit] kPa
"} signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - spawn(5) - src.updateUsrDialog() - /obj/machinery/computer/general_air_control/fuel_injection icon = 'icons/obj/computer.dmi' icon_screen = "alert:0" @@ -437,27 +404,34 @@ Min Core Pressure: [pressure_limit] kPa
"} ..() -/obj/machinery/computer/general_air_control/fuel_injection/return_text() - var/output = ..() - - output += "Fuel Injection System
" - if(device_info) - var/power = device_info["power"] - var/volume_rate = device_info["volume_rate"] - output += {"Status: [power?("Injecting"):("On Hold")] Refresh
-Rate: [volume_rate] L/sec
"} - - if(automation) - output += "Automated Fuel Injection: Engaged
" - output += "Injector Controls Locked Out
" - else - output += "Automated Fuel Injection: Disengaged
" - output += "Injector: Toggle Power Inject (1 Cycle)
" +/obj/machinery/computer/general_air_control/fuel_injection/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + var/list/data = list() + var/sensors_ui[0] + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/sensor_data = sensor_information[id_tag] + sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) else - output += "ERROR: Can not find device Search
" + sensors_ui = null - return output + data["sensors"] = sensors_ui + data["fuel"] = 1 + data["automation"] = automation + + if(device_info) + data["device_info"] = list("power" = device_info["power"], "volume_rate" = device_info["volume_rate"]) + else + data["device_info"] = null + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "atmo_control.tmpl", src.name, 650, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(5) /obj/machinery/computer/general_air_control/fuel_injection/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm index e2a0aed826..5f0860606b 100644 --- a/code/game/machinery/atmoalter/meter.dm +++ b/code/game/machinery/atmoalter/meter.dm @@ -68,7 +68,7 @@ /obj/machinery/meter/examine(mob/user) var/t = "A gas flow meter. " - if(get_dist(user, src) > 3 && !(istype(user, /mob/living/silicon/ai) || istype(user, /mob/dead))) + if(get_dist(user, src) > 3 && !(istype(user, /mob/living/silicon/ai) || istype(user, /mob/observer/dead))) t += "You are too far away to read it." else if(stat & (NOPOWER|BROKEN)) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 972d9a717b..5901148603 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -7,7 +7,7 @@ use_power = 1 idle_power_usage = 10 active_power_usage = 2000 - + circuit = /obj/item/weapon/circuitboard/autolathe var/list/machine_recipes var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) @@ -23,21 +23,18 @@ var/datum/wires/autolathe/wires = null - /obj/machinery/autolathe/New() - ..() wires = new(src) - //Create parts for lathe. + circuit = new circuit(src) component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/autolathe(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/manipulator(src) component_parts += new /obj/item/weapon/stock_parts/console_screen(src) RefreshParts() - + /obj/machinery/autolathe/Destroy() qdel(wires) wires = null @@ -101,6 +98,7 @@ //Build list of multipliers for sheets. if(R.is_stack) if(max_sheets && max_sheets > 0) + max_sheets = min(max_sheets, R.max_stack) // Limit to the max allowed by stack type. multiplier_string += "
" for(var/i = 5;i