Tg patch branch to master (#192)
* code nitpicking * Midnight oil More like 6am oil. Still having issues with actually eating anyone. * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * missed commit * Noms * specific release doesn't work * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Tg modern (#149) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * Mentor system, Tickets, and discord (#151) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * vore tweaks * progress * dirtier fix than a korean hooker in the 60s * The release your hooker will always fake * you could save that hookers number but wouldn't you rather just vore the hooker instead * Save system is literal black magic * great googly moogly it's all gone to shit * We May 2015 save code now * fiddling with digestion code now * fuck if I know anymore. I'm going to bed * OWN UP YOUR OWN DIGESTION * UNREGULATED GUTS ARE NON COMPLIANT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * BELLIES MUST COMPLY WITH USER OWNERSHIP * Removed debug messages * Unneeded verb additions * file change tweaks * WATCH YOUR SPACING, DRIVER * Changelog and devourment for some mobs. Because I knew people were gunna ask. NO YOU CANNOT EAT THE FUCKING LEGION * Vore code sync (#157) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Escape and Devourable For the normies who play here yet complain about it. * Things that should be committed * unneeded files * Sizeray works now * tweaks and bed time going * IT WORKS mostly Need to get multiple guts and saving working tho * save tweaks * item hotfix * gut examine message * damifino * save system works also ensured some mobs have vore controls, so silicons can't even remotely do vore things. * code nitpicking * Midnight oil More like 6am oil. Still having issues with actually eating anyone. * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * missed commit * Noms * specific release doesn't work * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * vore tweaks * progress * dirtier fix than a korean hooker in the 60s * The release your hooker will always fake * you could save that hookers number but wouldn't you rather just vore the hooker instead * Save system is literal black magic * great googly moogly it's all gone to shit * We May 2015 save code now * fiddling with digestion code now * fuck if I know anymore. I'm going to bed * OWN UP YOUR OWN DIGESTION * UNREGULATED GUTS ARE NON COMPLIANT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * BELLIES MUST COMPLY WITH USER OWNERSHIP * Removed debug messages * Unneeded verb additions * file change tweaks * WATCH YOUR SPACING, DRIVER * Changelog and devourment for some mobs. Because I knew people were gunna ask. NO YOU CANNOT EAT THE FUCKING LEGION * title screen change from Crow's PR. * More of Crow's title screen stuff * mode tweaks.... again * gamemode voting in lobby via TalkingCactus disabled ashwalkers as roundstart Verk's species tweak paralax starts disabled by default * LOOC * index sync problem (#158) * digifix * things * furry races.dm * actually deletes species_types * maps * tgui and stuff * Sounds * icon updates * Defines and helpers * global vars and on click * controllers * datums * game folder * fixes invisible flan mobs * some modules * dropbomb verb enhanced * moar * moar * moar * even more again * and finally these for modules * Some compile tweaks * silly dme get updated you scrub * compiles cleanly now * various open PR fixes from TG as of 0800 Texas Standard Time * also fancy cryopods before I forget again * headslug gold core fix * edgy code of the modernization (#164) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Escape and Devourable For the normies who play here yet complain about it. * Things that should be committed * unneeded files * Sizeray works now * tweaks and bed time going * IT WORKS mostly Need to get multiple guts and saving working tho * save tweaks * item hotfix * gut examine message * damifino * save system works also ensured some mobs have vore controls, so silicons can't even remotely do vore things. * code nitpicking * Midnight oil More like 6am oil. Still having issues with actually eating anyone. * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * missed commit * Noms * specific release doesn't work * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * vore tweaks * progress * Small fixes for dogborgs and sprite accessories: -Ported the hidden snippets of the dogborg code. -Reset module now resets pixel offset and icon directory again. (broke shit when reseting from dogborg) -Medihound belly fixed. -Husky body marking tweaked to not overlap arms in side view. -Added husky ears that are basically wolf ears that use secondary color instead. * dirtier fix than a korean hooker in the 60s * The release your hooker will always fake * you could save that hookers number but wouldn't you rather just vore the hooker instead * Save system is literal black magic * great googly moogly it's all gone to shit * We May 2015 save code now * fiddling with digestion code now * fuck if I know anymore. I'm going to bed * OWN UP YOUR OWN DIGESTION * UNREGULATED GUTS ARE NON COMPLIANT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * BELLIES MUST COMPLY WITH USER OWNERSHIP * Removed debug messages * Unneeded verb additions * file change tweaks * WATCH YOUR SPACING, DRIVER * Changelog and devourment for some mobs. Because I knew people were gunna ask. NO YOU CANNOT EAT THE FUCKING LEGION * title screen change from Crow's PR. * More of Crow's title screen stuff * mode tweaks.... again * gamemode voting in lobby via TalkingCactus disabled ashwalkers as roundstart Verk's species tweak paralax starts disabled by default * LOOC * index sync problem (#158) * digifix * things * furry races.dm * actually deletes species_types * maps * tgui and stuff * Sounds * icon updates * Defines and helpers * global vars and on click * controllers * datums * game folder * fixes invisible flan mobs * some modules * dropbomb verb enhanced * moar * moar * moar * even more again * and finally these for modules * Some compile tweaks * silly dme get updated you scrub * compiles cleanly now * various open PR fixes from TG as of 0800 Texas Standard Time * also fancy cryopods before I forget again * headslug gold core fix * some species and DNA tweaks * Digest already damn you * suddenly sound and resist works. wtf * Minor tweaks, cryopod noise change * Vore tested working, species working * Merge test onto bleeding edgy (#165) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Escape and Devourable For the normies who play here yet complain about it. * Things that should be committed * unneeded files * Sizeray works now * tweaks and bed time going * IT WORKS mostly Need to get multiple guts and saving working tho * save tweaks * item hotfix * gut examine message * damifino * save system works also ensured some mobs have vore controls, so silicons can't even remotely do vore things. * code nitpicking * Midnight oil More like 6am oil. Still having issues with actually eating anyone. * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * missed commit * Noms * specific release doesn't work * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * vore tweaks * progress * Small fixes for dogborgs and sprite accessories: -Ported the hidden snippets of the dogborg code. -Reset module now resets pixel offset and icon directory again. (broke shit when reseting from dogborg) -Medihound belly fixed. -Husky body marking tweaked to not overlap arms in side view. -Added husky ears that are basically wolf ears that use secondary color instead. * dirtier fix than a korean hooker in the 60s * The release your hooker will always fake * you could save that hookers number but wouldn't you rather just vore the hooker instead * Save system is literal black magic * great googly moogly it's all gone to shit * We May 2015 save code now * fiddling with digestion code now * fuck if I know anymore. I'm going to bed * OWN UP YOUR OWN DIGESTION * UNREGULATED GUTS ARE NON COMPLIANT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * BELLIES MUST COMPLY WITH USER OWNERSHIP * Removed debug messages * Unneeded verb additions * file change tweaks * WATCH YOUR SPACING, DRIVER * Changelog and devourment for some mobs. Because I knew people were gunna ask. NO YOU CANNOT EAT THE FUCKING LEGION * title screen change from Crow's PR. * More of Crow's title screen stuff * mode tweaks.... again * gamemode voting in lobby via TalkingCactus disabled ashwalkers as roundstart Verk's species tweak paralax starts disabled by default * LOOC * index sync problem (#158) * digifix * things * furry races.dm * actually deletes species_types * maps * tgui and stuff * Sounds * icon updates * Defines and helpers * global vars and on click * controllers * datums * game folder * fixes invisible flan mobs * some modules * dropbomb verb enhanced * moar * moar * moar * even more again * and finally these for modules * Some compile tweaks * silly dme get updated you scrub * compiles cleanly now * various open PR fixes from TG as of 0800 Texas Standard Time * also fancy cryopods before I forget again * headslug gold core fix * some species and DNA tweaks * Digest already damn you * suddenly sound and resist works. wtf * Minor tweaks, cryopod noise change * Vore tested working, species working * travis map updates * updates * pool's closed due to lag * datum pools are closed too * Initializing new pool's closed * Pool's closed and initializing shit is done * sprite updates * chattering is okay to do now. * bleeblin edgy 1/23 (#166) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Escape and Devourable For the normies who play here yet complain about it. * Things that should be committed * unneeded files * Sizeray works now * tweaks and bed time going * IT WORKS mostly Need to get multiple guts and saving working tho * save tweaks * item hotfix * gut examine message * damifino * save system works also ensured some mobs have vore controls, so silicons can't even remotely do vore things. * code nitpicking * Midnight oil More like 6am oil. Still having issues with actually eating anyone. * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * missed commit * Noms * specific release doesn't work * Tg modernization patch (#115) * sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * Subsystem 12/21 Most Recent TG subsystem folder * globalvars 12/21 Tossed out the flavor_misc and parallax files * Onclick 12/21 as well as .dme updates * _defines 12/21 ommited old _MC.dm * _HELPERS 12/21 Preserved snowflake placement of furry sprites * _defeines/genetics reapplied narkism holdover for snowflake races. * Oops forgot mutant colors * modules porting 12/21 + Sounds/icons Admin, Client and most of mob life files ommitted * enviroment file * Admin optimizations ahelp log system kept * Mob ports 12/21 Flavor text preserved * datums ported 12/21 * Game ported 12/21 * batch of duplicate fixes/dogborg work Dogborgs need to be modernized to refractored borg standards. * moar fixes * Maps and futher compile fixes * port from cactus did * fix format error * Update preferences.dm unfuck * Revert "port from cactus did" * unfuck * more sprite work * vore * disabled roundstart xenos for now * admin QOL needs callback porting, TBD * Mentor system initial port I'm sure I've missed a fuckton of shit * test merge * Jesus tits did this finally fix compile issues? * Initial test compiles. hooray. * Admin ticket fixes * I'll give you a bad argument you piece of shit dream maker I fucking swear on my mum * who list wip also ahelps are broken again. fuck if I know why * discord bot basics * maybe tickets work now & bot framework done * ahelp callback readd * vore tweaks * progress * Small fixes for dogborgs and sprite accessories: -Ported the hidden snippets of the dogborg code. -Reset module now resets pixel offset and icon directory again. (broke shit when reseting from dogborg) -Medihound belly fixed. -Husky body marking tweaked to not overlap arms in side view. -Added husky ears that are basically wolf ears that use secondary color instead. * dirtier fix than a korean hooker in the 60s * The release your hooker will always fake * you could save that hookers number but wouldn't you rather just vore the hooker instead * Save system is literal black magic * great googly moogly it's all gone to shit * We May 2015 save code now * fiddling with digestion code now * fuck if I know anymore. I'm going to bed * OWN UP YOUR OWN DIGESTION * UNREGULATED GUTS ARE NON COMPLIANT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * BELLIES MUST COMPLY WITH USER OWNERSHIP * Removed debug messages * Unneeded verb additions * file change tweaks * WATCH YOUR SPACING, DRIVER * Changelog and devourment for some mobs. Because I knew people were gunna ask. NO YOU CANNOT EAT THE FUCKING LEGION * title screen change from Crow's PR. * More of Crow's title screen stuff * mode tweaks.... again * gamemode voting in lobby via TalkingCactus disabled ashwalkers as roundstart Verk's species tweak paralax starts disabled by default * LOOC * index sync problem (#158) * digifix * things * furry races.dm * actually deletes species_types * maps * tgui and stuff * Sounds * icon updates * Defines and helpers * global vars and on click * controllers * datums * game folder * fixes invisible flan mobs * some modules * dropbomb verb enhanced * moar * moar * moar * even more again * and finally these for modules * Some compile tweaks * silly dme get updated you scrub * compiles cleanly now * various open PR fixes from TG as of 0800 Texas Standard Time * also fancy cryopods before I forget again * headslug gold core fix * some species and DNA tweaks * Digest already damn you * suddenly sound and resist works. wtf * Minor tweaks, cryopod noise change * Vore tested working, species working * travis map updates * updates * pool's closed due to lag * datum pools are closed too * Initializing new pool's closed * Pool's closed and initializing shit is done * sprite updates * chattering is okay to do now. * Update .travis.yml * Update .travis.yml * Update .travis.yml * Revert "Modern modern" * Revert "Revert "Modern modern"" * fix it fix it fix it fix it * fixes title screen - thanks crow * Riding code reverted * possible tgui fix? * who the fuck even knows if this is the problem * adds moths and sharks (no colors yet, not greyscaled) adds LOOC back * "fixes" missing items in some machinery. * slight tweaks to abductor spawns borer event enabled (max 1) * Update .travis.yml * fixes shuttle purchase from comms * fixes and QoL * Polymorphing all is dangerous too * re-fixes ahelp ticket system again * metagaming check proving to be spamlicious * Fixes not being able to see devoured mob poses * fix for vehicle buckling * ahelp timer runtime fix (#178) * controller and game updates 1/29 * Defines, helpers, datums 1/29 * world.dm updates * modules/admin tweaks * everything in modules not a mob * modules/mob fixes and such No more PAIs ventcrawling * icons, maps, tools, etc. * compiler fixes * round type vote fixed * hardsuit cargo pack * reduce ion and electric storm chance * perms access for travis * fix helmet to the suit removes CE from crate * changelog * fuck * perms for travis... again * Update tgstation.dme * Update tgstation.dme * Donation race * redpanda * red panda * size play work * Size chemical basics Needs testing/refining * some fixing ports before I just fucking ported it anyway * It's been a fucking week. * commiting moar changes because github * admins.txt lol * icons * defines and such * globalvars and onclick * Controllers * datums * game folder * oh look, HoG is back * modules pt 1 * client things * more modules * everything not mob code * some mob stuff * more mob things * silicon mobs * ayylims and monkeys * human updates * huh * housekeeping is fired. * last minute fixes * more last minute things * human parts double check'd * more paper * Icons are fixed * double check of thermal protection code. (#191)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
//Used by jobs_have_maint_access
|
||||
#define ASSISTANTS_HAVE_MAINT_ACCESS 1
|
||||
@@ -10,6 +10,12 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/autoadmin = 0
|
||||
var/autoadmin_rank = "Game Admin"
|
||||
|
||||
/datum/protected_configuration/vv_get_var(var_name)
|
||||
return debug_variable(var_name, "SECRET", 0, src)
|
||||
|
||||
/datum/protected_configuration/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/datum/configuration
|
||||
var/name = "Configuration" // datum name
|
||||
|
||||
@@ -18,6 +24,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/server_suffix = 0 // generate numeric suffix based on server port
|
||||
var/lobby_countdown = 120 // In between round countdown.
|
||||
var/round_end_countdown = 25 // Post round murder death kill countdown
|
||||
var/hub = 0
|
||||
|
||||
var/log_ooc = 0 // log OOC channel
|
||||
var/log_access = 0 // log login/logout
|
||||
@@ -33,6 +40,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/log_adminchat = 0 // log admin chat messages
|
||||
var/log_pda = 0 // log pda messages
|
||||
var/log_hrefs = 0 // log all links clicked in-game. Could be used for debugging and tracking down exploits
|
||||
var/log_twitter = 0 // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
|
||||
var/log_world_topic = 0 // log all world.Topic() calls
|
||||
var/sql_enabled = 0 // for sql switching
|
||||
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
|
||||
@@ -47,6 +55,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1.
|
||||
var/fps = 20
|
||||
var/allow_holidays = 0 //toggles whether holiday-specific content should be used
|
||||
var/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling
|
||||
|
||||
var/hostedby = null
|
||||
var/respawn = 1
|
||||
@@ -69,6 +78,13 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
var/forbid_singulo_possession = 0
|
||||
var/useircbot = 0
|
||||
var/announce_watchlist = 0
|
||||
var/announce_adminhelps = 0
|
||||
var/check_randomizer = 0
|
||||
|
||||
var/allow_panic_bunker_bounce = 0 //Send new players somewhere else
|
||||
var/panic_server_name = "somewhere else"
|
||||
var/panic_address = "byond://" //Reconnect a player this linked server if this server isn't accepting new players
|
||||
|
||||
//IP Intel vars
|
||||
var/ipintel_email
|
||||
@@ -77,9 +93,13 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/ipintel_save_bad = 1
|
||||
var/ipintel_domain = "check.getipintel.net"
|
||||
|
||||
var/mentors_mobname_only = 0 // Only display mob name to mentors in mentorhelps
|
||||
var/mentor_legacy_system = 0 // Whether to use the legacy mentor system (flat file) instead of SQL
|
||||
|
||||
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
|
||||
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
|
||||
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
|
||||
var/use_account_age_for_jobs = 0 //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
|
||||
var/see_own_notes = 0 //Can players see their own admin notes (read-only)? Config option in config.txt
|
||||
|
||||
//Population cap vars
|
||||
@@ -96,6 +116,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/list/modes = list() // allowed modes
|
||||
var/list/votable_modes = list() // votable modes
|
||||
var/list/probabilities = list() // relative probability of each mode
|
||||
var/list/min_pop = list() // overrides for acceptible player counts in a mode
|
||||
var/list/max_pop = list()
|
||||
|
||||
var/humans_need_surnames = 0
|
||||
var/allow_ai = 0 // allow ai job
|
||||
@@ -137,9 +159,6 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/alert_desc_red_downto = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
|
||||
var/alert_desc_delta = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
|
||||
|
||||
var/health_threshold_crit = 0
|
||||
var/health_threshold_dead = -100
|
||||
|
||||
var/revival_pod_plants = 1
|
||||
var/revival_cloning = 1
|
||||
var/revival_brain_life = -1
|
||||
@@ -167,6 +186,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/silent_ai = 0
|
||||
var/silent_borg = 0
|
||||
|
||||
var/damage_multiplier = 1 //Modifier for damage to all mobs. Impacts healing as well.
|
||||
|
||||
var/allowwebclient = 0
|
||||
var/webclientmembersonly = 0
|
||||
|
||||
@@ -174,6 +195,9 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
var/default_laws = 0 //Controls what laws the AI spawns with.
|
||||
var/silicon_max_law_amount = 12
|
||||
var/list/lawids = list()
|
||||
|
||||
var/list/law_weights = list()
|
||||
|
||||
var/assistant_cap = -1
|
||||
|
||||
@@ -182,6 +206,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/grey_assistants = 0
|
||||
|
||||
var/lavaland_budget = 60
|
||||
var/space_budget = 16
|
||||
|
||||
var/aggressive_changelog = 0
|
||||
|
||||
@@ -213,10 +238,20 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/client_error_message = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
|
||||
|
||||
var/cross_name = "Other server"
|
||||
var/showircname = 0
|
||||
|
||||
var/list/gamemode_cache = null
|
||||
|
||||
// Discord crap.
|
||||
var/discord_url = "hfdksjhfa.com"
|
||||
var/discord_password
|
||||
|
||||
var/minutetopiclimit
|
||||
var/secondtopiclimit
|
||||
|
||||
/datum/configuration/New()
|
||||
var/list/L = subtypesof(/datum/game_mode)
|
||||
for(var/T in L)
|
||||
gamemode_cache = typecacheof(/datum/game_mode,TRUE)
|
||||
for(var/T in gamemode_cache)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
// their information, but it is the only way (at least that I know of).
|
||||
var/datum/game_mode/M = new T()
|
||||
@@ -260,12 +295,16 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
if(type == "config")
|
||||
switch(name)
|
||||
if("hub")
|
||||
config.hub = 1
|
||||
if("admin_legacy_system")
|
||||
config.admin_legacy_system = 1
|
||||
if("ban_legacy_system")
|
||||
config.ban_legacy_system = 1
|
||||
if("use_age_restriction_for_jobs")
|
||||
config.use_age_restriction_for_jobs = 1
|
||||
if("use_account_age_for_jobs")
|
||||
config.use_account_age_for_jobs = 1
|
||||
if("lobby_countdown")
|
||||
config.lobby_countdown = text2num(value)
|
||||
if("round_end_countdown")
|
||||
@@ -298,6 +337,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.log_pda = 1
|
||||
if("log_hrefs")
|
||||
config.log_hrefs = 1
|
||||
if("log_twitter")
|
||||
config.log_twitter = 1
|
||||
if("log_world_topic")
|
||||
config.log_world_topic = 1
|
||||
if("allow_admin_ooccolor")
|
||||
@@ -341,7 +382,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if("guest_ban")
|
||||
guests_allowed = 0
|
||||
if("usewhitelist")
|
||||
config.usewhitelist = 1
|
||||
config.usewhitelist = TRUE
|
||||
if("allow_metadata")
|
||||
config.allow_Metadata = 1
|
||||
if("kick_inactive")
|
||||
@@ -362,6 +403,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
var/ticklag = text2num(value)
|
||||
if(ticklag > 0)
|
||||
fps = 10 / ticklag
|
||||
if("tick_limit_mc_init")
|
||||
tick_limit_mc_init = text2num(value)
|
||||
if("fps")
|
||||
fps = text2num(value)
|
||||
if("automute_on")
|
||||
@@ -376,6 +419,18 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
global.cross_allowed = 1
|
||||
if("cross_comms_name")
|
||||
cross_name = value
|
||||
if("panic_server_name")
|
||||
panic_server_name = value
|
||||
if("panic_server_address")
|
||||
panic_address = value
|
||||
if(value != "byond:\\address:port")
|
||||
allow_panic_bunker_bounce = 1
|
||||
if("medal_hub_address")
|
||||
global.medal_hub = value
|
||||
if("medal_hub_password")
|
||||
global.medal_pass = value
|
||||
if("show_irc_name")
|
||||
config.showircname = 1
|
||||
if("see_own_notes")
|
||||
config.see_own_notes = 1
|
||||
if("soft_popcap")
|
||||
@@ -396,6 +451,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.notify_new_player_age = text2num(value)
|
||||
if("irc_first_connection_alert")
|
||||
config.irc_first_connection_alert = 1
|
||||
if("check_randomizer")
|
||||
config.check_randomizer = 1
|
||||
if("ipintel_email")
|
||||
if (value != "ch@nge.me")
|
||||
config.ipintel_email = value
|
||||
@@ -442,16 +499,23 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.client_error_version = text2num(value)
|
||||
if("client_error_message")
|
||||
config.client_error_message = value
|
||||
|
||||
if("announce_adminhelps")
|
||||
config.announce_adminhelps = 1
|
||||
if("discord_url")
|
||||
config.discord_url = value
|
||||
if("discord_password")
|
||||
config.discord_password = value
|
||||
if("minute_topic_limit")
|
||||
config.minutetopiclimit = text2num(value)
|
||||
if("second_topic_limit")
|
||||
config.secondtopiclimit = text2num(value)
|
||||
else
|
||||
diary << "Unknown setting in configuration: '[name]'"
|
||||
|
||||
else if(type == "game_options")
|
||||
switch(name)
|
||||
if("health_threshold_crit")
|
||||
config.health_threshold_crit = text2num(value)
|
||||
if("health_threshold_dead")
|
||||
config.health_threshold_dead = text2num(value)
|
||||
if("damage_multiplier")
|
||||
config.damage_multiplier = text2num(value)
|
||||
if("revival_pod_plants")
|
||||
config.revival_pod_plants = text2num(value)
|
||||
if("revival_cloning")
|
||||
@@ -520,6 +584,34 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.midround_antag_time_check = text2num(value)
|
||||
if("midround_antag_life_check")
|
||||
config.midround_antag_life_check = text2num(value)
|
||||
if("min_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
var/mode_value = null
|
||||
|
||||
if(pop_pos)
|
||||
mode_name = lowertext(copytext(value, 1, pop_pos))
|
||||
mode_value = copytext(value, pop_pos + 1)
|
||||
if(mode_name in config.modes)
|
||||
config.min_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
diary << "Unknown minimum population configuration definition: [mode_name]."
|
||||
else
|
||||
diary << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
if("max_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
var/mode_value = null
|
||||
|
||||
if(pop_pos)
|
||||
mode_name = lowertext(copytext(value, 1, pop_pos))
|
||||
mode_value = copytext(value, pop_pos + 1)
|
||||
if(mode_name in config.modes)
|
||||
config.max_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
diary << "Unknown maximum population configuration definition: [mode_name]."
|
||||
else
|
||||
diary << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
if("shuttle_refuel_delay")
|
||||
config.shuttle_refuel_delay = text2num(value)
|
||||
if("show_game_type_odds")
|
||||
@@ -589,6 +681,19 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.sandbox_autoclose = 1
|
||||
if("default_laws")
|
||||
config.default_laws = text2num(value)
|
||||
if("random_laws")
|
||||
var/law_id = lowertext(value)
|
||||
lawids += law_id
|
||||
if("law_weight")
|
||||
// Value is in the form "LAWID,NUMBER"
|
||||
var/list/L = splittext(value, ",")
|
||||
if(L.len != 2)
|
||||
diary << "Invalid LAW_WEIGHT: " + t
|
||||
continue
|
||||
var/lawid = L[1]
|
||||
var/weight = text2num(L[2])
|
||||
law_weights[lawid] = weight
|
||||
|
||||
if("silicon_max_law_amount")
|
||||
config.silicon_max_law_amount = text2num(value)
|
||||
if("join_with_mutant_race")
|
||||
@@ -609,6 +714,8 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
config.grey_assistants = 1
|
||||
if("lavaland_budget")
|
||||
config.lavaland_budget = text2num(value)
|
||||
if("space_budget")
|
||||
config.space_budget = text2num(value)
|
||||
if("no_summon_guns")
|
||||
config.no_summon_guns = 1
|
||||
if("no_summon_magic")
|
||||
@@ -735,7 +842,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
/datum/configuration/proc/pick_mode(mode_name)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
// their information, but it is the only way (at least that I know of).
|
||||
for(var/T in subtypesof(/datum/game_mode))
|
||||
for(var/T in gamemode_cache)
|
||||
var/datum/game_mode/M = new T()
|
||||
if(M.config_tag && M.config_tag == mode_name)
|
||||
return M
|
||||
@@ -744,7 +851,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
/datum/configuration/proc/get_runnable_modes()
|
||||
var/list/datum/game_mode/runnable_modes = new
|
||||
for(var/T in subtypesof(/datum/game_mode))
|
||||
for(var/T in gamemode_cache)
|
||||
var/datum/game_mode/M = new T()
|
||||
//world << "DEBUG: [T], tag=[M.config_tag], prob=[probabilities[M.config_tag]]"
|
||||
if(!(M.config_tag in modes))
|
||||
@@ -753,6 +860,10 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.can_start())
|
||||
runnable_modes[M] = probabilities[M.config_tag]
|
||||
//world << "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]"
|
||||
@@ -760,7 +871,7 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
|
||||
/datum/configuration/proc/get_runnable_midround_modes(crew)
|
||||
var/list/datum/game_mode/runnable_modes = new
|
||||
for(var/T in (subtypesof(/datum/game_mode) - ticker.mode.type))
|
||||
for(var/T in (gamemode_cache - ticker.mode.type))
|
||||
var/datum/game_mode/M = new T()
|
||||
if(!(M.config_tag in modes))
|
||||
qdel(M)
|
||||
@@ -768,7 +879,13 @@ f//Configuraton defines //TODO: Move all yes/no switches into bitflags
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.required_players <= crew)
|
||||
if(M.maximum_players >= 0 && M.maximum_players < crew)
|
||||
continue
|
||||
runnable_modes[M] = probabilities[M.config_tag]
|
||||
return runnable_modes
|
||||
|
||||
|
||||
@@ -27,9 +27,12 @@ var/datum/controller/failsafe/Failsafe
|
||||
if(istype(Failsafe))
|
||||
qdel(Failsafe)
|
||||
Failsafe = src
|
||||
spawn()
|
||||
Failsafe.Loop()
|
||||
qdel(Failsafe) //when Loop() returns, we delete ourselves and let the mc recreate us
|
||||
LaunchLoop()
|
||||
|
||||
/datum/controller/failsafe/proc/LaunchLoop()
|
||||
set waitfor = 0
|
||||
Failsafe.Loop()
|
||||
qdel(Failsafe) //when Loop() returns, we delete ourselves and let the mc recreate us
|
||||
|
||||
/datum/controller/failsafe/Destroy()
|
||||
..()
|
||||
|
||||
+45
-39
@@ -35,6 +35,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
var/init_time
|
||||
var/tickdrift = 0
|
||||
|
||||
var/sleep_delta
|
||||
|
||||
var/make_runtime = 0
|
||||
|
||||
// Has round started? (So we know what subsystems to run)
|
||||
@@ -50,7 +52,6 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
|
||||
/datum/controller/master/New()
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
check_for_cleanbot_bug()
|
||||
subsystems = list()
|
||||
if (Master != src)
|
||||
if (istype(Master))
|
||||
@@ -65,6 +66,11 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
// Tell qdel() to Del() this object.
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
/datum/controller/master/proc/Shutdown()
|
||||
processing = FALSE
|
||||
for(var/datum/subsystem/ss in subsystems)
|
||||
ss.Shutdown()
|
||||
|
||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
/proc/Recreate_MC()
|
||||
@@ -101,26 +107,30 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
world.log << msg
|
||||
if (istype(Master.subsystems))
|
||||
subsystems = Master.subsystems
|
||||
spawn (10)
|
||||
StartProcessing()
|
||||
StartProcessing(10)
|
||||
else
|
||||
world << "<span class='boldannounce'>The Master Controller is having some issues, we will need to re-initialize EVERYTHING</span>"
|
||||
spawn (20)
|
||||
init_subtypes(/datum/subsystem, subsystems)
|
||||
Setup()
|
||||
Setup(20, TRUE)
|
||||
|
||||
|
||||
// Please don't stuff random bullshit here,
|
||||
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
|
||||
/datum/controller/master/proc/Setup()
|
||||
check_for_cleanbot_bug()
|
||||
/datum/controller/master/proc/Setup(delay, init_sss)
|
||||
set waitfor = 0
|
||||
|
||||
if(delay)
|
||||
sleep(delay)
|
||||
|
||||
if(init_sss)
|
||||
init_subtypes(/datum/subsystem, subsystems)
|
||||
|
||||
world << "<span class='boldannounce'>Initializing subsystems...</span>"
|
||||
|
||||
// Sort subsystems by init_order, so they initialize in the correct order.
|
||||
sortTim(subsystems, /proc/cmp_subsystem_init)
|
||||
|
||||
// Initialize subsystems.
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_MC_INIT
|
||||
CURRENT_TICKLIMIT = config.tick_limit_mc_init
|
||||
for (var/datum/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_NO_INIT)
|
||||
continue
|
||||
@@ -133,15 +143,12 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
|
||||
// Sort subsystems by display setting for easy access.
|
||||
sortTim(subsystems, /proc/cmp_subsystem_display)
|
||||
check_for_cleanbot_bug()
|
||||
// Set world options.
|
||||
world.sleep_offline = 1
|
||||
world.fps = config.fps
|
||||
check_for_cleanbot_bug()
|
||||
sleep(1)
|
||||
check_for_cleanbot_bug()
|
||||
// Loop.
|
||||
Master.StartProcessing()
|
||||
Master.StartProcessing(0)
|
||||
|
||||
// Notify the MC that the round has started.
|
||||
/datum/controller/master/proc/RoundStart()
|
||||
@@ -155,8 +162,10 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
SS.next_fire = timer
|
||||
|
||||
// Starts the mc, and sticks around to restart it if the loop ever ends.
|
||||
/datum/controller/master/proc/StartProcessing()
|
||||
/datum/controller/master/proc/StartProcessing(delay)
|
||||
set waitfor = 0
|
||||
if(delay)
|
||||
sleep(delay)
|
||||
var/rtn = Loop()
|
||||
if (rtn > 0 || processing < 0)
|
||||
return //this was suppose to happen.
|
||||
@@ -165,8 +174,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
message_admins("MC crashed or runtimed, restarting")
|
||||
var/rtn2 = Recreate_MC()
|
||||
if (rtn2 <= 0)
|
||||
log_game("Failed to recreate MC (Error code: [rtn2]), its up to the failsafe now")
|
||||
message_admins("Failed to recreate MC (Error code: [rtn2]), its up to the failsafe now")
|
||||
log_game("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now")
|
||||
message_admins("Failed to recreate MC (Error code: [rtn2]), it's up to the failsafe now")
|
||||
Failsafe.defcon = 2
|
||||
|
||||
// Main loop.
|
||||
@@ -189,6 +198,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
SS.queued_time = 0
|
||||
SS.queue_next = null
|
||||
SS.queue_prev = null
|
||||
SS.state = SS_IDLE
|
||||
if (SS.flags & SS_TICKER)
|
||||
tickersubsystems += SS
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
@@ -225,6 +235,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
while (1)
|
||||
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((world.timeofday - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
||||
if (processing <= 0)
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
@@ -232,6 +243,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
|
||||
if (world.tick_usage > TICK_LIMIT_MC)
|
||||
sleep_delta += 2
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5)
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
continue
|
||||
|
||||
@@ -260,6 +272,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
@@ -271,6 +284,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
error_level--
|
||||
@@ -280,6 +294,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
|
||||
iteration++
|
||||
last_run = world.time
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
|
||||
|
||||
@@ -288,6 +304,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
// This is what decides if something should run.
|
||||
/datum/controller/master/proc/CheckQueue(list/subsystemstocheck)
|
||||
. = 0 //so the mc knows if we runtimed
|
||||
|
||||
//we create our variables outside of the loops to save on overhead
|
||||
var/datum/subsystem/SS
|
||||
var/SS_flags
|
||||
@@ -296,7 +313,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
if (!thing)
|
||||
subsystemstocheck -= thing
|
||||
SS = thing
|
||||
if (SS.queued_time) //already in the queue
|
||||
if (SS.state != SS_IDLE)
|
||||
continue
|
||||
if (SS.can_fire <= 0)
|
||||
continue
|
||||
@@ -307,10 +324,6 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
subsystemstocheck -= SS
|
||||
if (!(SS_flags & SS_TICKER) && (SS_flags & SS_KEEP_TIMING) && SS.last_fire + (SS.wait * 0.75) > world.time)
|
||||
continue
|
||||
|
||||
//Queue it to run.
|
||||
// (we loop thru a linked list until we get to the end or find the right point)
|
||||
// (this lets us sort our run order correctly without having to re-sort the entire already sorted list)
|
||||
SS.enqueue()
|
||||
. = 1
|
||||
|
||||
@@ -341,9 +354,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
while (queue_node)
|
||||
if (ran && world.tick_usage > TICK_LIMIT_RUNNING)
|
||||
break
|
||||
if (!istype(queue_node))
|
||||
world.log << "[__FILE__]:[__LINE__] queue_node bad, now equals: [queue_node](\ref[queue_node])"
|
||||
return
|
||||
|
||||
queue_node_flags = queue_node.flags
|
||||
queue_node_priority = queue_node.queued_priority
|
||||
|
||||
@@ -358,9 +369,6 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
queue_priority_count -= queue_node_priority
|
||||
queue_priority_count += queue_node.queued_priority
|
||||
current_tick_budget -= queue_node_priority
|
||||
if (!istype(queue_node))
|
||||
world.log << "[__FILE__]:[__LINE__] queue_node bad, now equals: [queue_node](\ref[queue_node])"
|
||||
return
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
|
||||
@@ -381,24 +389,25 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
ran_non_ticker = TRUE
|
||||
ran = TRUE
|
||||
tick_usage = world.tick_usage
|
||||
queue_node_paused = queue_node.paused
|
||||
queue_node.paused = FALSE
|
||||
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
|
||||
last_type_processed = queue_node
|
||||
|
||||
queue_node.fire(queue_node_paused)
|
||||
queue_node.state = SS_RUNNING
|
||||
|
||||
var/state = queue_node.ignite(queue_node_paused)
|
||||
if (state == SS_RUNNING)
|
||||
state = SS_IDLE
|
||||
current_tick_budget -= queue_node_priority
|
||||
tick_usage = world.tick_usage - tick_usage
|
||||
|
||||
if (tick_usage < 0)
|
||||
tick_usage = 0
|
||||
|
||||
if (queue_node.paused)
|
||||
queue_node.state = state
|
||||
|
||||
if (state == SS_PAUSED)
|
||||
queue_node.paused_ticks++
|
||||
queue_node.paused_tick_usage += tick_usage
|
||||
if (!istype(queue_node))
|
||||
world.log << "[__FILE__]:[__LINE__] queue_node bad, now equals: [queue_node](\ref[queue_node])"
|
||||
return
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
|
||||
@@ -432,12 +441,9 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
|
||||
//remove from queue
|
||||
queue_node.dequeue()
|
||||
if (!istype(queue_node))
|
||||
world.log << "[__FILE__]:[__LINE__] queue_node bad, now equals: [queue_node](\ref[queue_node])"
|
||||
return
|
||||
|
||||
queue_node = queue_node.queue_next
|
||||
|
||||
CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
. = 1
|
||||
|
||||
//resets the queue, and all subsystems, while filtering out the subsystem lists
|
||||
@@ -468,7 +474,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
SS.queue_prev = null
|
||||
SS.queued_priority = 0
|
||||
SS.queued_time = 0
|
||||
SS.paused = 0
|
||||
SS.state = SS_IDLE
|
||||
if (queue_head && !istype(queue_head))
|
||||
world.log << "MC: SoftReset: Found bad data in subsystem queue, queue_head = '[queue_head]'"
|
||||
queue_head = null
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
var/next_fire = 0 //scheduled world.time for next fire()
|
||||
var/cost = 0 //average time to execute
|
||||
var/tick_usage = 0 //average tick usage
|
||||
var/paused = 0 //was this subsystem paused mid fire.
|
||||
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
|
||||
var/paused_ticks = 0 //ticks this ss is taking to run right now.
|
||||
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
|
||||
var/ticks = 1 //how many ticks does this ss take to run on avg.
|
||||
var/times_fired = 0 //number of times we have called fire()
|
||||
var/queued_time = 0 //time we entered the queue, (for timing and priority reasons)
|
||||
var/queued_priority //we keep a running total to make the math easier, if it changes mid-fire that would break our running total, so we store it here
|
||||
var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here
|
||||
//linked list stuff for the queue
|
||||
var/datum/subsystem/queue_next
|
||||
var/datum/subsystem/queue_prev
|
||||
@@ -37,13 +37,28 @@
|
||||
// Used to initialize the subsystem BEFORE the map has loaded
|
||||
/datum/subsystem/New()
|
||||
|
||||
//cleanup actions
|
||||
/datum/subsystem/proc/Shutdown()
|
||||
return
|
||||
|
||||
//This is used so the mc knows when the subsystem sleeps. do not override.
|
||||
/datum/subsystem/proc/ignite(resumed = 0)
|
||||
set waitfor = 0
|
||||
. = SS_SLEEPING
|
||||
fire(resumed)
|
||||
. = state
|
||||
if (state == SS_SLEEPING)
|
||||
state = SS_IDLE
|
||||
if (state == SS_PAUSING)
|
||||
var/QT = queued_time
|
||||
enqueue()
|
||||
state = SS_PAUSED
|
||||
queued_time = QT
|
||||
|
||||
//previously, this would have been named 'process()' but that name is used everywhere for different things!
|
||||
//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds.
|
||||
//fire(), and the procs it calls, SHOULD NOT HAVE ANY SLEEP OPERATIONS in them!
|
||||
//YE BE WARNED!
|
||||
//Sleeping in here prevents future fires until returned.
|
||||
/datum/subsystem/proc/fire(resumed = 0)
|
||||
set waitfor = 0 //this should not be depended upon, this is just to solve issues with sleeps messing up tick tracking
|
||||
can_fire = 0
|
||||
flags |= SS_NO_FIRE
|
||||
throw EXCEPTION("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.")
|
||||
|
||||
@@ -53,6 +68,10 @@
|
||||
flags |= SS_NO_FIRE
|
||||
Master.subsystems -= src
|
||||
|
||||
|
||||
//Queue it to run.
|
||||
// (we loop thru a linked list until we get to the end or find the right point)
|
||||
// (this lets us sort our run order correctly without having to re-sort the entire already sorted list)
|
||||
/datum/subsystem/proc/enqueue()
|
||||
var/SS_priority = priority
|
||||
var/SS_flags = flags
|
||||
@@ -86,6 +105,7 @@
|
||||
|
||||
queued_time = world.time
|
||||
queued_priority = SS_priority
|
||||
state = SS_QUEUED
|
||||
if (SS_flags & SS_BACKGROUND) //update our running total
|
||||
Master.queue_priority_count_bg += SS_priority
|
||||
else
|
||||
@@ -120,12 +140,17 @@
|
||||
if (src == Master.queue_head)
|
||||
Master.queue_head = queue_next
|
||||
queued_time = 0
|
||||
if (state == SS_QUEUED)
|
||||
state = SS_IDLE
|
||||
|
||||
|
||||
/datum/subsystem/proc/pause()
|
||||
. = 1
|
||||
paused = TRUE
|
||||
paused_ticks++
|
||||
if (state == SS_RUNNING)
|
||||
state = SS_PAUSED
|
||||
else if (state == SS_SLEEPING)
|
||||
state = SS_PAUSING
|
||||
|
||||
|
||||
//used to initialize the subsystem AFTER the map has loaded
|
||||
/datum/subsystem/proc/Initialize(start_timeofday)
|
||||
@@ -139,12 +164,31 @@
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug("Initializing...", src)
|
||||
|
||||
|
||||
|
||||
if(can_fire)
|
||||
msg = "[round(cost*ticks,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
else
|
||||
msg = "OFFLINE\t[msg]"
|
||||
|
||||
stat(name, statclick.update(msg))
|
||||
var/title = name
|
||||
if (can_fire)
|
||||
title = "\[[state_letter()]][title]"
|
||||
|
||||
stat(title, statclick.update(msg))
|
||||
|
||||
/datum/subsystem/proc/state_letter()
|
||||
switch (state)
|
||||
if (SS_RUNNING)
|
||||
. = "R"
|
||||
if (SS_QUEUED)
|
||||
. = "Q"
|
||||
if (SS_PAUSED, SS_PAUSING)
|
||||
. = "P"
|
||||
if (SS_SLEEPING)
|
||||
. = "S"
|
||||
if (SS_IDLE)
|
||||
. = " "
|
||||
|
||||
//could be used to postpone a costly subsystem for (default one) var/cycles, cycles
|
||||
//for instance, during cpu intensive operations like explosions
|
||||
@@ -156,8 +200,13 @@
|
||||
//should attempt to salvage what it can from the old instance of subsystem
|
||||
/datum/subsystem/proc/Recover()
|
||||
|
||||
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
|
||||
/datum/subsystem/on_varedit(edited_var)
|
||||
if (edited_var == "can_fire" && can_fire)
|
||||
next_fire = world.time + wait
|
||||
..()
|
||||
/datum/subsystem/vv_edit_var(var_name, var_value)
|
||||
switch (var_name)
|
||||
if ("can_fire")
|
||||
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
|
||||
if (var_value)
|
||||
next_fire = world.time + wait
|
||||
if ("queued_priority") //editing this breaks things.
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
var/datum/subsystem/acid/SSacid
|
||||
|
||||
/datum/subsystem/acid
|
||||
name = "Acid"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/acid/New()
|
||||
NEW_SS_GLOBAL(SSacid)
|
||||
|
||||
|
||||
/datum/subsystem/acid/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/acid/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while (currentrun.len)
|
||||
var/obj/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O || qdeleted(O))
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(O.acid_level && O.acid_processing())
|
||||
else
|
||||
O.overlays -= acid_overlay
|
||||
O.priority_overlays -= acid_overlay
|
||||
processing -= O
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -30,6 +30,7 @@ var/datum/subsystem/air/SSair
|
||||
var/list/obj/machinery/atmos_machinery = list()
|
||||
|
||||
|
||||
|
||||
//Special functions lists
|
||||
var/list/turf/active_super_conductivity = list()
|
||||
var/list/turf/open/high_pressure_delta = list()
|
||||
@@ -72,7 +73,7 @@ var/datum/subsystem/air/SSair
|
||||
if(currentpart == SSAIR_PIPENETS || !resumed)
|
||||
process_pipenets(resumed)
|
||||
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_ATMOSMACHINERY
|
||||
@@ -81,7 +82,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_atmos_machinery(resumed)
|
||||
cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_ACTIVETURFS
|
||||
@@ -90,7 +91,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_active_turfs(resumed)
|
||||
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_EXCITEDGROUPS
|
||||
@@ -99,7 +100,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_excited_groups(resumed)
|
||||
cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_HIGHPRESSURE
|
||||
@@ -108,7 +109,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_high_pressure_delta(resumed)
|
||||
cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_HOTSPOTS
|
||||
@@ -117,7 +118,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_hotspots(resumed)
|
||||
cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_SUPERCONDUCTIVITY
|
||||
@@ -126,7 +127,7 @@ var/datum/subsystem/air/SSair
|
||||
timer = world.tick_usage
|
||||
process_super_conductivity(resumed)
|
||||
cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(world.tick_usage - timer))
|
||||
if(paused)
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_PIPENETS
|
||||
@@ -236,6 +237,8 @@ var/datum/subsystem/air/SSair
|
||||
|
||||
/datum/subsystem/air/proc/remove_from_active(turf/open/T)
|
||||
active_turfs -= T
|
||||
if(currentpart == SSAIR_ACTIVETURFS)
|
||||
currentrun -= T
|
||||
if(istype(T))
|
||||
T.excited = 0
|
||||
if(T.excited_group)
|
||||
@@ -246,6 +249,8 @@ var/datum/subsystem/air/SSair
|
||||
if(istype(T) && T.air)
|
||||
T.excited = 1
|
||||
active_turfs |= T
|
||||
if(currentpart == SSAIR_ACTIVETURFS)
|
||||
currentrun |= T
|
||||
if(blockchanges && T.excited_group)
|
||||
T.excited_group.garbage_collect()
|
||||
else
|
||||
@@ -264,6 +269,7 @@ var/datum/subsystem/air/SSair
|
||||
if (T.blocks_air)
|
||||
continue
|
||||
T.Initalize_Atmos(times_fired)
|
||||
CHECK_TICK
|
||||
|
||||
if(active_turfs.len)
|
||||
var/starting_ats = active_turfs.len
|
||||
@@ -279,6 +285,7 @@ var/datum/subsystem/air/SSair
|
||||
var/list/new_turfs_to_check = list()
|
||||
for(var/turf/open/T in turfs_to_check)
|
||||
new_turfs_to_check += T.resolve_active_graph()
|
||||
CHECK_TICK
|
||||
|
||||
active_turfs += new_turfs_to_check
|
||||
turfs_to_check = new_turfs_to_check
|
||||
@@ -289,6 +296,7 @@ var/datum/subsystem/air/SSair
|
||||
var/datum/excited_group/EG = thing
|
||||
EG.self_breakdown(space_is_all_consuming = 1)
|
||||
EG.dismantle()
|
||||
CHECK_TICK
|
||||
|
||||
var/msg = "HEY! LISTEN! [(world.timeofday - timer)/10] Seconds were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
|
||||
world << "<span class='boldannounce'>[msg]</span>"
|
||||
|
||||
@@ -15,7 +15,5 @@ var/datum/subsystem/assets/SSasset
|
||||
A.register()
|
||||
|
||||
for(var/client/C in clients)
|
||||
// Doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps.
|
||||
spawn(10)
|
||||
getFilesSlow(C, cache, FALSE)
|
||||
..()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, cache, FALSE), 10)
|
||||
..()
|
||||
@@ -0,0 +1,84 @@
|
||||
var/datum/subsystem/augury/SSaugury
|
||||
|
||||
/datum/subsystem/augury
|
||||
name = "Augury"
|
||||
flags = SS_NO_INIT
|
||||
|
||||
var/list/watchers = list()
|
||||
var/list/doombringers = list()
|
||||
|
||||
var/list/observers_given_action = list()
|
||||
|
||||
/datum/subsystem/augury/New()
|
||||
NEW_SS_GLOBAL(SSaugury)
|
||||
|
||||
/datum/subsystem/augury/stat_entry(msg)
|
||||
..("W:[watchers.len]|D:[doombringers.len]")
|
||||
|
||||
/datum/subsystem/augury/proc/register_doom(atom/A, severity)
|
||||
doombringers[A] = severity
|
||||
|
||||
/datum/subsystem/augury/fire()
|
||||
var/biggest_doom = null
|
||||
var/biggest_threat = null
|
||||
|
||||
for(var/d in doombringers)
|
||||
if(!d || qdeleted(d))
|
||||
doombringers -= d
|
||||
continue
|
||||
var/threat = doombringers[d]
|
||||
if((biggest_threat == null) || (biggest_threat < threat))
|
||||
biggest_doom = d
|
||||
biggest_threat = threat
|
||||
|
||||
if(doombringers.len)
|
||||
for(var/i in player_list)
|
||||
if(isobserver(i) && (!(observers_given_action[i])))
|
||||
var/datum/action/innate/augury/A = new
|
||||
A.Grant(i)
|
||||
observers_given_action[i] = TRUE
|
||||
else
|
||||
for(var/i in observers_given_action)
|
||||
if(observers_given_action[i] && isobserver(i))
|
||||
var/mob/dead/observer/O = i
|
||||
for(var/datum/action/innate/augury/A in O.actions)
|
||||
qdel(A)
|
||||
observers_given_action -= i
|
||||
|
||||
for(var/w in watchers)
|
||||
if(!w)
|
||||
watchers -= w
|
||||
continue
|
||||
var/mob/dead/observer/O = w
|
||||
if(biggest_doom && (!O.orbiting || O.orbiting.orbiting != biggest_doom))
|
||||
O.ManualFollow(biggest_doom)
|
||||
|
||||
/datum/action/innate/augury
|
||||
name = "Auto Follow Debris"
|
||||
icon_icon = 'icons/obj/meteor.dmi'
|
||||
button_icon_state = "flaming"
|
||||
background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
|
||||
|
||||
/datum/action/innate/augury/Destroy()
|
||||
if(owner)
|
||||
SSaugury.watchers -= owner
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/augury/Activate()
|
||||
SSaugury.watchers += owner
|
||||
owner << "<span class='notice'>You are now auto-following debris.</span>"
|
||||
active = TRUE
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/innate/augury/Deactivate()
|
||||
SSaugury.watchers -= owner
|
||||
owner << "<span class='notice'>You are no longer auto-following debris.</span>"
|
||||
active = FALSE
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/innate/augury/UpdateButtonIcon(status_only = FALSE)
|
||||
..()
|
||||
if(active)
|
||||
button.icon_state = "template_active"
|
||||
else
|
||||
button.icon_state = "template"
|
||||
@@ -0,0 +1,37 @@
|
||||
#define COMMUNICATION_COOLDOWN 600
|
||||
#define COMMUNICATION_COOLDOWN_AI 600
|
||||
|
||||
var/datum/subsystem/communications/SScommunications
|
||||
|
||||
/datum/subsystem/communications
|
||||
name = "Communications"
|
||||
flags = SS_NO_INIT | SS_NO_FIRE
|
||||
|
||||
var/silicon_message_cooldown
|
||||
var/nonsilicon_message_cooldown
|
||||
|
||||
/datum/subsystem/communications/New()
|
||||
NEW_SS_GLOBAL(SScommunications)
|
||||
|
||||
/datum/subsystem/communications/proc/can_announce(mob/living/user, is_silicon)
|
||||
if(is_silicon && silicon_message_cooldown > world.time)
|
||||
. = FALSE
|
||||
else if(!is_silicon && nonsilicon_message_cooldown > world.time)
|
||||
. = FALSE
|
||||
else
|
||||
. = TRUE
|
||||
|
||||
/datum/subsystem/communications/proc/make_announcement(mob/living/user, is_silicon, input)
|
||||
if(!can_announce(user, is_silicon))
|
||||
return FALSE
|
||||
if(is_silicon)
|
||||
minor_announce(html_decode(input),"[user.name] Announces:")
|
||||
silicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN_AI
|
||||
else
|
||||
priority_announce(html_decode(input), null, 'sound/misc/announce.ogg', "Captain")
|
||||
nonsilicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN
|
||||
log_say("[key_name(user)] has made a priority announcement: [input]")
|
||||
message_admins("[key_name_admin(user)] has made a priority announcement.")
|
||||
|
||||
#undef COMMUNICATION_COOLDOWN
|
||||
#undef COMMUNICATION_COOLDOWN_AI
|
||||
@@ -59,14 +59,6 @@ var/datum/subsystem/events/SSevent
|
||||
/datum/subsystem/events/proc/reschedule()
|
||||
scheduled = world.time + rand(frequency_lower, max(frequency_lower,frequency_upper))
|
||||
|
||||
if(world.time > 108000) //3 hours
|
||||
frequency_lower=1000
|
||||
frequency_upper=1500
|
||||
if(SSshuttle.emergency.mode < SHUTTLE_CALL)
|
||||
SSshuttle.emergency.request(null, 1.5)
|
||||
log_game("Round time limit reached. Shuttle has been auto-called.")
|
||||
message_admins("Round time limit reached. Shuttle called.")
|
||||
|
||||
//selects a random event based on whether it can occur and it's 'weight'(probability)
|
||||
/datum/subsystem/events/proc/spawnEvent()
|
||||
if(!config.allow_random_events)
|
||||
@@ -105,13 +97,14 @@ var/datum/subsystem/events/SSevent
|
||||
continue
|
||||
if (E.alertadmins)
|
||||
message_admins("Random Event triggering: [E.name] ([E.typepath])")
|
||||
deadchat_broadcast("[E.name] has just been randomly triggered!") //STOP ASSUMING IT'S BADMINS!
|
||||
log_game("Random Event triggering: [E.name] ([E.typepath])")
|
||||
return
|
||||
|
||||
/datum/round_event/proc/findEventArea() //Here's a nice proc to use to find an area for your event to land in!
|
||||
var/list/safe_areas = list(
|
||||
/area/turret_protected/ai,
|
||||
/area/turret_protected/ai_upload,
|
||||
/area/ai_monitored/turret_protected/ai,
|
||||
/area/ai_monitored/turret_protected/ai_upload,
|
||||
/area/engine,
|
||||
/area/solar,
|
||||
/area/holodeck,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
var/datum/subsystem/fastprocess/SSfastprocess
|
||||
|
||||
/datum/subsystem/fastprocess
|
||||
name = "Fast Process"
|
||||
priority = 25
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
wait = 2
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
/datum/subsystem/fastprocess/New()
|
||||
NEW_SS_GLOBAL(SSfastprocess)
|
||||
|
||||
/datum/subsystem/fastprocess/stat_entry()
|
||||
..("FP:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/fastprocess/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(currentrun.len)
|
||||
var/datum/thing = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(thing)
|
||||
thing.process(wait)
|
||||
else
|
||||
SSfastprocess.processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -0,0 +1,42 @@
|
||||
var/datum/subsystem/fire_burning/SSfire_burning
|
||||
|
||||
/datum/subsystem/fire_burning
|
||||
name = "Fire Burning"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/fire_burning/New()
|
||||
NEW_SS_GLOBAL(SSfire_burning)
|
||||
|
||||
|
||||
/datum/subsystem/fire_burning/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/fire_burning/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(currentrun.len)
|
||||
var/obj/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O || qdeleted(O))
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(O.resistance_flags & ON_FIRE)
|
||||
O.take_damage(20, BURN, "fire", 0)
|
||||
else
|
||||
processing -= O
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
@@ -54,7 +54,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
|
||||
/datum/subsystem/garbage_collector/fire()
|
||||
HandleToBeQueued()
|
||||
if (!paused)
|
||||
if(state == SS_RUNNING)
|
||||
HandleQueue()
|
||||
|
||||
//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond.
|
||||
@@ -70,7 +70,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
Queue(ref)
|
||||
tobequeued.Cut(1, 2)
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/HandleQueue(time_to_stop)
|
||||
/datum/subsystem/garbage_collector/proc/HandleQueue()
|
||||
delslasttick = 0
|
||||
gcedlasttick = 0
|
||||
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
|
||||
@@ -121,7 +121,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
++totalgcs
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/QueueForQueuing(datum/A)
|
||||
if (istype(A) && isnull(A.gc_destroyed))
|
||||
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
tobequeued += A
|
||||
A.gc_destroyed = GC_QUEUED_FOR_QUEUING
|
||||
|
||||
@@ -142,7 +142,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
queue[refid] = gctime
|
||||
|
||||
/datum/subsystem/garbage_collector/proc/HardQueue(datum/A)
|
||||
if (istype(A) && isnull(A.gc_destroyed))
|
||||
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
tobequeued += A
|
||||
A.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
|
||||
|
||||
@@ -158,19 +158,23 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
if(!D)
|
||||
return
|
||||
#ifdef TESTING
|
||||
SSgarbage.qdel_list += "[A.type]"
|
||||
SSgarbage.qdel_list += "[D.type]"
|
||||
#endif
|
||||
if(!istype(D))
|
||||
del(D)
|
||||
else if(isnull(D.gc_destroyed))
|
||||
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
|
||||
var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up.
|
||||
if(!D)
|
||||
return
|
||||
switch(hint)
|
||||
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
|
||||
SSgarbage.QueueForQueuing(D)
|
||||
if (QDEL_HINT_LETMELIVE, QDEL_HINT_IWILLGC) //qdel should let the object live after calling destory.
|
||||
if (QDEL_HINT_IWILLGC)
|
||||
return
|
||||
if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory.
|
||||
if(!force)
|
||||
D.gc_destroyed = null //clear the gc variable (important!)
|
||||
return
|
||||
// Returning LETMELIVE after being told to force destroy
|
||||
// indicates the objects Destroy() does not respect force
|
||||
@@ -186,18 +190,18 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
SSgarbage.HardQueue(D)
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
del(D)
|
||||
if (QDEL_HINT_PUTINPOOL) //qdel will put this object in the pool.
|
||||
PlaceInPool(D, 0)
|
||||
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
|
||||
SSgarbage.QueueForQueuing(D)
|
||||
#ifdef TESTING
|
||||
A.find_references()
|
||||
D.find_references()
|
||||
#endif
|
||||
else
|
||||
if(!SSgarbage.noqdelhint["[D.type]"])
|
||||
SSgarbage.noqdelhint["[D.type]"] = "[D.type]"
|
||||
testing("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
|
||||
SSgarbage.QueueForQueuing(D)
|
||||
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
|
||||
|
||||
// Returns 1 if the object has been queued for deletion.
|
||||
/proc/qdeleted(datum/D)
|
||||
@@ -207,25 +211,42 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Returns true if the object's destroy has been called (set just before it is called)
|
||||
/proc/qdestroying(datum/D)
|
||||
if(!istype(D))
|
||||
return FALSE
|
||||
if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Default implementation of clean-up code.
|
||||
// This should be overridden to remove all references pointing to the object being destroyed.
|
||||
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
|
||||
/datum/proc/Destroy(force=FALSE)
|
||||
tag = null
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
for(var/thing in timers)
|
||||
var/datum/timedevent/timer = thing
|
||||
if (timer.spent)
|
||||
continue
|
||||
qdel(timer)
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
/datum/var/gc_destroyed //Time when this object was destroyed.
|
||||
|
||||
#ifdef TESTING
|
||||
/client/var/running_find_references
|
||||
/datum/var/running_find_references
|
||||
|
||||
/datum/verb/find_references()
|
||||
/datum/verb/find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set background = 1
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
|
||||
/datum/proc/find_references(skip_alert)
|
||||
running_find_references = type
|
||||
if(usr && usr.client)
|
||||
if(usr.client.running_find_references)
|
||||
@@ -237,9 +258,10 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
return
|
||||
|
||||
if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
running_find_references = null
|
||||
return
|
||||
if(!skip_alert)
|
||||
if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
//this keeps the garbage collector from failing to collect objects being searched for in here
|
||||
SSgarbage.can_fire = 0
|
||||
@@ -248,13 +270,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
var/list/things = list()
|
||||
for(var/client/thing)
|
||||
things |= thing
|
||||
for(var/datum/thing)
|
||||
things |= thing
|
||||
testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)")
|
||||
for(var/datum/thing in things)
|
||||
for(var/datum/thing in world)
|
||||
if(usr && usr.client && !usr.client.running_find_references) return
|
||||
for(var/varname in thing.vars)
|
||||
var/variable = thing.vars[varname]
|
||||
@@ -263,6 +279,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
else if(islist(variable))
|
||||
if(src in variable)
|
||||
testing("Found [src.type] \ref[src] in [thing.type]'s [varname] list var.")
|
||||
CHECK_TICK
|
||||
testing("Completed search for references to a [type].")
|
||||
if(usr && usr.client)
|
||||
usr.client.running_find_references = null
|
||||
@@ -290,7 +307,7 @@ var/datum/subsystem/garbage_collector/SSgarbage
|
||||
|
||||
qdel(src)
|
||||
if(!running_find_references)
|
||||
find_references()
|
||||
find_references(TRUE)
|
||||
|
||||
/client/verb/show_qdeleted()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -16,7 +16,7 @@ var/datum/subsystem/icon_smooth/SSicon_smooth
|
||||
while(smooth_queue.len)
|
||||
var/atom/A = smooth_queue[smooth_queue.len]
|
||||
smooth_queue.len--
|
||||
ss_smooth_icon(A)
|
||||
smooth_icon(A)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
if (!smooth_queue.len)
|
||||
@@ -25,8 +25,13 @@ var/datum/subsystem/icon_smooth/SSicon_smooth
|
||||
/datum/subsystem/icon_smooth/Initialize()
|
||||
smooth_zlevel(1,TRUE)
|
||||
smooth_zlevel(2,TRUE)
|
||||
for(var/V in smooth_queue)
|
||||
var/queue = smooth_queue
|
||||
smooth_queue = list()
|
||||
for(var/V in queue)
|
||||
var/atom/A = V
|
||||
if(A.z == 1 || A.z == 2)
|
||||
smooth_queue -= A
|
||||
if(!A || A.z <= 2)
|
||||
continue
|
||||
smooth_icon(A)
|
||||
CHECK_TICK
|
||||
|
||||
..()
|
||||
@@ -6,6 +6,8 @@ var/datum/subsystem/job/SSjob
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/occupations = list() //List of all jobs
|
||||
var/list/name_occupations = list() //Dict of all jobs, keys are titles
|
||||
var/list/type_occupations = list() //Dict of all jobs, keys are types
|
||||
var/list/unassigned = list() //Players who need jobs
|
||||
var/list/job_debug = list() //Debug info
|
||||
var/initial_players_to_assign = 0 //used for checking against population caps
|
||||
@@ -15,7 +17,8 @@ var/datum/subsystem/job/SSjob
|
||||
|
||||
|
||||
/datum/subsystem/job/Initialize(timeofday)
|
||||
SetupOccupations()
|
||||
if(!occupations.len)
|
||||
SetupOccupations()
|
||||
if(config.load_jobs_from_txt)
|
||||
LoadJobs()
|
||||
..()
|
||||
@@ -37,6 +40,8 @@ var/datum/subsystem/job/SSjob
|
||||
if(!job.config_check())
|
||||
continue
|
||||
occupations += job
|
||||
name_occupations[job.title] = job
|
||||
type_occupations[J] = job
|
||||
|
||||
return 1
|
||||
|
||||
@@ -49,14 +54,15 @@ var/datum/subsystem/job/SSjob
|
||||
|
||||
|
||||
/datum/subsystem/job/proc/GetJob(rank)
|
||||
if(!rank)
|
||||
return null
|
||||
for(var/datum/job/J in occupations)
|
||||
if(!J)
|
||||
continue
|
||||
if(J.title == rank)
|
||||
return J
|
||||
return null
|
||||
if(!occupations.len)
|
||||
SetupOccupations()
|
||||
return name_occupations[rank]
|
||||
|
||||
/datum/subsystem/job/proc/GetJobType(jobtype)
|
||||
if(!occupations.len)
|
||||
SetupOccupations()
|
||||
return type_occupations[jobtype]
|
||||
|
||||
|
||||
/datum/subsystem/job/proc/AssignRole(mob/new_player/player, rank, latejoin=0)
|
||||
Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]")
|
||||
@@ -328,7 +334,7 @@ var/datum/subsystem/job/SSjob
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(PopcapReached())
|
||||
RejectPlayer(player)
|
||||
else if(player.client.prefs.userandomjob)
|
||||
else if(player.client.prefs.joblessrole == BERANDOMJOB)
|
||||
GiveRandomJob(player)
|
||||
|
||||
Debug("DO, Standard Check end")
|
||||
@@ -339,8 +345,15 @@ var/datum/subsystem/job/SSjob
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(PopcapReached())
|
||||
RejectPlayer(player)
|
||||
Debug("AC2 Assistant located, Player: [player]")
|
||||
AssignRole(player, "Assistant")
|
||||
if(player.client.prefs.joblessrole == BEASSISTANT)
|
||||
Debug("AC2 Assistant located, Player: [player]")
|
||||
AssignRole(player, "Assistant")
|
||||
else // For those who don't want to play if their preference were filled, back you go.
|
||||
RejectPlayer(player)
|
||||
|
||||
for(var/mob/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?)
|
||||
GiveRandomJob(player)
|
||||
|
||||
return 1
|
||||
|
||||
//Gives the player the stuff he should have with his rank
|
||||
@@ -375,7 +388,7 @@ var/datum/subsystem/job/SSjob
|
||||
if(clear)
|
||||
S = T
|
||||
continue
|
||||
if(istype(S, /obj/effect/landmark) && istype(S.loc, /turf))
|
||||
if(istype(S, /obj/effect/landmark) && isturf(S.loc))
|
||||
H.loc = S.loc
|
||||
|
||||
if(H.mind)
|
||||
@@ -385,7 +398,6 @@ var/datum/subsystem/job/SSjob
|
||||
var/new_mob = job.equip(H)
|
||||
if(ismob(new_mob))
|
||||
H = new_mob
|
||||
job.apply_fingerprints(H)
|
||||
|
||||
H << "<b>You are the [rank].</b>"
|
||||
H << "<b>As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.</b>"
|
||||
@@ -394,7 +406,11 @@ var/datum/subsystem/job/SSjob
|
||||
H << "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>"
|
||||
if(config.minimal_access_threshold)
|
||||
H << "<FONT color='blue'><B>As this station was initially staffed with a [config.jobs_have_minimal_access ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>"
|
||||
return 1
|
||||
|
||||
if(job && H)
|
||||
job.after_spawn(H)
|
||||
|
||||
return H
|
||||
|
||||
|
||||
/datum/subsystem/job/proc/setup_officer_positions()
|
||||
@@ -470,7 +486,8 @@ var/datum/subsystem/job/SSjob
|
||||
/datum/subsystem/job/proc/RejectPlayer(mob/new_player/player)
|
||||
if(player.mind && player.mind.special_role)
|
||||
return
|
||||
Debug("Popcap overflow Check observer located, Player: [player]")
|
||||
if(PopcapReached())
|
||||
Debug("Popcap overflow Check observer located, Player: [player]")
|
||||
player << "<b>You have failed to qualify for any job you desired.</b>"
|
||||
unassigned -= player
|
||||
player.ready = 0
|
||||
|
||||
@@ -1,67 +1,119 @@
|
||||
// Needed for changeTurf() so it doesn't screw up before lighting overlays have been made.
|
||||
var/lighting_overlays_initialized = FALSE
|
||||
var/datum/subsystem/lighting/SSlighting
|
||||
|
||||
/var/list/lighting_update_lights = list() // List of lighting sources queued for update.
|
||||
/var/list/lighting_update_corners = list() // List of lighting corners queued for update.
|
||||
/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update.
|
||||
|
||||
/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated.
|
||||
/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated.
|
||||
/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated.
|
||||
#define SSLIGHTING_LIGHTS 1
|
||||
#define SSLIGHTING_TURFS 2
|
||||
|
||||
/datum/subsystem/lighting
|
||||
name = "lighting"
|
||||
name = "Lighting"
|
||||
init_order = 1
|
||||
wait = 2
|
||||
wait = 1
|
||||
flags = SS_TICKER
|
||||
priority = 25
|
||||
display_order = 5
|
||||
priority = 40
|
||||
flags = SS_POST_FIRE_TIMING
|
||||
|
||||
var/list/changed_lights = list() //list of all datum/light_source that need updating
|
||||
var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len)
|
||||
var/list/changed_turfs = list() //list of all turfs which may have a different light level
|
||||
var/changed_turfs_workload = 0 //stats on the largest number of turfs changed (max changed_turfs.len)
|
||||
|
||||
|
||||
/datum/subsystem/lighting/New()
|
||||
NEW_SS_GLOBAL(SSlighting)
|
||||
return ..()
|
||||
|
||||
/datum/subsystem/lighting/Initialize()
|
||||
|
||||
/datum/subsystem/lighting/stat_entry()
|
||||
..("L:[round(changed_lights_workload,1)]|T:[round(changed_turfs_workload,1)]")
|
||||
|
||||
|
||||
//Workhorse of lighting. It cycles through each light that needs updating. It updates their
|
||||
//effects and then processes every turf in the queue, updating their lighting object's appearance
|
||||
//Any light that returns 1 in check() deletes itself
|
||||
//By using queues we are ensuring we don't perform more updates than are necessary
|
||||
/datum/subsystem/lighting/fire(resumed = 0)
|
||||
var/ticklimit = CURRENT_TICKLIMIT
|
||||
//split our tick allotment in half so we don't spend it all on lightshift checks
|
||||
CURRENT_TICKLIMIT = world.tick_usage + ((ticklimit-world.tick_usage)/2)
|
||||
|
||||
var/list/changed_lights = src.changed_lights
|
||||
if (!resumed)
|
||||
changed_lights_workload = MC_AVERAGE(changed_lights_workload, changed_lights.len)
|
||||
var/i = 1
|
||||
while (i <= changed_lights.len)
|
||||
var/datum/light_source/LS = changed_lights[i++]
|
||||
LS.check()
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
if (i > 1)
|
||||
changed_lights.Cut(1,i)
|
||||
|
||||
CURRENT_TICKLIMIT = ticklimit
|
||||
var/list/changed_turfs = src.changed_turfs
|
||||
if (!resumed)
|
||||
changed_turfs_workload = MC_AVERAGE(changed_turfs_workload, changed_turfs.len)
|
||||
i = 1
|
||||
while (i <= changed_turfs.len)
|
||||
var/turf/T = changed_turfs[i++]
|
||||
if(T.lighting_changed)
|
||||
T.redraw_lighting()
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
if (i > 1)
|
||||
changed_turfs.Cut(1,i)
|
||||
|
||||
//same as above except it attempts to shift ALL turfs in the world regardless of lighting_changed status
|
||||
/datum/subsystem/lighting/Initialize(timeofday)
|
||||
var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))
|
||||
if (config.starlight)
|
||||
for(var/area/A in world)
|
||||
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
if (A.lighting_use_dynamic == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
A.luminosity = 0
|
||||
|
||||
create_all_lighting_overlays()
|
||||
global.lighting_overlays_initialized = TRUE
|
||||
CHECK_TICK
|
||||
for(var/thing in changed_lights)
|
||||
var/datum/light_source/LS = thing
|
||||
LS.check()
|
||||
CHECK_TICK
|
||||
changed_lights.Cut()
|
||||
|
||||
/datum/subsystem/lighting/fire()
|
||||
for(var/thing in turfs_to_init)
|
||||
var/turf/T = thing
|
||||
T.init_lighting()
|
||||
CHECK_TICK
|
||||
changed_turfs.Cut()
|
||||
|
||||
lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated.
|
||||
lighting_update_lights = list()
|
||||
for(var/datum/light_source/L in lighting_update_lights_old)
|
||||
..()
|
||||
|
||||
if(L.check() || L.destroyed || L.force_update)
|
||||
L.remove_lum()
|
||||
if(!L.destroyed)
|
||||
L.apply_lum()
|
||||
//Used to strip valid information from an existing instance and transfer it to the replacement. i.e. when a crash occurs
|
||||
//It works by using spawn(-1) to transfer the data, if there is a runtime the data does not get transfered but the loop
|
||||
//does not crash
|
||||
/datum/subsystem/lighting/Recover()
|
||||
if(!istype(SSlighting.changed_turfs))
|
||||
SSlighting.changed_turfs = list()
|
||||
if(!istype(SSlighting.changed_lights))
|
||||
SSlighting.changed_lights = list()
|
||||
|
||||
else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
for(var/thing in SSlighting.changed_lights)
|
||||
var/datum/light_source/LS = thing
|
||||
spawn(-1) //so we don't crash the loop (inefficient)
|
||||
LS.check()
|
||||
|
||||
L.vis_update = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
for(var/thing in changed_turfs)
|
||||
var/turf/T = thing
|
||||
if(T.lighting_changed)
|
||||
spawn(-1)
|
||||
T.redraw_lighting()
|
||||
|
||||
lighting_update_corners_old = lighting_update_corners //Same as above.
|
||||
lighting_update_corners = list()
|
||||
for(var/A in lighting_update_corners_old)
|
||||
var/datum/lighting_corner/C = A
|
||||
|
||||
C.update_overlays()
|
||||
|
||||
C.needs_update = FALSE
|
||||
|
||||
lighting_update_overlays_old = lighting_update_overlays //Same as above.
|
||||
lighting_update_overlays = list()
|
||||
|
||||
for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old)
|
||||
O.update_overlay()
|
||||
O.needs_update = 0
|
||||
var/msg = "## DEBUG: [time2text(world.timeofday)] [name] subsystem restarted. Reports:\n"
|
||||
for(var/varname in SSlighting.vars)
|
||||
switch(varname)
|
||||
if("tag","bestF","type","parent_type","vars")
|
||||
continue
|
||||
else
|
||||
var/varval1 = SSlighting.vars[varname]
|
||||
var/varval2 = vars[varname]
|
||||
if(istype(varval1,/list))
|
||||
varval1 = "/list([length(varval1)])"
|
||||
varval2 = "/list([length(varval2)])"
|
||||
msg += "\t [varname] = [varval1] -> [varval2]\n"
|
||||
world.log << msg
|
||||
|
||||
@@ -6,6 +6,9 @@ var/datum/subsystem/mapping/SSmapping
|
||||
flags = SS_NO_FIRE
|
||||
display_order = 50
|
||||
|
||||
var/list/nuke_tiles = list()
|
||||
var/list/nuke_threats = list()
|
||||
|
||||
|
||||
/datum/subsystem/mapping/New()
|
||||
NEW_SS_GLOBAL(SSmapping)
|
||||
@@ -34,11 +37,34 @@ var/datum/subsystem/mapping/SSmapping
|
||||
else
|
||||
space_zlevels += i
|
||||
|
||||
seedRuins(space_zlevels, rand(8,16), /area/space, space_ruins_templates)
|
||||
seedRuins(space_zlevels, config.space_budget, /area/space, space_ruins_templates)
|
||||
|
||||
// Set up Z-level transistions.
|
||||
setup_map_transitions()
|
||||
..()
|
||||
|
||||
/* Nuke threats, for making the blue tiles on the station go RED
|
||||
Used by the AI doomsday and the self destruct nuke.
|
||||
*/
|
||||
|
||||
/datum/subsystem/mapping/proc/add_nuke_threat(datum/nuke)
|
||||
nuke_threats[nuke] = TRUE
|
||||
check_nuke_threats()
|
||||
|
||||
/datum/subsystem/mapping/proc/remove_nuke_threat(datum/nuke)
|
||||
nuke_threats -= nuke
|
||||
check_nuke_threats()
|
||||
|
||||
/datum/subsystem/mapping/proc/check_nuke_threats()
|
||||
for(var/datum/d in nuke_threats)
|
||||
if(!istype(d) || qdeleted(d))
|
||||
nuke_threats -= d
|
||||
|
||||
var/threats = nuke_threats.len
|
||||
|
||||
for(var/N in nuke_tiles)
|
||||
var/turf/open/floor/T = N
|
||||
T.icon_state = (threats ? "rcircuitanim" : T.icon_regular_floor)
|
||||
|
||||
/datum/subsystem/mapping/Recover()
|
||||
flags |= SS_NO_INIT
|
||||
|
||||
@@ -87,7 +87,7 @@ var/datum/subsystem/minimap/SSminimap
|
||||
var/obj/obj
|
||||
var/list/obj_icons
|
||||
// Don't use icons for space, just add objects in space if they exist.
|
||||
if(istype(tile, /turf/open/space))
|
||||
if(isspaceturf(tile))
|
||||
obj = locate(/obj/structure/lattice/catwalk) in tile
|
||||
if(obj)
|
||||
tile_icon = new /icon('icons/obj/smooth_structures/catwalk.dmi', "catwalk", SOUTH)
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
var/datum/subsystem/objects/SSobj
|
||||
|
||||
/datum/var/isprocessing = 0
|
||||
/datum/proc/process()
|
||||
set waitfor = 0
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return 0
|
||||
|
||||
/datum/subsystem/objects
|
||||
name = "Objects"
|
||||
init_order = 12
|
||||
priority = 40
|
||||
|
||||
var/list/atom_spawners = list()
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
var/list/burning = list()
|
||||
|
||||
/datum/subsystem/objects/New()
|
||||
NEW_SS_GLOBAL(SSobj)
|
||||
|
||||
/datum/subsystem/objects/Initialize(timeofdayl)
|
||||
trigger_atom_spawners()
|
||||
setupGenetics()
|
||||
for(var/thing in world)
|
||||
var/atom/A = thing
|
||||
A.initialize()
|
||||
CHECK_TICK
|
||||
. = ..()
|
||||
|
||||
/datum/subsystem/objects/proc/trigger_atom_spawners(zlevel, ignore_z=FALSE)
|
||||
for(var/V in atom_spawners)
|
||||
var/atom/A = V
|
||||
if (!ignore_z && (zlevel && A.z != zlevel))
|
||||
continue
|
||||
A.spawn_atom_to_world()
|
||||
|
||||
/datum/subsystem/objects/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/objects/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(currentrun.len)
|
||||
var/datum/thing = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(thing)
|
||||
thing.process(wait)
|
||||
else
|
||||
SSobj.processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
for(var/obj/burningobj in SSobj.burning)
|
||||
if(burningobj && (burningobj.burn_state == ON_FIRE))
|
||||
if(burningobj.burn_world_time < world.time)
|
||||
burningobj.burn()
|
||||
else
|
||||
SSobj.burning.Remove(burningobj)
|
||||
|
||||
/datum/subsystem/objects/proc/setup_template_objects(list/objects)
|
||||
trigger_atom_spawners(0, ignore_z=TRUE)
|
||||
for(var/A in objects)
|
||||
var/atom/B = A
|
||||
B.initialize()
|
||||
|
||||
/datum/subsystem/objects/Recover()
|
||||
if (istype(SSobj.atom_spawners))
|
||||
atom_spawners = SSobj.atom_spawners
|
||||
if (istype(SSobj.processing))
|
||||
processing = SSobj.processing
|
||||
if (istype(SSobj.burning))
|
||||
burning = SSobj.burning
|
||||
@@ -0,0 +1,50 @@
|
||||
var/datum/subsystem/orbit/SSorbit
|
||||
|
||||
/datum/subsystem/orbit
|
||||
name = "Orbits"
|
||||
priority = 35
|
||||
wait = 2
|
||||
flags = SS_NO_INIT|SS_TICKER
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/subsystem/orbit/New()
|
||||
NEW_SS_GLOBAL(SSorbit)
|
||||
|
||||
|
||||
/datum/subsystem/orbit/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/orbit/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while (currentrun.len)
|
||||
var/datum/orbit/O = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!O)
|
||||
processing -= O
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
if (!O.orbiter)
|
||||
qdel(O)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
if (O.lastprocess >= world.time) //we already checked recently
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
var/targetloc = get_turf(O.orbiting)
|
||||
if (targetloc != O.lastloc || O.orbiter.loc != targetloc)
|
||||
O.Check(targetloc)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
var/datum/subsystem/pai/SSpai
|
||||
var/list/obj/item/device/paicard/pai_card_list = list()
|
||||
|
||||
/datum/subsystem/pai
|
||||
name = "pAI"
|
||||
init_order = 20
|
||||
flags = SS_NO_FIRE|SS_NO_INIT
|
||||
|
||||
var/askDelay = 600
|
||||
var/const/NEVER_FOR_THIS_ROUND = -1
|
||||
flags = SS_NO_INIT|SS_NO_FIRE
|
||||
|
||||
var/list/candidates = list()
|
||||
var/list/asked = list()
|
||||
var/ghost_spam = FALSE
|
||||
var/spam_delay = 100
|
||||
|
||||
/datum/subsystem/pai/New()
|
||||
NEW_SS_GLOBAL(SSpai)
|
||||
@@ -20,6 +20,8 @@ var/datum/subsystem/pai/SSpai
|
||||
if(card.pai)
|
||||
return
|
||||
if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate))
|
||||
if(check_ready(candidate) != candidate)
|
||||
return FALSE
|
||||
var/mob/living/silicon/pai/pai = new(card)
|
||||
if(!candidate.name)
|
||||
pai.name = pick(ninja_names)
|
||||
@@ -29,7 +31,6 @@ var/datum/subsystem/pai/SSpai
|
||||
pai.key = candidate.key
|
||||
|
||||
card.setPersonality(pai)
|
||||
card.looking_for_personality = 0
|
||||
|
||||
ticker.mode.update_cult_icons_removed(card.pai.mind)
|
||||
ticker.mode.update_rev_icons_removed(card.pai.mind)
|
||||
@@ -76,8 +77,8 @@ var/datum/subsystem/pai/SSpai
|
||||
if("submit")
|
||||
if(candidate)
|
||||
candidate.ready = 1
|
||||
for(var/obj/item/device/paicard/p in world)
|
||||
if(p.looking_for_personality == 1)
|
||||
for(var/obj/item/device/paicard/p in pai_card_list)
|
||||
if(!p.pai)
|
||||
p.alertUpdate()
|
||||
usr << browse(null, "window=paiRecruit")
|
||||
return
|
||||
@@ -134,17 +135,31 @@ var/datum/subsystem/pai/SSpai
|
||||
|
||||
M << browse(dat, "window=paiRecruit")
|
||||
|
||||
/datum/subsystem/pai/proc/spam_again()
|
||||
ghost_spam = FALSE
|
||||
|
||||
/datum/subsystem/pai/proc/check_ready(var/datum/paiCandidate/C)
|
||||
if(!C.ready)
|
||||
return FALSE
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(O.key == C.key)
|
||||
return C
|
||||
return FALSE
|
||||
|
||||
/datum/subsystem/pai/proc/findPAI(obj/item/device/paicard/p, mob/user)
|
||||
requestRecruits()
|
||||
if(!ghost_spam)
|
||||
ghost_spam = TRUE
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
if(!G.key || !G.client)
|
||||
continue
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
G << "<span class='ghostalert'>Someone is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>"
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
if(c.ready)
|
||||
var/found = 0
|
||||
for(var/mob/dead/observer/o in player_list)
|
||||
if(o.key == c.key)
|
||||
found = 1
|
||||
if(found)
|
||||
available.Add(c)
|
||||
available.Add(check_ready(c))
|
||||
var/dat = ""
|
||||
|
||||
dat += {"
|
||||
@@ -180,36 +195,6 @@ var/datum/subsystem/pai/SSpai
|
||||
|
||||
user << browse(dat, "window=findPai")
|
||||
|
||||
/datum/subsystem/pai/proc/requestRecruits()
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(jobban_isbanned(O, ROLE_PAI))
|
||||
continue
|
||||
if(asked[O.ckey])
|
||||
if(world.time < asked[O.ckey] + askDelay || asked[O.ckey] == NEVER_FOR_THIS_ROUND)
|
||||
continue
|
||||
else
|
||||
asked.Remove(O.ckey)
|
||||
if(O.client)
|
||||
var/hasSubmitted = 0
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
if(c.key == O.key)
|
||||
hasSubmitted = 1
|
||||
if(!hasSubmitted && (ROLE_PAI in O.client.prefs.be_special))
|
||||
question(O.client)
|
||||
|
||||
/datum/subsystem/pai/proc/question(client/C)
|
||||
set waitfor = 0
|
||||
if(!C)
|
||||
return
|
||||
asked[C.ckey] = world.time
|
||||
var/response = tgalert(C, "Someone is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", "Yes", "No", "Never for this round", StealFocus=0, Timeout=askDelay)
|
||||
if(!C)
|
||||
return //handle logouts that happen whilst the alert is waiting for a response.
|
||||
if(response == "Yes")
|
||||
recruitWindow(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
asked[C.ckey] = NEVER_FOR_THIS_ROUND
|
||||
|
||||
/datum/paiCandidate
|
||||
var/name
|
||||
var/key
|
||||
|
||||
@@ -1,12 +1,42 @@
|
||||
var/datum/subsystem/parallax/SSparallax
|
||||
|
||||
/datum/subsystem/parallax
|
||||
name = "Space Parallax"
|
||||
init_order = 18
|
||||
flags = SS_NO_FIRE
|
||||
name = "parallax"
|
||||
wait = 2
|
||||
flags = SS_POST_FIRE_TIMING | SS_FIRE_IN_LOBBY | SS_BACKGROUND | SS_NO_INIT
|
||||
priority = 65
|
||||
var/list/currentrun
|
||||
|
||||
/datum/subsystem/parallax/New()
|
||||
NEW_SS_GLOBAL(SSparallax)
|
||||
NEW_SS_GLOBAL(SSparallax)
|
||||
return ..()
|
||||
|
||||
/datum/subsystem/parallax/Initialize()
|
||||
create_global_parallax_icons()
|
||||
/datum/subsystem/parallax/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = clients.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(length(currentrun))
|
||||
var/client/C = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!C || !C.eye)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
var/atom/movable/A = C.eye
|
||||
if(!A)
|
||||
return
|
||||
for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc);
|
||||
|
||||
if(A != C.movingmob)
|
||||
if(C.movingmob != null)
|
||||
C.movingmob.client_mobs_in_contents -= C.mob
|
||||
UNSETEMPTY(C.movingmob.client_mobs_in_contents)
|
||||
LAZYINITLIST(A.client_mobs_in_contents)
|
||||
A.client_mobs_in_contents += C.mob
|
||||
C.movingmob = A
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
currentrun = null
|
||||
@@ -0,0 +1,130 @@
|
||||
var/datum/subsystem/persistence/SSpersistence
|
||||
|
||||
/datum/subsystem/persistence
|
||||
name = "Persistence"
|
||||
init_order = -100
|
||||
flags = SS_NO_FIRE
|
||||
var/savefile/secret_satchels
|
||||
var/list/satchel_blacklist = list() //this is a typecache
|
||||
var/list/new_secret_satchels = list() //these are objects
|
||||
var/old_secret_satchels = ""
|
||||
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/savefile/chisel_messages_sav
|
||||
|
||||
/datum/subsystem/persistence/New()
|
||||
NEW_SS_GLOBAL(SSpersistence)
|
||||
|
||||
/datum/subsystem/persistence/Initialize()
|
||||
LoadSatchels()
|
||||
LoadPoly()
|
||||
LoadChiselMessages()
|
||||
..()
|
||||
|
||||
/datum/subsystem/persistence/proc/LoadSatchels()
|
||||
secret_satchels = new /savefile("data/npc_saves/SecretSatchels.sav")
|
||||
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/weapon/crowbar))
|
||||
secret_satchels[MAP_NAME] >> old_secret_satchels
|
||||
|
||||
var/list/expanded_old_satchels = list()
|
||||
var/placed_satchels = 0
|
||||
|
||||
if(!isnull(old_secret_satchels))
|
||||
expanded_old_satchels = splittext(old_secret_satchels,"#")
|
||||
if(PlaceSecretSatchel(expanded_old_satchels))
|
||||
placed_satchels++
|
||||
else
|
||||
expanded_old_satchels.len = 0
|
||||
|
||||
var/list/free_satchels = list()
|
||||
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,ZLEVEL_STATION), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,ZLEVEL_STATION)))) //Nontrivially expensive but it's roundstart only
|
||||
if(isfloorturf(T) && !istype(T,/turf/open/floor/plating/))
|
||||
free_satchels += new /obj/item/weapon/storage/backpack/satchel/flat/secret(T)
|
||||
if(!isemptylist(free_satchels) && ((free_satchels.len + placed_satchels) >= (50 - expanded_old_satchels.len) * 0.1)) //up to six tiles, more than enough to kill anything that moves
|
||||
break
|
||||
|
||||
/datum/subsystem/persistence/proc/PlaceSecretSatchel(list/expanded_old_satchels)
|
||||
var/satchel_string
|
||||
|
||||
if(expanded_old_satchels.len >= 20) //guards against low drop pools assuring that one player cannot reliably find his own gear.
|
||||
satchel_string = pick_n_take(expanded_old_satchels)
|
||||
|
||||
old_secret_satchels = jointext(expanded_old_satchels,"#")
|
||||
secret_satchels[MAP_NAME] << old_secret_satchels
|
||||
|
||||
var/list/chosen_satchel = splittext(satchel_string,"|")
|
||||
if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed
|
||||
return 0
|
||||
|
||||
var/path = text2path(chosen_satchel[3]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
return 0
|
||||
|
||||
var/obj/item/weapon/storage/backpack/satchel/flat/F = new()
|
||||
F.x = text2num(chosen_satchel[1])
|
||||
F.y = text2num(chosen_satchel[2])
|
||||
F.z = ZLEVEL_STATION
|
||||
if(isfloorturf(F.loc) && !istype(F.loc,/turf/open/floor/plating/))
|
||||
F.hide(1)
|
||||
new path(F)
|
||||
return 1
|
||||
|
||||
/datum/subsystem/persistence/proc/LoadPoly()
|
||||
for(var/mob/living/simple_animal/parrot/Poly/P in living_mob_list)
|
||||
twitterize(P.speech_buffer, "polytalk")
|
||||
break //Who's been duping the bird?!
|
||||
|
||||
/datum/subsystem/persistence/proc/LoadChiselMessages()
|
||||
chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
var/saved_json
|
||||
chisel_messages_sav[MAP_NAME] >> saved_json
|
||||
|
||||
if(!saved_json)
|
||||
return
|
||||
|
||||
var/saved_messages = json_decode(saved_json)
|
||||
|
||||
for(var/item in saved_messages)
|
||||
var/turf/T = locate(item["x"], item["y"], ZLEVEL_STATION)
|
||||
if(!isturf(T))
|
||||
continue
|
||||
if(locate(/obj/structure/chisel_message) in T)
|
||||
continue
|
||||
var/obj/structure/chisel_message/M = new(T)
|
||||
M.unpack(item)
|
||||
if(!M.loc)
|
||||
M.persists = FALSE
|
||||
qdel(M)
|
||||
|
||||
|
||||
/datum/subsystem/persistence/proc/CollectData()
|
||||
CollectChiselMessages()
|
||||
CollectSecretSatchels()
|
||||
|
||||
/datum/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
for(var/A in new_secret_satchels)
|
||||
var/obj/item/weapon/storage/backpack/satchel/flat/F = A
|
||||
if(qdeleted(F) || F.z != ZLEVEL_STATION || F.invisibility != INVISIBILITY_MAXIMUM)
|
||||
continue
|
||||
var/list/savable_obj = list()
|
||||
for(var/obj/O in F)
|
||||
if(is_type_in_typecache(O, satchel_blacklist) || O.admin_spawned)
|
||||
continue
|
||||
if(O.persistence_replacement)
|
||||
savable_obj += O.persistence_replacement
|
||||
else
|
||||
savable_obj += O.type
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#"
|
||||
secret_satchels[MAP_NAME] << old_secret_satchels
|
||||
|
||||
/datum/subsystem/persistence/proc/CollectChiselMessages()
|
||||
for(var/obj/structure/chisel_message/M in chisel_messages)
|
||||
saved_messages += list(M.pack())
|
||||
|
||||
chisel_messages_sav[MAP_NAME] << json_encode(saved_messages)
|
||||
|
||||
/datum/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list.
|
||||
@@ -0,0 +1,33 @@
|
||||
#define PING_BUFFER_TIME 25
|
||||
|
||||
var/datum/subsystem/ping/SSping
|
||||
|
||||
/datum/subsystem/ping
|
||||
name = "Ping"
|
||||
wait = 6
|
||||
flags = SS_NO_INIT|SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
priority = 10
|
||||
var/list/currentrun
|
||||
|
||||
/datum/subsystem/ping/New()
|
||||
NEW_SS_GLOBAL(SSping)
|
||||
|
||||
/datum/subsystem/ping/fire(resumed = FALSE)
|
||||
if (!resumed)
|
||||
src.currentrun = clients.Copy()
|
||||
|
||||
var/list/currentrun = src.currentrun
|
||||
while (length(currentrun))
|
||||
var/client/C = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if (!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1))
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
|
||||
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
|
||||
return
|
||||
|
||||
currentrun = null
|
||||
|
||||
#undef PING_BUFFER_TIME
|
||||
@@ -0,0 +1,10 @@
|
||||
//Fires five times every second.
|
||||
|
||||
var/datum/subsystem/processing/fastprocess/SSfastprocess
|
||||
/datum/subsystem/processing/fastprocess
|
||||
name = "Fast Processing"
|
||||
wait = 2
|
||||
stat_tag = "FP"
|
||||
|
||||
/datum/subsystem/processing/fastprocess/New()
|
||||
NEW_SS_GLOBAL(SSfastprocess)
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
var/datum/subsystem/processing/flightpacks/SSflightpacks
|
||||
/datum/subsystem/processing/flightpacks
|
||||
name = "Flightpack Movement"
|
||||
priority = 30
|
||||
wait = 2
|
||||
stat_tag = "FM"
|
||||
flags = SS_NO_INIT|SS_TICKER|SS_KEEP_TIMING
|
||||
|
||||
/datum/subsystem/processing/flightpacks/New()
|
||||
NEW_SS_GLOBAL(SSflightpacks)
|
||||
@@ -0,0 +1,86 @@
|
||||
var/datum/subsystem/objects/SSobj
|
||||
|
||||
#define INITIALIZATION_INSSOBJ 0 //New should not call Initialize
|
||||
#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE)
|
||||
#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE)
|
||||
|
||||
/datum/var/isprocessing = 0
|
||||
/datum/proc/process()
|
||||
set waitfor = 0
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return 0
|
||||
|
||||
/datum/subsystem/objects
|
||||
name = "Objects"
|
||||
init_order = 12
|
||||
priority = 40
|
||||
|
||||
var/initialized = INITIALIZATION_INSSOBJ
|
||||
var/old_initialized
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
/datum/subsystem/objects/New()
|
||||
NEW_SS_GLOBAL(SSobj)
|
||||
|
||||
/datum/subsystem/objects/Initialize(timeofdayl)
|
||||
fire_overlay.appearance_flags = RESET_COLOR
|
||||
setupGenetics() //to set the mutations' place in structural enzymes, so monkey.initialize() knows where to put the monkey mutation.
|
||||
initialized = INITIALIZATION_INNEW_MAPLOAD
|
||||
InitializeAtoms()
|
||||
. = ..()
|
||||
|
||||
/datum/subsystem/objects/proc/InitializeAtoms(list/objects = null)
|
||||
if(initialized == INITIALIZATION_INSSOBJ)
|
||||
return
|
||||
initialized = INITIALIZATION_INNEW_MAPLOAD
|
||||
if(objects)
|
||||
for(var/thing in objects)
|
||||
var/atom/A = thing
|
||||
A.Initialize(TRUE)
|
||||
CHECK_TICK
|
||||
else
|
||||
for(var/atom/A in world)
|
||||
if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call
|
||||
var/start_tick = world.time
|
||||
A.Initialize(TRUE)
|
||||
if(start_tick != world.time)
|
||||
WARNING("[A]: [A.type] slept during it's Initialize!")
|
||||
CHECK_TICK
|
||||
initialized = INITIALIZATION_INNEW_REGULAR
|
||||
|
||||
/datum/subsystem/objects/proc/map_loader_begin()
|
||||
old_initialized = initialized
|
||||
initialized = INITIALIZATION_INSSOBJ
|
||||
|
||||
/datum/subsystem/objects/proc/map_loader_stop()
|
||||
initialized = old_initialized
|
||||
|
||||
/datum/subsystem/objects/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/objects/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(currentrun.len)
|
||||
var/datum/thing = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(thing)
|
||||
thing.process(wait)
|
||||
else
|
||||
SSobj.processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/subsystem/objects/Recover()
|
||||
initialized = SSobj.initialized
|
||||
if(initialized == INITIALIZATION_INNEW_MAPLOAD)
|
||||
InitializeAtoms()
|
||||
old_initialized = SSobj.old_initialized
|
||||
|
||||
if (istype(SSobj.processing))
|
||||
processing = SSobj.processing
|
||||
@@ -0,0 +1,34 @@
|
||||
//Used to process objects. Fires once every second.
|
||||
|
||||
var/datum/subsystem/processing/SSprocessing
|
||||
/datum/subsystem/processing
|
||||
name = "Processing"
|
||||
priority = 25
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
wait = 10
|
||||
|
||||
var/stat_tag = "P" //Used for logging
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
/datum/subsystem/processing/New()
|
||||
NEW_SS_GLOBAL(SSprocessing)
|
||||
|
||||
/datum/subsystem/processing/stat_entry()
|
||||
..("[stat_tag]:[processing.len]")
|
||||
|
||||
/datum/subsystem/processing/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
currentrun = processing.Copy()
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/current_run = currentrun
|
||||
|
||||
while(current_run.len)
|
||||
var/datum/thing = current_run[current_run.len]
|
||||
current_run.len--
|
||||
if(thing)
|
||||
thing.process(wait)
|
||||
else
|
||||
processing -= thing
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -0,0 +1,17 @@
|
||||
var/datum/subsystem/religion/SSreligion
|
||||
|
||||
/datum/subsystem/religion
|
||||
name = "Religion"
|
||||
init_order = 19
|
||||
flags = SS_NO_FIRE|SS_NO_INIT
|
||||
|
||||
var/bible_deity_name
|
||||
var/Bible_icon_state
|
||||
var/Bible_item_state
|
||||
var/Bible_name
|
||||
var/Bible_deity_name
|
||||
|
||||
var/holy_weapon
|
||||
|
||||
/datum/subsystem/religion/New()
|
||||
NEW_SS_GLOBAL(SSreligion)
|
||||
@@ -3,12 +3,16 @@ var/datum/subsystem/server_maint/SSserver
|
||||
/datum/subsystem/server_maint
|
||||
name = "Server Tasks"
|
||||
wait = 6000
|
||||
init_order = 19
|
||||
flags = SS_NO_TICK_CHECK|SS_NO_INIT
|
||||
flags = SS_NO_TICK_CHECK
|
||||
|
||||
/datum/subsystem/server_maint/New()
|
||||
NEW_SS_GLOBAL(SSserver)
|
||||
|
||||
/datum/subsystem/server_maint/Initialize(timeofday)
|
||||
if (config.hub)
|
||||
world.visibility = 1
|
||||
..()
|
||||
|
||||
/datum/subsystem/server_maint/fire()
|
||||
//handle kicking inactive players
|
||||
if(config.kick_inactive > 0)
|
||||
@@ -17,7 +21,7 @@ var/datum/subsystem/server_maint/SSserver
|
||||
if(!istype(C.mob, /mob/dead))
|
||||
log_access("AFK: [key_name(C)]")
|
||||
C << "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>"
|
||||
del(C)
|
||||
qdel(C)
|
||||
|
||||
if(config.sql_enabled)
|
||||
sql_poll_players()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define HIGHLIGHT_DYNAMIC_TRANSIT 1
|
||||
|
||||
var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
/datum/subsystem/shuttle
|
||||
@@ -10,6 +12,10 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
var/list/stationary = list()
|
||||
var/list/transit = list()
|
||||
|
||||
var/list/turf/transit_turfs = list()
|
||||
var/list/transit_requesters = list()
|
||||
var/clear_transit = FALSE
|
||||
|
||||
//emergency shuttle stuff
|
||||
var/obj/docking_port/mobile/emergency/emergency
|
||||
var/obj/docking_port/mobile/emergency/backup/backup_shuttle
|
||||
@@ -18,6 +24,7 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
var/emergencyEscapeTime = 1200 //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
|
||||
var/area/emergencyLastCallLoc
|
||||
var/emergencyNoEscape
|
||||
var/list/hostileEnvironments = list()
|
||||
|
||||
//supply shuttle stuff
|
||||
var/obj/docking_port/mobile/supply/supply
|
||||
@@ -33,6 +40,11 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
var/datum/round_event/shuttle_loan/shuttle_loan
|
||||
|
||||
var/shuttle_purchased = FALSE //If the station has purchased a replacement escape shuttle this round
|
||||
var/list/shuttle_purchase_requirements_met = list() //For keeping track of ingame events that would unlock new shuttles, such as defeating a boss or discovering a secret item
|
||||
|
||||
var/lockdown = FALSE //disallow transit after nuke goes off
|
||||
|
||||
/datum/subsystem/shuttle/New()
|
||||
NEW_SS_GLOBAL(SSshuttle)
|
||||
|
||||
@@ -53,16 +65,87 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
supply_packs[P.type] = P
|
||||
|
||||
initial_move()
|
||||
..()
|
||||
setup_transit_zone()
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
color_space()
|
||||
#endif
|
||||
|
||||
/datum/subsystem/shuttle/proc/setup_transit_zone()
|
||||
if(transit_markers.len == 0)
|
||||
WARNING("No /obj/effect/landmark/transit placed on the map!")
|
||||
return
|
||||
// transit zone
|
||||
var/turf/A = get_turf(transit_markers[1])
|
||||
var/turf/B = get_turf(transit_markers[2])
|
||||
for(var/i in block(A, B))
|
||||
var/turf/T = i
|
||||
T.ChangeTurf(/turf/open/space)
|
||||
transit_turfs += T
|
||||
T.flags |= UNUSED_TRANSIT_TURF
|
||||
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
/datum/subsystem/shuttle/proc/color_space()
|
||||
if(transit_markers.len == 0)
|
||||
WARNING("No /obj/effect/landmark/transit placed on the map!")
|
||||
return
|
||||
var/turf/A = get_turf(transit_markers[1])
|
||||
var/turf/B = get_turf(transit_markers[2])
|
||||
for(var/i in block(A, B))
|
||||
var/turf/T = i
|
||||
// Only dying the "pure" space, not the transit tiles
|
||||
if(istype(T, /turf/open/space/transit) || !isspaceturf(T))
|
||||
continue
|
||||
if((T.x == A.x) || (T.x == B.x) || (T.y == A.y) || (T.y == B.y))
|
||||
T.color = "#ffff00"
|
||||
else
|
||||
T.color = "#00ffff"
|
||||
#endif
|
||||
|
||||
//world.log << "[transit_turfs.len] transit turfs registered"
|
||||
|
||||
/datum/subsystem/shuttle/fire()
|
||||
for(var/thing in mobile)
|
||||
if(thing)
|
||||
var/obj/docking_port/mobile/P = thing
|
||||
P.check()
|
||||
if(!thing)
|
||||
mobile.Remove(thing)
|
||||
continue
|
||||
mobile.Remove(thing)
|
||||
var/obj/docking_port/mobile/P = thing
|
||||
P.check()
|
||||
var/changed_transit = FALSE
|
||||
for(var/thing in transit)
|
||||
var/obj/docking_port/stationary/transit/T = thing
|
||||
if(!T.owner)
|
||||
qdel(T, force=TRUE)
|
||||
changed_transit = TRUE
|
||||
// This next one removes transit docks/zones that aren't
|
||||
// immediately being used. This will mean that the zone creation
|
||||
// code will be running a lot.
|
||||
var/obj/docking_port/mobile/owner = T.owner
|
||||
if(owner)
|
||||
var/idle = owner.mode == SHUTTLE_IDLE
|
||||
var/not_centcom_evac = owner.launch_status == NOLAUNCH
|
||||
var/not_in_use = (!T.get_docked())
|
||||
if(idle && not_centcom_evac && not_in_use)
|
||||
qdel(T, force=TRUE)
|
||||
changed_transit = TRUE
|
||||
if(clear_transit)
|
||||
transit_requesters.Cut()
|
||||
for(var/i in transit)
|
||||
qdel(i, force=TRUE)
|
||||
setup_transit_zone()
|
||||
clear_transit = FALSE
|
||||
changed_transit = TRUE
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
if(changed_transit)
|
||||
color_space()
|
||||
#endif
|
||||
|
||||
while(transit_requesters.len)
|
||||
var/requester = popleft(transit_requesters)
|
||||
var/success = generate_transit_dock(requester)
|
||||
if(!success) // BACK OF THE QUEUE
|
||||
transit_requesters += requester
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/subsystem/shuttle/proc/getShuttle(id)
|
||||
for(var/obj/docking_port/mobile/M in mobile)
|
||||
@@ -105,6 +188,9 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
if(SHUTTLE_DOCKED)
|
||||
user << "The emergency shuttle is already here."
|
||||
return
|
||||
if(SHUTTLE_IGNITING)
|
||||
user << "The emergency shuttle is firing its engines to leave."
|
||||
return
|
||||
if(SHUTTLE_ESCAPE)
|
||||
user << "The emergency shuttle is moving away to a safe distance."
|
||||
return
|
||||
@@ -114,22 +200,24 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
|
||||
call_reason = trim(html_encode(call_reason))
|
||||
|
||||
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
|
||||
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && seclevel2num(get_security_level()) > SEC_LEVEL_GREEN)
|
||||
user << "You must provide a reason."
|
||||
return
|
||||
|
||||
var/area/signal_origin = get_area(user)
|
||||
var/emergency_reason = "\nNature of emergency:\n\n[call_reason]"
|
||||
if(seclevel2num(get_security_level()) == SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
|
||||
emergency.request(null, 0.5, signal_origin, html_decode(emergency_reason), 1)
|
||||
else
|
||||
emergency.request(null, 1, signal_origin, html_decode(emergency_reason), 0)
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
emergency.request(null, 2, signal_origin, html_decode(emergency_reason), 0)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
emergency.request(null, 1, signal_origin, html_decode(emergency_reason), 0)
|
||||
else
|
||||
emergency.request(null, 0.5, signal_origin, html_decode(emergency_reason), 1) // There is a serious threat we gotta move no time to give them five minutes.
|
||||
|
||||
log_game("[key_name(user)] has called the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has called the shuttle.")
|
||||
|
||||
return
|
||||
|
||||
// Called when an emergency shuttle mobile docking port is
|
||||
// destroyed, which will only happen with admin intervention
|
||||
/datum/subsystem/shuttle/proc/emergencyDeregister()
|
||||
@@ -149,19 +237,24 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
return
|
||||
if(ticker.mode.name == "meteor")
|
||||
return
|
||||
if(seclevel2num(get_security_level()) == SEC_LEVEL_RED)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
|
||||
return
|
||||
else
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.5)
|
||||
return
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime)
|
||||
return
|
||||
if(SEC_LEVEL_BLUE)
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.5)
|
||||
return
|
||||
else
|
||||
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
|
||||
return
|
||||
return 1
|
||||
|
||||
/datum/subsystem/shuttle/proc/autoEvac()
|
||||
var/callShuttle = 1
|
||||
|
||||
for(var/thing in shuttle_caller_list)
|
||||
if(istype(thing, /mob/living/silicon/ai))
|
||||
if(isAI(thing))
|
||||
var/mob/living/silicon/ai/AI = thing
|
||||
if(AI.stat || !AI.client)
|
||||
continue
|
||||
@@ -181,6 +274,34 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.")
|
||||
message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.")
|
||||
|
||||
/datum/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad)
|
||||
hostileEnvironments[bad] = TRUE
|
||||
checkHostileEnvironment()
|
||||
|
||||
/datum/subsystem/shuttle/proc/clearHostileEnvironment(datum/bad)
|
||||
hostileEnvironments -= bad
|
||||
checkHostileEnvironment()
|
||||
|
||||
/datum/subsystem/shuttle/proc/checkHostileEnvironment()
|
||||
for(var/datum/d in hostileEnvironments)
|
||||
if(!istype(d) || qdeleted(d))
|
||||
hostileEnvironments -= d
|
||||
emergencyNoEscape = hostileEnvironments.len
|
||||
|
||||
if(emergencyNoEscape && (emergency.mode == SHUTTLE_IGNITING))
|
||||
emergency.mode = SHUTTLE_STRANDED
|
||||
emergency.timer = null
|
||||
emergency.sound_played = FALSE
|
||||
priority_announce("Hostile environment detected. \
|
||||
Departure has been postponed indefinitely pending \
|
||||
conflict resolution.", null, 'sound/misc/notice1.ogg', "Priority")
|
||||
if(!emergencyNoEscape && (emergency.mode == SHUTTLE_STRANDED))
|
||||
emergency.mode = SHUTTLE_DOCKED
|
||||
emergency.setTimer(emergencyDockTime)
|
||||
priority_announce("Hostile environment resolved. \
|
||||
You have 3 minutes to board the Emergency Shuttle.",
|
||||
null, 'sound/AI/shuttledock.ogg', "Priority")
|
||||
|
||||
//try to move/request to dockHome if possible, otherwise dockAway. Mainly used for admin buttons
|
||||
/datum/subsystem/shuttle/proc/toggleShuttle(shuttleId, dockHome, dockAway, timed)
|
||||
var/obj/docking_port/mobile/M = getShuttle(shuttleId)
|
||||
@@ -213,11 +334,149 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
return 2
|
||||
return 0 //dock successful
|
||||
|
||||
/datum/subsystem/shuttle/proc/request_transit_dock(obj/docking_port/mobile/M)
|
||||
if(!istype(M))
|
||||
throw EXCEPTION("[M] is not a mobile docking port")
|
||||
|
||||
if(M.assigned_transit)
|
||||
return
|
||||
else
|
||||
if(!(M in transit_requesters))
|
||||
transit_requesters += M
|
||||
|
||||
/datum/subsystem/shuttle/proc/generate_transit_dock(obj/docking_port/mobile/M)
|
||||
// First, determine the size of the needed zone
|
||||
// Because of shuttle rotation, the "width" of the shuttle is not
|
||||
// always x.
|
||||
var/travel_dir = M.preferred_direction
|
||||
// Remember, the direction is the direction we appear to be
|
||||
// coming from
|
||||
var/dock_angle = dir2angle(M.preferred_direction) + M.port_angle + 180
|
||||
var/dock_dir = angle2dir(dock_angle)
|
||||
|
||||
var/transit_width = SHUTTLE_TRANSIT_BORDER * 2
|
||||
var/transit_height = SHUTTLE_TRANSIT_BORDER * 2
|
||||
|
||||
// Shuttles travelling on their side have their dimensions swapped
|
||||
// from our perspective
|
||||
switch(dock_dir)
|
||||
if(NORTH, SOUTH)
|
||||
transit_width += M.width
|
||||
transit_height += M.height
|
||||
if(EAST, WEST)
|
||||
transit_width += M.height
|
||||
transit_height += M.width
|
||||
/*
|
||||
world << "The attempted transit dock will be [transit_width] width, and \
|
||||
[transit_height] in height. The travel dir is [travel_dir]."
|
||||
*/
|
||||
|
||||
// Then find a place to put the zone
|
||||
|
||||
var/list/proposed_zone
|
||||
|
||||
base:
|
||||
for(var/i in transit_turfs)
|
||||
CHECK_TICK
|
||||
var/turf/topleft = i
|
||||
if(!(topleft.flags & UNUSED_TRANSIT_TURF))
|
||||
continue
|
||||
var/turf/bottomright = locate(topleft.x + transit_width,
|
||||
topleft.y + transit_height, topleft.z)
|
||||
if(!bottomright)
|
||||
continue
|
||||
if(!(bottomright.flags & UNUSED_TRANSIT_TURF))
|
||||
continue
|
||||
|
||||
proposed_zone = block(topleft, bottomright)
|
||||
if(!proposed_zone)
|
||||
continue
|
||||
for(var/j in proposed_zone)
|
||||
var/turf/T = j
|
||||
if(!T)
|
||||
continue base
|
||||
if(!(T.flags & UNUSED_TRANSIT_TURF))
|
||||
continue base
|
||||
//world << "[COORD(topleft)] and [COORD(bottomright)]"
|
||||
break base
|
||||
|
||||
if((!proposed_zone) || (!proposed_zone.len))
|
||||
return FALSE
|
||||
|
||||
var/turf/topleft = proposed_zone[1]
|
||||
//world << "[COORD(topleft)] is TOPLEFT"
|
||||
// Then create a transit docking port in the middle
|
||||
var/coords = M.return_coords(0, 0, dock_dir)
|
||||
//world << json_encode(coords)
|
||||
/* 0------2
|
||||
| |
|
||||
| |
|
||||
| x |
|
||||
3------1
|
||||
*/
|
||||
|
||||
var/x0 = coords[1]
|
||||
var/y0 = coords[2]
|
||||
var/x1 = coords[3]
|
||||
var/y1 = coords[4]
|
||||
// Then we want the point closest to -infinity,-infinity
|
||||
var/x2 = min(x0, x1)
|
||||
var/y2 = min(y0, y1)
|
||||
/*
|
||||
var/lowx = topleft.x + SHUTTLE_TRANSIT_BORDER
|
||||
var/lowy = topleft.y + SHUTTLE_TRANSIT_BORDER
|
||||
|
||||
var/turf/low_point = locate(lowx, lowy, topleft.z)
|
||||
new /obj/effect/landmark/stationary(low_point)
|
||||
world << "Starting at the low point, we go [x2],[y2]"
|
||||
*/
|
||||
// Then invert the numbers
|
||||
var/transit_x = topleft.x + SHUTTLE_TRANSIT_BORDER + abs(x2)
|
||||
var/transit_y = topleft.y + SHUTTLE_TRANSIT_BORDER + abs(y2)
|
||||
|
||||
var/transit_path = /turf/open/space/transit
|
||||
switch(travel_dir)
|
||||
if(NORTH)
|
||||
transit_path = /turf/open/space/transit/north
|
||||
if(SOUTH)
|
||||
transit_path = /turf/open/space/transit/south
|
||||
if(EAST)
|
||||
transit_path = /turf/open/space/transit/east
|
||||
if(WEST)
|
||||
transit_path = /turf/open/space/transit/west
|
||||
|
||||
//world << "Docking port at [transit_x], [transit_y], [topleft.z]"
|
||||
var/turf/midpoint = locate(transit_x, transit_y, topleft.z)
|
||||
if(!midpoint)
|
||||
return FALSE
|
||||
//world << "Making transit dock at [COORD(midpoint)]"
|
||||
var/area/shuttle/transit/A = new()
|
||||
A.parallax_movedir = travel_dir
|
||||
var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint)
|
||||
new_transit_dock.assigned_turfs = proposed_zone
|
||||
new_transit_dock.name = "Transit for [M.id]/[M.name]"
|
||||
new_transit_dock.turf_type = transit_path
|
||||
new_transit_dock.owner = M
|
||||
new_transit_dock.assigned_area = A
|
||||
|
||||
|
||||
// Add 180, because ports point inwards, rather than outwards
|
||||
new_transit_dock.setDir(angle2dir(dock_angle))
|
||||
|
||||
for(var/i in new_transit_dock.assigned_turfs)
|
||||
var/turf/T = i
|
||||
T.ChangeTurf(transit_path)
|
||||
T.flags &= ~(UNUSED_TRANSIT_TURF)
|
||||
A.contents += T
|
||||
|
||||
M.assigned_transit = new_transit_dock
|
||||
return TRUE
|
||||
|
||||
/datum/subsystem/shuttle/proc/initial_move()
|
||||
for(var/obj/docking_port/mobile/M in mobile)
|
||||
if(!M.roundstart_move)
|
||||
continue
|
||||
moveShuttle(M.id, "[M.roundstart_move]", 0)
|
||||
M.dockRoundstart()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/subsystem/shuttle/Recover()
|
||||
@@ -239,6 +498,8 @@ var/datum/subsystem/shuttle/SSshuttle
|
||||
backup_shuttle = SSshuttle.backup_shuttle
|
||||
if (istype(SSshuttle.supply))
|
||||
supply = SSshuttle.supply
|
||||
if (istype(SSshuttle.transit_turfs))
|
||||
transit_turfs = SSshuttle.transit_turfs
|
||||
|
||||
centcom_message = SSshuttle.centcom_message
|
||||
ordernum = SSshuttle.ordernum
|
||||
|
||||
@@ -2,9 +2,9 @@ var/datum/subsystem/spacedrift/SSspacedrift
|
||||
|
||||
/datum/subsystem/spacedrift
|
||||
name = "Space Drift"
|
||||
priority = 40
|
||||
priority = 30
|
||||
wait = 5
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
flags = SS_NO_INIT|SS_KEEP_TIMING
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
@@ -61,3 +61,4 @@ var/datum/subsystem/spacedrift/SSspacedrift
|
||||
AM.inertia_last_loc = AM.loc
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
var/datum/subsystem/squeak/SSsqueak
|
||||
|
||||
// The Squeak
|
||||
// because this is about placement of mice mobs, and nothing to do with
|
||||
// mice - the computer peripheral
|
||||
|
||||
/datum/subsystem/squeak
|
||||
name = "Squeak"
|
||||
priority = 40
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/exposed_wires = list()
|
||||
|
||||
/datum/subsystem/squeak/New()
|
||||
NEW_SS_GLOBAL(SSsqueak)
|
||||
|
||||
/datum/subsystem/squeak/Initialize(timeofday)
|
||||
trigger_migration()
|
||||
|
||||
/datum/subsystem/squeak/proc/trigger_migration(num_mice=10)
|
||||
find_exposed_wires()
|
||||
|
||||
var/mob/living/simple_animal/mouse/M
|
||||
var/turf/proposed_turf
|
||||
|
||||
while((num_mice > 0) && exposed_wires.len)
|
||||
proposed_turf = pick_n_take(exposed_wires)
|
||||
if(!M)
|
||||
M = new(proposed_turf)
|
||||
else
|
||||
M.forceMove(proposed_turf)
|
||||
if(M.environment_is_safe())
|
||||
num_mice -= 1
|
||||
M = null
|
||||
|
||||
/datum/subsystem/squeak/proc/find_exposed_wires()
|
||||
exposed_wires.Cut()
|
||||
|
||||
var/list/all_turfs = block(locate(1,1,1), locate(world.maxx,world.maxy,1))
|
||||
for(var/turf/open/floor/plating/T in all_turfs)
|
||||
if(is_blocked_turf(T))
|
||||
continue
|
||||
if(locate(/obj/structure/cable) in T)
|
||||
exposed_wires += T
|
||||
@@ -0,0 +1,37 @@
|
||||
var/datum/subsystem/stickyban/SSstickyban
|
||||
|
||||
/datum/subsystem/stickyban
|
||||
name = "Sticky Ban"
|
||||
init_order = -10
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/cache = list()
|
||||
|
||||
/datum/subsystem/stickyban/New()
|
||||
NEW_SS_GLOBAL(SSstickyban)
|
||||
|
||||
/datum/subsystem/stickyban/Initialize(timeofday)
|
||||
var/list/bannedkeys = world.GetConfig("ban")
|
||||
//sanitize the sticky ban list
|
||||
for (var/bannedkey in bannedkeys)
|
||||
var/ckey = ckey(bannedkey)
|
||||
var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey))
|
||||
|
||||
//byond stores sticky bans by key, that can end up confusing things
|
||||
//i also remove it here so that if any stickybans cause a runtime, they just stop existing
|
||||
world.SetConfig("ban", bannedkey, null)
|
||||
|
||||
if (!ban["ckey"])
|
||||
ban["ckey"] = ckey
|
||||
|
||||
//storing these can break things and isn't needed for sticky ban tracking
|
||||
ban -= "IP"
|
||||
ban -= "computer_id"
|
||||
|
||||
ban["matches_this_round"] = list()
|
||||
ban["existing_user_matches_this_round"] = list()
|
||||
ban["admin_matches_this_round"] = list()
|
||||
cache[ckey] = ban
|
||||
|
||||
for (var/bannedckey in cache)
|
||||
world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey]))
|
||||
@@ -18,6 +18,9 @@ var/datum/subsystem/tgui/SStgui
|
||||
|
||||
NEW_SS_GLOBAL(SStgui)
|
||||
|
||||
/datum/subsystem/tgui/Shutdown()
|
||||
close_all_uis()
|
||||
|
||||
/datum/subsystem/tgui/stat_entry()
|
||||
..("P:[processing_uis.len]")
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#define MAX_THROWING_DIST 512 // 2 z-levels on default width
|
||||
#define MAX_TICKS_TO_MAKE_UP 3 //how many missed ticks will we attempt to make up for this run.
|
||||
var/datum/subsystem/throwing/SSthrowing
|
||||
|
||||
/datum/subsystem/throwing
|
||||
name = "Throwing"
|
||||
priority = 25
|
||||
wait = 1
|
||||
flags = SS_NO_INIT|SS_KEEP_TIMING|SS_TICKER
|
||||
|
||||
var/list/currentrun
|
||||
var/list/processing
|
||||
|
||||
/datum/subsystem/throwing/New()
|
||||
NEW_SS_GLOBAL(SSthrowing)
|
||||
processing = list()
|
||||
|
||||
|
||||
/datum/subsystem/throwing/stat_entry()
|
||||
..("P:[processing.len]")
|
||||
|
||||
|
||||
/datum/subsystem/throwing/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(length(currentrun))
|
||||
var/atom/movable/AM = currentrun[currentrun.len]
|
||||
var/datum/thrownthing/TT = currentrun[AM]
|
||||
currentrun.len--
|
||||
if (!AM || !TT)
|
||||
processing -= AM
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
TT.tick()
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
currentrun = null
|
||||
|
||||
/datum/thrownthing
|
||||
var/atom/movable/thrownthing
|
||||
var/atom/target
|
||||
var/turf/target_turf
|
||||
var/init_dir
|
||||
var/maxrange
|
||||
var/speed
|
||||
var/mob/thrower
|
||||
var/diagonals_first
|
||||
var/dist_travelled = 0
|
||||
var/start_time
|
||||
var/dist_x
|
||||
var/dist_y
|
||||
var/dx
|
||||
var/dy
|
||||
var/pure_diagonal
|
||||
var/diagonal_error
|
||||
var/datum/callback/callback
|
||||
|
||||
/datum/thrownthing/proc/tick()
|
||||
var/atom/movable/AM = thrownthing
|
||||
if (!isturf(AM.loc) || !AM.throwing)
|
||||
finialize()
|
||||
return
|
||||
|
||||
if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
|
||||
finialize()
|
||||
return
|
||||
|
||||
var/atom/step
|
||||
|
||||
//calculate how many tiles to move, making up for any missed ticks.
|
||||
var/tilestomove = round(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
|
||||
while (tilestomove-- > 0)
|
||||
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
|
||||
finialize()
|
||||
return
|
||||
|
||||
if (dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction
|
||||
step = get_step(AM, get_dir(AM, target_turf))
|
||||
else
|
||||
step = get_step(AM, init_dir)
|
||||
|
||||
if (!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first
|
||||
if (diagonal_error >= 0 && max(dist_x,dist_y) - dist_travelled != 1) //we do a step forward unless we're right before the target
|
||||
step = get_step(AM, dx)
|
||||
diagonal_error += (diagonal_error < 0) ? dist_x/2 : -dist_y
|
||||
|
||||
if (!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
|
||||
finialize()
|
||||
return
|
||||
|
||||
AM.Move(step, get_dir(AM, step))
|
||||
|
||||
if (!AM.throwing) // we hit something during our move
|
||||
finialize(hit = TRUE)
|
||||
return
|
||||
|
||||
dist_travelled++
|
||||
|
||||
if (dist_travelled > MAX_THROWING_DIST)
|
||||
finialize()
|
||||
return
|
||||
|
||||
/datum/thrownthing/proc/finialize(hit = FALSE)
|
||||
set waitfor = 0
|
||||
SSthrowing.processing -= thrownthing
|
||||
//done throwing, either because it hit something or it finished moving
|
||||
thrownthing.throwing = 0
|
||||
if (!hit)
|
||||
for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on.
|
||||
var/atom/A = thing
|
||||
if (A == target)
|
||||
hit = 1
|
||||
thrownthing.throw_impact(A)
|
||||
break
|
||||
if (!hit)
|
||||
thrownthing.throw_impact(get_turf(thrownthing)) // we haven't hit something yet and we still must, let's hit the ground.
|
||||
thrownthing.newtonian_move(init_dir)
|
||||
else
|
||||
thrownthing.newtonian_move(init_dir)
|
||||
if (callback)
|
||||
callback.Invoke()
|
||||
|
||||
/datum/thrownthing/proc/hitcheck()
|
||||
for (var/thing in get_turf(thrownthing))
|
||||
var/atom/movable/AM = thing
|
||||
if (AM == thrownthing)
|
||||
continue
|
||||
if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER))
|
||||
thrownthing.throwing = 0
|
||||
thrownthing.throw_impact(AM)
|
||||
return 1
|
||||
@@ -11,6 +11,8 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
var/current_state = GAME_STATE_STARTUP //state of current round (used by process()) Use the defines GAME_STATE_* !
|
||||
var/force_ending = 0 //Round was ended by admin intervention
|
||||
// If true, there is no lobby phase, the game starts immediately.
|
||||
var/start_immediately = FALSE
|
||||
|
||||
var/hide_mode = 0
|
||||
var/datum/game_mode/mode = null
|
||||
@@ -22,21 +24,19 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
|
||||
|
||||
//These bible variables should be a preference
|
||||
var/Bible_icon_state //icon_state the chaplain has chosen for his bible
|
||||
var/Bible_item_state //item_state the chaplain has chosen for his bible
|
||||
var/Bible_name //name of the bible
|
||||
var/Bible_deity_name //name of chaplin's deity
|
||||
|
||||
var/list/syndicate_coalition = list() //list of traitor-compatible factions
|
||||
var/list/factions = list() //list of all factions
|
||||
var/list/availablefactions = list() //list of factions with openings
|
||||
var/list/scripture_states = list(SCRIPTURE_DRIVER = TRUE, \
|
||||
SCRIPTURE_SCRIPT = FALSE, \
|
||||
SCRIPTURE_APPLICATION = FALSE, \
|
||||
SCRIPTURE_REVENANT = FALSE, \
|
||||
SCRIPTURE_JUDGEMENT = FALSE) //list of clockcult scripture states for announcements
|
||||
|
||||
var/delay_end = 0 //if set true, the round will not restart on it's own
|
||||
|
||||
var/triai = 0 //Global holder for Triumvirate
|
||||
var/tipped = 0 //Did we broadcast the tip of the day yet?
|
||||
var/modevoted = 0 //Have we sent a vote for the gamemode?
|
||||
var/selected_tip // What will be the tip of the day?
|
||||
|
||||
var/timeLeft = 1200 //pregame timer
|
||||
@@ -51,11 +51,14 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
var/maprotatechecked = 0
|
||||
|
||||
var/modevoted = 0 //Have we sent a vote for the gamemode?
|
||||
|
||||
var/news_report
|
||||
|
||||
/datum/subsystem/ticker/New()
|
||||
NEW_SS_GLOBAL(ticker)
|
||||
|
||||
login_music = pickweight(list('sound/ambience/title1.ogg' = 30, 'sound/ambience/title2.ogg' = 30, 'sound/ambience/title3.ogg' = 30, 'sound/ambience/title4.ogg' = 30, 'sound/ambience/title5.ogg' = 30, 'sound/ambience/title6.ogg' = 30, 'sound/ambience/title7.ogg' = 30, 'sound/ambience/clown.ogg' = 3)) // choose title music!
|
||||
login_music = pickweight(list('sound/ambience/title2.ogg' = 15, 'sound/ambience/title1.ogg' =15, 'sound/ambience/title3.ogg' =14, 'sound/ambience/title4.ogg' =14, 'sound/misc/i_did_not_grief_them.ogg' =14, 'sound/ambience/clown.ogg' = 9)) // choose title music!
|
||||
if(SSevent.holidays && SSevent.holidays[APRIL_FOOLS])
|
||||
login_music = 'sound/ambience/clown.ogg'
|
||||
|
||||
@@ -64,16 +67,17 @@ var/datum/subsystem/ticker/ticker
|
||||
syndicate_code_phrase = generate_code_phrase()
|
||||
if(!syndicate_code_response)
|
||||
syndicate_code_response = generate_code_phrase()
|
||||
setupFactions()
|
||||
..()
|
||||
|
||||
/datum/subsystem/ticker/fire()
|
||||
switch(current_state)
|
||||
if(GAME_STATE_STARTUP)
|
||||
timeLeft = config.lobby_countdown * 10
|
||||
world << "<b><font color='blue'>Welcome to the pre-game lobby!</font></b>"
|
||||
world << "Please, setup your character and select ready. Game will start in [config.lobby_countdown] seconds"
|
||||
world << "<span class='boldnotice'>Welcome to [station_name()]!</span>"
|
||||
world << "Please set up your character and select \"Ready\". The game will start in [config.lobby_countdown] seconds."
|
||||
current_state = GAME_STATE_PREGAME
|
||||
for(var/client/C in clients)
|
||||
window_flash(C) //let them know lobby has opened up.
|
||||
|
||||
if(GAME_STATE_PREGAME)
|
||||
//lobby stats for statpanels
|
||||
@@ -84,6 +88,9 @@ var/datum/subsystem/ticker/ticker
|
||||
if(player.ready)
|
||||
++totalPlayersReady
|
||||
|
||||
if(start_immediately)
|
||||
timeLeft = 0
|
||||
|
||||
//countdown
|
||||
if(timeLeft < 0)
|
||||
return
|
||||
@@ -109,16 +116,19 @@ var/datum/subsystem/ticker/ticker
|
||||
mode.process(wait * 0.1)
|
||||
check_queue()
|
||||
check_maprotate()
|
||||
scripture_states = scripture_unlock_alert(scripture_states)
|
||||
|
||||
if(!mode.explosion_in_progress && mode.check_finished() || force_ending)
|
||||
current_state = GAME_STATE_FINISHED
|
||||
toggle_ooc(1) // Turn it on
|
||||
declare_completion(force_ending)
|
||||
spawn(50)
|
||||
if(mode.station_was_nuked)
|
||||
world.Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke")
|
||||
else
|
||||
world.Reboot("Round ended.", "end_proper", "proper completion")
|
||||
addtimer(CALLBACK(src, .proc/NukeCleanup), 50)
|
||||
|
||||
/datum/subsystem/ticker/proc/NukeCleanup()
|
||||
if(mode.station_was_nuked)
|
||||
world.Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke")
|
||||
else
|
||||
world.Reboot("Round ended.", "end_proper", "proper completion")
|
||||
|
||||
/datum/subsystem/ticker/proc/setup()
|
||||
//Create and announce mode
|
||||
@@ -159,19 +169,19 @@ var/datum/subsystem/ticker/ticker
|
||||
if(!can_continue)
|
||||
qdel(mode)
|
||||
mode = null
|
||||
world << "<B>Error setting up [master_mode]. It's likely that there are no available antagonists for the selected mode.</B> Reverting to pre-game lobby."
|
||||
world << "<B>Error setting up [master_mode].</B> Reverting to pre-game lobby."
|
||||
SSjob.ResetOccupations()
|
||||
return 0
|
||||
else
|
||||
world << "<span class='notice'>DEBUG: Bypassing prestart checks..."
|
||||
message_admins("<span class='notice'>DEBUG: Bypassing prestart checks...</span>")
|
||||
|
||||
if(hide_mode)
|
||||
var/list/modes = new
|
||||
for (var/datum/game_mode/M in runnable_modes)
|
||||
modes += M.name
|
||||
modes = sortList(modes)
|
||||
world << "<B>The current game mode is - Secret!</B>"
|
||||
world << "<B>Possibilities:</B> [english_list(modes)]"
|
||||
world << "<b>The gamemode is: secret!\n\
|
||||
Possibilities:</B> [english_list(modes)]"
|
||||
else
|
||||
mode.announce()
|
||||
|
||||
@@ -197,50 +207,56 @@ var/datum/subsystem/ticker/ticker
|
||||
var/datum/holiday/holiday = SSevent.holidays[holidayname]
|
||||
world << "<h4>[holiday.greet()]</h4>"
|
||||
|
||||
|
||||
spawn(0)//Forking here so we dont have to wait for this to finish
|
||||
mode.post_setup()
|
||||
//Cleanup some stuff
|
||||
for(var/obj/effect/landmark/start/S in landmarks_list)
|
||||
//Deleting Startpoints but we need the ai point to AI-ize people later
|
||||
if(S.name != "AI")
|
||||
qdel(S)
|
||||
|
||||
var/list/adm = get_admin_counts()
|
||||
if(!adm["present"])
|
||||
send2irc("Server", "Round just started with no active admins online!")
|
||||
PostSetup()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/subsystem/ticker/proc/PostSetup()
|
||||
set waitfor = 0
|
||||
mode.post_setup()
|
||||
//Cleanup some stuff
|
||||
for(var/obj/effect/landmark/start/S in landmarks_list)
|
||||
//Deleting Startpoints but we need the ai point to AI-ize people later
|
||||
if(S.name != "AI")
|
||||
qdel(S)
|
||||
/*
|
||||
var/list/adm = get_admin_counts()
|
||||
if(!adm["present"])
|
||||
send2irc("Server", "Round just started with no active admins online!")
|
||||
*/
|
||||
/datum/subsystem/ticker/proc/station_explosion_detonation(atom/bomb)
|
||||
if(bomb) //BOOM
|
||||
var/turf/epi = bomb.loc
|
||||
qdel(bomb)
|
||||
if(epi)
|
||||
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE)
|
||||
|
||||
//Plus it provides an easy way to make cinematics for other events. Just use this as a template
|
||||
/datum/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null)
|
||||
/datum/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null, atom/bomb = null)
|
||||
if( cinematic )
|
||||
return //already a cinematic in progress!
|
||||
|
||||
for (var/datum/html_interface/hi in html_interfaces)
|
||||
hi.closeAll()
|
||||
SStgui.close_all_uis()
|
||||
|
||||
//Turn off the shuttles, there's no escape now
|
||||
if(!station_missed && bomb)
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
SSshuttle.lockdown = TRUE
|
||||
|
||||
//initialise our cinematic screen object
|
||||
cinematic = new /obj/screen{icon='icons/effects/station_explosion.dmi';icon_state="station_intact";layer=21;mouse_opacity=0;screen_loc="1,0";}(src)
|
||||
|
||||
var/obj/structure/bed/temp_buckle = new(src)
|
||||
if(station_missed)
|
||||
for(var/mob/M in mob_list)
|
||||
M.buckled = temp_buckle //buckles the mob so it can't do anything
|
||||
if(M.client)
|
||||
M.client.screen += cinematic //show every client the cinematic
|
||||
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
|
||||
for(var/mob/M in mob_list)
|
||||
M.buckled = temp_buckle
|
||||
if(M.client)
|
||||
M.client.screen += cinematic
|
||||
if(M.stat != DEAD)
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z==1)
|
||||
M.death(0) //no mercy
|
||||
for(var/mob/M in mob_list)
|
||||
M.notransform = TRUE //stop everything moving
|
||||
if(M.client)
|
||||
M.client.screen += cinematic //show every client the cinematic
|
||||
|
||||
var/actually_blew_up = TRUE
|
||||
//Now animate the cinematic
|
||||
switch(station_missed)
|
||||
if(1) //nuke was nearby but (mostly) missed
|
||||
if(NUKE_NEAR_MISS) //nuke was nearby but (mostly) missed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
@@ -248,27 +264,32 @@ var/datum/subsystem/ticker/ticker
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb)
|
||||
flick("station_intact_fade_red",cinematic)
|
||||
cinematic.icon_state = "summary_nukefail"
|
||||
if("gang war") //Gang Domination (just show the override screen)
|
||||
cinematic.icon_state = "intro_malf_still"
|
||||
flick("intro_malf",cinematic)
|
||||
actually_blew_up = FALSE
|
||||
sleep(70)
|
||||
if("fake") //The round isn't over, we're just freaking people out for fun
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/items/bikehorn.ogg')
|
||||
flick("summary_selfdes",cinematic)
|
||||
actually_blew_up = FALSE
|
||||
else
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
//flick("end",cinematic)
|
||||
station_explosion_detonation(bomb)
|
||||
|
||||
|
||||
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
sleep(50)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb)
|
||||
actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station
|
||||
else //station was destroyed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
@@ -278,47 +299,61 @@ var/datum/subsystem/ticker/ticker
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_nukewin"
|
||||
if("AI malfunction") //Malf (screen,explosion,summary)
|
||||
flick("intro_malf",cinematic)
|
||||
sleep(76)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb
|
||||
cinematic.icon_state = "summary_malf"
|
||||
if("blob") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb) //TODO: no idea what this case could be
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
if("no_core") //Nuke failed to detonate as it had no core
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_intact",cinematic)
|
||||
world << sound('sound/ambience/signal.ogg')
|
||||
sleep(100)
|
||||
if(cinematic)
|
||||
qdel(cinematic)
|
||||
cinematic = null
|
||||
if(temp_buckle)
|
||||
qdel(temp_buckle)
|
||||
addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100)
|
||||
return //Faster exit, since nothing happened
|
||||
else //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red", cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
//If its actually the end of the round, wait for it to end.
|
||||
//Otherwise if its a verb it will continue on afterwards.
|
||||
spawn(300)
|
||||
if(cinematic)
|
||||
qdel(cinematic) //end the cinematic
|
||||
if(temp_buckle)
|
||||
qdel(temp_buckle) //release everybody
|
||||
return
|
||||
|
||||
var/bombloc = null
|
||||
if(actually_blew_up)
|
||||
if(bomb && bomb.loc)
|
||||
bombloc = bomb.z
|
||||
else if(!station_missed)
|
||||
bombloc = ZLEVEL_STATION
|
||||
|
||||
if(mode)
|
||||
mode.explosion_in_progress = 0
|
||||
world << "<B>The station was destoyed by the nuclear blast!</B>"
|
||||
mode.station_was_nuked = (station_missed<2) //station_missed==1 is a draw. the station becomes irradiated and needs to be evacuated.
|
||||
|
||||
addtimer(CALLBACK(src, .proc/finish_cinematic, bombloc, actually_blew_up), 300)
|
||||
|
||||
/datum/subsystem/ticker/proc/finish_cinematic(killz, actually_blew_up)
|
||||
if(cinematic)
|
||||
qdel(cinematic) //end the cinematic
|
||||
cinematic = null
|
||||
for(var/mob/M in mob_list)
|
||||
M.notransform = FALSE
|
||||
if(actually_blew_up && !isnull(killz) && M.stat != DEAD && M.z == killz)
|
||||
M.gib()
|
||||
|
||||
/datum/subsystem/ticker/proc/create_characters()
|
||||
for(var/mob/new_player/player in player_list)
|
||||
@@ -350,7 +385,7 @@ var/datum/subsystem/ticker/ticker
|
||||
SSjob.EquipRank(player, player.mind.assigned_role, 0)
|
||||
if(captainless)
|
||||
for(var/mob/M in player_list)
|
||||
if(!istype(M,/mob/new_player))
|
||||
if(!isnewplayer(M))
|
||||
M << "Captainship not forced on anyone."
|
||||
|
||||
|
||||
@@ -359,6 +394,7 @@ var/datum/subsystem/ticker/ticker
|
||||
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
|
||||
var/num_survivors = 0
|
||||
var/num_escapees = 0
|
||||
var/num_shuttle_escapees = 0
|
||||
|
||||
world << "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>"
|
||||
|
||||
@@ -368,11 +404,16 @@ var/datum/subsystem/ticker/ticker
|
||||
if(Player.stat != DEAD && !isbrain(Player))
|
||||
num_survivors++
|
||||
if(station_evacuated) //If the shuttle has already left the station
|
||||
var/area/shuttle_area
|
||||
if(SSshuttle && SSshuttle.emergency)
|
||||
shuttle_area = SSshuttle.emergency.areaInstance
|
||||
if(!Player.onCentcom() && !Player.onSyndieBase())
|
||||
Player << "<font color='blue'><b>You managed to survive, but were marooned on [station_name()]...</b></FONT>"
|
||||
else
|
||||
num_escapees++
|
||||
Player << "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>"
|
||||
if(get_area(Player) == shuttle_area)
|
||||
num_shuttle_escapees++
|
||||
else
|
||||
Player << "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>"
|
||||
else
|
||||
@@ -381,15 +422,22 @@ var/datum/subsystem/ticker/ticker
|
||||
//Round statistics report
|
||||
var/datum/station_state/end_state = new /datum/station_state()
|
||||
end_state.count()
|
||||
var/station_integrity = min(round( 100 * start_state.score(end_state), 0.1), 100)
|
||||
var/station_integrity = min(PERCENT(start_state.score(end_state)), 100)
|
||||
|
||||
world << "<BR>[TAB]Shift Duration: <B>[round(world.time / 36000)]:[add_zero("[world.time / 600 % 60]", 2)]:[world.time / 100 % 6][world.time / 100 % 10]</B>"
|
||||
world << "<BR>[TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>"
|
||||
if(mode.station_was_nuked)
|
||||
ticker.news_report = STATION_DESTROYED_NUKE
|
||||
var/total_players = joined_player_list.len
|
||||
if(joined_player_list.len)
|
||||
world << "<BR>[TAB]Total Population: <B>[joined_player_list.len]</B>"
|
||||
world << "<BR>[TAB]Total Population: <B>[total_players]</B>"
|
||||
if(station_evacuated)
|
||||
world << "<BR>[TAB]Evacuation Rate: <B>[num_escapees] ([round((num_escapees/joined_player_list.len)*100, 0.1)]%)</B>"
|
||||
world << "<BR>[TAB]Survival Rate: <B>[num_survivors] ([round((num_survivors/joined_player_list.len)*100, 0.1)]%)</B>"
|
||||
world << "<BR>[TAB]Evacuation Rate: <B>[num_escapees] ([PERCENT(num_escapees/total_players)]%)</B>"
|
||||
world << "<BR>[TAB](on emergency shuttle): <B>[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)</B>"
|
||||
news_report = STATION_EVACUATED
|
||||
if(SSshuttle.emergency.is_hijacked())
|
||||
news_report = SHUTTLE_HIJACK
|
||||
world << "<BR>[TAB]Survival Rate: <B>[num_survivors] ([PERCENT(num_survivors/total_players)]%)</B>"
|
||||
world << "<BR>"
|
||||
|
||||
//Silicon laws report
|
||||
@@ -426,6 +474,9 @@ var/datum/subsystem/ticker/ticker
|
||||
if (findtext("[handler]","auto_declare_completion_"))
|
||||
call(mode, handler)(force_ending)
|
||||
|
||||
if(cross_allowed)
|
||||
send_news_report()
|
||||
|
||||
//Print a list of antagonists to the server log
|
||||
var/list/total_antagonists = list()
|
||||
//Look into all mobs in world, dead or alive
|
||||
@@ -443,6 +494,43 @@ var/datum/subsystem/ticker/ticker
|
||||
for(var/i in total_antagonists)
|
||||
log_game("[i]s[total_antagonists[i]].")
|
||||
|
||||
//Borers
|
||||
var/borerwin = FALSE
|
||||
if(borers.len)
|
||||
var/borertext = "<br><font size=3><b>The borers were:</b></font>"
|
||||
for(var/mob/living/simple_animal/borer/B in borers)
|
||||
if((B.key || B.controlling) && B.stat != DEAD)
|
||||
borertext += "<br>[B.controlling ? B.victim.key : B.key] was [B.truename] ("
|
||||
var/turf/location = get_turf(B)
|
||||
if(location.z == ZLEVEL_CENTCOM && B.victim)
|
||||
borertext += "escaped with host"
|
||||
else
|
||||
borertext += "failed"
|
||||
borertext += ")"
|
||||
world << borertext
|
||||
|
||||
var/total_borers = 0
|
||||
for(var/mob/living/simple_animal/borer/B in borers)
|
||||
if((B.key || B.victim) && B.stat != DEAD)
|
||||
total_borers++
|
||||
if(total_borers)
|
||||
var/total_borer_hosts = 0
|
||||
for(var/mob/living/carbon/C in mob_list)
|
||||
var/mob/living/simple_animal/borer/D = C.has_brain_worms()
|
||||
var/turf/location = get_turf(C)
|
||||
if(location.z == ZLEVEL_CENTCOM && D && D.stat != DEAD)
|
||||
total_borer_hosts++
|
||||
if(total_borer_hosts_needed <= total_borer_hosts)
|
||||
borerwin = TRUE
|
||||
world << "<b>There were [total_borers] borers alive at round end!</b>"
|
||||
world << "<b>A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [total_borer_hosts_needed] hosts to escape.</b>"
|
||||
if(borerwin)
|
||||
world << "<b><font color='green'>The borers were successful!</font></b>"
|
||||
else
|
||||
world << "<b><font color='red'>The borers have failed!</font></b>"
|
||||
|
||||
mode.declare_station_goal_completion()
|
||||
|
||||
//Adds the del() log to world.log in a format condensable by the runtime condenser found in tools
|
||||
if(SSgarbage.didntgc.len)
|
||||
var/dellog = ""
|
||||
@@ -451,6 +539,8 @@ var/datum/subsystem/ticker/ticker
|
||||
dellog += "Failures : [SSgarbage.didntgc[path]] \n"
|
||||
world.log << dellog
|
||||
|
||||
//Collects persistence features
|
||||
SSpersistence.CollectData()
|
||||
return 1
|
||||
|
||||
/datum/subsystem/ticker/proc/send_tip_of_the_round()
|
||||
@@ -504,9 +594,10 @@ var/datum/subsystem/ticker/ticker
|
||||
//map rotate chance defaults to 75% of the length of the round (in minutes)
|
||||
if (!prob((world.time/600)*config.maprotatechancedelta))
|
||||
return
|
||||
spawn(0) //compiling a map can lock up the mc for 30 to 60 seconds if we don't spawn
|
||||
maprotate()
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /.proc/maprotate)
|
||||
|
||||
/datum/subsystem/ticker/proc/send_gamemode_vote(var/)
|
||||
SSvote.initiate_vote("roundtype","server")
|
||||
|
||||
/world/proc/has_round_started()
|
||||
if (ticker && ticker.current_state >= GAME_STATE_PLAYING)
|
||||
@@ -526,11 +617,6 @@ var/datum/subsystem/ticker/ticker
|
||||
|
||||
minds = ticker.minds
|
||||
|
||||
Bible_icon_state = ticker.Bible_icon_state
|
||||
Bible_item_state = ticker.Bible_item_state
|
||||
Bible_name = ticker.Bible_name
|
||||
Bible_deity_name = ticker.Bible_deity_name
|
||||
|
||||
syndicate_coalition = ticker.syndicate_coalition
|
||||
factions = ticker.factions
|
||||
availablefactions = ticker.availablefactions
|
||||
@@ -551,5 +637,56 @@ var/datum/subsystem/ticker/ticker
|
||||
cinematic = ticker.cinematic
|
||||
maprotatechecked = ticker.maprotatechecked
|
||||
|
||||
/datum/subsystem/ticker/proc/send_gamemode_vote(var/)
|
||||
SSvote.initiate_vote("roundtype","server")
|
||||
modevoted = ticker.modevoted
|
||||
|
||||
/datum/subsystem/ticker/proc/send_news_report()
|
||||
var/news_message
|
||||
var/news_source = "Nanotrasen News Network"
|
||||
switch(news_report)
|
||||
if(NUKE_SYNDICATE_BASE)
|
||||
news_message = "In a daring raid, the heroic crew of [station_name()] detonated a nuclear device in the heart of a terrorist base."
|
||||
if(STATION_DESTROYED_NUKE)
|
||||
news_message = "We would like to reassure all employees that the reports of a Syndicate backed nuclear attack on [station_name()] are, in fact, a hoax. Have a secure day!"
|
||||
if(STATION_EVACUATED)
|
||||
news_message = "The crew of [station_name()] has been evacuated amid unconfirmed reports of enemy activity."
|
||||
if(GANG_LOSS)
|
||||
news_message = "Organized crime aboard [station_name()] has been stamped out by members of our ever vigilant security team. Remember to thank your assigned officers today!"
|
||||
if(GANG_TAKEOVER)
|
||||
news_message = "Contact with [station_name()] has been lost after a sophisticated hacking attack by organized criminal elements. Stay vigilant!"
|
||||
if(BLOB_WIN)
|
||||
news_message = "[station_name()] was overcome by an unknown biological outbreak, killing all crew on board. Don't let it happen to you! Remember, a clean work station is a safe work station."
|
||||
if(BLOB_NUKE)
|
||||
news_message = "[station_name()] is currently undergoing decontanimation after a controlled burst of radiation was used to remove a biological ooze. All employees were safely evacuated prior, and are enjoying a relaxing vacation."
|
||||
if(BLOB_DESTROYED)
|
||||
news_message = "[station_name()] is currently undergoing decontamination procedures after the destruction of a biological hazard. As a reminder, any crew members experiencing cramps or bloating should report immediately to security for incineration."
|
||||
if(CULT_ESCAPE)
|
||||
news_message = "Security Alert: A group of religious fanatics have escaped from [station_name()]."
|
||||
if(CULT_FAILURE)
|
||||
news_message = "Following the dismantling of a restricted cult aboard [station_name()], we would like to remind all employees that worship outside of the Chapel is strictly prohibited, and cause for termination."
|
||||
if(CULT_SUMMON)
|
||||
news_message = "Company officials would like to clarify that [station_name()] was scheduled to be decommissioned following meteor damage earlier this year. Earlier reports of an unknowable eldritch horror were made in error."
|
||||
if(NUKE_MISS)
|
||||
news_message = "The Syndicate have bungled a terrorist attack [station_name()], detonating a nuclear weapon in empty space near by."
|
||||
if(OPERATIVES_KILLED)
|
||||
news_message = "Repairs to [station_name()] are underway after an elite Syndicate death squad was wiped out by the crew."
|
||||
if(OPERATIVE_SKIRMISH)
|
||||
news_message = "A skirmish between security forces and Syndicate agents aboard [station_name()] ended with both sides bloodied but intact."
|
||||
if(REVS_WIN)
|
||||
news_message = "Company officials have reassured investors that despite a union led revolt aboard [station_name()] that there will be no wage increases for workers."
|
||||
if(REVS_LOSE)
|
||||
news_message = "[station_name()] quickly put down a misguided attempt at mutiny. Remember, unionizing is illegal!"
|
||||
if(WIZARD_KILLED)
|
||||
news_message = "Tensions have flared with the Wizard's Federation following the death of one of their members aboard [station_name()]."
|
||||
if(STATION_NUKED)
|
||||
news_message = "[station_name()] activated its self destruct device for unknown reasons. Attempts to clone the Captain so he can be arrested and executed are under way."
|
||||
if(CLOCK_SUMMON)
|
||||
news_message = "The garbled messages about hailing a mouse and strange energy readings from [station_name()] have been discovered to be an ill-advised, if thorough, prank by a clown."
|
||||
if(CLOCK_SILICONS)
|
||||
news_message = "The project started by [station_name()] to upgrade their silicon units with advanced equipment have been largely successful, though they have thus far refused to release schematics in a violation of company policy."
|
||||
if(CLOCK_PROSELYTIZATION)
|
||||
news_message = "The burst of energy released near [station_name()] has been confirmed as merely a test of a new weapon. However, due to an unexpected mechanical error, their communications system has been knocked offline."
|
||||
if(SHUTTLE_HIJACK)
|
||||
news_message = "During routine evacuation procedures, the emergency shuttle of [station_name()] had its navigation protocols corrupted and went off course, but was recovered shortly after."
|
||||
|
||||
if(news_message)
|
||||
send2irc(news_source, news_message,"News_Report")
|
||||
|
||||
@@ -1,102 +1,341 @@
|
||||
#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
|
||||
#define BUCKET_POS(timer) (round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) + 1)
|
||||
var/datum/subsystem/timer/SStimer
|
||||
|
||||
/datum/subsystem/timer
|
||||
name = "Timer"
|
||||
wait = 2 //SS_TICKER subsystem, so wait is in ticks
|
||||
wait = 1 //SS_TICKER subsystem, so wait is in ticks
|
||||
init_order = 1
|
||||
display_order = 3
|
||||
can_fire = 0 //start disabled
|
||||
flags = SS_FIRE_IN_LOBBY|SS_TICKER|SS_POST_FIRE_TIMING|SS_NO_INIT
|
||||
|
||||
flags = SS_FIRE_IN_LOBBY|SS_TICKER|SS_NO_INIT
|
||||
|
||||
var/list/datum/timedevent/processing
|
||||
var/list/hashes
|
||||
|
||||
var/head_offset = 0 //world.time of the first entry in the the bucket.
|
||||
var/practical_offset = 0 //index of the first non-empty item in the bucket.
|
||||
var/bucket_resolution = 0 //world.tick_lag the bucket was designed for
|
||||
var/bucket_count = 0 //how many timers are in the buckets
|
||||
|
||||
var/list/bucket_list //list of buckets, each bucket holds every timer that has to run that byond tick.
|
||||
|
||||
var/list/timer_id_dict //list of all active timers assoicated to their timer id (for easy lookup)
|
||||
|
||||
var/list/clienttime_timers //special snowflake timers that run on fancy pansy "client time"
|
||||
|
||||
|
||||
/datum/subsystem/timer/New()
|
||||
processing = list()
|
||||
hashes = list()
|
||||
bucket_list = list()
|
||||
timer_id_dict = list()
|
||||
|
||||
clienttime_timers = list()
|
||||
|
||||
NEW_SS_GLOBAL(SStimer)
|
||||
|
||||
|
||||
/datum/subsystem/timer/stat_entry(msg)
|
||||
..("P:[processing.len]")
|
||||
..("B:[bucket_count] P:[length(processing)] H:[length(hashes)] C:[length(clienttime_timers)]")
|
||||
|
||||
/datum/subsystem/timer/fire()
|
||||
if(!processing.len)
|
||||
can_fire = 0 //nothing to do, lets stop firing.
|
||||
return
|
||||
for(var/datum/timedevent/event in processing)
|
||||
if(!event.thingToCall || qdeleted(event.thingToCall))
|
||||
qdel(event)
|
||||
if(event.timeToRun <= world.time)
|
||||
runevent(event)
|
||||
qdel(event)
|
||||
/datum/subsystem/timer/fire(resumed = FALSE)
|
||||
if (length(clienttime_timers))
|
||||
for (var/thing in clienttime_timers)
|
||||
var/datum/timedevent/ctime_timer = thing
|
||||
if (ctime_timer.spent)
|
||||
qdel(ctime_timer)
|
||||
continue
|
||||
if (ctime_timer.timeToRun <= REALTIMEOFDAY)
|
||||
var/datum/callback/callBack = ctime_timer.callBack
|
||||
ctime_timer.spent = TRUE
|
||||
callBack.InvokeAsync()
|
||||
qdel(ctime_timer)
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
var/static/list/spent = list()
|
||||
var/static/datum/timedevent/timer
|
||||
var/static/datum/timedevent/head
|
||||
|
||||
if (practical_offset > BUCKET_LEN || (!resumed && length(src.bucket_list) != BUCKET_LEN || world.tick_lag != bucket_resolution))
|
||||
shift_buckets()
|
||||
resumed = FALSE
|
||||
|
||||
|
||||
if (!resumed)
|
||||
timer = null
|
||||
head = null
|
||||
|
||||
var/list/bucket_list = src.bucket_list
|
||||
|
||||
while (practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time && !MC_TICK_CHECK)
|
||||
if (!timer || !head || timer == head)
|
||||
head = bucket_list[practical_offset]
|
||||
if (!head)
|
||||
practical_offset++
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
continue
|
||||
timer = head
|
||||
do
|
||||
var/datum/callback/callBack = timer.callBack
|
||||
if (!callBack)
|
||||
qdel(timer)
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("Invalid timer: timer.timeToRun=[timer.timeToRun]||qdeleted(timer)=[qdeleted(timer)]||world.time=[world.time]||head_offset=[head_offset]||practical_offset=[practical_offset]||timer.spent=[timer.spent]")
|
||||
|
||||
if (!timer.spent)
|
||||
spent += timer
|
||||
timer.spent = TRUE
|
||||
callBack.InvokeAsync()
|
||||
|
||||
timer = timer.next
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
while (timer && timer != head)
|
||||
timer = null
|
||||
bucket_list[practical_offset++] = null
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/subsystem/timer/proc/runevent(datum/timedevent/event)
|
||||
set waitfor = 0
|
||||
if(event.thingToCall == GLOBAL_PROC && istext(event.procToCall))
|
||||
call("/proc/[event.procToCall]")(arglist(event.argList))
|
||||
else
|
||||
call(event.thingToCall, event.procToCall)(arglist(event.argList))
|
||||
bucket_count -= length(spent)
|
||||
|
||||
for (var/spent_timer in spent)
|
||||
qdel(spent_timer)
|
||||
|
||||
spent.len = 0
|
||||
|
||||
|
||||
/datum/subsystem/timer/proc/shift_buckets()
|
||||
var/list/bucket_list = src.bucket_list
|
||||
var/list/alltimers = list()
|
||||
//collect the timers currently in the bucket
|
||||
for (var/bucket_head in bucket_list)
|
||||
if (!bucket_head)
|
||||
continue
|
||||
var/datum/timedevent/bucket_node = bucket_head
|
||||
do
|
||||
alltimers += bucket_node
|
||||
bucket_node = bucket_node.next
|
||||
while(bucket_node && bucket_node != bucket_head)
|
||||
|
||||
bucket_list.len = 0
|
||||
bucket_list.len = BUCKET_LEN
|
||||
|
||||
practical_offset = 1
|
||||
bucket_count = 0
|
||||
head_offset = world.time
|
||||
bucket_resolution = world.tick_lag
|
||||
|
||||
alltimers += processing
|
||||
if (!length(alltimers))
|
||||
return
|
||||
|
||||
sortTim(alltimers, .proc/cmp_timer)
|
||||
|
||||
var/datum/timedevent/head = alltimers[1]
|
||||
|
||||
if (head.timeToRun < head_offset)
|
||||
head_offset = head.timeToRun
|
||||
|
||||
var/list/timers_to_remove = list()
|
||||
|
||||
for (var/thing in alltimers)
|
||||
var/datum/timedevent/timer = thing
|
||||
if (!timer)
|
||||
timers_to_remove += timer
|
||||
continue
|
||||
|
||||
var/bucket_pos = BUCKET_POS(timer)
|
||||
if (bucket_pos > BUCKET_LEN)
|
||||
break
|
||||
|
||||
timers_to_remove += timer //remove it from the big list once we are done
|
||||
if (!timer.callBack || timer.spent)
|
||||
continue
|
||||
bucket_count++
|
||||
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
|
||||
if (!bucket_head)
|
||||
bucket_list[bucket_pos] = timer
|
||||
timer.next = null
|
||||
timer.prev = null
|
||||
continue
|
||||
|
||||
if (!bucket_head.prev)
|
||||
bucket_head.prev = bucket_head
|
||||
timer.next = bucket_head
|
||||
timer.prev = bucket_head.prev
|
||||
timer.next.prev = timer
|
||||
timer.prev.next = timer
|
||||
|
||||
processing = (alltimers - timers_to_remove)
|
||||
|
||||
|
||||
/datum/subsystem/timer/Recover()
|
||||
processing |= SStimer.processing
|
||||
hashes |= SStimer.hashes
|
||||
timer_id_dict |= SStimer.timer_id_dict
|
||||
bucket_list |= SStimer.bucket_list
|
||||
|
||||
/datum/var/list/active_timers
|
||||
/datum/timedevent
|
||||
var/thingToCall
|
||||
var/procToCall
|
||||
var/timeToRun
|
||||
var/argList
|
||||
var/id
|
||||
var/datum/callback/callBack
|
||||
var/timeToRun
|
||||
var/hash
|
||||
var/list/flags
|
||||
var/spent = FALSE //set to true right before running.
|
||||
|
||||
//cicular doublely linked list
|
||||
var/datum/timedevent/next
|
||||
var/datum/timedevent/prev
|
||||
|
||||
var/static/nextid = 1
|
||||
|
||||
/datum/timedevent/New()
|
||||
/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
|
||||
id = nextid++
|
||||
src.callBack = callBack
|
||||
src.timeToRun = timeToRun
|
||||
src.flags = flags
|
||||
src.hash = hash
|
||||
|
||||
if (flags & TIMER_UNIQUE)
|
||||
SStimer.hashes[hash] = src
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
SStimer.timer_id_dict["timerid[id]"] = src
|
||||
|
||||
if (callBack.object != GLOBAL_PROC)
|
||||
LAZYINITLIST(callBack.object.active_timers)
|
||||
callBack.object.active_timers += src
|
||||
|
||||
if (flags & TIMER_CLIENT_TIME)
|
||||
SStimer.clienttime_timers += src
|
||||
return
|
||||
|
||||
//get the list of buckets
|
||||
var/list/bucket_list = SStimer.bucket_list
|
||||
//calculate our place in the bucket list
|
||||
var/bucket_pos = BUCKET_POS(src)
|
||||
//we are too far aways from needing to run to be in the bucket list, shift_buckets() will handle us.
|
||||
if (bucket_pos > length(bucket_list))
|
||||
SStimer.processing += src
|
||||
return
|
||||
//get the bucket for our tick
|
||||
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
|
||||
SStimer.bucket_count++
|
||||
//empty bucket, we will just add ourselves
|
||||
if (!bucket_head)
|
||||
bucket_list[bucket_pos] = src
|
||||
if (bucket_pos < SStimer.practical_offset)
|
||||
SStimer.practical_offset = bucket_pos
|
||||
return
|
||||
//other wise, lets do a simplified linked list add.
|
||||
if (!bucket_head.prev)
|
||||
bucket_head.prev = bucket_head
|
||||
next = bucket_head
|
||||
prev = bucket_head.prev
|
||||
next.prev = src
|
||||
prev.next = src
|
||||
|
||||
/datum/timedevent/Destroy()
|
||||
SStimer.processing -= src
|
||||
SStimer.hashes -= hash
|
||||
..()
|
||||
if (flags & TIMER_UNIQUE)
|
||||
SStimer.hashes -= hash
|
||||
|
||||
|
||||
if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers)
|
||||
callBack.object.active_timers -= src
|
||||
UNSETEMPTY(callBack.object.active_timers)
|
||||
|
||||
callBack = null
|
||||
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
SStimer.timer_id_dict -= "timerid[id]"
|
||||
|
||||
if (flags & TIMER_CLIENT_TIME)
|
||||
SStimer.clienttime_timers -= src
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
if (!spent)
|
||||
if (prev == next && next)
|
||||
next.prev = null
|
||||
prev.next = null
|
||||
else
|
||||
if (prev)
|
||||
prev.next = next
|
||||
if (next)
|
||||
next.prev = prev
|
||||
|
||||
var/bucketpos = BUCKET_POS(src)
|
||||
var/datum/timedevent/buckethead
|
||||
var/list/bucket_list = SStimer.bucket_list
|
||||
|
||||
if (bucketpos > 0 && bucketpos <= length(bucket_list))
|
||||
buckethead = bucket_list[bucketpos]
|
||||
SStimer.bucket_count--
|
||||
else
|
||||
SStimer.processing -= src
|
||||
|
||||
if (buckethead == src)
|
||||
bucket_list[bucketpos] = next
|
||||
else
|
||||
if (prev && prev.next == src)
|
||||
prev.next = next
|
||||
if (next && next.prev == src)
|
||||
next.prev = prev
|
||||
next = null
|
||||
prev = null
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
/proc/addtimer(thingToCall, procToCall, wait, unique = FALSE, ...)
|
||||
if (!thingToCall || !procToCall)
|
||||
proc/addtimer(datum/callback/callback, wait, flags)
|
||||
if (!callback)
|
||||
return
|
||||
if (!SStimer.can_fire)
|
||||
SStimer.can_fire = 1
|
||||
|
||||
var/datum/timedevent/event = new()
|
||||
event.thingToCall = thingToCall
|
||||
event.procToCall = procToCall
|
||||
event.timeToRun = world.time + wait
|
||||
var/hashlist = args.Copy()
|
||||
|
||||
hashlist[1] = "[thingToCall](\ref[thingToCall])"
|
||||
event.hash = jointext(args, null)
|
||||
if(args.len > 4)
|
||||
event.argList = args.Copy(5)
|
||||
|
||||
// Check for dupes if unique = 1.
|
||||
if(unique)
|
||||
var/datum/timedevent/hash_event = SStimer.hashes[event.hash]
|
||||
if(hash_event)
|
||||
return hash_event.id
|
||||
SStimer.hashes[event.hash] = event
|
||||
if (wait <= 0)
|
||||
SStimer.runevent(event)
|
||||
SStimer.hashes -= event.hash
|
||||
callback.InvokeAsync()
|
||||
return
|
||||
// If we are unique (or we're not checking that), add the timer and return the id.
|
||||
SStimer.processing += event
|
||||
|
||||
return event.id
|
||||
var/hash
|
||||
|
||||
if (flags & TIMER_UNIQUE)
|
||||
var/list/hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
|
||||
hashlist += callback.arguments
|
||||
hash = hashlist.Join("|||||||")
|
||||
|
||||
var/datum/timedevent/hash_timer = SStimer.hashes[hash]
|
||||
if(hash_timer)
|
||||
if (flags & TIMER_OVERRIDE)
|
||||
qdel(hash_timer)
|
||||
else
|
||||
if (hash_timer.flags & TIMER_STOPPABLE)
|
||||
. = hash_timer.id
|
||||
return
|
||||
|
||||
|
||||
var/timeToRun = world.time + wait
|
||||
if (flags & TIMER_CLIENT_TIME)
|
||||
timeToRun = REALTIMEOFDAY + wait
|
||||
|
||||
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
return timer.id
|
||||
|
||||
/proc/deltimer(id)
|
||||
for(var/datum/timedevent/event in SStimer.processing)
|
||||
if(event.id == id)
|
||||
qdel(event)
|
||||
return 1
|
||||
return 0
|
||||
if (!id)
|
||||
return FALSE
|
||||
if (!istext(id))
|
||||
if (istype(id, /datum/timedevent))
|
||||
qdel(id)
|
||||
return TRUE
|
||||
var/datum/timedevent/timer = SStimer.timer_id_dict["timerid[id]"]
|
||||
if (timer && !timer.spent)
|
||||
qdel(timer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
#undef BUCKET_LEN
|
||||
#undef BUCKET_POS
|
||||
|
||||
@@ -58,15 +58,20 @@ var/datum/subsystem/vote/SSvote
|
||||
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)
|
||||
var/list/non_voters = directory.Copy()
|
||||
non_voters -= voted
|
||||
for (var/non_voter_ckey in non_voters)
|
||||
var/client/C = non_voters[non_voter_ckey]
|
||||
if (!C || C.is_afk())
|
||||
non_voters -= non_voter_ckey
|
||||
if(non_voters.len > 0)
|
||||
if(mode == "restart")
|
||||
choices["Continue Playing"] += non_voters
|
||||
choices["Continue Playing"] += non_voters.len
|
||||
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
|
||||
choices[master_mode] += non_voters.len
|
||||
if(choices[master_mode] >= greatest_votes)
|
||||
greatest_votes = choices[master_mode]
|
||||
//get all options with that many votes and return them in a list
|
||||
@@ -121,6 +126,7 @@ var/datum/subsystem/vote/SSvote
|
||||
restart = 1
|
||||
else
|
||||
master_mode = .
|
||||
|
||||
if("roundtype")
|
||||
if(ticker && ticker.mode)
|
||||
message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
@@ -128,6 +134,7 @@ var/datum/subsystem/vote/SSvote
|
||||
world.save_mode(.)
|
||||
master_mode = .
|
||||
world << "<span class='adminnotice'><b>The mode is now: [master_mode]</b></span>"
|
||||
|
||||
if(restart)
|
||||
var/active_admins = 0
|
||||
for(var/client/C in admins)
|
||||
|
||||
@@ -29,13 +29,13 @@ var/datum/subsystem/weather/SSweather
|
||||
var/datum/weather/W = pickweight(possible_weather_for_this_z)
|
||||
run_weather(W.name, Z)
|
||||
eligible_zlevels -= Z
|
||||
addtimer(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TRUE, Z) //Around 5-10 minutes between weathers
|
||||
addtimer(CALLBACK(src, .proc/make_z_eligible, Z), rand(3000, 6000) + W.weather_duration_upper, TIMER_UNIQUE) //Around 5-10 minutes between weathers
|
||||
|
||||
/datum/subsystem/weather/Initialize(start_timeofday)
|
||||
..()
|
||||
for(var/V in subtypesof(/datum/weather))
|
||||
var/datum/weather/W = V
|
||||
existing_weather |= new W
|
||||
new W //weather->New will handle adding itself to the list
|
||||
|
||||
/datum/subsystem/weather/proc/run_weather(weather_name, Z)
|
||||
if(!weather_name)
|
||||
|
||||
Reference in New Issue
Block a user