Merge branch 'master' of https://github.com/PolarisSS13/Polaris into ATaleofBlobsandMen

# FixConflicts:
#	polaris.dme
This commit is contained in:
Mechoid
2020-04-09 22:55:42 -07:00
773 changed files with 30521 additions and 10522 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,7 @@
#ignore misc BYOND files #ignore misc BYOND files
Thumbs.db Thumbs.db
vchat.db
vchat.db*
*.log *.log
*.int *.int
*.rsc *.rsc

View File

@@ -1,16 +1,12 @@
#pretending we're C because otherwise ruby will initialize, even with "language: dm". #pretending we're C because otherwise ruby will initialize, even with "language: dm".
language: c language: c
sudo: false
env: env:
global: global:
- BASENAME="polaris" # $BASENAME.dmb, $BASENAME.dme, etc.
- BYOND_MAJOR="513" - BYOND_MAJOR="513"
- BYOND_MINOR="1502" - BYOND_MINOR="1513"
- MACRO_COUNT=4 - MACRO_COUNT=4
matrix:
- TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0"
- TEST_DEFINE="AWAY_MISSION_TEST" TEST_FILE="code/_away_mission_tests.dm" RUN="0"
- TEST_DEFINE="UNIT_TEST" TEST_FILE="code/_unit_tests.dm" RUN="1"
cache: cache:
directories: directories:
@@ -22,30 +18,38 @@ addons:
- libc6-i386 - libc6-i386
- libgcc1:i386 - libgcc1:i386
- libstdc++6:i386 - libstdc++6:i386
- libssl-dev:i386
before_script: before_install:
- chmod +x ./install-byond.sh - chmod -R +x ./tools/travis
- ./install-byond.sh
install: install:
- pip install --user PyYaml -q - ./tools/travis/install_byond.sh
- pip install --user beautifulsoup4 -q
before_script:
- shopt -s globstar
script: script:
- shopt -s globstar - ./tools/travis/compile_and_run.sh
- (! grep 'step_[xy]' maps/**/*.dmm)
- (! grep -Pn '( |\t|;|{)tag( ?)=' maps/**/*.dmm)
- (! find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano)
- (! 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 ../..
# Run our test
- cp config/example/* config/
- echo "#define ${TEST_DEFINE} 1" > ${TEST_FILE}
- DreamMaker polaris.dme
- if [ $RUN -eq 1 ]; then DreamDaemon polaris.dmb -invisible -trusted -core 2>&1 | tee log.txt; fi
- if [ $RUN -eq 1 ]; then grep "All Unit Tests Passed" log.txt; fi
# Build-specific settings
jobs:
include:
- stage: "File Tests" #This is the odd man out, with specific installs and stuff.
name: "Validate Files"
install: #Need python for some of the tag matching stuff
- pip install --user PyYaml -q
- pip install --user beautifulsoup4 -q
script: ./tools/travis/validate_files.sh
addons:
apt:
packages: ~ # Don't need any packages for this
- stage: "Unit Tests"
env: TEST_DEFINE="UNIT_TEST" TEST_FILE="code/_unit_tests.dm" RUN="1"
name: "Compile normally (unit tests)"
- stage: "Isolation Tests"
env: TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0"
name: "Compile POIs (no run)"
- env: TEST_DEFINE="AWAY_MISSION_TEST" TEST_FILE="code/_away_mission_tests.dm" RUN="0"
name: "Compile away missions (no run)"

View File

@@ -1,7 +1,7 @@
/obj/machinery/atmospherics/binary /obj/machinery/atmospherics/binary
dir = SOUTH dir = SOUTH
initialize_directions = SOUTH|NORTH initialize_directions = SOUTH|NORTH
use_power = 1 use_power = USE_POWER_IDLE
var/datum/gas_mixture/air1 var/datum/gas_mixture/air1
var/datum/gas_mixture/air2 var/datum/gas_mixture/air2

View File

@@ -20,7 +20,7 @@
level = 1 level = 1
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP power_rating = 7500 //7500 W ~ 10 HP
@@ -214,10 +214,10 @@
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0 return 0
if(signal.data["power"]) if(signal.data["power"])
use_power = text2num(signal.data["power"]) update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"]) if(signal.data["power_toggle"])
use_power = !use_power update_use_power(!use_power)
if(signal.data["direction"]) if(signal.data["direction"])
pump_direction = text2num(signal.data["direction"]) pump_direction = text2num(signal.data["direction"])

View File

@@ -12,7 +12,7 @@
name = "pressure regulator" name = "pressure regulator"
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power." desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
use_power = 0 use_power = USE_POWER_OFF
var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards). var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards).
var/target_pressure = ONE_ATMOSPHERE var/target_pressure = ONE_ATMOSPHERE

View File

@@ -237,10 +237,9 @@
var/kin_to_el_ratio = 0.1 //How much kinetic energy will be taken from turbine and converted into electricity var/kin_to_el_ratio = 0.1 //How much kinetic energy will be taken from turbine and converted into electricity
var/obj/machinery/atmospherics/pipeturbine/turbine var/obj/machinery/atmospherics/pipeturbine/turbine
/obj/machinery/power/turbinemotor/New() /obj/machinery/power/turbinemotor/Initialize()
..() . = ..()
spawn(1) updateConnection()
updateConnection()
/obj/machinery/power/turbinemotor/proc/updateConnection() /obj/machinery/power/turbinemotor/proc/updateConnection()
turbine = null turbine = null

View File

@@ -26,7 +26,7 @@ Thus, the two variables affect pump operation are set in New():
//var/max_volume_transfer = 10000 //var/max_volume_transfer = 10000
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP power_rating = 7500 //7500 W ~ 10 HP
@@ -47,7 +47,7 @@ Thus, the two variables affect pump operation are set in New():
/obj/machinery/atmospherics/binary/pump/on /obj/machinery/atmospherics/binary/pump/on
icon_state = "map_on" icon_state = "map_on"
use_power = 1 use_power = USE_POWER_IDLE
/obj/machinery/atmospherics/binary/pump/update_icon() /obj/machinery/atmospherics/binary/pump/update_icon()
@@ -160,12 +160,12 @@ Thus, the two variables affect pump operation are set in New():
if(signal.data["power"]) if(signal.data["power"])
if(text2num(signal.data["power"])) if(text2num(signal.data["power"]))
use_power = 1 update_use_power(USE_POWER_IDLE)
else else
use_power = 0 update_use_power(USE_POWER_OFF)
if("power_toggle" in signal.data) if("power_toggle" in signal.data)
use_power = !use_power update_use_power(!use_power)
if(signal.data["set_output_pressure"]) if(signal.data["set_output_pressure"])
target_pressure = between( target_pressure = between(
@@ -199,7 +199,7 @@ Thus, the two variables affect pump operation are set in New():
if(..()) return 1 if(..()) return 1
if(href_list["power"]) if(href_list["power"])
use_power = !use_power update_use_power(!use_power)
switch(href_list["set_press"]) switch(href_list["set_press"])
if ("min") if ("min")

View File

@@ -11,7 +11,7 @@
power_rating = 15000 //15000 W ~ 20 HP power_rating = 15000 //15000 W ~ 20 HP
/obj/machinery/atmospherics/binary/pump/high_power/on /obj/machinery/atmospherics/binary/pump/high_power/on
use_power = 1 use_power = USE_POWER_IDLE
icon_state = "map_on" icon_state = "map_on"
/obj/machinery/atmospherics/binary/pump/high_power/update_icon() /obj/machinery/atmospherics/binary/pump/high_power/update_icon()

View File

@@ -11,7 +11,7 @@
var/datum/omni_port/input var/datum/omni_port/input
var/datum/omni_port/output var/datum/omni_port/output
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP power_rating = 7500 //7500 W ~ 10 HP
@@ -161,13 +161,13 @@
switch(href_list["command"]) switch(href_list["command"])
if("power") if("power")
if(!configuring) if(!configuring)
use_power = !use_power update_use_power(!use_power)
else else
use_power = 0 update_use_power(USE_POWER_OFF)
if("configure") if("configure")
configuring = !configuring configuring = !configuring
if(configuring) if(configuring)
use_power = 0 update_use_power(USE_POWER_OFF)
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !use_power) if(configuring && !use_power)

View File

@@ -6,7 +6,7 @@
icon_state = "map_mixer" icon_state = "map_mixer"
pipe_state = "omni_mixer" pipe_state = "omni_mixer"
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 3700 //3700 W ~ 5 HP power_rating = 3700 //3700 W ~ 5 HP
@@ -178,13 +178,13 @@
switch(href_list["command"]) switch(href_list["command"])
if("power") if("power")
if(!configuring) if(!configuring)
use_power = !use_power update_use_power(!use_power)
else else
use_power = 0 update_use_power(USE_POWER_OFF)
if("configure") if("configure")
configuring = !configuring configuring = !configuring
if(configuring) if(configuring)
use_power = 0 update_use_power(USE_POWER_OFF)
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !use_power) if(configuring && !use_power)

View File

@@ -5,7 +5,7 @@
name = "omni device" name = "omni device"
icon = 'icons/atmos/omni_devices.dmi' icon = 'icons/atmos/omni_devices.dmi'
icon_state = "base" icon_state = "base"
use_power = 1 use_power = USE_POWER_IDLE
initialize_directions = 0 initialize_directions = 0
construction_type = /obj/item/pipe/quaternary construction_type = /obj/item/pipe/quaternary
level = 1 level = 1
@@ -67,7 +67,7 @@
last_flow_rate = 0 last_flow_rate = 0
if(error_check()) if(error_check())
use_power = 0 update_use_power(USE_POWER_OFF)
if((stat & (NOPOWER|BROKEN)) || !use_power) if((stat & (NOPOWER|BROKEN)) || !use_power)
return 0 return 0

View File

@@ -18,7 +18,7 @@
var/datum/pipe_network/network var/datum/pipe_network/network
var/on = 0 var/on = 0
use_power = 0 use_power = USE_POWER_OFF
level = 1 level = 1
/obj/machinery/atmospherics/portables_connector/init_dir() /obj/machinery/atmospherics/portables_connector/init_dir()

View File

@@ -9,7 +9,7 @@
name = "Gas filter" name = "Gas filter"
desc = "Filters one type of gas from an input, and pushes it out the side." desc = "Filters one type of gas from an input, and pushes it out the side."
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP
@@ -73,7 +73,7 @@
icon_state += use_power ? "on" : "off" icon_state += use_power ? "on" : "off"
else else
icon_state += "off" icon_state += "off"
use_power = 0 update_use_power(USE_POWER_OFF)
/obj/machinery/atmospherics/trinary/atmos_filter/process() /obj/machinery/atmospherics/trinary/atmos_filter/process()
..() ..()

View File

@@ -8,7 +8,7 @@
name = "Gas mixer" name = "Gas mixer"
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
@@ -35,7 +35,7 @@
icon_state += use_power ? "on" : "off" icon_state += use_power ? "on" : "off"
else else
icon_state += "off" icon_state += "off"
use_power = 0 update_use_power(USE_POWER_OFF)
/obj/machinery/atmospherics/trinary/mixer/New() /obj/machinery/atmospherics/trinary/mixer/New()
..() ..()
@@ -114,7 +114,7 @@
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) /obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
if(..()) return 1 if(..()) return 1
if(href_list["power"]) if(href_list["power"])
use_power = !use_power update_use_power(!use_power)
if(href_list["set_press"]) if(href_list["set_press"])
var/max_flow_rate = min(air1.volume, air2.volume) var/max_flow_rate = min(air1.volume, air2.volume)
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num

View File

@@ -1,7 +1,7 @@
/obj/machinery/atmospherics/trinary /obj/machinery/atmospherics/trinary
dir = SOUTH dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST initialize_directions = SOUTH|NORTH|WEST
use_power = 0 use_power = USE_POWER_OFF
pipe_flags = PIPING_DEFAULT_LAYER_ONLY|PIPING_ONE_PER_TURF pipe_flags = PIPING_DEFAULT_LAYER_ONLY|PIPING_ONE_PER_TURF
var/mirrored = FALSE var/mirrored = FALSE

View File

@@ -8,7 +8,7 @@
icon_state = "freezer_0" icon_state = "freezer_0"
density = 1 density = 1
anchored = 1 anchored = 1
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 5 // 5 Watts for thermostat related circuitry idle_power_usage = 5 // 5 Watts for thermostat related circuitry
circuit = /obj/item/weapon/circuitboard/unary_atmos/cooler circuit = /obj/item/weapon/circuitboard/unary_atmos/cooler
@@ -99,7 +99,7 @@
if(..()) if(..())
return 1 return 1
if(href_list["toggleStatus"]) if(href_list["toggleStatus"])
use_power = !use_power update_use_power(!use_power)
update_icon() update_icon()
if(href_list["temp"]) if(href_list["temp"])
var/amount = text2num(href_list["temp"]) var/amount = text2num(href_list["temp"])

View File

@@ -8,7 +8,7 @@
icon_state = "heater_0" icon_state = "heater_0"
density = 1 density = 1
anchored = 1 anchored = 1
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 5 //5 Watts for thermostat related circuitry idle_power_usage = 5 //5 Watts for thermostat related circuitry
circuit = /obj/item/weapon/circuitboard/unary_atmos/heater circuit = /obj/item/weapon/circuitboard/unary_atmos/heater
@@ -119,7 +119,7 @@
if(..()) if(..())
return 1 return 1
if(href_list["toggleStatus"]) if(href_list["toggleStatus"])
use_power = !use_power update_use_power(!use_power)
update_icon() update_icon()
if(href_list["temp"]) if(href_list["temp"])
var/amount = text2num(href_list["temp"]) var/amount = text2num(href_list["temp"])

View File

@@ -10,7 +10,7 @@
name = "air injector" name = "air injector"
desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate." desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate."
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 15000 //15000 W ~ 20 HP power_rating = 15000 //15000 W ~ 20 HP
@@ -132,10 +132,10 @@
return 0 return 0
if(signal.data["power"]) if(signal.data["power"])
use_power = text2num(signal.data["power"]) update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"]) if(signal.data["power_toggle"])
use_power = !use_power update_use_power(!use_power)
if(signal.data["inject"]) if(signal.data["inject"])
spawn inject() spawn inject()
@@ -160,7 +160,7 @@
/obj/machinery/atmospherics/unary/outlet_injector/attack_hand(mob/user as mob) /obj/machinery/atmospherics/unary/outlet_injector/attack_hand(mob/user as mob)
to_chat(user, "<span class='notice'>You toggle \the [src].</span>") to_chat(user, "<span class='notice'>You toggle \the [src].</span>")
injecting = !injecting injecting = !injecting
use_power = injecting update_use_power(injecting ? USE_POWER_IDLE : USE_POWER_OFF)
update_icon() update_icon()
/obj/machinery/atmospherics/unary/outlet_injector/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) /obj/machinery/atmospherics/unary/outlet_injector/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)

View File

@@ -14,7 +14,7 @@
name = "Air Vent" name = "Air Vent"
desc = "Has a valve and pump attached to it" desc = "Has a valve and pump attached to it"
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP power_rating = 7500 //7500 W ~ 10 HP
@@ -50,18 +50,18 @@
var/datum/looping_sound/air_pump/soundloop var/datum/looping_sound/air_pump/soundloop
/obj/machinery/atmospherics/unary/vent_pump/on /obj/machinery/atmospherics/unary/vent_pump/on
use_power = 1 use_power = USE_POWER_IDLE
icon_state = "map_vent_out" icon_state = "map_vent_out"
/obj/machinery/atmospherics/unary/vent_pump/siphon /obj/machinery/atmospherics/unary/vent_pump/siphon
pump_direction = 0 pump_direction = 0
/obj/machinery/atmospherics/unary/vent_pump/siphon/on /obj/machinery/atmospherics/unary/vent_pump/siphon/on
use_power = 1 use_power = USE_POWER_IDLE
icon_state = "map_vent_in" icon_state = "map_vent_in"
/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos /obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos
use_power = 1 use_power = USE_POWER_IDLE
icon_state = "map_vent_in" icon_state = "map_vent_in"
external_pressure_bound = 0 external_pressure_bound = 0
external_pressure_bound_default = 0 external_pressure_bound_default = 0
@@ -173,7 +173,7 @@
return 1 return 1
if (!node) if (!node)
use_power = 0 update_use_power(USE_POWER_OFF)
if(!can_pump()) if(!can_pump())
return 0 return 0
@@ -295,10 +295,10 @@
pump_direction = 1 pump_direction = 1
if(signal.data["power"] != null) if(signal.data["power"] != null)
use_power = text2num(signal.data["power"]) update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"] != null) if(signal.data["power_toggle"] != null)
use_power = !use_power update_use_power(!use_power)
if(signal.data["checks"] != null) if(signal.data["checks"] != null)
if (signal.data["checks"] == "default") if (signal.data["checks"] == "default")

View File

@@ -5,7 +5,7 @@
name = "Air Scrubber" name = "Air Scrubber"
desc = "Has a valve and pump attached to it" desc = "Has a valve and pump attached to it"
use_power = 0 use_power = USE_POWER_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP power_rating = 7500 //7500 W ~ 10 HP
@@ -29,7 +29,7 @@
var/radio_filter_in var/radio_filter_in
/obj/machinery/atmospherics/unary/vent_scrubber/on /obj/machinery/atmospherics/unary/vent_scrubber/on
use_power = 1 use_power = USE_POWER_IDLE
icon_state = "map_scrubber_on" icon_state = "map_scrubber_on"
/obj/machinery/atmospherics/unary/vent_scrubber/New() /obj/machinery/atmospherics/unary/vent_scrubber/New()
@@ -135,7 +135,7 @@
return 1 return 1
if (!node) if (!node)
use_power = 0 update_use_power(USE_POWER_OFF)
//broadcast_status() //broadcast_status()
if(!use_power || (stat & (NOPOWER|BROKEN))) if(!use_power || (stat & (NOPOWER|BROKEN)))
return 0 return 0
@@ -180,21 +180,21 @@
return 0 return 0
if(signal.data["power"] != null) if(signal.data["power"] != null)
use_power = text2num(signal.data["power"]) update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"] != null) if(signal.data["power_toggle"] != null)
use_power = !use_power update_use_power(!use_power)
if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing
panic = text2num(signal.data["panic_siphon"]) panic = text2num(signal.data["panic_siphon"])
if(panic) if(panic)
use_power = 1 update_use_power(USE_POWER_IDLE)
scrubbing = 0 scrubbing = 0
else else
scrubbing = 1 scrubbing = 1
if(signal.data["toggle_panic_siphon"] != null) if(signal.data["toggle_panic_siphon"] != null)
panic = !panic panic = !panic
if(panic) if(panic)
use_power = 1 update_use_power(USE_POWER_IDLE)
scrubbing = 0 scrubbing = 0
else else
scrubbing = 1 scrubbing = 1

View File

@@ -9,7 +9,7 @@
var/leaking = FALSE // Do not set directly, use set_leaking(TRUE/FALSE) var/leaking = FALSE // Do not set directly, use set_leaking(TRUE/FALSE)
layer = PIPES_LAYER layer = PIPES_LAYER
use_power = 0 use_power = USE_POWER_OFF
pipe_flags = 0 // Does not have PIPING_DEFAULT_LAYER_ONLY flag. pipe_flags = 0 // Does not have PIPING_DEFAULT_LAYER_ONLY flag.

View File

@@ -22,7 +22,7 @@ What can I do with Planesmasters?
Planesmasters can be used as a neater way to deal with client images or potentially to do some neat things Planesmasters can be used as a neater way to deal with client images or potentially to do some neat things
How do planes work? How do planes work?
A plane can be any integer from -100 to 100. (If you want more, bug lummox.) A plane can be any integer from -10000 to 10000.
All planes above 0, the 'base plane', are visible even when your character cannot 'see' them, for example, the HUD. All planes above 0, the 'base plane', are visible even when your character cannot 'see' them, for example, the HUD.
All planes below 0, the 'base plane', are only visible when a character can see them. All planes below 0, the 'base plane', are only visible when a character can see them.
@@ -40,8 +40,14 @@ What is the naming convention for planes or layers?
*/ */
#define SPACE_PLANE -82 // Reserved for use in space/parallax #define SPACE_PLANE -82 // Reserved for use in space/parallax
#define PARALLAX_PLANE -80 // Reserved for use in space/parallax #define PARALLAX_PLANE -81 // Reserved for use in space/parallax
#define SKYBOX_PLANE -80 // Skybox parallax
#define DUST_PLANE -79 // For dust overlay on space turfs. Should be above skybox for parallax effect.
#define PLANE_LOOKINGGLASS -78 // For the Looking Glass holodecks
#define PLANE_LOOKINGGLASS_IMG -77 // For the Looking Glass holodecks
// OPENSPACE_PLANE reserves all planes between OPENSPACE_PLANE_START and OPENSPACE_PLANE_END inclusive // OPENSPACE_PLANE reserves all planes between OPENSPACE_PLANE_START and OPENSPACE_PLANE_END inclusive
#define OPENSPACE_PLANE -75 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 17) #define OPENSPACE_PLANE -75 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 17)
@@ -50,7 +56,6 @@ What is the naming convention for planes or layers?
#define OVER_OPENSPACE_PLANE -57 #define OVER_OPENSPACE_PLANE -57
// Turf Planes // Turf Planes
#define SPACE_PLANE -43 // Space turfs themselves
#define PLATING_PLANE -44 // Plating #define PLATING_PLANE -44 // Plating
#define DISPOSAL_LAYER 2.1 // Under objects, even when planeswapped #define DISPOSAL_LAYER 2.1 // Under objects, even when planeswapped
#define PIPES_LAYER 2.2 // Under objects, even when planeswapped #define PIPES_LAYER 2.2 // Under objects, even when planeswapped
@@ -86,6 +91,9 @@ What is the naming convention for planes or layers?
#define BELOW_MOB_LAYER 3.9 // Should be converted to plane swaps #define BELOW_MOB_LAYER 3.9 // Should be converted to plane swaps
#define ABOVE_MOB_LAYER 4.1 // Should be converted to plane swaps #define ABOVE_MOB_LAYER 4.1 // Should be converted to plane swaps
// Invisible things plane
#define CLOAKED_PLANE -15
// Top plane (in the sense that it's the highest in 'the world' and not a UI element) // Top plane (in the sense that it's the highest in 'the world' and not a UI element)
#define ABOVE_PLANE -10 #define ABOVE_PLANE -10

View File

@@ -29,6 +29,7 @@
#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Minimum amount of air that has to move before a group processing can be suspended #define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Minimum amount of air that has to move before a group processing can be suspended
#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Either this must be active #define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Either this must be active
#define MINIMUM_TEMPERATURE_TO_MOVE (T20C + 100) // or this (or both, obviously) #define MINIMUM_TEMPERATURE_TO_MOVE (T20C + 100) // or this (or both, obviously)
#define MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND (MINIMUM_AIR_TO_SUSPEND*R_IDEAL_GAS_EQUATION*T20C)/CELL_VOLUME // Minimum pressure difference between zones to suspend
#define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012 // Minimum temperature difference before group processing is suspended. #define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012 // Minimum temperature difference before group processing is suspended.
#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 #define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4

View File

@@ -14,4 +14,6 @@
#define COLOR_ASSEMBLY_LBLUE "#5D99BE" #define COLOR_ASSEMBLY_LBLUE "#5D99BE"
#define COLOR_ASSEMBLY_BLUE "#38559E" #define COLOR_ASSEMBLY_BLUE "#38559E"
#define COLOR_ASSEMBLY_PURPLE "#6F6192" #define COLOR_ASSEMBLY_PURPLE "#6F6192"
#define COLOR_ASSEMBLY_HOT_PINK "#FF69B4" #define COLOR_ASSEMBLY_HOT_PINK "#FF69B4"
#define COLOR_ASTEROID_ROCK "#735555"

View File

@@ -38,6 +38,7 @@
#define CONNECT_TYPE_SUPPLY 2 #define CONNECT_TYPE_SUPPLY 2
#define CONNECT_TYPE_SCRUBBER 4 #define CONNECT_TYPE_SCRUBBER 4
#define CONNECT_TYPE_HE 8 #define CONNECT_TYPE_HE 8
#define CONNECT_TYPE_FUEL 16 // TODO - Implement this! Its piping so better ask Leshana
// We are based on the three named layers of supply, regular, and scrubber. // We are based on the three named layers of supply, regular, and scrubber.
#define PIPING_LAYER_SUPPLY 1 #define PIPING_LAYER_SUPPLY 1

View File

@@ -6,6 +6,7 @@
//--------------- //---------------
#define isatom(D) istype(D, /atom) #define isatom(D) istype(D, /atom)
#define isclient(D) istype(D, /client)
//--------------- //---------------
//#define isobj(D) istype(D, /obj) //Built in //#define isobj(D) istype(D, /obj) //Built in

View File

@@ -11,6 +11,11 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define DOOR_CRUSH_DAMAGE 20 #define DOOR_CRUSH_DAMAGE 20
#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. #define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien.
// Constants for machine's use_power
#define USE_POWER_OFF 0 // No continuous power use
#define USE_POWER_IDLE 1 // Machine is using power at its idle power level
#define USE_POWER_ACTIVE 2 // Machine is using power at its active power level
// Channel numbers for power. // Channel numbers for power.
#define EQUIP 1 #define EQUIP 1
#define LIGHT 2 #define LIGHT 2
@@ -24,6 +29,11 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define MAINT 0x8 // Under maintenance. #define MAINT 0x8 // Under maintenance.
#define EMPED 0x10 // Temporary broken by EMP pulse. #define EMPED 0x10 // Temporary broken by EMP pulse.
// Remote control states
#define RCON_NO 1
#define RCON_AUTO 2
#define RCON_YES 3
// Used by firelocks // Used by firelocks
#define FIREDOOR_OPEN 1 #define FIREDOOR_OPEN 1
#define FIREDOOR_CLOSED 2 #define FIREDOOR_CLOSED 2

View File

@@ -2,7 +2,7 @@
// Turf-only flags. // Turf-only flags.
#define NOJAUNT 1 // This is used in literally one place, turf.dm, to block ethereal jaunt. #define NOJAUNT 1 // This is used in literally one place, turf.dm, to block ethereal jaunt.
#define TRANSITIONEDGE 7 // Distance from edge to move to another z-level. #define TRANSITIONEDGE 1 // Distance from edge to move to another z-level.
// Invisibility constants. These should only be used for TRUE invisibility, AKA nothing living players touch // Invisibility constants. These should only be used for TRUE invisibility, AKA nothing living players touch
#define INVISIBILITY_LIGHTING 20 #define INVISIBILITY_LIGHTING 20
@@ -80,7 +80,7 @@
#define COLOR_DARK_GRAY "#404040" #define COLOR_DARK_GRAY "#404040"
#define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (isclient(I) ? I : null))
// Shuttles. // Shuttles.
@@ -270,6 +270,7 @@
#define WORLD_ICON_SIZE 32 //Needed for the R-UST port #define WORLD_ICON_SIZE 32 //Needed for the R-UST port
#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port #define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port
#define MAX_CLIENT_VIEW 34 // Maximum effective value of client.view (According to DM references)
// Maploader bounds indices // Maploader bounds indices
#define MAP_MINX 1 #define MAP_MINX 1

View File

@@ -396,7 +396,9 @@
#define VIS_BUILDMODE 22 #define VIS_BUILDMODE 22
#define VIS_COUNT 22 //Must be highest number from above. #define VIS_CLOAKED 23
#define VIS_COUNT 23 //Must be highest number from above.
//Some mob icon layering defines //Some mob icon layering defines
#define BODY_LAYER -100 #define BODY_LAYER -100

16
code/__defines/overmap.dm Normal file
View File

@@ -0,0 +1,16 @@
//How far from the edge of overmap zlevel could randomly placed objects spawn
#define OVERMAP_EDGE 2
#define SHIP_SIZE_TINY 1
#define SHIP_SIZE_SMALL 2
#define SHIP_SIZE_LARGE 3
//multipliers for max_speed to find 'slow' and 'fast' speeds for the ship
#define SHIP_SPEED_SLOW 1/(40 SECONDS)
#define SHIP_SPEED_FAST 3/(20 SECONDS)// 15 speed
#define OVERMAP_WEAKNESS_NONE 0
#define OVERMAP_WEAKNESS_FIRE 1
#define OVERMAP_WEAKNESS_EMP 2
#define OVERMAP_WEAKNESS_MINING 4
#define OVERMAP_WEAKNESS_EXPLOSIVE 8

View File

@@ -0,0 +1,6 @@
#define EXAMINE_MODE_DEFAULT 0
#define EXAMINE_MODE_INCLUDE_USAGE 1
#define EXAMINE_MODE_SWITCH_TO_PANEL 2
// Should be one higher than the above
#define EXAMINE_MODE_MAX 3

View File

@@ -9,6 +9,11 @@
#define SLANDMARK_FLAG_AUTOSET 1 // If set, will set base area and turf type to same as where it was spawned at #define SLANDMARK_FLAG_AUTOSET 1 // If set, will set base area and turf type to same as where it was spawned at
#define SLANDMARK_FLAG_ZERO_G 2 // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity. #define SLANDMARK_FLAG_ZERO_G 2 // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity.
// Overmap landable shuttles (/obj/effect/overmap/visitable/ship/landable on a /datum/shuttle/autodock/overmap)
#define SHIP_STATUS_LANDED 1 // Ship is at any other shuttle landmark.
#define SHIP_STATUS_TRANSIT 2 // Ship is at it's shuttle datum's transition shuttle landmark.
#define SHIP_STATUS_OVERMAP 3 // Ship is at its "overmap" shuttle landmark (allowed to move on overmap now)
// Ferry shuttle location constants // Ferry shuttle location constants
#define FERRY_LOCATION_STATION 0 #define FERRY_LOCATION_STATION 0
#define FERRY_LOCATION_OFFSITE 1 #define FERRY_LOCATION_OFFSITE 1

View File

@@ -52,10 +52,12 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
// Subsystem init_order, from highest priority to lowest priority // Subsystem init_order, from highest priority to lowest priority
// Subsystems shutdown in the reverse of the order they initialize in // Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise. // The numbers just define the ordering, they are meaningless otherwise.
#define INIT_ORDER_SQLITE 19 #define INIT_ORDER_SQLITE 40
#define INIT_ORDER_CHEMISTRY 18 #define INIT_ORDER_CHEMISTRY 35
#define INIT_ORDER_MAPPING 17 #define INIT_ORDER_SKYBOX 30
#define INIT_ORDER_DECALS 16 #define INIT_ORDER_MAPPING 25
#define INIT_ORDER_DECALS 20
#define INIT_ORDER_JOB 17
#define INIT_ORDER_ATOMS 15 #define INIT_ORDER_ATOMS 15
#define INIT_ORDER_MACHINES 10 #define INIT_ORDER_MACHINES 10
#define INIT_ORDER_SHUTTLES 3 #define INIT_ORDER_SHUTTLES 3
@@ -63,22 +65,27 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_DEFAULT 0 #define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_LIGHTING 0 #define INIT_ORDER_LIGHTING 0
#define INIT_ORDER_AIR -1 #define INIT_ORDER_AIR -1
#define INIT_ORDER_ASSETS -3
#define INIT_ORDER_PLANETS -4 #define INIT_ORDER_PLANETS -4
#define INIT_ORDER_HOLOMAPS -5 #define INIT_ORDER_HOLOMAPS -5
#define INIT_ORDER_OVERLAY -6 #define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_ALARM -7
#define INIT_ORDER_XENOARCH -20 #define INIT_ORDER_XENOARCH -20
#define INIT_ORDER_CIRCUIT -21 #define INIT_ORDER_CIRCUIT -21
#define INIT_ORDER_AI -22 #define INIT_ORDER_AI -22
#define INIT_ORDER_JOB -23 #define INIT_ORDER_GAME_MASTER -24
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
// Subsystem fire priority, from lowest to highest priority // Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
#define FIRE_PRIORITY_SHUTTLES 5 #define FIRE_PRIORITY_SHUTTLES 5
#define FIRE_PRIORITY_SUPPLY 5
#define FIRE_PRIORITY_ORBIT 8 #define FIRE_PRIORITY_ORBIT 8
#define FIRE_PRIORITY_VOTE 9 #define FIRE_PRIORITY_VOTE 9
#define FIRE_PRIORITY_AI 10 #define FIRE_PRIORITY_AI 10
#define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_ALARM 20
#define FIRE_PRIORITY_CHARSETUP 25 #define FIRE_PRIORITY_CHARSETUP 25
#define FIRE_PRIORITY_AIRFLOW 30 #define FIRE_PRIORITY_AIRFLOW 30
#define FIRE_PRIORITY_AIR 35 #define FIRE_PRIORITY_AIR 35
@@ -88,6 +95,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_PLANETS 75 #define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100 #define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_PROJECTILES 150 #define FIRE_PRIORITY_PROJECTILES 150
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500 #define FIRE_PRIORITY_OVERLAYS 500
// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed) // Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)

View File

@@ -37,7 +37,11 @@
#define ARCHAEO_ALIEN_BOAT 37 #define ARCHAEO_ALIEN_BOAT 37
#define ARCHAEO_IMPERION_CIRCUIT 38 #define ARCHAEO_IMPERION_CIRCUIT 38
#define ARCHAEO_TELECUBE 39 #define ARCHAEO_TELECUBE 39
#define MAX_ARCHAEO 39 #define ARCHAEO_BATTERY 40
#define ARCHAEO_SYRINGE 41
#define ARCHAEO_RING 42
#define ARCHAEO_CLUB 43
#define MAX_ARCHAEO 43
#define DIGSITE_GARDEN 1 #define DIGSITE_GARDEN 1
#define DIGSITE_ANIMAL 2 #define DIGSITE_ANIMAL 2

View File

@@ -6,10 +6,10 @@
*/ */
// Determiner constants // Determiner constants
#define DET_NONE 0x00; #define DET_NONE 0x00
#define DET_DEFINITE 0x01; // the #define DET_DEFINITE 0x01 // the
#define DET_INDEFINITE 0x02; // a, an, some #define DET_INDEFINITE 0x02 // a, an, some
#define DET_AUTO 0x04; #define DET_AUTO 0x04
/* /*
* Misc * Misc
@@ -53,7 +53,7 @@
// atoms/items/objects can be pretty and whatnot // atoms/items/objects can be pretty and whatnot
var/atom/A = item var/atom/A = item
if(output_icons && isicon(A.icon) && !ismob(A)) // mobs tend to have unusable icons if(output_icons && isicon(A.icon) && !ismob(A)) // mobs tend to have unusable icons
item_str += "\icon[A]&nbsp;" item_str += "[bicon(A)]&nbsp;"
switch(determiners) switch(determiners)
if(DET_NONE) item_str += A.name if(DET_NONE) item_str += A.name
if(DET_DEFINITE) item_str += "\the [A]" if(DET_DEFINITE) item_str += "\the [A]"
@@ -206,6 +206,20 @@ proc/listclearnulls(list/list)
result = first - second result = first - second
return result return result
/*
Two lists may be different (A!=B) even if they have the same elements.
This actually tests if they have the same entries and values.
*/
/proc/same_entries(var/list/first, var/list/second)
if(!islist(first) || !islist(second))
return 0
if(length(first) != length(second))
return 0
for(var/entry in first)
if(!(entry in second) || (first[entry] != second[entry]))
return 0
return 1
/* /*
* Returns list containing entries that are in either list but not both. * Returns list containing entries that are in either list but not both.
* If skipref = 1, repeated elements are treated as one. * If skipref = 1, repeated elements are treated as one.
@@ -831,3 +845,18 @@ proc/dd_sortedTextList(list/incoming)
if(L.len) if(L.len)
. = L[1] . = L[1]
L.Cut(1,2) L.Cut(1,2)
//generates a list used to randomize transit animations so they aren't in lockstep
/proc/get_cross_shift_list(var/size)
var/list/result = list()
result += rand(0, 14)
for(var/i in 2 to size)
var/shifts = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
shifts -= result[i - 1] //consecutive shifts should not be equal
if(i == size)
shifts -= result[1] //because shift list is a ring buffer
result += pick(shifts)
return result

View File

@@ -24,4 +24,16 @@
if(A == myarea) //The loc of a turf is the area it is in. if(A == myarea) //The loc of a turf is the area it is in.
return 1 return 1
return 0 return 0
// Returns a list of area instances, or a subtypes of them, that are mapped in somewhere.
// Avoid feeding it `/area`, as it will likely cause a lot of lag as it evaluates every single area coded in.
/proc/get_all_existing_areas_of_types(list/area_types)
. = list()
for(var/area_type in area_types)
var/list/types = typesof(area_type)
for(var/T in types)
// Test for existance.
var/area/A = locate(T)
if(!istype(A) || !A.contents.len) // Empty contents list means it's not on the map.
continue
. += A

View File

@@ -19,8 +19,6 @@ var/global/list/side_effects = list() //list of all medical sideeffects types
var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking. var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
var/global/list/joblist = list() //list of all jobstypes, minus borg and AI 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_define_list list(MALE,FEMALE,PLURAL,NEUTER)
#define all_genders_text_list list("Male","Female","Plural","Neuter") #define all_genders_text_list list("Male","Female","Plural","Neuter")
@@ -30,9 +28,6 @@ var/list/mannequins_
var/global/list/poster_designs = list() var/global/list/poster_designs = list()
var/global/list/NT_poster_designs = list() var/global/list/NT_poster_designs = list()
// Uplinks
var/list/obj/item/device/uplink/world_uplinks = list()
//Preferences stuff //Preferences stuff
//Hairstyles //Hairstyles
var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name

View File

@@ -167,7 +167,7 @@ mob
Output_Icon() Output_Icon()
set name = "2. Output Icon" set name = "2. Output Icon"
to_chat(src, "Icon is: \icon[getFlatIcon(src)]") to_chat(src, "Icon is: [bicon(getFlatIcon(src))]")
Label_Icon() Label_Icon()
set name = "3. Label Icon" set name = "3. Label Icon"

View File

@@ -1,38 +1,3 @@
/atom/movable/proc/get_mob()
return
/obj/mecha/get_mob()
return occupant
/obj/vehicle/train/get_mob()
return buckled_mobs
/mob/get_mob()
return src
/mob/living/bot/mulebot/get_mob()
if(load && istype(load, /mob/living))
return list(src, load)
return src
/proc/mobs_in_view(var/range, var/source)
var/list/mobs = list()
for(var/atom/movable/AM in view(range, source))
var/M = AM.get_mob()
if(M)
mobs += M
return mobs
/proc/mobs_in_xray_view(var/range, var/source)
var/list/mobs = list()
for(var/atom/movable/AM in orange(range, source))
var/M = AM.get_mob()
if(M)
mobs += M
return mobs
proc/random_hair_style(gender, species = SPECIES_HUMAN) proc/random_hair_style(gender, species = SPECIES_HUMAN)
var/h_style = "Bald" var/h_style = "Bald"

View File

@@ -301,11 +301,15 @@ proc/TextPreview(var/string,var/len=40)
//For generating neat chat tag-images //For generating neat chat tag-images
//The icon var could be local in the proc, but it's a waste of resources //The icon var could be local in the proc, but it's a waste of resources
// to always create it and then throw it out. // to always create it and then throw it out.
/var/icon/text_tag_icons = new('./icons/chattags.dmi') /var/icon/text_tag_icons = 'icons/chattags.dmi'
/var/list/text_tag_cache = list()
/proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) /proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null)
if(!(C && C.is_preference_enabled(/datum/client_preference/chat_tags))) if(!(C && C.is_preference_enabled(/datum/client_preference/chat_tags)))
return tagdesc return tagdesc
return "<IMG src='\ref[text_tag_icons.icon]' class='text_tag' iconstate='[tagname]'" + (tagdesc ? " alt='[tagdesc]'" : "") + ">" if(!text_tag_cache[tagname])
var/icon/tag = icon(text_tag_icons, tagname)
text_tag_cache[tagname] = bicon(tag, TRUE, "text_tag")
return text_tag_cache[tagname]
/proc/contains_az09(var/input) /proc/contains_az09(var/input)
for(var/i=1, i<=length(input), i++) for(var/i=1, i<=length(input), i++)

View File

@@ -33,6 +33,20 @@
available_turfs = start_turfs available_turfs = start_turfs
return pick(available_turfs) return pick(available_turfs)
// Picks a turf that is clearance tiles away from the map edge given by dir, on z-level Z
/proc/pick_random_edge_turf(var/dir, var/Z, var/clearance = TRANSITIONEDGE + 1)
if(!dir)
return
switch(dir)
if(NORTH)
return locate(rand(clearance, world.maxx - clearance), world.maxy - clearance, Z)
if(SOUTH)
return locate(rand(clearance, world.maxx - clearance), clearance, Z)
if(EAST)
return locate(world.maxx - clearance, rand(clearance, world.maxy - clearance), Z)
if(WEST)
return locate(clearance, rand(clearance, world.maxy - clearance), Z)
/proc/is_below_sound_pressure(var/turf/T) /proc/is_below_sound_pressure(var/turf/T)
var/datum/gas_mixture/environment = T ? T.return_air() : null var/datum/gas_mixture/environment = T ? T.return_air() : null
var/pressure = environment ? environment.return_pressure() : 0 var/pressure = environment ? environment.return_pressure() : 0

File diff suppressed because it is too large Load Diff

View File

@@ -2,9 +2,16 @@
#define get_turf(A) get_step(A,0) #define get_turf(A) get_step(A,0)
#define get_x(A) (get_step(A, 0)?.x || 0)
#define get_y(A) (get_step(A, 0)?.y || 0)
#define get_z(A) (get_step(A, 0)?.z || 0)
#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") #define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
#define to_chat(target, message) target << message // #define to_chat(target, message) target << message Not anymore!
#define to_chat to_chat_filename=__FILE__;to_chat_line=__LINE__;to_chat_src=src;__to_chat
#define to_world(message) to_chat(world, message) #define to_world(message) to_chat(world, message)
#define to_world_log(message) world.log << message #define to_world_log(message) world.log << message
// TODO - Baystation has this log to crazy places. For now lets just world.log, but maybe look into it later. // TODO - Baystation has this log to crazy places. For now lets just world.log, but maybe look into it later.

View File

@@ -0,0 +1,67 @@
#define SKYBOX_PADDING 4 // How much larger we want the skybox image to be than client's screen (in turfs)
#define SKYBOX_PIXELS 736 // Size of skybox image in pixels
#define SKYBOX_TURFS (SKYBOX_PIXELS/WORLD_ICON_SIZE)
// Skybox screen object.
/obj/skybox
name = "skybox"
mouse_opacity = 0
anchored = TRUE
simulated = FALSE
screen_loc = "CENTER,CENTER"
plane = SKYBOX_PLANE
blend_mode = BLEND_MULTIPLY // You actually need to do it this way or you see it in occlusion.
// Adjust transform property to scale for client's view var. We assume the skybox is 736x736 px
/obj/skybox/proc/scale_to_view(var/view)
var/matrix/M = matrix()
// Translate to center the icon over us!
M.Translate(-(SKYBOX_PIXELS - WORLD_ICON_SIZE) / 2)
// Scale appropriately based on view size. (7 results in scale of 1)
view = text2num(view) || 7 // Sanitize
M.Scale(((min(MAX_CLIENT_VIEW, view) + SKYBOX_PADDING) * 2 + 1) / SKYBOX_TURFS)
src.transform = M
/client
var/obj/skybox/skybox
/client/proc/update_skybox(rebuild)
if(!skybox)
skybox = new()
skybox.scale_to_view(src.view)
screen += skybox
rebuild = 1
var/turf/T = get_turf(eye)
if(T)
if(rebuild)
skybox.cut_overlays()
skybox.add_overlay(SSskybox.get_skybox(T.z))
screen |= skybox
skybox.screen_loc = "CENTER:[(world.maxx>>1) - T.x],CENTER:[(world.maxy>>1) - T.y]"
/mob/Login()
. = ..()
client.update_skybox(TRUE)
/mob/Move()
var/old_z = get_z(src)
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
/mob/forceMove()
var/old_z = get_z(src)
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
/mob/set_viewsize()
. = ..()
if (. && client)
client.update_skybox()
client.skybox?.scale_to_view(client.view)
#undef SKYBOX_BORDER
#undef SKYBOX_PIXELS
#undef SKYBOX_TURFS

View File

@@ -1,42 +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()
// Alarm Manager, the manager for alarms.
var/datum/controller/process/alarm/alarm_manager
/datum/controller/process/alarm
var/list/datum/alarm/all_handlers = list()
/datum/controller/process/alarm/setup()
name = "alarm"
schedule_interval = 20 // every 2 seconds
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
alarm_manager = src
/datum/controller/process/alarm/doWork()
for(last_object in all_handlers)
var/datum/alarm_handler/AH = last_object
AH.process()
SCHECK
/datum/controller/process/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/controller/process/alarm/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len
/datum/controller/process/alarm/statProcess()
..()
stat(null, "[number_of_active_alarms()] alarm\s")

View File

@@ -1,9 +0,0 @@
/datum/controller/process/emergencyShuttle/setup()
name = "emergency shuttle"
schedule_interval = 20 // every 2 seconds
if(!emergency_shuttle)
emergency_shuttle = new
/datum/controller/process/emergencyShuttle/doWork()
emergency_shuttle.process()

View File

@@ -1,6 +0,0 @@
/datum/controller/process/game_master/setup()
name = "\improper GM controller"
schedule_interval = 600 // every 60 seconds
/datum/controller/process/game_master/doWork()
game_master.process()

View File

@@ -1,29 +0,0 @@
/datum/controller/process/mob
var/tmp/datum/updateQueue/updateQueueInstance
/datum/controller/process/mob/setup()
name = "mob"
schedule_interval = 20 // every 2 seconds
start_delay = 16
/datum/controller/process/mob/started()
..()
if(!mob_list)
mob_list = list()
/datum/controller/process/mob/doWork()
for(last_object in mob_list)
var/mob/M = last_object
if(M && !QDELETED(M))
try
M.Life()
catch(var/exception/e)
catchException(e, M)
SCHECK
else
catchBadType(M)
mob_list -= M
/datum/controller/process/mob/statProcess()
..()
stat(null, "[mob_list.len] mobs")

View File

@@ -5,10 +5,10 @@ datum/controller/transfer_controller
var/currenttick = 0 var/currenttick = 0
datum/controller/transfer_controller/New() datum/controller/transfer_controller/New()
timerbuffer = config.vote_autotransfer_initial timerbuffer = config.vote_autotransfer_initial
START_PROCESSING(SSobj, src) START_PROCESSING(SSprocessing, src)
datum/controller/transfer_controller/Destroy() datum/controller/transfer_controller/Destroy()
STOP_PROCESSING(SSobj, src) STOP_PROCESSING(SSprocessing, src)
datum/controller/transfer_controller/process() datum/controller/transfer_controller/process()
currenttick = currenttick + 1 currenttick = currenttick + 1

View File

@@ -264,6 +264,12 @@ var/list/gamemode_cache = list()
var/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit. var/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit.
var/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers. var/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers.
var/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes.
var/defib_braindamage_timer = 2 // How long until someone will get brain damage when defibbed, in minutes. The closer to the end of the above timer, the more brain damage they get.
// disables the annoying "You have already logged in this round, disconnect or be banned" popup for multikeying, because it annoys the shit out of me when testing.
var/disable_cid_warn_popup = FALSE
/datum/configuration/New() /datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L) for (var/T in L)
@@ -873,7 +879,14 @@ var/list/gamemode_cache = list()
if("sqlite_feedback_cooldown") if("sqlite_feedback_cooldown")
config.sqlite_feedback_cooldown = text2num(value) config.sqlite_feedback_cooldown = text2num(value)
if("defib_timer")
config.defib_timer = text2num(value)
if("defib_braindamage_timer")
config.defib_braindamage_timer = text2num(value)
if("disable_cid_warn_popup")
config.disable_cid_warn_popup = TRUE
else else
log_misc("Unknown setting in configuration: '[name]'") log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -2,7 +2,7 @@
// Controls the emergency shuttle // Controls the emergency shuttle
var/global/datum/emergency_shuttle_controller/emergency_shuttle var/global/datum/emergency_shuttle_controller/emergency_shuttle = new
/datum/emergency_shuttle_controller /datum/emergency_shuttle_controller
var/datum/shuttle/autodock/ferry/emergency/shuttle // Set in shuttle_emergency.dm TODO - is it really? var/datum/shuttle/autodock/ferry/emergency/shuttle // Set in shuttle_emergency.dm TODO - is it really?
@@ -75,8 +75,10 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
/datum/emergency_shuttle_controller/proc/set_launch_countdown(var/seconds) /datum/emergency_shuttle_controller/proc/set_launch_countdown(var/seconds)
wait_for_launch = 1 wait_for_launch = 1
launch_time = world.time + seconds*10 launch_time = world.time + seconds*10
START_PROCESSING(SSprocessing, src)
/datum/emergency_shuttle_controller/proc/stop_launch_countdown() /datum/emergency_shuttle_controller/proc/stop_launch_countdown()
STOP_PROCESSING(SSprocessing, src)
wait_for_launch = 0 wait_for_launch = 0
//calls the shuttle for an emergency evacuation //calls the shuttle for an emergency evacuation
@@ -120,7 +122,7 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
/datum/emergency_shuttle_controller/proc/recall() /datum/emergency_shuttle_controller/proc/recall()
if (!can_recall()) return if (!can_recall()) return
wait_for_launch = 0 stop_launch_countdown()
shuttle.cancel_launch(src) shuttle.cancel_launch(src)
if (evac) if (evac)

View File

@@ -196,7 +196,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
#else #else
world.sleep_offline = 1 world.sleep_offline = 1
#endif #endif
world.fps = config.fps world.change_fps(config.fps)
var/initialized_tod = REALTIMEOFDAY var/initialized_tod = REALTIMEOFDAY
sleep(1) sleep(1)
initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10

View File

@@ -38,7 +38,7 @@ SUBSYSTEM_DEF(air)
current_cycle = 0 current_cycle = 0
var/simulated_turf_count = 0 var/simulated_turf_count = 0
for(var/turf/simulated/S in turfs) for(var/turf/simulated/S in world)
simulated_turf_count++ simulated_turf_count++
S.update_air_properties() S.update_air_properties()
CHECK_TICK CHECK_TICK

View File

@@ -0,0 +1,45 @@
// We manually initialize the alarm handlers instead of looping over all existing types
// to make it possible to write: camera_alarm.triggerAlarm() rather than SSalarm.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()
SUBSYSTEM_DEF(alarm)
name = "Alarm"
wait = 2 SECONDS
priority = FIRE_PRIORITY_ALARM
init_order = INIT_ORDER_ALARM
var/list/datum/alarm/all_handlers
var/tmp/list/currentrun = null
var/static/list/active_alarm_cache = list()
/datum/controller/subsystem/alarm/Initialize()
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
. = ..()
/datum/controller/subsystem/alarm/fire(resumed = FALSE)
if(!resumed)
src.currentrun = all_handlers.Copy()
active_alarm_cache.Cut()
var/list/currentrun = src.currentrun // Cache for sanic speed
while (currentrun.len)
var/datum/alarm_handler/AH = currentrun[currentrun.len]
currentrun.len--
AH.process()
active_alarm_cache += AH.alarms
if (MC_TICK_CHECK)
return
/datum/controller/subsystem/alarm/proc/active_alarms()
return active_alarm_cache.Copy()
/datum/controller/subsystem/alarm/proc/number_of_active_alarms()
return active_alarm_cache.len
/datum/controller/subsystem/alarm/stat_entry()
..("[number_of_active_alarms()] alarm\s")

View File

@@ -0,0 +1,17 @@
SUBSYSTEM_DEF(assets)
name = "Assets"
init_order = INIT_ORDER_ASSETS
flags = SS_NO_FIRE
var/list/cache = list()
var/list/preload = list()
/datum/controller/subsystem/assets/Initialize(timeofday)
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
preload = cache.Copy() //don't preload assets generated during the round
for(var/client/C in GLOB.clients)
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
return ..()

View File

@@ -8,9 +8,9 @@ SUBSYSTEM_DEF(atoms)
init_order = INIT_ORDER_ATOMS init_order = INIT_ORDER_ATOMS
flags = SS_NO_FIRE flags = SS_NO_FIRE
var/initialized = INITIALIZATION_INSSATOMS var/static/initialized = INITIALIZATION_INSSATOMS
// var/list/created_atoms // This is never used, so don't bother. ~Leshana // var/list/created_atoms // This is never used, so don't bother. ~Leshana
var/old_initialized var/static/old_initialized
var/list/late_loaders var/list/late_loaders
var/list/created_atoms var/list/created_atoms

View File

@@ -0,0 +1,87 @@
SUBSYSTEM_DEF(chat)
name = "Chat"
flags = SS_TICKER
wait = 1 // SS_TICKER means this runs every tick
priority = FIRE_PRIORITY_CHAT
init_order = INIT_ORDER_CHAT
var/list/msg_queue = list()
/datum/controller/subsystem/chat/Initialize(timeofday)
init_vchat()
..()
/datum/controller/subsystem/chat/fire()
var/list/msg_queue = src.msg_queue // Local variable for sanic speed.
for(var/i in msg_queue)
var/client/C = i
var/list/messages = msg_queue[C]
msg_queue -= C
if (C)
C << output(jsEncode(messages), "htmloutput:putmessage")
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/chat/stat_entry()
..("C:[msg_queue.len]")
/datum/controller/subsystem/chat/proc/queue(target, time, message, handle_whitespace = TRUE)
if(!target || !message)
return
if(!istext(message))
stack_trace("to_chat called with invalid input type")
return
// Currently to_chat(world, ...) gets sent individually to each client. Consider.
if(target == world)
target = GLOB.clients
//Some macros remain in the string even after parsing and fuck up the eventual output
var/original_message = message
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(isnull(time))
time = world.time
var/list/messageStruct = list("time" = time, "message" = message);
if(islist(target))
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C)
return
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
//Send it to the old style output window.
DIRECT_OUTPUT(C, original_message)
continue
// // Client still loading, put their messages in a queue - Actually don't, logged already in database.
// if(!C.chatOutput.loaded && C.chatOutput.message_queue && islist(C.chatOutput.message_queue))
// C.chatOutput.message_queue[++C.chatOutput.message_queue.len] = messageStruct
// continue
LAZYINITLIST(msg_queue[C])
msg_queue[C][++msg_queue[C].len] = messageStruct
else
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
if(!C)
return
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
DIRECT_OUTPUT(C, original_message)
return
// // Client still loading, put their messages in a queue - Actually don't, logged already in database.
// if(!C.chatOutput.loaded && C.chatOutput.message_queue && islist(C.chatOutput.message_queue))
// C.chatOutput.message_queue[++C.chatOutput.message_queue.len] = messageStruct
// return
LAZYINITLIST(msg_queue[C])
msg_queue[C][++msg_queue[C].len] = messageStruct

View File

@@ -1,6 +1,8 @@
SUBSYSTEM_DEF(events) SUBSYSTEM_DEF(events)
name = "Events" name = "Events (Legacy)"
wait = 20 wait = 2 SECONDS
var/tmp/list/currentrun = null
var/list/datum/event/active_events = list() var/list/datum/event/active_events = list()
var/list/datum/event/finished_events = list() var/list/datum/event/finished_events = list()
@@ -11,23 +13,37 @@ SUBSYSTEM_DEF(events)
var/datum/event_meta/new_event = new var/datum/event_meta/new_event = new
/datum/controller/subsystem/events/Initialize() /datum/controller/subsystem/events/Initialize()
allEvents = typesof(/datum/event) - /datum/event
event_containers = list( event_containers = list(
EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane, EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane,
EVENT_LEVEL_MODERATE = new/datum/event_container/moderate, EVENT_LEVEL_MODERATE = new/datum/event_container/moderate,
EVENT_LEVEL_MAJOR = new/datum/event_container/major EVENT_LEVEL_MAJOR = new/datum/event_container/major
) )
allEvents = typesof(/datum/event) - /datum/event if(global.using_map.use_overmap)
GLOB.overmap_event_handler.create_events(global.using_map.overmap_z, global.using_map.overmap_size, global.using_map.overmap_event_areas)
return ..() return ..()
/datum/controller/subsystem/events/fire(resumed) /datum/controller/subsystem/events/fire(resumed)
for(var/datum/event/E in active_events) if (!resumed)
src.currentrun = active_events.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while (currentrun.len)
var/datum/event/E = currentrun[currentrun.len]
currentrun.len--
if(E.processing_active) if(E.processing_active)
E.process() E.process()
if (MC_TICK_CHECK)
return
for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR) for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/list/datum/event_container/EC = event_containers[i] var/list/datum/event_container/EC = event_containers[i]
EC.process() EC.process()
/datum/controller/subsystem/events/stat_entry()
..("E:[active_events.len]")
/datum/controller/subsystem/events/Recover() /datum/controller/subsystem/events/Recover()
if(SSevents.active_events) if(SSevents.active_events)
active_events |= SSevents.active_events active_events |= SSevents.active_events
@@ -35,6 +51,8 @@ SUBSYSTEM_DEF(events)
finished_events |= SSevents.finished_events finished_events |= SSevents.finished_events
/datum/controller/subsystem/events/proc/event_complete(var/datum/event/E) /datum/controller/subsystem/events/proc/event_complete(var/datum/event/E)
active_events -= E
if(!E.event_meta || !E.severity) // datum/event is used here and there for random reasons, maintaining "backwards compatibility" if(!E.event_meta || !E.severity) // datum/event is used here and there for random reasons, maintaining "backwards compatibility"
log_debug("Event of '[E.type]' with missing meta-data has completed.") log_debug("Event of '[E.type]' with missing meta-data has completed.")
return return
@@ -50,7 +68,7 @@ SUBSYSTEM_DEF(events)
log_debug("Event '[EM.name]' has completed at [stationtime2text()].") log_debug("Event '[EM.name]' has completed at [stationtime2text()].")
/datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay) /datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay)
var/list/datum/event_container/EC = event_containers[severity] var/datum/event_container/EC = event_containers[severity]
EC.next_event_time += delay EC.next_event_time += delay
/datum/controller/subsystem/events/proc/RoundEnd() /datum/controller/subsystem/events/proc/RoundEnd()

View File

@@ -0,0 +1,37 @@
// This is a simple ticker for the new event system.
// The logic that determines what events get chosen is held inside a seperate subsystem.
SUBSYSTEM_DEF(event_ticker)
name = "Events (Ticker)"
wait = 2 SECONDS
runlevels = RUNLEVEL_GAME
// List of `/datum/event2/event`s that are currently active, and receiving process() ticks.
var/list/active_events = list()
// List of `/datum/event2/event`s that finished, and are here for showing at roundend, if that's desired.
var/list/finished_events = list()
// Process active events.
/datum/controller/subsystem/event_ticker/fire(resumed)
for(var/E in active_events)
var/datum/event2/event/event = E
event.process()
if(event.finished)
event_finished(event)
// Starts an event, independent of the GM system.
// This means it will always run, and won't affect the GM system in any way, e.g. not putting the event off limits after one use.
/datum/controller/subsystem/event_ticker/proc/start_event(event_type)
var/datum/event2/event/E = new event_type(src)
E.execute()
event_started(E)
/datum/controller/subsystem/event_ticker/proc/event_started(datum/event2/event/E)
log_debug("Event [E.type] is now being ran.")
active_events += E
/datum/controller/subsystem/event_ticker/proc/event_finished(datum/event2/event/E)
log_debug("Event [E.type] has finished.")
active_events -= E
finished_events += E

View File

@@ -0,0 +1,373 @@
// This is a sort of successor to the various event systems created over the years. It is designed to be just a tad smarter than the
// previous ones, checking various things like player count, department size and composition, individual player activity,
// individual player (IC) skill, and such, in order to try to choose the best events to take in order to add spice or variety to
// the round.
// This subsystem holds the logic that chooses events. Actual event processing is handled in a seperate subsystem.
SUBSYSTEM_DEF(game_master)
name = "Events (Game Master)"
wait = 1 MINUTE
runlevels = RUNLEVEL_GAME
// The GM object is what actually chooses events.
// It's held in a seperate object for better encapsulation, and allows for different 'flavors' of GMs to be made, that choose events differently.
var/datum/game_master/GM = null
var/game_master_type = /datum/game_master/default
var/list/available_events = list() // A list of meta event objects.
var/danger = 0 // The GM's best guess at how chaotic the round is. High danger makes it hold back.
var/staleness = -20 // Determines liklihood of the GM doing something, increases over time.
var/next_event = 0 // Minimum amount of time of nothingness until the GM can pick something again.
var/debug_messages = FALSE // If true, debug information is written to `log_debug()`.
/datum/controller/subsystem/game_master/Initialize()
var/list/subtypes = subtypesof(/datum/event2/meta)
for(var/T in subtypes)
var/datum/event2/meta/M = new T(src)
if(!M.name)
continue
available_events += M
GM = new game_master_type(src)
if(config && !config.enable_game_master)
can_fire = FALSE
return ..()
/datum/controller/subsystem/game_master/fire(resumed)
adjust_staleness(1)
adjust_danger(-1)
var/global_afk = metric.assess_all_living_mobs()
global_afk = abs(global_afk - 100)
global_afk = round(global_afk / 100, 0.1)
adjust_staleness(global_afk) // Staleness increases faster if more people are less active.
if(GM.ignore_time_restrictions || next_event < world.time)
if(prob(staleness) && pre_event_checks())
do_event_decision()
/datum/controller/subsystem/game_master/proc/do_event_decision()
log_game_master("Going to choose an event.")
var/datum/event2/meta/event_picked = GM.choose_event()
if(event_picked)
run_event(event_picked)
next_event = world.time + rand(GM.decision_cooldown_lower_bound, GM.decision_cooldown_upper_bound)
/datum/controller/subsystem/game_master/proc/debug_gm()
can_fire = TRUE
staleness = 100
debug_messages = TRUE
/datum/controller/subsystem/game_master/proc/run_event(datum/event2/meta/chosen_event)
var/datum/event2/event/E = chosen_event.make_event()
chosen_event.times_ran++
if(!chosen_event.reusable)
// Disable this event, so it only gets picked once.
chosen_event.enabled = FALSE
if(chosen_event.event_class)
// Disable similar events, too.
for(var/M in available_events)
var/datum/event2/meta/meta = M
if(meta.event_class == chosen_event.event_class)
meta.enabled = FALSE
SSevent_ticker.event_started(E)
adjust_danger(chosen_event.chaos)
adjust_staleness(-(10 + chosen_event.chaos)) // More chaotic events reduce staleness more, e.g. a 25 chaos event will reduce it by 35.
// Tell the game master that something dangerous happened, e.g. someone dying, station explosions.
/datum/controller/subsystem/game_master/proc/adjust_danger(amount)
amount *= GM.danger_modifier
danger = round(between(0, danger + amount, 1000), 0.1)
// Tell the game master that things are getting boring if positive, or something interesting if negative..
/datum/controller/subsystem/game_master/proc/adjust_staleness(amount)
amount *= GM.staleness_modifier
staleness = round( between(-20, staleness + amount, 100), 0.1)
// These are ran before committing to an event.
// Returns TRUE if the system is allowed to procede, otherwise returns FALSE.
/datum/controller/subsystem/game_master/proc/pre_event_checks(quiet = FALSE)
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
if(!quiet)
log_game_master("Unable to start event: Ticker is nonexistant, or the game is not ongoing.")
return FALSE
if(GM.ignore_time_restrictions)
return TRUE
if(next_event > world.time) // Sanity.
if(!quiet)
log_game_master("Unable to start event: Time until next event is approximately [round((next_event - world.time) / (1 MINUTE))] minute(s)")
return FALSE
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
var/mills = round_duration_in_ticks
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
// if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
// if(!quiet)
// log_debug("Game Master unable to start event: It is too early.")
// return FALSE
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
if(!quiet)
log_game_master("Unable to start event: It is too late.")
return FALSE
return TRUE
/datum/controller/subsystem/game_master/proc/choose_game_master(mob/user)
var/list/subtypes = subtypesof(/datum/game_master)
var/new_gm_path = input(user, "What kind of Game Master do you want?", "New Game Master", /datum/game_master/default) as null|anything in subtypes
if(new_gm_path)
log_and_message_admins("has swapped the current GM ([GM.type]) for a new GM ([new_gm_path]).")
GM = new new_gm_path(src)
/datum/controller/subsystem/game_master/proc/log_game_master(message)
if(debug_messages)
log_debug("GAME MASTER: [message]")
// This object makes the actual decisions.
/datum/game_master
var/datum/controller/subsystem/game_master/ticker = null
// Multiplier for how much 'danger' is accumulated. Higer generally makes it possible for more dangerous events to be picked.
var/danger_modifier = 1.0
// Ditto. Higher numbers generally result in more events occuring in a round.
var/staleness_modifier = 1.0
var/decision_cooldown_lower_bound = 5 MINUTES // Lower bound for how long to wait until -the potential- for another event being decided.
var/decision_cooldown_upper_bound = 20 MINUTES // Same, but upper bound.
var/ignore_time_restrictions = FALSE // Useful for debugging without needing to wait 20 minutes each time.
var/ignore_round_chaos = FALSE // If true, the system will happily choose back to back intense events like meteors and blobs, Dwarf Fortress style.
/datum/game_master/New(datum/controller/subsystem/game_master/new_ticker)
ticker = new_ticker
/client/proc/show_gm_status()
set category = "Debug"
set name = "Show GM Status"
set desc = "Shows you what the GM is thinking. If only that existed in real life..."
if(check_rights(R_ADMIN|R_EVENT|R_DEBUG))
SSgame_master.interact(usr)
else
to_chat(usr, span("warning", "You do not have sufficent rights to view the GM panel, sorry."))
/datum/controller/subsystem/game_master/proc/interact(var/client/user)
if(!user)
return
// Using lists for string tree conservation.
var/list/dat = list("<html><head><title>Automated Game Master Event System</title></head><body>")
// Makes the system turn on or off.
dat += href(src, list("toggle" = 1), "\[Toggle GM\]")
dat += " | "
// Makes the system not care about staleness or being near round-end.
dat += href(src, list("toggle_time_restrictions" = 1), "\[Toggle Time Restrictions\]")
dat += " | "
// Makes the system not care about how chaotic the round might be.
dat += href(src, list("toggle_chaos_throttle" = 1), "\[Toggle Chaos Throttling\]")
dat += " | "
// Makes the system immediately choose an event, while still bound to factors like danger, weights, and department staffing.
dat += href(src, list("force_choose_event" = 1), "\[Force Event Decision\]")
dat += "<br>"
// Swaps out the current GM for a new one with different ideas on what a good event might be.
dat += href(src, list("change_gm" = 1), "\[Change GM\]")
dat += "<br>"
dat += "Current GM Type: [GM.type]<br>"
dat += "State: [can_fire ? "Active": "Inactive"]<br>"
dat += "Status: [pre_event_checks(TRUE) ? "Ready" : "Suppressed"]<br><br>"
dat += "Staleness: [staleness] "
dat += href(src, list("set_staleness" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Staleness is an estimate of how boring the round might be, and if an event should be done. It is increased passively over time, \
and increases faster if people are AFK. It deceases when events and certain 'interesting' things happen in the round.</i><br>"
dat += "Danger: [danger] "
dat += href(src, list("set_danger" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Danger is an estimate of how chaotic the round has been so far. It is decreased passively over time, and is increased by having \
certain chaotic events be selected, or chaotic things happen in the round. A sufficently high amount of danger will make the system \
avoid using destructive events, to avoid pushing the station over the edge.</i><br>"
dat += "<h2>Player Activity:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Category</th>"
dat += "<th>Activity Percentage</th>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Living Mobs</td>"
dat += "<td>[metric.assess_all_living_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Ghosts</td>"
dat += "<td>[metric.assess_all_dead_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Departments</td>"
dat += "</tr>"
for(var/D in metric.departments)
dat += "<tr>"
dat += "<td>[D]</td>"
dat += "<td>[metric.assess_department(D)]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Players</td>"
dat += "</tr>"
for(var/P in player_list)
var/mob/M = P
dat += "<tr>"
dat += "<td>[M] ([M.ckey])</td>"
dat += "<td>[metric.assess_player_activity(M)]%</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events available:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Name</th>"
dat += "<th>Involved Departments</th>"
dat += "<th>Chaos</th>"
dat += "<th>Chaotic Threshold</th>"
dat += "<th>Weight</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in available_events)
var/datum/event2/meta/event = E
dat += "<tr>"
if(!event.enabled)
dat += "<td><strike>[event.name]</strike></td>"
else
dat += "<td>[event.name]</td>"
dat += "<td>[english_list(event.departments)]</td>"
dat += "<td>[event.chaos]</td>"
dat += "<td>[event.chaotic_threshold]</td>"
dat += "<td>[event.get_weight()]</td>"
dat += "<td>[href(event, list("force" = 1), "\[Force\]")] [href(event, list("toggle" = 1), "\[Toggle\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events active:</h2>"
dat += "Current time: [world.time]"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Time Started</th>"
dat += "<th>Time to Announce</th>"
dat += "<th>Time to End</th>"
dat += "<th>Announced</th>"
dat += "<th>Started</th>"
dat += "<th>Ended</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.active_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_to_announce ? event.time_to_announce : "NULL"]</td>"
dat += "<td>[event.time_to_end ? event.time_to_end : "NULL"]</td>"
dat += "<td>[event.announced ? "Yes" : "No"]</td>"
dat += "<td>[event.started ? "Yes" : "No"]</td>"
dat += "<td>[event.ended ? "Yes" : "No"]</td>"
dat += "<td>[href(event, list("abort" = 1), "\[Abort\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "</body></html>"
dat += "<h2>Events completed:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Start Time</th>"
dat += "<th>Finish Time</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.finished_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_finished]</td>"
dat += "</tr>"
dat += "</body></html>"
var/datum/browser/popup = new(user, "game_master_debug", "Automated Game Master Event System", 800, 500, src)
popup.set_content(dat.Join())
popup.open()
/datum/controller/subsystem/game_master/Topic(href, href_list)
if(..())
return
if(href_list["close"]) // Needed or the window re-opens after closing, making it last forever.
return
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
message_admins("[usr] has attempted to modify the Game Master values without sufficent privilages.")
return
if(href_list["toggle"])
can_fire = !can_fire
message_admins("GM was [!can_fire ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_time_restrictions"])
GM.ignore_time_restrictions = !GM.ignore_time_restrictions
message_admins("GM event time restrictions was [GM.ignore_time_restrictions ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_chaos_throttle"])
GM.ignore_round_chaos = !GM.ignore_round_chaos
message_admins("GM event chaos restrictions was [GM.ignore_round_chaos ? "dis" : "en"]abled by [usr.key].")
if(href_list["force_choose_event"])
do_event_decision()
message_admins("[usr.key] forced the Game Master to choose an event immediately.")
if(href_list["change_gm"])
choose_game_master(usr)
if(href_list["set_staleness"])
var/amount = input(usr, "How much staleness should there be?", "Game Master") as null|num
if(!isnull(amount))
staleness = amount
message_admins("GM staleness was set to [amount] by [usr.key].")
if(href_list["set_danger"])
var/amount = input(usr, "How much danger should there be?", "Game Master") as null|num
if(!isnull(amount))
danger = amount
message_admins("GM danger was set to [amount] by [usr.key].")
interact(usr) // To refresh the UI.

View File

@@ -15,8 +15,7 @@ SUBSYSTEM_DEF(inactivity)
while(client_list.len) while(client_list.len)
var/client/C = client_list[client_list.len] var/client/C = client_list[client_list.len]
client_list.len-- client_list.len--
if(!C.holder && C.is_afk(config.kick_inactive MINUTES) && !isobserver(C.mob)) if(C.is_afk(config.kick_inactive MINUTES) && can_kick(C))
to_chat(C, "<span class='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</span>") to_chat(C, "<span class='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</span>")
var/information var/information
@@ -34,6 +33,9 @@ SUBSYSTEM_DEF(inactivity)
if(job) if(job)
information = " while [job]." information = " while [job]."
else if(isobserver(C.mob))
information = " while a ghost."
else if(issilicon(C.mob)) else if(issilicon(C.mob))
information = " while a silicon." information = " while a silicon."
if(isAI(C.mob)) if(isAI(C.mob))
@@ -55,4 +57,7 @@ SUBSYSTEM_DEF(inactivity)
return return
/datum/controller/subsystem/inactivity/stat_entry() /datum/controller/subsystem/inactivity/stat_entry()
..("Kicked: [number_kicked]") ..("Kicked: [number_kicked]")
/datum/controller/subsystem/inactivity/proc/can_kick(var/client/C)
return TRUE

View File

@@ -16,8 +16,7 @@ SUBSYSTEM_DEF(mapping)
if(config.generate_map) if(config.generate_map)
// Map-gen is still very specific to the map, however putting it here should ensure it loads in the correct order. // Map-gen is still very specific to the map, however putting it here should ensure it loads in the correct order.
if(using_map.perform_map_generation()) using_map.perform_map_generation()
using_map.refresh_mining_turfs()
/datum/controller/subsystem/mapping/proc/load_map_templates() /datum/controller/subsystem/mapping/proc/load_map_templates()

View File

@@ -0,0 +1,55 @@
//
// Mobs Subsystem - Process mob.Life()
//
SUBSYSTEM_DEF(mobs)
name = "Mobs"
priority = 100
wait = 2 SECONDS
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/currentrun = list()
var/log_extensively = FALSE
var/list/timelog = list()
var/list/busy_z_levels = list()
var/slept_mobs = 0
/datum/controller/subsystem/mobs/stat_entry()
..("P: [global.mob_list.len] | S: [slept_mobs]")
/datum/controller/subsystem/mobs/fire(resumed = 0)
var/list/busy_z_levels = src.busy_z_levels
if (!resumed)
slept_mobs = 0
src.currentrun = mob_list.Copy()
busy_z_levels.Cut()
for(var/played_mob in player_list)
if(!played_mob || isobserver(played_mob))
continue
var/mob/pm = played_mob
busy_z_levels |= pm.z
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
var/times_fired = src.times_fired
while(currentrun.len)
var/mob/M = currentrun[currentrun.len]
currentrun.len--
if(QDELETED(M))
mob_list -= M
else
// Right now mob.Life() is unstable enough I think we need to use a try catch.
// Obviously we should try and get rid of this for performance reasons when we can.
try
if(M.low_priority && !(M.z in busy_z_levels))
slept_mobs++
continue
M.Life(times_fired)
catch(var/exception/e)
log_runtime(e, M, "Caught by [name] subsystem")
if (MC_TICK_CHECK)
return

View File

@@ -1,41 +1,17 @@
SUBSYSTEM_DEF(nanoui) SUBSYSTEM_DEF(nanoui)
name = "NanoUI" name = "NanoUI"
wait = 5 wait = 5
flags = SS_NO_INIT
// a list of current open /nanoui UIs, grouped by src_object and ui_key // a list of current open /nanoui UIs, grouped by src_object and ui_key
var/list/open_uis = list() var/list/open_uis = list()
// a list of current open /nanoui UIs, not grouped, for use in processing // a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list() var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/datum/controller/subsystem/nanoui/Initialize()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/images/status_icons/",\
"nano/images/modular_computers/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
.=..()
for(var/i in GLOB.clients)
send_resources(i)
/datum/controller/subsystem/nanoui/Recover() /datum/controller/subsystem/nanoui/Recover()
if(SSnanoui.open_uis) if(SSnanoui.open_uis)
open_uis |= SSnanoui.open_uis open_uis |= SSnanoui.open_uis
if(SSnanoui.processing_uis) if(SSnanoui.processing_uis)
processing_uis |= SSnanoui.processing_uis processing_uis |= SSnanoui.processing_uis
if(SSnanoui.asset_files)
asset_files |= SSnanoui.asset_files
/datum/controller/subsystem/nanoui/stat_entry() /datum/controller/subsystem/nanoui/stat_entry()
return ..("[processing_uis.len] UIs") return ..("[processing_uis.len] UIs")
@@ -44,10 +20,3 @@ SUBSYSTEM_DEF(nanoui)
for(var/thing in processing_uis) for(var/thing in processing_uis)
var/datum/nanoui/UI = thing var/datum/nanoui/UI = thing
UI.process() UI.process()
//Sends asset files to a client, called on client/New()
/datum/controller/subsystem/nanoui/proc/send_resources(client)
if(!subsystem_initialized)
return
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client

View File

@@ -8,6 +8,14 @@ PROCESSING_SUBSYSTEM_DEF(chemistry)
var/list/chemical_reagents = list() var/list/chemical_reagents = list()
/datum/controller/subsystem/processing/chemistry/Recover() /datum/controller/subsystem/processing/chemistry/Recover()
log_debug("[name] subsystem Recover().")
if(SSchemistry.current_thing)
log_debug("current_thing was: (\ref[SSchemistry.current_thing])[SSchemistry.current_thing]([SSchemistry.current_thing.type]) - currentrun: [SSchemistry.currentrun.len] vs total: [SSchemistry.processing.len]")
var/list/old_processing = SSchemistry.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
chemical_reactions = SSchemistry.chemical_reactions chemical_reactions = SSchemistry.chemical_reactions
chemical_reagents = SSchemistry.chemical_reagents chemical_reagents = SSchemistry.chemical_reagents

View File

@@ -4,3 +4,12 @@ PROCESSING_SUBSYSTEM_DEF(fastprocess)
name = "Fast Processing" name = "Fast Processing"
wait = 2 wait = 2
stat_tag = "FP" stat_tag = "FP"
/datum/controller/subsystem/processing/fastprocess/Recover()
log_debug("[name] subsystem Recover().")
if(SSfastprocess.current_thing)
log_debug("current_thing was: (\ref[SSfastprocess.current_thing])[SSfastprocess.current_thing]([SSfastprocess.current_thing.type]) - currentrun: [SSfastprocess.currentrun.len] vs total: [SSfastprocess.processing.len]")
var/list/old_processing = SSfastprocess.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D

View File

@@ -3,3 +3,14 @@ PROCESSING_SUBSYSTEM_DEF(obj)
priority = FIRE_PRIORITY_OBJ priority = FIRE_PRIORITY_OBJ
flags = SS_NO_INIT flags = SS_NO_INIT
wait = 20 wait = 20
/datum/controller/subsystem/processing/obj/Recover()
log_debug("[name] subsystem Recover().")
if(SSobj.current_thing)
log_debug("current_thing was: (\ref[SSobj.current_thing])[SSobj.current_thing]([SSobj.current_thing.type]) - currentrun: [SSobj.currentrun.len] vs total: [SSobj.processing.len]")
var/list/old_processing = SSobj.processing.Copy()
for(var/datum/D in old_processing)
if(!isobj(D))
log_debug("[name] subsystem Recover() found inappropriate item in list: [D.type]")
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D

View File

@@ -13,6 +13,16 @@ SUBSYSTEM_DEF(processing)
var/debug_last_thing var/debug_last_thing
var/debug_original_process_proc // initial() does not work with procs var/debug_original_process_proc // initial() does not work with procs
var/datum/current_thing
/datum/controller/subsystem/processing/Recover()
log_debug("[name] subsystem Recover().")
if(SSprocessing.current_thing)
log_debug("current_thing was: (\ref[SSprocessing.current_thing])[SSprocessing.current_thing]([SSprocessing.current_thing.type]) - currentrun: [SSprocessing.currentrun.len] vs total: [SSprocessing.processing.len]")
var/list/old_processing = SSprocessing.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
/datum/controller/subsystem/processing/stat_entry() /datum/controller/subsystem/processing/stat_entry()
..("[stat_tag]:[processing.len]") ..("[stat_tag]:[processing.len]")
@@ -24,16 +34,19 @@ SUBSYSTEM_DEF(processing)
var/list/current_run = currentrun var/list/current_run = currentrun
while(current_run.len) while(current_run.len)
var/datum/thing = current_run[current_run.len] current_thing = current_run[current_run.len]
current_run.len-- current_run.len--
if(QDELETED(thing)) if(QDELETED(current_thing))
processing -= thing processing -= current_thing
else if(thing.process(wait) == PROCESS_KILL) else if(current_thing.process(wait) == PROCESS_KILL)
// fully stop so that a future START_PROCESSING will work // fully stop so that a future START_PROCESSING will work
STOP_PROCESSING(src, thing) STOP_PROCESSING(src, current_thing)
if (MC_TICK_CHECK) if (MC_TICK_CHECK)
current_thing = null
return return
current_thing = null
/datum/controller/subsystem/processing/proc/toggle_debug() /datum/controller/subsystem/processing/proc/toggle_debug()
if(!check_rights(R_DEBUG)) if(!check_rights(R_DEBUG))
return return

View File

@@ -8,6 +8,15 @@ PROCESSING_SUBSYSTEM_DEF(projectiles)
var/global_pixel_speed = 2 var/global_pixel_speed = 2
var/global_iterations_per_move = 16 var/global_iterations_per_move = 16
/datum/controller/subsystem/processing/projectiles/Recover()
log_debug("[name] subsystem Recover().")
if(SSprojectiles.current_thing)
log_debug("current_thing was: (\ref[SSprojectiles.current_thing])[SSprojectiles.current_thing]([SSprojectiles.current_thing.type]) - currentrun: [SSprojectiles.currentrun.len] vs total: [SSprojectiles.processing.len]")
var/list/old_processing = SSprojectiles.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
/datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed) /datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed)
global_pixel_speed = new_speed global_pixel_speed = new_speed
for(var/i in processing) for(var/i in processing)

View File

@@ -1,3 +1,14 @@
PROCESSING_SUBSYSTEM_DEF(turfs) PROCESSING_SUBSYSTEM_DEF(turfs)
name = "Turf Processing" name = "Turf Processing"
wait = 20 wait = 20
/datum/controller/subsystem/processing/turfs/Recover()
log_debug("[name] subsystem Recover().")
if(SSturfs.current_thing)
log_debug("current_thing was: (\ref[SSturfs.current_thing])[SSturfs.current_thing]([SSturfs.current_thing.type]) - currentrun: [SSturfs.currentrun.len] vs total: [SSturfs.processing.len]")
var/list/old_processing = SSturfs.processing.Copy()
for(var/datum/D in old_processing)
if(!isturf(D))
log_debug("[name] subsystem Recover() found inappropriate item in list: [D.type]")
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D

View File

@@ -15,7 +15,6 @@ SUBSYSTEM_DEF(shuttles)
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
// TODO OVERMAP - These two are unused for now
var/overmap_halted = FALSE // Whether ships can move on the overmap; used for adminbus. var/overmap_halted = FALSE // Whether ships can move on the overmap; used for adminbus.
var/list/ships = list() // List of all ships. var/list/ships = list() // List of all ships.
@@ -99,14 +98,13 @@ SUBSYSTEM_DEF(shuttles)
registered_shuttle_landmarks[shuttle_landmark_tag] = shuttle_landmark registered_shuttle_landmarks[shuttle_landmark_tag] = shuttle_landmark
last_landmark_registration_time = world.time last_landmark_registration_time = world.time
// TODO - Uncomment once overmap sectors are ported var/obj/effect/overmap/visitable/O = landmarks_still_needed[shuttle_landmark_tag]
//var/obj/effect/overmap/visitable/O = landmarks_still_needed[shuttle_landmark_tag] if(O) //These need to be added to sectors, which we handle.
//if(O) //These need to be added to sectors, which we handle. try_add_landmark_tag(shuttle_landmark_tag, O)
// try_add_landmark_tag(shuttle_landmark_tag, O) landmarks_still_needed -= shuttle_landmark_tag
// landmarks_still_needed -= shuttle_landmark_tag else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically
//else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically O = map_sectors["[shuttle_landmark.z]"]
// O = map_sectors["[shuttle_landmark.z]"] O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
// O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
/datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag) /datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag)
return registered_shuttle_landmarks[shuttle_landmark_tag] return registered_shuttle_landmarks[shuttle_landmark_tag]
@@ -114,39 +112,37 @@ SUBSYSTEM_DEF(shuttles)
//Checks if the given sector's landmarks have initialized; if so, registers them with the sector, if not, marks them for assignment after they come in. //Checks if the given sector's landmarks have initialized; if so, registers them with the sector, if not, marks them for assignment after they come in.
//Also adds automatic landmarks that were waiting on their sector to spawn. //Also adds automatic landmarks that were waiting on their sector to spawn.
/datum/controller/subsystem/shuttles/proc/initialize_sector(obj/effect/overmap/visitable/given_sector) /datum/controller/subsystem/shuttles/proc/initialize_sector(obj/effect/overmap/visitable/given_sector)
return // TODO - Uncomment once overmap sectors are ported given_sector.populate_sector_objects() // This is a late init operation that sets up the sector's map_z and does non-overmap-related init tasks.
// given_sector.populate_sector_objects() // This is a late init operation that sets up the sector's map_z and does non-overmap-related init tasks.
// for(var/landmark_tag in given_sector.initial_generic_waypoints) for(var/landmark_tag in given_sector.initial_generic_waypoints)
// if(!try_add_landmark_tag(landmark_tag, given_sector)) if(!try_add_landmark_tag(landmark_tag, given_sector))
// landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is. landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is.
// for(var/shuttle_name in given_sector.initial_restricted_waypoints) for(var/shuttle_name in given_sector.initial_restricted_waypoints)
// for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name])
// if(!try_add_landmark_tag(landmark_tag, given_sector)) if(!try_add_landmark_tag(landmark_tag, given_sector))
// landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is. landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is.
// var/landmarks_to_check = landmarks_awaiting_sector.Copy() var/landmarks_to_check = landmarks_awaiting_sector.Copy()
// for(var/thing in landmarks_to_check) for(var/thing in landmarks_to_check)
// var/obj/effect/shuttle_landmark/automatic/landmark = thing var/obj/effect/shuttle_landmark/automatic/landmark = thing
// if(landmark.z in given_sector.map_z) if(landmark.z in given_sector.map_z)
// given_sector.add_landmark(landmark, landmark.shuttle_restricted) given_sector.add_landmark(landmark, landmark.shuttle_restricted)
// landmarks_awaiting_sector -= landmark landmarks_awaiting_sector -= landmark
// TODO - Uncomment once overmap sectors are ported // Attempts to add a landmark instance with a sector (returns false if landmark isn't registered yet)
//// Attempts to add a landmark instance with a sector (returns false if landmark isn't registered yet) /datum/controller/subsystem/shuttles/proc/try_add_landmark_tag(landmark_tag, obj/effect/overmap/visitable/given_sector)
///datum/controller/subsystem/shuttles/proc/try_add_landmark_tag(landmark_tag, obj/effect/overmap/visitable/given_sector) var/obj/effect/shuttle_landmark/landmark = get_landmark(landmark_tag)
// var/obj/effect/shuttle_landmark/landmark = get_landmark(landmark_tag) if(!landmark)
// if(!landmark) return
// return
// if(landmark.landmark_tag in given_sector.initial_generic_waypoints) if(landmark.landmark_tag in given_sector.initial_generic_waypoints)
// given_sector.add_landmark(landmark) given_sector.add_landmark(landmark)
// . = 1 . = 1
// for(var/shuttle_name in given_sector.initial_restricted_waypoints) for(var/shuttle_name in given_sector.initial_restricted_waypoints)
// if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name])
// given_sector.add_landmark(landmark, shuttle_name) given_sector.add_landmark(landmark, shuttle_name)
// . = 1 . = 1
/datum/controller/subsystem/shuttles/proc/initialize_shuttle(var/shuttle_type) /datum/controller/subsystem/shuttles/proc/initialize_shuttle(var/shuttle_type)
var/datum/shuttle/shuttle = shuttle_type var/datum/shuttle/shuttle = shuttle_type
@@ -170,13 +166,13 @@ SUBSYSTEM_DEF(shuttles)
error("Shuttle [S] was unable to find mothership [mothership]!") error("Shuttle [S] was unable to find mothership [mothership]!")
// Admin command to halt/resume overmap // Admin command to halt/resume overmap
// /datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting) /datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting)
// if(overmap_halted == new_setting) if(overmap_halted == new_setting)
// return return
// overmap_halted = !overmap_halted overmap_halted = !overmap_halted
// for(var/ship in ships) for(var/ship in ships)
// var/obj/effect/overmap/visitable/ship/ship_effect = ship var/obj/effect/overmap/visitable/ship/ship_effect = ship
// overmap_halted ? ship_effect.halt() : ship_effect.unhalt() overmap_halted ? ship_effect.halt() : ship_effect.unhalt()
/datum/controller/subsystem/shuttles/stat_entry() /datum/controller/subsystem/shuttles/stat_entry()
..("Shuttles:[process_shuttles.len]/[shuttles.len], Ships:[ships.len], L:[registered_shuttle_landmarks.len][overmap_halted ? ", HALT" : ""]") ..("Shuttles:[process_shuttles.len]/[shuttles.len], Ships:[ships.len], L:[registered_shuttle_landmarks.len][overmap_halted ? ", HALT" : ""]")

View File

@@ -0,0 +1,135 @@
//Exists to handle a few global variables that change enough to justify this. Technically a parallax, but it exhibits a skybox effect.
SUBSYSTEM_DEF(skybox)
name = "Space skybox"
init_order = INIT_ORDER_SKYBOX
flags = SS_NO_FIRE
var/static/list/skybox_cache = list()
var/static/list/dust_cache = list()
var/static/list/speedspace_cache = list()
var/static/list/mapedge_cache = list()
var/static/list/phase_shift_by_x = list()
var/static/list/phase_shift_by_y = list()
/datum/controller/subsystem/skybox/PreInit()
//Static
for (var/i in 0 to 25)
var/image/im = image('icons/turf/space_dust.dmi', "[i]")
im.plane = DUST_PLANE
im.alpha = 128 //80
im.blend_mode = BLEND_ADD
dust_cache["[i]"] = im
//Moving
for (var/i in 0 to 14)
// NORTH/SOUTH
var/image/im = image('icons/turf/space_dust_transit.dmi', "speedspace_ns_[i]")
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
speedspace_cache["NS_[i]"] = im
// EAST/WEST
im = image('icons/turf/space_dust_transit.dmi', "speedspace_ew_[i]")
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
speedspace_cache["EW_[i]"] = im
//Over-the-edge images
for (var/dir in alldirs)
var/image/I = image('icons/turf/space.dmi', "white")
var/matrix/M = matrix()
var/horizontal = (dir & (WEST|EAST))
var/vertical = (dir & (NORTH|SOUTH))
M.Scale(horizontal ? 8 : 1, vertical ? 8 : 1)
I.transform = M
I.appearance_flags = KEEP_APART | TILE_BOUND
I.plane = SPACE_PLANE
I.layer = 0
if(dir & NORTH)
I.pixel_y = 112
else if(dir & SOUTH)
I.pixel_y = -112
if(dir & EAST)
I.pixel_x = 112
else if(dir & WEST)
I.pixel_x = -112
mapedge_cache["[dir]"] = I
//Shuffle some lists
phase_shift_by_x = get_cross_shift_list(15)
phase_shift_by_y = get_cross_shift_list(15)
. = ..()
/datum/controller/subsystem/skybox/Initialize()
. = ..()
/datum/controller/subsystem/skybox/proc/get_skybox(z)
if(!skybox_cache["[z]"])
skybox_cache["[z]"] = generate_skybox(z)
if(global.using_map.use_overmap)
var/obj/effect/overmap/visitable/O = map_sectors["[z]"]
if(istype(O))
for(var/zlevel in O.map_z)
skybox_cache["[zlevel]"] = skybox_cache["[z]"]
return skybox_cache["[z]"]
/datum/controller/subsystem/skybox/proc/generate_skybox(z)
var/datum/skybox_settings/settings = global.using_map.get_skybox_datum(z)
var/image/res = image(settings.icon)
res.appearance_flags = KEEP_TOGETHER
var/image/base = image(settings.icon, settings.icon_state)
base.color = settings.color
if(settings.use_stars)
var/image/stars = image(settings.icon, settings.star_state)
stars.appearance_flags = RESET_COLOR
base.overlays += stars
res.overlays += base
if(global.using_map.use_overmap && settings.use_overmap_details)
var/obj/effect/overmap/visitable/O = map_sectors["[z]"]
if(istype(O))
var/image/overmap = image(settings.icon)
overmap.overlays += O.generate_skybox()
for(var/obj/effect/overmap/visitable/other in O.loc)
if(other != O)
overmap.overlays += other.get_skybox_representation()
overmap.appearance_flags = RESET_COLOR
res.overlays += overmap
// Allow events to apply custom overlays to skybox! (Awesome!)
for(var/datum/event/E in SSevents.active_events)
if(E.has_skybox_image && E.isRunning && (z in E.affecting_z))
res.overlays += E.get_skybox_image()
return res
/datum/controller/subsystem/skybox/proc/rebuild_skyboxes(var/list/zlevels)
for(var/z in zlevels)
skybox_cache["[z]"] = generate_skybox(z)
for(var/client/C)
C.update_skybox(1)
// Settings datum that maps can override to play with their skyboxes
/datum/skybox_settings
var/icon = 'icons/skybox/skybox.dmi' //Path to our background. Lets us use anything we damn well please. Skyboxes need to be 736x736
var/icon_state = "dyable"
var/color
var/random_color = FALSE
var/use_stars = TRUE
var/star_icon = 'icons/skybox/skybox.dmi'
var/star_state = "stars"
var/use_overmap_details = TRUE //Do we try to draw overmap visitables in our sector on the map?
/datum/skybox_settings/New()
..()
if(random_color)
color = rgb(rand(0,255), rand(0,255), rand(0,255))

View File

@@ -1,33 +1,15 @@
// TODO - Refactor to use the Supply Subsystem (SSsupply)
//Supply packs are in /code/datums/supplypacks //Supply packs are in /code/datums/supplypacks
//Computers are in /code/game/machinery/computer/supply.dm //Computers are in /code/game/machinery/computer/supply.dm
SUBSYSTEM_DEF(supply)
name = "Supply"
wait = 20 SECONDS
priority = FIRE_PRIORITY_SUPPLY
//Initializes at default time
flags = SS_NO_TICK_CHECK
/datum/supply_order
var/ordernum // Unfabricatable index
var/index // Fabricatable index
var/datum/supply_pack/object = null
var/cost // Cost of the supply pack (Fabricatable) (Changes not reflected when purchasing supply packs, this is cosmetic only)
var/name // Name of the supply pack datum (Fabricatable)
var/ordered_by = null // Who requested the order
var/comment = null // What reason was given for the order
var/approved_by = null // Who approved the order
var/ordered_at // Date and time the order was requested at
var/approved_at // Date and time the order was approved at
var/status // [Requested, Accepted, Denied, Shipped]
/datum/exported_crate
var/name
var/value
var/list/contents
var/datum/controller/supply/supply_controller = new()
/datum/controller/supply
//supply points //supply points
var/points = 50 var/points = 50
var/points_per_process = 1.5 var/points_per_process = 1.0 // Processes every 20 seconds, so this is 3 per minute
var/points_per_slip = 2 var/points_per_slip = 2
var/points_per_money = 0.02 // 1 point for $50 var/points_per_money = 0.02 // 1 point for $50
//control //control
@@ -46,9 +28,10 @@ var/datum/controller/supply/supply_controller = new()
"platinum" = 5 "platinum" = 5
) )
/datum/controller/supply/New() /datum/controller/subsystem/supply/Initialize()
ordernum = rand(1,9000) ordernum = rand(1,9000)
// build master supply list
for(var/typepath in subtypesof(/datum/supply_pack)) for(var/typepath in subtypesof(/datum/supply_pack))
var/datum/supply_pack/P = new typepath() var/datum/supply_pack/P = new typepath()
if(P.name) if(P.name)
@@ -56,20 +39,18 @@ var/datum/controller/supply/supply_controller = new()
else else
qdel(P) qdel(P)
/datum/controller/process/supply/setup() // TODO - Auto-build material_points_conversion from material datums
name = "supply controller" . = ..()
schedule_interval = 300 // every 30 seconds
/datum/controller/process/supply/doWork() // Supply shuttle ticker - handles supply point regeneration. Just add points over time.
supply_controller.process() /datum/controller/subsystem/supply/fire()
// Supply shuttle ticker - handles supply point regeneration
// This is called by the process scheduler every thirty seconds
/datum/controller/supply/process()
points += points_per_process points += points_per_process
/datum/controller/subsystem/supply/stat_entry()
..("Points: [points]")
//To stop things being sent to CentCom which should not be sent to centcomm. Recursively checks for these types. //To stop things being sent to CentCom which should not be sent to centcomm. Recursively checks for these types.
/datum/controller/supply/proc/forbidden_atoms_check(atom/A) /datum/controller/subsystem/supply/proc/forbidden_atoms_check(atom/A)
if(isliving(A)) if(isliving(A))
return 1 return 1
if(istype(A,/obj/item/weapon/disk/nuclear)) if(istype(A,/obj/item/weapon/disk/nuclear))
@@ -84,7 +65,7 @@ var/datum/controller/supply/supply_controller = new()
return 1 return 1
//Selling //Selling
/datum/controller/supply/proc/sell() /datum/controller/subsystem/supply/proc/sell()
// Loop over each area in the supply shuttle // Loop over each area in the supply shuttle
for(var/area/subarea in shuttle.shuttle_area) for(var/area/subarea in shuttle.shuttle_area)
callHook("sell_shuttle", list(subarea)); callHook("sell_shuttle", list(subarea));
@@ -160,7 +141,7 @@ var/datum/controller/supply/supply_controller = new()
qdel(MA) qdel(MA)
/datum/controller/supply/proc/get_clear_turfs() /datum/controller/subsystem/supply/proc/get_clear_turfs()
var/list/clear_turfs = list() var/list/clear_turfs = list()
for(var/area/subarea in shuttle.shuttle_area) for(var/area/subarea in shuttle.shuttle_area)
@@ -179,7 +160,7 @@ var/datum/controller/supply/supply_controller = new()
return clear_turfs return clear_turfs
//Buying //Buying
/datum/controller/supply/proc/buy() /datum/controller/subsystem/supply/proc/buy()
var/list/shoppinglist = list() var/list/shoppinglist = list()
for(var/datum/supply_order/SO in order_history) for(var/datum/supply_order/SO in order_history)
if(SO.status == SUP_ORDER_APPROVED) if(SO.status == SUP_ORDER_APPROVED)
@@ -258,9 +239,9 @@ var/datum/controller/supply/supply_controller = new()
return return
// Will attempt to purchase the specified order, returning TRUE on success, FALSE on failure // Will attempt to purchase the specified order, returning TRUE on success, FALSE on failure
/datum/controller/supply/proc/approve_order(var/datum/supply_order/O, var/mob/user) /datum/controller/subsystem/supply/proc/approve_order(var/datum/supply_order/O, var/mob/user)
// Not enough points to purchase the crate // Not enough points to purchase the crate
if(supply_controller.points <= O.object.cost) if(points <= O.object.cost)
return FALSE return FALSE
// Based on the current model, there shouldn't be any entries in order_history, requestlist, or shoppinglist, that aren't matched in adm_order_history // Based on the current model, there shouldn't be any entries in order_history, requestlist, or shoppinglist, that aren't matched in adm_order_history
@@ -287,11 +268,11 @@ var/datum/controller/supply/supply_controller = new()
adm_order.approved_at = stationdate2text() + " - " + stationtime2text() adm_order.approved_at = stationdate2text() + " - " + stationtime2text()
// Deduct cost // Deduct cost
supply_controller.points -= O.object.cost points -= O.object.cost
return TRUE return TRUE
// Will deny the specified order. Only useful if the order is currently requested, but available at any status // Will deny the specified order. Only useful if the order is currently requested, but available at any status
/datum/controller/supply/proc/deny_order(var/datum/supply_order/O, var/mob/user) /datum/controller/subsystem/supply/proc/deny_order(var/datum/supply_order/O, var/mob/user)
// Based on the current model, there shouldn't be any entries in order_history, requestlist, or shoppinglist, that aren't matched in adm_order_history // Based on the current model, there shouldn't be any entries in order_history, requestlist, or shoppinglist, that aren't matched in adm_order_history
var/datum/supply_order/adm_order var/datum/supply_order/adm_order
for(var/datum/supply_order/temp in adm_order_history) for(var/datum/supply_order/temp in adm_order_history)
@@ -317,22 +298,22 @@ var/datum/controller/supply/supply_controller = new()
return return
// Will deny all requested orders // Will deny all requested orders
/datum/controller/supply/proc/deny_all_pending(var/mob/user) /datum/controller/subsystem/supply/proc/deny_all_pending(var/mob/user)
for(var/datum/supply_order/O in order_history) for(var/datum/supply_order/O in order_history)
if(O.status == SUP_ORDER_REQUESTED) if(O.status == SUP_ORDER_REQUESTED)
deny_order(O, user) deny_order(O, user)
// Will delete the specified order from the user-side list // Will delete the specified order from the user-side list
/datum/controller/supply/proc/delete_order(var/datum/supply_order/O, var/mob/user) /datum/controller/subsystem/supply/proc/delete_order(var/datum/supply_order/O, var/mob/user)
// Making sure they know what they're doing // Making sure they know what they're doing
if(alert(user, "Are you sure you want to delete this record? If it has been approved, cargo points will NOT be refunded!", "Delete Record","No","Yes") == "Yes") if(alert(user, "Are you sure you want to delete this record? If it has been approved, cargo points will NOT be refunded!", "Delete Record","No","Yes") == "Yes")
if(alert(user, "Are you really sure? There is no way to recover the order once deleted.", "Delete Record", "No", "Yes") == "Yes") if(alert(user, "Are you really sure? There is no way to recover the order once deleted.", "Delete Record", "No", "Yes") == "Yes")
log_admin("[key_name(user)] has deleted supply order \ref[O] [O] from the user-side order history.") log_admin("[key_name(user)] has deleted supply order \ref[O] [O] from the user-side order history.")
supply_controller.order_history -= O order_history -= O
return return
// Will generate a new, requested order, for the given supply pack type // Will generate a new, requested order, for the given supply pack type
/datum/controller/supply/proc/create_order(var/datum/supply_pack/S, var/mob/user, var/reason) /datum/controller/subsystem/supply/proc/create_order(var/datum/supply_pack/S, var/mob/user, var/reason)
var/datum/supply_order/new_order = new() var/datum/supply_order/new_order = new()
var/datum/supply_order/adm_order = new() // Admin-recorded order must be a separate copy in memory, or user-made edits will corrupt it var/datum/supply_order/adm_order = new() // Admin-recorded order must be a separate copy in memory, or user-made edits will corrupt it
@@ -367,16 +348,16 @@ var/datum/controller/supply/supply_controller = new()
adm_order_history += adm_order adm_order_history += adm_order
// Will delete the specified export receipt from the user-side list // Will delete the specified export receipt from the user-side list
/datum/controller/supply/proc/delete_export(var/datum/exported_crate/E, var/mob/user) /datum/controller/subsystem/supply/proc/delete_export(var/datum/exported_crate/E, var/mob/user)
// Making sure they know what they're doing // Making sure they know what they're doing
if(alert(user, "Are you sure you want to delete this record?", "Delete Record","No","Yes") == "Yes") if(alert(user, "Are you sure you want to delete this record?", "Delete Record","No","Yes") == "Yes")
if(alert(user, "Are you really sure? There is no way to recover the receipt once deleted.", "Delete Record", "No", "Yes") == "Yes") if(alert(user, "Are you really sure? There is no way to recover the receipt once deleted.", "Delete Record", "No", "Yes") == "Yes")
log_admin("[key_name(user)] has deleted export receipt \ref[E] [E] from the user-side export history.") log_admin("[key_name(user)] has deleted export receipt \ref[E] [E] from the user-side export history.")
supply_controller.exported_crates -= E exported_crates -= E
return return
// Will add an item entry to the specified export receipt on the user-side list // Will add an item entry to the specified export receipt on the user-side list
/datum/controller/supply/proc/add_export_item(var/datum/exported_crate/E, var/mob/user) /datum/controller/subsystem/supply/proc/add_export_item(var/datum/exported_crate/E, var/mob/user)
var/new_name = input(user, "Name", "Please enter the name of the item.") as null|text var/new_name = input(user, "Name", "Please enter the name of the item.") as null|text
if(!new_name) if(!new_name)
return return
@@ -394,3 +375,21 @@ var/datum/controller/supply/supply_controller = new()
"quantity" = new_quantity, "quantity" = new_quantity,
"value" = new_value "value" = new_value
) )
/datum/exported_crate
var/name
var/value
var/list/contents
/datum/supply_order
var/ordernum // Unfabricatable index
var/index // Fabricatable index
var/datum/supply_pack/object = null
var/cost // Cost of the supply pack (Fabricatable) (Changes not reflected when purchasing supply packs, this is cosmetic only)
var/name // Name of the supply pack datum (Fabricatable)
var/ordered_by = null // Who requested the order
var/comment = null // What reason was given for the order
var/approved_by = null // Who approved the order
var/ordered_at // Date and time the order was requested at
var/approved_at // Date and time the order was approved at
var/status // [Requested, Accepted, Denied, Shipped]

View File

@@ -350,7 +350,8 @@ SUBSYSTEM_DEF(vote)
if("cancel") if("cancel")
if(usr.client.holder) if(usr.client.holder)
reset() if("Yes" == alert(usr, "You are about to cancel this vote. Are you sure?", "Cancel Vote", "No", "Yes"))
reset()
if("toggle_restart") if("toggle_restart")
if(usr.client.holder) if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart config.allow_vote_restart = !config.allow_vote_restart

View File

@@ -30,7 +30,7 @@ SUBSYSTEM_DEF(xenoarch)
. = ..() . = ..()
/datum/controller/subsystem/xenoarch/proc/SetupXenoarch() /datum/controller/subsystem/xenoarch/proc/SetupXenoarch()
for(var/turf/simulated/mineral/M in turfs) for(var/turf/simulated/mineral/M in world)
if(!M.density || M.z in using_map.xenoarch_exempt_levels) if(!M.density || M.z in using_map.xenoarch_exempt_levels)
continue continue

View File

@@ -94,14 +94,12 @@
options["LEGACY: air_master"] = air_master options["LEGACY: air_master"] = air_master
options["LEGACY: job_master"] = job_master options["LEGACY: job_master"] = job_master
options["LEGACY: radio_controller"] = radio_controller options["LEGACY: radio_controller"] = radio_controller
options["LEGACY: supply_controller"] = supply_controller
options["LEGACY: emergency_shuttle"] = emergency_shuttle options["LEGACY: emergency_shuttle"] = emergency_shuttle
options["LEGACY: paiController"] = paiController options["LEGACY: paiController"] = paiController
options["LEGACY: cameranet"] = cameranet options["LEGACY: cameranet"] = cameranet
options["LEGACY: transfer_controller"] = transfer_controller options["LEGACY: transfer_controller"] = transfer_controller
options["LEGACY: gas_data"] = gas_data options["LEGACY: gas_data"] = gas_data
options["LEGACY: plant_controller"] = plant_controller options["LEGACY: plant_controller"] = plant_controller
options["LEGACY: alarm_manager"] = alarm_manager
var/pick = input(mob, "Choose a controller to debug/view variables of.", "VV controller:") as null|anything in options var/pick = input(mob, "Choose a controller to debug/view variables of.", "VV controller:") as null|anything in options
if(!pick) if(!pick)

View File

@@ -0,0 +1,6 @@
// Push button, receive event.
// Returns a selected event datum.
/datum/game_master/proc/choose_event()
/datum/game_master/proc/log_game_master(message)
SSgame_master.log_game_master(message)

View File

@@ -0,0 +1,89 @@
// The default game master tries to choose events with these goals in mind.
// * Don't choose an event if the crew can't take it. E.g. no meteors after half of the crew died.
// * Try to involve lots of people, particuarly in active departments.
// * Avoid giving events to the same department multiple times in a row.
/datum/game_master/default
// If an event was done for a specific department, it is written here, so it doesn't do it again.
var/last_department_used = null
/datum/game_master/default/choose_event()
log_game_master("Now starting event decision.")
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
var/list/best_events = decide_best_events(most_active_departments)
if(LAZYLEN(best_events))
log_game_master("Got [best_events.len] choice\s for the next event.")
var/list/weighted_events = list()
for(var/E in best_events)
var/datum/event2/meta/event = E
var/weight = event.get_weight()
if(weight <= 0)
continue
weighted_events[event] = weight
log_game_master("Filtered down to [weighted_events.len] choice\s.")
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
last_department_used = LAZYACCESS(choice.departments, 1)
return choice
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
if(!LAZYLEN(most_active_departments)) // Server's empty?
log_game_master("Game Master failed to find any active departments.")
return list()
var/list/best_events = list()
if(most_active_departments.len >= 2)
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
best_events = filter_events_by_departments(top_two)
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
return best_events
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
best_events = filter_events_by_departments(most_active_departments[1])
if(LAZYLEN(best_events))
return best_events
// At this point we should expand our horizons.
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
if(LAZYLEN(best_events))
return best_events
// Just give a random event if for some reason it still can't make up its mind.
best_events = filter_events_by_departments()
if(LAZYLEN(best_events))
return best_events
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
return list()
// Filters the available events down to events for specific departments.
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
// If no list is passed, all the events will be returned.
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
. = list()
for(var/E in ticker.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
if(event.chaotic_threshold && !ignore_round_chaos)
if(ticker.danger > event.chaotic_threshold)
continue
// An event has to involve all of these departments to pass.
var/viable = TRUE
if(LAZYLEN(departments))
for(var/department in departments)
if(!LAZYFIND(departments, department))
viable = FALSE
break
if(viable)
. += event

View File

@@ -0,0 +1,44 @@
// The `classic` game master tries to act like the old system, choosing events without any specific goals.
// * Has no goals, and instead operates purely off of the weights of the events it has.
// * Does not react to danger at all.
/datum/game_master/classic/choose_event()
var/list/weighted_events = list()
for(var/E in ticker.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
weighted_events[event] = event.get_weight()
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
return choice
// The `super_random` game master chooses events purely at random, ignoring weights entirely.
// * Has no goals, and instead chooses randomly, ignoring weights.
// * Does not react to danger at all.
/datum/game_master/super_random/choose_event()
return pick(ticker.available_events)
// The `brutal` game master tries to run dangerous events frequently.
// * Chaotic events have their weights artifically boosted.
// * Ignores accumulated danger.
/datum/game_master/brutal
ignore_round_chaos = TRUE
/datum/game_master/brutal/choose_event()
var/list/weighted_events = list()
for(var/E in ticker.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
weighted_events[event] = event.get_weight() + (event.chaos * 2)
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
return choice

View File

@@ -9,6 +9,9 @@
/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir) /atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir)
set_dir(new_dir) set_dir(new_dir)
/datum/proc/qdel_self()
qdel(src)
/proc/register_all_movement(var/event_source, var/listener) /proc/register_all_movement(var/event_source, var/listener)
GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set) GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)

View File

@@ -0,0 +1,24 @@
// Observer Pattern Implementation: Stat Set
// Registration type: /mob/living
//
// Raised when: A /mob/living changes stat, using the set_stat() proc
//
// Arguments that the called proc should expect:
// /mob/living/stat_mob: The mob whose stat changed
// /old_stat: Status before the change.
// /new_stat: Status after the change.
GLOBAL_DATUM_INIT(stat_set_event, /decl/observ/stat_set, new)
/decl/observ/stat_set
name = "Stat Set"
expected_type = /mob/living
/****************
* Stat Handling *
****************/
/mob/living/set_stat(var/new_stat)
var/old_stat = stat
. = ..()
if(stat != old_stat)
GLOB.stat_set_event.raise_event(src, old_stat, new_stat)

View File

@@ -48,10 +48,10 @@ var/global/datum/repository/crew/crew_repository = new()
if(C.sensor_mode >= SUIT_SENSOR_TRACKING) if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H) var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name) crewmemberData["area"] = sanitize(A.get_name())
crewmemberData["x"] = pos.x crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y crewmemberData["y"] = pos.y
crewmemberData["z"] = pos.z crewmemberData["z"] = using_map.get_zlevel_name(pos.z)
crewmembers[++crewmembers.len] = crewmemberData crewmembers[++crewmembers.len] = crewmemberData

View File

@@ -339,14 +339,14 @@
/datum/supply_pack/med/distillery /datum/supply_pack/med/distillery
name = "Chemical distiller crate" name = "Chemical distiller crate"
contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery = 1) contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery = 1)
cost = 175 cost = 50
containertype = /obj/structure/largecrate containertype = /obj/structure/largecrate
containername = "Chemical distiller crate" containername = "Chemical distiller crate"
/datum/supply_pack/med/advdistillery /datum/supply_pack/med/advdistillery
name = "Industrial Chemical distiller crate" name = "Industrial Chemical distiller crate"
contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery/industrial = 1) contains = list(/obj/machinery/portable_atmospherics/powered/reagent_distillery/industrial = 1)
cost = 250 cost = 150
containertype = /obj/structure/largecrate containertype = /obj/structure/largecrate
containername = "Industrial Chemical distiller crate" containername = "Industrial Chemical distiller crate"

View File

@@ -116,6 +116,15 @@
containername = "Robolimb blueprints (Bishop)" containername = "Robolimb blueprints (Bishop)"
access = access_robotics access = access_robotics
/datum/supply_pack/robotics/robolimbs/cenilimicybernetics
name = "Cenilimi Cybernetics robolimb blueprints"
contains = list(/obj/item/weapon/disk/limb/cenilimicybernetics)
cost = 45
containertype = /obj/structure/closet/crate/secure/science
containername = "Robolimb blueprints (Cenilimi Cybernetics)"
access = access_robotics
/datum/supply_pack/robotics/mecha_ripley /datum/supply_pack/robotics/mecha_ripley
name = "Circuit Crate (\"Ripley\" APLU)" name = "Circuit Crate (\"Ripley\" APLU)"
contains = list( contains = list(

View File

@@ -91,4 +91,4 @@
var/obj/structure/largecrate/C = /obj/structure/largecrate var/obj/structure/largecrate/C = /obj/structure/largecrate
icon = image(initial(C.icon), initial(C.icon_state)) icon = image(initial(C.icon), initial(C.icon_state))
return "\icon[icon]" return "[bicon(icon)]"

View File

@@ -146,7 +146,7 @@ datum/uplink_item/dd_SortValue()
/datum/uplink_item/item/log_icon() /datum/uplink_item/item/log_icon()
var/obj/I = path var/obj/I = path
return "\icon[I]" return "[bicon(I)]"
/******************************** /********************************
* * * *
@@ -160,7 +160,7 @@ datum/uplink_item/dd_SortValue()
if(!default_abstract_uplink_icon) if(!default_abstract_uplink_icon)
default_abstract_uplink_icon = image('icons/obj/pda.dmi', "pda-syn") default_abstract_uplink_icon = image('icons/obj/pda.dmi', "pda-syn")
return "\icon[default_abstract_uplink_icon]" return "[bicon(default_abstract_uplink_icon)]"
/* /*
* Crated goods. * Crated goods.

View File

@@ -60,7 +60,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32
C.light_disabled = !C.light_disabled C.light_disabled = !C.light_disabled
if(CAMERA_WIRE_ALARM) if(CAMERA_WIRE_ALARM)
C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
return return
/datum/wires/camera/proc/CanDeconstruct() /datum/wires/camera/proc/CanDeconstruct()

View File

@@ -34,16 +34,16 @@ var/const/WIRE_NEXT = 1024
var/obj/machinery/media/jukebox/A = holder var/obj/machinery/media/jukebox/A = holder
switch(index) switch(index)
if(WIRE_POWER) if(WIRE_POWER)
holder.visible_message("<span class='notice'>\icon[holder] The power light flickers.</span>") holder.visible_message("<span class='notice'>[bicon(holder)] The power light flickers.</span>")
A.shock(usr, 90) A.shock(usr, 90)
if(WIRE_HACK) if(WIRE_HACK)
holder.visible_message("<span class='notice'>\icon[holder] The parental guidance light flickers.</span>") holder.visible_message("<span class='notice'>[bicon(holder)] The parental guidance light flickers.</span>")
if(WIRE_REVERSE) if(WIRE_REVERSE)
holder.visible_message("<span class='notice'>\icon[holder] The data light blinks ominously.</span>") holder.visible_message("<span class='notice'>[bicon(holder)] The data light blinks ominously.</span>")
if(WIRE_SPEEDUP) if(WIRE_SPEEDUP)
holder.visible_message("<span class='notice'>\icon[holder] The speakers squeaks.</span>") holder.visible_message("<span class='notice'>[bicon(holder)] The speakers squeaks.</span>")
if(WIRE_SPEEDDOWN) if(WIRE_SPEEDDOWN)
holder.visible_message("<span class='notice'>\icon[holder] The speakers rumble.</span>") holder.visible_message("<span class='notice'>[bicon(holder)] The speakers rumble.</span>")
if(WIRE_START) if(WIRE_START)
A.StartPlaying() A.StartPlaying()
if(WIRE_STOP) if(WIRE_STOP)

View File

@@ -23,15 +23,15 @@
switch(index) switch(index)
if(WIRE_DETONATE) if(WIRE_DETONATE)
C.visible_message("\icon[C] *BEEE-*", "\icon[C] *BEEE-*") C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
C.explode() C.explode()
if(WIRE_TIMED_DET) if(WIRE_TIMED_DET)
C.visible_message("\icon[C] *BEEE-*", "\icon[C] *BEEE-*") C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
C.explode() C.explode()
if(WIRE_DISARM) if(WIRE_DISARM)
C.visible_message("\icon[C] *click!*", "\icon[C] *click!*") C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
new C.mineitemtype(get_turf(C)) new C.mineitemtype(get_turf(C))
spawn(0) spawn(0)
qdel(C) qdel(C)
@@ -45,7 +45,7 @@
return return
if(WIRE_BADDISARM) if(WIRE_BADDISARM)
C.visible_message("\icon[C] *BEEPBEEPBEEP*", "\icon[C] *BEEPBEEPBEEP*") C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
spawn(20) spawn(20)
C.explode() C.explode()
return return
@@ -56,24 +56,24 @@
return return
switch(index) switch(index)
if(WIRE_DETONATE) if(WIRE_DETONATE)
C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
if(WIRE_TIMED_DET) if(WIRE_TIMED_DET)
C.visible_message("\icon[C] *BEEPBEEPBEEP*", "\icon[C] *BEEPBEEPBEEP*") C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
spawn(20) spawn(20)
C.explode() C.explode()
if(WIRE_DISARM) if(WIRE_DISARM)
C.visible_message("\icon[C] *ping*", "\icon[C] *ping*") C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
if(WIRE_DUMMY_1) if(WIRE_DUMMY_1)
C.visible_message("\icon[C] *ping*", "\icon[C] *ping*") C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
if(WIRE_DUMMY_2) if(WIRE_DUMMY_2)
C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
if(WIRE_BADDISARM) if(WIRE_BADDISARM)
C.visible_message("\icon[C] *ping*", "\icon[C] *ping*") C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
return return
/datum/wires/mines/CanUse(var/mob/living/L) /datum/wires/mines/CanUse(var/mob/living/L)

View File

@@ -28,7 +28,7 @@ var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be.
C.interface_control = !C.interface_control C.interface_control = !C.interface_control
if(PARTICLE_LIMIT_POWER_WIRE) if(PARTICLE_LIMIT_POWER_WIRE)
C.visible_message("\icon[C]<b>[C]</b> makes a large whirring noise.") C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
/datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended) /datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended)
var/obj/machinery/particle_accelerator/control_box/C = holder var/obj/machinery/particle_accelerator/control_box/C = holder

View File

@@ -124,7 +124,7 @@ var/global/list/PDA_Manifest = list()
if(depthead && car.len != 1) if(depthead && car.len != 1)
car.Swap(1,car.len) car.Swap(1,car.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO)) if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN))
civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive) civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1 department = 1
if(depthead && civ.len != 1) if(depthead && civ.len != 1)

View File

@@ -66,7 +66,6 @@
attack_verb = list("HONKED") attack_verb = list("HONKED")
var/spam_flag = 0 var/spam_flag = 0
/obj/item/weapon/c_tube /obj/item/weapon/c_tube
name = "cardboard tube" name = "cardboard tube"
desc = "A tube... of cardboard." desc = "A tube... of cardboard."
@@ -77,141 +76,6 @@
throw_speed = 4 throw_speed = 4
throw_range = 5 throw_range = 5
/obj/item/weapon/cane
name = "cane"
desc = "A cane used by a true gentleman."
icon = 'icons/obj/weapons.dmi'
icon_state = "cane"
item_icons = list(
slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
)
force = 5.0
throwforce = 7.0
w_class = ITEMSIZE_NORMAL
matter = list(DEFAULT_WALL_MATERIAL = 50)
attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed")
/obj/item/weapon/cane/concealed
var/concealed_blade
/obj/item/weapon/cane/concealed/New()
..()
var/obj/item/weapon/material/butterfly/switchblade/temp_blade = new(src)
concealed_blade = temp_blade
temp_blade.attack_self()
/obj/item/weapon/cane/concealed/attack_self(var/mob/user)
var/datum/gender/T = gender_datums[user.get_visible_gender()]
if(concealed_blade)
user.visible_message("<span class='warning'>[user] has unsheathed \a [concealed_blade] from [T.his] [src]!</span>", "You unsheathe \the [concealed_blade] from \the [src].")
// Calling drop/put in hands to properly call item drop/pickup procs
playsound(user.loc, 'sound/weapons/holster/sheathout.ogg', 50, 1)
user.drop_from_inventory(src)
user.put_in_hands(concealed_blade)
user.put_in_hands(src)
user.update_inv_l_hand(0)
user.update_inv_r_hand()
concealed_blade = null
else
..()
/obj/item/weapon/cane/concealed/attackby(var/obj/item/weapon/material/butterfly/W, var/mob/user)
if(!src.concealed_blade && istype(W))
var/datum/gender/T = gender_datums[user.get_visible_gender()]
user.visible_message("<span class='warning'>[user] has sheathed \a [W] into [T.his] [src]!</span>", "You sheathe \the [W] into \the [src].")
playsound(user.loc, 'sound/weapons/holster/sheathin.ogg', 50, 1)
user.drop_from_inventory(W)
W.loc = src
src.concealed_blade = W
update_icon()
else
..()
/obj/item/weapon/cane/concealed/update_icon()
if(concealed_blade)
name = initial(name)
icon_state = initial(icon_state)
item_state = initial(icon_state)
else
name = "cane shaft"
icon_state = "nullrod"
item_state = "foldcane"
/obj/item/weapon/cane/whitecane
name = "white cane"
desc = "A white cane. They are commonly used by the blind or visually impaired as a mobility tool or as a courtesy to others."
icon = 'icons/obj/weapons.dmi'
icon_state = "whitecane"
/obj/item/weapon/cane/whitecane/attack(mob/M as mob, mob/user as mob)
if(user.a_intent == I_HELP)
user.visible_message("<span class='notice'>\The [user] has lightly tapped [M] on the ankle with their white cane!</span>")
return
else
..()
/obj/item/weapon/cane/crutch
name ="crutch"
desc = "A long stick with a crosspiece at the top, used to help with walking."
icon_state = "crutch"
item_state = "crutch"
//Code for Telescopic White Cane writen by Gozulio
/obj/item/weapon/melee/collapsable_whitecane
name = "telescopic white cane"
desc = "A telescoping white cane. They are commonly used by the blind or visually impaired as a mobility tool or as a courtesy to others."
icon = 'icons/obj/weapons.dmi'
icon_state = "whitecane1in"
item_icons = list(
slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
)
slot_flags = SLOT_BELT
w_class = ITEMSIZE_SMALL
force = 3
var/on = 0
/obj/item/weapon/melee/collapsable_whitecane/attack_self(mob/user as mob)
on = !on
if(on)
user.visible_message("<span class='notice'>\The [user] extends the white cane.</span>",\
"<span class='warning'>You extend the white cane.</span>",\
"You hear an ominous click.")
icon_state = "whitecane1out"
item_state_slots = list(slot_r_hand_str = "whitecane", slot_l_hand_str = "whitecane")
w_class = ITEMSIZE_NORMAL
force = 5
attack_verb = list("smacked", "struck", "cracked", "beaten")
else
user.visible_message("<span class='notice'>\The [user] collapses the white cane.</span>",\
"<span class='notice'>You collapse the white cane.</span>",\
"You hear a click.")
icon_state = "whitecane1in"
item_state_slots = list(slot_r_hand_str = null, slot_l_hand_str = null)
w_class = ITEMSIZE_SMALL
force = 3
attack_verb = list("hit", "poked")
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.update_inv_l_hand()
H.update_inv_r_hand()
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
add_fingerprint(user)
return
/obj/item/weapon/melee/collapsable_whitecane/attack(mob/M as mob, mob/user as mob)
if(user.a_intent == I_HELP)
user.visible_message("<span class='notice'>\The [user] has lightly tapped [M] on the ankle with their white cane!</span>")
return
else
..()
/obj/item/weapon/disk /obj/item/weapon/disk
name = "disk" name = "disk"
icon = 'icons/obj/items.dmi' icon = 'icons/obj/items.dmi'

View File

@@ -49,20 +49,20 @@
datum/announcement/proc/Message(message as text, message_title as text) datum/announcement/proc/Message(message as text, message_title as text)
for(var/mob/M in player_list) for(var/mob/M in player_list)
if(!istype(M,/mob/new_player) && !isdeaf(M)) if(!istype(M,/mob/new_player) && !isdeaf(M))
M << "<h2 class='alert'>[title]</h2>" to_chat(M, "<h2 class='alert'>[title]</h2>")
M << "<span class='alert'>[message]</span>" to_chat(M, "<span class='alert'>[message]</span>")
if (announcer) if (announcer)
M << "<span class='alert'> -[html_encode(announcer)]</span>" to_chat(M, "<span class='alert'> -[html_encode(announcer)]</span>")
datum/announcement/minor/Message(message as text, message_title as text) datum/announcement/minor/Message(message as text, message_title as text)
world << "<b>[message]</b>" to_world("<b>[message]</b>")
datum/announcement/priority/Message(message as text, message_title as text) datum/announcement/priority/Message(message as text, message_title as text)
world << "<h1 class='alert'>[message_title]</h1>" to_world("<h1 class='alert'>[message_title]</h1>")
world << "<span class='alert'>[message]</span>" to_world("<span class='alert'>[message]</span>")
if(announcer) if(announcer)
world << "<span class='alert'> -[html_encode(announcer)]</span>" to_world("<span class='alert'> -[html_encode(announcer)]</span>")
world << "<br>" to_world("<br>")
datum/announcement/priority/command/Message(message as text, message_title as text) datum/announcement/priority/command/Message(message as text, message_title as text)
var/command var/command
@@ -74,11 +74,11 @@ datum/announcement/priority/command/Message(message as text, message_title as te
command += "<br>" command += "<br>"
for(var/mob/M in player_list) for(var/mob/M in player_list)
if(!istype(M,/mob/new_player) && !isdeaf(M)) if(!istype(M,/mob/new_player) && !isdeaf(M))
M << command to_chat(M, command)
datum/announcement/priority/security/Message(message as text, message_title as text) datum/announcement/priority/security/Message(message as text, message_title as text)
world << "<font size=4 color='red'>[message_title]</font>" to_world("<font size=4 color='red'>[message_title]</font>")
world << "<font color='red'>[message]</font>" to_world("<font color='red'>[message]</font>")
datum/announcement/proc/NewsCast(message as text, message_title as text) datum/announcement/proc/NewsCast(message as text, message_title as text)
if(!newscast) if(!newscast)

View File

@@ -70,6 +70,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
flags = RAD_SHIELDED flags = RAD_SHIELDED
sound_env = SMALL_ENCLOSED sound_env = SMALL_ENCLOSED
base_turf = /turf/space base_turf = /turf/space
forbid_events = TRUE
/area/shuttle/arrival /area/shuttle/arrival
name = "\improper Arrival Shuttle" name = "\improper Arrival Shuttle"
@@ -807,6 +808,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Construction Area" name = "\improper Construction Area"
icon_state = "construction" icon_state = "construction"
/area/hallway/secondary/entry
forbid_events = TRUE
/area/hallway/secondary/entry/fore /area/hallway/secondary/entry/fore
name = "\improper Shuttle Dock Hallway - Mid" name = "\improper Shuttle Dock Hallway - Mid"
icon_state = "entry_1" icon_state = "entry_1"
@@ -981,6 +985,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
icon_state = "Sleep" icon_state = "Sleep"
flags = RAD_SHIELDED flags = RAD_SHIELDED
ambience = AMBIENCE_GENERIC ambience = AMBIENCE_GENERIC
forbid_events = TRUE
/area/crew_quarters/toilet /area/crew_quarters/toilet
name = "\improper Dormitory Toilets" name = "\improper Dormitory Toilets"
@@ -1280,6 +1285,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
icon_state = "Holodeck" icon_state = "Holodeck"
dynamic_lighting = 0 dynamic_lighting = 0
sound_env = LARGE_ENCLOSED sound_env = LARGE_ENCLOSED
forbid_events = TRUE
/area/holodeck/alphadeck /area/holodeck/alphadeck
name = "\improper Holodeck Alpha" name = "\improper Holodeck Alpha"
@@ -1379,6 +1385,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Engine Room" name = "\improper Engine Room"
icon_state = "engine" icon_state = "engine"
sound_env = LARGE_ENCLOSED sound_env = LARGE_ENCLOSED
forbid_events = TRUE
/area/engineering/engine_airlock /area/engineering/engine_airlock
name = "\improper Engine Room Airlock" name = "\improper Engine Room Airlock"

View File

@@ -30,6 +30,7 @@
var/used_environ = 0 var/used_environ = 0
var/has_gravity = 1 var/has_gravity = 1
var/secret_name = FALSE // This tells certain things that display areas' names that they shouldn't display this area's name.
var/obj/machinery/power/apc/apc = null var/obj/machinery/power/apc/apc = null
var/no_air = null var/no_air = null
// var/list/lights // list of all lights on this area // var/list/lights // list of all lights on this area
@@ -41,26 +42,20 @@
var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf
var/global/global_uid = 0 var/global/global_uid = 0
var/uid var/uid
var/forbid_events = FALSE // If true, random events will not start inside this area.
/area/New() /area/New()
icon_state = ""
uid = ++global_uid uid = ++global_uid
all_areas += src all_areas += src //Replace with /area in world? Byond optimizes X in world loops.
if(!requires_power)
power_light = 0
power_equip = 0
power_environ = 0
if(dynamic_lighting)
luminosity = 0
else
luminosity = 1
..() ..()
/area/Initialize() /area/Initialize()
. = ..() . = ..()
luminosity = !(dynamic_lighting)
icon_state = ""
return INITIALIZE_HINT_LATELOAD // Areas tradiationally are initialized AFTER other atoms. return INITIALIZE_HINT_LATELOAD // Areas tradiationally are initialized AFTER other atoms.
/area/LateInitialize() /area/LateInitialize()
@@ -83,7 +78,7 @@
// NOTE: There probably won't be any atoms in these turfs, but just in case we should call these procs. // NOTE: There probably won't be any atoms in these turfs, but just in case we should call these procs.
A.contents.Add(T) A.contents.Add(T)
if(old_area) if(old_area)
// Handle dynamic lighting update if // Handle dynamic lighting update if
if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting) if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting)
if(A.dynamic_lighting) if(A.dynamic_lighting)
T.lighting_build_overlay() T.lighting_build_overlay()
@@ -360,6 +355,8 @@ var/list/mob/living/forced_ambiance_list = new
temp_airlock.prison_open() temp_airlock.prison_open()
for(var/obj/machinery/door/window/temp_windoor in src) for(var/obj/machinery/door/window/temp_windoor in src)
temp_windoor.open() temp_windoor.open()
for(var/obj/machinery/door/blast/temp_blast in src)
temp_blast.open()
/area/has_gravity() /area/has_gravity()
return has_gravity return has_gravity
@@ -420,3 +417,8 @@ var/list/ghostteleportlocs = list()
ghostteleportlocs = sortAssoc(ghostteleportlocs) ghostteleportlocs = sortAssoc(ghostteleportlocs)
return 1 return 1
/area/proc/get_name()
if(secret_name)
return "Unknown Area"
return name

View File

@@ -41,8 +41,7 @@
_preloader.load(src) _preloader.load(src)
// Pass our arguments to InitAtom so they can be passed to initialize(), but replace 1st with if-we're-during-mapload. // Pass our arguments to InitAtom so they can be passed to initialize(), but replace 1st with if-we're-during-mapload.
var/do_initialize = SSatoms && SSatoms.initialized // Workaround our non-ideal initialization order: SSatoms may not exist yet. var/do_initialize = SSatoms.initialized
//var/do_initialize = SSatoms.initialized
if(do_initialize > INITIALIZATION_INSSATOMS) if(do_initialize > INITIALIZATION_INSSATOMS)
args[1] = (do_initialize == INITIALIZATION_INNEW_MAPLOAD) args[1] = (do_initialize == INITIALIZATION_INNEW_MAPLOAD)
if(SSatoms.InitAtom(src, args)) if(SSatoms.InitAtom(src, args))
@@ -183,9 +182,15 @@
else else
f_name += "oil-stained [name][infix]." f_name += "oil-stained [name][infix]."
to_chat(user, "\icon[src] That's [f_name] [suffix]") to_chat(user, "[bicon(src)] That's [f_name] [suffix]")
to_chat(user,desc) to_chat(user,desc)
if(user.client?.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
to_chat(user, description_info)
if(user.client?.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
user.client.statpanel = "Examine" // Switch to stat panel
return distance == -1 || (get_dist(src, user) <= distance) return distance == -1 || (get_dist(src, user) <= distance)
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set. // called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.

View File

@@ -23,6 +23,9 @@
var/old_y = 0 var/old_y = 0
var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P) var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P)
var/movement_type = NONE var/movement_type = NONE
var/cloaked = FALSE //If we're cloaked or not
var/image/cloaked_selfimage //The image we use for our client to let them see where we are
/atom/movable/Destroy() /atom/movable/Destroy()
. = ..() . = ..()
@@ -44,7 +47,7 @@
pulledby = null pulledby = null
/atom/movable/vv_edit_var(var_name, var_value) /atom/movable/vv_edit_var(var_name, var_value)
if(GLOB.VVpixelmovement[var_name]) //Pixel movement is not yet implemented, changing this will break everything irreversibly. if(var_name in GLOB.VVpixelmovement) //Pixel movement is not yet implemented, changing this will break everything irreversibly.
return FALSE return FALSE
return ..() return ..()
@@ -452,30 +455,33 @@
var/move_to_z = src.get_transit_zlevel() var/move_to_z = src.get_transit_zlevel()
if(move_to_z) if(move_to_z)
z = move_to_z var/new_z = move_to_z
var/new_x
var/new_y
if(x <= TRANSITIONEDGE) if(x <= TRANSITIONEDGE)
x = world.maxx - TRANSITIONEDGE - 2 new_x = world.maxx - TRANSITIONEDGE - 2
y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
else if (x >= (world.maxx - TRANSITIONEDGE + 1)) else if (x >= (world.maxx - TRANSITIONEDGE + 1))
x = TRANSITIONEDGE + 1 new_x = TRANSITIONEDGE + 1
y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
else if (y <= TRANSITIONEDGE) else if (y <= TRANSITIONEDGE)
y = world.maxy - TRANSITIONEDGE -2 new_y = world.maxy - TRANSITIONEDGE -2
x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
else if (y >= (world.maxy - TRANSITIONEDGE + 1)) else if (y >= (world.maxy - TRANSITIONEDGE + 1))
y = TRANSITIONEDGE + 1 new_y = TRANSITIONEDGE + 1
x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
if(ticker && istype(ticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear if(ticker && istype(ticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear
var/datum/game_mode/nuclear/G = ticker.mode var/datum/game_mode/nuclear/G = ticker.mode
G.check_nuke_disks() G.check_nuke_disks()
spawn(0) var/turf/T = locate(new_x, new_y, new_z)
if(loc) loc.Entered(src) if(istype(T))
forceMove(T)
//by default, transition randomly to another zlevel //by default, transition randomly to another zlevel
/atom/movable/proc/get_transit_zlevel() /atom/movable/proc/get_transit_zlevel()
@@ -509,3 +515,93 @@
// Called when touching a lava tile. // Called when touching a lava tile.
/atom/movable/proc/lava_act() /atom/movable/proc/lava_act()
fire_act(null, 10000, 1000) fire_act(null, 10000, 1000)
// Procs to cloak/uncloak
/atom/movable/proc/cloak()
if(cloaked)
return FALSE
cloaked = TRUE
. = TRUE // We did work
var/static/animation_time = 1 SECOND
cloaked_selfimage = get_cloaked_selfimage()
//Wheeee
cloak_animation(animation_time)
//Needs to be last so people can actually see the effect before we become invisible
plane = CLOAKED_PLANE
/atom/movable/proc/uncloak()
if(!cloaked)
return FALSE
cloaked = FALSE
. = TRUE // We did work
var/static/animation_time = 1 SECOND
QDEL_NULL(cloaked_selfimage)
//Needs to be first so people can actually see the effect, so become uninvisible first
plane = initial(plane)
//Oooooo
uncloak_animation(animation_time)
// Animations for cloaking/uncloaking
/atom/movable/proc/cloak_animation(var/length = 1 SECOND)
//Save these
var/initial_alpha = alpha
//Animate alpha fade
animate(src, alpha = 0, time = length)
//Animate a cloaking effect
var/our_filter = filters.len+1 //Filters don't appear to have a type that can be stored in a var and accessed. This is how the DM reference does it.
filters += filter(type="wave", x = 0, y = 16, size = 0, offset = 0, flags = WAVE_SIDEWAYS)
animate(filters[our_filter], offset = 1, size = 8, time = length, flags = ANIMATION_PARALLEL)
//Wait for animations to finish
sleep(length+5)
//Remove those
filters -= filters[our_filter]
//Back to original alpha
alpha = initial_alpha
/atom/movable/proc/uncloak_animation(var/length = 1 SECOND)
//Save these
var/initial_alpha = alpha
//Put us back to normal, but no alpha
alpha = 0
//Animate alpha fade up
animate(src, alpha = initial_alpha, time = length)
//Animate a cloaking effect
var/our_filter = filters.len+1 //Filters don't appear to have a type that can be stored in a var and accessed. This is how the DM reference does it.
filters += filter(type="wave", x=0, y = 16, size = 8, offset = 1, flags = WAVE_SIDEWAYS)
animate(filters[our_filter], offset = 0, size = 0, time = length, flags = ANIMATION_PARALLEL)
//Wait for animations to finish
sleep(length+5)
//Remove those
filters -= filters[our_filter]
// So cloaked things can see themselves, if necessary
/atom/movable/proc/get_cloaked_selfimage()
var/icon/selficon = icon(icon, icon_state)
selficon.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) //White
var/image/selfimage = image(selficon)
selfimage.color = "#0000FF"
selfimage.alpha = 100
selfimage.layer = initial(layer)
selfimage.plane = initial(plane)
selfimage.loc = src
return selfimage

View File

@@ -46,7 +46,7 @@
icon_state = "scanner_0" icon_state = "scanner_0"
density = 1 density = 1
anchored = 1.0 anchored = 1.0
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 50 idle_power_usage = 50
active_power_usage = 300 active_power_usage = 300
interact_offline = 1 interact_offline = 1
@@ -260,7 +260,7 @@
var/obj/item/weapon/disk/data/disk = null var/obj/item/weapon/disk/data/disk = null
var/selected_menu_key = null var/selected_menu_key = null
anchored = 1 anchored = 1
use_power = 1 use_power = USE_POWER_IDLE
idle_power_usage = 10 idle_power_usage = 10
active_power_usage = 400 active_power_usage = 400
var/waiting_for_user_input=0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X var/waiting_for_user_input=0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
@@ -293,19 +293,15 @@
else else
return return
/obj/machinery/computer/scan_consolenew/New() /obj/machinery/computer/scan_consolenew/Initialize()
..() . = ..()
for(var/i=0;i<3;i++) for(var/i=0;i<3;i++)
buffers[i+1]=new /datum/dna2/record buffers[i+1]=new /datum/dna2/record
spawn(5) for(dir in list(NORTH,EAST,SOUTH,WEST))
for(dir in list(NORTH,EAST,SOUTH,WEST)) connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir)) if(connected)
if(!isnull(connected)) break
break VARSET_IN(src, injector_ready, TRUE, 25 SECONDS)
spawn(250)
src.injector_ready = 1
return
return
/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer) /obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer)
var/list/arr = list() var/list/arr = list()

View File

@@ -69,7 +69,7 @@
O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss()) O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss())
O.adjustToxLoss(M.getToxLoss() + 20) O.adjustToxLoss(M.getToxLoss() + 20)
O.adjustOxyLoss(M.getOxyLoss()) O.adjustOxyLoss(M.getOxyLoss())
O.stat = M.stat O.set_stat(M.stat)
O.a_intent = I_HURT O.a_intent = I_HURT
for (var/obj/item/weapon/implant/I in implants) for (var/obj/item/weapon/implant/I in implants)
I.loc = O I.loc = O
@@ -154,7 +154,7 @@
O.take_overall_damage(M.getBruteLoss(), M.getFireLoss()) O.take_overall_damage(M.getBruteLoss(), M.getFireLoss())
O.adjustToxLoss(M.getToxLoss()) O.adjustToxLoss(M.getToxLoss())
O.adjustOxyLoss(M.getOxyLoss()) O.adjustOxyLoss(M.getOxyLoss())
O.stat = M.stat O.set_stat(M.stat)
for (var/obj/item/weapon/implant/I in implants) for (var/obj/item/weapon/implant/I in implants)
I.loc = O I.loc = O
I.implanted = O I.implanted = O

View File

@@ -29,7 +29,7 @@
var/mob/living/carbon/human/C = src var/mob/living/carbon/human/C = src
to_chat(C, "<span class='notice'>Energy rushes through us. [C.lying ? "We arise." : ""]</span>") to_chat(C, "<span class='notice'>Energy rushes through us. [C.lying ? "We arise." : ""]</span>")
C.stat = 0 C.set_stat(CONSCIOUS)
C.SetParalysis(0) C.SetParalysis(0)
C.SetStunned(0) C.SetStunned(0)
C.SetWeakened(0) C.SetWeakened(0)

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