mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Merge branch 'master' of https://github.com/PolarisSS13/Polaris into 12/16/2015_newwizard
This commit is contained in:
46
.travis.yml
46
.travis.yml
@@ -1,28 +1,44 @@
|
|||||||
#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:
|
||||||
BYOND_MAJOR="508"
|
BYOND_MAJOR="510"
|
||||||
BYOND_MINOR="1287"
|
BYOND_MINOR="1346"
|
||||||
|
MACRO_COUNT=987
|
||||||
|
|
||||||
before_install:
|
cache:
|
||||||
- sudo apt-get update -qq
|
directories:
|
||||||
- sudo apt-get install libc6:i386 libgcc1:i386 libstdc++6:i386 -qq
|
- $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}
|
||||||
- sudo apt-get install python -qq
|
|
||||||
- sudo apt-get install python-pip -qq
|
addons:
|
||||||
- sudo pip install PyYaml -q
|
apt:
|
||||||
- sudo pip install beautifulsoup4 -q
|
packages:
|
||||||
|
- libc6-i386
|
||||||
|
- libgcc1:i386
|
||||||
|
- libstdc++6:i386
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- chmod +x ./install-byond.sh
|
||||||
|
- ./install-byond.sh
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip
|
- pip install --user PyYaml -q
|
||||||
- unzip byond.zip
|
- pip install --user beautifulsoup4 -q
|
||||||
- cd byond
|
|
||||||
- sudo make install
|
|
||||||
- cd ..
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- shopt -s globstar
|
- shopt -s globstar
|
||||||
- (! grep 'step_[xy]' maps/**/*.dmm)
|
- (! grep 'step_[xy]' maps/**/*.dmm)
|
||||||
- (! find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano)
|
- (! find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano)
|
||||||
- (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; [ $num -le 1355 ])
|
- (! grep -En "<\s*span\s+class\s*=\s*('[^'>]+|[^'>]+')\s*>" **/*.dm)
|
||||||
|
- awk -f tools/indentation.awk **/*.dm
|
||||||
|
- md5sum -c - <<< "88490b460c26947f5ec1ab1bb9fa9f17 *html/changelogs/example.yml"
|
||||||
|
- (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ])
|
||||||
|
- source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup
|
||||||
|
- python tools/TagMatcher/tag-matcher.py ../..
|
||||||
|
- echo "#define UNIT_TEST 1" > code/_unit_tests.dm
|
||||||
|
- cp config/example/* config/
|
||||||
- DreamMaker polaris.dme
|
- DreamMaker polaris.dme
|
||||||
|
- DreamDaemon polaris.dmb -invisible -trusted -core 2>&1 | tee log.txt
|
||||||
|
- grep "All Unit Tests Passed" log.txt
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
anchored = 1
|
anchored = 1
|
||||||
use_power = 0
|
use_power = 0
|
||||||
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
|
||||||
|
|
||||||
var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something.
|
var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something.
|
||||||
var/internal_volume = 600 // L
|
var/internal_volume = 600 // L
|
||||||
@@ -23,8 +24,8 @@
|
|||||||
/obj/machinery/atmospherics/unary/freezer/New()
|
/obj/machinery/atmospherics/unary/freezer/New()
|
||||||
..()
|
..()
|
||||||
initialize_directions = dir
|
initialize_directions = dir
|
||||||
|
circuit = new circuit(src)
|
||||||
component_parts = list()
|
component_parts = list()
|
||||||
component_parts += new /obj/item/weapon/circuitboard/unary_atmos/cooler(src)
|
|
||||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||||
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
||||||
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
anchored = 1
|
anchored = 1
|
||||||
use_power = 0
|
use_power = 0
|
||||||
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
|
||||||
|
|
||||||
var/max_temperature = T20C + 680
|
var/max_temperature = T20C + 680
|
||||||
var/internal_volume = 600 //L
|
var/internal_volume = 600 //L
|
||||||
@@ -23,9 +24,8 @@
|
|||||||
/obj/machinery/atmospherics/unary/heater/New()
|
/obj/machinery/atmospherics/unary/heater/New()
|
||||||
..()
|
..()
|
||||||
initialize_directions = dir
|
initialize_directions = dir
|
||||||
|
circuit = new circuit(src)
|
||||||
component_parts = list()
|
component_parts = list()
|
||||||
component_parts += new /obj/item/weapon/circuitboard/unary_atmos/heater(src)
|
|
||||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
|
||||||
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
||||||
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ obj/machinery/atmospherics/mains_pipe
|
|||||||
icon = 'icons/obj/atmospherics/mainspipe.dmi'
|
icon = 'icons/obj/atmospherics/mainspipe.dmi'
|
||||||
layer = 2.4 //under wires with their 2.5
|
layer = 2.4 //under wires with their 2.5
|
||||||
|
|
||||||
force = 20
|
|
||||||
|
|
||||||
var/volume = 0
|
var/volume = 0
|
||||||
|
|
||||||
var/alert_pressure = 80*ONE_ATMOSPHERE
|
var/alert_pressure = 80*ONE_ATMOSPHERE
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
|
var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
|
||||||
var/datum/pipeline/parent
|
var/datum/pipeline/parent
|
||||||
var/volume = 0
|
var/volume = 0
|
||||||
force = 20
|
|
||||||
|
|
||||||
layer = 2.4 //under wires with their 2.44
|
layer = 2.4 //under wires with their 2.44
|
||||||
use_power = 0
|
use_power = 0
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ mob/check_airflow_movable(n)
|
|||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
mob/dead/observer/check_airflow_movable()
|
mob/observer/check_airflow_movable()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
mob/living/silicon/check_airflow_movable()
|
mob/living/silicon/check_airflow_movable()
|
||||||
@@ -247,6 +247,6 @@ zone/proc/movables()
|
|||||||
. = list()
|
. = list()
|
||||||
for(var/turf/T in contents)
|
for(var/turf/T in contents)
|
||||||
for(var/atom/movable/A in T)
|
for(var/atom/movable/A in T)
|
||||||
if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/eye))
|
if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/observer))
|
||||||
continue
|
continue
|
||||||
. += A
|
. += A
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs)
|
|||||||
//Get heat transfer coefficients for clothing.
|
//Get heat transfer coefficients for clothing.
|
||||||
|
|
||||||
for(var/obj/item/clothing/C in src)
|
for(var/obj/item/clothing/C in src)
|
||||||
if(l_hand == C || r_hand == C)
|
if(item_is_in_hands(C))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if( C.max_heat_protection_temperature >= last_temperature )
|
if( C.max_heat_protection_temperature >= last_temperature )
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ var/global/vs_control/vsc = new
|
|||||||
else if(istext(vars["[V]_RANDOM"]))
|
else if(istext(vars["[V]_RANDOM"]))
|
||||||
var/txt = vars["[V]_RANDOM"]
|
var/txt = vars["[V]_RANDOM"]
|
||||||
if(findtextEx(txt,"PROB"))
|
if(findtextEx(txt,"PROB"))
|
||||||
txt = text2list(txt,"/")
|
txt = splittext(txt,"/")
|
||||||
txt[1] = replacetext(txt[1],"PROB","")
|
txt[1] = replacetext(txt[1],"PROB","")
|
||||||
var/p = text2num(txt[1])
|
var/p = text2num(txt[1])
|
||||||
var/r = txt[2]
|
var/r = txt[2]
|
||||||
@@ -358,7 +358,7 @@ var/global/vs_control/vsc = new
|
|||||||
newvalue = vars[V]
|
newvalue = vars[V]
|
||||||
else if(findtextEx(txt,"PICK"))
|
else if(findtextEx(txt,"PICK"))
|
||||||
txt = replacetext(txt,"PICK","")
|
txt = replacetext(txt,"PICK","")
|
||||||
txt = text2list(txt,",")
|
txt = splittext(txt,",")
|
||||||
newvalue = pick(txt)
|
newvalue = pick(txt)
|
||||||
else
|
else
|
||||||
newvalue = roll(txt)
|
newvalue = roll(txt)
|
||||||
|
|||||||
3
code/__defines/appearance.dm
Normal file
3
code/__defines/appearance.dm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Consider these images/atoms as part of the UI/HUD
|
||||||
|
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA
|
||||||
|
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR
|
||||||
18
code/__defines/btime.dm
Normal file
18
code/__defines/btime.dm
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Comment this out if the external btime library is unavailable
|
||||||
|
#define PRECISE_TIMER_AVAILABLE
|
||||||
|
|
||||||
|
#ifdef PRECISE_TIMER_AVAILABLE
|
||||||
|
var/global/__btime__libName = "btime.[world.system_type==MS_WINDOWS?"dll":"so"]"
|
||||||
|
#define TimeOfHour (__extern__timeofhour)
|
||||||
|
#define __extern__timeofhour text2num(call(__btime__libName, "gettime")())
|
||||||
|
/hook/startup/proc/checkbtime()
|
||||||
|
try
|
||||||
|
// This will always return 1 unless the btime library cannot be accessed
|
||||||
|
if(TimeOfHour || 1) return 1
|
||||||
|
catch(var/exception/e)
|
||||||
|
log_to_dd("PRECISE_TIMER_AVAILABLE is defined in btime.dm, but calling the btime library failed: [e]")
|
||||||
|
log_to_dd("This is a fatal error. The world will now shut down.")
|
||||||
|
del(world)
|
||||||
|
#else
|
||||||
|
#define TimeOfHour (world.timeofday % 36000)
|
||||||
|
#endif
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#define IS_TAJARA 5
|
#define IS_TAJARA 5
|
||||||
#define IS_XENOS 6
|
#define IS_XENOS 6
|
||||||
#define IS_TESHARI 7
|
#define IS_TESHARI 7
|
||||||
|
#define IS_SLIME 8
|
||||||
|
|
||||||
#define CE_STABLE "stable" // Inaprovaline
|
#define CE_STABLE "stable" // Inaprovaline
|
||||||
#define CE_ANTIBIOTIC "antibiotic" // Spaceacilin
|
#define CE_ANTIBIOTIC "antibiotic" // Spaceacilin
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#define CUT "cut"
|
#define CUT "cut"
|
||||||
#define BRUISE "bruise"
|
#define BRUISE "bruise"
|
||||||
|
#define PIERCE "pierce"
|
||||||
|
|
||||||
#define STUN "stun"
|
#define STUN "stun"
|
||||||
#define WEAKEN "weaken"
|
#define WEAKEN "weaken"
|
||||||
@@ -34,18 +35,20 @@
|
|||||||
#define ORGAN_BLEEDING (1<<1)
|
#define ORGAN_BLEEDING (1<<1)
|
||||||
#define ORGAN_BROKEN (1<<2)
|
#define ORGAN_BROKEN (1<<2)
|
||||||
#define ORGAN_DESTROYED (1<<3)
|
#define ORGAN_DESTROYED (1<<3)
|
||||||
#define ORGAN_ROBOT (1<<4)
|
#define ORGAN_SPLINTED (1<<4)
|
||||||
#define ORGAN_SPLINTED (1<<5)
|
#define ORGAN_DEAD (1<<5)
|
||||||
#define ORGAN_DEAD (1<<6)
|
#define ORGAN_MUTATED (1<<6)
|
||||||
#define ORGAN_MUTATED (1<<7)
|
|
||||||
#define ORGAN_ASSISTED (1<<8)
|
|
||||||
|
|
||||||
#define DROPLIMB_EDGE 0
|
#define DROPLIMB_EDGE 0
|
||||||
#define DROPLIMB_BLUNT 1
|
#define DROPLIMB_BLUNT 1
|
||||||
#define DROPLIMB_BURN 2
|
#define DROPLIMB_BURN 2
|
||||||
|
|
||||||
// Damage above this value must be repaired with surgery.
|
// Damage above this value must be repaired with surgery.
|
||||||
#define ROBOLIMB_SELF_REPAIR_CAP 30
|
#define ROBOLIMB_REPAIR_CAP 30
|
||||||
|
|
||||||
|
#define ORGAN_ASSISTED 1 // Like pacemakers, not robotic
|
||||||
|
#define ORGAN_ROBOT 2 // Fully robotic, no organic parts
|
||||||
|
#define ORGAN_LIFELIKE 3 // Robotic, made to appear organic
|
||||||
|
|
||||||
//Germs and infections.
|
//Germs and infections.
|
||||||
#define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still.
|
#define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#define BE_ALIEN 0x40
|
#define BE_ALIEN 0x40
|
||||||
#define BE_AI 0x80
|
#define BE_AI 0x80
|
||||||
#define BE_CULTIST 0x100
|
#define BE_CULTIST 0x100
|
||||||
#define BE_MONKEY 0x200
|
#define BE_RENEGADE 0x200
|
||||||
#define BE_NINJA 0x400
|
#define BE_NINJA 0x400
|
||||||
#define BE_RAIDER 0x800
|
#define BE_RAIDER 0x800
|
||||||
#define BE_PLANT 0x1000
|
#define BE_PLANT 0x1000
|
||||||
@@ -37,7 +37,7 @@ var/list/be_special_flags = list(
|
|||||||
"Xenomorph" = BE_ALIEN,
|
"Xenomorph" = BE_ALIEN,
|
||||||
"Positronic Brain" = BE_AI,
|
"Positronic Brain" = BE_AI,
|
||||||
"Cultist" = BE_CULTIST,
|
"Cultist" = BE_CULTIST,
|
||||||
"Monkey" = BE_MONKEY,
|
"Renegade" = BE_RENEGADE,
|
||||||
"Ninja" = BE_NINJA,
|
"Ninja" = BE_NINJA,
|
||||||
"Raider" = BE_RAIDER,
|
"Raider" = BE_RAIDER,
|
||||||
"Diona" = BE_PLANT,
|
"Diona" = BE_PLANT,
|
||||||
@@ -82,6 +82,7 @@ var/list/be_special_flags = list(
|
|||||||
#define MODE_LOYALIST "loyalist"
|
#define MODE_LOYALIST "loyalist"
|
||||||
#define MODE_MALFUNCTION "malf"
|
#define MODE_MALFUNCTION "malf"
|
||||||
#define MODE_TRAITOR "traitor"
|
#define MODE_TRAITOR "traitor"
|
||||||
|
#define MODE_AUTOTRAITOR "autotraitor"
|
||||||
|
|
||||||
#define DEFAULT_TELECRYSTAL_AMOUNT 12
|
#define DEFAULT_TELECRYSTAL_AMOUNT 12
|
||||||
|
|
||||||
|
|||||||
@@ -27,21 +27,21 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
|
|||||||
#define AI_CAMERA_LUMINOSITY 6
|
#define AI_CAMERA_LUMINOSITY 6
|
||||||
|
|
||||||
// Camera networks
|
// Camera networks
|
||||||
#define NETWORK_CRESCENT "Crescent"
|
#define NETWORK_CRESCENT "Spaceport"
|
||||||
#define NETWORK_CAFE_DOCK "Cafe Dock"
|
// #define NETWORK_CAFE_DOCK "Cafe Dock"
|
||||||
#define NETWORK_CARGO "Cargo"
|
#define NETWORK_CARGO "Cargo"
|
||||||
#define NETWORK_CIVILIAN "Civilian"
|
#define NETWORK_CIVILIAN "Civilian"
|
||||||
#define NETWORK_CIVILIAN_EAST "Civilian East"
|
// #define NETWORK_CIVILIAN_EAST "Civilian East"
|
||||||
#define NETWORK_CIVILIAN_WEST "Civilian West"
|
// #define NETWORK_CIVILIAN_WEST "Civilian West"
|
||||||
#define NETWORK_COMMAND "Command"
|
#define NETWORK_COMMAND "Command"
|
||||||
#define NETWORK_ENGINE "Engine"
|
#define NETWORK_ENGINE "Engine"
|
||||||
#define NETWORK_ENGINEERING "Engineering"
|
#define NETWORK_ENGINEERING "Engineering"
|
||||||
#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost"
|
#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost"
|
||||||
#define NETWORK_ERT "ZeEmergencyResponseTeam"
|
#define NETWORK_ERT "ZeEmergencyResponseTeam"
|
||||||
#define NETWORK_EXODUS "Northern Star"
|
#define NETWORK_EXODUS station_short
|
||||||
#define NETWORK_MEDICAL "Medical"
|
#define NETWORK_MEDICAL "Medical"
|
||||||
#define NETWORK_MERCENARY "MercurialNet"
|
#define NETWORK_MERCENARY "MercurialNet"
|
||||||
#define NETWORK_MINE "MINE"
|
#define NETWORK_MINE "Mining Outpost"
|
||||||
#define NETWORK_NORTHERN_STAR "Northern Star"
|
#define NETWORK_NORTHERN_STAR "Northern Star"
|
||||||
#define NETWORK_RESEARCH "Research"
|
#define NETWORK_RESEARCH "Research"
|
||||||
#define NETWORK_RESEARCH_OUTPOST "Research Outpost"
|
#define NETWORK_RESEARCH_OUTPOST "Research Outpost"
|
||||||
@@ -50,6 +50,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
|
|||||||
#define NETWORK_SECURITY "Security"
|
#define NETWORK_SECURITY "Security"
|
||||||
#define NETWORK_TELECOM "Tcomsat"
|
#define NETWORK_TELECOM "Tcomsat"
|
||||||
#define NETWORK_THUNDER "Thunderdome"
|
#define NETWORK_THUNDER "Thunderdome"
|
||||||
|
#define NETWORK_COMMUNICATORS "Communicators"
|
||||||
|
|
||||||
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
|
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
|
||||||
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret")
|
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret")
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
#define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio.
|
#define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio.
|
||||||
#define HUMAN_EXPOSED_SURFACE_AREA 5.2 //m^2, surface area of 1.7m (H) x 0.46m (D) cylinder
|
#define HUMAN_EXPOSED_SURFACE_AREA 5.2 //m^2, surface area of 1.7m (H) x 0.46m (D) cylinder
|
||||||
|
|
||||||
#define T0C 273.15 // 0.0 degrees celcius
|
#define T0C 273.15 // 0.0 degrees celcius
|
||||||
#define T20C 293.15 // 20.0 degrees celcius
|
#define T20C 293.15 // 20.0 degrees celcius
|
||||||
#define TCMB 2.7 // -270.3 degrees celcius
|
#define TCMB 2.7 // -270.3 degrees celcius
|
||||||
|
#define TN60C 213.15 // -60 degrees celcius
|
||||||
|
|
||||||
#define CLAMP01(x) max(0, min(1, x))
|
#define CLAMP01(x) max(0, min(1, x))
|
||||||
#define QUANTIZE(variable) (round(variable,0.0001))
|
#define QUANTIZE(variable) (round(variable,0.0001))
|
||||||
|
|||||||
@@ -23,27 +23,7 @@
|
|||||||
|
|
||||||
// Some arbitrary defines to be used by self-pruning global lists. (see master_controller)
|
// Some arbitrary defines to be used by self-pruning global lists. (see master_controller)
|
||||||
#define PROCESS_KILL 26 // Used to trigger removal from a processing list.
|
#define PROCESS_KILL 26 // Used to trigger removal from a processing list.
|
||||||
#define MAX_GEAR_COST 10 // Used in chargen for accessory loadout limit.
|
#define MAX_GEAR_COST 15 // Used in chargen for accessory loadout limit.
|
||||||
|
|
||||||
// Preference toggles.
|
|
||||||
#define SOUND_ADMINHELP 0x1
|
|
||||||
#define SOUND_MIDI 0x2
|
|
||||||
#define SOUND_AMBIENCE 0x4
|
|
||||||
#define SOUND_LOBBY 0x8
|
|
||||||
#define CHAT_OOC 0x10
|
|
||||||
#define CHAT_DEAD 0x20
|
|
||||||
#define CHAT_GHOSTEARS 0x40
|
|
||||||
#define CHAT_GHOSTSIGHT 0x80
|
|
||||||
#define CHAT_PRAYER 0x100
|
|
||||||
#define CHAT_RADIO 0x200
|
|
||||||
#define CHAT_ATTACKLOGS 0x400
|
|
||||||
#define CHAT_DEBUGLOGS 0x800
|
|
||||||
#define CHAT_LOOC 0x1000
|
|
||||||
#define CHAT_GHOSTRADIO 0x2000
|
|
||||||
#define SHOW_TYPING 0x4000
|
|
||||||
#define CHAT_NOICONS 0x8000
|
|
||||||
|
|
||||||
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC)
|
|
||||||
|
|
||||||
// For secHUDs and medHUDs and variants. The number is the location of the image on the list hud_list of humans.
|
// For secHUDs and medHUDs and variants. The number is the location of the image on the list hud_list of humans.
|
||||||
#define HEALTH_HUD 1 // A simple line rounding the mob's number health.
|
#define HEALTH_HUD 1 // A simple line rounding the mob's number health.
|
||||||
@@ -58,24 +38,37 @@
|
|||||||
#define LIFE_HUD 10 // STATUS_HUD that only reports dead or alive
|
#define LIFE_HUD 10 // STATUS_HUD that only reports dead or alive
|
||||||
|
|
||||||
//some colors
|
//some colors
|
||||||
#define COLOR_WHITE "#FFFFFF"
|
#define COLOR_WHITE "#FFFFFF"
|
||||||
#define COLOR_SILVER "#C0C0C0"
|
#define COLOR_SILVER "#C0C0C0"
|
||||||
#define COLOR_GRAY "#808080"
|
#define COLOR_GRAY "#808080"
|
||||||
#define COLOR_BLACK "#000000"
|
#define COLOR_BLACK "#000000"
|
||||||
#define COLOR_RED "#FF0000"
|
#define COLOR_RED "#FF0000"
|
||||||
#define COLOR_MAROON "#800000"
|
#define COLOR_MAROON "#800000"
|
||||||
#define COLOR_YELLOW "#FFFF00"
|
#define COLOR_YELLOW "#FFFF00"
|
||||||
#define COLOR_OLIVE "#808000"
|
#define COLOR_OLIVE "#808000"
|
||||||
#define COLOR_LIME "#00FF00"
|
#define COLOR_LIME "#00FF00"
|
||||||
#define COLOR_GREEN "#008000"
|
#define COLOR_GREEN "#008000"
|
||||||
#define COLOR_CYAN "#00FFFF"
|
#define COLOR_CYAN "#00FFFF"
|
||||||
#define COLOR_TEAL "#008080"
|
#define COLOR_TEAL "#008080"
|
||||||
#define COLOR_BLUE "#0000FF"
|
#define COLOR_BLUE "#0000FF"
|
||||||
#define COLOR_NAVY "#000080"
|
#define COLOR_NAVY "#000080"
|
||||||
#define COLOR_PINK "#FF00FF"
|
#define COLOR_PINK "#FF00FF"
|
||||||
#define COLOR_PURPLE "#800080"
|
#define COLOR_PURPLE "#800080"
|
||||||
#define COLOR_ORANGE "#FF9900"
|
#define COLOR_ORANGE "#FF9900"
|
||||||
#define COLOR_LUMINOL "#66FFFF"
|
#define COLOR_LUMINOL "#66FFFF"
|
||||||
|
#define COLOR_BEIGE "#CEB689"
|
||||||
|
#define COLOR_BLUE_GRAY "#6A97B0"
|
||||||
|
#define COLOR_BROWN "#B19664"
|
||||||
|
#define COLOR_DARK_BROWN "#917448"
|
||||||
|
#define COLOR_DARK_ORANGE "#B95A00"
|
||||||
|
#define COLOR_GREEN_GRAY "#8DAF6A"
|
||||||
|
#define COLOR_RED_GRAY "#AA5F61"
|
||||||
|
#define COLOR_PALE_BLUE_GRAY "#8BBBD5"
|
||||||
|
#define COLOR_PALE_GREEN_GRAY "#AED18B"
|
||||||
|
#define COLOR_PALE_RED_GRAY "#CC9090"
|
||||||
|
#define COLOR_PALE_PURPLE_GRAY "#BDA2BA"
|
||||||
|
#define COLOR_PURPLE_GRAY "#A2819E"
|
||||||
|
|
||||||
// Shuttles.
|
// Shuttles.
|
||||||
|
|
||||||
// These define the time taken for the shuttle to get to the space station, and the time before it leaves again.
|
// These define the time taken for the shuttle to get to the space station, and the time before it leaves again.
|
||||||
@@ -98,10 +91,10 @@
|
|||||||
|
|
||||||
// Setting this much higher than 1024 could allow spammers to DOS the server easily.
|
// Setting this much higher than 1024 could allow spammers to DOS the server easily.
|
||||||
#define MAX_MESSAGE_LEN 1024
|
#define MAX_MESSAGE_LEN 1024
|
||||||
#define MAX_PAPER_MESSAGE_LEN 3072
|
#define MAX_PAPER_MESSAGE_LEN 6144
|
||||||
#define MAX_BOOK_MESSAGE_LEN 9216
|
#define MAX_BOOK_MESSAGE_LEN 12288
|
||||||
#define MAX_LNAME_LEN 64
|
#define MAX_LNAME_LEN 64
|
||||||
#define MAX_NAME_LEN 26
|
#define MAX_NAME_LEN 52
|
||||||
|
|
||||||
// Event defines.
|
// Event defines.
|
||||||
#define EVENT_LEVEL_MUNDANE 1
|
#define EVENT_LEVEL_MUNDANE 1
|
||||||
@@ -163,19 +156,6 @@
|
|||||||
#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
|
#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
|
||||||
#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
|
#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
|
||||||
|
|
||||||
// Custom colors
|
|
||||||
#define COLOR_BEIGE "#CEB689"
|
|
||||||
#define COLOR_BLUE_GRAY "#6A97B0"
|
|
||||||
#define COLOR_BROWN "#B19664"
|
|
||||||
#define COLOR_DARK_BROWN "#917448"
|
|
||||||
#define COLOR_DARK_ORANGE "#B95A00"
|
|
||||||
#define COLOR_GREEN_GRAY "#8DAF6A"
|
|
||||||
#define COLOR_RED_GRAY "#AA5F61"
|
|
||||||
#define COLOR_PALE_BLUE_GRAY "#8BBBD5"
|
|
||||||
#define COLOR_PALE_GREEN_GRAY "#AED18B"
|
|
||||||
#define COLOR_PALE_RED_GRAY "#CC9090"
|
|
||||||
#define COLOR_PALE_PURPLE_GRAY "#BDA2BA"
|
|
||||||
#define COLOR_PURPLE_GRAY "#A2819E"
|
|
||||||
|
|
||||||
// Vending stuff
|
// Vending stuff
|
||||||
#define CAT_NORMAL 1
|
#define CAT_NORMAL 1
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#define GODMODE 0x1000
|
#define GODMODE 0x1000
|
||||||
#define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath.
|
#define FAKEDEATH 0x2000 // Replaces stuff like changeling.changeling_fakedeath.
|
||||||
#define DISFIGURED 0x4000 // Set but never checked. Remove this sometime and replace occurences with the appropriate organ code
|
#define DISFIGURED 0x4000 // Set but never checked. Remove this sometime and replace occurences with the appropriate organ code
|
||||||
#define XENO_HOST 0x8000 // Tracks whether we're gonna be a baby alien's mummy.
|
|
||||||
|
|
||||||
// Grab levels.
|
// Grab levels.
|
||||||
#define GRAB_PASSIVE 1
|
#define GRAB_PASSIVE 1
|
||||||
@@ -27,11 +26,11 @@
|
|||||||
#define BORGXRAY 0x4
|
#define BORGXRAY 0x4
|
||||||
#define BORGMATERIAL 8
|
#define BORGMATERIAL 8
|
||||||
|
|
||||||
#define HOSTILE_STANCE_IDLE 1
|
#define STANCE_IDLE 1
|
||||||
#define HOSTILE_STANCE_ALERT 2
|
#define STANCE_ALERT 2
|
||||||
#define HOSTILE_STANCE_ATTACK 3
|
#define STANCE_ATTACK 3
|
||||||
#define HOSTILE_STANCE_ATTACKING 4
|
#define STANCE_ATTACKING 4
|
||||||
#define HOSTILE_STANCE_TIRED 5
|
#define STANCE_TIRED 5
|
||||||
|
|
||||||
#define LEFT 1
|
#define LEFT 1
|
||||||
#define RIGHT 2
|
#define RIGHT 2
|
||||||
@@ -136,9 +135,15 @@
|
|||||||
#define INCAPACITATION_RESTRAINED 1
|
#define INCAPACITATION_RESTRAINED 1
|
||||||
#define INCAPACITATION_BUCKLED_PARTIALLY 2
|
#define INCAPACITATION_BUCKLED_PARTIALLY 2
|
||||||
#define INCAPACITATION_BUCKLED_FULLY 4
|
#define INCAPACITATION_BUCKLED_FULLY 4
|
||||||
|
#define INCAPACITATION_STUNNED 8
|
||||||
|
#define INCAPACITATION_FORCELYING 16 //needs a better name - represents being knocked down BUT still conscious.
|
||||||
|
#define INCAPACITATION_KNOCKOUT 32
|
||||||
|
|
||||||
|
|
||||||
#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY)
|
#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY)
|
||||||
#define INCAPACITATION_ALL (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY)
|
#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING)
|
||||||
|
#define INCAPACITATION_DISABLED (INCAPACITATION_KNOCKDOWN|INCAPACITATION_STUNNED)
|
||||||
|
#define INCAPACITATION_ALL (~INCAPACITATION_NONE)
|
||||||
|
|
||||||
// Bodyparts and organs.
|
// Bodyparts and organs.
|
||||||
#define O_MOUTH "mouth"
|
#define O_MOUTH "mouth"
|
||||||
@@ -180,4 +185,9 @@
|
|||||||
#define MOB_PULL_NONE 0
|
#define MOB_PULL_NONE 0
|
||||||
#define MOB_PULL_SMALLER 1
|
#define MOB_PULL_SMALLER 1
|
||||||
#define MOB_PULL_SAME 2
|
#define MOB_PULL_SAME 2
|
||||||
#define MOB_PULL_LARGER 3
|
#define MOB_PULL_LARGER 3
|
||||||
|
|
||||||
|
//XENOBIO2 FLAGS
|
||||||
|
#define NOMUT 0
|
||||||
|
#define COLORMUT 1
|
||||||
|
#define SPECIESMUT 2
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
#define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds
|
#define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds
|
||||||
#define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds
|
#define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds
|
||||||
#define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks
|
#define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks
|
||||||
#define PROCESS_DEFAULT_SLEEP_INTERVAL 2 // 2 ticks
|
#define PROCESS_DEFAULT_SLEEP_INTERVAL 8 // 2 ticks
|
||||||
#define PROCESS_DEFAULT_CPU_THRESHOLD 90 // 90%
|
#define PROCESS_DEFAULT_CPU_THRESHOLD 90 // 90%
|
||||||
|
|
||||||
//#define UPDATE_QUEUE_DEBUG
|
// SCHECK macros
|
||||||
|
// This references src directly to work around a weird bug with try/catch
|
||||||
|
#define SCHECK_EVERY(this_many_calls) if(++src.calls_since_last_scheck >= this_many_calls) sleepCheck()
|
||||||
|
#define SCHECK SCHECK_EVERY(50)
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
#define TECH_ILLEGAL "syndicate"
|
#define TECH_ILLEGAL "syndicate"
|
||||||
#define TECH_ARCANE "arcane"
|
#define TECH_ARCANE "arcane"
|
||||||
|
|
||||||
#define IMPRINTER 0x1 //For circuits. Uses glass/chemicals.
|
#define IMPRINTER 0x0001 //For circuits. Uses glass/chemicals.
|
||||||
#define PROTOLATHE 0x2 //New stuff. Uses glass/metal/chemicals
|
#define PROTOLATHE 0x0002 //New stuff. Uses glass/metal/chemicals
|
||||||
#define MECHFAB 0x4 //Mechfab
|
#define MECHFAB 0x0004 //Mechfab
|
||||||
#define CHASSIS 0x8 //For protolathe, but differently
|
#define CHASSIS 0x0008 //For protolathe, but differently
|
||||||
|
#define PROSFAB 0x0010 //For prosthetics fab
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
// unused: 0x8000 - higher than this will overflow
|
// unused: 0x8000 - higher than this will overflow
|
||||||
|
|
||||||
// Species spawn flags
|
// Species spawn flags
|
||||||
#define IS_WHITELISTED 0x1 // Must be whitelisted to play.
|
#define SPECIES_IS_WHITELISTED 0x1 // Must be whitelisted to play.
|
||||||
#define CAN_JOIN 0x2 // Species is selectable in chargen.
|
#define SPECIES_IS_RESTRICTED 0x2 // Is not a core/normally playable species. (castes, mutantraces)
|
||||||
#define IS_RESTRICTED 0x4 // Is not a core/normally playable species. (castes, mutantraces)
|
#define SPECIES_CAN_JOIN 0x4 // Species is selectable in chargen.
|
||||||
|
|
||||||
// Species appearance flags
|
// Species appearance flags
|
||||||
#define HAS_SKIN_TONE 0x1 // Skin tone selectable in chargen. (0-255)
|
#define HAS_SKIN_TONE 0x1 // Skin tone selectable in chargen. (0-255)
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#define HAS_UNDERWEAR 0x8 // Underwear is drawn onto the mob icon.
|
#define HAS_UNDERWEAR 0x8 // Underwear is drawn onto the mob icon.
|
||||||
#define HAS_EYE_COLOR 0x10 // Eye colour selectable in chargen. (RGB)
|
#define HAS_EYE_COLOR 0x10 // Eye colour selectable in chargen. (RGB)
|
||||||
#define HAS_HAIR_COLOR 0x20 // Hair colour selectable in chargen. (RGB)
|
#define HAS_HAIR_COLOR 0x20 // Hair colour selectable in chargen. (RGB)
|
||||||
|
#define RADIATION_GLOWS 0x40 // Radiation causes this character to glow.
|
||||||
|
|
||||||
// Languages.
|
// Languages.
|
||||||
#define LANGUAGE_SOL_COMMON "Sol Common"
|
#define LANGUAGE_SOL_COMMON "Sol Common"
|
||||||
@@ -29,6 +30,8 @@
|
|||||||
#define LANGUAGE_ROOTSPEAK "Rootspeak"
|
#define LANGUAGE_ROOTSPEAK "Rootspeak"
|
||||||
#define LANGUAGE_TRADEBAND "Tradeband"
|
#define LANGUAGE_TRADEBAND "Tradeband"
|
||||||
#define LANGUAGE_GUTTER "Gutter"
|
#define LANGUAGE_GUTTER "Gutter"
|
||||||
|
#define LANGUAGE_SCHECHI "Schechi"
|
||||||
|
#define LANGUAGE_CULT "Cult"
|
||||||
|
|
||||||
// Language flags.
|
// Language flags.
|
||||||
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
|
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
|
||||||
|
|||||||
4
code/__defines/unit_tests.dm
Normal file
4
code/__defines/unit_tests.dm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#define ASCII_ESC ascii2text(27)
|
||||||
|
#define ASCII_RED "[ASCII_ESC]\[31m"
|
||||||
|
#define ASCII_GREEN "[ASCII_ESC]\[32m"
|
||||||
|
#define ASCII_RESET "[ASCII_ESC]\[0m"
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if DM_VERSION < 510
|
||||||
|
|
||||||
json_token
|
json_token
|
||||||
var
|
var
|
||||||
value
|
value
|
||||||
@@ -202,4 +204,6 @@ json_reader
|
|||||||
|
|
||||||
die(json_token/T)
|
die(json_token/T)
|
||||||
if(!T) T = get_token()
|
if(!T) T = get_token()
|
||||||
CRASH("Unexpected token: [T.value].")
|
CRASH("Unexpected token: [T.value].")
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if DM_VERSION < 510
|
||||||
|
|
||||||
json_writer
|
json_writer
|
||||||
var
|
var
|
||||||
use_cache = 0
|
use_cache = 0
|
||||||
@@ -48,7 +50,7 @@ json_writer
|
|||||||
var/lrep = length(json_escape[targ])
|
var/lrep = length(json_escape[targ])
|
||||||
txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ))
|
txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ))
|
||||||
start = i + lrep
|
start = i + lrep
|
||||||
|
|
||||||
return {""[txt]""}
|
return {""[txt]""}
|
||||||
|
|
||||||
is_associative(list/L)
|
is_associative(list/L)
|
||||||
@@ -56,3 +58,5 @@ json_writer
|
|||||||
// if the key is a list that means it's actually an array of lists (stupid Byond...)
|
// if the key is a list that means it's actually an array of lists (stupid Byond...)
|
||||||
if(!isnum(key) && !isnull(L[key]) && !istype(key, /list))
|
if(!isnum(key) && !isnull(L[key]) && !istype(key, /list))
|
||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
|
#if DM_VERSION < 510
|
||||||
/*
|
/*
|
||||||
n_Json v11.3.21
|
n_Json v11.3.21
|
||||||
*/
|
*/
|
||||||
|
|
||||||
proc
|
proc
|
||||||
json2list(json)
|
json_decode(json)
|
||||||
var/static/json_reader/_jsonr = new()
|
var/static/json_reader/_jsonr = new()
|
||||||
return _jsonr.ReadObject(_jsonr.ScanJson(json))
|
return _jsonr.ReadObject(_jsonr.ScanJson(json))
|
||||||
|
|
||||||
list2json(list/L)
|
json_encode(list/L)
|
||||||
var/static/json_writer/_jsonw = new()
|
var/static/json_writer/_jsonw = new()
|
||||||
return _jsonw.write(L)
|
return _jsonw.write(L)
|
||||||
|
#endif
|
||||||
list2json_usecache(list/L)
|
|
||||||
var/static/json_writer/_jsonw = new()
|
|
||||||
_jsonw.use_cache = 1
|
|
||||||
return _jsonw.write(L)
|
|
||||||
6
code/_compatibility/509/text.dm
Normal file
6
code/_compatibility/509/text.dm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#if DM_VERSION < 510
|
||||||
|
|
||||||
|
/proc/replacetext(text, find, replacement)
|
||||||
|
return jointext(splittext(text, find), replacement)
|
||||||
|
|
||||||
|
#endif
|
||||||
102
code/_compatibility/509/type2type.dm
Normal file
102
code/_compatibility/509/type2type.dm
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#if DM_VERSION < 510
|
||||||
|
// Concatenates a list of strings into a single string. A seperator may optionally be provided.
|
||||||
|
/proc/jointext(list/ls, sep)
|
||||||
|
if (ls.len <= 1) // Early-out code for empty or singleton lists.
|
||||||
|
return ls.len ? ls[1] : ""
|
||||||
|
|
||||||
|
var/l = ls.len // Made local for sanic speed.
|
||||||
|
var/i = 0 // Incremented every time a list index is accessed.
|
||||||
|
|
||||||
|
if (sep <> null)
|
||||||
|
// Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc...
|
||||||
|
#define S1 sep, ls[++i]
|
||||||
|
#define S4 S1, S1, S1, S1
|
||||||
|
#define S16 S4, S4, S4, S4
|
||||||
|
#define S64 S16, S16, S16, S16
|
||||||
|
|
||||||
|
. = "[ls[++i]]" // Make sure the initial element is converted to text.
|
||||||
|
|
||||||
|
// Having the small concatenations come before the large ones boosted speed by an average of at least 5%.
|
||||||
|
if (l-1 & 0x01) // 'i' will always be 1 here.
|
||||||
|
. = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2.
|
||||||
|
if (l-i & 0x02)
|
||||||
|
. = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
|
||||||
|
if (l-i & 0x04)
|
||||||
|
. = text("[][][][][][][][][]", ., S4) // And so on....
|
||||||
|
if (l-i & 0x08)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][]", ., S4, S4)
|
||||||
|
if (l-i & 0x10)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16)
|
||||||
|
if (l-i & 0x20)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
|
||||||
|
if (l-i & 0x40)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
|
||||||
|
while (l > i) // Chomp through the rest of the list, 128 elements at a time.
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
|
||||||
|
|
||||||
|
#undef S64
|
||||||
|
#undef S16
|
||||||
|
#undef S4
|
||||||
|
#undef S1
|
||||||
|
else
|
||||||
|
// Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc...
|
||||||
|
#define S1 ls[++i]
|
||||||
|
#define S4 S1, S1, S1, S1
|
||||||
|
#define S16 S4, S4, S4, S4
|
||||||
|
#define S64 S16, S16, S16, S16
|
||||||
|
|
||||||
|
. = "[ls[++i]]" // Make sure the initial element is converted to text.
|
||||||
|
|
||||||
|
if (l-1 & 0x01) // 'i' will always be 1 here.
|
||||||
|
. += S1 // Append 1 element if the remaining elements are not a multiple of 2.
|
||||||
|
if (l-i & 0x02)
|
||||||
|
. = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
|
||||||
|
if (l-i & 0x04)
|
||||||
|
. = text("[][][][][]", ., S4) // And so on...
|
||||||
|
if (l-i & 0x08)
|
||||||
|
. = text("[][][][][][][][][]", ., S4, S4)
|
||||||
|
if (l-i & 0x10)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][]", ., S16)
|
||||||
|
if (l-i & 0x20)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
|
||||||
|
if (l-i & 0x40)
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
|
||||||
|
while (l > i) // Chomp through the rest of the list, 128 elements at a time.
|
||||||
|
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
||||||
|
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
|
||||||
|
|
||||||
|
#undef S64
|
||||||
|
#undef S16
|
||||||
|
#undef S4
|
||||||
|
#undef S1
|
||||||
|
|
||||||
|
// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator)
|
||||||
|
/proc/splittext(text, delimiter="\n")
|
||||||
|
var/delim_len = length(delimiter)
|
||||||
|
if (delim_len < 1)
|
||||||
|
return list(text)
|
||||||
|
|
||||||
|
. = list()
|
||||||
|
var/last_found = 1
|
||||||
|
var/found
|
||||||
|
|
||||||
|
do
|
||||||
|
found = findtext(text, delimiter, last_found, 0)
|
||||||
|
. += copytext(text, last_found, found)
|
||||||
|
last_found = found + delim_len
|
||||||
|
while (found)
|
||||||
|
#endif
|
||||||
1
code/_helpers/_global_objects.dm
Normal file
1
code/_helpers/_global_objects.dm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
var/datum/gear_tweak/color/gear_tweak_free_color_choice = new()
|
||||||
@@ -74,7 +74,6 @@ var/global/list/GlobalPool = list()
|
|||||||
|
|
||||||
D.Destroy()
|
D.Destroy()
|
||||||
D.ResetVars()
|
D.ResetVars()
|
||||||
D.disposed = 1 //Set to stop processing while pooled
|
|
||||||
|
|
||||||
/proc/IsPooled(var/datum/D)
|
/proc/IsPooled(var/datum/D)
|
||||||
if(isnull(GlobalPool[D.type]))
|
if(isnull(GlobalPool[D.type]))
|
||||||
@@ -86,7 +85,6 @@ var/global/list/GlobalPool = list()
|
|||||||
New(arglist(args))
|
New(arglist(args))
|
||||||
else
|
else
|
||||||
New(args)
|
New(args)
|
||||||
disposed = null
|
|
||||||
|
|
||||||
/atom/movable/Prepare(args)
|
/atom/movable/Prepare(args)
|
||||||
var/list/args_list = args
|
var/list/args_list = args
|
||||||
|
|||||||
@@ -244,10 +244,50 @@
|
|||||||
var/turf/ear = get_turf(M)
|
var/turf/ear = get_turf(M)
|
||||||
if(ear)
|
if(ear)
|
||||||
// Ghostship is magic: Ghosts can hear radio chatter from anywhere
|
// Ghostship is magic: Ghosts can hear radio chatter from anywhere
|
||||||
if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO)))
|
if(speaker_coverage[ear] || (istype(M, /mob/observer/dead) && M.is_preference_enabled(/datum/client_preference/ghost_radio)))
|
||||||
. |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
|
. |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
|
||||||
return .
|
return .
|
||||||
|
|
||||||
|
//Uses dview to quickly return mobs and objects in view,
|
||||||
|
// then adds additional mobs or objects if they are in range 'smartly',
|
||||||
|
// based on their presence in lists of players or registered objects
|
||||||
|
// Type: 1-audio, 2-visual, 0-neither
|
||||||
|
/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/type = 1)
|
||||||
|
var/list/mobs = list()
|
||||||
|
var/list/objs = list()
|
||||||
|
|
||||||
|
var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM)
|
||||||
|
var/list/hearturfs = list()
|
||||||
|
|
||||||
|
for(var/atom/movable/AM in hear)
|
||||||
|
if(ismob(AM))
|
||||||
|
mobs += AM
|
||||||
|
hearturfs += AM.locs[1]
|
||||||
|
else if(isobj(AM))
|
||||||
|
objs += AM
|
||||||
|
hearturfs += AM.locs[1]
|
||||||
|
|
||||||
|
//A list of every mob with a client
|
||||||
|
for(var/mob/M in player_list)
|
||||||
|
if(M.loc && M.locs[1] in hearturfs)
|
||||||
|
mobs |= M
|
||||||
|
|
||||||
|
else if(M.stat == DEAD)
|
||||||
|
switch(type)
|
||||||
|
if(1) //Audio messages use ghost_ears
|
||||||
|
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
|
||||||
|
mobs |= M
|
||||||
|
if(2) //Visual messages use ghost_sight
|
||||||
|
if(M.is_preference_enabled(/datum/client_preference/ghost_sight))
|
||||||
|
mobs |= M
|
||||||
|
|
||||||
|
//For objects below the top level who still want to hear
|
||||||
|
for(var/obj/O in listening_objects)
|
||||||
|
if(O.loc && O.locs[1] in hearturfs)
|
||||||
|
objs |= O
|
||||||
|
|
||||||
|
return list("mobs" = mobs, "objs" = objs)
|
||||||
|
|
||||||
#define SIGN(X) ((X<0)?-1:1)
|
#define SIGN(X) ((X<0)?-1:1)
|
||||||
|
|
||||||
proc
|
proc
|
||||||
@@ -323,7 +363,7 @@ proc/isInSight(var/atom/A, var/atom/B)
|
|||||||
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
||||||
var/i = 0
|
var/i = 0
|
||||||
while(candidates.len <= 0 && i < 5)
|
while(candidates.len <= 0 && i < 5)
|
||||||
for(var/mob/dead/observer/G in player_list)
|
for(var/mob/observer/dead/G in player_list)
|
||||||
if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
|
if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
|
||||||
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
||||||
candidates += G.key
|
candidates += G.key
|
||||||
@@ -337,7 +377,7 @@ proc/isInSight(var/atom/A, var/atom/B)
|
|||||||
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
||||||
var/i = 0
|
var/i = 0
|
||||||
while(candidates.len <= 0 && i < 5)
|
while(candidates.len <= 0 && i < 5)
|
||||||
for(var/mob/dead/observer/G in player_list)
|
for(var/mob/observer/dead/G in player_list)
|
||||||
if(G.client.prefs.be_special & BE_ALIEN)
|
if(G.client.prefs.be_special & BE_ALIEN)
|
||||||
if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) // the most active players are more likely to become an alien
|
if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) // the most active players are more likely to become an alien
|
||||||
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ var/global/list/human_mob_list = list() //List of all human mobs and sub-type
|
|||||||
var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
|
var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
|
||||||
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
|
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
|
||||||
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
|
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
|
||||||
|
var/global/list/listening_objects = list() //List of all objects which care about receiving messages (communicators, radios, etc)
|
||||||
|
|
||||||
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
|
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
|
||||||
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
|
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
|
||||||
@@ -23,6 +24,9 @@ var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
|
|||||||
|
|
||||||
var/global/list/turfs = list() //list of all turfs
|
var/global/list/turfs = list() //list of all turfs
|
||||||
|
|
||||||
|
#define all_genders_define_list list(MALE,FEMALE,PLURAL,NEUTER)
|
||||||
|
#define all_genders_text_list list("Male","Female","Plural","Neuter")
|
||||||
|
|
||||||
//Languages/species/whitelist.
|
//Languages/species/whitelist.
|
||||||
var/global/list/all_species[0]
|
var/global/list/all_species[0]
|
||||||
var/global/list/all_languages[0]
|
var/global/list/all_languages[0]
|
||||||
@@ -30,6 +34,8 @@ var/global/list/language_keys[0] // Table of say codes for all languages
|
|||||||
var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check.
|
var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check.
|
||||||
var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise.
|
var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise.
|
||||||
|
|
||||||
|
var/list/mannequins_
|
||||||
|
|
||||||
// Posters
|
// Posters
|
||||||
var/global/list/poster_designs = list()
|
var/global/list/poster_designs = list()
|
||||||
|
|
||||||
@@ -46,39 +52,7 @@ var/global/list/facial_hair_styles_male_list = list()
|
|||||||
var/global/list/facial_hair_styles_female_list = list()
|
var/global/list/facial_hair_styles_female_list = list()
|
||||||
var/global/list/skin_styles_female_list = list() //unused
|
var/global/list/skin_styles_female_list = list() //unused
|
||||||
//Underwear
|
//Underwear
|
||||||
var/global/list/underwear_top_t = list(
|
var/datum/category_collection/underwear/global_underwear = new()
|
||||||
"Bra, Red" = "t1", "Bra, White" = "t2", "Bra, Yellow" = "t3", "Bra, Blue" = "t4", "Bra, Black" = "t5", "Lacy Bra" = "t6", "Sports Bra, Black" = "t7", "Sports Bra, White" = "t8",
|
|
||||||
"Sports Bra Alt, Black" = "t9", "Sporta Bra Alt, White" = "t10", "Bra, Baby-Blue" = "t11", "Bra, Green" = "t12", "Bra, Pink" = "t13", "Bra, Violet" = "t14",
|
|
||||||
"Lacy Bra Alt" = "t15", "Lacy Bra Alt, Violet" = "t16", "Halterneck Bra, Black" = "t17", "Halterneck Bra, Blue" = "t18", "Halterneck Bra, Green" = "t19", "Halterneck Bra, Purple" = "t20",
|
|
||||||
"Halterneck Bra, Red" = "t21", "Halterneck Bra, Teal" = "t22", "Halterneck Bra, Violet" = "t23", "Halterneck Bra, White" = "t24", "None")
|
|
||||||
var/global/list/underwear_bottom_t = list(
|
|
||||||
"Briefs, White" = "b1", "Briefs, Grey" = "b2", "Briefs, Green" = "b3", "Briefs, Blue" = "b4", "Briefs, Black" = "b5", "Boxers, Loveheart" = "b7", "Boxers, Black" = "b8",
|
|
||||||
"Boxers, Grey" = "b9", "Boxers, Green & Blue Striped" = "b10", "Panties, Red" = "b11", "Panties, White" = "b12", "Panties, Yellow" = "b13", "Panties, Blue" = "b14",
|
|
||||||
"Panties, Light-Black" = "b15", "Thong" = "b16", "Panties, Black" = "b17", "Panties Alt, White" = "b18", "Compression Shorts, Black" = "b19", "Compression Shorts, White" = "b20",
|
|
||||||
"Compression Shorts, Baby-Blue" = "b21", "Panties, Green" = "b22", "Compression Shorts, Pink" = "b23", "Thong, Violet" = "b24", "Thong Alt" = "b25", "Thong Alt, Violet" = "b26",
|
|
||||||
"Alt Thong, Black" = "b27", "Alt Thong, Blue" = "b28", "Alt Thong, Green" = "b29", "Alt Thong, Purple" = "b30", "Alt Thong, Red" = "b31", "Alt Thong, Teal" = "b32",
|
|
||||||
"Alt Thong, Violet" = "b33", "Alt Thong, White" = "b34", "None")
|
|
||||||
//undershirt
|
|
||||||
var/global/list/undershirt_t = list(
|
|
||||||
"White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3",
|
|
||||||
"White shirt" = "u4", "White shirt 2" = "shirt_white_s", "White tank top 2" = "tank_white_s",
|
|
||||||
"Black shirt 2" = "shirt_black_s", "Grey shirt" = "shirt_grey_s", "Heart shirt" = "lover_s",
|
|
||||||
"I love NT shirt" = "ilovent_s", "White shortsleeve shirt" = "whiteshortsleeve_s", "Purple shortsleeve shirt" = "purpleshortsleeve_s",
|
|
||||||
"Blue shortsleeve shirt" = "blueshortsleeve_s", "Green shortsleeve shirt" = "greenshortsleeve_s", "Black shortsleeve shirt" = "blackshortsleeve_s",
|
|
||||||
"Blue shirt" = "blueshirt_s", "Red shirt" = "redshirt_s", "Yellow shirt" = "yellowshirt_s", "Green shirt" = "greenshirt_s",
|
|
||||||
"Blue polo shirt" = "bluepolo_s", "Red polo shirt" = "redpolo_s", "White polo shirt" = "whitepolo_s",
|
|
||||||
"Grey-yellow polo shirt" = "grayyellowpolo_s", "Fire tank top" = "tank_fire_s", "NT shirt" = "shirt_nano_s",
|
|
||||||
"Blue shirt 2" = "shirt_blue_s", "Red shirt 2" = "shirt_red_s", "Red tank top" = "tank_red_s", "Green shirt 2" = "shirt_green_s",
|
|
||||||
"Tiedye shirt" = "shirt_tiedye_s", "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s",
|
|
||||||
"Blue striped shirt" = "shirt_stripes_s", "Blue sport shirt" = "blueshirtsport_s", "None")
|
|
||||||
//Socks
|
|
||||||
var/global/list/socks_t = list(
|
|
||||||
"White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
|
|
||||||
"White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short",
|
|
||||||
"Black knee" = "black_knee", "Black thigh" = "black_thigh", "Thin knee" = "thin_knee",
|
|
||||||
"Thin thigh" = "thin_thigh", "Pantyhose" = "pantyhose", "Striped thigh" = "striped_thigh",
|
|
||||||
"Striped knee" = "striped_knee", "Rainbow knee" = "rainbow_knee", "Rainbow thigh" = "rainbow_thigh",
|
|
||||||
"Fishnets" = "fishnet", "Thin white thigh" = "thinwhite_thigh", "Thin white knee" = "thinwhite_knee", "None")
|
|
||||||
|
|
||||||
//Backpacks
|
//Backpacks
|
||||||
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")
|
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")
|
||||||
@@ -128,6 +102,14 @@ var/global/list/string_slot_flags = list(
|
|||||||
"holster" = SLOT_HOLSTER
|
"holster" = SLOT_HOLSTER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/proc/get_mannequin(var/ckey)
|
||||||
|
if(!mannequins_)
|
||||||
|
mannequins_ = new()
|
||||||
|
. = mannequins_[ckey]
|
||||||
|
if(!.)
|
||||||
|
. = new/mob/living/carbon/human/dummy/mannequin()
|
||||||
|
mannequins_[ckey] = .
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
/////Initial Building/////
|
/////Initial Building/////
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
@@ -185,16 +167,22 @@ var/global/list/string_slot_flags = list(
|
|||||||
language_keys[lowertext(L.key)] = L
|
language_keys[lowertext(L.key)] = L
|
||||||
|
|
||||||
var/rkey = 0
|
var/rkey = 0
|
||||||
paths = typesof(/datum/species)-/datum/species
|
paths = typesof(/datum/species)
|
||||||
for(var/T in paths)
|
for(var/T in paths)
|
||||||
|
|
||||||
rkey++
|
rkey++
|
||||||
var/datum/species/S = new T
|
|
||||||
|
var/datum/species/S = T
|
||||||
|
if(!initial(S.name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
S = new T
|
||||||
S.race_key = rkey //Used in mob icon caching.
|
S.race_key = rkey //Used in mob icon caching.
|
||||||
all_species[S.name] = S
|
all_species[S.name] = S
|
||||||
|
|
||||||
if(!(S.spawn_flags & IS_RESTRICTED))
|
if(!(S.spawn_flags & SPECIES_IS_RESTRICTED))
|
||||||
playable_species += S.name
|
playable_species += S.name
|
||||||
if(S.spawn_flags & IS_WHITELISTED)
|
if(S.spawn_flags & SPECIES_IS_WHITELISTED)
|
||||||
whitelisted_species += S.name
|
whitelisted_species += S.name
|
||||||
|
|
||||||
//Posters
|
//Posters
|
||||||
@@ -216,3 +204,5 @@ var/global/list/string_slot_flags = list(
|
|||||||
. += " has: [t]\n"
|
. += " has: [t]\n"
|
||||||
world << .
|
world << .
|
||||||
*/
|
*/
|
||||||
|
//Hexidecimal numbers
|
||||||
|
var/global/list/hexNums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
|
||||||
|
|||||||
@@ -30,13 +30,6 @@
|
|||||||
|
|
||||||
return "[output][and_text][input[index]]"
|
return "[output][and_text][input[index]]"
|
||||||
|
|
||||||
|
|
||||||
/proc/ConvertReqString2List(var/list/source_list)
|
|
||||||
var/list/temp_list = params2list(source_list)
|
|
||||||
for(var/O in temp_list)
|
|
||||||
temp_list[O] = text2num(temp_list[O])
|
|
||||||
return temp_list
|
|
||||||
|
|
||||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||||
proc/listgetindex(var/list/list,index)
|
proc/listgetindex(var/list/list,index)
|
||||||
if(istype(list) && list.len)
|
if(istype(list) && list.len)
|
||||||
@@ -48,9 +41,7 @@ proc/listgetindex(var/list/list,index)
|
|||||||
return
|
return
|
||||||
|
|
||||||
proc/islist(list/list)
|
proc/islist(list/list)
|
||||||
if(istype(list))
|
return(istype(list))
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Return either pick(list) or null if list is not of type /list or is empty
|
//Return either pick(list) or null if list is not of type /list or is empty
|
||||||
proc/safepick(list/list)
|
proc/safepick(list/list)
|
||||||
@@ -611,13 +602,13 @@ proc/dd_sortedTextList(list/incoming)
|
|||||||
/datum/alarm/dd_SortValue()
|
/datum/alarm/dd_SortValue()
|
||||||
return "[sanitize_old(last_name)]"
|
return "[sanitize_old(last_name)]"
|
||||||
|
|
||||||
/proc/subtypes(prototype)
|
/proc/subtypesof(prototype)
|
||||||
return (typesof(prototype) - prototype)
|
return (typesof(prototype) - prototype)
|
||||||
|
|
||||||
//creates every subtype of prototype (excluding prototype) and adds it to list L.
|
//creates every subtype of prototype (excluding prototype) and adds it to list L.
|
||||||
//if no list/L is provided, one is created.
|
//if no list/L is provided, one is created.
|
||||||
/proc/init_subtypes(prototype, list/L)
|
/proc/init_subtypes(prototype, list/L)
|
||||||
if(!istype(L)) L = list()
|
if(!istype(L)) L = list()
|
||||||
for(var/path in subtypes(prototype))
|
for(var/path in subtypesof(prototype))
|
||||||
L += new path()
|
L += new path()
|
||||||
return L
|
return L
|
||||||
|
|||||||
@@ -25,16 +25,14 @@
|
|||||||
if (config.log_admin)
|
if (config.log_admin)
|
||||||
diary << "\[[time_stamp()]]ADMIN: [text][log_end]"
|
diary << "\[[time_stamp()]]ADMIN: [text][log_end]"
|
||||||
|
|
||||||
|
|
||||||
/proc/log_debug(text)
|
/proc/log_debug(text)
|
||||||
if (config.log_debug)
|
if (config.log_debug)
|
||||||
diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
|
diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
|
||||||
|
|
||||||
for(var/client/C in admins)
|
for(var/client/C in admins)
|
||||||
if(C.prefs.toggles & CHAT_DEBUGLOGS)
|
if(C.is_preference_enabled(/datum/client_preference/debug/show_debug_logs))
|
||||||
C << "DEBUG: [text]"
|
C << "DEBUG: [text]"
|
||||||
|
|
||||||
|
|
||||||
/proc/log_game(text)
|
/proc/log_game(text)
|
||||||
if (config.log_game)
|
if (config.log_game)
|
||||||
diary << "\[[time_stamp()]]GAME: [text][log_end]"
|
diary << "\[[time_stamp()]]GAME: [text][log_end]"
|
||||||
@@ -79,9 +77,17 @@
|
|||||||
if (config.log_pda)
|
if (config.log_pda)
|
||||||
diary << "\[[time_stamp()]]PDA: [text][log_end]"
|
diary << "\[[time_stamp()]]PDA: [text][log_end]"
|
||||||
|
|
||||||
|
/proc/log_to_dd(text)
|
||||||
|
world.log << text //this comes before the config check because it can't possibly runtime
|
||||||
|
if(config.log_world_output)
|
||||||
|
diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]"
|
||||||
|
|
||||||
/proc/log_misc(text)
|
/proc/log_misc(text)
|
||||||
diary << "\[[time_stamp()]]MISC: [text][log_end]"
|
diary << "\[[time_stamp()]]MISC: [text][log_end]"
|
||||||
|
|
||||||
|
/proc/log_unit_test(text)
|
||||||
|
world.log << "## UNIT_TEST: [text]"
|
||||||
|
|
||||||
//pretty print a direction bitflag, can be useful for debugging.
|
//pretty print a direction bitflag, can be useful for debugging.
|
||||||
/proc/print_dir(var/dir)
|
/proc/print_dir(var/dir)
|
||||||
var/list/comps = list()
|
var/list/comps = list()
|
||||||
@@ -91,7 +97,7 @@
|
|||||||
if(dir & WEST) comps += "WEST"
|
if(dir & WEST) comps += "WEST"
|
||||||
if(dir & UP) comps += "UP"
|
if(dir & UP) comps += "UP"
|
||||||
if(dir & DOWN) comps += "DOWN"
|
if(dir & DOWN) comps += "DOWN"
|
||||||
|
|
||||||
return english_list(comps, nothing_text="0", and_text="|", comma_text="|")
|
return english_list(comps, nothing_text="0", and_text="|", comma_text="|")
|
||||||
|
|
||||||
//more or less a logging utility
|
//more or less a logging utility
|
||||||
|
|||||||
@@ -30,13 +30,10 @@ proc/random_hair_style(gender, species = "Human")
|
|||||||
var/list/valid_hairstyles = list()
|
var/list/valid_hairstyles = list()
|
||||||
for(var/hairstyle in hair_styles_list)
|
for(var/hairstyle in hair_styles_list)
|
||||||
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
|
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
|
||||||
|
if(gender == MALE && S.gender == FEMALE)
|
||||||
if(gender != NEUTER && gender != PLURAL)
|
continue
|
||||||
if(gender == MALE && S.gender == FEMALE)
|
if(gender == FEMALE && S.gender == MALE)
|
||||||
continue
|
continue
|
||||||
if(gender == FEMALE && S.gender == MALE)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if( !(species in S.species_allowed))
|
if( !(species in S.species_allowed))
|
||||||
continue
|
continue
|
||||||
valid_hairstyles[hairstyle] = hair_styles_list[hairstyle]
|
valid_hairstyles[hairstyle] = hair_styles_list[hairstyle]
|
||||||
@@ -52,13 +49,10 @@ proc/random_facial_hair_style(gender, species = "Human")
|
|||||||
var/list/valid_facialhairstyles = list()
|
var/list/valid_facialhairstyles = list()
|
||||||
for(var/facialhairstyle in facial_hair_styles_list)
|
for(var/facialhairstyle in facial_hair_styles_list)
|
||||||
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
|
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
|
||||||
|
if(gender == MALE && S.gender == FEMALE)
|
||||||
if(gender != NEUTER && gender != PLURAL)
|
continue
|
||||||
if(gender == MALE && S.gender == FEMALE)
|
if(gender == FEMALE && S.gender == MALE)
|
||||||
continue
|
continue
|
||||||
if(gender == FEMALE && S.gender == MALE)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if( !(species in S.species_allowed))
|
if( !(species in S.species_allowed))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -171,3 +165,88 @@ Proc for attack log creation, because really why not
|
|||||||
return 0
|
return 0
|
||||||
var/mob/living/silicon/robot/R = thing.loc
|
var/mob/living/silicon/robot/R = thing.loc
|
||||||
return (thing in R.module.modules)
|
return (thing in R.module.modules)
|
||||||
|
|
||||||
|
/proc/get_exposed_defense_zone(var/atom/movable/target)
|
||||||
|
var/obj/item/weapon/grab/G = locate() in target
|
||||||
|
if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
|
||||||
|
return pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
|
||||||
|
else
|
||||||
|
return pick("chest", "groin")
|
||||||
|
|
||||||
|
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1)
|
||||||
|
if(!user || !target)
|
||||||
|
return 0
|
||||||
|
var/user_loc = user.loc
|
||||||
|
var/target_loc = target.loc
|
||||||
|
|
||||||
|
var/holding = user.get_active_hand()
|
||||||
|
var/datum/progressbar/progbar
|
||||||
|
if (progress)
|
||||||
|
progbar = new(user, time, target)
|
||||||
|
|
||||||
|
var/endtime = world.time+time
|
||||||
|
var/starttime = world.time
|
||||||
|
. = 1
|
||||||
|
while (world.time < endtime)
|
||||||
|
sleep(1)
|
||||||
|
if (progress)
|
||||||
|
progbar.update(world.time - starttime)
|
||||||
|
if(!user || !target)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
if(uninterruptible)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if(!user || user.incapacitated() || user.loc != user_loc)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if(target.loc != target_loc)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if(user.get_active_hand() != holding)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if (progbar)
|
||||||
|
qdel(progbar)
|
||||||
|
|
||||||
|
/proc/do_after(mob/user, delay, atom/target = null, needhand = 1, progress = 1, var/incapacitation_flags = INCAPACITATION_DEFAULT)
|
||||||
|
if(!user)
|
||||||
|
return 0
|
||||||
|
var/atom/target_loc = null
|
||||||
|
if(target)
|
||||||
|
target_loc = target.loc
|
||||||
|
|
||||||
|
var/atom/original_loc = user.loc
|
||||||
|
|
||||||
|
var/holding = user.get_active_hand()
|
||||||
|
|
||||||
|
var/datum/progressbar/progbar
|
||||||
|
if (progress)
|
||||||
|
progbar = new(user, delay, target)
|
||||||
|
|
||||||
|
var/endtime = world.time + delay
|
||||||
|
var/starttime = world.time
|
||||||
|
. = 1
|
||||||
|
while (world.time < endtime)
|
||||||
|
sleep(1)
|
||||||
|
if (progress)
|
||||||
|
progbar.update(world.time - starttime)
|
||||||
|
|
||||||
|
if(!user || user.incapacitated(incapacitation_flags) || user.loc != original_loc)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if(target_loc && (!target || target_loc != target.loc))
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if(needhand)
|
||||||
|
if(user.get_active_hand() != holding)
|
||||||
|
. = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if (progbar)
|
||||||
|
qdel(progbar)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ var/religion_name = null
|
|||||||
return capitalize(name)
|
return capitalize(name)
|
||||||
|
|
||||||
/proc/system_name()
|
/proc/system_name()
|
||||||
return "Vir"
|
return starsys_name
|
||||||
|
|
||||||
/proc/station_name()
|
/proc/station_name()
|
||||||
if (station_name)
|
if (station_name)
|
||||||
@@ -161,7 +161,7 @@ var/syndicate_code_response//Code response for traitors.
|
|||||||
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
|
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
|
||||||
Can probably be done through "{ }" but I don't really see the practical benefit.
|
Can probably be done through "{ }" but I don't really see the practical benefit.
|
||||||
One example of an earlier system is commented below.
|
One example of an earlier system is commented below.
|
||||||
/N
|
-N
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm
|
/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm
|
||||||
|
|||||||
@@ -175,13 +175,6 @@
|
|||||||
/*
|
/*
|
||||||
* Text modification
|
* Text modification
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/proc/replacetext(text, find, replacement)
|
|
||||||
return list2text(text2list(text, find), replacement)
|
|
||||||
|
|
||||||
/proc/replacetextEx(text, find, replacement)
|
|
||||||
return list2text(text2listEx(text, find), replacement)
|
|
||||||
|
|
||||||
/proc/replace_characters(var/t,var/list/repl_chars)
|
/proc/replace_characters(var/t,var/list/repl_chars)
|
||||||
for(var/char in repl_chars)
|
for(var/char in repl_chars)
|
||||||
t = replacetext(t, char, repl_chars[char])
|
t = replacetext(t, char, repl_chars[char])
|
||||||
@@ -311,7 +304,7 @@ proc/TextPreview(var/string,var/len=40)
|
|||||||
// to always create it and then throw it out.
|
// to always create it and then throw it out.
|
||||||
/var/icon/text_tag_icons = new('./icons/chattags.dmi')
|
/var/icon/text_tag_icons = new('./icons/chattags.dmi')
|
||||||
/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.prefs.toggles & CHAT_NOICONS))
|
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]'" : "") + ">"
|
return "<IMG src='\ref[text_tag_icons.icon]' class='text_tag' iconstate='[tagname]'" + (tagdesc ? " alt='[tagdesc]'" : "") + ">"
|
||||||
|
|
||||||
@@ -330,3 +323,12 @@ proc/TextPreview(var/string,var/len=40)
|
|||||||
if(48 to 57) //Numbers
|
if(48 to 57) //Numbers
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip out the special beyond characters for \proper and \improper
|
||||||
|
* from text that will be sent to the browser.
|
||||||
|
*/
|
||||||
|
/proc/strip_improper(var/text)
|
||||||
|
return replacetext(replacetext(text, "\proper", ""), "\improper", "")
|
||||||
|
|
||||||
|
#define gender2text(gender) capitalize(gender)
|
||||||
@@ -30,11 +30,21 @@ proc/isDay(var/month, var/day)
|
|||||||
|
|
||||||
var/next_duration_update = 0
|
var/next_duration_update = 0
|
||||||
var/last_round_duration = 0
|
var/last_round_duration = 0
|
||||||
proc/round_duration()
|
var/round_start_time = 0
|
||||||
|
|
||||||
|
/hook/roundstart/proc/start_timer()
|
||||||
|
round_start_time = world.time
|
||||||
|
return 1
|
||||||
|
|
||||||
|
#define round_duration_in_ticks (round_start_time ? world.time - round_start_time : 0)
|
||||||
|
|
||||||
|
/proc/round_duration_as_text()
|
||||||
|
if(!round_start_time)
|
||||||
|
return "00:00"
|
||||||
if(last_round_duration && world.time < next_duration_update)
|
if(last_round_duration && world.time < next_duration_update)
|
||||||
return last_round_duration
|
return last_round_duration
|
||||||
|
|
||||||
var/mills = world.time // 1/10 of a second, not real milliseconds but whatever
|
var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever
|
||||||
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
|
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
|
||||||
var/mins = round((mills % 36000) / 600)
|
var/mins = round((mills % 36000) / 600)
|
||||||
var/hours = round(mills / 36000)
|
var/hours = round(mills / 36000)
|
||||||
|
|||||||
@@ -50,141 +50,15 @@
|
|||||||
while (left-- > 0)
|
while (left-- > 0)
|
||||||
. = "0[.]"
|
. = "0[.]"
|
||||||
|
|
||||||
// Concatenates a list of strings into a single string. A seperator may optionally be provided.
|
|
||||||
/proc/list2text(list/ls, sep)
|
|
||||||
if (ls.len <= 1) // Early-out code for empty or singleton lists.
|
|
||||||
return ls.len ? ls[1] : ""
|
|
||||||
|
|
||||||
var/l = ls.len // Made local for sanic speed.
|
|
||||||
var/i = 0 // Incremented every time a list index is accessed.
|
|
||||||
|
|
||||||
if (sep <> null)
|
|
||||||
// Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc...
|
|
||||||
#define S1 sep, ls[++i]
|
|
||||||
#define S4 S1, S1, S1, S1
|
|
||||||
#define S16 S4, S4, S4, S4
|
|
||||||
#define S64 S16, S16, S16, S16
|
|
||||||
|
|
||||||
. = "[ls[++i]]" // Make sure the initial element is converted to text.
|
|
||||||
|
|
||||||
// Having the small concatenations come before the large ones boosted speed by an average of at least 5%.
|
|
||||||
if (l-1 & 0x01) // 'i' will always be 1 here.
|
|
||||||
. = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2.
|
|
||||||
if (l-i & 0x02)
|
|
||||||
. = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
|
|
||||||
if (l-i & 0x04)
|
|
||||||
. = text("[][][][][][][][][]", ., S4) // And so on....
|
|
||||||
if (l-i & 0x08)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][]", ., S4, S4)
|
|
||||||
if (l-i & 0x10)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16)
|
|
||||||
if (l-i & 0x20)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
|
|
||||||
if (l-i & 0x40)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
|
|
||||||
while (l > i) // Chomp through the rest of the list, 128 elements at a time.
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
|
|
||||||
|
|
||||||
#undef S64
|
|
||||||
#undef S16
|
|
||||||
#undef S4
|
|
||||||
#undef S1
|
|
||||||
else
|
|
||||||
// Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc...
|
|
||||||
#define S1 ls[++i]
|
|
||||||
#define S4 S1, S1, S1, S1
|
|
||||||
#define S16 S4, S4, S4, S4
|
|
||||||
#define S64 S16, S16, S16, S16
|
|
||||||
|
|
||||||
. = "[ls[++i]]" // Make sure the initial element is converted to text.
|
|
||||||
|
|
||||||
if (l-1 & 0x01) // 'i' will always be 1 here.
|
|
||||||
. += S1 // Append 1 element if the remaining elements are not a multiple of 2.
|
|
||||||
if (l-i & 0x02)
|
|
||||||
. = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
|
|
||||||
if (l-i & 0x04)
|
|
||||||
. = text("[][][][][]", ., S4) // And so on...
|
|
||||||
if (l-i & 0x08)
|
|
||||||
. = text("[][][][][][][][][]", ., S4, S4)
|
|
||||||
if (l-i & 0x10)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][]", ., S16)
|
|
||||||
if (l-i & 0x20)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
|
|
||||||
if (l-i & 0x40)
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
|
|
||||||
while (l > i) // Chomp through the rest of the list, 128 elements at a time.
|
|
||||||
. = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
|
|
||||||
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
|
|
||||||
|
|
||||||
#undef S64
|
|
||||||
#undef S16
|
|
||||||
#undef S4
|
|
||||||
#undef S1
|
|
||||||
|
|
||||||
// Slower then list2text, but correctly processes associative lists.
|
|
||||||
proc/tg_list2text(list/list, glue=",")
|
|
||||||
if (!istype(list) || !list.len)
|
|
||||||
return
|
|
||||||
var/output
|
|
||||||
for(var/i=1 to list.len)
|
|
||||||
output += (i!=1? glue : null)+(!isnull(list["[list[i]]"])?"[list["[list[i]]"]]":"[list[i]]")
|
|
||||||
return output
|
|
||||||
|
|
||||||
// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator)
|
|
||||||
/proc/text2list(text, delimiter="\n")
|
|
||||||
var/delim_len = length(delimiter)
|
|
||||||
if (delim_len < 1)
|
|
||||||
return list(text)
|
|
||||||
|
|
||||||
. = list()
|
|
||||||
var/last_found = 1
|
|
||||||
var/found
|
|
||||||
|
|
||||||
do
|
|
||||||
found = findtext(text, delimiter, last_found, 0)
|
|
||||||
. += copytext(text, last_found, found)
|
|
||||||
last_found = found + delim_len
|
|
||||||
while (found)
|
|
||||||
|
|
||||||
// Case sensitive version of /proc/text2list().
|
|
||||||
/proc/text2listEx(text, delimiter="\n")
|
|
||||||
var/delim_len = length(delimiter)
|
|
||||||
if (delim_len < 1)
|
|
||||||
return list(text)
|
|
||||||
|
|
||||||
. = list()
|
|
||||||
var/last_found = 1
|
|
||||||
var/found
|
|
||||||
|
|
||||||
do
|
|
||||||
found = findtextEx(text, delimiter, last_found, 0)
|
|
||||||
. += copytext(text, last_found, found)
|
|
||||||
last_found = found + delim_len
|
|
||||||
while (found)
|
|
||||||
|
|
||||||
/proc/text2numlist(text, delimiter="\n")
|
/proc/text2numlist(text, delimiter="\n")
|
||||||
var/list/num_list = list()
|
var/list/num_list = list()
|
||||||
for(var/x in text2list(text, delimiter))
|
for(var/x in splittext(text, delimiter))
|
||||||
num_list += text2num(x)
|
num_list += text2num(x)
|
||||||
return num_list
|
return num_list
|
||||||
|
|
||||||
// Splits the text of a file at seperator and returns them in a list.
|
// Splits the text of a file at seperator and returns them in a list.
|
||||||
/proc/file2list(filename, seperator="\n")
|
/proc/file2list(filename, seperator="\n")
|
||||||
return text2list(return_file_text(filename),seperator)
|
return splittext(return_file_text(filename),seperator)
|
||||||
|
|
||||||
// Turns a direction into text
|
// Turns a direction into text
|
||||||
/proc/num2dir(direction)
|
/proc/num2dir(direction)
|
||||||
@@ -275,6 +149,26 @@ proc/tg_list2text(list/list, glue=",")
|
|||||||
if (rights & R_MENTOR) . += "[seperator]+MENTOR"
|
if (rights & R_MENTOR) . += "[seperator]+MENTOR"
|
||||||
return .
|
return .
|
||||||
|
|
||||||
|
// Converts a hexadecimal color (e.g. #FF0050) to a list of numbers for red, green, and blue (e.g. list(255,0,80) ).
|
||||||
|
/proc/hex2rgb(hex)
|
||||||
|
// Strips the starting #, in case this is ever supplied without one, so everything doesn't break.
|
||||||
|
if(findtext(hex,"#",1,2))
|
||||||
|
hex = copytext(hex, 2)
|
||||||
|
return list(hex2rgb_r(hex), hex2rgb_g(hex), hex2rgb_b(hex))
|
||||||
|
|
||||||
|
// The three procs below require that the '#' part of the hex be stripped, which hex2rgb() does automatically.
|
||||||
|
/proc/hex2rgb_r(hex)
|
||||||
|
var/hex_to_work_on = copytext(hex,1,3)
|
||||||
|
return hex2num(hex_to_work_on)
|
||||||
|
|
||||||
|
/proc/hex2rgb_g(hex)
|
||||||
|
var/hex_to_work_on = copytext(hex,3,5)
|
||||||
|
return hex2num(hex_to_work_on)
|
||||||
|
|
||||||
|
/proc/hex2rgb_b(hex)
|
||||||
|
var/hex_to_work_on = copytext(hex,5,7)
|
||||||
|
return hex2num(hex_to_work_on)
|
||||||
|
|
||||||
// heat2color functions. Adapted from: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
// heat2color functions. Adapted from: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||||
/proc/heat2color(temp)
|
/proc/heat2color(temp)
|
||||||
return rgb(heat2color_r(temp), heat2color_g(temp), heat2color_b(temp))
|
return rgb(heat2color_r(temp), heat2color_g(temp), heat2color_b(temp))
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
|||||||
|
|
||||||
//Now to find a box from center location and make that our destination.
|
//Now to find a box from center location and make that our destination.
|
||||||
for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) ))
|
for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) ))
|
||||||
if(density&&T.density) continue//If density was specified.
|
if(density&&(T.density||T.contains_dense_objects())) continue//If density was specified.
|
||||||
if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map.
|
if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map.
|
||||||
if(T.y>world.maxy || T.y<1) continue
|
if(T.y>world.maxy || T.y<1) continue
|
||||||
destination_list += T
|
destination_list += T
|
||||||
@@ -146,7 +146,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
|||||||
else return
|
else return
|
||||||
|
|
||||||
else//Same deal here.
|
else//Same deal here.
|
||||||
if(density&&destination.density) return
|
if(density&&(destination.density||destination.contains_dense_objects())) return
|
||||||
if(destination.x>world.maxx || destination.x<1) return
|
if(destination.x>world.maxx || destination.x<1) return
|
||||||
if(destination.y>world.maxy || destination.y<1) return
|
if(destination.y>world.maxy || destination.y<1) return
|
||||||
else return
|
else return
|
||||||
@@ -462,7 +462,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
|||||||
if (M.real_name && M.real_name != M.name)
|
if (M.real_name && M.real_name != M.name)
|
||||||
name += " \[[M.real_name]\]"
|
name += " \[[M.real_name]\]"
|
||||||
if (M.stat == 2)
|
if (M.stat == 2)
|
||||||
if(istype(M, /mob/dead/observer/))
|
if(istype(M, /mob/observer/dead/))
|
||||||
name += " \[ghost\]"
|
name += " \[ghost\]"
|
||||||
else
|
else
|
||||||
name += " \[dead\]"
|
name += " \[dead\]"
|
||||||
@@ -474,7 +474,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
|||||||
/proc/sortmobs()
|
/proc/sortmobs()
|
||||||
var/list/moblist = list()
|
var/list/moblist = list()
|
||||||
var/list/sortmob = sortAtom(mob_list)
|
var/list/sortmob = sortAtom(mob_list)
|
||||||
for(var/mob/eye/M in sortmob)
|
for(var/mob/observer/eye/M in sortmob)
|
||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
for(var/mob/living/silicon/ai/M in sortmob)
|
for(var/mob/living/silicon/ai/M in sortmob)
|
||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
@@ -488,7 +488,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
|||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
for(var/mob/living/carbon/alien/M in sortmob)
|
for(var/mob/living/carbon/alien/M in sortmob)
|
||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
for(var/mob/dead/observer/M in sortmob)
|
for(var/mob/observer/dead/M in sortmob)
|
||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
for(var/mob/new_player/M in sortmob)
|
for(var/mob/new_player/M in sortmob)
|
||||||
moblist.Add(M)
|
moblist.Add(M)
|
||||||
@@ -646,47 +646,6 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
|||||||
|
|
||||||
else return get_step(ref, base_dir)
|
else return get_step(ref, base_dir)
|
||||||
|
|
||||||
/proc/do_mob(var/mob/user, var/mob/target, var/delay = 30, var/numticks = 5, var/needhand = 1) //This is quite an ugly solution but i refuse to use the old request system.
|
|
||||||
if(!user || !target) return 0
|
|
||||||
if(numticks == 0) return 0
|
|
||||||
|
|
||||||
var/delayfraction = round(delay/numticks)
|
|
||||||
var/original_user_loc = user.loc
|
|
||||||
var/original_target_loc = target.loc
|
|
||||||
var/holding = user.get_active_hand()
|
|
||||||
|
|
||||||
for(var/i = 0, i<numticks, i++)
|
|
||||||
sleep(delayfraction)
|
|
||||||
|
|
||||||
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_user_loc)
|
|
||||||
return 0
|
|
||||||
if(!target || target.loc != original_target_loc)
|
|
||||||
return 0
|
|
||||||
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
|
|
||||||
return 0
|
|
||||||
|
|
||||||
return 1
|
|
||||||
|
|
||||||
/proc/do_after(var/mob/user as mob, delay as num, var/numticks = 5, var/needhand = 1)
|
|
||||||
if(!user || isnull(user))
|
|
||||||
return 0
|
|
||||||
if(numticks == 0)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
var/delayfraction = round(delay/numticks)
|
|
||||||
var/original_loc = user.loc
|
|
||||||
var/holding = user.get_active_hand()
|
|
||||||
|
|
||||||
for(var/i = 0, i<numticks, i++)
|
|
||||||
sleep(delayfraction)
|
|
||||||
|
|
||||||
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_loc)
|
|
||||||
return 0
|
|
||||||
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
|
|
||||||
return 0
|
|
||||||
|
|
||||||
return 1
|
|
||||||
|
|
||||||
//Takes: Anything that could possibly have variables and a varname to check.
|
//Takes: Anything that could possibly have variables and a varname to check.
|
||||||
//Returns: 1 if found, 0 if not.
|
//Returns: 1 if found, 0 if not.
|
||||||
/proc/hasvar(var/datum/A, var/varname)
|
/proc/hasvar(var/datum/A, var/varname)
|
||||||
@@ -861,7 +820,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
|||||||
if(!istype(O,/obj)) continue
|
if(!istype(O,/obj)) continue
|
||||||
O.loc = X
|
O.loc = X
|
||||||
for(var/mob/M in T)
|
for(var/mob/M in T)
|
||||||
if(!istype(M,/mob) || istype(M, /mob/eye)) continue // If we need to check for more mobs, I'll add a variable
|
if(!istype(M,/mob) || istype(M, /mob/observer/eye)) continue // If we need to check for more mobs, I'll add a variable
|
||||||
M.loc = X
|
M.loc = X
|
||||||
|
|
||||||
// var/area/AR = X.loc
|
// var/area/AR = X.loc
|
||||||
@@ -995,7 +954,7 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
|
|||||||
|
|
||||||
for(var/mob/M in T)
|
for(var/mob/M in T)
|
||||||
|
|
||||||
if(!istype(M,/mob) || istype(M, /mob/eye)) continue // If we need to check for more mobs, I'll add a variable
|
if(!istype(M,/mob) || istype(M, /mob/observer/eye)) continue // If we need to check for more mobs, I'll add a variable
|
||||||
mobs += M
|
mobs += M
|
||||||
|
|
||||||
for(var/mob/M in mobs)
|
for(var/mob/M in mobs)
|
||||||
@@ -1080,10 +1039,9 @@ proc/get_mob_with_client_list()
|
|||||||
|
|
||||||
//gets the turf the atom is located in (or itself, if it is a turf).
|
//gets the turf the atom is located in (or itself, if it is a turf).
|
||||||
//returns null if the atom is not in a turf.
|
//returns null if the atom is not in a turf.
|
||||||
/proc/get_turf(atom/A)
|
/proc/get_turf(atom/movable/A)
|
||||||
if(!istype(A)) return
|
if(isturf(A)) return A
|
||||||
for(A, A && !isturf(A), A=A.loc);
|
if(A && A.locs.len) return A.locs[1]
|
||||||
return A
|
|
||||||
|
|
||||||
/proc/get(atom/loc, type)
|
/proc/get(atom/loc, type)
|
||||||
while(loc)
|
while(loc)
|
||||||
@@ -1299,7 +1257,7 @@ var/list/WALLITEMS = list(
|
|||||||
arglist = list2params(arglist)
|
arglist = list2params(arglist)
|
||||||
return "<a href='?src=\ref[D];[arglist]'>[content]</a>"
|
return "<a href='?src=\ref[D];[arglist]'>[content]</a>"
|
||||||
|
|
||||||
/proc/get_random_colour(var/simple, var/lower, var/upper)
|
/proc/get_random_colour(var/simple, var/lower=0, var/upper=255)
|
||||||
var/colour
|
var/colour
|
||||||
if(simple)
|
if(simple)
|
||||||
colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))
|
colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))
|
||||||
@@ -1351,3 +1309,15 @@ var/mob/dview/dview_mob = new
|
|||||||
// call to generate a stack trace and print to runtime logs
|
// call to generate a stack trace and print to runtime logs
|
||||||
/proc/crash_with(msg)
|
/proc/crash_with(msg)
|
||||||
CRASH(msg)
|
CRASH(msg)
|
||||||
|
|
||||||
|
/proc/screen_loc2turf(scr_loc, turf/origin)
|
||||||
|
var/tX = splittext(scr_loc, ",")
|
||||||
|
var/tY = splittext(tX[2], ":")
|
||||||
|
var/tZ = origin.z
|
||||||
|
tY = tY[1]
|
||||||
|
tX = splittext(tX[1], ":")
|
||||||
|
tX = tX[1]
|
||||||
|
tX = max(1, min(world.maxx, origin.x + (text2num(tX) - (world.view + 1))))
|
||||||
|
tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1))))
|
||||||
|
return locate(tX, tY, tZ)
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,15 @@
|
|||||||
|
|
||||||
#define isanimal(A) istype(A, /mob/living/simple_animal)
|
#define isanimal(A) istype(A, /mob/living/simple_animal)
|
||||||
|
|
||||||
|
#define isairlock(A) istype(A, /obj/machinery/door/airlock)
|
||||||
|
|
||||||
#define isbrain(A) istype(A, /mob/living/carbon/brain)
|
#define isbrain(A) istype(A, /mob/living/carbon/brain)
|
||||||
|
|
||||||
#define iscarbon(A) istype(A, /mob/living/carbon)
|
#define iscarbon(A) istype(A, /mob/living/carbon)
|
||||||
|
|
||||||
#define iscorgi(A) istype(A, /mob/living/simple_animal/corgi)
|
#define iscorgi(A) istype(A, /mob/living/simple_animal/corgi)
|
||||||
|
|
||||||
#define isEye(A) istype(A, /mob/eye)
|
#define isEye(A) istype(A, /mob/observer/eye)
|
||||||
|
|
||||||
#define ishuman(A) istype(A, /mob/living/carbon/human)
|
#define ishuman(A) istype(A, /mob/living/carbon/human)
|
||||||
|
|
||||||
@@ -23,7 +25,7 @@
|
|||||||
|
|
||||||
#define isnewplayer(A) istype(A, /mob/new_player)
|
#define isnewplayer(A) istype(A, /mob/new_player)
|
||||||
|
|
||||||
#define isobserver(A) istype(A, /mob/dead/observer)
|
#define isobserver(A) istype(A, /mob/observer/dead)
|
||||||
|
|
||||||
#define isorgan(A) istype(A, /obj/item/organ/external)
|
#define isorgan(A) istype(A, /obj/item/organ/external)
|
||||||
|
|
||||||
@@ -34,3 +36,7 @@
|
|||||||
#define issilicon(A) istype(A, /mob/living/silicon)
|
#define issilicon(A) istype(A, /mob/living/silicon)
|
||||||
|
|
||||||
#define isslime(A) istype(A, /mob/living/carbon/slime)
|
#define isslime(A) istype(A, /mob/living/carbon/slime)
|
||||||
|
|
||||||
|
#define isxeno(A) istype(A, /mob/living/simple_animal/xeno)
|
||||||
|
|
||||||
|
#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
||||||
|
|||||||
1
code/_onclick/_defines.dm
Normal file
1
code/_onclick/_defines.dm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#define CLICKCATCHER_PLANE -99
|
||||||
@@ -121,9 +121,9 @@
|
|||||||
|
|
||||||
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
|
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
|
||||||
if(density)
|
if(density)
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("command"="open", "activate" = "1"))
|
||||||
else
|
else
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "0"), 1)
|
Topic(src, list("command"="open", "activate" = "0"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/atom/proc/AICtrlClick()
|
/atom/proc/AICtrlClick()
|
||||||
@@ -131,17 +131,17 @@
|
|||||||
|
|
||||||
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
|
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
|
||||||
if(locked)
|
if(locked)
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
|
Topic(src, list("command"="bolts", "activate" = "0"))
|
||||||
else
|
else
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "1"), 1)
|
Topic(src, list("command"="bolts", "activate" = "1"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
|
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
|
||||||
Topic(src, list("src"= "\ref[src]", "breaker"="1"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("breaker"="1"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
|
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("command"="enable", "value"="[!enabled]"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/atom/proc/AIAltClick(var/atom/A)
|
/atom/proc/AIAltClick(var/atom/A)
|
||||||
@@ -150,14 +150,14 @@
|
|||||||
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
|
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
|
||||||
if(!electrified_until)
|
if(!electrified_until)
|
||||||
// permanent shock
|
// permanent shock
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("command"="electrify_permanently", "activate" = "1"))
|
||||||
else
|
else
|
||||||
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
|
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "0"), 1)
|
Topic(src, list("command"="electrify_permanently", "activate" = "0"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
|
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("command"="lethal", "value"="[!lethal]"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/atom/proc/AIMiddleClick(var/mob/living/silicon/user)
|
/atom/proc/AIMiddleClick(var/mob/living/silicon/user)
|
||||||
@@ -169,9 +169,9 @@
|
|||||||
return
|
return
|
||||||
|
|
||||||
if(!src.lights)
|
if(!src.lights)
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
Topic(src, list("command"="lights", "activate" = "1"))
|
||||||
else
|
else
|
||||||
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "0"), 1)
|
Topic(src, list("command"="lights", "activate" = "0"))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -87,6 +87,7 @@
|
|||||||
if(in_throw_mode)
|
if(in_throw_mode)
|
||||||
if(isturf(A) || isturf(A.loc))
|
if(isturf(A) || isturf(A.loc))
|
||||||
throw_item(A)
|
throw_item(A)
|
||||||
|
trigger_aiming(TARGET_CAN_CLICK)
|
||||||
return 1
|
return 1
|
||||||
throw_mode_off()
|
throw_mode_off()
|
||||||
|
|
||||||
@@ -94,20 +95,14 @@
|
|||||||
|
|
||||||
if(W == A) // Handle attack_self
|
if(W == A) // Handle attack_self
|
||||||
W.attack_self(src)
|
W.attack_self(src)
|
||||||
if(hand)
|
trigger_aiming(TARGET_CAN_CLICK)
|
||||||
update_inv_l_hand(0)
|
update_inv_active_hand(0)
|
||||||
else
|
|
||||||
update_inv_r_hand(0)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
//Atoms on your person
|
//Atoms on your person
|
||||||
// A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth.
|
// A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth.
|
||||||
var/sdepth = A.storage_depth(src)
|
var/sdepth = A.storage_depth(src)
|
||||||
if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1))
|
if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1))
|
||||||
// faster access to objects already on you
|
|
||||||
if(A.loc != src)
|
|
||||||
setMoveCooldown(10) //getting something out of a backpack
|
|
||||||
|
|
||||||
if(W)
|
if(W)
|
||||||
var/resolved = W.resolve_attackby(A, src)
|
var/resolved = W.resolve_attackby(A, src)
|
||||||
if(!resolved && A && W)
|
if(!resolved && A && W)
|
||||||
@@ -116,6 +111,8 @@
|
|||||||
if(ismob(A)) // No instant mob attacking
|
if(ismob(A)) // No instant mob attacking
|
||||||
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
UnarmedAttack(A, 1)
|
UnarmedAttack(A, 1)
|
||||||
|
|
||||||
|
trigger_aiming(TARGET_CAN_CLICK)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
|
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
|
||||||
@@ -126,8 +123,6 @@
|
|||||||
sdepth = A.storage_depth_turf()
|
sdepth = A.storage_depth_turf()
|
||||||
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
|
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
|
||||||
if(A.Adjacent(src)) // see adjacent.dm
|
if(A.Adjacent(src)) // see adjacent.dm
|
||||||
setMoveCooldown(5)
|
|
||||||
|
|
||||||
if(W)
|
if(W)
|
||||||
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
|
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
|
||||||
var/resolved = W.resolve_attackby(A,src)
|
var/resolved = W.resolve_attackby(A,src)
|
||||||
@@ -137,12 +132,15 @@
|
|||||||
if(ismob(A)) // No instant mob attacking
|
if(ismob(A)) // No instant mob attacking
|
||||||
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
UnarmedAttack(A, 1)
|
UnarmedAttack(A, 1)
|
||||||
|
trigger_aiming(TARGET_CAN_CLICK)
|
||||||
return
|
return
|
||||||
else // non-adjacent click
|
else // non-adjacent click
|
||||||
if(W)
|
if(W)
|
||||||
W.afterattack(A, src, 0, params) // 0: not Adjacent
|
W.afterattack(A, src, 0, params) // 0: not Adjacent
|
||||||
else
|
else
|
||||||
RangedAttack(A, params)
|
RangedAttack(A, params)
|
||||||
|
|
||||||
|
trigger_aiming(TARGET_CAN_CLICK)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/mob/proc/setClickCooldown(var/timeout)
|
/mob/proc/setClickCooldown(var/timeout)
|
||||||
@@ -194,15 +192,8 @@
|
|||||||
if((LASER in mutations) && a_intent == I_HURT)
|
if((LASER in mutations) && a_intent == I_HURT)
|
||||||
LaserEyes(A) // moved into a proc below
|
LaserEyes(A) // moved into a proc below
|
||||||
else if(TK in mutations)
|
else if(TK in mutations)
|
||||||
switch(get_dist(src,A))
|
if(get_dist(src, A) > tk_maxrange)
|
||||||
if(1 to 5) // not adjacent may mean blocked by window
|
return
|
||||||
setMoveCooldown(2)
|
|
||||||
if(5 to 7)
|
|
||||||
setMoveCooldown(5)
|
|
||||||
if(8 to tk_maxrange)
|
|
||||||
setMoveCooldown(10)
|
|
||||||
else
|
|
||||||
return
|
|
||||||
A.attack_tk(src)
|
A.attack_tk(src)
|
||||||
/*
|
/*
|
||||||
Restrained ClickOn
|
Restrained ClickOn
|
||||||
@@ -328,3 +319,28 @@
|
|||||||
else direction = WEST
|
else direction = WEST
|
||||||
if(direction != dir)
|
if(direction != dir)
|
||||||
facedir(direction)
|
facedir(direction)
|
||||||
|
|
||||||
|
/obj/screen/click_catcher
|
||||||
|
icon = 'icons/mob/screen_gen.dmi'
|
||||||
|
icon_state = "click_catcher"
|
||||||
|
plane = CLICKCATCHER_PLANE
|
||||||
|
mouse_opacity = 2
|
||||||
|
screen_loc = "CENTER-7,CENTER-7"
|
||||||
|
|
||||||
|
/obj/screen/click_catcher/proc/MakeGreed()
|
||||||
|
. = list()
|
||||||
|
for(var/i = 0, i<15, i++)
|
||||||
|
for(var/j = 0, j<15, j++)
|
||||||
|
var/obj/screen/click_catcher/CC = new()
|
||||||
|
CC.screen_loc = "NORTH-[i],EAST-[j]"
|
||||||
|
. += CC
|
||||||
|
|
||||||
|
/obj/screen/click_catcher/Click(location, control, params)
|
||||||
|
var/list/modifiers = params2list(params)
|
||||||
|
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
|
||||||
|
var/mob/living/carbon/C = usr
|
||||||
|
C.swap_hand()
|
||||||
|
else
|
||||||
|
var/turf/T = screen_loc2turf("screen-loc", get_turf(usr))
|
||||||
|
T.Click(location, control, params)
|
||||||
|
. = 1
|
||||||
|
|||||||
@@ -68,15 +68,15 @@
|
|||||||
update_icon()
|
update_icon()
|
||||||
|
|
||||||
/obj/screen/movable/ability_master/proc/open_ability_master()
|
/obj/screen/movable/ability_master/proc/open_ability_master()
|
||||||
var/list/screen_loc_xy = text2list(screen_loc,",")
|
var/list/screen_loc_xy = splittext(screen_loc,",")
|
||||||
|
|
||||||
//Create list of X offsets
|
//Create list of X offsets
|
||||||
var/list/screen_loc_X = text2list(screen_loc_xy[1],":")
|
var/list/screen_loc_X = splittext(screen_loc_xy[1],":")
|
||||||
var/x_position = decode_screen_X(screen_loc_X[1])
|
var/x_position = decode_screen_X(screen_loc_X[1])
|
||||||
var/x_pix = screen_loc_X[2]
|
var/x_pix = screen_loc_X[2]
|
||||||
|
|
||||||
//Create list of Y offsets
|
//Create list of Y offsets
|
||||||
var/list/screen_loc_Y = text2list(screen_loc_xy[2],":")
|
var/list/screen_loc_Y = splittext(screen_loc_xy[2],":")
|
||||||
var/y_position = decode_screen_Y(screen_loc_Y[1])
|
var/y_position = decode_screen_Y(screen_loc_Y[1])
|
||||||
var/y_pix = screen_loc_Y[2]
|
var/y_pix = screen_loc_Y[2]
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@
|
|||||||
using.layer = SCREEN_LAYER
|
using.layer = SCREEN_LAYER
|
||||||
adding += using
|
adding += using
|
||||||
|
|
||||||
//Crew Monitorting
|
//Crew Monitoring
|
||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "Crew Monitorting"
|
using.name = "Crew Monitoring"
|
||||||
using.icon = 'icons/mob/screen_ai.dmi'
|
using.icon = 'icons/mob/screen_ai.dmi'
|
||||||
using.icon_state = "crew_monitor"
|
using.icon_state = "crew_monitor"
|
||||||
using.screen_loc = ui_ai_crew_monitor
|
using.screen_loc = ui_ai_crew_monitor
|
||||||
@@ -130,6 +130,8 @@
|
|||||||
using.layer = SCREEN_LAYER
|
using.layer = SCREEN_LAYER
|
||||||
adding += using
|
adding += using
|
||||||
|
|
||||||
|
mymob.client.screen = list()
|
||||||
mymob.client.screen += adding + other
|
mymob.client.screen += adding + other
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -21,26 +21,13 @@
|
|||||||
mymob.healths.name = "health"
|
mymob.healths.name = "health"
|
||||||
mymob.healths.screen_loc = ui_alien_health
|
mymob.healths.screen_loc = ui_alien_health
|
||||||
|
|
||||||
mymob.blind = new /obj/screen()
|
|
||||||
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
|
|
||||||
mymob.blind.icon_state = "blackimageoverlay"
|
|
||||||
mymob.blind.name = " "
|
|
||||||
mymob.blind.screen_loc = "1,1"
|
|
||||||
mymob.blind.layer = 0
|
|
||||||
|
|
||||||
mymob.flash = new /obj/screen()
|
|
||||||
mymob.flash.icon = 'icons/mob/screen1_alien.dmi'
|
|
||||||
mymob.flash.icon_state = "blank"
|
|
||||||
mymob.flash.name = "flash"
|
|
||||||
mymob.flash.screen_loc = ui_entire_screen
|
|
||||||
mymob.flash.layer = 17
|
|
||||||
|
|
||||||
mymob.fire = new /obj/screen()
|
mymob.fire = new /obj/screen()
|
||||||
mymob.fire.icon = 'icons/mob/screen1_alien.dmi'
|
mymob.fire.icon = 'icons/mob/screen1_alien.dmi'
|
||||||
mymob.fire.icon_state = "fire0"
|
mymob.fire.icon_state = "fire0"
|
||||||
mymob.fire.name = "fire"
|
mymob.fire.name = "fire"
|
||||||
mymob.fire.screen_loc = ui_fire
|
mymob.fire.screen_loc = ui_fire
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach )
|
mymob.client.screen += list( mymob.healths, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach )
|
||||||
mymob.client.screen += src.adding + src.other
|
mymob.client.screen += src.adding + src.other
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
118
code/_onclick/hud/fullscreen.dm
Normal file
118
code/_onclick/hud/fullscreen.dm
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#define FULLSCREEN_LAYER 18
|
||||||
|
#define DAMAGE_LAYER FULLSCREEN_LAYER + 0.1
|
||||||
|
#define BLIND_LAYER DAMAGE_LAYER + 0.1
|
||||||
|
#define CRIT_LAYER BLIND_LAYER + 0.1
|
||||||
|
|
||||||
|
/mob
|
||||||
|
var/list/screens = list()
|
||||||
|
|
||||||
|
/mob/proc/set_fullscreen(condition, screen_name, screen_type, arg)
|
||||||
|
condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name)
|
||||||
|
|
||||||
|
/mob/proc/overlay_fullscreen(category, type, severity)
|
||||||
|
var/obj/screen/fullscreen/screen = screens[category]
|
||||||
|
|
||||||
|
if(screen)
|
||||||
|
if(screen.type != type)
|
||||||
|
clear_fullscreen(category, FALSE)
|
||||||
|
screen = null
|
||||||
|
else if(!severity || severity == screen.severity)
|
||||||
|
return null
|
||||||
|
|
||||||
|
if(!screen)
|
||||||
|
screen = PoolOrNew(type)
|
||||||
|
|
||||||
|
screen.icon_state = "[initial(screen.icon_state)][severity]"
|
||||||
|
screen.severity = severity
|
||||||
|
|
||||||
|
screens[category] = screen
|
||||||
|
if(client && stat != DEAD)
|
||||||
|
client.screen += screen
|
||||||
|
return screen
|
||||||
|
|
||||||
|
/mob/proc/clear_fullscreen(category, animated = 10)
|
||||||
|
var/obj/screen/fullscreen/screen = screens[category]
|
||||||
|
if(!screen)
|
||||||
|
return
|
||||||
|
|
||||||
|
screens -= category
|
||||||
|
|
||||||
|
if(animated)
|
||||||
|
spawn(0)
|
||||||
|
animate(screen, alpha = 0, time = animated)
|
||||||
|
sleep(animated)
|
||||||
|
if(client)
|
||||||
|
client.screen -= screen
|
||||||
|
qdel(screen)
|
||||||
|
else
|
||||||
|
if(client)
|
||||||
|
client.screen -= screen
|
||||||
|
qdel(screen)
|
||||||
|
|
||||||
|
/mob/proc/clear_fullscreens()
|
||||||
|
for(var/category in screens)
|
||||||
|
clear_fullscreen(category)
|
||||||
|
|
||||||
|
/mob/proc/hide_fullscreens()
|
||||||
|
if(client)
|
||||||
|
for(var/category in screens)
|
||||||
|
client.screen -= screens[category]
|
||||||
|
|
||||||
|
/mob/proc/reload_fullscreen()
|
||||||
|
if(client && stat != DEAD) //dead mob do not see any of the fullscreen overlays that he has.
|
||||||
|
for(var/category in screens)
|
||||||
|
client.screen |= screens[category]
|
||||||
|
|
||||||
|
/obj/screen/fullscreen
|
||||||
|
icon = 'icons/mob/screen_full.dmi'
|
||||||
|
icon_state = "default"
|
||||||
|
screen_loc = "CENTER-7,CENTER-7"
|
||||||
|
layer = FULLSCREEN_LAYER
|
||||||
|
mouse_opacity = 0
|
||||||
|
var/severity = 0
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/Destroy()
|
||||||
|
severity = 0
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/brute
|
||||||
|
icon_state = "brutedamageoverlay"
|
||||||
|
layer = DAMAGE_LAYER
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/oxy
|
||||||
|
icon_state = "oxydamageoverlay"
|
||||||
|
layer = DAMAGE_LAYER
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/crit
|
||||||
|
icon_state = "passage"
|
||||||
|
layer = CRIT_LAYER
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/blind
|
||||||
|
icon_state = "blackimageoverlay"
|
||||||
|
layer = BLIND_LAYER
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/impaired
|
||||||
|
icon_state = "impairedoverlay"
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/blurry
|
||||||
|
icon = 'icons/mob/screen1.dmi'
|
||||||
|
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||||
|
icon_state = "blurry"
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/flash
|
||||||
|
icon = 'icons/mob/screen1.dmi'
|
||||||
|
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||||
|
icon_state = "flash"
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/flash/noise
|
||||||
|
icon_state = "noise"
|
||||||
|
|
||||||
|
/obj/screen/fullscreen/high
|
||||||
|
icon = 'icons/mob/screen1.dmi'
|
||||||
|
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||||
|
icon_state = "druggy"
|
||||||
|
|
||||||
|
#undef FULLSCREEN_LAYER
|
||||||
|
#undef BLIND_LAYER
|
||||||
|
#undef DAMAGE_LAYER
|
||||||
|
#undef CRIT_LAYER
|
||||||
@@ -6,12 +6,14 @@ var/datum/global_hud/global_hud = new()
|
|||||||
var/list/global_huds = list(
|
var/list/global_huds = list(
|
||||||
global_hud.druggy,
|
global_hud.druggy,
|
||||||
global_hud.blurry,
|
global_hud.blurry,
|
||||||
|
global_hud.whitense,
|
||||||
global_hud.vimpaired,
|
global_hud.vimpaired,
|
||||||
global_hud.darkMask,
|
global_hud.darkMask,
|
||||||
global_hud.nvg,
|
global_hud.nvg,
|
||||||
global_hud.thermal,
|
global_hud.thermal,
|
||||||
global_hud.meson,
|
global_hud.meson,
|
||||||
global_hud.science)
|
global_hud.science
|
||||||
|
)
|
||||||
|
|
||||||
/datum/hud/var/obj/screen/grab_intent
|
/datum/hud/var/obj/screen/grab_intent
|
||||||
/datum/hud/var/obj/screen/hurt_intent
|
/datum/hud/var/obj/screen/hurt_intent
|
||||||
@@ -21,6 +23,7 @@ var/list/global_huds = list(
|
|||||||
/datum/global_hud
|
/datum/global_hud
|
||||||
var/obj/screen/druggy
|
var/obj/screen/druggy
|
||||||
var/obj/screen/blurry
|
var/obj/screen/blurry
|
||||||
|
var/obj/screen/whitense
|
||||||
var/list/vimpaired
|
var/list/vimpaired
|
||||||
var/list/darkMask
|
var/list/darkMask
|
||||||
var/obj/screen/nvg
|
var/obj/screen/nvg
|
||||||
@@ -53,6 +56,14 @@ var/list/global_huds = list(
|
|||||||
blurry.layer = 17
|
blurry.layer = 17
|
||||||
blurry.mouse_opacity = 0
|
blurry.mouse_opacity = 0
|
||||||
|
|
||||||
|
//static overlay effect for cameras and the like
|
||||||
|
whitense = new /obj/screen()
|
||||||
|
whitense.screen_loc = ui_entire_screen
|
||||||
|
whitense.icon = 'icons/effects/static.dmi'
|
||||||
|
whitense.icon_state = "1 light"
|
||||||
|
whitense.layer = 17
|
||||||
|
whitense.mouse_opacity = 0
|
||||||
|
|
||||||
nvg = setup_overlay("nvg_hud")
|
nvg = setup_overlay("nvg_hud")
|
||||||
thermal = setup_overlay("thermal_hud")
|
thermal = setup_overlay("thermal_hud")
|
||||||
meson = setup_overlay("meson_hud")
|
meson = setup_overlay("meson_hud")
|
||||||
@@ -260,9 +271,9 @@ datum/hud/New(mob/owner)
|
|||||||
if(ishuman(mymob))
|
if(ishuman(mymob))
|
||||||
human_hud(ui_style, ui_color, ui_alpha, mymob) // Pass the player the UI style chosen in preferences
|
human_hud(ui_style, ui_color, ui_alpha, mymob) // Pass the player the UI style chosen in preferences
|
||||||
else if(isrobot(mymob))
|
else if(isrobot(mymob))
|
||||||
robot_hud()
|
robot_hud(ui_style, ui_color, ui_alpha, mymob)
|
||||||
else if(isbrain(mymob))
|
else if(isbrain(mymob))
|
||||||
brain_hud(ui_style)
|
mymob.instantiate_hud(src)
|
||||||
else if(isalien(mymob))
|
else if(isalien(mymob))
|
||||||
larva_hud()
|
larva_hud()
|
||||||
else if(isslime(mymob))
|
else if(isslime(mymob))
|
||||||
@@ -375,3 +386,9 @@ datum/hud/New(mob/owner)
|
|||||||
hud_used.hidden_inventory_update()
|
hud_used.hidden_inventory_update()
|
||||||
hud_used.persistant_inventory_update()
|
hud_used.persistant_inventory_update()
|
||||||
update_action_buttons()
|
update_action_buttons()
|
||||||
|
|
||||||
|
/mob/proc/add_click_catcher()
|
||||||
|
client.screen += client.void
|
||||||
|
|
||||||
|
/mob/new_player/add_click_catcher()
|
||||||
|
return
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
inv_box.name = "r_hand"
|
inv_box.name = "r_hand"
|
||||||
inv_box.icon = ui_style
|
inv_box.icon = ui_style
|
||||||
inv_box.icon_state = "r_hand_inactive"
|
inv_box.icon_state = "r_hand_inactive"
|
||||||
if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use
|
if(!target.hand) //This being 0 or null means the right hand is in use
|
||||||
inv_box.icon_state = "r_hand_active"
|
inv_box.icon_state = "r_hand_active"
|
||||||
inv_box.screen_loc = ui_rhand
|
inv_box.screen_loc = ui_rhand
|
||||||
inv_box.slot_id = slot_r_hand
|
inv_box.slot_id = slot_r_hand
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
inv_box.name = "l_hand"
|
inv_box.name = "l_hand"
|
||||||
inv_box.icon = ui_style
|
inv_box.icon = ui_style
|
||||||
inv_box.icon_state = "l_hand_inactive"
|
inv_box.icon_state = "l_hand_inactive"
|
||||||
if(mymob && mymob.hand) //This being 1 means the left hand is in use
|
if(target.hand) //This being 1 means the left hand is in use
|
||||||
inv_box.icon_state = "l_hand_active"
|
inv_box.icon_state = "l_hand_active"
|
||||||
inv_box.screen_loc = ui_lhand
|
inv_box.screen_loc = ui_lhand
|
||||||
inv_box.slot_id = slot_l_hand
|
inv_box.slot_id = slot_l_hand
|
||||||
@@ -313,31 +313,6 @@
|
|||||||
mymob.wiz_energy_display.icon_state = "wiz_energy"
|
mymob.wiz_energy_display.icon_state = "wiz_energy"
|
||||||
hud_elements |= mymob.wiz_energy_display
|
hud_elements |= mymob.wiz_energy_display
|
||||||
|
|
||||||
mymob.blind = new /obj/screen()
|
|
||||||
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
|
|
||||||
mymob.blind.icon_state = "blackimageoverlay"
|
|
||||||
mymob.blind.name = " "
|
|
||||||
mymob.blind.screen_loc = "1,1"
|
|
||||||
mymob.blind.mouse_opacity = 0
|
|
||||||
mymob.blind.layer = 0
|
|
||||||
hud_elements |= mymob.blind
|
|
||||||
|
|
||||||
mymob.damageoverlay = new /obj/screen()
|
|
||||||
mymob.damageoverlay.icon = 'icons/mob/screen1_full.dmi'
|
|
||||||
mymob.damageoverlay.icon_state = "oxydamageoverlay0"
|
|
||||||
mymob.damageoverlay.name = "dmg"
|
|
||||||
mymob.damageoverlay.screen_loc = "1,1"
|
|
||||||
mymob.damageoverlay.mouse_opacity = 0
|
|
||||||
mymob.damageoverlay.layer = 18.1 //The black screen overlay sets layer to 18 to display it, this one has to be just on top.
|
|
||||||
hud_elements |= mymob.damageoverlay
|
|
||||||
|
|
||||||
mymob.flash = new /obj/screen()
|
|
||||||
mymob.flash.icon = ui_style
|
|
||||||
mymob.flash.icon_state = "blank"
|
|
||||||
mymob.flash.name = "flash"
|
|
||||||
mymob.flash.screen_loc = ui_entire_screen
|
|
||||||
mymob.flash.layer = 17
|
|
||||||
hud_elements |= mymob.flash
|
|
||||||
|
|
||||||
mymob.pain = new /obj/screen( null )
|
mymob.pain = new /obj/screen( null )
|
||||||
|
|
||||||
@@ -371,11 +346,12 @@
|
|||||||
mymob.radio_use_icon.color = ui_color
|
mymob.radio_use_icon.color = ui_color
|
||||||
mymob.radio_use_icon.alpha = ui_alpha
|
mymob.radio_use_icon.alpha = ui_alpha
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
|
|
||||||
mymob.client.screen += hud_elements
|
mymob.client.screen += hud_elements
|
||||||
mymob.client.screen += src.adding + src.hotkeybuttons
|
mymob.client.screen += src.adding + src.hotkeybuttons
|
||||||
inventory_shown = 0;
|
mymob.client.screen += mymob.client.void
|
||||||
|
inventory_shown = 0
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -397,10 +373,7 @@
|
|||||||
f_style = "Shaved"
|
f_style = "Shaved"
|
||||||
if(dna.species == "Human") //no more xenos losing ears/tentacles
|
if(dna.species == "Human") //no more xenos losing ears/tentacles
|
||||||
h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3")
|
h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3")
|
||||||
undershirt = null
|
all_underwear.Cut()
|
||||||
underwear_top = null
|
|
||||||
underwear_bottom = null
|
|
||||||
socks = null
|
|
||||||
regenerate_icons()
|
regenerate_icons()
|
||||||
|
|
||||||
/obj/screen/ling
|
/obj/screen/ling
|
||||||
@@ -416,7 +389,6 @@
|
|||||||
/obj/screen/wizard/instability
|
/obj/screen/wizard/instability
|
||||||
name = "instability"
|
name = "instability"
|
||||||
icon_state = "instability-1"
|
icon_state = "instability-1"
|
||||||
invisibility = 0
|
|
||||||
|
|
||||||
/obj/screen/wizard/energy
|
/obj/screen/wizard/energy
|
||||||
name = "energy"
|
name = "energy"
|
||||||
|
|||||||
@@ -27,13 +27,13 @@
|
|||||||
return
|
return
|
||||||
|
|
||||||
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
|
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
|
||||||
var/list/screen_loc_params = text2list(PM["screen-loc"], ",")
|
var/list/screen_loc_params = splittext(PM["screen-loc"], ",")
|
||||||
|
|
||||||
//Split X+Pixel_X up into list(X, Pixel_X)
|
//Split X+Pixel_X up into list(X, Pixel_X)
|
||||||
var/list/screen_loc_X = text2list(screen_loc_params[1],":")
|
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
|
||||||
screen_loc_X[1] = encode_screen_X(text2num(screen_loc_X[1]))
|
screen_loc_X[1] = encode_screen_X(text2num(screen_loc_X[1]))
|
||||||
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
|
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
|
||||||
var/list/screen_loc_Y = text2list(screen_loc_params[2],":")
|
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
|
||||||
screen_loc_Y[1] = encode_screen_Y(text2num(screen_loc_Y[1]))
|
screen_loc_Y[1] = encode_screen_Y(text2num(screen_loc_Y[1]))
|
||||||
|
|
||||||
if(snap2grid) //Discard Pixel Values
|
if(snap2grid) //Discard Pixel Values
|
||||||
|
|||||||
@@ -5,14 +5,6 @@
|
|||||||
/datum/hud/proc/ghost_hud()
|
/datum/hud/proc/ghost_hud()
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/hud/proc/brain_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
|
|
||||||
mymob.blind = new /obj/screen()
|
|
||||||
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
|
|
||||||
mymob.blind.icon_state = "blackimageoverlay"
|
|
||||||
mymob.blind.name = " "
|
|
||||||
mymob.blind.screen_loc = "1,1"
|
|
||||||
mymob.blind.layer = 0
|
|
||||||
|
|
||||||
/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
|
/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
|
||||||
|
|
||||||
blobpwrdisplay = new /obj/screen()
|
blobpwrdisplay = new /obj/screen()
|
||||||
@@ -27,9 +19,10 @@
|
|||||||
blobhealthdisplay.screen_loc = ui_internal
|
blobhealthdisplay.screen_loc = ui_internal
|
||||||
blobhealthdisplay.layer = 20
|
blobhealthdisplay.layer = 20
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
|
|
||||||
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
|
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
|
|
||||||
/datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
|
/datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
|
||||||
|
|
||||||
@@ -94,8 +87,9 @@
|
|||||||
src.adding += using
|
src.adding += using
|
||||||
hurt_intent = using
|
hurt_intent = using
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
mymob.client.screen += src.adding
|
mymob.client.screen += src.adding
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -114,13 +108,6 @@
|
|||||||
else if(istype(mymob,/mob/living/simple_animal/construct/harvester))
|
else if(istype(mymob,/mob/living/simple_animal/construct/harvester))
|
||||||
constructtype = "harvester"
|
constructtype = "harvester"
|
||||||
|
|
||||||
mymob.flash = new /obj/screen()
|
|
||||||
mymob.flash.icon = 'icons/mob/screen1.dmi'
|
|
||||||
mymob.flash.icon_state = "blank"
|
|
||||||
mymob.flash.name = "flash"
|
|
||||||
mymob.flash.screen_loc = ui_entire_screen
|
|
||||||
mymob.flash.layer = 17
|
|
||||||
|
|
||||||
if(constructtype)
|
if(constructtype)
|
||||||
mymob.fire = new /obj/screen()
|
mymob.fire = new /obj/screen()
|
||||||
mymob.fire.icon = 'icons/mob/screen1_construct.dmi'
|
mymob.fire.icon = 'icons/mob/screen1_construct.dmi'
|
||||||
@@ -151,6 +138,7 @@
|
|||||||
mymob.purged.name = "purged"
|
mymob.purged.name = "purged"
|
||||||
mymob.purged.screen_loc = ui_construct_purge
|
mymob.purged.screen_loc = ui_construct_purge
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
|
|
||||||
mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged, mymob.flash)
|
mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged)
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
var/obj/screen/robot_inventory
|
var/obj/screen/robot_inventory
|
||||||
|
/*
|
||||||
|
/mob/living/silicon/robot/instantiate_hud(var/datum/hud/HUD, var/ui_style, var/ui_color, var/ui_alpha)
|
||||||
|
HUD.robot_hud(ui_style, ui_color, ui_alpha, src)*/
|
||||||
|
|
||||||
|
/datum/hud/proc/robot_hud(ui_style='icons/mob/screen1_robot.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255, var/mob/living/silicon/robot/target)
|
||||||
|
/* var/datum/hud_data/hud_data
|
||||||
|
if(!istype(target))
|
||||||
|
hud_data = new()
|
||||||
|
|
||||||
/datum/hud/proc/robot_hud()
|
if(hud_data.icon)
|
||||||
|
ui_style = hud_data.icon*/
|
||||||
|
|
||||||
|
if(ui_style == 'icons/mob/screen/minimalist.dmi')
|
||||||
|
ui_style = 'icons/mob/screen1_robot_minimalist.dmi'
|
||||||
|
else
|
||||||
|
ui_style = 'icons/mob/screen1_robot.dmi'
|
||||||
|
|
||||||
src.adding = list()
|
src.adding = list()
|
||||||
src.other = list()
|
src.other = list()
|
||||||
@@ -12,7 +25,9 @@ var/obj/screen/robot_inventory
|
|||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "radio"
|
using.name = "radio"
|
||||||
using.set_dir(SOUTHWEST)
|
using.set_dir(SOUTHWEST)
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
|
using.color = ui_color
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.icon_state = "radio"
|
using.icon_state = "radio"
|
||||||
using.screen_loc = ui_movi
|
using.screen_loc = ui_movi
|
||||||
using.layer = 20
|
using.layer = 20
|
||||||
@@ -23,7 +38,9 @@ var/obj/screen/robot_inventory
|
|||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "module1"
|
using.name = "module1"
|
||||||
using.set_dir(SOUTHWEST)
|
using.set_dir(SOUTHWEST)
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
|
using.color = ui_color
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.icon_state = "inv1"
|
using.icon_state = "inv1"
|
||||||
using.screen_loc = ui_inv1
|
using.screen_loc = ui_inv1
|
||||||
using.layer = 20
|
using.layer = 20
|
||||||
@@ -33,7 +50,9 @@ var/obj/screen/robot_inventory
|
|||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "module2"
|
using.name = "module2"
|
||||||
using.set_dir(SOUTHWEST)
|
using.set_dir(SOUTHWEST)
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
|
using.color = ui_color
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.icon_state = "inv2"
|
using.icon_state = "inv2"
|
||||||
using.screen_loc = ui_inv2
|
using.screen_loc = ui_inv2
|
||||||
using.layer = 20
|
using.layer = 20
|
||||||
@@ -43,7 +62,9 @@ var/obj/screen/robot_inventory
|
|||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "module3"
|
using.name = "module3"
|
||||||
using.set_dir(SOUTHWEST)
|
using.set_dir(SOUTHWEST)
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
|
using.color = ui_color
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.icon_state = "inv3"
|
using.icon_state = "inv3"
|
||||||
using.screen_loc = ui_inv3
|
using.screen_loc = ui_inv3
|
||||||
using.layer = 20
|
using.layer = 20
|
||||||
@@ -56,7 +77,8 @@ var/obj/screen/robot_inventory
|
|||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "act_intent"
|
using.name = "act_intent"
|
||||||
using.set_dir(SOUTHWEST)
|
using.set_dir(SOUTHWEST)
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.icon_state = mymob.a_intent
|
using.icon_state = mymob.a_intent
|
||||||
using.screen_loc = ui_acti
|
using.screen_loc = ui_acti
|
||||||
using.layer = 20
|
using.layer = 20
|
||||||
@@ -65,47 +87,60 @@ var/obj/screen/robot_inventory
|
|||||||
|
|
||||||
//Cell
|
//Cell
|
||||||
mymob:cells = new /obj/screen()
|
mymob:cells = new /obj/screen()
|
||||||
mymob:cells.icon = 'icons/mob/screen1_robot.dmi'
|
mymob:cells.icon = ui_style
|
||||||
mymob:cells.icon_state = "charge-empty"
|
mymob:cells.icon_state = "charge-empty"
|
||||||
|
mymob:cells.alpha = ui_alpha
|
||||||
mymob:cells.name = "cell"
|
mymob:cells.name = "cell"
|
||||||
mymob:cells.screen_loc = ui_toxin
|
mymob:cells.screen_loc = ui_toxin
|
||||||
|
src.other += mymob:cells
|
||||||
|
|
||||||
//Health
|
//Health
|
||||||
mymob.healths = new /obj/screen()
|
mymob.healths = new /obj/screen()
|
||||||
mymob.healths.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.healths.icon = ui_style
|
||||||
mymob.healths.icon_state = "health0"
|
mymob.healths.icon_state = "health0"
|
||||||
|
mymob.healths.alpha = ui_alpha
|
||||||
mymob.healths.name = "health"
|
mymob.healths.name = "health"
|
||||||
mymob.healths.screen_loc = ui_borg_health
|
mymob.healths.screen_loc = ui_borg_health
|
||||||
|
src.other += mymob.healths
|
||||||
|
|
||||||
//Installed Module
|
//Installed Module
|
||||||
mymob.hands = new /obj/screen()
|
mymob.hands = new /obj/screen()
|
||||||
mymob.hands.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.hands.icon = ui_style
|
||||||
mymob.hands.icon_state = "nomod"
|
mymob.hands.icon_state = "nomod"
|
||||||
|
mymob.hands.alpha = ui_alpha
|
||||||
mymob.hands.name = "module"
|
mymob.hands.name = "module"
|
||||||
mymob.hands.screen_loc = ui_borg_module
|
mymob.hands.screen_loc = ui_borg_module
|
||||||
|
src.other += mymob.hands
|
||||||
|
|
||||||
//Module Panel
|
//Module Panel
|
||||||
using = new /obj/screen()
|
using = new /obj/screen()
|
||||||
using.name = "panel"
|
using.name = "panel"
|
||||||
using.icon = 'icons/mob/screen1_robot.dmi'
|
using.icon = ui_style
|
||||||
using.icon_state = "panel"
|
using.icon_state = "panel"
|
||||||
|
using.alpha = ui_alpha
|
||||||
using.screen_loc = ui_borg_panel
|
using.screen_loc = ui_borg_panel
|
||||||
using.layer = 19
|
using.layer = 19
|
||||||
src.adding += using
|
src.adding += using
|
||||||
|
|
||||||
//Store
|
//Store
|
||||||
mymob.throw_icon = new /obj/screen()
|
mymob.throw_icon = new /obj/screen()
|
||||||
mymob.throw_icon.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.throw_icon.icon = ui_style
|
||||||
mymob.throw_icon.icon_state = "store"
|
mymob.throw_icon.icon_state = "store"
|
||||||
|
mymob.throw_icon.alpha = ui_alpha
|
||||||
|
mymob.throw_icon.color = ui_color
|
||||||
mymob.throw_icon.name = "store"
|
mymob.throw_icon.name = "store"
|
||||||
mymob.throw_icon.screen_loc = ui_borg_store
|
mymob.throw_icon.screen_loc = ui_borg_store
|
||||||
|
src.other += mymob.throw_icon
|
||||||
|
|
||||||
//Inventory
|
//Inventory
|
||||||
robot_inventory = new /obj/screen()
|
robot_inventory = new /obj/screen()
|
||||||
robot_inventory.name = "inventory"
|
robot_inventory.name = "inventory"
|
||||||
robot_inventory.icon = 'icons/mob/screen1_robot.dmi'
|
robot_inventory.icon = ui_style
|
||||||
robot_inventory.icon_state = "inventory"
|
robot_inventory.icon_state = "inventory"
|
||||||
|
robot_inventory.alpha = ui_alpha
|
||||||
|
robot_inventory.color = ui_color
|
||||||
robot_inventory.screen_loc = ui_borg_inventory
|
robot_inventory.screen_loc = ui_borg_inventory
|
||||||
|
src.other += robot_inventory
|
||||||
|
|
||||||
//Temp
|
//Temp
|
||||||
mymob.bodytemp = new /obj/screen()
|
mymob.bodytemp = new /obj/screen()
|
||||||
@@ -113,54 +148,56 @@ var/obj/screen/robot_inventory
|
|||||||
mymob.bodytemp.name = "body temperature"
|
mymob.bodytemp.name = "body temperature"
|
||||||
mymob.bodytemp.screen_loc = ui_temp
|
mymob.bodytemp.screen_loc = ui_temp
|
||||||
|
|
||||||
|
|
||||||
mymob.oxygen = new /obj/screen()
|
mymob.oxygen = new /obj/screen()
|
||||||
mymob.oxygen.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.oxygen.icon = ui_style
|
||||||
mymob.oxygen.icon_state = "oxy0"
|
mymob.oxygen.icon_state = "oxy0"
|
||||||
|
mymob.oxygen.alpha = ui_alpha
|
||||||
mymob.oxygen.name = "oxygen"
|
mymob.oxygen.name = "oxygen"
|
||||||
mymob.oxygen.screen_loc = ui_oxygen
|
mymob.oxygen.screen_loc = ui_oxygen
|
||||||
|
src.other += mymob.oxygen
|
||||||
|
|
||||||
mymob.fire = new /obj/screen()
|
mymob.fire = new /obj/screen()
|
||||||
mymob.fire.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.fire.icon = ui_style
|
||||||
mymob.fire.icon_state = "fire0"
|
mymob.fire.icon_state = "fire0"
|
||||||
|
mymob.fire.alpha = ui_alpha
|
||||||
mymob.fire.name = "fire"
|
mymob.fire.name = "fire"
|
||||||
mymob.fire.screen_loc = ui_fire
|
mymob.fire.screen_loc = ui_fire
|
||||||
|
src.other += mymob.fire
|
||||||
|
|
||||||
mymob.pullin = new /obj/screen()
|
mymob.pullin = new /obj/screen()
|
||||||
mymob.pullin.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.pullin.icon = ui_style
|
||||||
mymob.pullin.icon_state = "pull0"
|
mymob.pullin.icon_state = "pull0"
|
||||||
|
mymob.pullin.alpha = ui_alpha
|
||||||
|
mymob.pullin.color = ui_color
|
||||||
mymob.pullin.name = "pull"
|
mymob.pullin.name = "pull"
|
||||||
mymob.pullin.screen_loc = ui_borg_pull
|
mymob.pullin.screen_loc = ui_borg_pull
|
||||||
|
src.other += mymob.pullin
|
||||||
mymob.blind = new /obj/screen()
|
|
||||||
mymob.blind.icon = 'icons/mob/screen1_full.dmi'
|
|
||||||
mymob.blind.icon_state = "blackimageoverlay"
|
|
||||||
mymob.blind.name = " "
|
|
||||||
mymob.blind.screen_loc = "1,1"
|
|
||||||
mymob.blind.layer = 0
|
|
||||||
|
|
||||||
mymob.flash = new /obj/screen()
|
|
||||||
mymob.flash.icon = 'icons/mob/screen1_robot.dmi'
|
|
||||||
mymob.flash.icon_state = "blank"
|
|
||||||
mymob.flash.name = "flash"
|
|
||||||
mymob.flash.screen_loc = ui_entire_screen
|
|
||||||
mymob.flash.layer = 17
|
|
||||||
|
|
||||||
mymob.zone_sel = new /obj/screen/zone_sel()
|
mymob.zone_sel = new /obj/screen/zone_sel()
|
||||||
mymob.zone_sel.icon = 'icons/mob/screen1_robot.dmi'
|
mymob.zone_sel.icon = ui_style
|
||||||
|
mymob.zone_sel.alpha = ui_alpha
|
||||||
mymob.zone_sel.overlays.Cut()
|
mymob.zone_sel.overlays.Cut()
|
||||||
mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
|
mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
|
||||||
|
|
||||||
//Handle the gun settings buttons
|
//Handle the gun settings buttons
|
||||||
mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
|
mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
|
||||||
|
mymob.gun_setting_icon.icon = ui_style
|
||||||
|
mymob.gun_setting_icon.alpha = ui_alpha
|
||||||
mymob.item_use_icon = new /obj/screen/gun/item(null)
|
mymob.item_use_icon = new /obj/screen/gun/item(null)
|
||||||
|
mymob.item_use_icon.icon = ui_style
|
||||||
|
mymob.item_use_icon.alpha = ui_alpha
|
||||||
mymob.gun_move_icon = new /obj/screen/gun/move(null)
|
mymob.gun_move_icon = new /obj/screen/gun/move(null)
|
||||||
|
mymob.gun_move_icon.icon = ui_style
|
||||||
|
mymob.gun_move_icon.alpha = ui_alpha
|
||||||
mymob.radio_use_icon = new /obj/screen/gun/radio(null)
|
mymob.radio_use_icon = new /obj/screen/gun/radio(null)
|
||||||
|
mymob.radio_use_icon.icon = ui_style
|
||||||
|
mymob.radio_use_icon.alpha = ui_alpha
|
||||||
|
|
||||||
mymob.client.screen = null
|
mymob.client.screen = list()
|
||||||
|
|
||||||
mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, robot_inventory, mymob.gun_setting_icon)
|
mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, robot_inventory, mymob.gun_setting_icon)
|
||||||
mymob.client.screen += src.adding + src.other
|
mymob.client.screen += src.adding + src.other
|
||||||
|
mymob.client.screen += mymob.client.void
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -420,7 +420,7 @@
|
|||||||
var/mob/living/silicon/ai/AI = usr
|
var/mob/living/silicon/ai/AI = usr
|
||||||
AI.toggle_camera_light()
|
AI.toggle_camera_light()
|
||||||
|
|
||||||
if("Crew Monitorting")
|
if("Crew Monitoring")
|
||||||
if(isAI(usr))
|
if(isAI(usr))
|
||||||
var/mob/living/silicon/ai/AI = usr
|
var/mob/living/silicon/ai/AI = usr
|
||||||
AI.subsystem_crew_monitor()
|
AI.subsystem_crew_monitor()
|
||||||
|
|||||||
@@ -57,15 +57,15 @@
|
|||||||
overlays.Add(open_state)
|
overlays.Add(open_state)
|
||||||
|
|
||||||
/obj/screen/movable/spell_master/proc/open_spellmaster()
|
/obj/screen/movable/spell_master/proc/open_spellmaster()
|
||||||
var/list/screen_loc_xy = text2list(screen_loc,",")
|
var/list/screen_loc_xy = splittext(screen_loc,",")
|
||||||
|
|
||||||
//Create list of X offsets
|
//Create list of X offsets
|
||||||
var/list/screen_loc_X = text2list(screen_loc_xy[1],":")
|
var/list/screen_loc_X = splittext(screen_loc_xy[1],":")
|
||||||
var/x_position = decode_screen_X(screen_loc_X[1])
|
var/x_position = decode_screen_X(screen_loc_X[1])
|
||||||
var/x_pix = screen_loc_X[2]
|
var/x_pix = screen_loc_X[2]
|
||||||
|
|
||||||
//Create list of Y offsets
|
//Create list of Y offsets
|
||||||
var/list/screen_loc_Y = text2list(screen_loc_xy[2],":")
|
var/list/screen_loc_Y = splittext(screen_loc_xy[2],":")
|
||||||
var/y_position = decode_screen_Y(screen_loc_Y[1])
|
var/y_position = decode_screen_Y(screen_loc_Y[1])
|
||||||
var/y_pix = screen_loc_Y[2]
|
var/y_pix = screen_loc_Y[2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,59 @@
|
|||||||
|
/*
|
||||||
|
=== Item Click Call Sequences ===
|
||||||
|
These are the default click code call sequences used when clicking on stuff with an item.
|
||||||
|
|
||||||
|
Atoms:
|
||||||
|
|
||||||
|
mob/ClickOn() calls the item's resolve_attackby() proc.
|
||||||
|
item/resolve_attackby() calls the target atom's attackby() proc.
|
||||||
|
|
||||||
|
Mobs:
|
||||||
|
|
||||||
|
mob/living/attackby() after checking for surgery, calls the item's attack() proc.
|
||||||
|
item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself.
|
||||||
|
mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit.
|
||||||
|
|
||||||
|
Item Hit Effects:
|
||||||
|
|
||||||
|
item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to
|
||||||
|
avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent).
|
||||||
|
*/
|
||||||
|
|
||||||
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
|
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
|
||||||
/obj/item/proc/attack_self(mob/user)
|
/obj/item/proc/attack_self(mob/user)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
//I would prefer to rename this to attack(), but that would involve touching hundreds of files.
|
||||||
|
/obj/item/proc/resolve_attackby(atom/A, mob/user)
|
||||||
|
add_fingerprint(user)
|
||||||
|
return A.attackby(src, user)
|
||||||
|
|
||||||
// No comment
|
// No comment
|
||||||
/atom/proc/attackby(obj/item/W, mob/user)
|
/atom/proc/attackby(obj/item/W, mob/user)
|
||||||
return
|
return
|
||||||
|
|
||||||
/atom/movable/attackby(obj/item/W, mob/user)
|
/atom/movable/attackby(obj/item/W, mob/user)
|
||||||
if(!(W.flags&NOBLUDGEON))
|
if(!(W.flags & NOBLUDGEON))
|
||||||
visible_message("<span class='danger'>[src] has been hit by [user] with [W].</span>")
|
visible_message("<span class='danger'>[src] has been hit by [user] with [W].</span>")
|
||||||
|
|
||||||
/mob/living/attackby(obj/item/I, mob/user)
|
/mob/living/attackby(obj/item/I, mob/user)
|
||||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
if(!ismob(user))
|
||||||
if(istype(I) && ismob(user))
|
return 0
|
||||||
I.attack(src, user)
|
if(can_operate(src) && I.do_surgery(src,user)) //Surgery
|
||||||
|
return 1
|
||||||
|
return I.attack(src, user, user.zone_sel.selecting)
|
||||||
|
|
||||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||||
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||||
return
|
return
|
||||||
|
|
||||||
//TODO: refactor mob attack code.
|
//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files.
|
||||||
/*
|
/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||||
Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here.
|
if(!force || (flags & NOBLUDGEON))
|
||||||
leave attackby() as handling the general case of "using an item on a mob"
|
return 0
|
||||||
attackby() will decide to call attacked_by() or not.
|
if(M == user && user.a_intent != I_HURT)
|
||||||
attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm"
|
return 0
|
||||||
attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing.
|
|
||||||
attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
|
|
||||||
|
|
||||||
if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0
|
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
user.lastattacked = M
|
user.lastattacked = M
|
||||||
@@ -46,50 +65,22 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call
|
|||||||
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
|
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
// Attacking someone with a weapon while they are neck-grabbed
|
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
if(user.a_intent == I_HURT)
|
user.do_attack_animation(M)
|
||||||
for(var/obj/item/weapon/grab/G in M.grabbed_by)
|
|
||||||
if(G.assailant == user && G.state >= GRAB_NECK)
|
|
||||||
M.attack_throat(src, G, user)
|
|
||||||
|
|
||||||
|
var/hit_zone = M.resolve_item_attack(src, user, target_zone)
|
||||||
|
if(hit_zone)
|
||||||
|
apply_hit_effect(M, user, hit_zone)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result
|
||||||
|
/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||||
|
if(hitsound)
|
||||||
|
playsound(loc, hitsound, 50, 1, -1)
|
||||||
|
|
||||||
var/power = force
|
var/power = force
|
||||||
if(HULK in user.mutations)
|
if(HULK in user.mutations)
|
||||||
power *= 2
|
power *= 2
|
||||||
|
return target.hit_with_weapon(src, user, power, hit_zone)
|
||||||
|
|
||||||
// TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z
|
|
||||||
user.do_attack_animation(M)
|
|
||||||
user.break_cloak()
|
|
||||||
if(istype(M, /mob/living/carbon/human))
|
|
||||||
var/mob/living/carbon/human/H = M
|
|
||||||
|
|
||||||
// Handle striking to cripple.
|
|
||||||
var/dislocation_str
|
|
||||||
if(user.a_intent == I_DISARM)
|
|
||||||
dislocation_str = H.attack_joint(src, user, def_zone)
|
|
||||||
if(H.attacked_by(src, user, def_zone) && hitsound)
|
|
||||||
playsound(loc, hitsound, 50, 1, -1)
|
|
||||||
spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves.
|
|
||||||
if(dislocation_str) user.visible_message("<span class='danger'>[dislocation_str]</span>")
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
if(attack_verb.len)
|
|
||||||
user.visible_message("<span class='danger'>[M] has been [pick(attack_verb)] with [src] by [user]!</span>")
|
|
||||||
else
|
|
||||||
user.visible_message("<span class='danger'>[M] has been attacked with [src] by [user]!</span>")
|
|
||||||
|
|
||||||
if (hitsound)
|
|
||||||
playsound(loc, hitsound, 50, 1, -1)
|
|
||||||
switch(damtype)
|
|
||||||
if("brute")
|
|
||||||
M.take_organ_damage(power)
|
|
||||||
if(prob(33)) // Added blood for whacking non-humans too
|
|
||||||
var/turf/simulated/location = get_turf(M)
|
|
||||||
if(istype(location)) location.add_blood_floor(M)
|
|
||||||
if("fire")
|
|
||||||
if (!(COLD_RESISTANCE in M.mutations))
|
|
||||||
M.take_organ_damage(0, power)
|
|
||||||
M << "Aargh it burns!"
|
|
||||||
M.updatehealth()
|
|
||||||
add_fingerprint(user)
|
|
||||||
return 1
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/client/var/inquisitive_ghost = 1
|
/client/var/inquisitive_ghost = 1
|
||||||
/mob/dead/observer/verb/toggle_inquisition() // warning: unexpected inquisition
|
/mob/observer/dead/verb/toggle_inquisition() // warning: unexpected inquisition
|
||||||
set name = "Toggle Inquisitiveness"
|
set name = "Toggle Inquisitiveness"
|
||||||
set desc = "Sets whether your ghost examines everything on click by default"
|
set desc = "Sets whether your ghost examines everything on click by default"
|
||||||
set category = "Ghost"
|
set category = "Ghost"
|
||||||
@@ -10,25 +10,24 @@
|
|||||||
else
|
else
|
||||||
src << "<span class='notice'>You will no longer examine things you click on.</span>"
|
src << "<span class='notice'>You will no longer examine things you click on.</span>"
|
||||||
|
|
||||||
/mob/dead/observer/DblClickOn(var/atom/A, var/params)
|
/mob/observer/dead/DblClickOn(var/atom/A, var/params)
|
||||||
if(client.buildmode)
|
if(client.buildmode)
|
||||||
build_click(src, client.buildmode, params, A)
|
build_click(src, client.buildmode, params, A)
|
||||||
return
|
return
|
||||||
if(can_reenter_corpse && mind && mind.current)
|
if(can_reenter_corpse && mind && mind.current)
|
||||||
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
|
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
|
||||||
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
|
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
|
||||||
return // seems legit.
|
return
|
||||||
|
|
||||||
// Things you might plausibly want to follow
|
// Things you might plausibly want to follow
|
||||||
if((ismob(A) && A != src) || istype(A,/obj/singularity))
|
if(istype(A,/atom/movable))
|
||||||
ManualFollow(A)
|
ManualFollow(A)
|
||||||
|
|
||||||
// Otherwise jump
|
// Otherwise jump
|
||||||
else
|
else
|
||||||
following = null
|
following = null
|
||||||
forceMove(get_turf(A))
|
forceMove(get_turf(A))
|
||||||
|
|
||||||
/mob/dead/observer/ClickOn(var/atom/A, var/params)
|
/mob/observer/dead/ClickOn(var/atom/A, var/params)
|
||||||
if(client.buildmode)
|
if(client.buildmode)
|
||||||
build_click(src, client.buildmode, params, A)
|
build_click(src, client.buildmode, params, A)
|
||||||
return
|
return
|
||||||
@@ -39,7 +38,7 @@
|
|||||||
A.attack_ghost(src)
|
A.attack_ghost(src)
|
||||||
|
|
||||||
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
|
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
|
||||||
/atom/proc/attack_ghost(mob/dead/observer/user as mob)
|
/atom/proc/attack_ghost(mob/observer/dead/user as mob)
|
||||||
if(user.client && user.client.inquisitive_ghost)
|
if(user.client && user.client.inquisitive_ghost)
|
||||||
user.examinate(src)
|
user.examinate(src)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
if(!..())
|
if(!..())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
A.attack_generic(src,rand(5,6),"bitten")
|
A.attack_generic(src,rand(5,6),"bitten")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -76,6 +77,9 @@
|
|||||||
Feedstop()
|
Feedstop()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
//should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too
|
||||||
|
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
|
|
||||||
var/mob/living/M = A
|
var/mob/living/M = A
|
||||||
if (istype(M))
|
if (istype(M))
|
||||||
|
|
||||||
@@ -88,7 +92,7 @@
|
|||||||
if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime))
|
if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime))
|
||||||
if(ishuman(M))
|
if(ishuman(M))
|
||||||
var/mob/living/carbon/human/H = M
|
var/mob/living/carbon/human/H = M
|
||||||
stunprob *= H.species.siemens_coefficient
|
stunprob *= max(H.species.siemens_coefficient,0)
|
||||||
|
|
||||||
|
|
||||||
switch(power * 10)
|
switch(power * 10)
|
||||||
@@ -144,6 +148,7 @@
|
|||||||
custom_emote(1,"[friendly] [A]!")
|
custom_emote(1,"[friendly] [A]!")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||||
var/damage = rand(melee_damage_lower, melee_damage_upper)
|
var/damage = rand(melee_damage_lower, melee_damage_upper)
|
||||||
if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound)
|
if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound)
|
||||||
playsound(loc, attack_sound, 50, 1, 1)
|
playsound(loc, attack_sound, 50, 1, 1)
|
||||||
|
|||||||
@@ -107,20 +107,11 @@ var/const/tk_maxrange = 15
|
|||||||
return
|
return
|
||||||
|
|
||||||
var/d = get_dist(user, target)
|
var/d = get_dist(user, target)
|
||||||
if(focus) d = max(d,get_dist(user,focus)) // whichever is further
|
if(focus)
|
||||||
switch(d)
|
d = max(d, get_dist(user, focus)) // whichever is further
|
||||||
if(0)
|
if(d > tk_maxrange)
|
||||||
;
|
user << "<span class='notice'>Your mind won't reach that far.</span>"
|
||||||
if(1 to 5) // not adjacent may mean blocked by window
|
return
|
||||||
if(!proximity)
|
|
||||||
user.setMoveCooldown(2)
|
|
||||||
if(5 to 7)
|
|
||||||
user.setMoveCooldown(5)
|
|
||||||
if(8 to tk_maxrange)
|
|
||||||
user.setMoveCooldown(10)
|
|
||||||
else
|
|
||||||
user << "<span class='notice'>Your mind won't reach that far.</span>"
|
|
||||||
return
|
|
||||||
|
|
||||||
if(!focus)
|
if(!focus)
|
||||||
focus_object(target, user)
|
focus_object(target, user)
|
||||||
|
|||||||
10
code/_unit_tests.dm
Normal file
10
code/_unit_tests.dm
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This file is used by Travis to indicate that Unit Tests are to be ran.
|
||||||
|
* Do not add anything but the UNIT_TEST definition here as it will be overwritten by Travis when running tests.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Should you wish to edit set UNIT_TEST to 1 like so:
|
||||||
|
* #define UNIT_TEST 1
|
||||||
|
*/
|
||||||
|
#define UNIT_TEST 0
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// DM Environment file for ProcessScheduler.dme.
|
|
||||||
// All manual changes should be made outside the BEGIN_ and END_ blocks.
|
|
||||||
// New source code should be placed in .dm files: choose File/New --> Code File.
|
|
||||||
|
|
||||||
// BEGIN_INTERNALS
|
|
||||||
// END_INTERNALS
|
|
||||||
|
|
||||||
// BEGIN_FILE_DIR
|
|
||||||
#define FILE_DIR .
|
|
||||||
// END_FILE_DIR
|
|
||||||
|
|
||||||
// BEGIN_PREFERENCES
|
|
||||||
// END_PREFERENCES
|
|
||||||
|
|
||||||
// BEGIN_INCLUDE
|
|
||||||
#include "core\_define.dm"
|
|
||||||
#include "core\_stubs.dm"
|
|
||||||
#include "core\process.dm"
|
|
||||||
#include "core\processScheduler.dm"
|
|
||||||
#include "core\updateQueue.dm"
|
|
||||||
#include "core\updateQueueWorker.dm"
|
|
||||||
#include "test\processSchedulerView.dm"
|
|
||||||
#include "test\testDyingUpdateQueueProcess.dm"
|
|
||||||
#include "test\testHarness.dm"
|
|
||||||
#include "test\testHungProcess.dm"
|
|
||||||
#include "test\testNiceProcess.dm"
|
|
||||||
#include "test\testSlowProcess.dm"
|
|
||||||
#include "test\testUpdateQueue.dm"
|
|
||||||
#include "test\testUpdateQueueProcess.dm"
|
|
||||||
#include "test\testZombieProcess.dm"
|
|
||||||
// END_INCLUDE
|
|
||||||
|
|
||||||
@@ -4,15 +4,7 @@
|
|||||||
* This file contains constructs that the process scheduler expects to exist
|
* This file contains constructs that the process scheduler expects to exist
|
||||||
* in a standard ss13 fork.
|
* in a standard ss13 fork.
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
/**
|
|
||||||
* message_admins
|
|
||||||
*
|
|
||||||
* sends a message to admins
|
|
||||||
*/
|
|
||||||
/proc/message_admins(msg)
|
|
||||||
world << msg
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* logTheThing
|
* logTheThing
|
||||||
*
|
*
|
||||||
@@ -22,17 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
/proc/logTheThing(type, source, target, text, diaryType)
|
/proc/logTheThing(type, source, target, text, diaryType)
|
||||||
if(diaryType)
|
if(diaryType)
|
||||||
world << "Diary: \[[diaryType]:[type]] [text]"
|
log_debug("Diary: \[[diaryType]:[type]] [text]")
|
||||||
else
|
else
|
||||||
world << "Log: \[[type]] [text]"
|
log_debug("Log: \[[type]] [text]")
|
||||||
|
|
||||||
/**
|
|
||||||
* var/disposed
|
|
||||||
*
|
|
||||||
* In goonstation, disposed is set to 1 after an object enters the delete queue
|
|
||||||
* or the object is placed in an object pool (effectively out-of-play so to speak)
|
|
||||||
*/
|
|
||||||
/datum/var/disposed
|
|
||||||
// Garbage collection (controller).
|
|
||||||
/datum/var/gcDestroyed
|
|
||||||
/datum/var/timeDestroyed
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
// This controls how often the process will yield (call sleep(0)) while it is running.
|
// This controls how often the process will yield (call sleep(0)) while it is running.
|
||||||
// Every concurrent process should sleep periodically while running in order to allow other
|
// Every concurrent process should sleep periodically while running in order to allow other
|
||||||
// processes to execute concurrently.
|
// processes to execute concurrently.
|
||||||
var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL
|
var/tmp/sleep_interval
|
||||||
|
|
||||||
// hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window
|
// hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window
|
||||||
var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME
|
var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME
|
||||||
@@ -59,20 +59,20 @@
|
|||||||
// hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process.
|
// hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process.
|
||||||
var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME
|
var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME
|
||||||
|
|
||||||
// cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag)
|
|
||||||
var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD
|
|
||||||
|
|
||||||
// How many times in the current run has the process deferred work till the next tick?
|
// How many times in the current run has the process deferred work till the next tick?
|
||||||
var/tmp/cpu_defer_count = 0
|
var/tmp/cpu_defer_count = 0
|
||||||
|
|
||||||
|
// How many SCHECKs have been skipped (to limit btime calls)
|
||||||
|
var/tmp/calls_since_last_scheck = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* recordkeeping vars
|
* recordkeeping vars
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Records the time (server ticks) at which the process last finished sleeping
|
// Records the time (1/10s timeofday) at which the process last finished sleeping
|
||||||
var/tmp/last_slept = 0
|
var/tmp/last_slept = 0
|
||||||
|
|
||||||
// Records the time (s-ticks) at which the process last began running
|
// Records the time (1/10s timeofday) at which the process last began running
|
||||||
var/tmp/run_start = 0
|
var/tmp/run_start = 0
|
||||||
|
|
||||||
// Records the number of times this process has been killed and restarted
|
// Records the number of times this process has been killed and restarted
|
||||||
@@ -85,26 +85,33 @@
|
|||||||
|
|
||||||
var/tmp/last_object
|
var/tmp/last_object
|
||||||
|
|
||||||
datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
|
// Counts the number of times an exception has occurred; gets reset after 10
|
||||||
|
var/tmp/list/exceptions = list()
|
||||||
|
|
||||||
|
// Number of deciseconds to delay before starting the process
|
||||||
|
var/start_delay = 0
|
||||||
|
|
||||||
|
/datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
|
||||||
..()
|
..()
|
||||||
main = scheduler
|
main = scheduler
|
||||||
previousStatus = "idle"
|
previousStatus = "idle"
|
||||||
idle()
|
idle()
|
||||||
name = "process"
|
name = "process"
|
||||||
schedule_interval = 50
|
schedule_interval = 50
|
||||||
sleep_interval = 2
|
sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL
|
||||||
last_slept = 0
|
last_slept = 0
|
||||||
run_start = 0
|
run_start = 0
|
||||||
ticks = 0
|
ticks = 0
|
||||||
last_task = 0
|
last_task = 0
|
||||||
last_object = null
|
last_object = null
|
||||||
|
|
||||||
datum/controller/process/proc/started()
|
/datum/controller/process/proc/started()
|
||||||
|
var/timeofhour = TimeOfHour
|
||||||
// Initialize last_slept so we can know when to sleep
|
// Initialize last_slept so we can know when to sleep
|
||||||
last_slept = world.timeofday
|
last_slept = timeofhour
|
||||||
|
|
||||||
// Initialize run_start so we can detect hung processes.
|
// Initialize run_start so we can detect hung processes.
|
||||||
run_start = world.timeofday
|
run_start = timeofhour
|
||||||
|
|
||||||
// Initialize defer count
|
// Initialize defer count
|
||||||
cpu_defer_count = 0
|
cpu_defer_count = 0
|
||||||
@@ -114,65 +121,65 @@ datum/controller/process/proc/started()
|
|||||||
|
|
||||||
onStart()
|
onStart()
|
||||||
|
|
||||||
datum/controller/process/proc/finished()
|
/datum/controller/process/proc/finished()
|
||||||
ticks++
|
ticks++
|
||||||
idle()
|
idle()
|
||||||
main.processFinished(src)
|
main.processFinished(src)
|
||||||
|
|
||||||
onFinish()
|
onFinish()
|
||||||
|
|
||||||
datum/controller/process/proc/doWork()
|
/datum/controller/process/proc/doWork()
|
||||||
|
|
||||||
datum/controller/process/proc/setup()
|
/datum/controller/process/proc/setup()
|
||||||
|
|
||||||
datum/controller/process/proc/process()
|
/datum/controller/process/proc/process()
|
||||||
started()
|
started()
|
||||||
doWork()
|
doWork()
|
||||||
finished()
|
finished()
|
||||||
|
|
||||||
datum/controller/process/proc/running()
|
/datum/controller/process/proc/running()
|
||||||
idle = 0
|
idle = 0
|
||||||
queued = 0
|
queued = 0
|
||||||
running = 1
|
running = 1
|
||||||
hung = 0
|
hung = 0
|
||||||
setStatus(PROCESS_STATUS_RUNNING)
|
setStatus(PROCESS_STATUS_RUNNING)
|
||||||
|
|
||||||
datum/controller/process/proc/idle()
|
/datum/controller/process/proc/idle()
|
||||||
queued = 0
|
queued = 0
|
||||||
running = 0
|
running = 0
|
||||||
idle = 1
|
idle = 1
|
||||||
hung = 0
|
hung = 0
|
||||||
setStatus(PROCESS_STATUS_IDLE)
|
setStatus(PROCESS_STATUS_IDLE)
|
||||||
|
|
||||||
datum/controller/process/proc/queued()
|
/datum/controller/process/proc/queued()
|
||||||
idle = 0
|
idle = 0
|
||||||
running = 0
|
running = 0
|
||||||
queued = 1
|
queued = 1
|
||||||
hung = 0
|
hung = 0
|
||||||
setStatus(PROCESS_STATUS_QUEUED)
|
setStatus(PROCESS_STATUS_QUEUED)
|
||||||
|
|
||||||
datum/controller/process/proc/hung()
|
/datum/controller/process/proc/hung()
|
||||||
hung = 1
|
hung = 1
|
||||||
setStatus(PROCESS_STATUS_HUNG)
|
setStatus(PROCESS_STATUS_HUNG)
|
||||||
|
|
||||||
datum/controller/process/proc/handleHung()
|
/datum/controller/process/proc/handleHung()
|
||||||
|
var/timeofhour = TimeOfHour
|
||||||
var/datum/lastObj = last_object
|
var/datum/lastObj = last_object
|
||||||
var/lastObjType = "null"
|
var/lastObjType = "null"
|
||||||
if(istype(lastObj))
|
if(istype(lastObj))
|
||||||
lastObjType = lastObj.type
|
lastObjType = lastObj.type
|
||||||
|
|
||||||
// If world.timeofday has rolled over, then we need to adjust.
|
// If timeofhour has rolled over, then we need to adjust.
|
||||||
if (world.timeofday < run_start)
|
if (timeofhour < run_start)
|
||||||
run_start -= 864000
|
run_start -= 36000
|
||||||
|
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(timeofhour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
|
||||||
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(world.timeofday - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
|
|
||||||
logTheThing("debug", null, null, msg)
|
logTheThing("debug", null, null, msg)
|
||||||
logTheThing("diary", null, null, msg, "debug")
|
logTheThing("diary", null, null, msg, "debug")
|
||||||
message_admins(msg)
|
message_admins(msg)
|
||||||
|
|
||||||
main.restartProcess(src.name)
|
main.restartProcess(src.name)
|
||||||
|
|
||||||
datum/controller/process/proc/kill()
|
/datum/controller/process/proc/kill()
|
||||||
if (!killed)
|
if (!killed)
|
||||||
var/msg = "[name] process was killed at tick #[ticks]."
|
var/msg = "[name] process was killed at tick #[ticks]."
|
||||||
logTheThing("debug", null, null, msg)
|
logTheThing("debug", null, null, msg)
|
||||||
@@ -182,59 +189,68 @@ datum/controller/process/proc/kill()
|
|||||||
// Allow inheritors to clean up if needed
|
// Allow inheritors to clean up if needed
|
||||||
onKill()
|
onKill()
|
||||||
|
|
||||||
killed = TRUE
|
// This should del
|
||||||
|
del(src)
|
||||||
|
|
||||||
del(src) // This should del
|
// Do not call this directly - use SHECK or SCHECK_EVERY
|
||||||
|
/datum/controller/process/proc/sleepCheck(var/tickId = 0)
|
||||||
datum/controller/process/proc/scheck(var/tickId = 0)
|
calls_since_last_scheck = 0
|
||||||
if (killed)
|
if (killed)
|
||||||
// The kill proc is the only place where killed is set.
|
// The kill proc is the only place where killed is set.
|
||||||
// The kill proc should have deleted this datum, and all sleeping procs that are
|
// The kill proc should have deleted this datum, and all sleeping procs that are
|
||||||
// owned by it.
|
// owned by it.
|
||||||
CRASH("A killed process is still running somehow...")
|
CRASH("A killed process is still running somehow...")
|
||||||
|
if (hung)
|
||||||
|
// This will only really help if the doWork proc ends up in an infinite loop.
|
||||||
|
handleHung()
|
||||||
|
CRASH("Process [name] hung and was restarted.")
|
||||||
|
|
||||||
// For each tick the process defers, it increments the cpu_defer_count so we don't
|
if (main.getCurrentTickElapsedTime() > main.timeAllowance)
|
||||||
// defer indefinitely
|
sleep(world.tick_lag)
|
||||||
if (world.cpu >= cpu_threshold + cpu_defer_count * 10)
|
|
||||||
sleep(1)
|
|
||||||
cpu_defer_count++
|
cpu_defer_count++
|
||||||
last_slept = world.timeofday
|
last_slept = TimeOfHour
|
||||||
else
|
else
|
||||||
// If world.timeofday has rolled over, then we need to adjust.
|
var/timeofhour = TimeOfHour
|
||||||
if (world.timeofday < last_slept)
|
// If timeofhour has rolled over, then we need to adjust.
|
||||||
last_slept -= 864000
|
if (timeofhour < last_slept)
|
||||||
|
last_slept -= 36000
|
||||||
|
|
||||||
if (world.timeofday > last_slept + sleep_interval)
|
if (timeofhour > last_slept + sleep_interval)
|
||||||
// If we haven't slept in sleep_interval ticks, sleep to allow other work to proceed.
|
// If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed.
|
||||||
sleep(0)
|
sleep(0)
|
||||||
last_slept = world.timeofday
|
last_slept = TimeOfHour
|
||||||
|
|
||||||
datum/controller/process/proc/update()
|
/datum/controller/process/proc/update()
|
||||||
// Clear delta
|
// Clear delta
|
||||||
if(previousStatus != status)
|
if(previousStatus != status)
|
||||||
setStatus(status)
|
setStatus(status)
|
||||||
|
|
||||||
var/elapsedTime = getElapsedTime()
|
var/elapsedTime = getElapsedTime()
|
||||||
|
|
||||||
if (elapsedTime > hang_restart_time)
|
if (hung)
|
||||||
|
handleHung()
|
||||||
|
return
|
||||||
|
else if (elapsedTime > hang_restart_time)
|
||||||
hung()
|
hung()
|
||||||
else if (elapsedTime > hang_alert_time)
|
else if (elapsedTime > hang_alert_time)
|
||||||
setStatus(PROCESS_STATUS_PROBABLY_HUNG)
|
setStatus(PROCESS_STATUS_PROBABLY_HUNG)
|
||||||
else if (elapsedTime > hang_warning_time)
|
else if (elapsedTime > hang_warning_time)
|
||||||
setStatus(PROCESS_STATUS_MAYBE_HUNG)
|
setStatus(PROCESS_STATUS_MAYBE_HUNG)
|
||||||
|
|
||||||
datum/controller/process/proc/getElapsedTime()
|
|
||||||
if (world.timeofday < run_start)
|
|
||||||
return world.timeofday - (run_start - 864000)
|
|
||||||
return world.timeofday - run_start
|
|
||||||
|
|
||||||
datum/controller/process/proc/tickDetail()
|
/datum/controller/process/proc/getElapsedTime()
|
||||||
|
var/timeofhour = TimeOfHour
|
||||||
|
if (timeofhour < run_start)
|
||||||
|
return timeofhour - (run_start - 36000)
|
||||||
|
return timeofhour - run_start
|
||||||
|
|
||||||
|
/datum/controller/process/proc/tickDetail()
|
||||||
return
|
return
|
||||||
|
|
||||||
datum/controller/process/proc/getContext()
|
/datum/controller/process/proc/getContext()
|
||||||
return "<tr><td>[name]</td><td>[main.averageRunTime(src)]</td><td>[main.last_run_time[src]]</td><td>[main.highest_run_time[src]]</td><td>[ticks]</td></tr>\n"
|
return "<tr><td>[name]</td><td>[main.averageRunTime(src)]</td><td>[main.last_run_time[src]]</td><td>[main.highest_run_time[src]]</td><td>[ticks]</td></tr>\n"
|
||||||
|
|
||||||
datum/controller/process/proc/getContextData()
|
/datum/controller/process/proc/getContextData()
|
||||||
return list(
|
return list(
|
||||||
"name" = name,
|
"name" = name,
|
||||||
"averageRunTime" = main.averageRunTime(src),
|
"averageRunTime" = main.averageRunTime(src),
|
||||||
@@ -246,10 +262,10 @@ datum/controller/process/proc/getContextData()
|
|||||||
"disabled" = disabled
|
"disabled" = disabled
|
||||||
)
|
)
|
||||||
|
|
||||||
datum/controller/process/proc/getStatus()
|
/datum/controller/process/proc/getStatus()
|
||||||
return status
|
return status
|
||||||
|
|
||||||
datum/controller/process/proc/getStatusText(var/s = 0)
|
/datum/controller/process/proc/getStatusText(var/s = 0)
|
||||||
if(!s)
|
if(!s)
|
||||||
s = status
|
s = status
|
||||||
switch(s)
|
switch(s)
|
||||||
@@ -268,21 +284,21 @@ datum/controller/process/proc/getStatusText(var/s = 0)
|
|||||||
else
|
else
|
||||||
return "UNKNOWN"
|
return "UNKNOWN"
|
||||||
|
|
||||||
datum/controller/process/proc/getPreviousStatus()
|
/datum/controller/process/proc/getPreviousStatus()
|
||||||
return previousStatus
|
return previousStatus
|
||||||
|
|
||||||
datum/controller/process/proc/getPreviousStatusText()
|
/datum/controller/process/proc/getPreviousStatusText()
|
||||||
return getStatusText(previousStatus)
|
return getStatusText(previousStatus)
|
||||||
|
|
||||||
datum/controller/process/proc/setStatus(var/newStatus)
|
/datum/controller/process/proc/setStatus(var/newStatus)
|
||||||
previousStatus = status
|
previousStatus = status
|
||||||
status = newStatus
|
status = newStatus
|
||||||
|
|
||||||
datum/controller/process/proc/setLastTask(var/task, var/object)
|
/datum/controller/process/proc/setLastTask(var/task, var/object)
|
||||||
last_task = task
|
last_task = task
|
||||||
last_object = object
|
last_object = object
|
||||||
|
|
||||||
datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
|
/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
|
||||||
main = target.main
|
main = target.main
|
||||||
name = target.name
|
name = target.name
|
||||||
schedule_interval = target.schedule_interval
|
schedule_interval = target.schedule_interval
|
||||||
@@ -295,28 +311,62 @@ datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target
|
|||||||
last_object = target.last_object
|
last_object = target.last_object
|
||||||
copyStateFrom(target)
|
copyStateFrom(target)
|
||||||
|
|
||||||
datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
|
/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
|
||||||
|
|
||||||
datum/controller/process/proc/onKill()
|
/datum/controller/process/proc/onKill()
|
||||||
|
|
||||||
datum/controller/process/proc/onStart()
|
/datum/controller/process/proc/onStart()
|
||||||
|
|
||||||
datum/controller/process/proc/onFinish()
|
/datum/controller/process/proc/onFinish()
|
||||||
|
|
||||||
datum/controller/process/proc/disable()
|
/datum/controller/process/proc/disable()
|
||||||
disabled = 1
|
disabled = 1
|
||||||
|
|
||||||
datum/controller/process/proc/enable()
|
/datum/controller/process/proc/enable()
|
||||||
disabled = 0
|
disabled = 0
|
||||||
|
|
||||||
|
/datum/controller/process/proc/getAverageRunTime()
|
||||||
|
return main.averageRunTime(src)
|
||||||
/datum/controller/process/proc/getLastRunTime()
|
/datum/controller/process/proc/getLastRunTime()
|
||||||
return main.getProcessLastRunTime(src)
|
return main.getProcessLastRunTime(src)
|
||||||
|
|
||||||
|
/datum/controller/process/proc/getHighestRunTime()
|
||||||
|
return main.getProcessHighestRunTime(src)
|
||||||
|
|
||||||
/datum/controller/process/proc/getTicks()
|
/datum/controller/process/proc/getTicks()
|
||||||
return ticks
|
return ticks
|
||||||
|
|
||||||
/datum/controller/process/proc/getStatName()
|
/datum/controller/process/proc/statProcess()
|
||||||
return name
|
var/averageRunTime = round(getAverageRunTime(), 0.1)/10
|
||||||
|
var/lastRunTime = round(getLastRunTime(), 0.1)/10
|
||||||
|
var/highestRunTime = round(getHighestRunTime(), 0.1)/10
|
||||||
|
stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [cpu_defer_count]")
|
||||||
|
|
||||||
/datum/controller/process/proc/getTickTime()
|
/datum/controller/process/proc/catchException(var/exception/e, var/thrower)
|
||||||
return "#[getTicks()]\t- [getLastRunTime()]"
|
var/etext = "[e]"
|
||||||
|
var/eid = "[e]" // Exception ID, for tracking repeated exceptions
|
||||||
|
var/ptext = "" // "processing..." text, for what was being processed (if known)
|
||||||
|
if(istype(e))
|
||||||
|
etext += " in [e.file], line [e.line]"
|
||||||
|
eid = "[e.file]:[e.line]"
|
||||||
|
if(eid in exceptions)
|
||||||
|
if(exceptions[eid]++ >= 10)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
exceptions[eid] = 1
|
||||||
|
if(istype(thrower, /datum))
|
||||||
|
var/datum/D = thrower
|
||||||
|
ptext = " processing [D.type]"
|
||||||
|
if(istype(thrower, /atom))
|
||||||
|
var/atom/A = thrower
|
||||||
|
ptext += " ([A]) ([A.x],[A.y],[A.z])"
|
||||||
|
log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]")
|
||||||
|
if(exceptions[eid] >= 10)
|
||||||
|
log_to_dd("This exception will now be ignored for ten minutes.")
|
||||||
|
spawn(6000)
|
||||||
|
exceptions[eid] = 0
|
||||||
|
|
||||||
|
/datum/controller/process/proc/catchBadType(var/datum/caught)
|
||||||
|
if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed))
|
||||||
|
return // Only bother with types we can identify and that don't belong
|
||||||
|
catchException("Type [caught.type] does not belong in process' queue")
|
||||||
@@ -17,7 +17,10 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
// Process name -> process object map
|
// Process name -> process object map
|
||||||
var/tmp/datum/controller/process/list/nameToProcessMap = new
|
var/tmp/datum/controller/process/list/nameToProcessMap = new
|
||||||
|
|
||||||
// Process last start times
|
// Process last queued times (world time)
|
||||||
|
var/tmp/datum/controller/process/list/last_queued = new
|
||||||
|
|
||||||
|
// Process last start times (real time)
|
||||||
var/tmp/datum/controller/process/list/last_start = new
|
var/tmp/datum/controller/process/list/last_start = new
|
||||||
|
|
||||||
// Process last run durations
|
// Process last run durations
|
||||||
@@ -29,8 +32,8 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
// Process highest run time
|
// Process highest run time
|
||||||
var/tmp/datum/controller/process/list/highest_run_time = new
|
var/tmp/datum/controller/process/list/highest_run_time = new
|
||||||
|
|
||||||
// Sleep 1 tick -- This may be too aggressive.
|
// How long to sleep between runs (set to tick_lag in New)
|
||||||
var/tmp/scheduler_sleep_interval = 1
|
var/tmp/scheduler_sleep_interval
|
||||||
|
|
||||||
// Controls whether the scheduler is running or not
|
// Controls whether the scheduler is running or not
|
||||||
var/tmp/isRunning = 0
|
var/tmp/isRunning = 0
|
||||||
@@ -38,6 +41,25 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
// Setup for these processes will be deferred until all the other processes are set up.
|
// Setup for these processes will be deferred until all the other processes are set up.
|
||||||
var/tmp/list/deferredSetupList = new
|
var/tmp/list/deferredSetupList = new
|
||||||
|
|
||||||
|
var/tmp/currentTick = 0
|
||||||
|
|
||||||
|
var/tmp/currentTickStart = 0
|
||||||
|
|
||||||
|
var/tmp/timeAllowance = 0
|
||||||
|
|
||||||
|
var/tmp/cpuAverage = 0
|
||||||
|
|
||||||
|
var/tmp/timeAllowanceMax = 0
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/New()
|
||||||
|
..()
|
||||||
|
// When the process scheduler is first new'd, tick_lag may be wrong, so these
|
||||||
|
// get re-initialized when the process scheduler is started.
|
||||||
|
// (These are kept here for any processes that decide to process before round start)
|
||||||
|
scheduler_sleep_interval = world.tick_lag
|
||||||
|
timeAllowance = world.tick_lag * 0.5
|
||||||
|
timeAllowanceMax = world.tick_lag
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* deferSetupFor
|
* deferSetupFor
|
||||||
* @param path processPath
|
* @param path processPath
|
||||||
@@ -57,7 +79,7 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
|
|
||||||
var/process
|
var/process
|
||||||
// Add all the processes we can find, except for the ticker
|
// Add all the processes we can find, except for the ticker
|
||||||
for (process in typesof(/datum/controller/process) - /datum/controller/process)
|
for (process in subtypesof(/datum/controller/process))
|
||||||
if (!(process in deferredSetupList))
|
if (!(process in deferredSetupList))
|
||||||
addProcess(new process(src))
|
addProcess(new process(src))
|
||||||
|
|
||||||
@@ -66,11 +88,22 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
|
|
||||||
/datum/controller/processScheduler/proc/start()
|
/datum/controller/processScheduler/proc/start()
|
||||||
isRunning = 1
|
isRunning = 1
|
||||||
|
// tick_lag will have been set by now, so re-initialize these
|
||||||
|
scheduler_sleep_interval = world.tick_lag
|
||||||
|
timeAllowance = world.tick_lag * 0.5
|
||||||
|
timeAllowanceMax = world.tick_lag
|
||||||
|
updateStartDelays()
|
||||||
spawn(0)
|
spawn(0)
|
||||||
process()
|
process()
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/process()
|
/datum/controller/processScheduler/proc/process()
|
||||||
|
updateCurrentTickData()
|
||||||
|
|
||||||
|
for(var/i=world.tick_lag,i<world.tick_lag*50,i+=world.tick_lag)
|
||||||
|
spawn(i) updateCurrentTickData()
|
||||||
while(isRunning)
|
while(isRunning)
|
||||||
|
// Hopefully spawning this for 50 ticks in the future will make it the first thing in the queue.
|
||||||
|
spawn(world.tick_lag*50) updateCurrentTickData()
|
||||||
checkRunningProcesses()
|
checkRunningProcesses()
|
||||||
queueProcesses()
|
queueProcesses()
|
||||||
runQueuedProcesses()
|
runQueuedProcesses()
|
||||||
@@ -92,15 +125,11 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
// Check status changes
|
// Check status changes
|
||||||
if(status != previousStatus)
|
if(status != previousStatus)
|
||||||
//Status changed.
|
//Status changed.
|
||||||
|
|
||||||
switch(status)
|
switch(status)
|
||||||
if(PROCESS_STATUS_MAYBE_HUNG)
|
|
||||||
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
|
|
||||||
if(PROCESS_STATUS_PROBABLY_HUNG)
|
if(PROCESS_STATUS_PROBABLY_HUNG)
|
||||||
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
|
message_admins("Process '[p.name]' may be hung.")
|
||||||
if(PROCESS_STATUS_HUNG)
|
if(PROCESS_STATUS_HUNG)
|
||||||
message_admins("Process '[p.name]' is [p.getStatusText(status)].")
|
message_admins("Process '[p.name]' is hung and will be restarted.")
|
||||||
p.handleHung()
|
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/queueProcesses()
|
/datum/controller/processScheduler/proc/queueProcesses()
|
||||||
for(var/datum/controller/process/p in processes)
|
for(var/datum/controller/process/p in processes)
|
||||||
@@ -108,12 +137,8 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
if (p.disabled || p.running || p.queued || !p.idle)
|
if (p.disabled || p.running || p.queued || !p.idle)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
// If world.timeofday has rolled over, then we need to adjust.
|
|
||||||
if (world.timeofday < last_start[p])
|
|
||||||
last_start[p] -= 864000
|
|
||||||
|
|
||||||
// If the process should be running by now, go ahead and queue it
|
// If the process should be running by now, go ahead and queue it
|
||||||
if (world.timeofday > last_start[p] + p.schedule_interval)
|
if (world.time >= last_queued[p] + p.schedule_interval)
|
||||||
setQueuedProcessState(p)
|
setQueuedProcessState(p)
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/runQueuedProcesses()
|
/datum/controller/processScheduler/proc/runQueuedProcesses()
|
||||||
@@ -176,6 +201,10 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
|
|
||||||
nameToProcessMap[newProcess.name] = newProcess
|
nameToProcessMap[newProcess.name] = newProcess
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/proc/updateStartDelays()
|
||||||
|
for(var/datum/controller/process/p in processes)
|
||||||
|
if(p.start_delay)
|
||||||
|
last_queued[p] = world.time - p.start_delay
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process)
|
/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process)
|
||||||
spawn(0)
|
spawn(0)
|
||||||
@@ -197,8 +226,6 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
if (!(process in idle))
|
if (!(process in idle))
|
||||||
idle += process
|
idle += process
|
||||||
|
|
||||||
process.idle()
|
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process)
|
/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process)
|
||||||
if (process in running)
|
if (process in running)
|
||||||
running -= process
|
running -= process
|
||||||
@@ -218,21 +245,22 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
if (!(process in running))
|
if (!(process in running))
|
||||||
running += process
|
running += process
|
||||||
|
|
||||||
process.running()
|
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null)
|
/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null)
|
||||||
if (isnull(time))
|
if (isnull(time))
|
||||||
time = world.timeofday
|
time = TimeOfHour
|
||||||
|
last_queued[process] = world.time
|
||||||
last_start[process] = time
|
last_start[process] = time
|
||||||
|
else
|
||||||
|
last_queued[process] = (time == 0 ? 0 : world.time)
|
||||||
|
last_start[process] = time
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null)
|
/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null)
|
||||||
if (isnull(time))
|
if (isnull(time))
|
||||||
time = world.timeofday
|
time = TimeOfHour
|
||||||
|
|
||||||
// If world.timeofday has rolled over, then we need to adjust.
|
// If world.timeofday has rolled over, then we need to adjust.
|
||||||
if (time < last_start[process])
|
if (time < last_start[process])
|
||||||
last_start[process] -= 864000
|
last_start[process] -= 36000
|
||||||
|
|
||||||
var/lastRunTime = time - last_start[process]
|
var/lastRunTime = time - last_start[process]
|
||||||
|
|
||||||
@@ -273,6 +301,12 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
return t / c
|
return t / c
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process)
|
||||||
|
return last_run_time[process]
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process)
|
||||||
|
return highest_run_time[process]
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/getStatusData()
|
/datum/controller/processScheduler/proc/getStatusData()
|
||||||
var/list/data = new
|
var/list/data = new
|
||||||
|
|
||||||
@@ -310,11 +344,39 @@ var/global/datum/controller/processScheduler/processScheduler
|
|||||||
var/datum/controller/process/process = nameToProcessMap[processName]
|
var/datum/controller/process/process = nameToProcessMap[processName]
|
||||||
process.disable()
|
process.disable()
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/getProcess(var/name)
|
/datum/controller/processScheduler/proc/getCurrentTickElapsedTime()
|
||||||
return nameToProcessMap[name]
|
if (world.time > currentTick)
|
||||||
|
updateCurrentTickData()
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return TimeOfHour - currentTickStart
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process)
|
/datum/controller/processScheduler/proc/updateCurrentTickData()
|
||||||
return last_run_time[process]
|
if (world.time > currentTick)
|
||||||
|
// New tick!
|
||||||
|
currentTick = world.time
|
||||||
|
currentTickStart = TimeOfHour
|
||||||
|
updateTimeAllowance()
|
||||||
|
cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3
|
||||||
|
|
||||||
/datum/controller/processScheduler/proc/getIsRunning()
|
/datum/controller/processScheduler/proc/updateTimeAllowance()
|
||||||
return isRunning
|
// Time allowance goes down linearly with world.cpu.
|
||||||
|
var/tmp/error = cpuAverage - 100
|
||||||
|
var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error))
|
||||||
|
|
||||||
|
//timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1))
|
||||||
|
timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta))
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/proc/sign(var/x)
|
||||||
|
if (x == 0)
|
||||||
|
return 1
|
||||||
|
return x / abs(x)
|
||||||
|
|
||||||
|
/datum/controller/processScheduler/proc/statProcesses()
|
||||||
|
if(!isRunning)
|
||||||
|
stat("Processes", "Scheduler not running")
|
||||||
|
return
|
||||||
|
stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])")
|
||||||
|
stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA")
|
||||||
|
for(var/datum/controller/process/p in processes)
|
||||||
|
p.statProcess()
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
/**
|
|
||||||
* updateQueue.dm
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef UPDATE_QUEUE_DEBUG
|
|
||||||
#define uq_dbg(text) world << text
|
|
||||||
#else
|
|
||||||
#define uq_dbg(text)
|
|
||||||
#endif
|
|
||||||
/datum/updateQueue
|
|
||||||
var/tmp/list/objects
|
|
||||||
var/tmp/previousStart
|
|
||||||
var/tmp/procName
|
|
||||||
var/tmp/list/arguments
|
|
||||||
var/tmp/datum/updateQueueWorker/currentWorker
|
|
||||||
var/tmp/workerTimeout
|
|
||||||
var/tmp/adjustedWorkerTimeout
|
|
||||||
var/tmp/currentKillCount
|
|
||||||
var/tmp/totalKillCount
|
|
||||||
|
|
||||||
/datum/updateQueue/New(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0)
|
|
||||||
..()
|
|
||||||
|
|
||||||
uq_dbg("Update queue created.")
|
|
||||||
|
|
||||||
// Init proc allows for recycling the worker.
|
|
||||||
init(objects = objects, procName = procName, arguments = arguments, workerTimeout = workerTimeout, inplace = inplace)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* init
|
|
||||||
* @param list objects objects to update
|
|
||||||
* @param text procName the proc to call on each item in the object list
|
|
||||||
* @param list arguments optional arguments to pass to the update proc
|
|
||||||
* @param number workerTimeout number of ticks to wait for an update to
|
|
||||||
finish before forking a new update worker
|
|
||||||
* @param bool inplace whether the updateQueue should make a copy of objects.
|
|
||||||
the internal list will be modified, so it is usually
|
|
||||||
a good idea to leave this alone. Default behavior is to
|
|
||||||
copy.
|
|
||||||
*/
|
|
||||||
/datum/updateQueue/proc/init(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0)
|
|
||||||
uq_dbg("Update queue initialization started.")
|
|
||||||
|
|
||||||
if (!inplace)
|
|
||||||
// Make an internal copy of the list so we're not modifying the original.
|
|
||||||
initList(objects)
|
|
||||||
else
|
|
||||||
src.objects = objects
|
|
||||||
|
|
||||||
// Init vars
|
|
||||||
src.procName = procName
|
|
||||||
src.arguments = arguments
|
|
||||||
src.workerTimeout = workerTimeout
|
|
||||||
|
|
||||||
adjustedWorkerTimeout = workerTimeout
|
|
||||||
currentKillCount = 0
|
|
||||||
totalKillCount = 0
|
|
||||||
|
|
||||||
uq_dbg("Update queue initialization finished. procName = '[procName]'")
|
|
||||||
|
|
||||||
/datum/updateQueue/proc/initList(list/toCopy)
|
|
||||||
/**
|
|
||||||
* We will copy the list in reverse order, as our doWork proc
|
|
||||||
* will access them by popping an element off the end of the list.
|
|
||||||
* This ends up being quite a lot faster than taking elements off
|
|
||||||
* the head of the list.
|
|
||||||
*/
|
|
||||||
objects = new
|
|
||||||
|
|
||||||
uq_dbg("Copying [toCopy.len] items for processing.")
|
|
||||||
|
|
||||||
for(var/i=toCopy.len,i>0,)
|
|
||||||
objects.len++
|
|
||||||
objects[objects.len] = toCopy[i--]
|
|
||||||
|
|
||||||
/datum/updateQueue/proc/Run()
|
|
||||||
uq_dbg("Starting run...")
|
|
||||||
|
|
||||||
startWorker()
|
|
||||||
while (istype(currentWorker) && !currentWorker.finished)
|
|
||||||
sleep(2)
|
|
||||||
checkWorker()
|
|
||||||
|
|
||||||
uq_dbg("UpdateQueue completed run.")
|
|
||||||
|
|
||||||
/datum/updateQueue/proc/checkWorker()
|
|
||||||
if(istype(currentWorker))
|
|
||||||
// If world.timeofday has rolled over, then we need to adjust.
|
|
||||||
if(world.timeofday < currentWorker.lastStart)
|
|
||||||
currentWorker.lastStart -= 864000
|
|
||||||
|
|
||||||
if(world.timeofday - currentWorker.lastStart > adjustedWorkerTimeout)
|
|
||||||
// This worker is a bit slow, let's spawn a new one and kill the old one.
|
|
||||||
uq_dbg("Current worker is lagging... starting a new one.")
|
|
||||||
killWorker()
|
|
||||||
startWorker()
|
|
||||||
else // No worker!
|
|
||||||
uq_dbg("update queue ended up without a worker... starting a new one...")
|
|
||||||
startWorker()
|
|
||||||
|
|
||||||
/datum/updateQueue/proc/startWorker()
|
|
||||||
// only run the worker if we have objects to work on
|
|
||||||
if(objects.len)
|
|
||||||
uq_dbg("Starting worker process.")
|
|
||||||
|
|
||||||
// No need to create a fresh worker if we already have one...
|
|
||||||
if (istype(currentWorker))
|
|
||||||
currentWorker.init(objects, procName, arguments)
|
|
||||||
else
|
|
||||||
currentWorker = new(objects, procName, arguments)
|
|
||||||
currentWorker.start()
|
|
||||||
else
|
|
||||||
uq_dbg("Queue is empty. No worker was started.")
|
|
||||||
currentWorker = null
|
|
||||||
|
|
||||||
/datum/updateQueue/proc/killWorker()
|
|
||||||
// Kill the worker
|
|
||||||
currentWorker.kill()
|
|
||||||
currentWorker = null
|
|
||||||
// After we kill a worker, yield so that if the worker's been tying up the cpu, other stuff can immediately resume
|
|
||||||
sleep(-1)
|
|
||||||
currentKillCount++
|
|
||||||
totalKillCount++
|
|
||||||
if (currentKillCount >= 3)
|
|
||||||
uq_dbg("[currentKillCount] workers have been killed with a timeout of [adjustedWorkerTimeout]. Increasing worker timeout to compensate.")
|
|
||||||
adjustedWorkerTimeout++
|
|
||||||
currentKillCount = 0
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
datum/updateQueueWorker
|
|
||||||
var/tmp/list/objects
|
|
||||||
var/tmp/killed
|
|
||||||
var/tmp/finished
|
|
||||||
var/tmp/procName
|
|
||||||
var/tmp/list/arguments
|
|
||||||
var/tmp/lastStart
|
|
||||||
var/tmp/cpuThreshold
|
|
||||||
|
|
||||||
datum/updateQueueWorker/New(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90)
|
|
||||||
..()
|
|
||||||
uq_dbg("updateQueueWorker created.")
|
|
||||||
|
|
||||||
init(objects, procName, arguments, cpuThreshold)
|
|
||||||
|
|
||||||
datum/updateQueueWorker/proc/init(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90)
|
|
||||||
src.objects = objects
|
|
||||||
src.procName = procName
|
|
||||||
src.arguments = arguments
|
|
||||||
src.cpuThreshold = cpuThreshold
|
|
||||||
|
|
||||||
killed = 0
|
|
||||||
finished = 0
|
|
||||||
|
|
||||||
datum/updateQueueWorker/proc/doWork()
|
|
||||||
// If there's nothing left to execute or we were killed, mark finished and return.
|
|
||||||
if (!objects || !objects.len) return finished()
|
|
||||||
|
|
||||||
lastStart = world.timeofday // Absolute number of ticks since the world started up
|
|
||||||
|
|
||||||
var/datum/object = objects[objects.len] // Pull out the object
|
|
||||||
objects.len-- // Remove the object from the list
|
|
||||||
|
|
||||||
if (istype(object) && !isturf(object) && !object.disposed && isnull(object.gcDestroyed)) // We only work with real objects
|
|
||||||
call(object, procName)(arglist(arguments))
|
|
||||||
|
|
||||||
// If there's nothing left to execute
|
|
||||||
// or we were killed while running the above code, mark finished and return.
|
|
||||||
if (!objects || !objects.len) return finished()
|
|
||||||
|
|
||||||
if (world.cpu > cpuThreshold)
|
|
||||||
// We don't want to force a tick into overtime!
|
|
||||||
// If the tick is about to go overtime, spawn the next update to go
|
|
||||||
// in the next tick.
|
|
||||||
uq_dbg("tick went into overtime with world.cpu = [world.cpu], deferred next update to next tick [1+(world.time / world.tick_lag)]")
|
|
||||||
|
|
||||||
spawn(1)
|
|
||||||
doWork()
|
|
||||||
else
|
|
||||||
spawn(0) // Execute anonymous function immediately as if we were in a while loop...
|
|
||||||
doWork()
|
|
||||||
|
|
||||||
datum/updateQueueWorker/proc/finished()
|
|
||||||
uq_dbg("updateQueueWorker finished.")
|
|
||||||
/**
|
|
||||||
* If the worker was killed while it was working on something, it
|
|
||||||
* should delete itself when it finally finishes working on it.
|
|
||||||
* Meanwhile, the updateQueue will have proceeded on with the rest of
|
|
||||||
* the queue. This will also terminate the spawned function that was
|
|
||||||
* created in the kill() proc.
|
|
||||||
*/
|
|
||||||
if(killed)
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
finished = 1
|
|
||||||
|
|
||||||
datum/updateQueueWorker/proc/kill()
|
|
||||||
uq_dbg("updateQueueWorker killed.")
|
|
||||||
killed = 1
|
|
||||||
objects = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the worker is not done in 30 seconds after it's killed,
|
|
||||||
* we'll forcibly delete it, causing the anonymous function it was
|
|
||||||
* running to be terminated. Hasta la vista, baby.
|
|
||||||
*/
|
|
||||||
spawn(300)
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
datum/updateQueueWorker/proc/start()
|
|
||||||
uq_dbg("updateQueueWorker started.")
|
|
||||||
spawn(0)
|
|
||||||
doWork()
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/datum/processSchedulerView
|
|
||||||
|
|
||||||
/datum/processSchedulerView/Topic(href, href_list)
|
|
||||||
if (!href_list["action"])
|
|
||||||
return
|
|
||||||
|
|
||||||
switch (href_list["action"])
|
|
||||||
if ("kill")
|
|
||||||
var/toKill = href_list["name"]
|
|
||||||
processScheduler.killProcess(toKill)
|
|
||||||
refreshProcessTable()
|
|
||||||
if ("enable")
|
|
||||||
var/toEnable = href_list["name"]
|
|
||||||
processScheduler.enableProcess(toEnable)
|
|
||||||
refreshProcessTable()
|
|
||||||
if ("disable")
|
|
||||||
var/toDisable = href_list["name"]
|
|
||||||
processScheduler.disableProcess(toDisable)
|
|
||||||
refreshProcessTable()
|
|
||||||
if ("refresh")
|
|
||||||
refreshProcessTable()
|
|
||||||
|
|
||||||
/datum/processSchedulerView/proc/refreshProcessTable()
|
|
||||||
windowCall("handleRefresh", getProcessTable())
|
|
||||||
|
|
||||||
/datum/processSchedulerView/proc/windowCall(var/function, var/data = null)
|
|
||||||
usr << output(data, "processSchedulerContext.browser:[function]")
|
|
||||||
|
|
||||||
/datum/processSchedulerView/proc/getProcessTable()
|
|
||||||
var/text = "<table class=\"table table-striped\"><thead><tr><td>Name</td><td>Avg(s)</td><td>Last(s)</td><td>Highest(s)</td><td>Tickcount</td><td>Tickrate</td><td>State</td><td>Action</td></tr></thead><tbody>"
|
|
||||||
// and the context of each
|
|
||||||
for (var/list/data in processScheduler.getStatusData())
|
|
||||||
text += "<tr>"
|
|
||||||
text += "<td>[data["name"]]</td>"
|
|
||||||
text += "<td>[num2text(data["averageRunTime"]/10,3)]</td>"
|
|
||||||
text += "<td>[num2text(data["lastRunTime"]/10,3)]</td>"
|
|
||||||
text += "<td>[num2text(data["highestRunTime"]/10,3)]</td>"
|
|
||||||
text += "<td>[num2text(data["ticks"],4)]</td>"
|
|
||||||
text += "<td>[data["schedule"]]</td>"
|
|
||||||
text += "<td>[data["status"]]</td>"
|
|
||||||
text += "<td><button class=\"btn kill-btn\" data-process-name=\"[data["name"]]\" id=\"kill-[data["name"]]\">Kill</button>"
|
|
||||||
if (data["disabled"])
|
|
||||||
text += "<button class=\"btn enable-btn\" data-process-name=\"[data["name"]]\" id=\"enable-[data["name"]]\">Enable</button>"
|
|
||||||
else
|
|
||||||
text += "<button class=\"btn disable-btn\" data-process-name=\"[data["name"]]\" id=\"disable-[data["name"]]\">Disable</button>"
|
|
||||||
text += "</td>"
|
|
||||||
text += "</tr>"
|
|
||||||
|
|
||||||
text += "</tbody></table>"
|
|
||||||
return text
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getContext
|
|
||||||
* Outputs an interface showing stats for all processes.
|
|
||||||
*/
|
|
||||||
/datum/processSchedulerView/proc/getContext()
|
|
||||||
bootstrap_browse()
|
|
||||||
usr << browse('processScheduler.js', "file=processScheduler.js;display=0")
|
|
||||||
|
|
||||||
var/text = {"<html><head>
|
|
||||||
<title>Process Scheduler Detail</title>
|
|
||||||
<script type="text/javascript">var ref = '\ref[src]';</script>
|
|
||||||
[bootstrap_includes()]
|
|
||||||
<script type="text/javascript" src="processScheduler.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h2>Process Scheduler</h2>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button id="btn-refresh" class="btn">Refresh</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>The process scheduler controls [processScheduler.getProcessCount()] loops.<h3>"}
|
|
||||||
|
|
||||||
text += "<div id=\"processTable\">"
|
|
||||||
text += getProcessTable()
|
|
||||||
text += "</div></body></html>"
|
|
||||||
|
|
||||||
usr << browse(text, "window=processSchedulerContext;size=800x600")
|
|
||||||
|
|
||||||
/datum/processSchedulerView/proc/bootstrap_browse()
|
|
||||||
usr << browse('bower_components/jquery/dist/jquery.min.js', "file=jquery.min.js;display=0")
|
|
||||||
usr << browse('bower_components/bootstrap2.3.2/bootstrap/js/bootstrap.min.js', "file=bootstrap.min.js;display=0")
|
|
||||||
usr << browse('bower_components/bootstrap2.3.2/bootstrap/css/bootstrap.min.css', "file=bootstrap.min.css;display=0")
|
|
||||||
usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings-white.png', "file=glyphicons-halflings-white.png;display=0")
|
|
||||||
usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings.png', "file=glyphicons-halflings.png;display=0")
|
|
||||||
usr << browse('bower_components/json2/json2.js', "file=json2.js;display=0")
|
|
||||||
|
|
||||||
/datum/processSchedulerView/proc/bootstrap_includes()
|
|
||||||
return {"
|
|
||||||
<link rel="stylesheet" href="bootstrap.min.css" />
|
|
||||||
<script type="text/javascript" src="json2.js"></script>
|
|
||||||
<script type="text/javascript" src="jquery.min.js"></script>
|
|
||||||
<script type="text/javascript" src="bootstrap.js"></script>
|
|
||||||
"}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* testDyingUpdateQueueProcess
|
|
||||||
* This process is an example of a process using an updateQueue.
|
|
||||||
* The datums updated by this process behave badly and block the update loop
|
|
||||||
* by sleeping. If you #define UPDATE_QUEUE_DEBUG, you will see the updateQueue
|
|
||||||
* killing off its worker processes and spawning new ones to work around slow
|
|
||||||
* updates. This means that if you have a code path that sleeps for a long time
|
|
||||||
* in mob.Life once in a blue moon, the mob update loop will not hang.
|
|
||||||
*/
|
|
||||||
/datum/slowTestDatum/proc/wackyUpdateProcessName()
|
|
||||||
sleep(rand(0,20)) // Randomly REALLY slow :|
|
|
||||||
|
|
||||||
/datum/controller/process/testDyingUpdateQueueProcess
|
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
var/tmp/list/testDatums = list()
|
|
||||||
|
|
||||||
/datum/controller/process/testDyingUpdateQueueProcess/setup()
|
|
||||||
name = "Dying UpdateQueue Process"
|
|
||||||
schedule_interval = 30 // every 3 seconds
|
|
||||||
updateQueueInstance = new
|
|
||||||
for(var/i = 1, i < 30, i++)
|
|
||||||
testDatums.Add(new /datum/slowTestDatum)
|
|
||||||
|
|
||||||
/datum/controller/process/testDyingUpdateQueueProcess/doWork()
|
|
||||||
updateQueueInstance.init(testDatums, "wackyUpdateProcessName")
|
|
||||||
updateQueueInstance.Run()
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
These are simple defaults for your project.
|
|
||||||
*/
|
|
||||||
#define DEBUG
|
|
||||||
|
|
||||||
var/global/datum/processSchedulerView/processSchedulerView
|
|
||||||
|
|
||||||
world
|
|
||||||
loop_checks = 0
|
|
||||||
New()
|
|
||||||
..()
|
|
||||||
processScheduler = new
|
|
||||||
processSchedulerView = new
|
|
||||||
|
|
||||||
mob
|
|
||||||
step_size = 8
|
|
||||||
|
|
||||||
New()
|
|
||||||
..()
|
|
||||||
|
|
||||||
|
|
||||||
verb
|
|
||||||
startProcessScheduler()
|
|
||||||
set name = "Start Process Scheduler"
|
|
||||||
processScheduler.setup()
|
|
||||||
processScheduler.start()
|
|
||||||
|
|
||||||
getProcessSchedulerContext()
|
|
||||||
set name = "Get Process Scheduler Status Panel"
|
|
||||||
processSchedulerView.getContext()
|
|
||||||
|
|
||||||
runUpdateQueueTests()
|
|
||||||
set name = "Run Update Queue Testsuite"
|
|
||||||
var/datum/updateQueueTests/t = new
|
|
||||||
t.runTests()
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* testHungProcess
|
|
||||||
* This process is an example of a simple update loop process that hangs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/controller/process/testHungProcess/setup()
|
|
||||||
name = "Hung Process"
|
|
||||||
schedule_interval = 30 // every 3 seconds
|
|
||||||
|
|
||||||
/datum/controller/process/testHungProcess/doWork()
|
|
||||||
sleep(1000) // FUCK
|
|
||||||
// scheck is also responsible for handling hung processes. If a process
|
|
||||||
// hangs, and later resumes, but has already been killed by the scheduler,
|
|
||||||
// scheck will force the process to bail out.
|
|
||||||
scheck()
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* testNiceProcess
|
|
||||||
* This process is an example of a simple update loop process that is
|
|
||||||
* relatively fast.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/controller/process/testNiceProcess/setup()
|
|
||||||
name = "Nice Process"
|
|
||||||
schedule_interval = 10 // every second
|
|
||||||
|
|
||||||
/datum/controller/process/testNiceProcess/doWork()
|
|
||||||
sleep(rand(1,5)) // Just to pretend we're doing something
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* testSlowProcess
|
|
||||||
* This process is an example of a simple update loop process that is slow.
|
|
||||||
* The update loop here sleeps inside to provide an example, but if you had
|
|
||||||
* a computationally intensive loop process that is simply slow, you can use
|
|
||||||
* scheck() inside the loop to force it to yield periodically according to
|
|
||||||
* the sleep_interval var. By default, scheck will cause a loop to sleep every
|
|
||||||
* 2 ticks.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/controller/process/testSlowProcess/setup()
|
|
||||||
name = "Slow Process"
|
|
||||||
schedule_interval = 30 // every 3 seconds
|
|
||||||
|
|
||||||
/datum/controller/process/testSlowProcess/doWork()
|
|
||||||
// set background = 1 will cause loop constructs to sleep periodically,
|
|
||||||
// whenever the BYOND scheduler deems it productive to do so.
|
|
||||||
// This behavior is not always sufficient, nor is it always consistent.
|
|
||||||
// Rather than leaving it up to the BYOND scheduler, we can control it
|
|
||||||
// ourselves and leave nothing to the black box.
|
|
||||||
set background = 1
|
|
||||||
|
|
||||||
for(var/i=1,i<30,i++)
|
|
||||||
// Just to pretend we're doing something here
|
|
||||||
sleep(rand(3, 5))
|
|
||||||
|
|
||||||
// Forces this loop to yield(sleep) periodically.
|
|
||||||
scheck()
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
var/global/list/updateQueueTestCount = list()
|
|
||||||
|
|
||||||
/datum/updateQueueTests
|
|
||||||
var/start
|
|
||||||
proc
|
|
||||||
runTests()
|
|
||||||
world << "<b>Running 9 tests...</b>"
|
|
||||||
testUpdateQueuePerformance()
|
|
||||||
sleep(1)
|
|
||||||
testInplace()
|
|
||||||
sleep(1)
|
|
||||||
testInplaceUpdateQueuePerformance()
|
|
||||||
sleep(1)
|
|
||||||
testUpdateQueueReinit()
|
|
||||||
sleep(1)
|
|
||||||
testCrashingQueue()
|
|
||||||
sleep(1)
|
|
||||||
testEmptyQueue()
|
|
||||||
sleep(1)
|
|
||||||
testManySlowItemsInQueue()
|
|
||||||
sleep(1)
|
|
||||||
testVariableWorkerTimeout()
|
|
||||||
sleep(1)
|
|
||||||
testReallySlowItemInQueue()
|
|
||||||
sleep(1)
|
|
||||||
world << "<b>Finished!</b>"
|
|
||||||
|
|
||||||
beginTiming()
|
|
||||||
start = world.time
|
|
||||||
|
|
||||||
endTiming(text)
|
|
||||||
var/time = (world.time - start) / world.tick_lag
|
|
||||||
world << {"<b><font color="blue">Performance - [text] - <font color="green">[time]</font> ticks</font></b>"}
|
|
||||||
|
|
||||||
getCount()
|
|
||||||
return updateQueueTestCount[updateQueueTestCount.len]
|
|
||||||
|
|
||||||
incrementTestCount()
|
|
||||||
updateQueueTestCount.len++
|
|
||||||
updateQueueTestCount[updateQueueTestCount.len] = 0
|
|
||||||
|
|
||||||
assertCountEquals(count, text)
|
|
||||||
assertThat(getCount() == count, text)
|
|
||||||
|
|
||||||
assertCountLessThan(count, text)
|
|
||||||
assertThat(getCount() < count, text)
|
|
||||||
|
|
||||||
assertCountGreaterThan(count, text)
|
|
||||||
assertThat(getCount() > count, text)
|
|
||||||
|
|
||||||
assertThat(condition, text)
|
|
||||||
if (condition)
|
|
||||||
world << {"<font color="green"><b>PASS</b></font>: [text]"}
|
|
||||||
else
|
|
||||||
world << {"<b><font color="red">FAIL</font>: [text]</b>"}
|
|
||||||
|
|
||||||
testUpdateQueuePerformance()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=100000,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
|
|
||||||
beginTiming()
|
|
||||||
uq.Run()
|
|
||||||
endTiming("updating 100000 simple objects")
|
|
||||||
|
|
||||||
assertCountEquals(100000, "test that update queue updates all objects expected")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testUpdateQueueReinit()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=100,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
uq.Run()
|
|
||||||
objs = new
|
|
||||||
|
|
||||||
for(var/i=1,i<=100,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
uq.init(objs)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(200, "test that update queue reinitializes properly and updates all objects as expected.")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testInplace()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=100,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
var/datum/updateQueue/uq = new(objects = objs, inplace = 1)
|
|
||||||
uq.Run()
|
|
||||||
assertThat(objs.len == 0, "test that update queue inplace option really works inplace")
|
|
||||||
assertCountEquals(100, "test that inplace update queue updates the right number of objects")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testInplaceUpdateQueuePerformance()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=100000,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
|
|
||||||
beginTiming()
|
|
||||||
uq.Run()
|
|
||||||
endTiming("updating 100000 simple objects in place")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testCrashingQueue()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=10,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
objs.Add(new /datum/uqTestDatum/crasher(updateQueueTestCount.len))
|
|
||||||
for(var/i=1,i<=10,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(20, "test that update queue handles crashed update procs OK")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testEmptyQueue()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(0, "test that update queue doesn't barf on empty lists")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testManySlowItemsInQueue()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=30,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len))
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(30, "test that update queue slows down execution if too many objects are slow to update")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testVariableWorkerTimeout()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=20,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len))
|
|
||||||
var/datum/updateQueue/uq = new(objs, workerTimeout=6)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(20, "test that variable worker timeout works properly")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
testReallySlowItemInQueue()
|
|
||||||
incrementTestCount()
|
|
||||||
var/list/objs = new
|
|
||||||
for(var/i=1,i<=10,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
objs.Add(new /datum/uqTestDatum/reallySlow(updateQueueTestCount.len))
|
|
||||||
for(var/i=1,i<=10,i++)
|
|
||||||
objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len))
|
|
||||||
var/datum/updateQueue/uq = new(objs)
|
|
||||||
uq.Run()
|
|
||||||
assertCountEquals(20, "test that update queue skips objects that are too slow to update")
|
|
||||||
del(objs)
|
|
||||||
del(uq)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
datum/uqTestDatum
|
|
||||||
var/testNum
|
|
||||||
New(testNum)
|
|
||||||
..()
|
|
||||||
src.testNum = testNum
|
|
||||||
proc/update()
|
|
||||||
updateQueueTestCount[testNum]++
|
|
||||||
proc/lag(cycles)
|
|
||||||
set background = 1
|
|
||||||
for(var/i=0,i<cycles,)
|
|
||||||
i++
|
|
||||||
datum/uqTestDatum/fast
|
|
||||||
|
|
||||||
datum/uqTestDatum/slow
|
|
||||||
update()
|
|
||||||
set background = 1
|
|
||||||
var/start = world.timeofday
|
|
||||||
while(world.timeofday - start < 5) // lag 4 deciseconds
|
|
||||||
..()
|
|
||||||
|
|
||||||
datum/uqTestDatum/reallySlow
|
|
||||||
update()
|
|
||||||
set background = 1
|
|
||||||
var/start = world.timeofday
|
|
||||||
while(world.timeofday - start < 300) // lag 30 seconds
|
|
||||||
..()
|
|
||||||
|
|
||||||
datum/uqTestDatum/crasher
|
|
||||||
update()
|
|
||||||
CRASH("I crashed! (I am supposed to crash XD)")
|
|
||||||
..() // This should do nothing lol
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* testUpdateQueueProcess
|
|
||||||
* This process is an example of a process using an updateQueue.
|
|
||||||
* The datums updated by this process behave nicely and do not block.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/fastTestDatum/proc/wackyUpdateProcessName()
|
|
||||||
sleep(prob(10)) // Pretty quick, usually instant
|
|
||||||
|
|
||||||
/datum/controller/process/testUpdateQueueProcess
|
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
var/tmp/list/testDatums = list()
|
|
||||||
|
|
||||||
/datum/controller/process/testUpdateQueueProcess/setup()
|
|
||||||
name = "UpdateQueue Process"
|
|
||||||
schedule_interval = 20 // every 2 seconds
|
|
||||||
updateQueueInstance = new
|
|
||||||
for(var/i = 1, i < 30, i++)
|
|
||||||
testDatums.Add(new /datum/fastTestDatum)
|
|
||||||
|
|
||||||
/datum/controller/process/testUpdateQueueProcess/doWork()
|
|
||||||
updateQueueInstance.init(testDatums, "wackyUpdateProcessName")
|
|
||||||
updateQueueInstance.Run()
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* testBadZombieProcess
|
|
||||||
* This process is an example of a simple update loop process that hangs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/controller/process/testZombieProcess/setup()
|
|
||||||
name = "Zombie Process"
|
|
||||||
schedule_interval = 30 // every 3 seconds
|
|
||||||
|
|
||||||
/datum/controller/process/testZombieProcess/doWork()
|
|
||||||
for (var/i = 0, i < 1000, i++)
|
|
||||||
sleep(1)
|
|
||||||
scheck()
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/datum/controller/process/air/setup()
|
/datum/controller/process/air/setup()
|
||||||
name = "air"
|
name = "air"
|
||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
|
start_delay = 4
|
||||||
|
|
||||||
if(!air_master)
|
if(!air_master)
|
||||||
air_master = new
|
air_master = new
|
||||||
|
|||||||
@@ -1,10 +1,42 @@
|
|||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
/datum/controller/process/alarm/setup()
|
/datum/controller/process/alarm/setup()
|
||||||
name = "alarm"
|
name = "alarm"
|
||||||
schedule_interval = 20 // every 2 seconds
|
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()
|
/datum/controller/process/alarm/doWork()
|
||||||
alarm_manager.fire()
|
for(last_object in all_handlers)
|
||||||
|
var/datum/alarm_handler/AH = last_object
|
||||||
|
AH.process()
|
||||||
|
SCHECK
|
||||||
|
|
||||||
/datum/controller/process/alarm/getStatName()
|
/datum/controller/process/alarm/proc/active_alarms()
|
||||||
var/list/alarms = alarm_manager.active_alarms()
|
var/list/all_alarms = new
|
||||||
return ..()+"([alarms.len])"
|
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")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
var/datum/controller/process/chemistry/chemistryProcess
|
var/datum/controller/process/chemistry/chemistryProcess
|
||||||
|
|
||||||
/datum/controller/process/chemistry
|
/datum/controller/process/chemistry
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
var/list/active_holders
|
var/list/active_holders
|
||||||
var/list/chemical_reactions
|
var/list/chemical_reactions
|
||||||
var/list/chemical_reagents
|
var/list/chemical_reagents
|
||||||
@@ -9,23 +8,24 @@ var/datum/controller/process/chemistry/chemistryProcess
|
|||||||
/datum/controller/process/chemistry/setup()
|
/datum/controller/process/chemistry/setup()
|
||||||
name = "chemistry"
|
name = "chemistry"
|
||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
updateQueueInstance = new
|
|
||||||
chemistryProcess = src
|
chemistryProcess = src
|
||||||
active_holders = list()
|
active_holders = list()
|
||||||
chemical_reactions = chemical_reactions_list
|
chemical_reactions = chemical_reactions_list
|
||||||
chemical_reagents = chemical_reagents_list
|
chemical_reagents = chemical_reagents_list
|
||||||
|
|
||||||
/datum/controller/process/chemistry/getStatName()
|
/datum/controller/process/chemistry/statProcess()
|
||||||
return ..()+"([active_holders.len])"
|
..()
|
||||||
|
stat(null, "[active_holders.len] reagent holder\s")
|
||||||
|
|
||||||
/datum/controller/process/chemistry/doWork()
|
/datum/controller/process/chemistry/doWork()
|
||||||
for(var/datum/reagents/holder in active_holders)
|
for(last_object in active_holders)
|
||||||
|
var/datum/reagents/holder = last_object
|
||||||
if(!holder.process_reactions())
|
if(!holder.process_reactions())
|
||||||
active_holders -= holder
|
active_holders -= holder
|
||||||
scheck()
|
SCHECK
|
||||||
|
|
||||||
/datum/controller/process/chemistry/proc/mark_for_update(var/datum/reagents/holder)
|
/datum/controller/process/chemistry/proc/mark_for_update(var/datum/reagents/holder)
|
||||||
if(holder in active_holders)
|
if(holder in active_holders)
|
||||||
return
|
return
|
||||||
|
|
||||||
//Process once, right away. If we still need to continue then add to the active_holders list and continue later
|
//Process once, right away. If we still need to continue then add to the active_holders list and continue later
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/datum/controller/process/disease
|
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
|
|
||||||
/datum/controller/process/disease/setup()
|
|
||||||
name = "disease"
|
|
||||||
schedule_interval = 20 // every 2 seconds
|
|
||||||
updateQueueInstance = new
|
|
||||||
|
|
||||||
/datum/controller/process/disease/doWork()
|
|
||||||
updateQueueInstance.init(active_diseases, "process")
|
|
||||||
updateQueueInstance.Run()
|
|
||||||
|
|
||||||
/datum/controller/process/disease/getStatName()
|
|
||||||
return ..()+"([active_diseases.len])"
|
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
|
// The time a datum was destroyed by the GC, or null if it hasn't been
|
||||||
|
/datum/var/gcDestroyed
|
||||||
|
|
||||||
|
#define GC_COLLECTIONS_PER_RUN 300
|
||||||
|
#define GC_COLLECTION_TIMEOUT (30 SECONDS)
|
||||||
|
#define GC_FORCE_DEL_PER_RUN 30
|
||||||
|
|
||||||
var/datum/controller/process/garbage_collector/garbage_collector
|
var/datum/controller/process/garbage_collector/garbage_collector
|
||||||
var/list/delayed_garbage = list()
|
var/list/delayed_garbage = list()
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector
|
/datum/controller/process/garbage_collector
|
||||||
var/garbage_collect = 1 // Whether or not to actually do work
|
var/garbage_collect = 1 // Whether or not to actually do work
|
||||||
var/collection_timeout = 300 //deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
|
var/total_dels = 0 // number of total del()'s
|
||||||
var/max_checks_multiplier = 5 //multiplier (per-decisecond) for calculating max number of tests per tick. These tests check if our GC'd objects are actually GC'd
|
var/tick_dels = 0 // number of del()'s we've done this tick
|
||||||
var/max_forcedel_multiplier = 1 //multiplier (per-decisecond) for calculating max number of force del() calls per tick.
|
var/soft_dels = 0
|
||||||
|
|
||||||
var/dels = 0 // number of del()'s we've done this tick
|
|
||||||
var/hard_dels = 0 // number of hard dels in total
|
var/hard_dels = 0 // number of hard dels in total
|
||||||
var/list/destroyed = list() // list of refID's of things that should be garbage collected
|
var/list/destroyed = list() // list of refID's of things that should be garbage collected
|
||||||
// refID's are associated with the time at which they time out and need to be manually del()
|
// refID's are associated with the time at which they time out and need to be manually del()
|
||||||
@@ -18,7 +23,8 @@ var/list/delayed_garbage = list()
|
|||||||
|
|
||||||
/datum/controller/process/garbage_collector/setup()
|
/datum/controller/process/garbage_collector/setup()
|
||||||
name = "garbage"
|
name = "garbage"
|
||||||
schedule_interval = 2 SECONDS
|
schedule_interval = 5 SECONDS
|
||||||
|
start_delay = 3
|
||||||
|
|
||||||
if(!garbage_collector)
|
if(!garbage_collector)
|
||||||
garbage_collector = src
|
garbage_collector = src
|
||||||
@@ -36,38 +42,14 @@ world/loop_checks = 0
|
|||||||
if(!garbage_collect)
|
if(!garbage_collect)
|
||||||
return
|
return
|
||||||
|
|
||||||
dels = 0
|
tick_dels = 0
|
||||||
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
|
var/time_to_kill = world.time - GC_COLLECTION_TIMEOUT
|
||||||
var/checkRemain = max_checks_multiplier * schedule_interval
|
var/checkRemain = GC_COLLECTIONS_PER_RUN
|
||||||
var/maxDels = max_forcedel_multiplier * schedule_interval
|
var/remaining_force_dels = GC_FORCE_DEL_PER_RUN
|
||||||
|
|
||||||
#ifdef GC_FINDREF
|
|
||||||
var/list/searching = list()
|
|
||||||
for(var/refID in destroyed) // Reference search - before all deletions and for all at once
|
|
||||||
var/GCd_at_time = destroyed[refID]
|
|
||||||
if(GCd_at_time > time_to_kill)
|
|
||||||
break
|
|
||||||
var/atom/A = locate(refID)
|
|
||||||
if(A && A.gcDestroyed == GCd_at_time)
|
|
||||||
searching += A
|
|
||||||
if(searching.len >= checkRemain)
|
|
||||||
break
|
|
||||||
|
|
||||||
for(var/atom/A in searching)
|
|
||||||
testing("GC: Searching references for [A] | [A.type]")
|
|
||||||
if(A.loc != null)
|
|
||||||
testing("GC: [A] | [A.type] is located in [A.loc] instead of null")
|
|
||||||
if(A.contents.len)
|
|
||||||
testing("GC: [A] | [A.type] has contents: [list2text(A.contents)]")
|
|
||||||
if(searching.len)
|
|
||||||
for(var/atom/D in world)
|
|
||||||
LookForRefs(D, searching)
|
|
||||||
for(var/datum/D)
|
|
||||||
LookForRefs(D, searching)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while(destroyed.len && --checkRemain >= 0)
|
while(destroyed.len && --checkRemain >= 0)
|
||||||
if(dels >= maxDels)
|
if(remaining_force_dels <= 0)
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
testing("GC: Reached max force dels per tick [dels] vs [maxDels]")
|
testing("GC: Reached max force dels per tick [dels] vs [maxDels]")
|
||||||
#endif
|
#endif
|
||||||
@@ -88,13 +70,22 @@ world/loop_checks = 0
|
|||||||
testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --")
|
testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --")
|
||||||
logging["[A.type]"]++
|
logging["[A.type]"]++
|
||||||
del(A)
|
del(A)
|
||||||
++dels
|
|
||||||
++hard_dels
|
hard_dels++
|
||||||
#ifdef GC_DEBUG
|
remaining_force_dels--
|
||||||
else
|
else
|
||||||
|
#ifdef GC_DEBUG
|
||||||
testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]")
|
testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]")
|
||||||
#endif
|
#endif
|
||||||
|
soft_dels++
|
||||||
|
tick_dels++
|
||||||
|
total_dels++
|
||||||
destroyed.Cut(1, 2)
|
destroyed.Cut(1, 2)
|
||||||
|
SCHECK
|
||||||
|
|
||||||
|
#undef GC_FORCE_DEL_PER_TICK
|
||||||
|
#undef GC_COLLECTION_TIMEOUT
|
||||||
|
#undef GC_COLLECTIONS_PER_TICK
|
||||||
|
|
||||||
#ifdef GC_FINDREF
|
#ifdef GC_FINDREF
|
||||||
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
|
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
|
||||||
@@ -132,8 +123,11 @@ world/loop_checks = 0
|
|||||||
destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list.
|
destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list.
|
||||||
destroyed["\ref[A]"] = world.time
|
destroyed["\ref[A]"] = world.time
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/getStatName()
|
/datum/controller/process/garbage_collector/statProcess()
|
||||||
return ..()+"([garbage_collector.destroyed.len]/[garbage_collector.dels]/[garbage_collector.hard_dels])"
|
..()
|
||||||
|
stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued")
|
||||||
|
stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run")
|
||||||
|
|
||||||
|
|
||||||
// Tests if an atom has been deleted.
|
// Tests if an atom has been deleted.
|
||||||
/proc/deleted(atom/A)
|
/proc/deleted(atom/A)
|
||||||
@@ -149,7 +143,7 @@ world/loop_checks = 0
|
|||||||
crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.")
|
crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.")
|
||||||
del(A)
|
del(A)
|
||||||
if(garbage_collector)
|
if(garbage_collector)
|
||||||
garbage_collector.dels++
|
garbage_collector.total_dels++
|
||||||
garbage_collector.hard_dels++
|
garbage_collector.hard_dels++
|
||||||
else if(isnull(A.gcDestroyed))
|
else if(isnull(A.gcDestroyed))
|
||||||
// Let our friend know they're about to get collected
|
// Let our friend know they're about to get collected
|
||||||
@@ -263,4 +257,4 @@ world/loop_checks = 0
|
|||||||
|
|
||||||
#ifdef GC_FINDREF
|
#ifdef GC_FINDREF
|
||||||
#undef GC_FINDREF
|
#undef GC_FINDREF
|
||||||
#endif
|
#endif
|
||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
/datum/controller/process/inactivity/doWork()
|
/datum/controller/process/inactivity/doWork()
|
||||||
if(config.kick_inactive)
|
if(config.kick_inactive)
|
||||||
for(var/client/C in clients)
|
for(last_object in clients)
|
||||||
|
var/client/C = last_object
|
||||||
if(!C.holder && C.is_afk(config.kick_inactive MINUTES))
|
if(!C.holder && C.is_afk(config.kick_inactive MINUTES))
|
||||||
if(!istype(C.mob, /mob/dead))
|
if(!istype(C.mob, /mob/observer/dead))
|
||||||
log_access("AFK: [key_name(C)]")
|
log_access("AFK: [key_name(C)]")
|
||||||
C << "<SPAN CLASS='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</SPAN>"
|
C << "<SPAN CLASS='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</SPAN>"
|
||||||
del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients.
|
del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients.
|
||||||
scheck()
|
SCHECK
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/datum/controller/process/machinery/setup()
|
/datum/controller/process/machinery/setup()
|
||||||
name = "machinery"
|
name = "machinery"
|
||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
|
start_delay = 12
|
||||||
|
|
||||||
/datum/controller/process/machinery/doWork()
|
/datum/controller/process/machinery/doWork()
|
||||||
internal_sort()
|
internal_sort()
|
||||||
@@ -17,12 +18,9 @@
|
|||||||
machines = dd_sortedObjectList(machines)
|
machines = dd_sortedObjectList(machines)
|
||||||
|
|
||||||
/datum/controller/process/machinery/proc/internal_process_machinery()
|
/datum/controller/process/machinery/proc/internal_process_machinery()
|
||||||
for(var/obj/machinery/M in machines)
|
for(last_object in machines)
|
||||||
|
var/obj/machinery/M = last_object
|
||||||
if(M && !M.gcDestroyed)
|
if(M && !M.gcDestroyed)
|
||||||
#ifdef PROFILE_MACHINES
|
|
||||||
var/time_start = world.timeofday
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(M.process() == PROCESS_KILL)
|
if(M.process() == PROCESS_KILL)
|
||||||
//M.inMachineList = 0 We don't use this debugging function
|
//M.inMachineList = 0 We don't use this debugging function
|
||||||
machines.Remove(M)
|
machines.Remove(M)
|
||||||
@@ -31,41 +29,39 @@
|
|||||||
if(M && M.use_power)
|
if(M && M.use_power)
|
||||||
M.auto_use_power()
|
M.auto_use_power()
|
||||||
|
|
||||||
#ifdef PROFILE_MACHINES
|
SCHECK
|
||||||
var/time_end = world.timeofday
|
|
||||||
|
|
||||||
if(!(M.type in machine_profiling))
|
|
||||||
machine_profiling[M.type] = 0
|
|
||||||
|
|
||||||
machine_profiling[M.type] += (time_end - time_start)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
scheck()
|
|
||||||
|
|
||||||
/datum/controller/process/machinery/proc/internal_process_power()
|
/datum/controller/process/machinery/proc/internal_process_power()
|
||||||
for(var/datum/powernet/powerNetwork in powernets)
|
for(last_object in powernets)
|
||||||
if(istype(powerNetwork) && !powerNetwork.disposed)
|
var/datum/powernet/powerNetwork = last_object
|
||||||
|
if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed))
|
||||||
powerNetwork.reset()
|
powerNetwork.reset()
|
||||||
scheck()
|
SCHECK
|
||||||
continue
|
continue
|
||||||
|
|
||||||
powernets.Remove(powerNetwork)
|
powernets.Remove(powerNetwork)
|
||||||
|
|
||||||
/datum/controller/process/machinery/proc/internal_process_power_drain()
|
/datum/controller/process/machinery/proc/internal_process_power_drain()
|
||||||
// Currently only used by powersinks. These items get priority processed before machinery
|
// Currently only used by powersinks. These items get priority processed before machinery
|
||||||
for(var/obj/item/I in processing_power_items)
|
for(last_object in processing_power_items)
|
||||||
|
var/obj/item/I = last_object
|
||||||
if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
|
if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
|
||||||
processing_power_items.Remove(I)
|
processing_power_items.Remove(I)
|
||||||
scheck()
|
SCHECK
|
||||||
|
|
||||||
/datum/controller/process/machinery/proc/internal_process_pipenets()
|
/datum/controller/process/machinery/proc/internal_process_pipenets()
|
||||||
for(var/datum/pipe_network/pipeNetwork in pipe_networks)
|
for(last_object in pipe_networks)
|
||||||
if(istype(pipeNetwork) && !pipeNetwork.disposed)
|
var/datum/pipe_network/pipeNetwork = last_object
|
||||||
|
if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed))
|
||||||
pipeNetwork.process()
|
pipeNetwork.process()
|
||||||
scheck()
|
SCHECK
|
||||||
continue
|
continue
|
||||||
|
|
||||||
pipe_networks.Remove(pipeNetwork)
|
pipe_networks.Remove(pipeNetwork)
|
||||||
|
|
||||||
/datum/controller/process/machinery/getStatName()
|
/datum/controller/process/machinery/statProcess()
|
||||||
return ..()+"(MCH:[machines.len] PWR:[powernets.len] PIP:[pipe_networks.len])"
|
..()
|
||||||
|
stat(null, "[machines.len] machines")
|
||||||
|
stat(null, "[powernets.len] powernets")
|
||||||
|
stat(null, "[pipe_networks.len] pipenets")
|
||||||
|
stat(null, "[processing_power_items.len] power item\s")
|
||||||
@@ -4,20 +4,26 @@
|
|||||||
/datum/controller/process/mob/setup()
|
/datum/controller/process/mob/setup()
|
||||||
name = "mob"
|
name = "mob"
|
||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
updateQueueInstance = new
|
start_delay = 16
|
||||||
|
|
||||||
/datum/controller/process/mob/started()
|
/datum/controller/process/mob/started()
|
||||||
..()
|
..()
|
||||||
if(!updateQueueInstance)
|
if(!mob_list)
|
||||||
if(!mob_list)
|
mob_list = list()
|
||||||
mob_list = list()
|
|
||||||
else if(mob_list.len)
|
|
||||||
updateQueueInstance = new
|
|
||||||
|
|
||||||
/datum/controller/process/mob/doWork()
|
/datum/controller/process/mob/doWork()
|
||||||
if(updateQueueInstance)
|
for(last_object in mob_list)
|
||||||
updateQueueInstance.init(mob_list, "Life")
|
var/mob/M = last_object
|
||||||
updateQueueInstance.Run()
|
if(isnull(M.gcDestroyed))
|
||||||
|
try
|
||||||
|
M.Life()
|
||||||
|
catch(var/exception/e)
|
||||||
|
catchException(e, M)
|
||||||
|
SCHECK
|
||||||
|
else
|
||||||
|
catchBadType(M)
|
||||||
|
mob_list -= M
|
||||||
|
|
||||||
/datum/controller/process/mob/getStatName()
|
/datum/controller/process/mob/statProcess()
|
||||||
return ..()+"([mob_list.len])"
|
..()
|
||||||
|
stat(null, "[mob_list.len] mobs")
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
/datum/controller/process/nanoui
|
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
|
|
||||||
/datum/controller/process/nanoui/setup()
|
/datum/controller/process/nanoui/setup()
|
||||||
name = "nanoui"
|
name = "nanoui"
|
||||||
schedule_interval = 10 // every 1 second
|
schedule_interval = 20 // every 2 seconds
|
||||||
updateQueueInstance = new
|
|
||||||
|
/datum/controller/process/nanoui/statProcess()
|
||||||
|
..()
|
||||||
|
stat(null, "[nanomanager.processing_uis.len] UIs")
|
||||||
|
|
||||||
/datum/controller/process/nanoui/doWork()
|
/datum/controller/process/nanoui/doWork()
|
||||||
updateQueueInstance.init(nanomanager.processing_uis, "process")
|
for(last_object in nanomanager.processing_uis)
|
||||||
updateQueueInstance.Run()
|
var/datum/nanoui/NUI = last_object
|
||||||
|
if(istype(NUI) && isnull(NUI.gcDestroyed))
|
||||||
/datum/controller/process/nanoui/getStatName()
|
try
|
||||||
return ..()+"([nanomanager.processing_uis.len])"
|
NUI.process()
|
||||||
|
catch(var/exception/e)
|
||||||
|
catchException(e, NUI)
|
||||||
|
else
|
||||||
|
catchBadType(NUI)
|
||||||
|
nanomanager.processing_uis -= NUI
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
var/global/list/object_profiling = list()
|
|
||||||
/datum/controller/process/obj
|
|
||||||
var/tmp/datum/updateQueue/updateQueueInstance
|
|
||||||
|
|
||||||
/datum/controller/process/obj/setup()
|
/datum/controller/process/obj/setup()
|
||||||
name = "obj"
|
name = "obj"
|
||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
updateQueueInstance = new
|
start_delay = 8
|
||||||
|
|
||||||
/datum/controller/process/obj/started()
|
/datum/controller/process/obj/started()
|
||||||
..()
|
..()
|
||||||
if(!updateQueueInstance)
|
if(!processing_objects)
|
||||||
if(!processing_objects)
|
processing_objects = list()
|
||||||
processing_objects = list()
|
|
||||||
else if(processing_objects.len)
|
|
||||||
updateQueueInstance = new
|
|
||||||
|
|
||||||
/datum/controller/process/obj/doWork()
|
/datum/controller/process/obj/doWork()
|
||||||
if(updateQueueInstance)
|
for(last_object in processing_objects)
|
||||||
updateQueueInstance.init(processing_objects, "process")
|
var/datum/O = last_object
|
||||||
updateQueueInstance.Run()
|
if(isnull(O.gcDestroyed))
|
||||||
|
try
|
||||||
|
O:process()
|
||||||
|
catch(var/exception/e)
|
||||||
|
catchException(e, O)
|
||||||
|
SCHECK
|
||||||
|
else
|
||||||
|
catchBadType(O)
|
||||||
|
processing_objects -= O
|
||||||
|
|
||||||
/datum/controller/process/obj/getStatName()
|
/datum/controller/process/obj/statProcess()
|
||||||
return ..()+"([processing_objects.len])"
|
..()
|
||||||
|
stat(null, "[processing_objects.len] objects")
|
||||||
133
code/controllers/Processes/scheduler.dm
Normal file
133
code/controllers/Processes/scheduler.dm
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/var/datum/controller/process/scheduler/scheduler
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Scheduler *
|
||||||
|
************/
|
||||||
|
/datum/controller/process/scheduler
|
||||||
|
var/list/scheduled_tasks
|
||||||
|
|
||||||
|
/datum/controller/process/scheduler/setup()
|
||||||
|
name = "scheduler"
|
||||||
|
schedule_interval = 3 SECONDS
|
||||||
|
scheduled_tasks = list()
|
||||||
|
scheduler = src
|
||||||
|
|
||||||
|
/datum/controller/process/scheduler/doWork()
|
||||||
|
for(last_object in scheduled_tasks)
|
||||||
|
var/datum/scheduled_task/scheduled_task = last_object
|
||||||
|
try
|
||||||
|
if(world.time > scheduled_task.trigger_time)
|
||||||
|
unschedule(scheduled_task)
|
||||||
|
scheduled_task.pre_process()
|
||||||
|
scheduled_task.process()
|
||||||
|
scheduled_task.post_process()
|
||||||
|
catch(var/exception/e)
|
||||||
|
catchException(e, last_object)
|
||||||
|
SCHECK
|
||||||
|
|
||||||
|
/datum/controller/process/scheduler/statProcess()
|
||||||
|
..()
|
||||||
|
stat(null, "[scheduled_tasks.len] task\s")
|
||||||
|
|
||||||
|
/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st)
|
||||||
|
scheduled_tasks += st
|
||||||
|
destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule)
|
||||||
|
|
||||||
|
/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st)
|
||||||
|
if(st in scheduled_tasks)
|
||||||
|
scheduled_tasks -= st
|
||||||
|
destroyed_event.unregister(st, src)
|
||||||
|
|
||||||
|
/**********
|
||||||
|
* Helpers *
|
||||||
|
**********/
|
||||||
|
/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list())
|
||||||
|
return schedule_task(world.time + in_time, procedure, arguments)
|
||||||
|
|
||||||
|
/proc/schedule_task_with_source_in(var/in_time, var/source, var/procedure, var/list/arguments = list())
|
||||||
|
return schedule_task_with_source(world.time + in_time, source, procedure, arguments)
|
||||||
|
|
||||||
|
/proc/schedule_task(var/trigger_time, var/procedure, var/list/arguments)
|
||||||
|
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/destroy_scheduled_task, list())
|
||||||
|
scheduler.schedule(st)
|
||||||
|
return st
|
||||||
|
|
||||||
|
/proc/schedule_task_with_source(var/trigger_time, var/source, var/procedure, var/list/arguments)
|
||||||
|
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/destroy_scheduled_task, list())
|
||||||
|
scheduler.schedule(st)
|
||||||
|
return st
|
||||||
|
|
||||||
|
/proc/schedule_repeating_task(var/trigger_time, var/repeat_interval, var/procedure, var/list/arguments)
|
||||||
|
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
|
||||||
|
scheduler.schedule(st)
|
||||||
|
return st
|
||||||
|
|
||||||
|
/proc/schedule_repeating_task_with_source(var/trigger_time, var/repeat_interval, var/source, var/procedure, var/list/arguments)
|
||||||
|
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
|
||||||
|
scheduler.schedule(st)
|
||||||
|
return st
|
||||||
|
|
||||||
|
/*************
|
||||||
|
* Task Datum *
|
||||||
|
*************/
|
||||||
|
/datum/scheduled_task
|
||||||
|
var/trigger_time
|
||||||
|
var/procedure
|
||||||
|
var/list/arguments
|
||||||
|
var/task_after_process
|
||||||
|
var/list/task_after_process_args
|
||||||
|
|
||||||
|
/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||||
|
..()
|
||||||
|
src.trigger_time = trigger_time
|
||||||
|
src.procedure = procedure
|
||||||
|
src.arguments = arguments ? arguments : list()
|
||||||
|
src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task
|
||||||
|
src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list()
|
||||||
|
task_after_process_args += src
|
||||||
|
|
||||||
|
/datum/scheduled_task/Destroy()
|
||||||
|
procedure = null
|
||||||
|
arguments.Cut()
|
||||||
|
task_after_process = null
|
||||||
|
task_after_process_args.Cut()
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/scheduled_task/proc/pre_process()
|
||||||
|
task_triggered_event.raise_event(list(src))
|
||||||
|
|
||||||
|
/datum/scheduled_task/proc/process()
|
||||||
|
if(procedure)
|
||||||
|
call(procedure)(arglist(arguments))
|
||||||
|
|
||||||
|
/datum/scheduled_task/proc/post_process()
|
||||||
|
call(task_after_process)(arglist(task_after_process_args))
|
||||||
|
|
||||||
|
// Resets the trigger time, has no effect if the task has already triggered
|
||||||
|
/datum/scheduled_task/proc/trigger_task_in(var/trigger_in)
|
||||||
|
src.trigger_time = world.time + trigger_in
|
||||||
|
|
||||||
|
/datum/scheduled_task/source
|
||||||
|
var/datum/source
|
||||||
|
|
||||||
|
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||||
|
src.source = source
|
||||||
|
destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
|
||||||
|
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
|
||||||
|
|
||||||
|
/datum/scheduled_task/source/Destroy()
|
||||||
|
source = null
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/scheduled_task/source/process()
|
||||||
|
call(source, procedure)(arglist(arguments))
|
||||||
|
|
||||||
|
/datum/scheduled_task/source/proc/source_destroyed()
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/proc/destroy_scheduled_task(var/datum/scheduled_task/st)
|
||||||
|
qdel(st)
|
||||||
|
|
||||||
|
/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st)
|
||||||
|
st.trigger_time = world.time + trigger_delay
|
||||||
|
scheduler.schedule(st)
|
||||||
@@ -5,10 +5,12 @@ var/global/list/turf/processing_turfs = list()
|
|||||||
schedule_interval = 20 // every 2 seconds
|
schedule_interval = 20 // every 2 seconds
|
||||||
|
|
||||||
/datum/controller/process/turf/doWork()
|
/datum/controller/process/turf/doWork()
|
||||||
for(var/turf/T in processing_turfs)
|
for(last_object in processing_turfs)
|
||||||
|
var/turf/T = last_object
|
||||||
if(T.process() == PROCESS_KILL)
|
if(T.process() == PROCESS_KILL)
|
||||||
processing_turfs.Remove(T)
|
processing_turfs.Remove(T)
|
||||||
scheck()
|
SCHECK
|
||||||
|
|
||||||
/datum/controller/process/turf/getStatName()
|
/datum/controller/process/turf/statProcess()
|
||||||
return ..()+"([processing_turfs.len])"
|
..()
|
||||||
|
stat(null, "[processing_turfs.len] turf\s")
|
||||||
@@ -12,6 +12,6 @@ datum/controller/transfer_controller/Destroy()
|
|||||||
|
|
||||||
datum/controller/transfer_controller/proc/process()
|
datum/controller/transfer_controller/proc/process()
|
||||||
currenttick = currenttick + 1
|
currenttick = currenttick + 1
|
||||||
if (world.time >= timerbuffer - 600)
|
if (round_duration_in_ticks >= timerbuffer - 1 MINUTE)
|
||||||
vote.autotransfer()
|
vote.autotransfer()
|
||||||
timerbuffer = timerbuffer + config.vote_autotransfer_interval
|
timerbuffer = timerbuffer + config.vote_autotransfer_interval
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ var/list/gamemode_cache = list()
|
|||||||
var/log_pda = 0 // log pda messages
|
var/log_pda = 0 // log pda messages
|
||||||
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
|
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
|
||||||
var/log_runtime = 0 // logs world.log to a file
|
var/log_runtime = 0 // logs world.log to a file
|
||||||
var/sql_enabled = 1 // for sql switching
|
var/log_world_output = 0 // log world.log << messages
|
||||||
|
var/sql_enabled = 0 // for sql switching
|
||||||
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
|
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
|
||||||
var/allow_vote_restart = 0 // allow votes to restart
|
var/allow_vote_restart = 0 // allow votes to restart
|
||||||
var/ert_admin_call_only = 0
|
var/ert_admin_call_only = 0
|
||||||
@@ -265,7 +266,7 @@ var/list/gamemode_cache = list()
|
|||||||
if(type == "config")
|
if(type == "config")
|
||||||
switch (name)
|
switch (name)
|
||||||
if ("resource_urls")
|
if ("resource_urls")
|
||||||
config.resource_urls = text2list(value, " ")
|
config.resource_urls = splittext(value, " ")
|
||||||
|
|
||||||
if ("admin_legacy_system")
|
if ("admin_legacy_system")
|
||||||
config.admin_legacy_system = 1
|
config.admin_legacy_system = 1
|
||||||
@@ -289,7 +290,7 @@ var/list/gamemode_cache = list()
|
|||||||
config.log_access = 1
|
config.log_access = 1
|
||||||
|
|
||||||
if ("sql_enabled")
|
if ("sql_enabled")
|
||||||
config.sql_enabled = text2num(value)
|
config.sql_enabled = 1
|
||||||
|
|
||||||
if ("log_say")
|
if ("log_say")
|
||||||
config.log_say = 1
|
config.log_say = 1
|
||||||
@@ -327,6 +328,9 @@ var/list/gamemode_cache = list()
|
|||||||
if ("log_pda")
|
if ("log_pda")
|
||||||
config.log_pda = 1
|
config.log_pda = 1
|
||||||
|
|
||||||
|
if ("log_world_output")
|
||||||
|
config.log_world_output = 1
|
||||||
|
|
||||||
if ("log_hrefs")
|
if ("log_hrefs")
|
||||||
config.log_hrefs = 1
|
config.log_hrefs = 1
|
||||||
|
|
||||||
@@ -337,7 +341,7 @@ var/list/gamemode_cache = list()
|
|||||||
config.generate_asteroid = 1
|
config.generate_asteroid = 1
|
||||||
|
|
||||||
if ("asteroid_z_levels")
|
if ("asteroid_z_levels")
|
||||||
config.asteroid_z_levels = text2list(value, ";")
|
config.asteroid_z_levels = splittext(value, ";")
|
||||||
//Numbers get stored as strings, so we'll fix that right now.
|
//Numbers get stored as strings, so we'll fix that right now.
|
||||||
for(var/z_level in config.asteroid_z_levels)
|
for(var/z_level in config.asteroid_z_levels)
|
||||||
z_level = text2num(z_level)
|
z_level = text2num(z_level)
|
||||||
@@ -696,7 +700,7 @@ var/list/gamemode_cache = list()
|
|||||||
config.starlight = value >= 0 ? value : 0
|
config.starlight = value >= 0 ? value : 0
|
||||||
|
|
||||||
if("ert_species")
|
if("ert_species")
|
||||||
config.ert_species = text2list(value, ";")
|
config.ert_species = splittext(value, ";")
|
||||||
if(!config.ert_species.len)
|
if(!config.ert_species.len)
|
||||||
config.ert_species += "Human"
|
config.ert_species += "Human"
|
||||||
|
|
||||||
@@ -707,7 +711,7 @@ var/list/gamemode_cache = list()
|
|||||||
config.aggressive_changelog = 1
|
config.aggressive_changelog = 1
|
||||||
|
|
||||||
if("default_language_prefixes")
|
if("default_language_prefixes")
|
||||||
var/list/values = text2list(value, " ")
|
var/list/values = splittext(value, " ")
|
||||||
if(values.len > 0)
|
if(values.len > 0)
|
||||||
language_prefixes = values
|
language_prefixes = values
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
/**
|
/**
|
||||||
* Startup hook.
|
* Startup hook.
|
||||||
* Called in world.dm when the server starts.
|
* Called in world.dm when the server starts.
|
||||||
*/
|
*/
|
||||||
/hook/startup
|
/hook/startup
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roundstart hook.
|
* Roundstart hook.
|
||||||
* Called in gameticker.dm when a round starts.
|
* Called in gameticker.dm when a round starts.
|
||||||
*/
|
*/
|
||||||
/hook/roundstart
|
/hook/roundstart
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roundend hook.
|
* Roundend hook.
|
||||||
* Called in gameticker.dm when a round ends.
|
* Called in gameticker.dm when a round ends.
|
||||||
*/
|
*/
|
||||||
/hook/roundend
|
/hook/roundend
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Death hook.
|
* Death hook.
|
||||||
* Called in death.dm when someone dies.
|
* Called in death.dm when someone dies.
|
||||||
* Parameters: var/mob/living/carbon/human, var/gibbed
|
* Parameters: var/mob/living/carbon/human, var/gibbed
|
||||||
*/
|
*/
|
||||||
/hook/death
|
/hook/death
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cloning hook.
|
* Cloning hook.
|
||||||
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
* Called in cloning.dm when someone is brought back by the wonders of modern science.
|
||||||
* Parameters: var/mob/living/carbon/human
|
* Parameters: var/mob/living/carbon/human
|
||||||
*/
|
*/
|
||||||
/hook/clone
|
/hook/clone
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debrained hook.
|
* Debrained hook.
|
||||||
* Called in brain_item.dm when someone gets debrained.
|
* Called in brain_item.dm when someone gets debrained.
|
||||||
* Parameters: var/obj/item/organ/brain
|
* Parameters: var/obj/item/organ/brain
|
||||||
*/
|
*/
|
||||||
/hook/debrain
|
/hook/debrain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Borged hook.
|
* Borged hook.
|
||||||
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
* Called in robot_parts.dm when someone gets turned into a cyborg.
|
||||||
* Parameters: var/mob/living/silicon/robot
|
* Parameters: var/mob/living/silicon/robot
|
||||||
*/
|
*/
|
||||||
/hook/borgify
|
/hook/borgify
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Podman hook.
|
* Podman hook.
|
||||||
* Called in podmen.dm when someone is brought back as a Diona.
|
* Called in podmen.dm when someone is brought back as a Diona.
|
||||||
* Parameters: var/mob/living/carbon/alien/diona
|
* Parameters: var/mob/living/carbon/alien/diona
|
||||||
*/
|
*/
|
||||||
/hook/harvest_podman
|
/hook/harvest_podman
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payroll revoked hook.
|
* Payroll revoked hook.
|
||||||
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
|
||||||
* Parameters: var/datum/money_account
|
* Parameters: var/datum/money_account
|
||||||
*/
|
*/
|
||||||
/hook/revoke_payroll
|
/hook/revoke_payroll
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account suspension hook.
|
* Account suspension hook.
|
||||||
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
|
||||||
* Parameters: var/datum/money_account
|
* Parameters: var/datum/money_account
|
||||||
*/
|
*/
|
||||||
/hook/change_account_status
|
/hook/change_account_status
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Employee reassignment hook.
|
* Employee reassignment hook.
|
||||||
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
* Called in card.dm when someone's card is reassigned at the HoP's desk.
|
||||||
* Parameters: var/obj/item/weapon/card/id
|
* Parameters: var/obj/item/weapon/card/id
|
||||||
*/
|
*/
|
||||||
/hook/reassign_employee
|
/hook/reassign_employee
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Employee terminated hook.
|
* Employee terminated hook.
|
||||||
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
* Called in card.dm when someone's card is terminated at the HoP's desk.
|
||||||
* Parameters: var/obj/item/weapon/card/id
|
* Parameters: var/obj/item/weapon/card/id
|
||||||
*/
|
*/
|
||||||
/hook/terminate_employee
|
/hook/terminate_employee
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crate sold hook.
|
* Crate sold hook.
|
||||||
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
|
||||||
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
|
||||||
*/
|
*/
|
||||||
/hook/sell_crate
|
/hook/sell_crate
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
*
|
*
|
||||||
* To add some code to be called by the hook, define a proc under the type, as so:
|
* To add some code to be called by the hook, define a proc under the type, as so:
|
||||||
* @code
|
* @code
|
||||||
/hook/foo/proc/bar()
|
/hook/foo/proc/bar()
|
||||||
if(1)
|
if(1)
|
||||||
return 1 //Sucessful
|
return 1 //Sucessful
|
||||||
else
|
else
|
||||||
return 0 //Error, or runtime.
|
return 0 //Error, or runtime.
|
||||||
* @endcode
|
* @endcode
|
||||||
* All hooks must return nonzero on success, as runtimes will force return null.
|
* All hooks must return nonzero on success, as runtimes will force return null.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ datum/controller/game_controller/proc/setup_objects()
|
|||||||
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
|
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
|
||||||
sleep(-1)
|
sleep(-1)
|
||||||
for(var/atom/movable/object in world)
|
for(var/atom/movable/object in world)
|
||||||
object.initialize()
|
if(isnull(object.gcDestroyed))
|
||||||
|
object.initialize()
|
||||||
|
|
||||||
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
|
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
|
||||||
sleep(-1)
|
sleep(-1)
|
||||||
|
|||||||
31
code/controllers/observer_listener/atom/observer.dm
Normal file
31
code/controllers/observer_listener/atom/observer.dm
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#define OBSERVER_EVENT_DESTROY "OnDestroy"
|
||||||
|
|
||||||
|
/atom
|
||||||
|
var/list/observer_events
|
||||||
|
|
||||||
|
/atom/Destroy()
|
||||||
|
var/list/destroy_listeners = get_listener_list_from_event(OBSERVER_EVENT_DESTROY)
|
||||||
|
if(destroy_listeners)
|
||||||
|
for(var/destroy_listener in destroy_listeners)
|
||||||
|
call(destroy_listener, destroy_listeners[destroy_listener])(src)
|
||||||
|
|
||||||
|
for(var/list/listeners in observer_events)
|
||||||
|
listeners.Cut()
|
||||||
|
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/atom/proc/register(var/event, var/procOwner, var/proc_call)
|
||||||
|
var/list/listeners = get_listener_list_from_event(event)
|
||||||
|
listeners[procOwner] = proc_call
|
||||||
|
|
||||||
|
/atom/proc/unregister(var/event, var/procOwner)
|
||||||
|
var/list/listeners = get_listener_list_from_event(event)
|
||||||
|
listeners -= procOwner
|
||||||
|
|
||||||
|
/atom/proc/get_listener_list_from_event(var/observer_event)
|
||||||
|
if(!observer_events) observer_events = list()
|
||||||
|
var/list/listeners = observer_events[observer_event]
|
||||||
|
if(!listeners)
|
||||||
|
listeners = list()
|
||||||
|
observer_events[observer_event] = listeners
|
||||||
|
return listeners
|
||||||
@@ -264,7 +264,7 @@ var/global/datum/shuttle_controller/shuttle_controller
|
|||||||
var/datum/shuttle/ferry/multidock/specops/ERT = new()
|
var/datum/shuttle/ferry/multidock/specops/ERT = new()
|
||||||
ERT.location = 0
|
ERT.location = 0
|
||||||
ERT.warmup_time = 10
|
ERT.warmup_time = 10
|
||||||
ERT.area_offsite = locate(/area/shuttle/specops/station) //centcom is the home station, the Northern Star is offsite
|
ERT.area_offsite = locate(/area/shuttle/specops/station) //centcom is the home station, the player station is offsite
|
||||||
ERT.area_station = locate(/area/shuttle/specops/centcom)
|
ERT.area_station = locate(/area/shuttle/specops/centcom)
|
||||||
ERT.docking_controller_tag = "specops_shuttle_port"
|
ERT.docking_controller_tag = "specops_shuttle_port"
|
||||||
ERT.docking_controller_tag_station = "specops_shuttle_port"
|
ERT.docking_controller_tag_station = "specops_shuttle_port"
|
||||||
@@ -317,9 +317,9 @@ var/global/datum/shuttle_controller/shuttle_controller
|
|||||||
"Arrivals dock" = "nuke_shuttle_dock_airlock",
|
"Arrivals dock" = "nuke_shuttle_dock_airlock",
|
||||||
)
|
)
|
||||||
|
|
||||||
MS.announcer = "NDV Icarus"
|
MS.announcer = "Automated Traffic Control"
|
||||||
MS.arrival_message = "Attention, [station_short], you have a large signature approaching the station - looks unarmed to surface scans. We're too far out to intercept - brace for visitors."
|
MS.arrival_message = "Attention. A vessel is approaching the colony."
|
||||||
MS.departure_message = "Your visitors are on their way out of the system, [station_short], burning delta-v like it's nothing. Good riddance."
|
MS.departure_message = "Attention. A vessel is now leaving from the colony."
|
||||||
MS.interim = locate(/area/syndicate_station/transit)
|
MS.interim = locate(/area/syndicate_station/transit)
|
||||||
|
|
||||||
MS.warmup_time = 0
|
MS.warmup_time = 0
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// We manually initialize the alarm handlers instead of looping over all existing types
|
|
||||||
// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof.
|
|
||||||
/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
|
|
||||||
/var/global/datum/alarm_handler/camera/camera_alarm = new()
|
|
||||||
/var/global/datum/alarm_handler/fire/fire_alarm = new()
|
|
||||||
/var/global/datum/alarm_handler/motion/motion_alarm = new()
|
|
||||||
/var/global/datum/alarm_handler/power/power_alarm = new()
|
|
||||||
|
|
||||||
/datum/subsystem/alarm
|
|
||||||
name = "Alarm"
|
|
||||||
var/list/datum/alarm/all_handlers
|
|
||||||
|
|
||||||
/datum/subsystem/alarm/New()
|
|
||||||
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
|
|
||||||
|
|
||||||
/datum/subsystem/alarm/fire()
|
|
||||||
for(var/datum/alarm_handler/AH in all_handlers)
|
|
||||||
AH.process()
|
|
||||||
|
|
||||||
/datum/subsystem/alarm/proc/active_alarms()
|
|
||||||
var/list/all_alarms = new
|
|
||||||
for(var/datum/alarm_handler/AH in all_handlers)
|
|
||||||
var/list/alarms = AH.alarms
|
|
||||||
all_alarms += alarms
|
|
||||||
|
|
||||||
return all_alarms
|
|
||||||
|
|
||||||
/datum/subsystem/alarm/proc/number_of_active_alarms()
|
|
||||||
var/list/alarms = active_alarms()
|
|
||||||
return alarms.len
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
usr.client.debug_variables(antag)
|
usr.client.debug_variables(antag)
|
||||||
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
|
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
|
||||||
|
|
||||||
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry"))
|
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio"))
|
||||||
set category = "Debug"
|
set category = "Debug"
|
||||||
set name = "Debug Controller"
|
set name = "Debug Controller"
|
||||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||||
@@ -92,5 +92,11 @@
|
|||||||
if("Chemistry")
|
if("Chemistry")
|
||||||
debug_variables(chemistryProcess)
|
debug_variables(chemistryProcess)
|
||||||
feedback_add_details("admin_verb", "DChem")
|
feedback_add_details("admin_verb", "DChem")
|
||||||
|
if("Vote")
|
||||||
|
debug_variables(vote)
|
||||||
|
feedback_add_details("admin_verb", "DVote")
|
||||||
|
if("Xenobio")
|
||||||
|
debug_variables(xenobio_controller)
|
||||||
|
feedback_add_details("admin_verb", "DXenobio")
|
||||||
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
var/datum/controller/vote/vote = new()
|
var/datum/controller/vote/vote = new()
|
||||||
|
|
||||||
var/global/list/round_voters = list() //Keeps track of the individuals voting for a given round, for use in forcedrafting.
|
var/global/list/round_voters = list() // Keeps track of the individuals voting for a given round, for use in forcedrafting.
|
||||||
|
|
||||||
datum/controller/vote
|
#define VOTE_RESTART "restart"
|
||||||
var/initiator = null
|
#define VOTE_GAMEMODE "gamemode"
|
||||||
|
#define VOTE_CREW_TRANSFER "crew_transfer"
|
||||||
|
#define VOTE_ADD_ANTAGONIST "add_antagonist"
|
||||||
|
#define VOTE_CUSTOM "custom"
|
||||||
|
|
||||||
|
/datum/controller/vote
|
||||||
|
var/initiator = null // Key of the one who started the vote or "the server"
|
||||||
var/started_time = null
|
var/started_time = null
|
||||||
var/time_remaining = 0
|
var/time_remaining = 0
|
||||||
var/mode = null
|
var/mode = null
|
||||||
@@ -11,385 +17,366 @@ datum/controller/vote
|
|||||||
var/list/choices = list()
|
var/list/choices = list()
|
||||||
var/list/gamemode_names = list()
|
var/list/gamemode_names = list()
|
||||||
var/list/voted = list()
|
var/list/voted = list()
|
||||||
var/list/voting = list()
|
|
||||||
var/list/current_votes = list()
|
var/list/current_votes = list()
|
||||||
var/list/additional_text = list()
|
var/list/additional_text = list()
|
||||||
var/auto_muted = 0
|
|
||||||
|
|
||||||
New()
|
/datum/controller/vote/New()
|
||||||
if(vote != src)
|
if(vote != src)
|
||||||
if(istype(vote))
|
if(istype(vote))
|
||||||
del(vote)
|
del(vote)
|
||||||
vote = src
|
vote = src
|
||||||
|
|
||||||
proc/process() //called by master_controller
|
/datum/controller/vote/proc/process() //called by master_controller
|
||||||
if(mode)
|
if(mode)
|
||||||
// No more change mode votes after the game has started.
|
// No more change mode votes after the game has started.
|
||||||
// 3 is GAME_STATE_PLAYING, but that #define is undefined for some reason
|
if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP)
|
||||||
if(mode == "gamemode" && ticker.current_state >= 2)
|
world << "<b>Voting aborted due to game start.</b>"
|
||||||
world << "<b>Voting aborted due to game start.</b>"
|
src.reset()
|
||||||
src.reset()
|
return
|
||||||
return
|
|
||||||
|
|
||||||
// Calculate how much time is remaining by comparing current time, to time of vote start,
|
// Calculate how much time is remaining by comparing current time, to time of vote start,
|
||||||
// plus vote duration
|
// plus vote duration
|
||||||
time_remaining = round((started_time + config.vote_period - world.time)/10)
|
time_remaining = round((started_time + config.vote_period - world.time)/10)
|
||||||
|
|
||||||
if(time_remaining < 0)
|
|
||||||
result()
|
|
||||||
for(var/client/C in voting)
|
|
||||||
if(C)
|
|
||||||
C << browse(null,"window=vote")
|
|
||||||
reset()
|
|
||||||
else
|
|
||||||
for(var/client/C in voting)
|
|
||||||
if(C)
|
|
||||||
C << browse(vote.interface(C),"window=vote")
|
|
||||||
|
|
||||||
voting.Cut()
|
|
||||||
|
|
||||||
proc/autotransfer()
|
|
||||||
initiate_vote("crew_transfer","the server", 1)
|
|
||||||
log_debug("The server has called a crew transfer vote")
|
|
||||||
|
|
||||||
proc/autogamemode()
|
|
||||||
initiate_vote("gamemode","the server", 1)
|
|
||||||
log_debug("The server has called a gamemode vote")
|
|
||||||
|
|
||||||
proc/reset()
|
|
||||||
initiator = null
|
|
||||||
time_remaining = 0
|
|
||||||
mode = null
|
|
||||||
question = null
|
|
||||||
choices.Cut()
|
|
||||||
voted.Cut()
|
|
||||||
voting.Cut()
|
|
||||||
current_votes.Cut()
|
|
||||||
additional_text.Cut()
|
|
||||||
|
|
||||||
proc/get_result()
|
|
||||||
//get the highest number of votes
|
|
||||||
var/greatest_votes = 0
|
|
||||||
var/total_votes = 0
|
|
||||||
for(var/option in choices)
|
|
||||||
var/votes = choices[option]
|
|
||||||
total_votes += votes
|
|
||||||
if(votes > greatest_votes)
|
|
||||||
greatest_votes = votes
|
|
||||||
//default-vote for everyone who didn't vote
|
|
||||||
if(!config.vote_no_default && choices.len)
|
|
||||||
var/non_voters = (clients.len - total_votes)
|
|
||||||
if(non_voters > 0)
|
|
||||||
if(mode == "restart")
|
|
||||||
choices["Continue Playing"] += non_voters
|
|
||||||
if(choices["Continue Playing"] >= greatest_votes)
|
|
||||||
greatest_votes = choices["Continue Playing"]
|
|
||||||
else if(mode == "gamemode")
|
|
||||||
if(master_mode in choices)
|
|
||||||
choices[master_mode] += non_voters
|
|
||||||
if(choices[master_mode] >= greatest_votes)
|
|
||||||
greatest_votes = choices[master_mode]
|
|
||||||
else if(mode == "crew_transfer")
|
|
||||||
var/factor = 0.5
|
|
||||||
switch(world.time / (10 * 60)) // minutes
|
|
||||||
if(0 to 60)
|
|
||||||
factor = 0.5
|
|
||||||
if(61 to 120)
|
|
||||||
factor = 0.8
|
|
||||||
if(121 to 240)
|
|
||||||
factor = 1
|
|
||||||
if(241 to 300)
|
|
||||||
factor = 1.2
|
|
||||||
else
|
|
||||||
factor = 1.4
|
|
||||||
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
|
|
||||||
world << "<font color='purple'>Crew Transfer Factor: [factor]</font>"
|
|
||||||
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
|
|
||||||
|
|
||||||
|
|
||||||
//get all options with that many votes and return them in a list
|
|
||||||
. = list()
|
|
||||||
if(greatest_votes)
|
|
||||||
for(var/option in choices)
|
|
||||||
if(choices[option] == greatest_votes)
|
|
||||||
. += option
|
|
||||||
return .
|
|
||||||
|
|
||||||
proc/announce_result()
|
|
||||||
var/list/winners = get_result()
|
|
||||||
var/text
|
|
||||||
if(winners.len > 0)
|
|
||||||
if(winners.len > 1)
|
|
||||||
if(mode != "gamemode" || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
|
|
||||||
text = "<b>Vote Tied Between:</b>\n"
|
|
||||||
for(var/option in winners)
|
|
||||||
text += "\t[option]\n"
|
|
||||||
. = pick(winners)
|
|
||||||
|
|
||||||
for(var/key in current_votes)
|
|
||||||
if(choices[current_votes[key]] == .)
|
|
||||||
round_voters += key // Keep track of who voted for the winning round.
|
|
||||||
if((mode == "gamemode" && . == "Extended") || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes
|
|
||||||
text += "<b>Vote Result: [.]</b>"
|
|
||||||
else
|
|
||||||
if(mode != "gamemode")
|
|
||||||
text += "<b>Vote Result: [.]</b>"
|
|
||||||
else
|
|
||||||
text += "<b>The vote has ended.</b>" // What will be shown if it is a gamemode vote that isn't extended
|
|
||||||
|
|
||||||
else
|
|
||||||
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
|
|
||||||
if(mode == "add_antagonist")
|
|
||||||
antag_add_failed = 1
|
|
||||||
log_vote(text)
|
|
||||||
world << "<font color='purple'>[text]</font>"
|
|
||||||
return .
|
|
||||||
|
|
||||||
proc/result()
|
|
||||||
. = announce_result()
|
|
||||||
var/restart = 0
|
|
||||||
if(.)
|
|
||||||
switch(mode)
|
|
||||||
if("restart")
|
|
||||||
if(. == "Restart Round")
|
|
||||||
restart = 1
|
|
||||||
if("gamemode")
|
|
||||||
if(master_mode != .)
|
|
||||||
world.save_mode(.)
|
|
||||||
if(ticker && ticker.mode)
|
|
||||||
restart = 1
|
|
||||||
else
|
|
||||||
master_mode = .
|
|
||||||
if("crew_transfer")
|
|
||||||
if(. == "Initiate Crew Transfer")
|
|
||||||
init_shift_change(null, 1)
|
|
||||||
if("add_antagonist")
|
|
||||||
if(isnull(.) || . == "None")
|
|
||||||
antag_add_failed = 1
|
|
||||||
else
|
|
||||||
additional_antag_types |= antag_names_to_ids[.]
|
|
||||||
|
|
||||||
if(mode == "gamemode") //fire this even if the vote fails.
|
|
||||||
if(!round_progressing)
|
|
||||||
round_progressing = 1
|
|
||||||
world << "<font color='red'><b>The round will start soon.</b></font>"
|
|
||||||
|
|
||||||
if(restart)
|
|
||||||
world << "World restarting due to vote..."
|
|
||||||
feedback_set_details("end_error","restart vote")
|
|
||||||
if(blackbox) blackbox.save_all_data_to_sql()
|
|
||||||
sleep(50)
|
|
||||||
log_game("Rebooting due to restart vote")
|
|
||||||
world.Reboot()
|
|
||||||
|
|
||||||
return .
|
|
||||||
|
|
||||||
proc/submit_vote(var/ckey, var/vote)
|
|
||||||
if(mode)
|
|
||||||
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
|
|
||||||
return 0
|
|
||||||
if(vote && vote >= 1 && vote <= choices.len)
|
|
||||||
if(current_votes[ckey])
|
|
||||||
choices[choices[current_votes[ckey]]]--
|
|
||||||
voted += usr.ckey
|
|
||||||
choices[choices[vote]]++ //check this
|
|
||||||
current_votes[ckey] = vote
|
|
||||||
return vote
|
|
||||||
return 0
|
|
||||||
|
|
||||||
proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0)
|
|
||||||
if(!mode)
|
|
||||||
if(started_time != null && !(check_rights(R_ADMIN) || automatic))
|
|
||||||
var/next_allowed_time = (started_time + config.vote_delay)
|
|
||||||
if(next_allowed_time > world.time)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
if(time_remaining < 0)
|
||||||
|
result()
|
||||||
reset()
|
reset()
|
||||||
switch(vote_type)
|
|
||||||
if("restart")
|
/datum/controller/vote/proc/autotransfer()
|
||||||
choices.Add("Restart Round","Continue Playing")
|
initiate_vote(VOTE_CREW_TRANSFER, "the server", 1)
|
||||||
if("gamemode")
|
log_debug("The server has called a crew transfer vote")
|
||||||
if(ticker.current_state >= 2)
|
|
||||||
return 0
|
/datum/controller/vote/proc/autogamemode()
|
||||||
choices.Add(config.votable_modes)
|
initiate_vote(VOTE_GAMEMODE, "the server", 1)
|
||||||
for (var/F in choices)
|
log_debug("The server has called a gamemode vote")
|
||||||
var/datum/game_mode/M = gamemode_cache[F]
|
|
||||||
if(!M)
|
/datum/controller/vote/proc/reset()
|
||||||
continue
|
initiator = null
|
||||||
gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works
|
time_remaining = 0
|
||||||
additional_text.Add("<td align = 'center'>[M.required_players]</td>")
|
mode = null
|
||||||
gamemode_names["secret"] = "Secret"
|
question = null
|
||||||
if("crew_transfer")
|
choices.Cut()
|
||||||
if(check_rights(R_ADMIN|R_MOD, 0))
|
voted.Cut()
|
||||||
question = "End the shift?"
|
current_votes.Cut()
|
||||||
choices.Add("Initiate Crew Transfer", "Continue The Round")
|
additional_text.Cut()
|
||||||
|
|
||||||
|
/datum/controller/vote/proc/get_result() // Get the highest number of votes
|
||||||
|
var/greatest_votes = 0
|
||||||
|
var/total_votes = 0
|
||||||
|
|
||||||
|
for(var/option in choices)
|
||||||
|
var/votes = choices[option]
|
||||||
|
total_votes += votes
|
||||||
|
if(votes > greatest_votes)
|
||||||
|
greatest_votes = votes
|
||||||
|
|
||||||
|
if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote
|
||||||
|
var/non_voters = (clients.len - total_votes)
|
||||||
|
if(non_voters > 0)
|
||||||
|
if(mode == VOTE_RESTART)
|
||||||
|
choices["Continue Playing"] += non_voters
|
||||||
|
if(choices["Continue Playing"] >= greatest_votes)
|
||||||
|
greatest_votes = choices["Continue Playing"]
|
||||||
|
else if(mode == VOTE_GAMEMODE)
|
||||||
|
if(master_mode in choices)
|
||||||
|
choices[master_mode] += non_voters
|
||||||
|
if(choices[master_mode] >= greatest_votes)
|
||||||
|
greatest_votes = choices[master_mode]
|
||||||
|
else if(mode == VOTE_CREW_TRANSFER)
|
||||||
|
var/factor = 0.5
|
||||||
|
switch(world.time / (10 * 60)) // minutes
|
||||||
|
if(0 to 60)
|
||||||
|
factor = 0.5
|
||||||
|
if(61 to 120)
|
||||||
|
factor = 0.8
|
||||||
|
if(121 to 240)
|
||||||
|
factor = 1
|
||||||
|
if(241 to 300)
|
||||||
|
factor = 1.2
|
||||||
else
|
else
|
||||||
if (get_security_level() == "red" || get_security_level() == "delta")
|
factor = 1.4
|
||||||
initiator_key << "The current alert status is too high to call for a crew transfer!"
|
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
|
||||||
return 0
|
world << "<font color='purple'>Crew Transfer Factor: [factor]</font>"
|
||||||
if(ticker.current_state <= 2)
|
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
|
||||||
return 0
|
|
||||||
initiator_key << "The crew transfer button has been disabled!"
|
|
||||||
question = "End the shift?"
|
|
||||||
choices.Add("Initiate Crew Transfer", "Continue The Round")
|
|
||||||
if("add_antagonist")
|
|
||||||
if(!config.allow_extra_antags || ticker.current_state >= 2)
|
|
||||||
return 0
|
|
||||||
for(var/antag_type in all_antag_types)
|
|
||||||
var/datum/antagonist/antag = all_antag_types[antag_type]
|
|
||||||
if(!(antag.id in additional_antag_types) && antag.is_votable())
|
|
||||||
choices.Add(antag.role_text)
|
|
||||||
choices.Add("None")
|
|
||||||
if("custom")
|
|
||||||
question = sanitizeSafe(input(usr,"What is the vote for?") as text|null)
|
|
||||||
if(!question) return 0
|
|
||||||
for(var/i=1,i<=10,i++)
|
|
||||||
var/option = capitalize(sanitize(input(usr,"Please enter an option or hit cancel to finish") as text|null))
|
|
||||||
if(!option || mode || !usr.client) break
|
|
||||||
choices.Add(option)
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
mode = vote_type
|
|
||||||
initiator = initiator_key
|
|
||||||
started_time = world.time
|
|
||||||
var/text = "[capitalize(mode)] vote started by [initiator]."
|
|
||||||
if(mode == "custom")
|
|
||||||
text += "\n[question]"
|
|
||||||
|
|
||||||
log_vote(text)
|
. = list() // Get all options with that many votes and return them in a list
|
||||||
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period/10] seconds to vote.</font>"
|
if(greatest_votes)
|
||||||
switch(vote_type)
|
for(var/option in choices)
|
||||||
if("crew_transfer")
|
if(choices[option] == greatest_votes)
|
||||||
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
|
. += option
|
||||||
if("gamemode")
|
|
||||||
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
|
|
||||||
if("custom")
|
|
||||||
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
|
|
||||||
if(mode == "gamemode" && round_progressing)
|
|
||||||
round_progressing = 0
|
|
||||||
world << "<font color='red'><b>Round start has been delayed.</b></font>"
|
|
||||||
|
|
||||||
time_remaining = round(config.vote_period/10)
|
/datum/controller/vote/proc/announce_result()
|
||||||
return 1
|
var/list/winners = get_result()
|
||||||
return 0
|
var/text
|
||||||
|
if(winners.len > 0)
|
||||||
|
if(winners.len > 1)
|
||||||
|
if(mode != VOTE_GAMEMODE || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
|
||||||
|
text = "<b>Vote Tied Between:</b>\n"
|
||||||
|
for(var/option in winners)
|
||||||
|
text += "\t[option]\n"
|
||||||
|
. = pick(winners)
|
||||||
|
|
||||||
proc/interface(var/client/C)
|
for(var/key in current_votes)
|
||||||
if(!C) return
|
if(choices[current_votes[key]] == .)
|
||||||
var/admin = 0
|
round_voters += key // Keep track of who voted for the winning round.
|
||||||
var/trialmin = 0
|
if(mode != VOTE_GAMEMODE || . == "Extended" || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes
|
||||||
if(C.holder)
|
text += "<b>Vote Result: [.]</b>"
|
||||||
if(C.holder.rights & R_ADMIN)
|
|
||||||
admin = 1
|
|
||||||
trialmin = 1 // don't know why we use both of these it's really weird, but I'm 2 lasy to refactor this all to use just admin.
|
|
||||||
voting |= C
|
|
||||||
|
|
||||||
. = "<html><head><title>Voting Panel</title></head><body>"
|
|
||||||
if(mode)
|
|
||||||
if(question) . += "<h2>Vote: '[question]'</h2>"
|
|
||||||
else . += "<h2>Vote: [capitalize(mode)]</h2>"
|
|
||||||
. += "Time Left: [time_remaining] s<hr>"
|
|
||||||
. += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>"
|
|
||||||
if(capitalize(mode) == "Gamemode") .+= "<td align = 'center'><b>Minimum Players</b></td></tr>"
|
|
||||||
|
|
||||||
for(var/i = 1, i <= choices.len, i++)
|
|
||||||
var/votes = choices[choices[i]]
|
|
||||||
if(!votes) votes = 0
|
|
||||||
. += "<tr>"
|
|
||||||
if(mode == "gamemode")
|
|
||||||
if(current_votes[C.ckey] == i)
|
|
||||||
. += "<td><b><a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a></b></td><td align = 'center'>[votes]</td>"
|
|
||||||
else
|
|
||||||
. += "<td><a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a></td><td align = 'center'>[votes]</td>"
|
|
||||||
else
|
|
||||||
if(current_votes[C.ckey] == i)
|
|
||||||
. += "<td><b><a href='?src=\ref[src];vote=[i]'>[choices[i]]</a></b></td><td align = 'center'>[votes]</td>"
|
|
||||||
else
|
|
||||||
. += "<td><a href='?src=\ref[src];vote=[i]'>[choices[i]]</a></td><td align = 'center'>[votes]</td>"
|
|
||||||
if (additional_text.len >= i)
|
|
||||||
. += additional_text[i]
|
|
||||||
. += "</tr>"
|
|
||||||
|
|
||||||
. += "</table><hr>"
|
|
||||||
if(admin)
|
|
||||||
. += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) "
|
|
||||||
else
|
else
|
||||||
. += "<h2>Start a vote:</h2><hr><ul><li>"
|
text += "<b>The vote has ended.</b>"
|
||||||
//restart
|
|
||||||
if(trialmin || config.allow_vote_restart)
|
|
||||||
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
|
|
||||||
else
|
|
||||||
. += "<font color='grey'>Restart (Disallowed)</font>"
|
|
||||||
. += "</li><li>"
|
|
||||||
if(trialmin || config.allow_vote_restart)
|
|
||||||
. += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>"
|
|
||||||
else
|
|
||||||
. += "<font color='grey'>Crew Transfer (Disallowed)</font>"
|
|
||||||
if(trialmin)
|
|
||||||
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
|
|
||||||
. += "</li><li>"
|
|
||||||
//gamemode
|
|
||||||
if(trialmin || config.allow_vote_mode)
|
|
||||||
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
|
|
||||||
else
|
|
||||||
. += "<font color='grey'>GameMode (Disallowed)</font>"
|
|
||||||
if(trialmin)
|
|
||||||
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
|
|
||||||
. += "</li><li>"
|
|
||||||
//extra antagonists
|
|
||||||
if(!antag_add_failed && config.allow_extra_antags)
|
|
||||||
. += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>"
|
|
||||||
else
|
|
||||||
. += "<font color='grey'>Restart (Disallowed)</font>"
|
|
||||||
. += "</li>"
|
|
||||||
//custom
|
|
||||||
if(trialmin)
|
|
||||||
. += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>"
|
|
||||||
. += "</ul><hr>"
|
|
||||||
. += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>"
|
|
||||||
return .
|
|
||||||
|
|
||||||
|
else
|
||||||
|
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
|
||||||
|
if(mode == VOTE_ADD_ANTAGONIST)
|
||||||
|
antag_add_failed = 1
|
||||||
|
log_vote(text)
|
||||||
|
world << "<font color='purple'>[text]</font>"
|
||||||
|
|
||||||
Topic(href,href_list[],hsrc)
|
/datum/controller/vote/proc/result()
|
||||||
if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid
|
. = announce_result()
|
||||||
switch(href_list["vote"])
|
var/restart = 0
|
||||||
if("close")
|
if(.)
|
||||||
voting -= usr.client
|
switch(mode)
|
||||||
usr << browse(null, "window=vote")
|
if(VOTE_RESTART)
|
||||||
return
|
if(. == "Restart Round")
|
||||||
if("cancel")
|
restart = 1
|
||||||
if(usr.client.holder)
|
if(VOTE_GAMEMODE)
|
||||||
reset()
|
if(master_mode != .)
|
||||||
if("toggle_restart")
|
world.save_mode(.)
|
||||||
if(usr.client.holder)
|
if(ticker && ticker.mode)
|
||||||
config.allow_vote_restart = !config.allow_vote_restart
|
restart = 1
|
||||||
if("toggle_gamemode")
|
else
|
||||||
if(usr.client.holder)
|
master_mode = .
|
||||||
config.allow_vote_mode = !config.allow_vote_mode
|
if(VOTE_CREW_TRANSFER)
|
||||||
if("restart")
|
if(. == "Initiate Crew Transfer")
|
||||||
if(config.allow_vote_restart || usr.client.holder)
|
init_shift_change(null, 1)
|
||||||
initiate_vote("restart",usr.key)
|
if(VOTE_ADD_ANTAGONIST)
|
||||||
if("gamemode")
|
if(isnull(.) || . == "None")
|
||||||
if(config.allow_vote_mode || usr.client.holder)
|
antag_add_failed = 1
|
||||||
initiate_vote("gamemode",usr.key)
|
else
|
||||||
if("crew_transfer")
|
additional_antag_types |= antag_names_to_ids[.]
|
||||||
if(config.allow_vote_restart || usr.client.holder)
|
|
||||||
initiate_vote("crew_transfer",usr.key)
|
if(mode == VOTE_GAMEMODE) //fire this even if the vote fails.
|
||||||
if("add_antagonist")
|
if(!round_progressing)
|
||||||
if(config.allow_extra_antags)
|
round_progressing = 1
|
||||||
initiate_vote("add_antagonist",usr.key)
|
world << "<font color='red'><b>The round will start soon.</b></font>"
|
||||||
if("custom")
|
|
||||||
if(usr.client.holder)
|
if(restart)
|
||||||
initiate_vote("custom",usr.key)
|
world << "World restarting due to vote..."
|
||||||
|
feedback_set_details("end_error", "restart vote")
|
||||||
|
if(blackbox)
|
||||||
|
blackbox.save_all_data_to_sql()
|
||||||
|
sleep(50)
|
||||||
|
log_game("Rebooting due to restart vote")
|
||||||
|
world.Reboot()
|
||||||
|
|
||||||
|
/datum/controller/vote/proc/submit_vote(var/ckey, var/newVote)
|
||||||
|
if(mode)
|
||||||
|
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
|
||||||
|
return
|
||||||
|
if(current_votes[ckey])
|
||||||
|
choices[choices[current_votes[ckey]]]--
|
||||||
|
if(newVote && newVote >= 1 && newVote <= choices.len)
|
||||||
|
choices[choices[newVote]]++
|
||||||
|
current_votes[ckey] = newVote
|
||||||
|
else
|
||||||
|
current_votes[ckey] = null
|
||||||
|
|
||||||
|
/datum/controller/vote/proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0)
|
||||||
|
if(!mode)
|
||||||
|
if(started_time != null && !(check_rights(R_ADMIN) || automatic))
|
||||||
|
var/next_allowed_time = (started_time + config.vote_delay)
|
||||||
|
if(next_allowed_time > world.time)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
reset()
|
||||||
|
|
||||||
|
switch(vote_type)
|
||||||
|
if(VOTE_RESTART)
|
||||||
|
choices.Add("Restart Round", "Continue Playing")
|
||||||
|
if(VOTE_GAMEMODE)
|
||||||
|
if(ticker.current_state >= GAME_STATE_SETTING_UP)
|
||||||
|
return 0
|
||||||
|
choices.Add(config.votable_modes)
|
||||||
|
for(var/F in choices)
|
||||||
|
var/datum/game_mode/M = gamemode_cache[F]
|
||||||
|
if(!M)
|
||||||
|
continue
|
||||||
|
gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works
|
||||||
|
additional_text.Add("<td align = 'center'>[M.required_players]</td>")
|
||||||
|
gamemode_names["secret"] = "Secret"
|
||||||
|
if(VOTE_CREW_TRANSFER)
|
||||||
|
if(!check_rights(R_ADMIN|R_MOD, 0)) // The gods care not for the affairs of the mortals
|
||||||
|
if(get_security_level() == "red" || get_security_level() == "delta")
|
||||||
|
initiator_key << "The current alert status is too high to call for a crew transfer!"
|
||||||
|
return 0
|
||||||
|
if(ticker.current_state <= GAME_STATE_SETTING_UP)
|
||||||
|
initiator_key << "The crew transfer button has been disabled!"
|
||||||
|
return 0
|
||||||
|
question = "End the shift?"
|
||||||
|
choices.Add("Initiate Crew Transfer", "Continue The Round")
|
||||||
|
if(VOTE_ADD_ANTAGONIST)
|
||||||
|
if(!config.allow_extra_antags || ticker.current_state >= GAME_STATE_SETTING_UP)
|
||||||
|
return 0
|
||||||
|
for(var/antag_type in all_antag_types)
|
||||||
|
var/datum/antagonist/antag = all_antag_types[antag_type]
|
||||||
|
if(!(antag.id in additional_antag_types) && antag.is_votable())
|
||||||
|
choices.Add(antag.role_text)
|
||||||
|
choices.Add("None")
|
||||||
|
if(VOTE_CUSTOM)
|
||||||
|
question = sanitizeSafe(input(usr, "What is the vote for?") as text|null)
|
||||||
|
if(!question)
|
||||||
|
return 0
|
||||||
|
for(var/i = 1 to 10)
|
||||||
|
var/option = capitalize(sanitize(input(usr, "Please enter an option or hit cancel to finish") as text|null))
|
||||||
|
if(!option || mode || !usr.client)
|
||||||
|
break
|
||||||
|
choices.Add(option)
|
||||||
else
|
else
|
||||||
var/t = round(text2num(href_list["vote"]))
|
return 0
|
||||||
if(t) // It starts from 1, so there's no problem
|
|
||||||
submit_vote(usr.ckey, t)
|
|
||||||
usr.vote()
|
|
||||||
|
|
||||||
|
mode = vote_type
|
||||||
|
initiator = initiator_key
|
||||||
|
started_time = world.time
|
||||||
|
var/text = "[capitalize(mode)] vote started by [initiator]."
|
||||||
|
if(mode == VOTE_CUSTOM)
|
||||||
|
text += "\n[question]"
|
||||||
|
|
||||||
/mob/verb/vote()
|
log_vote(text)
|
||||||
|
|
||||||
|
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period / 10] seconds to vote.</font>"
|
||||||
|
if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM)
|
||||||
|
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
|
||||||
|
|
||||||
|
if(mode == VOTE_GAMEMODE && round_progressing)
|
||||||
|
round_progressing = 0
|
||||||
|
world << "<font color='red'><b>Round start has been delayed.</b></font>"
|
||||||
|
|
||||||
|
time_remaining = round(config.vote_period / 10)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
/datum/controller/vote/proc/interface(var/client/C)
|
||||||
|
if(!istype(C))
|
||||||
|
return
|
||||||
|
var/admin = 0
|
||||||
|
if(C.holder)
|
||||||
|
if(C.holder.rights & R_ADMIN)
|
||||||
|
admin = 1
|
||||||
|
|
||||||
|
. = "<html><head><title>Voting Panel</title></head><body>"
|
||||||
|
if(mode)
|
||||||
|
if(question)
|
||||||
|
. += "<h2>Vote: '[question]'</h2>"
|
||||||
|
else
|
||||||
|
. += "<h2>Vote: [capitalize(mode)]</h2>"
|
||||||
|
. += "Time Left: [time_remaining] s<hr>"
|
||||||
|
. += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>"
|
||||||
|
if(mode == VOTE_GAMEMODE)
|
||||||
|
.+= "<td align = 'center'><b>Minimum Players</b></td></tr>"
|
||||||
|
|
||||||
|
for(var/i = 1 to choices.len)
|
||||||
|
var/votes = choices[choices[i]]
|
||||||
|
if(!votes)
|
||||||
|
votes = 0
|
||||||
|
. += "<tr>"
|
||||||
|
var/thisVote = (current_votes[C.ckey] == i)
|
||||||
|
if(mode == VOTE_GAMEMODE)
|
||||||
|
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
|
||||||
|
else
|
||||||
|
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[choices[i]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
|
||||||
|
if (additional_text.len >= i)
|
||||||
|
. += additional_text[i]
|
||||||
|
. += "</tr>"
|
||||||
|
|
||||||
|
. += "<tr><td><a href='?src=\ref[src];vote=unvote'>Unvote</a></td></tr>"
|
||||||
|
|
||||||
|
. += "</table><hr>"
|
||||||
|
if(admin)
|
||||||
|
. += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) "
|
||||||
|
else
|
||||||
|
. += "<h2>Start a vote:</h2><hr><ul><li>"
|
||||||
|
if(admin || config.allow_vote_restart)
|
||||||
|
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
|
||||||
|
else
|
||||||
|
. += "<font color='grey'>Restart (Disallowed)</font>"
|
||||||
|
. += "</li><li>"
|
||||||
|
|
||||||
|
if(admin || config.allow_vote_restart)
|
||||||
|
. += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>"
|
||||||
|
else
|
||||||
|
. += "<font color='grey'>Crew Transfer (Disallowed)</font>"
|
||||||
|
|
||||||
|
if(admin)
|
||||||
|
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart ? "Allowed" : "Disallowed"]</a>)"
|
||||||
|
. += "</li><li>"
|
||||||
|
|
||||||
|
if(admin || config.allow_vote_mode)
|
||||||
|
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
|
||||||
|
else
|
||||||
|
. += "<font color='grey'>GameMode (Disallowed)</font>"
|
||||||
|
|
||||||
|
if(admin)
|
||||||
|
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode ? "Allowed" : "Disallowed"]</a>)"
|
||||||
|
. += "</li><li>"
|
||||||
|
|
||||||
|
if(!antag_add_failed && config.allow_extra_antags)
|
||||||
|
. += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>"
|
||||||
|
else
|
||||||
|
. += "<font color='grey'>Add Antagonist (Disallowed)</font>"
|
||||||
|
. += "</li>"
|
||||||
|
|
||||||
|
if(admin)
|
||||||
|
. += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>"
|
||||||
|
. += "</ul><hr>"
|
||||||
|
|
||||||
|
. += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>"
|
||||||
|
|
||||||
|
/datum/controller/vote/Topic(href, href_list[])
|
||||||
|
if(!usr || !usr.client)
|
||||||
|
return
|
||||||
|
switch(href_list["vote"])
|
||||||
|
if("close")
|
||||||
|
usr << browse(null, "window=vote")
|
||||||
|
return
|
||||||
|
|
||||||
|
if("cancel")
|
||||||
|
if(usr.client.holder)
|
||||||
|
reset()
|
||||||
|
if("toggle_restart")
|
||||||
|
if(usr.client.holder)
|
||||||
|
config.allow_vote_restart = !config.allow_vote_restart
|
||||||
|
if("toggle_gamemode")
|
||||||
|
if(usr.client.holder)
|
||||||
|
config.allow_vote_mode = !config.allow_vote_mode
|
||||||
|
|
||||||
|
if(VOTE_RESTART)
|
||||||
|
if(config.allow_vote_restart || usr.client.holder)
|
||||||
|
initiate_vote(VOTE_RESTART, usr.key)
|
||||||
|
if(VOTE_GAMEMODE)
|
||||||
|
if(config.allow_vote_mode || usr.client.holder)
|
||||||
|
initiate_vote(VOTE_GAMEMODE, usr.key)
|
||||||
|
if(VOTE_CREW_TRANSFER)
|
||||||
|
if(config.allow_vote_restart || usr.client.holder)
|
||||||
|
initiate_vote(VOTE_CREW_TRANSFER, usr.key)
|
||||||
|
if(VOTE_ADD_ANTAGONIST)
|
||||||
|
if(config.allow_extra_antags || usr.client.holder)
|
||||||
|
initiate_vote(VOTE_ADD_ANTAGONIST, usr.key)
|
||||||
|
if(VOTE_CUSTOM)
|
||||||
|
if(usr.client.holder)
|
||||||
|
initiate_vote(VOTE_CUSTOM, usr.key)
|
||||||
|
|
||||||
|
if("unvote")
|
||||||
|
submit_vote(usr.ckey, null)
|
||||||
|
|
||||||
|
else
|
||||||
|
var/t = round(text2num(href_list["vote"]))
|
||||||
|
if(t) // It starts from 1, so there's no problem
|
||||||
|
submit_vote(usr.ckey, t)
|
||||||
|
usr.client.vote()
|
||||||
|
|
||||||
|
/client/verb/vote()
|
||||||
set category = "OOC"
|
set category = "OOC"
|
||||||
set name = "Vote"
|
set name = "Vote"
|
||||||
|
|
||||||
if(vote)
|
if(vote)
|
||||||
src << browse(vote.interface(client),"window=vote")
|
src << browse(vote.interface(src), "window=vote;size=500x[300 + vote.choices.len * 25]")
|
||||||
|
|||||||
@@ -103,25 +103,26 @@ var/global/list/all_exonet_connections = list()
|
|||||||
return null
|
return null
|
||||||
|
|
||||||
// Proc: send_message()
|
// Proc: send_message()
|
||||||
// Parameters: 2 (target_address - the desired address to send the message to, message - the message to send)
|
// Parameters: 3 (target_address - the desired address to send the message to, message - the message to send, text - the message text if message is of type "text")
|
||||||
// Description: Sends the message to target_address, by calling receive_message() on the desired datum.
|
// Description: Sends the message to target_address, by calling receive_message() on the desired datum.
|
||||||
/datum/exonet_protocol/proc/send_message(var/target_address, var/message)
|
/datum/exonet_protocol/proc/send_message(var/target_address, var/message, var/text)
|
||||||
if(!address)
|
if(!address)
|
||||||
return 0
|
return 0
|
||||||
for(var/datum/exonet_protocol/exonet in all_exonet_connections)
|
for(var/datum/exonet_protocol/exonet in all_exonet_connections)
|
||||||
if(exonet.address == target_address)
|
if(exonet.address == target_address)
|
||||||
exonet.receive_message(holder, address, message)
|
exonet.receive_message(holder, address, message, text)
|
||||||
break
|
break
|
||||||
|
|
||||||
// Proc: receive_message()
|
// Proc: receive_message()
|
||||||
// Parameters: 3 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent)
|
// Parameters: 4 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent,
|
||||||
|
// text - the message text if message is of type "text")
|
||||||
// Description: Called when send_message() successfully reaches the intended datum. By default, calls receive_exonet_message() on the holder atom.
|
// Description: Called when send_message() successfully reaches the intended datum. By default, calls receive_exonet_message() on the holder atom.
|
||||||
/datum/exonet_protocol/proc/receive_message(var/atom/origin_atom, var/origin_address, var/message)
|
/datum/exonet_protocol/proc/receive_message(var/atom/origin_atom, var/origin_address, var/message, var/text)
|
||||||
holder.receive_exonet_message(origin_atom, origin_address, message)
|
holder.receive_exonet_message(origin_atom, origin_address, message, text)
|
||||||
return
|
return
|
||||||
|
|
||||||
// Proc: receive_exonet_message()
|
// Proc: receive_exonet_message()
|
||||||
// Parameters: 3 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent)
|
// Parameters: 3 (origin_atom - the origin datum's holder, origin_address - the address the message originated from, message - the message that was sent)
|
||||||
// Description: Override this to make your atom do something when a message is received.
|
// Description: Override this to make your atom do something when a message is received.
|
||||||
/atom/proc/receive_exonet_message(var/atom/origin_atom, var/origin_address, var/message)
|
/atom/proc/receive_exonet_message(var/atom/origin_atom, var/origin_address, var/message, var/text)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
height = nheight
|
height = nheight
|
||||||
if (nref)
|
if (nref)
|
||||||
ref = nref
|
ref = nref
|
||||||
|
// If a client exists, but they have disabled fancy windowing, disable it!
|
||||||
|
if(user && user.client && !user.client.is_preference_enabled(/datum/client_preference/browser_style))
|
||||||
|
return
|
||||||
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
|
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
|
||||||
|
|
||||||
/datum/browser/proc/set_title(ntitle)
|
/datum/browser/proc/set_title(ntitle)
|
||||||
@@ -74,10 +77,11 @@
|
|||||||
if (title_image)
|
if (title_image)
|
||||||
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
|
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
|
||||||
|
|
||||||
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
return {"<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<meta charset=ISO-8859-1">
|
||||||
<head>
|
<head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
[head_content]
|
[head_content]
|
||||||
</head>
|
</head>
|
||||||
<body scroll=auto>
|
<body scroll=auto>
|
||||||
@@ -177,4 +181,4 @@
|
|||||||
if(src && src.mob)
|
if(src && src.mob)
|
||||||
//world << "[src] was [src.mob.machine], setting to null"
|
//world << "[src] was [src.mob.machine], setting to null"
|
||||||
src.mob.unset_machine()
|
src.mob.unset_machine()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,17 +2,20 @@
|
|||||||
* Category Collection *
|
* Category Collection *
|
||||||
**********************/
|
**********************/
|
||||||
/datum/category_collection
|
/datum/category_collection
|
||||||
var/category_group_type // The type of categories to initialize
|
var/category_group_type // Type of categories to initialize
|
||||||
var/list/datum/category_group/categories // The list of initialized categories
|
var/list/datum/category_group/categories // List of initialized categories
|
||||||
|
var/list/datum/category_group/categories_by_name // Associative list of initialized categories, keyed by name
|
||||||
|
|
||||||
/datum/category_collection/New()
|
/datum/category_collection/New()
|
||||||
..()
|
..()
|
||||||
categories = new()
|
categories = new()
|
||||||
|
categories_by_name = new()
|
||||||
for(var/category_type in typesof(category_group_type))
|
for(var/category_type in typesof(category_group_type))
|
||||||
var/datum/category_group/category = category_type
|
var/datum/category_group/category = category_type
|
||||||
if(initial(category.name))
|
if(initial(category.name))
|
||||||
category = new category(src)
|
category = new category(src)
|
||||||
categories += category
|
categories += category
|
||||||
|
categories_by_name[category.name] = category
|
||||||
categories = dd_sortedObjectList(categories)
|
categories = dd_sortedObjectList(categories)
|
||||||
|
|
||||||
/datum/category_collection/Destroy()
|
/datum/category_collection/Destroy()
|
||||||
@@ -26,20 +29,23 @@
|
|||||||
******************/
|
******************/
|
||||||
/datum/category_group
|
/datum/category_group
|
||||||
var/name = ""
|
var/name = ""
|
||||||
var/category_item_type // The type of items to initialize
|
var/category_item_type // Type of items to initialize
|
||||||
var/list/datum/category_item/items // The list of initialized items
|
var/list/datum/category_item/items // List of initialized items
|
||||||
var/datum/category_collection/collection // The collection this group belongs to
|
var/list/datum/category_item/items_by_name // Associative list of initialized items, by name
|
||||||
|
var/datum/category_collection/collection // The collection this group belongs to
|
||||||
|
|
||||||
/datum/category_group/New(var/datum/category_collection/cc)
|
/datum/category_group/New(var/datum/category_collection/cc)
|
||||||
..()
|
..()
|
||||||
collection = cc
|
collection = cc
|
||||||
items = new()
|
items = new()
|
||||||
|
items_by_name = new()
|
||||||
|
|
||||||
for(var/item_type in typesof(category_item_type))
|
for(var/item_type in typesof(category_item_type))
|
||||||
var/datum/category_item/item = item_type
|
var/datum/category_item/item = item_type
|
||||||
if(initial(item.name))
|
if(initial(item.name))
|
||||||
item = new item(src)
|
item = new item(src)
|
||||||
items += item
|
items += item
|
||||||
|
items_by_name[item.name] = item
|
||||||
|
|
||||||
// For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order
|
// For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order
|
||||||
// If you change this, confirm that character setup doesn't become completely unordered.
|
// If you change this, confirm that character setup doesn't become completely unordered.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user